diff --git a/drivers/staging/qcacld-3.0/Android.mk b/drivers/staging/qcacld-3.0/Android.mk new file mode 100644 index 0000000000000000000000000000000000000000..a79a76554de7fa8a52e6d1a102f271ae03d6d743 --- /dev/null +++ b/drivers/staging/qcacld-3.0/Android.mk @@ -0,0 +1,85 @@ +# Android makefile for the WLAN Module + +# 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),) + +LOCAL_PATH := $(call my-dir) + +# This makefile is only for DLKM +ifneq ($(findstring vendor,$(LOCAL_PATH)),) + +ifneq ($(findstring opensource,$(LOCAL_PATH)),) + WLAN_BLD_DIR := vendor/qcom/opensource/wlan +endif # opensource + +# DLKM_DIR was moved for JELLY_BEAN (PLATFORM_SDK 16) +ifeq ($(call is-platform-sdk-version-at-least,16),true) + DLKM_DIR := $(TOP)/device/qcom/common/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 +KBUILD_OPTIONS += WLAN_COMMON_ROOT=../qca-wifi-host-cmn +KBUILD_OPTIONS += WLAN_COMMON_INC=$(WLAN_BLD_DIR)/qca-wifi-host-cmn + +# 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=wlan +KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) +KBUILD_OPTIONS += $(WLAN_SELECT) + +include $(CLEAR_VARS) +LOCAL_MODULE := $(WLAN_CHIPSET)_wlan.ko +LOCAL_MODULE_KBUILD_NAME := wlan.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 + +include $(DLKM_DIR)/AndroidKernelModule.mk +########################################################### + +# Create Symbolic link +ifneq ($(findstring $(WLAN_CHIPSET),$(WIFI_DRIVER_DEFAULT)),) +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) +ifneq ($(WIFI_DRIVER_INSTALL_TO_KERNEL_OUT),) +$(shell mkdir -p $(TARGET_OUT_VENDOR)/lib/modules; \ + ln -sf /$(TARGET_COPY_OUT_VENDOR)/lib/modules/$(WLAN_CHIPSET)/$(LOCAL_MODULE) $(TARGET_OUT_VENDOR)/lib/modules/wlan.ko) +endif +else +$(shell mkdir -p $(TARGET_OUT)/lib/modules; \ + ln -sf /system/lib/modules/$(WLAN_CHIPSET)/$(LOCAL_MODULE) $(TARGET_OUT)/lib/modules/wlan.ko) +endif +endif + +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) +$(shell ln -sf /mnt/vendor/persist/wlan_mac.bin $(TARGET_OUT_VENDOR)/firmware/wlan/qca_cld/wlan_mac.bin) +else +$(shell ln -sf /mnt/vendor/persist/wlan_mac.bin $(TARGET_OUT_ETC)/firmware/wlan/qca_cld/wlan_mac.bin) +endif +endif # DLKM check +endif # supported target check +endif # WLAN enabled check diff --git a/drivers/staging/qcacld-3.0/Kbuild b/drivers/staging/qcacld-3.0/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..ad4e9877d3a045bdd3b7cf70ec4008aa5d309d61 --- /dev/null +++ b/drivers/staging/qcacld-3.0/Kbuild @@ -0,0 +1,2187 @@ +# 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 := ../qca-wifi-host-cmn + WLAN_COMMON_INC := $(WLAN_ROOT)/$(WLAN_COMMON_ROOT) +endif + +WLAN_COMMON_ROOT ?= ../qca-wifi-host-cmn +WLAN_COMMON_INC ?= $(WLAN_ROOT)/$(WLAN_COMMON_ROOT) + +CONFIG_QCA_CLD_WLAN_PROFILE ?= default +ifeq ($(KERNEL_BUILD), n) +ifneq ($(ANDROID_BUILD_TOP),) + override WLAN_ROOT := $(ANDROID_BUILD_TOP)/$(WLAN_ROOT) + override WLAN_COMMON_INC := $(ANDROID_BUILD_TOP)/$(WLAN_COMMON_INC) +endif +endif + +include $(WLAN_ROOT)/configs/$(CONFIG_QCA_CLD_WLAN_PROFILE)_defconfig + +############ 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_ext_scan.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_packet_filter.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_stats.o \ + $(HDD_SRC_DIR)/wlan_hdd_trace.o \ + $(HDD_SRC_DIR)/wlan_hdd_tx_rx.o \ + $(HDD_SRC_DIR)/wlan_hdd_wext.o \ + $(HDD_SRC_DIR)/wlan_hdd_wmm.o \ + $(HDD_SRC_DIR)/wlan_hdd_wowl.o + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_llstat.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_csr.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_connect.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_offload.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_roam.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_LRO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_lro.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_NAN), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nan.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_MPC_UT_FRAMEWORK), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_conc_ut.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_NAN_DATAPATH), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nan_datapath.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_11AX), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_he.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_TWT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_twt.o +endif + +ifeq ($(CONFIG_LITHIUM), 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_SYSFS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs.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_QCACLD_FEATURE_HW_CAPABILITY), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_hw_capability.o +endif + +########### 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) + +HOST_DIAG_LOG_OBJS += $(HOST_DIAG_LOG_SRC_DIR)/host_diag_log.o + +############ 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) + +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 \ + + +############ 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_CFG_OBJS := $(MAC_SRC_DIR)/cfg/cfg_api.o \ + $(MAC_SRC_DIR)/cfg/cfg_param_name.o \ + $(MAC_SRC_DIR)/cfg/cfg_proc_msg.o \ + $(MAC_SRC_DIR)/cfg/cfg_send_msg.o + +MAC_DPH_OBJS := $(MAC_SRC_DIR)/dph/dph_hash_table.o + +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_ibss_peer_mgmt.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_ser_des_utils.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_sta_hash_api.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 + +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_WLAN_FEATURE_NAN_DATAPATH), 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 + +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) + +############ 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 + +############ 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) + +DFS_OBJS := $(DFS_CORE_SRC_DIR)/misc/dfs.o \ + $(DFS_CORE_SRC_DIR)/misc/dfs_cac.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 \ + $(DFS_CORE_SRC_DIR)/misc/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_ar.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_partial_offload_radar.o \ + $(DFS_CORE_SRC_DIR)/misc/dfs_filter_init.o \ + $(DFS_CORE_SRC_DIR)/misc/dfs_zero_cac.o +endif + +############ 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 + +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_neighbor_roam.o \ + $(SME_SRC_DIR)/csr/csr_util.o \ + + +ifeq ($(CONFIG_QCACLD_WLAN_LFR2), y) +SME_CSR_OBJS += $(SME_SRC_DIR)/csr/csr_roam_preauth.o \ + $(SME_SRC_DIR)/csr/csr_host_scan_roam.o +endif + +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_ft_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_NAN_OBJS = $(SME_SRC_DIR)/nan/nan_api.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), 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) + +############ 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 + +############ 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 + +############ 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 + +############ 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 + +############ 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_INC := -I$(WLAN_COMMON_INC)/$(QDF_OS_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(QDF_OS_LINUX_SRC_DIR) + +QDF_OBJS := $(QDF_LINUX_OBJ_DIR)/qdf_defer.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_event.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_file.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_threads.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_crypto.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_trace.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_idr.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_types.o \ + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_debugfs.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_ipa.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 +endif + +############ 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 + +##########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/p2p/inc \ + -I$(WLAN_COMMON_INC)/os_if/linux/spectral/inc \ + -I$(WLAN_COMMON_INC)/os_if/linux/tdls/inc + +OS_IF_OBJ := $(OS_IF_DIR)/linux/p2p/src/wlan_cfg80211_p2p.o \ + $(OS_IF_DIR)/linux/wlan_osif_request_manager.o + +############ 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 + +############# 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_bss_score.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_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 + +############# 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 +############# 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) +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 + +############# 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) + +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 \ + $(OS_IF_FTM_SRC)/wlan_cfg80211_ftm.o \ + $(TARGET_IF_FTM_SRC)/target_if_ftm.o + +ifeq ($(CONFIG_LINUX_QCMBR), y) +FTM_OBJS += $(OS_IF_FTM_SRC)/wlan_ioctl_ftm.o +endif + +############# 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 + +ifeq ($(CONFIG_WLAN_LRO), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_lro.o +endif + +############ 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 + + +###### 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 \ + -I$(WLAN_COMMON_INC)/umac/global_umac_dispatcher/lmac_if/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 + +########### 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 + +########## POWER MANAGEMENT OFFLOADS (PMO) ########## +PMO_DIR := components/pmo +PMO_INC := -I$(WLAN_ROOT)/$(PMO_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(PMO_DIR)/core/src \ + -I$(WLAN_ROOT)/$(PMO_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/$(PMO_DIR)/dispatcher/src \ + +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_ns.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)/core/src/wlan_pmo_pkt_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_ns.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 \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_pkt_filter.o +endif + +########## 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 + +######## 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 + +######## IPA ############## +IPA_DIR := components/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 + +######## 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_ucfg_api.o + +########## 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 + +########## 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)/pmo/src + +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_ns.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_pkt_filter.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 +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_IPA_OFFLOAD), y) +CLD_TARGET_IF_INC += -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/ipa/inc +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/ipa/src/target_if_ipa.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 + +############## UMAC P2P ########### +P2P_DIR := umac/p2p +P2P_CORE_DIR := $(P2P_DIR)/core +P2P_CORE_SRC_DIR := $(P2P_CORE_DIR)/src +P2P_CORE_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(P2P_CORE_SRC_DIR) +P2P_DISPATCHER_DIR := $(P2P_DIR)/dispatcher +P2P_DISPATCHER_INC_DIR := $(P2P_DISPATCHER_DIR)/inc +P2P_DISPATCHER_SRC_DIR := $(P2P_DISPATCHER_DIR)/src +P2P_DISPATCHER_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(P2P_DISPATCHER_SRC_DIR) +UMAC_P2P_INC := -I$(WLAN_COMMON_INC)/$(P2P_DISPATCHER_INC_DIR) \ + -I$(WLAN_COMMON_INC)/umac/scan/dispatcher/inc +UMAC_P2P_OBJS := $(P2P_DISPATCHER_OBJ_DIR)/wlan_p2p_ucfg_api.o \ + $(P2P_DISPATCHER_OBJ_DIR)/wlan_p2p_tgt_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 + +###### UMAC POLICY MGR ######## +UMAC_POLICY_MGR_DIR := $(WLAN_COMMON_ROOT)/umac/cmn_services/policy_mgr + +UMAC_POLICY_MGR_INC := -I$(WLAN_COMMON_INC)/umac/cmn_services/policy_mgr/inc \ + -I$(WLAN_COMMON_INC)/umac/cmn_services/policy_mgr/src + +UMAC_POLICY_MGR_OBJS := $(UMAC_POLICY_MGR_DIR)/src/wlan_policy_mgr_action.o \ + $(UMAC_POLICY_MGR_DIR)/src/wlan_policy_mgr_core.o \ + $(UMAC_POLICY_MGR_DIR)/src/wlan_policy_mgr_get_set_utils.o \ + $(UMAC_POLICY_MGR_DIR)/src/wlan_policy_mgr_init_deinit.o \ + $(UMAC_POLICY_MGR_DIR)/src/wlan_policy_mgr_pcl.o \ + +###### UMAC TDLS ######## +UMAC_TDLS_DIR := $(WLAN_COMMON_ROOT)/umac/tdls + +UMAC_TDLS_INC := -I$(WLAN_COMMON_INC)/umac/tdls/dispatcher/inc + +UMAC_TDLS_OBJS := $(UMAC_TDLS_DIR)/core/src/wlan_tdls_main.o \ + $(UMAC_TDLS_DIR)/core/src/wlan_tdls_cmds_process.o \ + $(UMAC_TDLS_DIR)/core/src/wlan_tdls_peer.o \ + $(UMAC_TDLS_DIR)/core/src/wlan_tdls_mgmt.o \ + $(UMAC_TDLS_DIR)/core/src/wlan_tdls_ct.o \ + $(UMAC_TDLS_DIR)/dispatcher/src/wlan_tdls_tgt_api.o \ + $(UMAC_TDLS_DIR)/dispatcher/src/wlan_tdls_ucfg_api.o \ + $(UMAC_TDLS_DIR)/dispatcher/src/wlan_tdls_utils_api.o \ + $(WLAN_COMMON_ROOT)/os_if/linux/tdls/src/wlan_cfg80211_tdls.o + +########### BMI ########### +BMI_DIR := core/bmi + +BMI_INC := -I$(WLAN_ROOT)/$(BMI_DIR)/inc + +BMI_OBJS := $(BMI_DIR)/src/bmi.o \ + $(BMI_DIR)/src/ol_fw.o \ + $(BMI_DIR)/src/ol_fw_common.o +BMI_OBJS += $(BMI_DIR)/src/bmi_1.o + +########## 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/core/src \ + -I$(WLAN_COMMON_INC)/target_if/init_deinit/inc \ + -I$(WLAN_COMMON_INC)/target_if/p2p/inc \ + -I$(WLAN_COMMON_INC)/target_if/regulatory/inc \ + -I$(WLAN_COMMON_INC)/target_if/tdls/inc + +TARGET_IF_OBJ := $(TARGET_IF_DIR)/core/src/target_if_main.o \ + $(TARGET_IF_DIR)/p2p/src/target_if_p2p.o \ + $(TARGET_IF_DIR)/regulatory/src/target_if_reg.o \ + $(TARGET_IF_DIR)/tdls/src/target_if_tdls.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 \ + +########### 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 \ + -I$(WLAN_COMMON_INC)/global_lmac_if/src + +GLOBAL_LMAC_IF_OBJ := $(GLOBAL_LMAC_IF_DIR)/src/wlan_global_lmac_if.o + +########### 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 + +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_pmo_api.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_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 + +########### FWLOG ########### +FWLOG_DIR := $(WLAN_COMMON_ROOT)/utils/fwlog + +FWLOG_INC := -I$(WLAN_ROOT)/$(FWLOG_DIR) + +FWLOG_OBJS := $(FWLOG_DIR)/dbglog_host.o + +############ TXRX ############ +TXRX_DIR := core/dp/txrx +TXRX_INC := -I$(WLAN_ROOT)/$(TXRX_DIR) + +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_tx_queue.o \ + $(TXRX_DIR)/ol_txrx_peer_find.o \ + $(TXRX_DIR)/ol_txrx_encap.o \ + $(TXRX_DIR)/ol_tx_send.o \ + $(TXRX_DIR)/ol_tx_sched.o \ + $(TXRX_DIR)/ol_tx_classify.o + +ifeq ($(CONFIG_WDI_EVENT_ENABLE), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_event.o +endif + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_flow_control.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_ipa.o +endif + +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_LITHIUM), y) +############ DP 3.0 ############ +DP_INC := -I$(WLAN_COMMON_ROOT)/dp/inc \ + -I$(WLAN_COMMON_ROOT)/dp/wifi3.0 + +DP_SRC := $(WLAN_COMMON_ROOT)/dp/wifi3.0 +DP_OBJS := $(DP_SRC)/dp_main.o \ + $(DP_SRC)/dp_tx.o \ + $(DP_SRC)/dp_tx_desc.o \ + $(DP_SRC)/dp_rx.o \ + $(DP_SRC)/dp_rx_err.o \ + $(DP_SRC)/dp_htt.o \ + $(DP_SRC)/dp_peer.o \ + $(DP_SRC)/dp_rx_desc.o \ + $(DP_SRC)/dp_reo.o \ + $(DP_SRC)/dp_rx_mon_dest.o \ + $(DP_SRC)/dp_rx_mon_status.o \ + $(DP_SRC)/dp_rx_defrag.o \ + $(DP_SRC)/dp_stats.o +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +DP_OBJS += $(DP_SRC)/dp_tx_flow_control.o +endif +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 + +############ CFG ############ +WCFG_DIR := wlan_cfg +WCFG_INC := -I$(WLAN_COMMON_INC)/$(WCFG_DIR) +WCFG_SRC := $(WLAN_COMMON_ROOT)/$(WCFG_DIR) +WCFG_OBJS := $(WCFG_SRC)/wlan_cfg.o + +############ 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 + +PKTLOG_OBJS := $(PKTLOG_DIR)/pktlog_ac.o \ + $(PKTLOG_DIR)/pktlog_internal.o \ + $(PKTLOG_DIR)/linux_ac.o + +############ HTT ############ +HTT_DIR := core/dp/htt +HTT_INC := -I$(WLAN_ROOT)/$(HTT_DIR) + +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 + +############## 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 + +############## REGULATORY ########### +REGULATORY_DIR := umac/regulatory +REGULATORY_CORE_INC_DIR := $(REGULATORY_DIR)/core/inc +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_INC_DIR) +REGULATORY_INC += -I$(WLAN_COMMON_INC)/$(REG_DISPATCHER_INC_DIR) +REGULATORY_OBJS := $(REG_CORE_OBJ_DIR)/reg_db.o \ + $(REG_CORE_OBJ_DIR)/reg_services.o \ + $(REG_CORE_OBJ_DIR)/reg_db_parser.o \ + $(REG_DISPATCHER_OBJ_DIR)/wlan_reg_services_api.o \ + $(REG_DISPATCHER_OBJ_DIR)/wlan_reg_tgt_api.o \ + $(REG_DISPATCHER_OBJ_DIR)/wlan_reg_ucfg_api.o + +############## 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 + +###### 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_dequeue.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_enqueue.o \ + $(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 + +###### 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_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_OS_IF_DIR)/os_if_wifi_pos.o \ + $(WIFI_POS_TGT_DIR)/target_if_wifi_pos.o +endif + +###### CP STATS ######## +CP_STATS_OS_IF_SRC := $(WLAN_COMMON_ROOT)/os_if/linux/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_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 + +ifeq ($(CONFIG_CP_STATS), y) +CP_STATS_OBJS := $(CP_STATS_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_STATS_OS_IF_SRC)/wlan_cfg80211_mc_cp_stats.o \ + $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_utils_api.o \ + $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_mc_tgt_api.o \ + $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_mc_ucfg_api.o +endif + +######################### NAN ######################### +NAN_CORE_DIR := $(WLAN_COMMON_ROOT)/umac/nan/core/src +NAN_CORE_INC := -I$(WLAN_COMMON_INC)/umac/nan/core/inc +NAN_UCFG_DIR := $(WLAN_COMMON_ROOT)/umac/nan/dispatcher/src +NAN_UCFG_INC := -I$(WLAN_COMMON_INC)/umac/nan/dispatcher/inc +NAN_TGT_DIR := $(WLAN_COMMON_ROOT)/target_if/nan/src +NAN_TGT_INC := -I$(WLAN_COMMON_INC)/target_if/nan/inc +NAN_OS_IF_DIR := $(WLAN_COMMON_ROOT)/os_if/linux/nan/src +NAN_OS_IF_INC := -I$(WLAN_COMMON_INC)/os_if/linux/nan/inc + +ifeq ($(CONFIG_NAN_CONVERGENCE), y) +WLAN_NAN_OBJS := $(NAN_CORE_DIR)/nan_main.o \ + $(NAN_CORE_DIR)/nan_api.o \ + $(NAN_CORE_DIR)/nan_utils.o \ + $(NAN_UCFG_DIR)/nan_ucfg_api.o \ + $(NAN_TGT_DIR)/target_if_nan.o \ + $(NAN_OS_IF_DIR)/os_if_nan.o +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 + +########### 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_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_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) +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) +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/mp_dev.o + +ifeq ($(CONFIG_WLAN_NAPI), y) +HIF_COMMON_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_exec.o +HIF_COMMON_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_irq_affinity.o +endif + + + +HIF_CE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_bmi.o \ + $(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/regtable.o + +ifeq ($(CONFIG_LITHIUM), y) +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/qca6290def.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_service_srng.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_sdio_send.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_bmi_reg_access.o \ + $(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)/hif_sdio_recv.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/regtable_sdio.o + +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 + +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_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_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 + +ifeq ($(CONFIG_LITHIUM), y) +############ HAL ############ +HAL_DIR := hal +HAL_INC := -I$(WLAN_COMMON_INC)/$(HAL_DIR)/inc \ + -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0 + +HAL_OBJS := $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/hal_srng.o \ + $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/hal_rx.o \ + $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/hal_wbm.o \ + $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/hal_reo.o +endif + +############ 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_WLAN_FEATURE_NAN_DATAPATH), 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_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_MPC_UT_FRAMEWORK), y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_utils_ut.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_WLAN_MWS_INFO_DEBUGFS), y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_coex.o +endif +############## 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_HIF_PCI), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_pcie.o +endif +ifeq ($(CONFIG_ICNSS), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_snoc.o +endif +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_sdio.o +endif +ifeq ($(CONFIG_PLD_USB_CNSS), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_usb.o +endif + +ifeq ($(CONFIG_QCA6290_11AX), y) +TARGET_INC := -I$(WLAN_ROOT)/../fw-api/hw/qca6290/11ax/v2 \ + -I$(WLAN_ROOT)/../fw-api/fw +else +TARGET_INC := -I$(WLAN_ROOT)/../fw-api/hw/qca6290/v2 \ + -I$(WLAN_ROOT)/../fw-api/fw +endif + +LINUX_INC := -Iinclude + +INCS := $(HDD_INC) \ + $(EPPING_INC) \ + $(LINUX_INC) \ + $(MAC_INC) \ + $(SAP_INC) \ + $(SME_INC) \ + $(SYS_INC) \ + $(QDF_INC) \ + $(WBUFF_INC) \ + $(CDS_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) \ + $(DFS_INC) \ + $(WCFG_INC) + +INCS += $(HIF_INC) \ + $(BMI_INC) + +ifeq ($(CONFIG_LITHIUM), y) +INCS += $(HAL_INC) \ + $(DP_INC) +endif + +################ WIFI POS ################ +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) +################ NAN POS ################ +INCS += $(NAN_CORE_INC) +INCS += $(NAN_UCFG_INC) +INCS += $(NAN_TGT_INC) +INCS += $(NAN_OS_IF_INC) +########################################## +INCS += $(UMAC_OBJMGR_INC) +INCS += $(UMAC_MGMT_TXRX_INC) +INCS += $(PMO_INC) +INCS += $(UMAC_P2P_INC) +INCS += $(UMAC_POLICY_MGR_INC) +INCS += $(TARGET_INC) +INCS += $(UMAC_TDLS_INC) +INCS += $(UMAC_SER_INC) +INCS += $(NLINK_INC) \ + $(PTT_INC) \ + $(WLAN_LOGGING_INC) + +INCS += $(PLD_INC) +INCS += $(OCB_INC) + +INCS += $(IPA_INC) +INCS += $(MLME_INC) + +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +INCS += $(PKTLOG_INC) +endif + +ifeq ($(BUILD_DIAG_VERSION), y) +INCS += $(HOST_DIAG_LOG_INC) +endif + +INCS += $(DISA_INC) +INCS += $(ACTION_OUI_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 += $(UMAC_TARGET_SPECTRAL_INC) + +OBJS := $(HDD_OBJS) \ + $(MAC_OBJS) \ + $(SAP_OBJS) \ + $(SME_OBJS) \ + $(SYS_OBJS) \ + $(QDF_OBJS) \ + $(WBUFF_OBJS) \ + $(CDS_OBJS) \ + $(FTM_OBJS) + +OBJS += $(WMA_OBJS) \ + $(TXRX_OBJS) \ + $(WMI_OBJS) \ + $(HTC_OBJS) \ + $(INIT_DEINIT_OBJS) \ + $(SCHEDULER_OBJS) \ + $(REGULATORY_OBJS) + +OBJS += $(HIF_OBJS) \ + $(BMI_OBJS) \ + $(HTT_OBJS) \ + $(OS_IF_OBJ) \ + $(TARGET_IF_OBJ) \ + $(CLD_TARGET_IF_OBJ) \ + $(GLOBAL_LMAC_IF_OBJ) + +ifeq ($(CONFIG_LITHIUM), y) +OBJS += $(HAL_OBJS) +endif + +ifeq ($(CONFIG_FEATURE_FW_LOG_PARSING), y) +OBJS += $(FWLOG_OBJS) +endif + +ifeq ($(CONFIG_FEATURE_EPPING), y) +OBJS += $(EPPING_OBJS) +endif + +ifeq ($(CONFIG_WLAN_DFS_MASTER_ENABLE), y) +OBJS += $(DFS_OBJS) +endif + +OBJS += $(UMAC_OBJMGR_OBJS) +OBJS += $(WIFI_POS_OBJS) +OBJS += $(CP_STATS_OBJS) +OBJS += $(WLAN_NAN_OBJS) +OBJS += $(UMAC_MGMT_TXRX_OBJS) +OBJS += $(UMAC_TDLS_OBJS) +OBJS += $(PMO_OBJS) +OBJS += $(UMAC_P2P_OBJS) +OBJS += $(UMAC_POLICY_MGR_OBJS) +OBJS += $(WLAN_LOGGING_OBJS) +OBJS += $(NLINK_OBJS) +OBJS += $(PTT_OBJS) +OBJS += $(UMAC_SER_OBJS) +OBJS += $(PLD_OBJS) +OBJS += $(MLME_OBJS) + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +OBJS += $(OCB_OBJS) +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +OBJS += $(IPA_OBJS) +endif + +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +OBJS += $(PKTLOG_OBJS) +endif + +ifeq ($(BUILD_DIAG_VERSION), y) +OBJS += $(HOST_DIAG_LOG_OBJS) +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DISA), y) +OBJS += $(DISA_OBJS) +endif + +ifeq ($(CONFIG_WLAN_FEATURE_ACTION_OUI), y) +OBJS += $(ACTION_OUI_OBJS) +endif + +OBJS += $(UMAC_DISP_OBJS) +OBJS += $(UMAC_SCAN_OBJS) +OBJS += $(UMAC_COMMON_OBJS) +OBJS += $(WCFG_OBJS) + +OBJS += $(UMAC_SPECTRAL_OBJS) + +ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP), y) +OBJS += $(UMAC_GREEN_AP_OBJS) +endif + +ifeq ($(CONFIG_LITHIUM), y) +OBJS += $(DP_OBJS) +endif + +ccflags-y += $(INCS) + +cppflags-y += -DANI_OS_TYPE_ANDROID=6 \ + -Wall\ + -Werror\ + -D__linux__ + +cppflags-$(CONFIG_PTT_SOCK_SVC_ENABLE) += -DPTT_SOCK_SVC_ENABLE +cppflags-$(CONFIG_FEATURE_WLAN_WAPI) += -DFEATURE_WLAN_WAPI +cppflags-$(CONFIG_FEATURE_WLAN_WAPI) += -DATH_SUPPORT_WAPI +cppflags-$(CONFIG_AGEIE_ON_SCAN_RESULTS) += -DWLAN_ENABLE_AGEIE_ON_SCAN_RESULTS +cppflags-$(CONFIG_SOFTAP_CHANNEL_RANGE) += -DSOFTAP_CHANNEL_RANGE +cppflags-$(CONFIG_FEATURE_WLAN_SCAN_PNO) += -DFEATURE_WLAN_SCAN_PNO +cppflags-$(CONFIG_WLAN_FEATURE_PACKET_FILTERING) += -DWLAN_FEATURE_PACKET_FILTERING +cppflags-$(CONFIG_WLAN_NS_OFFLOAD) += -DWLAN_NS_OFFLOAD +cppflags-$(CONFIG_FEATURE_WLAN_RA_FILTERING) += -DFEATURE_WLAN_RA_FILTERING +cppflags-$(CONFIG_FEATURE_WLAN_LPHB) += -DFEATURE_WLAN_LPHB +cppflags-$(CONFIG_QCA_SUPPORT_TX_THROTTLE) += -DQCA_SUPPORT_TX_THROTTLE +cppflags-$(CONFIG_WMI_INTERFACE_EVENT_LOGGING) += -DWMI_INTERFACE_EVENT_LOGGING +cppflags-$(CONFIG_WLAN_FEATURE_LINK_LAYER_STATS) += -DWLAN_FEATURE_LINK_LAYER_STATS +cppflags-$(CONFIG_FEATURE_WLAN_EXTSCAN) += -DFEATURE_WLAN_EXTSCAN +cppflags-$(CONFIG_160MHZ_SUPPORT) += -DCONFIG_160MHZ_SUPPORT +cppflags-$(CONFIG_MCL) += -DCONFIG_MCL +cppflags-$(CONFIG_MCL_REGDB) += -DCONFIG_MCL_REGDB +cppflags-$(CONFIG_LEGACY_CHAN_ENUM) += -DCONFIG_LEGACY_CHAN_ENUM +cppflags-$(CONFIG_WLAN_PMO_ENABLE) += -DWLAN_PMO_ENABLE +cppflags-$(CONFIG_CONVERGED_P2P_ENABLE) += -DCONVERGED_P2P_ENABLE +cppflags-$(CONFIG_WLAN_POLICY_MGR_ENABLE) += -DWLAN_POLICY_MGR_ENABLE +cppflags-$(CONFIG_SUPPORT_11AX) += -DSUPPORT_11AX +cppflags-$(CONFIG_HDD_INIT_WITH_RTNL_LOCK) += -DCONFIG_HDD_INIT_WITH_RTNL_LOCK +cppflags-$(CONFIG_CONVERGED_TDLS_ENABLE) += -DCONVERGED_TDLS_ENABLE +cppflags-$(CONFIG_WLAN_CONV_SPECTRAL_ENABLE) += -DWLAN_CONV_SPECTRAL_ENABLE +cppflags-$(CONFIG_WMI_CMD_STRINGS) += -DWMI_CMD_STRINGS +cppflags-$(CONFIG_FEATURE_MONITOR_MODE_SUPPORT) += -DFEATURE_MONITOR_MODE_SUPPORT +cppflags-$(CONFIG_WLAN_FEATURE_TWT) += -DWLAN_SUPPORT_TWT + +cppflags-$(CONFIG_WLAN_DISABLE_EXPORT_SYMBOL) += -DWLAN_DISABLE_EXPORT_SYMBOL +cppflags-$(CONFIG_WIFI_POS_CONVERGED) += -DWIFI_POS_CONVERGED +cppflags-$(CONFIG_WIFI_POS_LEGACY) += -DFEATURE_OEM_DATA_SUPPORT +cppflags-$(CONFIG_FEATURE_HTC_CREDIT_HISTORY) += -DFEATURE_HTC_CREDIT_HISTORY +cppflags-$(CONFIG_WLAN_FEATURE_P2P_DEBUG) += -DWLAN_FEATURE_P2P_DEBUG +cppflags-$(CONFIG_WLAN_LOGGING_SOCK_SVC) += -DWLAN_LOGGING_SOCK_SVC_ENABLE +cppflags-$(CONFIG_WLAN_FEATURE_FILS) += -DWLAN_FEATURE_FILS_SK +cppflags-$(CONFIG_CP_STATS) += -DQCA_SUPPORT_CP_STATS +cppflags-$(CONFIG_FEATURE_MEMDUMP_ENABLE) += -DWLAN_FEATURE_MEMDUMP_ENABLE +cppflags-$(CONFIG_FEATURE_FW_LOG_PARSING) += -DFEATURE_FW_LOG_PARSING + +ifeq ($(CONFIG_CNSS), y) +ifeq ($(CONFIG_CNSS_SDIO), y) +cppflags-y += -DCONFIG_PLD_SDIO_CNSS +else +cppflags-y += -DCONFIG_PLD_PCIE_CNSS +endif +endif + +ifeq ($(CONFIG_CNSS2), y) +cppflags-y += -DCONFIG_PLD_PCIE_CNSS +cppflags-y += -DCONFIG_PLD_PCIE_INIT +endif + +#Enable NL80211 test mode +cppflags-$(CONFIG_NL80211_TESTMODE) += -DWLAN_NL80211_TESTMODE + +# Flag to enable bus auto suspend +ifeq ($(CONFIG_HIF_PCI), y) +ifeq ($(CONFIG_BUS_AUTO_SUSPEND), y) +cppflags-y += -DFEATURE_RUNTIME_PM +endif +endif + +cppflags-$(CONFIG_ICNSS) += -DCONFIG_PLD_SNOC_ICNSS + +cppflags-$(CONFIG_ICNSS) += -DQCA_WIFI_3_0 + +cppflags-$(CONFIG_WIFI_3_0_ADRASTEA) += -DQCA_WIFI_3_0_ADRASTEA +cppflags-$(CONFIG_ADRASTEA_SHADOW_REGISTERS) += -DADRASTEA_SHADOW_REGISTERS +cppflags-$(CONFIG_ADRASTEA_RRI_ON_DDR) += -DADRASTEA_RRI_ON_DDR + +ifeq ($(CONFIG_QMI_SUPPORT), n) +cppflags-y += -DCONFIG_BYPASS_QMI +endif + +cppflags-$(CONFIG_WLAN_FASTPATH) += -DWLAN_FEATURE_FASTPATH + +cppflags-$(CONFIG_FEATURE_PKTLOG) += -DFEATURE_PKTLOG + +ifeq ($(CONFIG_WLAN_NAPI), y) +cppflags-y += -DFEATURE_NAPI +cppflags-y += -DHIF_IRQ_AFFINITY +ifeq ($(CONFIG_WLAN_NAPI_DEBUG), y) +cppflags-y += -DFEATURE_NAPI_DEBUG +endif +endif + +ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM))) +cppflags-y += -DMSM_PLATFORM +endif + +cppflags-y += -DQCA_SUPPORT_TXRX_LOCAL_PEER_ID + +cppflags-$(CONFIG_WLAN_TX_FLOW_CONTROL_V2) += -DQCA_LL_TX_FLOW_CONTROL_V2 +cppflags-$(CONFIG_WLAN_TX_FLOW_CONTROL_V2) += -DQCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +cppflags-$(CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY) += -DQCA_LL_LEGACY_TX_FLOW_CONTROL +cppflags-$(CONFIG_WLAN_PDEV_TX_FLOW_CONTROL) += -DQCA_LL_PDEV_TX_FLOW_CONTROL + +ifeq ($(BUILD_DEBUG_VERSION), y) +cppflags-y += -DWLAN_DEBUG +ifeq ($(CONFIG_TRACE_RECORD_FEATURE), y) +cppflags-y += -DTRACE_RECORD \ + -DLIM_TRACE_RECORD \ + -DSME_TRACE_RECORD \ + -DHDD_TRACE_RECORD +endif +endif +cppflags-$(CONFIG_UNIT_TEST) += -DWLAN_UNIT_TEST +cppflags-$(CONFIG_WLAN_DEBUG_CRASH_INJECT) += -DCONFIG_WLAN_DEBUG_CRASH_INJECT +cppflags-$(CONFIG_FEATURE_UNIT_TEST_SUSPEND) += -DWLAN_SUSPEND_RESUME_TEST + +ifeq ($(CONFIG_LEAK_DETECTION), y) +cppflags-y += \ + -DCONFIG_HALT_KMEMLEAK \ + -DCONFIG_LEAK_DETECTION \ + -DMEMORY_DEBUG \ + -DNBUF_MEMORY_DEBUG \ + -DNBUF_MAP_UNMAP_DEBUG \ + -DTIMER_MANAGER +endif + +cppflags-y += -DWLAN_FEATURE_P2P +cppflags-y += -DWLAN_FEATURE_WFD +ifeq ($(CONFIG_QCOM_VOWIFI_11R), y) +cppflags-y += -DKERNEL_SUPPORT_11R_CFG80211 +cppflags-y += -DUSE_80211_WMMTSPEC_FOR_RIC +endif + +ifeq ($(CONFIG_QCOM_ESE), y) +cppflags-y += -DFEATURE_WLAN_ESE +cppflags-y += -DQCA_COMPUTE_TX_DELAY +cppflags-y += -DQCA_COMPUTE_TX_DELAY_PER_TID +endif + +#normally, TDLS negative behavior is not needed +cppflags-$(CONFIG_QCOM_TDLS) += -DFEATURE_WLAN_TDLS + +cppflags-$(CONFIG_QCACLD_WLAN_LFR3) += -DWLAN_FEATURE_ROAM_OFFLOAD + +cppflags-$(CONFIG_CNSS_GENL) += -DCNSS_GENL + +cppflags-$(CONFIG_QCACLD_WLAN_LFR2) += -DWLAN_FEATURE_HOST_ROAM + +cppflags-$(CONFIG_WLAN_POWER_DEBUGFS) += -DWLAN_POWER_DEBUGFS + +cppflags-$(CONFIG_WLAN_MWS_INFO_DEBUGFS) += -DWLAN_MWS_INFO_DEBUGFS + +# Enable object manager reference count debug infrastructure +cppflags-$(CONFIG_WLAN_OBJMGR_DEBUG) += -DWLAN_OBJMGR_DEBUG +cppflags-$(CONFIG_WLAN_OBJMGR_DEBUG) += -DWLAN_OBJMGR_REF_ID_DEBUG + +cppflags-$(CONFIG_WLAN_FEATURE_SAE) += -DWLAN_FEATURE_SAE + +ifeq ($(BUILD_DIAG_VERSION), y) +cppflags-y += -DFEATURE_WLAN_DIAG_SUPPORT +cppflags-y += -DFEATURE_WLAN_DIAG_SUPPORT_CSR +cppflags-y += -DFEATURE_WLAN_DIAG_SUPPORT_LIM +ifeq ($(CONFIG_HIF_PCI), y) +cppflags-y += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +endif +endif + +ifeq ($(CONFIG_HIF_USB), y) +cppflags-y += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +cppflags-y += -DQCA_SUPPORT_OL_RX_REORDER_TIMEOUT +cppflags-y += -DCONFIG_ATH_PCIE_MAX_PERF=0 -DCONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD=0 -DCONFIG_DISABLE_CDC_MAX_PERF_WAR=0 +endif + +cppflags-$(CONFIG_WLAN_FEATURE_11W) += -DWLAN_FEATURE_11W + +cppflags-$(CONFIG_QCA_TXDESC_SANITY_CHECKS) += -DQCA_SUPPORT_TXDESC_SANITY_CHECKS + +cppflags-$(CONFIG_QCOM_LTE_COEX) += -DFEATURE_WLAN_CH_AVOID + +cppflags-$(CONFIG_WLAN_FEATURE_LPSS) += -DWLAN_FEATURE_LPSS + +cppflags-$(CONFIG_DESC_DUP_DETECT_DEBUG) += -DDESC_DUP_DETECT_DEBUG +cppflags-$(CONFIG_DEBUG_RX_RING_BUFFER) += -DDEBUG_RX_RING_BUFFER + +cppflags-$(CONFIG_DESC_TIMESTAMP_DEBUG_INFO) += -DDESC_TIMESTAMP_DEBUG_INFO + +cppflags-$(PANIC_ON_BUG) += -DPANIC_ON_BUG + +cppflags-$(WLAN_WARN_ON_ASSERT) += -DWLAN_WARN_ON_ASSERT + +ccflags-$(CONFIG_POWER_MANAGEMENT_OFFLOAD) += -DWLAN_POWER_MANAGEMENT_OFFLOAD + +cppflags-$(CONFIG_WLAN_LOG_FATAL) += -DWLAN_LOG_FATAL +cppflags-$(CONFIG_WLAN_LOG_ERROR) += -DWLAN_LOG_ERROR +cppflags-$(CONFIG_WLAN_LOG_WARN) += -DWLAN_LOG_WARN +cppflags-$(CONFIG_WLAN_LOG_INFO) += -DWLAN_LOG_INFO +cppflags-$(CONFIG_WLAN_LOG_DEBUG) += -DWLAN_LOG_DEBUG + +cppflags-$(WLAN_OPEN_SOURCE) += -DWLAN_OPEN_SOURCE + +cppflags-$(CONFIG_FEATURE_STATS_EXT) += -DWLAN_FEATURE_STATS_EXT + +cppflags-$(CONFIG_QCACLD_FEATURE_NAN) += -DWLAN_FEATURE_NAN + +cppflags-$(CONFIG_QCA_IBSS_SUPPORT) += -DQCA_IBSS_SUPPORT +cppflags-$(CONFIG_FEATURE_BECN_STATS) += -DWLAN_FEATURE_BEACON_RECEPTION_STATS + +#Set RX_PERFORMANCE +cppflags-$(CONFIG_RX_PERFORMANCE) += -DRX_PERFORMANCE + +#Set SLUB_MEM_OPTIMIZE +cppflags-$(CONFIG_SLUB_MEM_OPTIMIZE) += -DSLUB_MEM_OPTIMIZE + +#Enable OL debug and wmi unified functions +cppflags-$(CONFIG_ATH_PERF_PWR_OFFLOAD) += -DATH_PERF_PWR_OFFLOAD + +#Disable packet log +cppflags-$(CONFIG_REMOVE_PKT_LOG) += -DREMOVE_PKT_LOG + +#Enable 11AC TX +cppflags-$(CONFIG_ATH_11AC_TXCOMPACT) += -DATH_11AC_TXCOMPACT + +#Enable PCI specific APIS (dma, etc) +cppflags-$(CONFIG_HIF_PCI) += -DHIF_PCI + +cppflags-$(CONFIG_HIF_SNOC) += -DHIF_SNOC + +#Enable High Latency related Flags +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +cppflags-y += -DCONFIG_HL_SUPPORT \ + -DCONFIG_AR6320_SUPPORT \ + -DSDIO_3_0 \ + -DHIF_SDIO \ + -DCONFIG_DISABLE_CDC_MAX_PERF_WAR=0 \ + -DCONFIG_ATH_PROCFS_DIAG_SUPPORT \ + -DFEATURE_HL_GROUP_CREDIT_FLOW_CONTROL \ + -DHIF_MBOX_SLEEP_WAR \ + -DDEBUG_HL_LOGGING \ + -DQCA_BAD_PEER_TX_FLOW_CL \ + -DCONFIG_TX_DESC_HI_PRIO_RESERVE \ + -DCONFIG_PER_VDEV_TX_DESC_POOL \ + -DCONFIG_SDIO \ + -DFEATURE_WLAN_FORCE_SAP_SCC +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +cppflags-y += -DWLAN_FEATURE_DSRC + +ifeq ($(CONFIG_OCB_UT_FRAMEWORK), y) +cppflags-y += -DWLAN_OCB_UT +endif + +endif + +cppflags-$(CONFIG_FEATURE_SKB_PRE_ALLOC) += -DFEATURE_SKB_PRE_ALLOC + +#Enable USB specific APIS +ifeq ($(CONFIG_HIF_USB), y) +cppflags-y += -DHIF_USB \ + -DCONFIG_PLD_USB_CNSS \ + -DDEBUG_HL_LOGGING \ + -DCONFIG_HL_SUPPORT +endif + +#Enable FW logs through ini +cppflags-y += -DCONFIG_FW_LOGS_BASED_ON_INI + +#Enable pci read/write config functions +cppflags-$(CONFIG_ATH_PCI) += -DATH_PCI + +#Enable power management suspend/resume functionality +cppflags-$(CONFIG_ATH_BUS_PM) += -DATH_BUS_PM + +#Enable FLOWMAC module support +cppflags-$(CONFIG_ATH_SUPPORT_FLOWMAC_MODULE) += -DATH_SUPPORT_FLOWMAC_MODULE + +#Enable spectral support +cppflags-$(CONFIG_ATH_SUPPORT_SPECTRAL) += -DATH_SUPPORT_SPECTRAL + +#Enable WDI Event support +cppflags-$(CONFIG_WDI_EVENT_ENABLE) += -DWDI_EVENT_ENABLE + +#Endianness selection +ifeq ($(CONFIG_LITTLE_ENDIAN), y) +cppflags-y += -DANI_LITTLE_BYTE_ENDIAN +cppflags-y += -DANI_LITTLE_BIT_ENDIAN +cppflags-y += -DDOT11F_LITTLE_ENDIAN_HOST +else +cppflags-y += -DANI_BIG_BYTE_ENDIAN +cppflags-y += -DBIG_ENDIAN_HOST +endif + +#Enable MWS COEX support for 4G quick TDM and 5G NR pwr limit +cppflags-y += -DMWS_COEX + +#Enable TX reclaim support +cppflags-$(CONFIG_TX_CREDIT_RECLAIM_SUPPORT) += -DTX_CREDIT_RECLAIM_SUPPORT + +#Enable FTM support +cppflags-$(CONFIG_QCA_WIFI_FTM) += -DQCA_WIFI_FTM + +#Enable Checksum Offload support +cppflags-$(CONFIG_CHECKSUM_OFFLOAD) += -DCHECKSUM_OFFLOAD + +#Enable Checksum Offload support +cppflags-$(CONFIG_IPA_OFFLOAD) += -DIPA_OFFLOAD + +ifeq ($(CONFIG_ARCH_SDX20), y) +cppflags-y += -DSYNC_IPA_READY +endif + +#Enable wbuff +cppflags-$(CONFIG_WLAN_WBUFF) += -DWLAN_FEATURE_WBUFF + +#Enable GTK Offload +cppflags-$(CONFIG_GTK_OFFLOAD) += -DWLAN_FEATURE_GTK_OFFLOAD + +#Enable External WoW +cppflags-$(CONFIG_EXT_WOW) += -DWLAN_FEATURE_EXTWOW_SUPPORT + +#Mark it as SMP Kernel +cppflags-$(CONFIG_SMP) += -DQCA_CONFIG_SMP + +cppflags-$(CONFIG_CHNL_MATRIX_RESTRICTION) += -DWLAN_ENABLE_CHNL_MATRIX_RESTRICTION + +#Enable ICMP packet disable powersave feature +cppflags-$(CONFIG_ICMP_DISABLE_PS) += -DWLAN_ICMP_DISABLE_PS + +#Enable OBSS feature +cppflags-y += -DQCA_HT_2040_COEX + +#enable MCC TO SCC switch +cppflags-$(CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH) += -DFEATURE_WLAN_MCC_TO_SCC_SWITCH + +#enable wlan auto shutdown feature +cppflags-$(CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN) += -DFEATURE_WLAN_AUTO_SHUTDOWN + +#enable AP-AP ACS Optimization +cppflags-$(CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE) += -DFEATURE_WLAN_AP_AP_ACS_OPTIMIZE + +#Enable 4address scheme +cppflags-$(CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME) += -DFEATURE_WLAN_STA_4ADDR_SCHEME + +#enable MDM/SDX special config +cppflags-$(CONFIG_MDM_PLATFORM) += -DMDM_PLATFORM + +#Disable STA-AP Mode DFS support +cppflags-$(CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) += -DFEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + +#Open P2P device interface only for non-Mobile router use cases +cppflags-$(CONFIG_WLAN_OPEN_P2P_INTERFACE) += -DWLAN_OPEN_P2P_INTERFACE + +#Enable 2.4 GHz social channels in 5 GHz only mode for p2p usage +cppflags-$(CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY) += -DWLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + +#Green AP feature +cppflags-$(CONFIG_QCACLD_FEATURE_GREEN_AP) += -DWLAN_SUPPORT_GREEN_AP + +cppflags-$(CONFIG_QCACLD_FEATURE_APF) += -DFEATURE_WLAN_APF + +cppflags-$(CONFIG_WLAN_FEATURE_SARV1_TO_SARV2) += -DWLAN_FEATURE_SARV1_TO_SARV2 +cppflags-$(CONFIG_WLAN_SYSFS) += -DWLAN_SYSFS + +#Stats & Quota Metering feature +ifeq ($(CONFIG_IPA_OFFLOAD), y) +ifeq ($(CONFIG_QCACLD_FEATURE_METERING), y) +cppflags-y += -DFEATURE_METERING +endif +endif + +cppflags-$(CONFIG_TUFELLO_DUAL_FW_SUPPORT) += -DCONFIG_TUFELLO_DUAL_FW_SUPPORT +cppflags-$(CONFIG_CHANNEL_HOPPING_ALL_BANDS) += -DCHANNEL_HOPPING_ALL_BANDS + +#Enable Signed firmware support for split binary format +cppflags-$(CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT) += -DQCA_SIGNED_SPLIT_BINARY_SUPPORT + +#Enable single firmware binary format +cppflags-$(CONFIG_QCA_SINGLE_BINARY_SUPPORT) += -DQCA_SINGLE_BINARY_SUPPORT + +#Enable collecting target RAM dump after kernel panic +cppflags-$(CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC) += -DTARGET_RAMDUMP_AFTER_KERNEL_PANIC + +#Enable/disable secure firmware feature +cppflags-$(CONFIG_FEATURE_SECURE_FIRMWARE) += -DFEATURE_SECURE_FIRMWARE + +cppflags-$(CONFIG_ATH_PCIE_ACCESS_DEBUG) += -DCONFIG_ATH_PCIE_ACCESS_DEBUG + +# Enable feature support for Linux version QCMBR +cppflags-$(CONFIG_LINUX_QCMBR) += -DLINUX_QCMBR + +# Enable feature sync tsf between multi devices +cppflags-$(CONFIG_WLAN_SYNC_TSF) += -DWLAN_FEATURE_TSF +cppflags-$(CONFIG_WLAN_SYNC_TSF_PLUS) += -DWLAN_FEATURE_TSF_PLUS +# Enable feature sync tsf for chips based on Adrastea arch +cppflags-$(CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ) += -DWLAN_FEATURE_TSF_PLUS_NOIRQ + +cppflags-$(CONFIG_ATH_PROCFS_DIAG_SUPPORT) += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT + +cppflags-$(CONFIG_HELIUMPLUS) += -DHELIUMPLUS +cppflags-$(CONFIG_RX_OL) += -DRECEIVE_OFFLOAD +cppflags-$(CONFIG_TX_TID_OVERRIDE) += -DATH_TX_PRI_OVERRIDE +cppflags-$(CONFIG_AR900B) += -DAR900B +cppflags-$(CONFIG_HTT_PADDR64) += -DHTT_PADDR64 +cppflags-$(CONFIG_OL_RX_INDICATION_RECORD) += -DOL_RX_INDICATION_RECORD +cppflags-$(CONFIG_TSOSEG_DEBUG) += -DTSOSEG_DEBUG + +cppflags-$(CONFIG_ENABLE_DEBUG_ADDRESS_MARKING) += -DENABLE_DEBUG_ADDRESS_MARKING +cppflags-$(CONFIG_FEATURE_TSO) += -DFEATURE_TSO +cppflags-$(CONFIG_FEATURE_TSO_DEBUG) += -DFEATURE_TSO_DEBUG + +cppflags-$(CONFIG_WLAN_LRO) += -DFEATURE_LRO + +cppflags-$(CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE) += -DFEATURE_AP_MCC_CH_AVOIDANCE + +cppflags-$(CONFIG_MPC_UT_FRAMEWORK) += -DMPC_UT_FRAMEWORK + +cppflags-$(CONFIG_FEATURE_EPPING) += -DWLAN_FEATURE_EPPING + +cppflags-$(CONFIG_WLAN_OFFLOAD_PACKETS) += -DWLAN_FEATURE_OFFLOAD_PACKETS + +cppflags-$(CONFIG_WLAN_FEATURE_DISA) += -DWLAN_FEATURE_DISA + +cppflags-$(CONFIG_WLAN_FEATURE_ACTION_OUI) += -DWLAN_FEATURE_ACTION_OUI + +cppflags-$(CONFIG_WLAN_FEATURE_FIPS) += -DWLAN_FEATURE_FIPS + +cppflags-$(CONFIG_LFR_SUBNET_DETECTION) += -DFEATURE_LFR_SUBNET_DETECTION + +cppflags-$(CONFIG_MCC_TO_SCC_SWITCH) += -DFEATURE_WLAN_MCC_TO_SCC_SWITCH + +cppflags-$(CONFIG_WLAN_FEATURE_NAN_DATAPATH) += -DWLAN_FEATURE_NAN_DATAPATH + +cppflags-$(CONFIG_NAN_CONVERGENCE) += -DWLAN_FEATURE_NAN_CONVERGENCE + +cppflags-$(CONFIG_FEATURE_WLAN_D0WOW) += -DFEATURE_WLAN_D0WOW + +cppflags-$(CONFIG_QCA_WIFI_NAPIER_EMULATION) += -DQCA_WIFI_NAPIER_EMULATION +cppflags-$(CONFIG_SHADOW_V2) += -DCONFIG_SHADOW_V2 +cppflags-$(CONFIG_QCA6290_HEADERS_DEF) += -DQCA6290_HEADERS_DEF +cppflags-$(CONFIG_QCA_WIFI_QCA6290) += -DQCA_WIFI_QCA6290 +cppflags-$(CONFIG_QCA_WIFI_QCA8074) += -DQCA_WIFI_QCA8074 +cppflags-$(CONFIG_QCA_WIFI_QCA8074_VP) += -DQCA_WIFI_QCA8074_VP +cppflags-$(CONFIG_DP_INTR_POLL_BASED) += -DDP_INTR_POLL_BASED +cppflags-$(CONFIG_TX_PER_PDEV_DESC_POOL) += -DTX_PER_PDEV_DESC_POOL +cppflags-$(CONFIG_DP_TRACE) += -DCONFIG_DP_TRACE +cppflags-$(CONFIG_FEATURE_TSO) += -DFEATURE_TSO +cppflags-$(CONFIG_TSO_DEBUG_LOG_ENABLE) += -DTSO_DEBUG_LOG_ENABLE +cppflags-$(CONFIG_DP_LFR) += -DDP_LFR +cppflags-$(CONFIG_HTT_PADDR64) += -DHTT_PADDR64 + +ifeq ($(CONFIG_QCA6290_11AX), y) +cppflags-y += -DQCA_WIFI_QCA6290_11AX +endif + +cppflags-$(CONFIG_WLAN_FEATURE_11AX) += -DWLAN_FEATURE_11AX +cppflags-$(CONFIG_WLAN_FEATURE_11AX) += -DWLAN_FEATURE_11AX_BSS_COLOR + +# Dummy flag for WIN/MCL converged data path compilation +cppflags-y += -DDP_PRINT_ENABLE=0 +cppflags-y += -DATH_SUPPORT_WRAP=0 +cppflags-y += -DQCA_HOST2FW_RXBUF_RING +#endof dummy flags + +# Enable lock of serialization component to avoid race condition issues +cppflags-y += -DWLAN_CMD_SERIALIZATION_LOCKING + +ccflags-$(CONFIG_ENABLE_SIZE_OPTIMIZE) += -Os + +# DFS component +cppflags-y += -DWLAN_DFS_STATIC_MEM_ALLOC +cppflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DQCA_MCL_DFS_SUPPORT +ifeq ($(CONFIG_WLAN_FEATURE_DFS_OFFLOAD), y) +cppflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DWLAN_DFS_FULL_OFFLOAD +else +cppflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DWLAN_DFS_PARTIAL_OFFLOAD +endif +cppflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DDFS_COMPONENT_ENABLE +cppflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DQCA_DFS_USE_POLICY_MANAGER +cppflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DQCA_DFS_NOL_PLATFORM_DRV_SUPPORT + +cppflags-$(CONFIG_WLAN_DEBUGFS) += -DWLAN_DEBUGFS + +cppflags-$(CONFIG_DYNAMIC_DEBUG) += -DFEATURE_MULTICAST_HOST_FW_MSGS + +cppflags-$(CONFIG_ENABLE_SMMU_S1_TRANSLATION) += -DENABLE_SMMU_S1_TRANSLATION + +#Flag to enable/disable MTRACE feature +cppflags-$(CONFIG_ENABLE_MTRACE_LOG) += -DENABLE_MTRACE_LOG + +#Flag to enable NUD tracking +cppflags-$(CONFIG_WLAN_NUD_TRACKING) += -DWLAN_NUD_TRACKING + +#Flag to enable set and get disable channel list feature +cppflags-$(CONFIG_DISABLE_CHANNEL_LIST) += -DDISABLE_CHANNEL_LIST + +#Flag to enable set coex configuration feature +cppflags-$(CONFIG_QCACLD_FEATURE_COEX_CONFIG) += -DFEATURE_COEX_CONFIG + +#Flag to enable MPTA helper feature +cppflags-$(CONFIG_QCACLD_FEATURE_MPTA_HELPER) += -DFEATURE_MPTA_HELPER + +#Flag to enable get hw capability +cppflags-$(CONFIG_QCACLD_FEATURE_HW_CAPABILITY) += -DFEATURE_HW_CAPABILITY + +ifdef CONFIG_SCHED_HISTORY_SIZE +ccflags-y += -DWLAN_SCHED_HISTORY_SIZE=$(CONFIG_SCHED_HISTORY_SIZE) +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_TGT_NUM_MSDU_DESC +ccflags-y += -DCFG_TGT_NUM_MSDU_DESC=$(CONFIG_TGT_NUM_MSDU_DESC) +endif + +KBUILD_CPPFLAGS += $(cppflags-y) + +# 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. +ifneq ($(MODNAME), wlan) +CHIP_NAME ?= $(MODNAME) +ccflags-y += -DMULTI_IF_NAME=\"$(CHIP_NAME)\" +endif + +# 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 + +# 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 "," -) + +TIMESTAMP = $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') +BUILD_TAG = "$(TIMESTAMP); cld:$(CLD_IDS); cmn:$(CMN_IDS);" +# It's assumed that BUILD_TAG is used only in wlan_hdd_main.c +CFLAGS_wlan_hdd_main.o += -DBUILD_TAG=\"$(BUILD_TAG)\" +endif + +# Module information used by KBuild framework +obj-$(CONFIG_QCA_CLD_WLAN) += $(MODNAME).o +$(MODNAME)-y := $(OBJS) +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/drivers/staging/qcacld-3.0/Kconfig b/drivers/staging/qcacld-3.0/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..bb65a842cdc8d0870952ec94946d9c9bc1cf6252 --- /dev/null +++ b/drivers/staging/qcacld-3.0/Kconfig @@ -0,0 +1,159 @@ +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 QCACLD_WLAN_LFR3 + bool "Enable the WLAN Legacy Fast Roaming feature Version 3" + default n + +config PRIMA_WLAN_OKC + bool "Enable the Prima WLAN Opportunistic Key Caching feature" + default n + +config WLAN_FEATURE_11W + bool "Enable the WLAN 802.11w Protected Management Frames feature" + default n + +config WLAN_FEATURE_LPSS + bool "Enable the WLAN LPSS feature" + default n + +config QCOM_VOWIFI_11R + bool "Enable Fast Transition (11r) feature" + default n + +config QCACLD_FEATURE_NAN + bool "Enable NAN feature" + default n + +config WLAN_FEATURE_NAN_DATAPATH + bool "Enable NaN Data Path feature" + depends on QCACLD_FEATURE_NAN + default n + +config QCACLD_FEATURE_GREEN_AP + bool "Enable Green AP feature" + default n + +config HELIUMPLUS + bool "Enable Beeliner based descriptor structures for Helium" + default n + +config 64BIT_PADDR + bool "Enable 37-bit physical/bus addresses" + depends on HELIUMPLUS + default n + +config QCOM_TDLS + bool "Enable TDLS feature" + default n + +config QCOM_LTE_COEX + bool "Enable QCOM LTE Coex feature" + default n + +config MPC_UT_FRAMEWORK + bool "Enable Unit test framework for multiport concurrency" + default n + +config WLAN_OFFLOAD_PACKETS + bool "Enable offload packets feature" + default n + +config FEATURE_TSO + bool "Enable TCP Segmentation Offload" + depends on HELIUMPLUS + default n + +config FEATURE_TSO_DEBUG + bool "Enable TCP Segmentation Offload with debug" + depends on FEATURE_TSO + default n + +config WLAN_FASTPATH + bool "Enable fastpath for datapackets" + 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_TX_FLOW_CONTROL_V2 + bool "Enable tx flow control version:2" + default n + +config WLAN_LRO + bool "Enable Large Receive Offload" + depends on HELIUMPLUS + depends on INET_LRO + default n + +config WLAN_SYNC_TSF + bool "Enable QCOM sync multi devices tsf feature" + default n + +config LFR_SUBNET_DETECTION + bool "Enable LFR Subnet Change Detection" + default n + +config MCC_TO_SCC_SWITCH + bool "Enable MCC to SCC Switch Logic" + default n + +config QCACLD_WLAN_LFR2 + bool "Enable the WLAN Legacy Fast Roaming feature Version 2" + default n + +config WLAN_FEATURE_DISA + bool "Enable DISA certification feature" + default n + +config WLAN_FEATURE_FIPS + bool "Enable FIPS certification feature" + default n + +config WLAN_FEATURE_11AX + bool "Enable 11AX(High Efficiency) feature" + default n + +config ICMP_DISABLE_PS + bool "Enable ICMP packet disable powersave feature" + default n + +config BUILD_TIMESTAMP + bool "Embed timestamp in wlan version" + default n + +config WLAN_FEATURE_FILS + bool "Enable FILS feature" + default n + +config NAN_CONVERGENCE + bool "Enable NAN_CONVERGENCE feature" + default n + +config WLAN_OBJMGR_DEBUG + bool "Enable WLAN Obj Mgr Debug services" + default n + +config WLAN_FEATURE_DFS_OFFLOAD + bool "Enable dfs offload feature" + default n + +config WLAN_FEATURE_SARV1_TO_SARV2 + bool "Enable conversion of SAR v1 to v2 feature" + default n + +endif # QCA_CLD_WLAN diff --git a/drivers/staging/qcacld-3.0/Makefile b/drivers/staging/qcacld-3.0/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..fb78b03460b63dda2857e34c76e0ae2470f7f797 --- /dev/null +++ b/drivers/staging/qcacld-3.0/Makefile @@ -0,0 +1,32 @@ +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) + +# WLAN_ROOT must contain an absolute path (i.e. not a relative path) +KBUILD_OPTIONS := WLAN_ROOT=$(shell cd $(KERNEL_SRC); readlink -e $(M)) +KBUILD_OPTIONS += MODNAME?=wlan + +#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 + +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/drivers/staging/qcacld-3.0/README.txt b/drivers/staging/qcacld-3.0/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..bdf3e7a7adc4eaf2883ac235c8ad755f3552a88f --- /dev/null +++ b/drivers/staging/qcacld-3.0/README.txt @@ -0,0 +1 @@ +This is CNSS WLAN Host Driver for products starting from iHelium diff --git a/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_main.h b/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_main.h new file mode 100644 index 0000000000000000000000000000000000000000..7777476a62b5b493d7c040e23177adb4fb93f222 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_main.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: 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); + +#endif /* end of _WLAN_ACTION_OUI_MAIN_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_objmgr.h b/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_objmgr.h new file mode 100644 index 0000000000000000000000000000000000000000..17d0b09c8979c25e6465a115f116cfedd10330a6 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_priv.h b/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..2b325b4ae865ff22a8ef0810b2787c6ea51912fe --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_priv.h @@ -0,0 +1,147 @@ +/* + * 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: 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 + * @total_extensions: total count of extensions from all actions + * @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; + uint32_t total_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 + * @ation_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_send() - Send action oui extensions to target_if. + * @psoc_priv: pointer to action_oui psoc priv obj + * @ation_id: type of the action to be 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); + +#endif /* End of _WLAN_ACTION_OUI_PRIV_STRUCT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_main.c b/drivers/staging/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_main.c new file mode 100644 index 0000000000000000000000000000000000000000..825b989a16282e3668c505704a90abfd52666819 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_main.c @@ -0,0 +1,199 @@ +/* + * 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: Implement various notification handlers which are 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" + +/** + * 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; + 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; + } +} + +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) { + action_oui_err("Failed to allocate 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; + + status = action_oui_allocate(psoc_priv); + if (!QDF_IS_STATUS_SUCCESS(status)) { + action_oui_err("Failed to alloc action_oui"); + goto detach_psoc_priv; + } + + action_oui_debug("psoc priv attached"); + goto exit; + +detach_psoc_priv: + wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_ACTION_OUI, + (void *)psoc_priv); +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"); + + action_oui_destroy(psoc_priv); + qdf_mem_free(psoc_priv); + +exit: + ACTION_OUI_EXIT(); + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_parse.c b/drivers/staging/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_parse.c new file mode 100644 index 0000000000000000000000000000000000000000..347efc35c76313d8137000876582e06c8eaad40f --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_parse.c @@ -0,0 +1,977 @@ +/* + * 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: 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 + */ +#ifdef WLAN_DEBUG +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"; +} +#endif + +/** + * 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 is more than %u", + 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 + * @priv_obj: 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); + action_oui_err("Failed to allocate memory for action oui extension priv"); + 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; + } + + str1 = qdf_str_trim((char *)oui_string); + + while (str1) { + str2 = skip_spaces(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; + } + + 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_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; + + 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 QDF_STATUS_SUCCESS; + } + + no_oui_extensions = qdf_list_size(extension_list); + len = sizeof(*req) + no_oui_extensions * sizeof(*extension); + req = qdf_mem_malloc(len); + if (!req) { + action_oui_err("Failed to allocate memory for action_oui"); + 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->total_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) { + if ((*extension->capability & + ACTION_OUI_CAPABILITY_2G_BAND_MASK) && + !attr->enable_2g) + return false; + if ((*extension->capability & + ACTION_CAPABILITY_5G_BAND_MASK) && + !attr->enable_5g) + 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_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); + action_oui_debug("OUI List Empty"); + 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)) { + action_oui_debug("Wildcard OUI found"); + wildcard_oui = true; + } + + oui_ptr = action_oui_get_oui_ptr(extension, attr); + + if (!oui_ptr && !wildcard_oui) { + action_oui_debug("No matching IE found for OUI"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + extension->oui, + extension->oui_length); + goto next; + } + + action_oui_debug("IE found for OUI"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + extension->oui, + extension->oui_length); + + if (extension->data_length && !wildcard_oui && + !check_for_vendor_oui_data(extension, oui_ptr)) { + action_oui_debug("Vendor IE Data mismatch"); + goto next; + } + + if ((extension->info_mask & ACTION_OUI_INFO_MAC_ADDRESS) && + !check_for_vendor_ap_mac(extension, attr)) { + action_oui_debug("Vendor IE MAC Mismatch"); + goto next; + } + + if (!check_for_vendor_ap_capabilities(extension, attr)) { + action_oui_debug("Vendor IE capabilties mismatch"); + 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/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..817c1836e0be7b1758c5976c9a2f5cc8c0fb83ed --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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 + +#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 + +/** + * 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_MAXIMUM_ID: maximun 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_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[0]; +}; + +/** + * 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/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_tgt_api.h b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_tgt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..7a1d4f30802ffb0079cf9bc79fd16d06ee2c9176 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_ucfg_api.h b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_ucfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..00daeb9b66d65a732c3486e017709483c56ae514 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_ucfg_api.h @@ -0,0 +1,210 @@ +/* + * 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: 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_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 + * + * Return: When action_oui component is present return true + * else return false. + */ +static inline bool ucfg_action_oui_enabled(void) +{ + return true; +} + +/** + * 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); + +#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_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; +} + +#endif /* WLAN_FEATURE_ACTION_OUI */ + +#endif /* _WLAN_ACTION_OUI_UCFG_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_tgt_api.c b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_tgt_api.c new file mode 100644 index 0000000000000000000000000000000000000000..e3c2177d852819eab99194c5fcd4fa57ca4f73d0 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_ucfg_api.c b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_ucfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..f6d31f9191da40a0b2929d8ce0bc91acad6a70cc --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_ucfg_api.c @@ -0,0 +1,200 @@ +/* + * 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: 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 "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(); +} + +QDF_STATUS +ucfg_action_oui_parse(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) { + action_oui_err("Mem alloc failed for string: %u", action_id); + 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 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; + + 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; + } + + for (id = 0; id < ACTION_OUI_MAXIMUM_ID; id++) { + status = action_oui_send(psoc_priv, id); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_err("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) +{ + struct action_oui_psoc_priv *psoc_priv; + bool found = false; + + ACTION_OUI_ENTER(); + + 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); + if (found) + action_oui_debug("Search Successful"); + +exit: + ACTION_OUI_EXIT(); + return found; +} diff --git a/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_main.h b/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_main.h new file mode 100644 index 0000000000000000000000000000000000000000..26caad4b707fe2644946059ab337088cb97c4b44 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_main.h @@ -0,0 +1,87 @@ +/* + * 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 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_log(level, args...) QDF_TRACE(QDF_MODULE_ID_DISA, level, ## args) +#define disa_logfl(level, format, args...) disa_log(level, FL(format), ## args) + +#define disa_fatal(format, args...) \ + disa_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define disa_err(format, args...) \ + disa_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define disa_warn(format, args...) \ + disa_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define disa_info(format, args...) \ + disa_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define disa_debug(format, args...) \ + disa_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define DISA_ENTER() disa_debug("enter") +#define DISA_EXIT() disa_debug("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 + * + * 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/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_objmgr.h b/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_objmgr.h new file mode 100644 index 0000000000000000000000000000000000000000..6bb497741a6c5f175276ee4015f455300f8bcad6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_objmgr.h @@ -0,0 +1,192 @@ +/* + * 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_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/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_priv.h b/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..010d82f08d253f7d8b72517910134d7a584b0e15 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/disa/core/inc/wlan_disa_priv.h @@ -0,0 +1,59 @@ +/* + * 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 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 + * @disa_psoc_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 + * @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/drivers/staging/qcacld-3.0/components/disa/core/src/wlan_disa_main.c b/drivers/staging/qcacld-3.0/components/disa/core/src/wlan_disa_main.c new file mode 100644 index 0000000000000000000000000000000000000000..73033944d732898d5d384eddf997f92fd7539416 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/disa/core/src/wlan_disa_main.c @@ -0,0 +1,107 @@ +/* + * 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: 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 != NULL) { + 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) { + disa_err("unable to allocate disa_ctx"); + QDF_ASSERT(0); + 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/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_api.h b/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..12a689a699119767f10246727b1a8f0e4a0a9034 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_public_struct.h b/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..76aae8163d82d5aa721c3c423c53c4611bf733f4 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_public_struct.h b/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..1c30f853166775b9227af5e7071aee5a34bc437a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_public_struct.h @@ -0,0 +1,85 @@ +/* + * 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 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_length: 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 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/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_tgt_api.h b/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_tgt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..39887079ecca1f0c011de2cbf6a5000cc0c6ba46 --- /dev/null +++ b/drivers/staging/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_VDEV(vedv) \ + (&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/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_ucfg_api.h b/drivers/staging/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_ucfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b9c8206d3582438b1a24dbfae14a744820dabee9 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_obj_mgmt_api.c b/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_obj_mgmt_api.c new file mode 100644 index 0000000000000000000000000000000000000000..7c6a1feca270ea07c5a23afc27da04f31c7761bc --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_obj_mgmt_api.c @@ -0,0 +1,210 @@ +/* + * 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: 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 == NULL) { + disa_err("Failed to allocate 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/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_tgt_api.c b/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_tgt_api.c new file mode 100644 index 0000000000000000000000000000000000000000..5576ff1b601f29a7c3d0767e72d72622804ac4e8 --- /dev/null +++ b/drivers/staging/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_VDEV(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_VDEV(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_VDEV(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/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_ucfg_api.c b/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_ucfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..e93c707ad8e303b6586dfd6a4fd5741740af7e31 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_ucfg_api.c @@ -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: public API related to the disa called by north bound HDD/OSIF + */ + +#include "wlan_disa_ucfg_api.h" +#include "wlan_disa_main.h" + +/** + * ucfg_disa_encrypt_decrypt_req() - Send encrypt/decrypt request to the DISA + * core + * @psoc: objmgr psoc object + * @req: DISA encrypt/decrypt request parameters + * + * 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) +{ + return disa_core_encrypt_decrypt_req(psoc, req, cb, cookie); +} + + diff --git a/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_core.h b/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_core.h new file mode 100644 index 0000000000000000000000000000000000000000..0ad5b30037fe30b8c20293bf8de4f8ed779f113e --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_core.h @@ -0,0 +1,664 @@ +/* + * 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 _WLAN_IPA_CORE_H_ +#define _WLAN_IPA_CORE_H_ + +#ifdef IPA_OFFLOAD + +#include "wlan_ipa_priv.h" +#include "wlan_ipa_public_struct.h" + +/** + * wlan_ipa_is_enabled() - Is IPA enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA is enabled, false otherwise + */ +static inline bool wlan_ipa_is_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_ENABLE_MASK); +} + +/** + * wlan_ipa_uc_is_enabled() - Is IPA UC enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA UC is enabled, false otherwise + */ +static inline bool wlan_ipa_uc_is_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_ENABLE_MASK); +} + +/** + * wlan_ipa_is_rm_enabled() - Is IPA RM enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA RM is enabled, false otherwise + */ +static inline bool wlan_ipa_is_rm_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_RM_ENABLE_MASK); +} + +/** + * wlan_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA RM is enabled, false otherwise + */ +static inline +bool wlan_ipa_is_clk_scaling_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, + WLAN_IPA_CLK_SCALING_ENABLE_MASK | + WLAN_IPA_RM_ENABLE_MASK); +} + +/** + * wlan_ipa_is_rt_debugging_enabled() - Is IPA RT debugging enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPA RT debugging is enabled, false otherwise + */ +static inline +bool wlan_ipa_is_rt_debugging_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, + WLAN_IPA_REAL_TIME_DEBUGGING); +} + +/** + * wlan_ipa_setup - IPA initialize and setup + * @ipa_ctx: IPA priv obj + * @ipa_cfg: IPA config + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_config *ipa_cfg); + +/** + * wlan_ipa_get_obj_context - Get IPA OBJ context + * + * Return: IPA context + */ +struct wlan_ipa_priv *wlan_ipa_get_obj_context(void); + +/** + * wlan_ipa_cleanup - IPA cleanup + * @ipa_ctx: IPA priv obj + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_enable_pipes() - Enable IPA uC pipes + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_disable_pipes() - Disable IPA uC pipes + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_set_perf_level() - Set IPA performance level + * @ipa_ctx: IPA context + * @tx_packets: Number of packets transmitted in the last sample period + * @rx_packets: Number of packets received in the last sample period + * + * Return: QDF STATUS + */ +QDF_STATUS wlan_ipa_set_perf_level(struct wlan_ipa_priv *ipa_ctx, + uint64_t tx_packets, uint64_t rx_packets); + +/** + * wlan_ipa_init_perf_level() - Initialize IPA performance level + * @ipa_ctx: IPA context + * + * If IPA clock scaling is disabled, initialize perf level to maximum. + * Else set the lowest level to start with. + * + * Return: QDF STATUS + */ +QDF_STATUS wlan_ipa_init_perf_level(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_get_iface() - Get IPA interface + * @ipa_ctx: IPA context + * @mode: Interface device mode + * + * Return: IPA interface address + */ +struct wlan_ipa_iface_context +*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode); + +#ifndef CONFIG_IPA_WDI_UNIFIED_API +/** + * wlan_ipa_wdi_rm_request_resource() - IPA WDI request resource + * @ipa_ctx: IPA context + * @res_name: IPA RM resource name + * + * Return: 0 on success, negative errno on error + */ +static inline +int wlan_ipa_wdi_rm_request_resource(struct wlan_ipa_priv *ipa_ctx, + qdf_ipa_rm_resource_name_t res_name) +{ + return qdf_ipa_rm_request_resource(res_name); +} + +/** + * wlan_ipa_wdi_rm_release_resource() - IPA WDI release resource + * @ipa_ctx: IPA context + * @res_name: IPA RM resource name + * + * Return: 0 on success, negative errno on error + */ +static inline +int wlan_ipa_wdi_rm_release_resource(struct wlan_ipa_priv *ipa_ctx, + qdf_ipa_rm_resource_name_t res_name) +{ + return qdf_ipa_rm_release_resource(res_name); +} + +/** + * wlan_ipa_wdi_rm_request() - Request resource from IPA + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_wdi_rm_request(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_wdi_rm_try_release() - Attempt to release IPA resource + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_wdi_rm_try_release(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_wdi_setup_rm() - Setup IPA resource management + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_wdi_setup_rm(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_wdi_destroy_rm() - Destroy IPA resources + * @ipa_ctx: IPA context + * + * Destroys all resources associated with the IPA resource manager + * + * Return: None + */ +void wlan_ipa_wdi_destroy_rm(struct wlan_ipa_priv *ipa_ctx); + +static inline +int wlan_ipa_wdi_rm_notify_completion(qdf_ipa_rm_event_t event, + qdf_ipa_rm_resource_name_t res_name) +{ + return qdf_ipa_rm_notify_completion(event, res_name); +} + +static inline +int wlan_ipa_wdi_rm_inactivity_timer_destroy( + qdf_ipa_rm_resource_name_t res_name) +{ + return qdf_ipa_rm_inactivity_timer_destroy(res_name); +} + +bool wlan_ipa_is_rm_released(struct wlan_ipa_priv *ipa_ctx); + +#else /* CONFIG_IPA_WDI_UNIFIED_API */ + +static inline int wlan_ipa_wdi_rm_request_resource( + struct wlan_ipa_priv *ipa_ctx, + qdf_ipa_rm_resource_name_t res_name) +{ + return 0; +} + +static inline int wlan_ipa_wdi_rm_release_resource( + struct wlan_ipa_priv *ipa_ctx, + qdf_ipa_rm_resource_name_t res_name) +{ + return 0; +} + +static inline QDF_STATUS wlan_ipa_wdi_setup_rm(struct wlan_ipa_priv *ipa_ctx) +{ + return 0; +} + +static inline int wlan_ipa_wdi_destroy_rm(struct wlan_ipa_priv *ipa_ctx) +{ + return 0; +} + +static inline QDF_STATUS wlan_ipa_wdi_rm_request(struct wlan_ipa_priv *ipa_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlan_ipa_wdi_rm_try_release(struct wlan_ipa_priv + *ipa_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +int wlan_ipa_wdi_rm_notify_completion(qdf_ipa_rm_event_t event, + qdf_ipa_rm_resource_name_t res_name) +{ + return 0; +} + +static inline +int wlan_ipa_wdi_rm_inactivity_timer_destroy( + qdf_ipa_rm_resource_name_t res_name) +{ + return 0; +} + +static inline +bool wlan_ipa_is_rm_released(struct wlan_ipa_priv *ipa_ctx) +{ + return true; +} + +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ + +#ifdef FEATURE_METERING + +/** + * wlan_ipa_uc_op_metering() - IPA uC operation for stats and quota limit + * @ipa_ctx: IPA context + * @op_msg: operation message received from firmware + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx, + struct op_msg_type *op_msg); + +/** + * wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for + * __wlan_ipa_wdi_meter_notifier_cb + * @priv: pointer to private data registered with IPA (we register a + * pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt, + void *data); + +/** + * wlan_ipa_init_metering() - IPA metering stats completion event reset + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS enumeration + */ +void wlan_ipa_init_metering(struct wlan_ipa_priv *ipa_ctx); +#else + +static inline +QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx, + struct op_msg_type *op_msg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void wlan_ipa_wdi_meter_notifier_cb(void) +{ +} + +static inline void wlan_ipa_init_metering(struct wlan_ipa_priv *ipa_ctx) +{ +} +#endif /* FEATURE_METERING */ + +/** + * wlan_ipa_uc_stat() - Print IPA uC stats + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_uc_stat(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_info() - Print IPA uC resource and session information + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_uc_info(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_print_fw_wdi_stats() - Print FW IPA WDI stats + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_print_fw_wdi_stats(struct wlan_ipa_priv *ipa_ctx, + struct ipa_uc_fw_stats *uc_fw_stat); + +/** + * wlan_ipa_uc_stat_request() - Get IPA stats from IPA + * @ipa_ctx: IPA context + * @reason: STAT REQ Reason + * + * Return: None + */ +void wlan_ipa_uc_stat_request(struct wlan_ipa_priv *ipa_ctx, uint8_t reason); + +/** + * wlan_ipa_uc_stat_query() - Query the IPA stats + * @ipa_ctx: IPA context + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: None + */ +void wlan_ipa_uc_stat_query(struct wlan_ipa_priv *ipa_ctx, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff); + +/** + * wlan_ipa_dump_info() - dump IPA IPA struct + * @ipa_ctx: IPA context + * + * Dump entire struct ipa_ctx + * + * Return: none + */ +void wlan_ipa_dump_info(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_rt_debug_host_dump - dump rt debug buffer + * @ipa_ctx: IPA context + * + * If rt debug enabled, dump debug buffer contents based on requirement + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_host_dump(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_rt_debug_destructor() - called by data packet free + * @nbuff: packet pinter + * + * when free data packet, will be invoked by wlan client and will increase + * free counter + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_destructor(qdf_nbuf_t nbuff); + +/** + * wlan_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging + * @ipa_ctx: IPA context + * + * free all rt debugging resources + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_deinit(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_rt_debug_init() - initialize resources to handle rt debugging + * @ipa_ctx: IPA context + * + * alloc and initialize all rt debugging resources + * + * Return: none + */ +void wlan_ipa_uc_rt_debug_init(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_reg_sap_xmit_cb() - Register upper layer SAP cb to transmit + * @ipa_ctx: IPA context + * @cb: callback + * + * Return: None + */ +static inline +void wlan_ipa_reg_sap_xmit_cb(struct wlan_ipa_priv *ipa_ctx, + wlan_ipa_softap_xmit cb) +{ + ipa_ctx->softap_xmit = cb; +} + +/** + * wlan_ipa_reg_send_to_nw_cb() - Register cb to send IPA Rx packet to network + * @ipa_ctx: IPA context + * @cb: callback + * + * Return: None + */ +static inline +void wlan_ipa_reg_send_to_nw_cb(struct wlan_ipa_priv *ipa_ctx, + wlan_ipa_send_to_nw cb) +{ + ipa_ctx->send_to_nw = cb; +} + +/** + * wlan_ipa_set_mcc_mode() - Set MCC mode + * @ipa_ctx: IPA context + * @mcc_mode: 1=MCC/0=SCC + * + * Return: void + */ +void wlan_ipa_set_mcc_mode(struct wlan_ipa_priv *ipa_ctx, bool mcc_mode); + +/** + * wlan_ipa_set_dfs_cac_tx() - Set DFS cac tx block + * @ipa_ctx: IPA context + * @tx_block: dfs cac tx block + * + * Return: void + */ +static inline +void wlan_ipa_set_dfs_cac_tx(struct wlan_ipa_priv *ipa_ctx, bool tx_block) +{ + ipa_ctx->dfs_cac_block_tx = tx_block; +} + +/** + * wlan_ipa_set_ap_ibss_fwd() - Set AP intra bss forward + * @ipa_ctx: IPA context + * @intra_bss: enable or disable ap intra bss forward + * + * Return: void + */ +static inline +void wlan_ipa_set_ap_ibss_fwd(struct wlan_ipa_priv *ipa_ctx, bool intra_bss) +{ + ipa_ctx->ap_intrabss_fwd = intra_bss; +} + +/** + * wlan_ipa_uc_ol_init() - Initialize IPA uC offload + * @ipa_ctx: IPA context + * @osdev: Parent device instance + * + * This function is called to update IPA pipe configuration with resources + * allocated by wlan driver (cds_pre_enable) before enabling it in FW + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx, + qdf_device_t osdev); + +/** + * wlan_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_flush() - flush IPA exception path SKB's + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_suspend() - Suspend IPA + * @ipa_ctx: IPA context + * + * Return: QDF STATUS + */ +QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_resume() - Resume IPA + * @ipa_ctx: IPA context + * + * Return: QDF STATUS + */ +QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx); + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * wlan_ipa_send_mcc_scc_msg() - Send IPA WLAN_SWITCH_TO_MCC/SCC message + * @ipa_ctx: IPA context + * @mcc_mode: 0=MCC/1=SCC + * + * Return: QDF STATUS + */ +QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx, + bool mcc_mode); +#else +static inline +QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx, + bool mcc_mode) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void wlan_ipa_mcc_work_handler(void *data) +{ +} +#endif + +/** + * wlan_ipa_wlan_evt() - IPA event handler + * @net_dev: Interface net device + * @device_mode: Net interface device mode + * @sta_id: station id for the event + * @session_id: session id for the event + * @type: event enum of type ipa_wlan_event + * @mac_address: MAC address associated with the event + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, + uint8_t sta_id, uint8_t session_id, + enum wlan_ipa_wlan_event ipa_event_type, + uint8_t *mac_addr); + +/** + * wlan_ipa_uc_smmu_map() - 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 wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr); + +/** + * wlan_ipa_is_fw_wdi_activated() - Is FW WDI actived? + * @ipa_ctx: IPA contex + * + * Return: true if FW WDI actived, false otherwise + */ +bool wlan_ipa_is_fw_wdi_activated(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_uc_cleanup_sta - disconnect and cleanup sta iface + * @ipa_ctx: IPA context + * @net_dev: Interface net device + * + * Send disconnect sta event to IPA driver and cleanup IPA iface + * if not yet done + * + * Return: void + */ +void wlan_ipa_uc_cleanup_sta(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev); + +/** + * wlan_ipa_uc_disconnect_ap() - send ap disconnect event + * @ipa_ctx: IPA context + * @net_dev: Interface net device + * + * Send disconnect ap event to IPA driver + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_uc_disconnect_ap(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev); + +/** + * wlan_ipa_cleanup_dev_iface() - Clean up net dev IPA interface + * @ipa_ctx: IPA context + * @net_dev: Interface net device + * + * Return: None + */ +void wlan_ipa_cleanup_dev_iface(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev); + +/** + * wlan_ipa_uc_ssr_cleanup() - handle IPA UC clean up during SSR + * @ipa_ctx: IPA context + * + * Return: None + */ +void wlan_ipa_uc_ssr_cleanup(struct wlan_ipa_priv *ipa_ctx); + +/** + * wlan_ipa_fw_rejuvenate_send_msg() - send fw rejuvenate message to IPA driver + * @ipa_ctx: IPA context + * + * Return: void + */ +void wlan_ipa_fw_rejuvenate_send_msg(struct wlan_ipa_priv *ipa_ctx); + +#endif /* IPA_OFFLOAD */ +#endif /* _WLAN_IPA_CORE_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_main.h b/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_main.h new file mode 100644 index 0000000000000000000000000000000000000000..1d73e445599c9797e641078887facf079faca501 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_main.h @@ -0,0 +1,435 @@ +/* + * 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. + */ +/** + * DOC: declare various api which shall be used by + * IPA user configuration and target interface + */ + +#ifndef _WLAN_IPA_MAIN_H_ +#define _WLAN_IPA_MAIN_H_ + +#ifdef IPA_OFFLOAD + +#include +#include +#include +#include + +#define ipa_log(level, args...) QDF_TRACE(QDF_MODULE_ID_IPA, level, ## args) +#define ipa_logfl(level, format, args...) ipa_log(level, FL(format), ## args) + +#define ipa_fatal(format, args...) \ + ipa_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define ipa_err(format, args...) \ + ipa_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define ipa_warn(format, args...) \ + ipa_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define ipa_info(format, args...) \ + ipa_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define ipa_debug(format, args...) \ + ipa_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define ipa_fatal_rl(params...) QDF_TRACE_FATAL_RL(QDF_MODULE_ID_IPA, params) +#define ipa_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_IPA, params) +#define ipa_warn_rl(params...) QDF_TRACE_WARN_RL(QDF_MODULE_ID_IPA, params) +#define ipa_info_rl(params...) QDF_TRACE_INFO_RL(QDF_MODULE_ID_IPA, params) +#define ipa_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_IPA, params) + +#define IPA_ENTER() ipa_debug("enter") +#define IPA_EXIT() ipa_debug("exit") + +/** + * ipa_check_hw_present() - get IPA hw status + * + * ipa_uc_reg_rdyCB is not directly designed to check + * ipa hw status. This is an undocumented function which + * has confirmed with IPA team. + * + * Return: true - ipa hw present + * false - ipa hw not present + */ +bool ipa_check_hw_present(void); + +/** + * wlan_get_pdev_ipa_obj() - private API to get ipa pdev object + * @pdev: pdev object + * + * Return: ipa object + */ +static inline struct wlan_ipa_priv * +ipa_pdev_get_priv_obj(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *pdev_obj; + + pdev_obj = (struct wlan_ipa_priv *) + wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_IPA); + + return pdev_obj; +} + +/** + * ipa_is_hw_support() - Is IPA HW support? + * + * Return: true if IPA HW is present or false otherwise + */ +bool ipa_is_hw_support(void); + +/** + * ipa_config_mem_alloc() - IPA config allocation + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_config_mem_alloc(void); + +/** + * ipa_config_mem_free() - IPA config mem free + * + * Return: None + */ +void ipa_config_mem_free(void); + +/** + * ipa_config_update() - IPA component config update + * @config: IPA config + * + * Return: None + */ +void ipa_config_update(struct wlan_ipa_config *config); + +/** + * ipa_config_is_enabled() - Is IPA config enabled? + * + * Return: true if IPA is enabled in IPA config + */ +bool ipa_config_is_enabled(void); + +/** + * ipa_config_is_uc_enabled() - Is IPA uC config enabled? + * + * Return: true if IPA uC is enabled in IPA config + */ +bool ipa_config_is_uc_enabled(void); + +/** + * ipa_obj_setup() - IPA obj initialization and setup + * @ipa_ctx: IPA obj context + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_obj_setup(struct wlan_ipa_priv *ipa_ctx); + +/** + * ipa_obj_cleanup() - IPA obj cleanup + * @ipa_ctx: IPA obj context + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_obj_cleanup(struct wlan_ipa_priv *ipa_ctx); + +/** + * ipa_send_uc_offload_enable_disable() - wdi enable/disable notify to fw + * @pdev: objmgr pdev object + * @req: ipa offload control request + * + * Return: QDF status success or failure + */ +QDF_STATUS ipa_send_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev, + struct ipa_uc_offload_control_params *req); + +/** + * ipa_set_dp_handle() - set dp soc handle + * @psoc: psoc handle + * @dp_soc: dp soc handle + * + * Return: None + */ +void ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, void *dp_soc); + +/** + * ipa_set_txrx_handle() - set dp txrx handle + * @psoc: psoc handle + * @txrx_handle: dp txrx handle + * + * Return: None + */ +void ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, void *txrx_handle); + +/** + * ipa_rm_set_perf_level() - set ipa rm perf level + * @pdev: pdev handle + * @tx_packets: packets transmitted in the last sample period + * @rx_packets: packets received in the last sample period + * + * Return: QDF_STATUS + */ +QDF_STATUS ipa_rm_set_perf_level(struct wlan_objmgr_pdev *pdev, + uint64_t tx_packets, uint64_t rx_packets); + +/** + * ipa_uc_info() - Print IPA uC resource and session information + * @pdev: pdev obj + * + * Return: None + */ +void ipa_uc_info(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_uc_stat() - Print IPA uC stats + * @pdev: pdev obj + * + * Return: None + */ +void ipa_uc_stat(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_uc_rt_debug_host_dump() - IPA rt debug host dump + * @pdev: pdev obj + * + * Return: None + */ +void ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_dump_info() - Dump IPA context information + * @pdev: pdev obj + * + * Return: None + */ +void ipa_dump_info(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_uc_stat_request() - Get IPA stats from IPA. + * @pdev: pdev obj + * @reason: STAT REQ Reason + * + * Return: None + */ +void ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason); + +/** + * ipa_uc_stat_query() - Query the IPA stats + * @pdev: pdev obj + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: None + */ +void ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff); + +/** + * ipa_reg_sap_xmit_cb() - Register upper layer SAP cb to transmit + * @pdev: pdev obj + * @cb: callback + * + * Return: None + */ +void ipa_reg_sap_xmit_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_softap_xmit cb); + +/** + * ipa_reg_send_to_nw_cb() - Register cb to send IPA Rx packet to network + * @pdev: pdev obj + * @cb: callback + * + * Return: None + */ +void ipa_reg_send_to_nw_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_send_to_nw cb); + +/** + * ipa_set_mcc_mode() - Set MCC mode + * @pdev: pdev obj + * @mcc_mode: 0=MCC/1=SCC + * + * Return: void + */ +void ipa_set_mcc_mode(struct wlan_objmgr_pdev *pdev, bool mcc_mode); + +/** + * ipa_set_dfs_cac_tx() - Set DFS cac tx block + * @pdev: pdev obj + * @tx_block: dfs cac tx block + * + * Return: void + */ +void ipa_set_dfs_cac_tx(struct wlan_objmgr_pdev *pdev, bool tx_block); + +/** + * ipa_set_ap_ibss_fwd() - Set AP intra bss forward + * @pdev: pdev obj + * @intra_bss: enable or disable ap intra bss forward + * + * Return: void + */ +void ipa_set_ap_ibss_fwd(struct wlan_objmgr_pdev *pdev, bool intra_bss); + +/** + * ipa_uc_force_pipe_shutdown() - Force IPA pipe shutdown + * @pdev: pdev obj + * + * Return: void + */ +void ipa_uc_force_pipe_shutdown(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_flush() - flush IPA exception path SKB's + * @pdev: pdev obj + * + * Return: None + */ +void ipa_flush(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_suspend() - Suspend IPA + * @pdev: pdev obj + * + * Return: QDF STATUS + */ +QDF_STATUS ipa_suspend(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_resume() - Resume IPA + * @pdev: pdev obj + * + * Return: None + */ +QDF_STATUS ipa_resume(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_uc_ol_init() - Initialize IPA uC offload + * @pdev: pdev obj + * @osdev: OS dev + * + * Return: QDF STATUS + */ +QDF_STATUS ipa_uc_ol_init(struct wlan_objmgr_pdev *pdev, + qdf_device_t osdev); + +/** + * ucfg_ipa_uc_ol_deinit() - Deinitialize IPA uC offload + * @pdev: pdev obj + * + * Return: QDF STATUS + */ +QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_send_mcc_scc_msg() - Send IPA WLAN_SWITCH_TO_MCC/SCC message + * @pdev: pdev obj + * @mcc_mode: 0=MCC/1=SCC + * + * Return: QDF STATUS + */ +QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode); + +/** + * ipa_wlan_evt() - IPA event handler + * @pdev: pdev obj + * @net_dev: Interface net device + * @device_mode: Net interface device mode + * @sta_id: station id for the event + * @session_id: session id for the event + * @type: event enum of type ipa_wlan_event + * @mac_address: MAC address associated with the event + * + * Return: QDF_STATUS + */ +QDF_STATUS ipa_wlan_evt(struct wlan_objmgr_pdev *pdev, qdf_netdev_t net_dev, + uint8_t device_mode, uint8_t sta_id, uint8_t session_id, + enum wlan_ipa_wlan_event ipa_event_type, + uint8_t *mac_addr); + +/** + * ipa_uc_smmu_map() - 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 + * + * Return: Status of map operation + */ +int ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr); + +/** + * ipa_is_fw_wdi_activated - Is FW WDI activated? + * @pdev: pdev obj + * + * Return: true if FW WDI activated, false otherwise + */ +bool ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_uc_cleanup_sta() - disconnect and cleanup sta iface + * @pdev: pdev obj + * @net_dev: Interface net device + * + * Send disconnect sta event to IPA driver and cleanup IPA iface, + * if not yet done + * + * Return: void + */ +void ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + +/** + * ipa_uc_disconnect_ap() - send ap disconnect event + * @pdev: pdev obj + * @net_dev: Interface net device + * + * Send disconnect ap event to IPA driver + * + * Return: QDF_STATUS + */ +QDF_STATUS ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + +/** + * ipa_cleanup_dev_iface() - Clean up net dev IPA interface + * @pdev: pdev obj + * @net_dev: Interface net device + * + * Return: None + */ +void ipa_cleanup_dev_iface(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + +/** + * ipa_uc_ssr_cleanup() - handle IPA UC cleanup during SSR + * @pdev: pdev obj + * + * Return: None + */ +void ipa_uc_ssr_cleanup(struct wlan_objmgr_pdev *pdev); + +/** + * ipa_fw_rejuvenate_send_msg() - send fw rejuvenate message to IPA driver + * @pdev: pdev obj + * + * Return: None + */ +void ipa_fw_rejuvenate_send_msg(struct wlan_objmgr_pdev *pdev); + +#else /* Not IPA_OFFLOAD */ +typedef QDF_STATUS (*wlan_ipa_softap_xmit)(qdf_nbuf_t nbuf, qdf_netdev_t dev); +typedef void (*wlan_ipa_send_to_nw)(qdf_nbuf_t nbuf, qdf_netdev_t dev); + +#endif /* IPA_OFFLOAD */ +#endif /* end of _WLAN_IPA_MAIN_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_priv.h b/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..40c4a43c47ade2ece2f0c16dce18169a55da3cfe --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/core/inc/wlan_ipa_priv.h @@ -0,0 +1,726 @@ +/* + * 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: Declare various struct, macros which are used privately in IPA + * component. + */ + +#ifndef _WLAN_IPA_PRIV_STRUCT_H_ +#define _WLAN_IPA_PRIV_STRUCT_H_ + +#ifdef IPA_OFFLOAD + +#ifdef CONFIG_IPA_WDI_UNIFIED_API +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include "wlan_ipa_public_struct.h" + +#define WLAN_IPA_RX_INACTIVITY_MSEC_DELAY 1000 +#define WLAN_IPA_UC_WLAN_8023_HDR_SIZE 14 + +#define WLAN_IPA_UC_NUM_WDI_PIPE 2 +#define WLAN_IPA_UC_MAX_PENDING_EVENT 33 + +#define WLAN_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000 +#define WLAN_IPA_UC_RT_DEBUG_PERIOD 300 +#define WLAN_IPA_UC_RT_DEBUG_BUF_COUNT 30 +#define WLAN_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000 + +#define WLAN_IPA_WLAN_HDR_DES_MAC_OFFSET 0 +#define WLAN_IPA_MAX_IFACE 3 +#define WLAN_IPA_MAX_SYSBAM_PIPE 4 +#define WLAN_IPA_MAX_SESSION 5 +#define WLAN_IPA_MAX_STA_COUNT 41 + +#define WLAN_IPA_RX_PIPE WLAN_IPA_MAX_IFACE +#define WLAN_IPA_ENABLE_MASK BIT(0) +#define WLAN_IPA_PRE_FILTER_ENABLE_MASK BIT(1) +#define WLAN_IPA_IPV6_ENABLE_MASK BIT(2) +#define WLAN_IPA_RM_ENABLE_MASK BIT(3) +#define WLAN_IPA_CLK_SCALING_ENABLE_MASK BIT(4) +#define WLAN_IPA_UC_ENABLE_MASK BIT(5) +#define WLAN_IPA_UC_STA_ENABLE_MASK BIT(6) +#define WLAN_IPA_REAL_TIME_DEBUGGING BIT(8) + +#define WLAN_IPA_MAX_BANDWIDTH 800 + +#define WLAN_IPA_MAX_PENDING_EVENT_COUNT 20 + +#define IPA_WLAN_RX_SOFTIRQ_THRESH 16 + +/** + * enum - IPA UC operation message + * + * @WLAN_IPA_UC_OPCODE_TX_SUSPEND: IPA WDI TX pipe suspend + * @WLAN_IPA_UC_OPCODE_TX_RESUME: IPA WDI TX pipe resume + * @WLAN_IPA_UC_OPCODE_RX_SUSPEND: IPA WDI RX pipe suspend + * @WLAN_IPA_UC_OPCODE_RX_RESUME: IPA WDI RX pipe resume + * @WLAN_IPA_UC_OPCODE_STATS: IPA UC stats + * @WLAN_IPA_UC_OPCODE_SHARING_STATS: IPA UC sharing stats + * @WLAN_IPA_UC_OPCODE_QUOTA_RSP: IPA UC quota response + * @WLAN_IPA_UC_OPCODE_QUOTA_IND: IPA UC quota indication + * @WLAN_IPA_UC_OPCODE_UC_READY: IPA UC ready indication + * @WLAN_IPA_UC_OPCODE_MAX: IPA UC max operation code + */ +enum wlan_ipa_uc_op_code { + WLAN_IPA_UC_OPCODE_TX_SUSPEND = 0, + WLAN_IPA_UC_OPCODE_TX_RESUME = 1, + WLAN_IPA_UC_OPCODE_RX_SUSPEND = 2, + WLAN_IPA_UC_OPCODE_RX_RESUME = 3, + WLAN_IPA_UC_OPCODE_STATS = 4, +#ifdef FEATURE_METERING + WLAN_IPA_UC_OPCODE_SHARING_STATS = 5, + WLAN_IPA_UC_OPCODE_QUOTA_RSP = 6, + WLAN_IPA_UC_OPCODE_QUOTA_IND = 7, +#endif + WLAN_IPA_UC_OPCODE_UC_READY = 8, + /* keep this last */ + WLAN_IPA_UC_OPCODE_MAX +}; + +/** + * enum - Reason codes for stat query + * + * @WLAN_IPA_UC_STAT_REASON_NONE: Initial value + * @WLAN_IPA_UC_STAT_REASON_DEBUG: For debug/info + * @WLAN_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration + * @WLAN_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump + */ +enum { + WLAN_IPA_UC_STAT_REASON_NONE, + WLAN_IPA_UC_STAT_REASON_DEBUG, + WLAN_IPA_UC_STAT_REASON_BW_CAL +}; + +/** + * enum wlan_ipa_rm_state - IPA resource manager state + * @WLAN_IPA_RM_RELEASED: PROD pipe resource released + * @WLAN_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet + * @WLAN_IPA_RM_GRANTED: PROD pipe resource granted + */ +enum wlan_ipa_rm_state { + WLAN_IPA_RM_RELEASED, + WLAN_IPA_RM_GRANT_PENDING, + WLAN_IPA_RM_GRANTED, +}; + +/** + * enum wlan_ipa_forward_type: Type of forward packet received from IPA + * @WLAN_IPA_FORWARD_PKT_NONE: No forward packet + * @WLAN_IPA_FORWARD_PKT_LOCAL_STACK: Packet forwarded to kernel network stack + * @WLAN_IPA_FORWARD_PKT_DISCARD: Discarded packet before sending to kernel + */ +enum wlan_ipa_forward_type { + WLAN_IPA_FORWARD_PKT_NONE = 0, + WLAN_IPA_FORWARD_PKT_LOCAL_STACK = 1, + WLAN_IPA_FORWARD_PKT_DISCARD = 2 +}; + +/** + * struct llc_snap_hdr - LLC snap header + * @dsap: Destination service access point + * @ssap: Source service access point + * @resv: Reserved for future use + * @eth_type: Ether type + */ +struct llc_snap_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t resv[4]; + qdf_be16_t eth_type; +} qdf_packed; + +/** + * struct wlan_ipa_tx_hdr - header type which IPA should handle to TX packet + * @eth: ether II header + * @llc_snap: LLC snap header + */ +struct wlan_ipa_tx_hdr { + qdf_ether_header_t eth; + struct llc_snap_hdr llc_snap; +} qdf_packed; + +/** + * struct frag_header - fragment header type registered to IPA hardware + * @length: fragment length + * @reserved1: Reserved not used + * @reserved2: Reserved not used + */ +#if defined (QCA_WIFI_3_0) || defined (CONFIG_LITHIUM) +struct frag_header { + uint16_t length; + uint32_t reserved1; + uint32_t reserved2; +} qdf_packed; +#else +struct frag_header { + uint32_t + length:16, + reserved16:16; + uint32_t reserved2; +} qdf_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; +} qdf_packed; + +/** + * struct wlan_ipa_uc_tx_hdr - full tx header registered to IPA hardware + * @frag_hd: fragment header + * @ipa_hd: ipa header + * @eth: ether II header + */ +struct wlan_ipa_uc_tx_hdr { + struct frag_header frag_hd; + struct ipa_header ipa_hd; + qdf_ether_header_t eth; +} qdf_packed; + +/** + * struct wlan_ipa_cld_hdr - IPA CLD Header + * @reserved: reserved fields + * @iface_id: interface ID + * @sta_id: Station ID + * + * Packed 32-bit structure + * +----------+----------+--------------+--------+ + * | Reserved | QCMAP ID | interface id | STA ID | + * +----------+----------+--------------+--------+ + */ +struct wlan_ipa_cld_hdr { + uint8_t reserved[2]; + uint8_t iface_id; + uint8_t sta_id; +} qdf_packed; + +/** + * struct wlan_ipa_rx_hdr - IPA RX header + * @cld_hdr: IPA CLD header + * @eth: ether II header + */ +struct wlan_ipa_rx_hdr { + struct wlan_ipa_cld_hdr cld_hdr; + qdf_ether_header_t eth; +} qdf_packed; + +/** + * struct wlan_ipa_pm_tx_cb - PM resume TX callback + * @exception: Exception packet + * @iface_context: Interface context + * @ipa_tx_desc: IPA TX descriptor + */ +struct wlan_ipa_pm_tx_cb { + bool exception; + struct wlan_ipa_iface_context *iface_context; + qdf_ipa_rx_data_t *ipa_tx_desc; +}; + +/** + * struct wlan_ipa_sys_pipe - IPA system pipe + * @conn_hdl: IPA system pipe connection handle + * @conn_hdl_valid: IPA system pipe valid flag + * @ipa_sys_params: IPA system pipe params + */ +struct wlan_ipa_sys_pipe { + uint32_t conn_hdl; + uint8_t conn_hdl_valid; + qdf_ipa_sys_connect_params_t ipa_sys_params; +}; + +/** + * struct wlan_ipa_iface_stats - IPA system pipe + * @num_tx: Number of TX packets + * @num_tx_drop: Number of TX packet drops + * @num_tx_err: Number of TX packet errors + * @num_tx_cac_drop: Number of TX packet drop due to CAC + * @num_rx_ipa_excep: Number of RX IPA exception packets + */ +struct wlan_ipa_iface_stats { + uint64_t num_tx; + uint64_t num_tx_drop; + uint64_t num_tx_err; + uint64_t num_tx_cac_drop; + uint64_t num_rx_ipa_excep; +}; + +/* IPA private context structure */ +struct wlan_ipa_priv; + +/** + * struct wlan_ipa_iface_context - IPA interface context + * @ipa_ctx: IPA private context + * @tl_context: TL context + * @cons_client: IPA consumer pipe + * @prod_client: IPA producer pipe + * @prod_client: IPA producer pipe + * @iface_id: IPA interface ID + * @dev: Net device structure + * @device_mode: Interface device mode + * @sta_id: Interface station ID + * @session_id: Session ID + * @interface_lock: Interface lock + * @ifa_address: Interface address + * @stats: Interface stats + */ +struct wlan_ipa_iface_context { + struct wlan_ipa_priv *ipa_ctx; + void *tl_context; + + qdf_ipa_client_type_t cons_client; + qdf_ipa_client_type_t prod_client; + + uint8_t iface_id; /* This iface ID */ + qdf_netdev_t dev; + enum QDF_OPMODE device_mode; + uint8_t sta_id; /* This iface station ID */ + uint8_t session_id; + qdf_spinlock_t interface_lock; + uint32_t ifa_address; + struct wlan_ipa_iface_stats stats; +}; + +/** + * struct wlan_ipa_stats - IPA system stats + * @event: WLAN IPA event record + * @num_send_msg: Number of sent IPA messages + * @num_rm_grant: Number of times IPA RM resource granted + * @num_rm_release: Number of times IPA RM resource released + * @num_rm_grant_imm: Number of immediate IPA RM granted + e @num_cons_perf_req: Number of CONS pipe perf request + * @num_prod_perf_req: Number of PROD pipe perf request + * @num_rx_drop: Number of RX packet drops + * @num_tx_desc_q_cnt: Number of TX descriptor queue count + * @num_tx_desc_err: Number of TX descriptor error + * @num_tx_comp_cnt: Number of TX qdf_event_t count + * @num_tx_queued: Number of TX queued + * @num_tx_dequeued: Number of TX dequeued + * @num_max_pm_queue: Number of packets in PM queue + * @num_rx_excep: Number of RX IPA exception packets + * @num_tx_fwd_ok: Number of TX forward packet success + * @num_tx_fwd_err: Number of TX forward packet failures + */ +struct wlan_ipa_stats { + uint32_t event[QDF_IPA_WLAN_EVENT_MAX]; + uint64_t num_send_msg; + uint64_t num_free_msg; + uint64_t num_rm_grant; + uint64_t num_rm_release; + uint64_t num_rm_grant_imm; + uint64_t num_cons_perf_req; + uint64_t num_prod_perf_req; + uint64_t num_rx_drop; + uint64_t num_tx_desc_q_cnt; + uint64_t num_tx_desc_error; + uint64_t num_tx_comp_cnt; + uint64_t num_tx_queued; + uint64_t num_tx_dequeued; + uint64_t num_max_pm_queue; + uint64_t num_rx_excep; + uint64_t num_tx_fwd_ok; + uint64_t num_tx_fwd_err; +}; + +/** + * struct ipa_uc_stas_map - IPA UC assoc station map + * @is_reserved: STA reserved flag + * @sta_id: Station ID + * @mac_addr: Station mac address + */ +struct ipa_uc_stas_map { + bool is_reserved; + uint8_t sta_id; + struct qdf_mac_addr mac_addr; +}; + +/** + * struct op_msg_type - IPA operation message type + * @msg_t: Message type + * @rsvd: Reserved + * @op_code: IPA Operation type + * @len: IPA message length + * @rsvd_snd: Reserved + */ +struct op_msg_type { + uint8_t msg_t; + uint8_t rsvd; + uint16_t op_code; + uint16_t len; + uint16_t rsvd_snd; +}; + +/** + * struct ipa_uc_fw_stats - IPA FW stats + * @tx_comp_ring_size: TX completion ring size + * @txcomp_ring_dbell_addr: TX comp ring door bell address + * @txcomp_ring_dbell_ind_val: TX cop ring door bell indication + * @txcomp_ring_dbell_cached_val: TX cop ring cached value + * @txpkts_enqueued: TX packets enqueued + * @txpkts_completed: TX packets completed + * @tx_is_suspend: TX suspend flag + * @tx_reserved: Reserved for TX stat + * @rx_ind_ring_base: RX indication ring base addess + * @rx_ind_ring_size: RX indication ring size + * @rx_ind_ring_dbell_addr: RX indication ring doorbell address + * @rx_ind_ring_dbell_ind_val: RX indication ring doorbell indication + * @rx_ind_ring_dbell_ind_cached_val: RX indication ring doorbell cached value + * @rx_ind_ring_rdidx_addr: RX indication ring read index address + * @rx_ind_ring_rd_idx_cached_val: RX indication ring read index cached value + * @rx_refill_idx: RX ring refill index + * @rx_num_pkts_indicated: Number of RX packets indicated + * @rx_buf_refilled: Number of RX buffer refilled + * @rx_num_ind_drop_no_space: Number of RX indication drops due to no space + * @rx_num_ind_drop_no_buf: Number of RX indication drops due to no buffer + * @rx_is_suspend: RX suspend flag + * @rx_reserved: Reserved for RX stat + */ +struct ipa_uc_fw_stats { + uint32_t tx_comp_ring_base; + uint32_t tx_comp_ring_size; + uint32_t tx_comp_ring_dbell_addr; + uint32_t tx_comp_ring_dbell_ind_val; + uint32_t tx_comp_ring_dbell_cached_val; + uint32_t tx_pkts_enqueued; + uint32_t tx_pkts_completed; + uint32_t tx_is_suspend; + uint32_t tx_reserved; + uint32_t rx_ind_ring_base; + uint32_t rx_ind_ring_size; + uint32_t rx_ind_ring_dbell_addr; + uint32_t rx_ind_ring_dbell_ind_val; + uint32_t rx_ind_ring_dbell_ind_cached_val; + uint32_t rx_ind_ring_rdidx_addr; + uint32_t rx_ind_ring_rd_idx_cached_val; + uint32_t rx_refill_idx; + uint32_t rx_num_pkts_indicated; + uint32_t rx_buf_refilled; + uint32_t rx_num_ind_drop_no_space; + uint32_t rx_num_ind_drop_no_buf; + uint32_t rx_is_suspend; + uint32_t rx_reserved; +}; + +/** + * struct wlan_ipa_uc_pending_event - WLAN IPA UC pending event + * @node: Pending event list node + * @type: WLAN IPA event type + * @device_mode: Device mode + * @sta_id: Station ID + * @session_id: Session ID + * @mac_addr: Mac address + * @is_loading: Driver loading flag + */ +struct wlan_ipa_uc_pending_event { + qdf_list_node_t node; + qdf_ipa_wlan_event type; + qdf_netdev_t net_dev; + uint8_t device_mode; + uint8_t sta_id; + uint8_t session_id; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + bool is_loading; +}; + +/** + * struct uc_rm_work_struct + * @work: uC RM work + * @event: IPA RM event + */ +struct uc_rm_work_struct { + qdf_work_t work; + qdf_ipa_rm_event_t event; +}; + +/** + * struct uc_op_work_struct + * @work: uC OP work + * @msg: OP message + */ +struct uc_op_work_struct { + qdf_work_t work; + struct op_msg_type *msg; +}; + +/** + * struct uc_rt_debug_info + * @time: system time + * @ipa_excep_count: IPA exception packet count + * @rx_drop_count: IPA Rx drop packet count + * @net_sent_count: IPA Rx packet sent to network stack count + * @rx_discard_count: IPA Rx discard packet count + * @tx_fwd_ok_count: IPA Tx forward success packet count + * @tx_fwd_count: IPA Tx forward packet count + * @rx_destructor_call: IPA Rx packet destructor count + */ +struct uc_rt_debug_info { + uint64_t time; + uint64_t ipa_excep_count; + uint64_t rx_drop_count; + uint64_t net_sent_count; + uint64_t rx_discard_count; + uint64_t tx_fwd_ok_count; + uint64_t tx_fwd_count; + uint64_t rx_destructor_call; +}; + +#ifdef FEATURE_METERING +/** + * struct ipa_uc_sharing_stats - IPA UC sharing stats + * @ipv4_rx_packets: IPv4 RX packets + * @ipv4_rx_bytes: IPv4 RX bytes + * @ipv6_rx_packets: IPv6 RX packets + * @ipv6_rx_bytes: IPv6 RX bytes + * @ipv4_tx_packets: IPv4 TX packets + * @ipv4_tx_bytes: IPv4 TX bytes + * @ipv6_tx_packets: IPv4 TX packets + * @ipv6_tx_bytes: IPv6 TX bytes + */ +struct ipa_uc_sharing_stats { + uint64_t ipv4_rx_packets; + uint64_t ipv4_rx_bytes; + uint64_t ipv6_rx_packets; + uint64_t ipv6_rx_bytes; + uint64_t ipv4_tx_packets; + uint64_t ipv4_tx_bytes; + uint64_t ipv6_tx_packets; + uint64_t ipv6_tx_bytes; +}; + +/** + * struct ipa_uc_quota_rsp - IPA UC quota response + * @success: Success or fail flag + * @reserved[3]: Reserved + * @quota_lo: Quota limit low bytes + * @quota_hi: Quota limit high bytes + */ +struct ipa_uc_quota_rsp { + uint8_t success; + uint8_t reserved[3]; + uint32_t quota_lo; + uint32_t quota_hi; +}; + +/** + * struct ipa_uc_quota_ind + * @quota_bytes: Quota bytes to set + */ +struct ipa_uc_quota_ind { + uint64_t quota_bytes; +}; +#endif + +/** + * struct wlan_ipa_tx_desc + * @node: TX descriptor node + * @priv: pointer to priv list entry + * @id: Tx desc idex + * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor + */ +struct wlan_ipa_tx_desc { + qdf_list_node_t node; + void *priv; + uint32_t id; + qdf_ipa_rx_data_t *ipa_tx_desc_ptr; +}; + +typedef QDF_STATUS (*wlan_ipa_softap_xmit)(qdf_nbuf_t nbuf, qdf_netdev_t dev); +typedef void (*wlan_ipa_send_to_nw)(qdf_nbuf_t nbuf, qdf_netdev_t dev); + +/* IPA private context structure definition */ +struct wlan_ipa_priv { + struct wlan_objmgr_pdev *pdev; + struct wlan_ipa_sys_pipe sys_pipe[WLAN_IPA_MAX_SYSBAM_PIPE]; + struct wlan_ipa_iface_context iface_context[WLAN_IPA_MAX_IFACE]; + uint8_t num_iface; + void *dp_soc; + void *dp_pdev; + struct wlan_ipa_config *config; + enum wlan_ipa_rm_state rm_state; + /* + * IPA driver can send RM notifications with IRQ disabled so using qdf + * APIs as it is taken care gracefully. Without this, kernel would throw + * an warning if spin_lock_bh is used while IRQ is disabled + */ + qdf_spinlock_t rm_lock; + struct uc_rm_work_struct uc_rm_work; + struct uc_op_work_struct uc_op_work[WLAN_IPA_UC_OPCODE_MAX]; + qdf_wake_lock_t wake_lock; + qdf_delayed_work_t wake_lock_work; + bool wake_lock_released; + + qdf_atomic_t tx_ref_cnt; + qdf_nbuf_queue_t pm_queue_head; + qdf_work_t pm_work; + qdf_spinlock_t pm_lock; + bool suspended; + + qdf_spinlock_t q_lock; + + qdf_spinlock_t pipes_down_lock; + bool pipes_down_in_progress; + + qdf_list_node_t pend_desc_head; + qdf_list_t tx_desc_list; + + struct wlan_ipa_stats stats; + + uint32_t curr_prod_bw; + uint32_t curr_cons_bw; + + uint8_t activated_fw_pipe; + uint8_t sap_num_connected_sta; + uint8_t sta_connected; + uint32_t tx_pipe_handle; + uint32_t rx_pipe_handle; + bool resource_loading; + bool resource_unloading; + bool pending_cons_req; + struct ipa_uc_stas_map assoc_stas_map[WLAN_IPA_MAX_STA_COUNT]; + qdf_list_t pending_event; + qdf_mutex_t event_lock; + bool ipa_pipes_down; + uint32_t ipa_tx_packets_diff; + uint32_t ipa_rx_packets_diff; + uint32_t ipa_p_tx_packets; + uint32_t ipa_p_rx_packets; + uint32_t stat_req_reason; + uint64_t ipa_tx_forward; + uint64_t ipa_rx_discard; + uint64_t ipa_rx_net_send_count; + uint64_t ipa_rx_internal_drop_count; + uint64_t ipa_rx_destructor_count; + qdf_mc_timer_t rt_debug_timer; + struct uc_rt_debug_info rt_bug_buffer[WLAN_IPA_UC_RT_DEBUG_BUF_COUNT]; + unsigned int rt_buf_fill_index; + qdf_ipa_wdi_in_params_t cons_pipe_in; + qdf_ipa_wdi_in_params_t prod_pipe_in; + bool uc_loaded; + bool wdi_enabled; + qdf_mc_timer_t rt_debug_fill_timer; + qdf_mutex_t rt_debug_lock; + qdf_mutex_t ipa_lock; + + uint8_t vdev_to_iface[WLAN_IPA_MAX_SESSION]; + bool vdev_offload_enabled[WLAN_IPA_MAX_SESSION]; + bool mcc_mode; + qdf_work_t mcc_work; + bool ap_intrabss_fwd; + bool dfs_cac_block_tx; +#ifdef FEATURE_METERING + struct ipa_uc_sharing_stats ipa_sharing_stats; + struct ipa_uc_quota_rsp ipa_quota_rsp; + struct ipa_uc_quota_ind ipa_quota_ind; + qdf_event_t ipa_uc_sharing_stats_comp; + qdf_event_t ipa_uc_set_quota_comp; +#endif + + wlan_ipa_softap_xmit softap_xmit; + wlan_ipa_send_to_nw send_to_nw; + ipa_uc_offload_control_req ipa_tx_op; + + qdf_event_t ipa_resource_comp; + + uint32_t wdi_version; + bool is_smmu_enabled; /* IPA caps returned from ipa_wdi_init */ +}; + +#define WLAN_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header) +#define WLAN_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header) +#define WLAN_IPA_WLAN_CLD_HDR_LEN sizeof(struct wlan_ipa_cld_hdr) +#define WLAN_IPA_UC_WLAN_CLD_HDR_LEN 0 +#define WLAN_IPA_WLAN_TX_HDR_LEN sizeof(struct wlan_ipa_tx_hdr) +#define WLAN_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct wlan_ipa_uc_tx_hdr) +#define WLAN_IPA_WLAN_RX_HDR_LEN sizeof(struct wlan_ipa_rx_hdr) +#define WLAN_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \ + (WLAN_IPA_WLAN_FRAG_HEADER + WLAN_IPA_WLAN_IPA_HEADER) + +#define WLAN_IPA_GET_IFACE_ID(_data) \ + (((struct wlan_ipa_cld_hdr *) (_data))->iface_id) + +#define WLAN_IPA_LOG(LVL, fmt, args ...) \ + QDF_TRACE(QDF_MODULE_ID_IPA, LVL, \ + "%s:%d: "fmt, __func__, __LINE__, ## args) + +#define WLAN_IPA_IS_CONFIG_ENABLED(_ipa_cfg, _mask) \ + (((_ipa_cfg)->ipa_config & (_mask)) == (_mask)) + +#define BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) + +#define WLAN_IPA_DBG_DUMP_RX_LEN 84 +#define WLAN_IPA_DBG_DUMP_TX_LEN 48 + +#define IPA_RESOURCE_COMP_WAIT_TIME 100 + +#ifdef FEATURE_METERING +#define IPA_UC_SHARING_STATES_WAIT_TIME 500 +#define IPA_UC_SET_QUOTA_WAIT_TIME 500 +#endif + +/** + * wlan_ipa_wlan_event_to_str() - convert IPA WLAN event to string + * @event: IPA WLAN event to be converted to a string + * + * Return: ASCII string representing the IPA WLAN event + */ +static inline char *wlan_ipa_wlan_event_to_str(qdf_ipa_wlan_event event) +{ + switch (event) { + CASE_RETURN_STRING(QDF_IPA_CLIENT_CONNECT); + CASE_RETURN_STRING(QDF_IPA_CLIENT_DISCONNECT); + CASE_RETURN_STRING(QDF_IPA_AP_CONNECT); + CASE_RETURN_STRING(QDF_IPA_AP_DISCONNECT); + CASE_RETURN_STRING(QDF_IPA_STA_CONNECT); + CASE_RETURN_STRING(QDF_IPA_STA_DISCONNECT); + CASE_RETURN_STRING(QDF_IPA_CLIENT_CONNECT_EX); + CASE_RETURN_STRING(QDF_SWITCH_TO_SCC); + CASE_RETURN_STRING(QDF_SWITCH_TO_MCC); + CASE_RETURN_STRING(QDF_WDI_ENABLE); + CASE_RETURN_STRING(QDF_WDI_DISABLE); + default: + return "UNKNOWN"; + } +} + +/** + * wlan_ipa_get_iface() - Get IPA interface + * @ipa_ctx: IPA context + * @mode: Interface device mode + * + * Return: IPA interface address + */ +struct wlan_ipa_iface_context +*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode); + +#endif /* IPA_OFFLOAD */ +#endif /* _WLAN_IPA_PRIV_STRUCT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_core.c b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_core.c new file mode 100644 index 0000000000000000000000000000000000000000..4ab35dd0667407c29067442fcf89ce1617492a67 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_core.c @@ -0,0 +1,3085 @@ +/* + * 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. + */ + +/* Include Files */ +#include "wlan_ipa_core.h" +#include "wlan_ipa_main.h" +#include +#include "cdp_txrx_ipa.h" +#include "wal_rx_desc.h" +#include "qdf_str.h" + +static struct wlan_ipa_priv *gp_ipa; + +static struct wlan_ipa_iface_2_client { + qdf_ipa_client_type_t cons_client; + qdf_ipa_client_type_t prod_client; +} wlan_ipa_iface_2_client[WLAN_IPA_MAX_IFACE] = { + { + QDF_IPA_CLIENT_WLAN2_CONS, QDF_IPA_CLIENT_WLAN1_PROD + }, { + QDF_IPA_CLIENT_WLAN3_CONS, QDF_IPA_CLIENT_WLAN1_PROD + }, { + QDF_IPA_CLIENT_WLAN4_CONS, QDF_IPA_CLIENT_WLAN1_PROD + } +}; + +/* Local Function Prototypes */ +static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt, + unsigned long data); +static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt, + unsigned long data); + +/** + * wlan_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled? + * @ipa_cfg: IPA config + * + * Return: true if STA mode IPA uC offload is enabled, false otherwise + */ +static inline bool wlan_ipa_uc_sta_is_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_UC_STA_ENABLE_MASK); +} + +/** + * wlan_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled? + * @ipa_cfg: IPA config + * + * Return: true if pre-filter is enabled, otherwise false + */ +static inline +bool wlan_ipa_is_pre_filter_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, + WLAN_IPA_PRE_FILTER_ENABLE_MASK); +} + +/** + * wlan_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled? + * @ipa_cfg: IPA config + * + * Return: true if IPv6 is enabled, otherwise false + */ +static inline bool wlan_ipa_is_ipv6_enabled(struct wlan_ipa_config *ipa_cfg) +{ + return WLAN_IPA_IS_CONFIG_ENABLED(ipa_cfg, WLAN_IPA_IPV6_ENABLE_MASK); +} + +/** + * wlan_ipa_msg_free_fn() - Free an IPA message + * @buff: pointer to the IPA message + * @len: length of the IPA message + * @type: type of IPA message + * + * Return: None + */ +static void wlan_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type) +{ + ipa_debug("msg type:%d, len:%d", type, len); + qdf_mem_free(buff); +} + +/** + * wlan_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback + * @priv_ctxt: IPA context + * + * Will be called by IPA context. + * It's atomic context, then should be scheduled to kworker thread + * + * Return: None + */ +static void wlan_ipa_uc_loaded_uc_cb(void *priv_ctxt) +{ + struct wlan_ipa_priv *ipa_ctx; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + + if (!priv_ctxt) { + ipa_err("Invalid IPA context"); + return; + } + + ipa_ctx = priv_ctxt; + ipa_ctx->uc_loaded = true; + + uc_op_work = &ipa_ctx->uc_op_work[WLAN_IPA_UC_OPCODE_UC_READY]; + if (!list_empty(&uc_op_work->work.work.entry)) { + /* uc_op_work is not initialized yet */ + return; + } + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) { + ipa_err("op_msg allocation fails"); + return; + } + + msg->op_code = WLAN_IPA_UC_OPCODE_UC_READY; + + /* When the same uC OPCODE is already pended, just return */ + if (uc_op_work->msg) + goto done; + + uc_op_work->msg = msg; + qdf_sched_work(0, &uc_op_work->work); + + /* work handler will free the msg buffer */ + return; + +done: + qdf_mem_free(msg); +} + +/** + * wlan_ipa_uc_send_wdi_control_msg() - Set WDI control message + * @ctrl: WDI control value + * + * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise. + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_ipa_uc_send_wdi_control_msg(bool ctrl) +{ + struct wlan_ipa_priv *ipa_ctx = gp_ipa; + qdf_ipa_msg_meta_t meta; + qdf_ipa_wlan_msg_t *ipa_msg; + int ret = 0; + + /* WDI enable message to IPA */ + QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*ipa_msg); + ipa_msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta)); + if (!ipa_msg) { + ipa_err("msg allocation failed"); + return QDF_STATUS_E_NOMEM; + } + + if (ctrl) { + QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_ENABLE); + ipa_ctx->stats.event[QDF_WDI_ENABLE]++; + } else { + QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_WDI_DISABLE); + ipa_ctx->stats.event[QDF_WDI_DISABLE]++; + } + + ipa_debug("ipa_send_msg(Evt:%d)", QDF_IPA_MSG_META_MSG_TYPE(&meta)); + ret = qdf_ipa_send_msg(&meta, ipa_msg, wlan_ipa_msg_free_fn); + if (ret) { + ipa_err("ipa_send_msg(Evt:%d)-fail=%d", + QDF_IPA_MSG_META_MSG_TYPE(&meta), ret); + qdf_mem_free(ipa_msg); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +struct wlan_ipa_priv *wlan_ipa_get_obj_context(void) +{ + return gp_ipa; +} + +/** + * wlan_ipa_send_pkt_to_tl() - Send an IPA packet to TL + * @iface_context: interface-specific IPA context + * @ipa_tx_desc: packet data descriptor + * + * Return: None + */ +static void wlan_ipa_send_pkt_to_tl( + struct wlan_ipa_iface_context *iface_context, + qdf_ipa_rx_data_t *ipa_tx_desc) +{ + struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx; + qdf_nbuf_t skb; + struct wlan_ipa_tx_desc *tx_desc; + + qdf_spin_lock_bh(&iface_context->interface_lock); + /* + * During CAC period, data packets shouldn't be sent over the air so + * drop all the packets here + */ + if (iface_context->device_mode == QDF_SAP_MODE || + iface_context->device_mode == QDF_P2P_GO_MODE) { + if (ipa_ctx->dfs_cac_block_tx) { + ipa_free_skb(ipa_tx_desc); + qdf_spin_unlock_bh(&iface_context->interface_lock); + iface_context->stats.num_tx_cac_drop++; + wlan_ipa_wdi_rm_try_release(ipa_ctx); + return; + } + } + qdf_spin_unlock_bh(&iface_context->interface_lock); + + skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc); + + qdf_mem_zero(skb->cb, sizeof(skb->cb)); + + /* Store IPA Tx buffer ownership into SKB CB */ + qdf_nbuf_ipa_owned_set(skb); + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + qdf_nbuf_mapped_paddr_set(skb, + QDF_IPA_RX_DATA_DMA_ADDR(ipa_tx_desc) + + WLAN_IPA_WLAN_FRAG_HEADER + + WLAN_IPA_WLAN_IPA_HEADER); + QDF_IPA_RX_DATA_SKB_LEN(ipa_tx_desc) -= + WLAN_IPA_WLAN_FRAG_HEADER + WLAN_IPA_WLAN_IPA_HEADER; + } else + qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr); + + qdf_spin_lock_bh(&ipa_ctx->q_lock); + /* get free Tx desc and assign ipa_tx_desc pointer */ + if (qdf_list_remove_front(&ipa_ctx->tx_desc_list, + (qdf_list_node_t **)&tx_desc) == + QDF_STATUS_SUCCESS) { + tx_desc->ipa_tx_desc_ptr = ipa_tx_desc; + ipa_ctx->stats.num_tx_desc_q_cnt++; + qdf_spin_unlock_bh(&ipa_ctx->q_lock); + /* Store Tx Desc index into SKB CB */ + QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id; + } else { + ipa_ctx->stats.num_tx_desc_error++; + qdf_spin_unlock_bh(&ipa_ctx->q_lock); + qdf_ipa_free_skb(ipa_tx_desc); + wlan_ipa_wdi_rm_try_release(ipa_ctx); + return; + } + + skb = cdp_ipa_tx_send_data_frame(cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_vdev *)iface_context->tl_context, + QDF_IPA_RX_DATA_SKB(ipa_tx_desc)); + if (skb) { + qdf_nbuf_free(skb); + iface_context->stats.num_tx_err++; + return; + } + + atomic_inc(&ipa_ctx->tx_ref_cnt); + + iface_context->stats.num_tx++; +} + +#ifdef CONFIG_IPA_WDI_UNIFIED_API + +/* + * TODO: Get WDI version through FW capabilities + */ +#ifdef CONFIG_LITHIUM +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_ctx->wdi_version = IPA_WDI_3; +} +#elif defined(QCA_WIFI_3_0) +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_ctx->wdi_version = IPA_WDI_2; +} +#else +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_ctx->wdi_version = IPA_WDI_1; +} +#endif + +static inline bool wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx, + qdf_device_t osdev) +{ + return ipa_ctx->is_smmu_enabled && qdf_mem_smmu_s1_enabled(osdev); +} + +static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx, + qdf_device_t osdev) +{ + qdf_ipa_sys_connect_params_t sys_in[WLAN_IPA_MAX_IFACE]; + int i; + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) + qdf_mem_copy(&sys_in[i], + &ipa_ctx->sys_pipe[i].ipa_sys_params, + sizeof(qdf_ipa_sys_connect_params_t)); + + return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + wlan_ipa_i2w_cb, wlan_ipa_w2i_cb, + wlan_ipa_wdi_meter_notifier_cb, + ipa_ctx->config->desc_size, + ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config), + &ipa_ctx->tx_pipe_handle, + &ipa_ctx->rx_pipe_handle, + wlan_ipa_wdi_is_smmu_enabled(ipa_ctx, osdev), + sys_in); +} + +#ifdef FEATURE_METERING +/** + * wlan_ipa_wdi_init_metering() - IPA WDI metering init + * @ipa_ctx: IPA context + * @in: IPA WDI in param + * + * Return: QDF_STATUS + */ +static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt, + qdf_ipa_wdi_init_in_params_t *in) +{ + QDF_IPA_WDI_INIT_IN_PARAMS_WDI_NOTIFY(in) = + wlan_ipa_wdi_meter_notifier_cb; +} +#else +static inline void wlan_ipa_wdi_init_metering(struct wlan_ipa_priv *ipa_ctxt, + qdf_ipa_wdi_init_in_params_t *in) +{ +} +#endif + +/** + * wlan_ipa_wdi_init() - IPA WDI init + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_ipa_wdi_init_in_params_t in; + qdf_ipa_wdi_init_out_params_t out; + int ret; + + ipa_ctx->uc_loaded = false; + + qdf_mem_zero(&in, sizeof(in)); + qdf_mem_zero(&out, sizeof(out)); + + QDF_IPA_WDI_INIT_IN_PARAMS_WDI_VERSION(&in) = ipa_ctx->wdi_version; + QDF_IPA_WDI_INIT_IN_PARAMS_NOTIFY(&in) = wlan_ipa_uc_loaded_uc_cb; + QDF_IPA_WDI_INIT_IN_PARAMS_PRIV(&in) = ipa_ctx; + wlan_ipa_wdi_init_metering(ipa_ctx, &in); + + ret = qdf_ipa_wdi_init(&in, &out); + if (ret) { + ipa_err("ipa_wdi_init failed with ret=%d", ret); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_IPA_WDI_INIT_OUT_PARAMS_IS_UC_READY(&out)) { + ipa_debug("IPA uC READY"); + ipa_ctx->uc_loaded = true; + ipa_ctx->is_smmu_enabled = + QDF_IPA_WDI_INIT_OUT_PARAMS_IS_SMMU_ENABLED(&out); + ipa_debug("is_smmu_enabled=%d", ipa_ctx->is_smmu_enabled); + } else { + return QDF_STATUS_E_BUSY; + } + + return QDF_STATUS_SUCCESS; +} + +static inline int wlan_ipa_wdi_cleanup(void) +{ + int ret; + + ret = qdf_ipa_wdi_cleanup(); + if (ret) + ipa_info("ipa_wdi_cleanup failed ret=%d", ret); + return ret; +} + +static inline int wlan_ipa_wdi_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + struct ipa_sys_connect_params *sys, + uint32_t *handle) +{ + return 0; +} + +static inline int wlan_ipa_wdi_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + uint32_t handle) +{ + return 0; +} + +/** + * wlan_ipa_pm_flush() - flush queued packets + * @work: pointer to the scheduled work + * + * Called during PM resume to send packets to TL which were queued + * while host was in the process of suspending. + * + * Return: None + */ +static void wlan_ipa_pm_flush(void *data) +{ + struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data; + struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL; + qdf_nbuf_t skb; + uint32_t dequeued = 0; + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) != + NULL)) { + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb; + dequeued++; + + if (pm_tx_cb->exception) { + if (ipa_ctx->softap_xmit && + pm_tx_cb->iface_context->dev) { + ipa_ctx->softap_xmit(skb, + pm_tx_cb->iface_context->dev); + ipa_ctx->stats.num_tx_fwd_ok++; + } else { + dev_kfree_skb_any(skb); + } + } else { + wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context, + pm_tx_cb->ipa_tx_desc); + } + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + } + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + ipa_ctx->stats.num_tx_dequeued += dequeued; + if (dequeued > ipa_ctx->stats.num_max_pm_queue) + ipa_ctx->stats.num_max_pm_queue = dequeued; +} + +int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + if (!num_buf) { + ipa_info("No buffers to map/unmap"); + return 0; + } + + if (map) + return qdf_ipa_wdi_create_smmu_mapping(num_buf, buf_arr); + else + return qdf_ipa_wdi_release_smmu_mapping(num_buf, buf_arr); +} + +#else /* CONFIG_IPA_WDI_UNIFIED_API */ + +static inline void wlan_ipa_wdi_get_wdi_version(struct wlan_ipa_priv *ipa_ctx) +{ +} + +static inline int wlan_ipa_wdi_is_smmu_enabled(struct wlan_ipa_priv *ipa_ctx, + qdf_device_t osdev) +{ + return qdf_mem_smmu_s1_enabled(osdev); +} + +static inline QDF_STATUS wlan_ipa_wdi_setup(struct wlan_ipa_priv *ipa_ctx, + qdf_device_t osdev) +{ + return cdp_ipa_setup(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + wlan_ipa_i2w_cb, wlan_ipa_w2i_cb, + wlan_ipa_wdi_meter_notifier_cb, + ipa_ctx->config->desc_size, + ipa_ctx, wlan_ipa_is_rm_enabled(ipa_ctx->config), + &ipa_ctx->tx_pipe_handle, + &ipa_ctx->rx_pipe_handle); +} + +static inline QDF_STATUS wlan_ipa_wdi_init(struct wlan_ipa_priv *ipa_ctx) +{ + struct ipa_wdi_uc_ready_params uc_ready_param; + + ipa_ctx->uc_loaded = false; + uc_ready_param.priv = (void *)ipa_ctx; + uc_ready_param.notify = wlan_ipa_uc_loaded_uc_cb; + if (qdf_ipa_uc_reg_rdyCB(&uc_ready_param)) { + ipa_info("UC Ready CB register fail"); + return QDF_STATUS_E_FAILURE; + } + + if (true == uc_ready_param.is_uC_ready) { + ipa_info("UC Ready"); + ipa_ctx->uc_loaded = true; + } else { + return QDF_STATUS_E_BUSY; + } + + return QDF_STATUS_SUCCESS; +} + +static inline int wlan_ipa_wdi_cleanup(void) +{ + int ret; + + ret = qdf_ipa_uc_dereg_rdyCB(); + if (ret) + ipa_info("UC Ready CB deregister fail"); + return ret; +} + +static inline int wlan_ipa_wdi_setup_sys_pipe( + struct wlan_ipa_priv *ipa_ctx, + struct ipa_sys_connect_params *sys, uint32_t *handle) +{ + return qdf_ipa_setup_sys_pipe(sys, handle); +} + +static inline int wlan_ipa_wdi_teardown_sys_pipe( + struct wlan_ipa_priv *ipa_ctx, + uint32_t handle) +{ + return qdf_ipa_teardown_sys_pipe(handle); +} + +/** + * wlan_ipa_pm_flush() - flush queued packets + * @work: pointer to the scheduled work + * + * Called during PM resume to send packets to TL which were queued + * while host was in the process of suspending. + * + * Return: None + */ +static void wlan_ipa_pm_flush(void *data) +{ + struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data; + struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL; + qdf_nbuf_t skb; + uint32_t dequeued = 0; + + qdf_wake_lock_acquire(&ipa_ctx->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) != + NULL)) { + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb; + dequeued++; + + if (pm_tx_cb->exception) { + if (ipa_ctx->softap_xmit && + pm_tx_cb->iface_context->dev) { + ipa_ctx->softap_xmit(skb, + pm_tx_cb->iface_context->dev); + ipa_ctx->stats.num_tx_fwd_ok++; + } else { + dev_kfree_skb_any(skb); + } + } else { + wlan_ipa_send_pkt_to_tl(pm_tx_cb->iface_context, + pm_tx_cb->ipa_tx_desc); + } + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + } + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + qdf_wake_lock_release(&ipa_ctx->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + + ipa_ctx->stats.num_tx_dequeued += dequeued; + if (dequeued > ipa_ctx->stats.num_max_pm_queue) + ipa_ctx->stats.num_max_pm_queue = dequeued; +} + +int wlan_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + if (!num_buf) { + ipa_info("No buffers to map/unmap"); + return 0; + } + + if (map) + return qdf_ipa_create_wdi_mapping(num_buf, buf_arr); + else + return qdf_ipa_release_wdi_mapping(num_buf, buf_arr); +} + +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ + +/** + * wlan_ipa_send_skb_to_network() - Send skb to kernel + * @skb: network buffer + * @iface_ctx: IPA interface context + * + * Called when a network buffer is received which should not be routed + * to the IPA module. + * + * Return: None + */ +static void +wlan_ipa_send_skb_to_network(qdf_nbuf_t skb, + struct wlan_ipa_iface_context *iface_ctx) +{ + struct wlan_ipa_priv *ipa_ctx = gp_ipa; + + if (!iface_ctx->dev) { + ipa_debug_rl("Invalid interface"); + ipa_ctx->ipa_rx_internal_drop_count++; + dev_kfree_skb_any(skb); + return; + } + + skb->destructor = wlan_ipa_uc_rt_debug_destructor; + + if (ipa_ctx->send_to_nw) + ipa_ctx->send_to_nw(skb, iface_ctx->dev); + + ipa_ctx->ipa_rx_net_send_count++; +} + +/** + * wlan_ipa_forward() - handle packet forwarding to wlan tx + * @ipa_ctx: pointer to ipa ipa context + * @iface_ctx: interface context + * @skb: data pointer + * + * if exception packet has set forward bit, copied new packet should be + * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should + * put into pm queue and tx procedure will be differed + * + * Return: None + */ +static void wlan_ipa_forward(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_iface_context *iface_ctx, + qdf_nbuf_t skb) +{ + struct wlan_ipa_pm_tx_cb *pm_tx_cb; + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + + /* Set IPA ownership for intra-BSS Tx packets to avoid skb_orphan */ + qdf_nbuf_ipa_owned_set(skb); + + /* WLAN subsystem is in suspend, put in queue */ + if (ipa_ctx->suspended) { + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + ipa_info_rl("Tx in suspend, put in queue"); + qdf_mem_zero(skb->cb, sizeof(skb->cb)); + pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb; + pm_tx_cb->exception = true; + pm_tx_cb->iface_context = iface_ctx; + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb); + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + ipa_ctx->stats.num_tx_queued++; + } else { + /* Resume, put packet into WLAN TX */ + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + if (ipa_ctx->softap_xmit) { + if (ipa_ctx->softap_xmit(skb, iface_ctx->dev)) { + ipa_err_rl("packet Tx fail"); + ipa_ctx->stats.num_tx_fwd_err++; + } else { + ipa_ctx->stats.num_tx_fwd_ok++; + } + } else { + dev_kfree_skb_any(skb); + } + } +} + +/** + * wlan_ipa_intrabss_forward() - Forward intra bss packets. + * @ipa_ctx: pointer to IPA IPA struct + * @iface_ctx: ipa interface context + * @desc: Firmware descriptor + * @skb: Data buffer + * + * Return: + * WLAN_IPA_FORWARD_PKT_NONE + * WLAN_IPA_FORWARD_PKT_DISCARD + * WLAN_IPA_FORWARD_PKT_LOCAL_STACK + * + */ + +static enum wlan_ipa_forward_type wlan_ipa_intrabss_forward( + struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_iface_context *iface_ctx, + uint8_t desc, + qdf_nbuf_t skb) +{ + int ret = WLAN_IPA_FORWARD_PKT_NONE; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if ((desc & FW_RX_DESC_FORWARD_M)) { + if (!ol_txrx_fwd_desc_thresh_check( + (struct ol_txrx_vdev_t *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, + iface_ctx->session_id))) { + /* Drop the packet*/ + ipa_ctx->stats.num_tx_fwd_err++; + dev_kfree_skb_any(skb); + ret = WLAN_IPA_FORWARD_PKT_DISCARD; + return ret; + } + ipa_debug_rl("Forward packet to Tx (fw_desc=%d)", desc); + ipa_ctx->ipa_tx_forward++; + + if ((desc & FW_RX_DESC_DISCARD_M)) { + wlan_ipa_forward(ipa_ctx, iface_ctx, skb); + ipa_ctx->ipa_rx_internal_drop_count++; + ipa_ctx->ipa_rx_discard++; + ret = WLAN_IPA_FORWARD_PKT_DISCARD; + } else { + struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC); + + if (cloned_skb) + wlan_ipa_forward(ipa_ctx, iface_ctx, + cloned_skb); + else + ipa_err_rl("tx skb alloc failed"); + ret = WLAN_IPA_FORWARD_PKT_LOCAL_STACK; + } + } + + return ret; +} + +/** + * __wlan_ipa_w2i_cb() - WLAN to IPA callback handler + * @priv: pointer to private data registered with IPA (we register a + * pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void __wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt, + unsigned long data) +{ + struct wlan_ipa_priv *ipa_ctx = NULL; + qdf_nbuf_t skb; + uint8_t iface_id; + uint8_t session_id; + struct wlan_ipa_iface_context *iface_context; + uint8_t fw_desc; + + ipa_ctx = (struct wlan_ipa_priv *)priv; + if (!ipa_ctx) { + if (evt == IPA_RECEIVE) { + skb = (qdf_nbuf_t)data; + dev_kfree_skb_any(skb); + } + return; + } + + if (qdf_is_module_state_transitioning()) { + ipa_err_rl("Module transition in progress"); + if (evt == IPA_RECEIVE) { + skb = (qdf_nbuf_t)data; + ipa_ctx->ipa_rx_internal_drop_count++; + dev_kfree_skb_any(skb); + } + return; + } + + switch (evt) { + case IPA_RECEIVE: + skb = (qdf_nbuf_t) data; + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + session_id = (uint8_t)skb->cb[0]; + iface_id = ipa_ctx->vdev_to_iface[session_id]; + } else { + iface_id = WLAN_IPA_GET_IFACE_ID(skb->data); + } + if (iface_id >= WLAN_IPA_MAX_IFACE) { + ipa_err_rl("Invalid iface_id: %u", iface_id); + ipa_ctx->ipa_rx_internal_drop_count++; + dev_kfree_skb_any(skb); + return; + } + + iface_context = &ipa_ctx->iface_context[iface_id]; + if (!iface_context->tl_context) { + ipa_err_rl("TL context of iface_id %u is NULL", + iface_id); + ipa_ctx->ipa_rx_internal_drop_count++; + dev_kfree_skb_any(skb); + return; + } + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + ipa_ctx->stats.num_rx_excep++; + qdf_nbuf_pull_head(skb, WLAN_IPA_UC_WLAN_CLD_HDR_LEN); + } else { + qdf_nbuf_pull_head(skb, WLAN_IPA_WLAN_CLD_HDR_LEN); + } + + iface_context->stats.num_rx_ipa_excep++; + + /* Disable to forward Intra-BSS Rx packets when + * ap_isolate=1 in hostapd.conf + */ + if (!ipa_ctx->ap_intrabss_fwd) { + /* + * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send + * all Rx packets to IPA uC, which need to be forwarded + * to other interface. + * And, IPA driver will send back to WLAN host driver + * through exception pipe with fw_desc field set by FW. + * Here we are checking fw_desc field for FORWARD bit + * set, and forward to Tx. Then copy to kernel stack + * only when DISCARD bit is not set. + */ + fw_desc = (uint8_t)skb->cb[1]; + if (WLAN_IPA_FORWARD_PKT_DISCARD == + wlan_ipa_intrabss_forward(ipa_ctx, iface_context, + fw_desc, skb)) + break; + } else { + ipa_debug_rl("Intra-BSS forwarding is disabled"); + } + + wlan_ipa_send_skb_to_network(skb, iface_context); + break; + + default: + ipa_err_rl("w2i cb wrong event: 0x%x", evt); + return; + } +} + +/** + * wlan_ipa_w2i_cb() - SSR wrapper for __wlan_ipa_w2i_cb + * @priv: pointer to private data registered with IPA (we register a + * pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void wlan_ipa_w2i_cb(void *priv, qdf_ipa_dp_evt_type_t evt, + unsigned long data) +{ + qdf_ssr_protect(__func__); + __wlan_ipa_w2i_cb(priv, evt, data); + qdf_ssr_unprotect(__func__); +} + +/** + * __wlan_ipa_i2w_cb() - IPA to WLAN callback + * @priv: pointer to private data registered with IPA (we register a + * pointer to the interface-specific IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void __wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt, + unsigned long data) +{ + struct wlan_ipa_priv *ipa_ctx = NULL; + qdf_ipa_rx_data_t *ipa_tx_desc; + struct wlan_ipa_iface_context *iface_context; + qdf_nbuf_t skb; + struct wlan_ipa_pm_tx_cb *pm_tx_cb = NULL; + + iface_context = (struct wlan_ipa_iface_context *)priv; + ipa_tx_desc = (qdf_ipa_rx_data_t *)data; + ipa_ctx = iface_context->ipa_ctx; + + if (qdf_is_module_state_transitioning()) { + ipa_err_rl("Module transition in progress"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_drop++; + return; + } + + if (evt != IPA_RECEIVE) { + ipa_err_rl("Event is not IPA_RECEIVE"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_drop++; + return; + } + + skb = QDF_IPA_RX_DATA_SKB(ipa_tx_desc); + + /* + * If PROD resource is not requested here then there may be cases where + * IPA hardware may be clocked down because of not having proper + * dependency graph between WLAN CONS and modem PROD pipes. Adding the + * workaround to request PROD resource while data is going over CONS + * pipe to prevent the IPA hardware clockdown. + */ + wlan_ipa_wdi_rm_request(ipa_ctx); + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + /* + * If host is still suspended then queue the packets and these will be + * drained later when resume completes. When packet is arrived here and + * host is suspended, this means that there is already resume is in + * progress. + */ + if (ipa_ctx->suspended) { + qdf_mem_zero(skb->cb, sizeof(skb->cb)); + pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb; + pm_tx_cb->iface_context = iface_context; + pm_tx_cb->ipa_tx_desc = ipa_tx_desc; + qdf_nbuf_queue_add(&ipa_ctx->pm_queue_head, skb); + ipa_ctx->stats.num_tx_queued++; + + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + return; + } + + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + /* + * If we are here means, host is not suspended, wait for the work queue + * to finish. + */ + qdf_flush_work(&ipa_ctx->pm_work); + + return wlan_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc); +} + +/** + * wlan_ipa_i2w_cb() - IPA to WLAN callback + * @priv: pointer to private data registered with IPA (we register a + * pointer to the interface-specific IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void wlan_ipa_i2w_cb(void *priv, qdf_ipa_dp_evt_type_t evt, + unsigned long data) +{ + qdf_ssr_protect(__func__); + __wlan_ipa_i2w_cb(priv, evt, data); + qdf_ssr_unprotect(__func__); +} + +QDF_STATUS wlan_ipa_suspend(struct wlan_ipa_priv *ipa_ctx) +{ + /* + * Check if IPA is ready for suspend, If we are here means, there is + * high chance that suspend would go through but just to avoid any race + * condition after suspend started, these checks are conducted before + * allowing to suspend. + */ + if (atomic_read(&ipa_ctx->tx_ref_cnt)) + return QDF_STATUS_E_AGAIN; + + if (!wlan_ipa_is_rm_released(ipa_ctx)) + return QDF_STATUS_E_AGAIN; + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + ipa_ctx->suspended = true; + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_ipa_resume(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_sched_work(0, &ipa_ctx->pm_work); + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + ipa_ctx->suspended = false; + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_ipa_uc_enable_pipes(struct wlan_ipa_priv *ipa_ctx) +{ + int result; + + ipa_debug("enter"); + + if (!ipa_ctx->ipa_pipes_down) { + /* + * IPA WDI Pipes are already activated due to + * rm deferred resources grant + */ + ipa_warn("IPA WDI Pipes are already activated"); + goto end; + } + + result = cdp_ipa_enable_pipes(ipa_ctx->dp_soc, + ipa_ctx->dp_pdev); + if (result) { + ipa_err("Enable IPA WDI PIPE failed: ret=%d", result); + return QDF_STATUS_E_FAILURE; + } + + qdf_event_reset(&ipa_ctx->ipa_resource_comp); + ipa_ctx->ipa_pipes_down = false; + + cdp_ipa_enable_autonomy(ipa_ctx->dp_soc, + ipa_ctx->dp_pdev); + +end: + ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_ipa_uc_disable_pipes(struct wlan_ipa_priv *ipa_ctx) +{ + int result; + + ipa_debug("enter"); + + if (ipa_ctx->ipa_pipes_down) { + ipa_warn("IPA WDI Pipes are already deactivated"); + goto end; + } + + qdf_spin_lock_bh(&ipa_ctx->pipes_down_lock); + if (ipa_ctx->pipes_down_in_progress || ipa_ctx->ipa_pipes_down) { + ipa_warn("IPA WDI Pipes down already in progress"); + qdf_spin_unlock_bh(&ipa_ctx->pipes_down_lock); + return QDF_STATUS_E_ALREADY; + } + ipa_ctx->pipes_down_in_progress = true; + qdf_spin_unlock_bh(&ipa_ctx->pipes_down_lock); + + cdp_ipa_disable_autonomy(ipa_ctx->dp_soc, + ipa_ctx->dp_pdev); + + result = cdp_ipa_disable_pipes(ipa_ctx->dp_soc, + ipa_ctx->dp_pdev); + if (result) { + ipa_err("Disable IPA WDI PIPE failed: ret=%d", result); + ipa_ctx->pipes_down_in_progress = false; + return QDF_STATUS_E_FAILURE; + } + + ipa_ctx->ipa_pipes_down = true; + ipa_ctx->pipes_down_in_progress = false; + +end: + ipa_debug("exit: ipa_pipes_down=%d", ipa_ctx->ipa_pipes_down); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_ipa_uc_find_add_assoc_sta() - Find associated station + * @ipa_ctx: Global IPA IPA context + * @sta_add: Should station be added + * @sta_id: ID of the station being queried + * + * Return: true if the station was found + */ +static bool wlan_ipa_uc_find_add_assoc_sta(struct wlan_ipa_priv *ipa_ctx, + bool sta_add, uint8_t sta_id, + uint8_t *mac_addr) +{ + bool sta_found = false; + uint8_t idx; + + for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) { + if ((ipa_ctx->assoc_stas_map[idx].is_reserved) && + (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) { + sta_found = true; + break; + } + } + if (sta_add && sta_found) { + ipa_err("STA ID %d already exist, cannot add", sta_id); + return sta_found; + } + if (sta_add) { + for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) { + if (!ipa_ctx->assoc_stas_map[idx].is_reserved) { + ipa_ctx->assoc_stas_map[idx].is_reserved = true; + ipa_ctx->assoc_stas_map[idx].sta_id = sta_id; + qdf_mem_copy(&ipa_ctx->assoc_stas_map[idx]. + mac_addr, mac_addr, + QDF_NET_ETH_LEN); + return sta_found; + } + } + } + if (!sta_add && !sta_found) { + ipa_err("STA ID %d does not exist, cannot delete", sta_id); + return sta_found; + } + if (!sta_add) { + for (idx = 0; idx < WLAN_IPA_MAX_STA_COUNT; idx++) { + if ((ipa_ctx->assoc_stas_map[idx].is_reserved) && + (ipa_ctx->assoc_stas_map[idx].sta_id == sta_id)) { + ipa_ctx->assoc_stas_map[idx].is_reserved = + false; + ipa_ctx->assoc_stas_map[idx].sta_id = 0xFF; + qdf_mem_zero( + &ipa_ctx->assoc_stas_map[idx].mac_addr, + QDF_NET_ETH_LEN); + return sta_found; + } + } + } + + return sta_found; +} + +/** + * wlan_ipa_get_ifaceid() - Get IPA context interface ID + * @ipa_ctx: IPA context + * @session_id: Session ID + * + * Return: None + */ +static int wlan_ipa_get_ifaceid(struct wlan_ipa_priv *ipa_ctx, + uint8_t session_id) +{ + struct wlan_ipa_iface_context *iface_ctx; + int i; + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + if (iface_ctx->session_id == session_id) + break; + } + + return i; +} + +/** + * wlan_ipa_cleanup_iface() - Cleanup IPA on a given interface + * @iface_context: interface-specific IPA context + * + * Return: None + */ +static void wlan_ipa_cleanup_iface(struct wlan_ipa_iface_context *iface_context) +{ + struct wlan_ipa_priv *ipa_ctx = iface_context->ipa_ctx; + + ipa_debug("enter"); + + if (!iface_context->tl_context) + return; + + cdp_ipa_cleanup_iface(ipa_ctx->dp_soc, + iface_context->dev->name, + wlan_ipa_is_ipv6_enabled(ipa_ctx->config)); + + qdf_spin_lock_bh(&iface_context->interface_lock); + iface_context->tl_context = NULL; + iface_context->dev = NULL; + iface_context->device_mode = QDF_MAX_NO_OF_MODE; + iface_context->session_id = WLAN_IPA_MAX_SESSION; + iface_context->sta_id = WLAN_IPA_MAX_STA_COUNT; + qdf_spin_unlock_bh(&iface_context->interface_lock); + iface_context->ifa_address = 0; + if (!iface_context->ipa_ctx->num_iface) { + ipa_err("NUM INTF 0, Invalid"); + QDF_ASSERT(0); + } + iface_context->ipa_ctx->num_iface--; + ipa_debug("exit: num_iface=%d", iface_context->ipa_ctx->num_iface); +} + +/** + * wlan_ipa_setup_iface() - Setup IPA on a given interface + * @ipa_ctx: IPA IPA global context + * @net_dev: Interface net device + * @device_mode: Net interface device mode + * @adapter: Interface upon which IPA is being setup + * @sta_id: Station ID of the API instance + * @session_id: Station ID of the API instance + * + * Return: QDF STATUS + */ +static QDF_STATUS wlan_ipa_setup_iface(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev, + uint8_t device_mode, uint8_t sta_id, + uint8_t session_id) +{ + struct wlan_ipa_iface_context *iface_context = NULL; + void *tl_context = NULL; + int i; + QDF_STATUS status; + + /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during + * channel change indication. Since these indications are sent by lower + * layer as SAP updates and IPA doesn't have to do anything for these + * updates so ignoring! + */ + if (device_mode == QDF_SAP_MODE) { + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &(ipa_ctx->iface_context[i]); + if (iface_context->dev == net_dev) + return QDF_STATUS_SUCCESS; + } + } + + if (WLAN_IPA_MAX_IFACE == ipa_ctx->num_iface) { + ipa_err("Max interface reached %d", WLAN_IPA_MAX_IFACE); + status = QDF_STATUS_E_NOMEM; + QDF_ASSERT(0); + goto end; + } + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + if (ipa_ctx->iface_context[i].tl_context == NULL) { + iface_context = &(ipa_ctx->iface_context[i]); + break; + } + } + + if (iface_context == NULL) { + ipa_err("All the IPA interfaces are in use"); + status = QDF_STATUS_E_NOMEM; + QDF_ASSERT(0); + goto end; + } + + iface_context->sta_id = sta_id; + tl_context = (void *)cdp_peer_get_vdev_by_sta_id(ipa_ctx->dp_soc, + ipa_ctx->dp_pdev, + sta_id); + if (tl_context == NULL) { + ipa_err("Not able to get TL context sta_id: %d", sta_id); + status = QDF_STATUS_E_INVAL; + goto end; + } + + iface_context->tl_context = tl_context; + iface_context->dev = net_dev; + iface_context->device_mode = device_mode; + iface_context->session_id = session_id; + + status = cdp_ipa_setup_iface(ipa_ctx->dp_soc, net_dev->name, + net_dev->dev_addr, + iface_context->prod_client, + iface_context->cons_client, + session_id, + wlan_ipa_is_ipv6_enabled(ipa_ctx->config)); + if (status != QDF_STATUS_SUCCESS) + goto end; + + ipa_ctx->num_iface++; + + ipa_debug("exit: num_iface=%d", ipa_ctx->num_iface); + + return status; + +end: + if (iface_context) + wlan_ipa_cleanup_iface(iface_context); + + return status; +} + +/** + * wlan_ipa_uc_handle_first_con() - Handle first uC IPA connection + * @ipa_ctx: IPA context + * + * Return: QDF STATUS + */ +static QDF_STATUS wlan_ipa_uc_handle_first_con(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_debug("enter"); + + ipa_ctx->activated_fw_pipe = 0; + ipa_ctx->resource_loading = true; + + /* If RM feature enabled + * Request PROD Resource first + * PROD resource may return sync or async manners + */ + if (wlan_ipa_is_rm_enabled(ipa_ctx->config)) { + if (!wlan_ipa_wdi_rm_request_resource(ipa_ctx, + IPA_RM_RESOURCE_WLAN_PROD)) { + /* RM PROD request sync return + * enable pipe immediately + */ + if (wlan_ipa_uc_enable_pipes(ipa_ctx)) { + ipa_err("IPA WDI Pipe activation failed"); + ipa_ctx->resource_loading = false; + return QDF_STATUS_E_BUSY; + } + } else { + ipa_err("IPA WDI Pipe activation deferred"); + } + } else { + /* RM Disabled + * Just enabled all the PIPEs + */ + if (wlan_ipa_uc_enable_pipes(ipa_ctx)) { + ipa_err("IPA WDI Pipe activation failed"); + ipa_ctx->resource_loading = false; + return QDF_STATUS_E_BUSY; + } + ipa_ctx->resource_loading = false; + } + + ipa_debug("exit"); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection + * @ipa_ctx: IPA context + * + * Return: None + */ +static void wlan_ipa_uc_handle_last_discon(struct wlan_ipa_priv *ipa_ctx) +{ + ipa_debug("enter"); + + ipa_ctx->resource_unloading = true; + qdf_event_reset(&ipa_ctx->ipa_resource_comp); + ipa_info("Disable FW RX PIPE"); + cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, false, false); + + ipa_debug("exit: IPA WDI Pipes deactivated"); +} + +static inline +bool wlan_sap_no_client_connected(struct wlan_ipa_priv *ipa_ctx) +{ + return !(ipa_ctx->sap_num_connected_sta); +} + +static inline +bool wlan_sta_is_connected(struct wlan_ipa_priv *ipa_ctx) +{ + return ipa_ctx->sta_connected; +} + +static inline +bool wlan_ipa_uc_is_loaded(struct wlan_ipa_priv *ipa_ctx) +{ + return ipa_ctx->uc_loaded; +} + +/** + * wlan_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw + * @ipa_ctx: global IPA context + * @offload_type: MCC or SCC + * @session_id: Session Id + * @enable: TX offload enable or disable + * + * Return: none + */ +static void wlan_ipa_uc_offload_enable_disable(struct wlan_ipa_priv *ipa_ctx, + uint32_t offload_type, + uint8_t session_id, + bool enable) +{ + + struct ipa_uc_offload_control_params req = {0}; + + if (session_id >= WLAN_IPA_MAX_SESSION) { + ipa_err("invalid session id: %d", session_id); + return; + } + + if (enable == ipa_ctx->vdev_offload_enabled[session_id]) { + ipa_info("IPA offload status is already set"); + ipa_info("offload_type=%d, vdev_id=%d, enable=%d", + offload_type, session_id, enable); + return; + } + + ipa_info("offload_type=%d, session_id=%d, enable=%d", + offload_type, session_id, enable); + + req.offload_type = offload_type; + req.vdev_id = session_id; + req.enable = enable; + + if (QDF_STATUS_SUCCESS != + ipa_send_uc_offload_enable_disable(ipa_ctx->pdev, &req)) { + ipa_err("Fail to enable IPA offload"); + ipa_err("offload type=%d, vdev_id=%d, enable=%d", + offload_type, session_id, enable); + } else { + ipa_ctx->vdev_offload_enabled[session_id] = enable; + } +} + +/** + * __wlan_ipa_wlan_evt() - IPA event handler + * @net_dev: Interface net device + * @device_mode: Net interface device mode + * @sta_id: station id for the event + * @session_id: session id for the event + * @type: event enum of type ipa_wlan_event + * @mac_address: MAC address associated with the event + * + * This function is meant to be called from within wlan_ipa_ctx.c + * + * Return: QDF STATUS + */ +static QDF_STATUS __wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, + uint8_t sta_id, uint8_t session_id, + qdf_ipa_wlan_event type, + uint8_t *mac_addr) +{ + struct wlan_ipa_priv *ipa_ctx = gp_ipa; + struct wlan_ipa_iface_context *iface_ctx = NULL; + qdf_ipa_msg_meta_t meta; + qdf_ipa_wlan_msg_t *msg; + qdf_ipa_wlan_msg_ex_t *msg_ex = NULL; + int i; + QDF_STATUS status; + uint8_t sta_session_id = WLAN_IPA_MAX_SESSION; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + + ipa_debug("%s: EVT: %d, MAC: %pM, sta_id: %d", + net_dev->name, type, mac_addr, sta_id); + + if (type >= QDF_IPA_WLAN_EVENT_MAX) + return QDF_STATUS_E_INVAL; + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config) && + !wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) && + (device_mode != QDF_SAP_MODE)) { + return QDF_STATUS_SUCCESS; + } + + pdev = ipa_ctx->pdev; + psoc = wlan_pdev_get_psoc(pdev); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, session_id, + WLAN_IPA_ID); + QDF_BUG(session_id < WLAN_IPA_MAX_SESSION); + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_IPA_ID); + else + ipa_err("vdev is NULL, session_id: %u", session_id); + + if (ipa_ctx->sta_connected) { + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (iface_ctx) + sta_session_id = iface_ctx->session_id; + else + ipa_err("sta iface_ctx is NULL"); + } + + /* + * During IPA UC resource loading/unloading new events can be issued. + */ + if (wlan_ipa_uc_is_enabled(ipa_ctx->config) && + (ipa_ctx->resource_loading || ipa_ctx->resource_unloading)) { + unsigned int pending_event_count; + struct wlan_ipa_uc_pending_event *pending_event = NULL; + + ipa_info("Event:%d IPA resource %s inprogress", type, + ipa_ctx->resource_loading ? + "load" : "unload"); + + /* Wait until completion of the long/unloading */ + status = qdf_wait_for_event_completion( + &ipa_ctx->ipa_resource_comp, + IPA_RESOURCE_COMP_WAIT_TIME); + if (status != QDF_STATUS_SUCCESS) { + /* + * If timed out, store the events separately and + * handle them later. + */ + ipa_info("IPA resource %s timed out", + ipa_ctx->resource_loading ? + "load" : "unload"); + + if (type == QDF_IPA_AP_DISCONNECT) { + wlan_ipa_uc_offload_enable_disable(ipa_ctx, + SIR_AP_RX_DATA_OFFLOAD, + session_id, false); + } else if (type == QDF_IPA_CLIENT_CONNECT_EX && + wlan_sap_no_client_connected(ipa_ctx)) { + if (wlan_sta_is_connected(ipa_ctx) && + wlan_ipa_uc_is_loaded(ipa_ctx) && + wlan_ipa_uc_sta_is_enabled(ipa_ctx-> + config)) { + wlan_ipa_uc_offload_enable_disable( + ipa_ctx, + SIR_STA_RX_DATA_OFFLOAD, + sta_session_id, true); + } + } + + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + + pending_event_count = + qdf_list_size(&ipa_ctx->pending_event); + if (pending_event_count >= + WLAN_IPA_MAX_PENDING_EVENT_COUNT) { + ipa_info("Reached max pending evt count"); + qdf_list_remove_front( + &ipa_ctx->pending_event, + (qdf_list_node_t **)&pending_event); + } else { + pending_event = + (struct wlan_ipa_uc_pending_event *) + qdf_mem_malloc(sizeof( + struct wlan_ipa_uc_pending_event)); + } + + if (!pending_event) { + ipa_err("Pending event memory alloc fail"); + qdf_mutex_release(&ipa_ctx->ipa_lock); + return QDF_STATUS_E_NOMEM; + } + + pending_event->net_dev = net_dev; + pending_event->device_mode = device_mode; + pending_event->sta_id = sta_id; + pending_event->session_id = session_id; + pending_event->type = type; + pending_event->is_loading = ipa_ctx->resource_loading; + qdf_mem_copy(pending_event->mac_addr, + mac_addr, QDF_MAC_ADDR_SIZE); + qdf_list_insert_back(&ipa_ctx->pending_event, + &pending_event->node); + + qdf_mutex_release(&ipa_ctx->ipa_lock); + + /* Cleanup interface */ + if (type == QDF_IPA_STA_DISCONNECT || + type == QDF_IPA_AP_DISCONNECT) { + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + + if (iface_ctx->dev == net_dev) + break; + } + if (iface_ctx) + wlan_ipa_cleanup_iface(iface_ctx); + } + + return QDF_STATUS_SUCCESS; + } + ipa_info("IPA resource %s completed", + ipa_ctx->resource_loading ? + "load" : "unload"); + } + + ipa_ctx->stats.event[type]++; + + QDF_IPA_SET_META_MSG_TYPE(&meta, type); + switch (type) { + case QDF_IPA_STA_CONNECT: + qdf_mutex_acquire(&ipa_ctx->event_lock); + + /* STA already connected and without disconnect, connect again + * This is Roaming scenario + */ + if (ipa_ctx->sta_connected) { + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (iface_ctx) + wlan_ipa_cleanup_iface(iface_ctx); + } + + status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode, + sta_id, session_id); + if (status != QDF_STATUS_SUCCESS) { + qdf_mutex_release(&ipa_ctx->event_lock); + goto end; + } + + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) && + (ipa_ctx->sap_num_connected_sta > 0) && + !ipa_ctx->sta_connected) { + qdf_mutex_release(&ipa_ctx->event_lock); + wlan_ipa_uc_offload_enable_disable(ipa_ctx, + SIR_STA_RX_DATA_OFFLOAD, session_id, + true); + qdf_mutex_acquire(&ipa_ctx->event_lock); + } + + ipa_ctx->vdev_to_iface[session_id] = + wlan_ipa_get_ifaceid(ipa_ctx, session_id); + + ipa_ctx->sta_connected = 1; + + qdf_mutex_release(&ipa_ctx->event_lock); + + ipa_debug("sta_connected=%d", ipa_ctx->sta_connected); + break; + + case QDF_IPA_AP_CONNECT: + qdf_mutex_acquire(&ipa_ctx->event_lock); + + /* For DFS channel we get two start_bss event (before and after + * CAC). Also when ACS range includes both DFS and non DFS + * channels, we could possibly change channel many times due to + * RADAR detection and chosen channel may not be a DFS channels. + * So dont return error here. Just discard the event. + */ + if (ipa_ctx->vdev_to_iface[session_id] != + WLAN_IPA_MAX_SESSION) { + qdf_mutex_release(&ipa_ctx->event_lock); + return 0; + } + + status = wlan_ipa_setup_iface(ipa_ctx, net_dev, device_mode, + sta_id, session_id); + if (status != QDF_STATUS_SUCCESS) { + qdf_mutex_release(&ipa_ctx->event_lock); + ipa_err("%s: Evt: %d, Interface setup failed", + msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta)); + goto end; + } + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + qdf_mutex_release(&ipa_ctx->event_lock); + wlan_ipa_uc_offload_enable_disable(ipa_ctx, + SIR_AP_RX_DATA_OFFLOAD, session_id, true); + qdf_mutex_acquire(&ipa_ctx->event_lock); + } + + ipa_ctx->vdev_to_iface[session_id] = + wlan_ipa_get_ifaceid(ipa_ctx, session_id); + qdf_mutex_release(&ipa_ctx->event_lock); + break; + + case QDF_IPA_STA_DISCONNECT: + qdf_mutex_acquire(&ipa_ctx->event_lock); + + if (!ipa_ctx->sta_connected) { + struct wlan_ipa_iface_context *iface; + + qdf_mutex_release(&ipa_ctx->event_lock); + ipa_err("%s: Evt: %d, STA already disconnected", + msg_ex->name, QDF_IPA_MSG_META_MSG_TYPE(&meta)); + + iface = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (iface && (iface->dev == net_dev)) + wlan_ipa_cleanup_iface(iface); + + return QDF_STATUS_E_INVAL; + } + + ipa_ctx->sta_connected = 0; + + if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED", + msg_ex->name); + } else { + /* Disable IPA UC TX PIPE when STA disconnected */ + if ((ipa_ctx->num_iface == 1) && + wlan_ipa_is_fw_wdi_activated(ipa_ctx) && + !ipa_ctx->ipa_pipes_down && + (ipa_ctx->resource_unloading == false)) { + if (cds_is_driver_unloading()) { + /* + * We disable WDI pipes directly here + * since IPA_OPCODE_TX/RX_SUSPEND + * message will not be processed when + * unloading WLAN driver is in progress + */ + wlan_ipa_uc_disable_pipes(ipa_ctx); + } else { + wlan_ipa_uc_handle_last_discon(ipa_ctx); + } + } + } + + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) && + (ipa_ctx->sap_num_connected_sta > 0)) { + qdf_mutex_release(&ipa_ctx->event_lock); + wlan_ipa_uc_offload_enable_disable(ipa_ctx, + SIR_STA_RX_DATA_OFFLOAD, session_id, false); + qdf_mutex_acquire(&ipa_ctx->event_lock); + ipa_ctx->vdev_to_iface[session_id] = + WLAN_IPA_MAX_SESSION; + } + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + + if (iface_ctx->dev == net_dev) + break; + } + if (i < WLAN_IPA_MAX_IFACE) + wlan_ipa_cleanup_iface(iface_ctx); + + qdf_mutex_release(&ipa_ctx->event_lock); + + ipa_debug("sta_connected=%d", ipa_ctx->sta_connected); + break; + + case QDF_IPA_AP_DISCONNECT: + qdf_mutex_acquire(&ipa_ctx->event_lock); + + if ((ipa_ctx->num_iface == 1) && + wlan_ipa_is_fw_wdi_activated(ipa_ctx) && + !ipa_ctx->ipa_pipes_down && + (ipa_ctx->resource_unloading == false)) { + if (cds_is_driver_unloading()) { + /* + * We disable WDI pipes directly here since + * IPA_OPCODE_TX/RX_SUSPEND message will not be + * processed when unloading WLAN driver is in + * progress + */ + wlan_ipa_uc_disable_pipes(ipa_ctx); + } else { + /* + * This shouldn't happen : + * No interface left but WDI pipes are still + * active - force close WDI pipes + */ + ipa_err("No interface left but WDI pipes are still active"); + wlan_ipa_uc_handle_last_discon(ipa_ctx); + } + } + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + qdf_mutex_release(&ipa_ctx->event_lock); + wlan_ipa_uc_offload_enable_disable(ipa_ctx, + SIR_AP_RX_DATA_OFFLOAD, session_id, false); + qdf_mutex_acquire(&ipa_ctx->event_lock); + ipa_ctx->vdev_to_iface[session_id] = + WLAN_IPA_MAX_SESSION; + } + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + + if (iface_ctx->dev == net_dev) + break; + } + if (i < WLAN_IPA_MAX_IFACE) + wlan_ipa_cleanup_iface(iface_ctx); + + qdf_mutex_release(&ipa_ctx->event_lock); + break; + + case QDF_IPA_CLIENT_CONNECT_EX: + if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + ipa_debug("%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED", + net_dev->name, type); + return QDF_STATUS_SUCCESS; + } + + qdf_mutex_acquire(&ipa_ctx->event_lock); + if (wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, true, sta_id, + mac_addr)) { + qdf_mutex_release(&ipa_ctx->event_lock); + ipa_err("%s: STA ID %d found", net_dev->name, sta_id); + return QDF_STATUS_SUCCESS; + } + + /* Enable IPA UC Data PIPEs when first STA connected */ + if (ipa_ctx->sap_num_connected_sta == 0 && + ipa_ctx->uc_loaded == true) { + + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) && + ipa_ctx->sta_connected) { + qdf_mutex_release(&ipa_ctx->event_lock); + wlan_ipa_uc_offload_enable_disable(ipa_ctx, + SIR_STA_RX_DATA_OFFLOAD, + sta_session_id, true); + qdf_mutex_acquire(&ipa_ctx->event_lock); + } + + status = wlan_ipa_uc_handle_first_con(ipa_ctx); + if (status != QDF_STATUS_SUCCESS) { + ipa_info("%s: handle 1st con fail", + net_dev->name); + + if (wlan_ipa_uc_sta_is_enabled( + ipa_ctx->config) && + ipa_ctx->sta_connected) { + qdf_mutex_release(&ipa_ctx->event_lock); + wlan_ipa_uc_offload_enable_disable( + ipa_ctx, + SIR_STA_RX_DATA_OFFLOAD, + sta_session_id, false); + } else { + qdf_mutex_release(&ipa_ctx->event_lock); + } + + return status; + } + } + + ipa_ctx->sap_num_connected_sta++; + + qdf_mutex_release(&ipa_ctx->event_lock); + + QDF_IPA_SET_META_MSG_TYPE(&meta, type); + QDF_IPA_MSG_META_MSG_LEN(&meta) = + (sizeof(qdf_ipa_wlan_msg_ex_t) + + sizeof(qdf_ipa_wlan_hdr_attrib_val_t)); + msg_ex = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta)); + + if (msg_ex == NULL) { + ipa_err("msg_ex allocation failed"); + return QDF_STATUS_E_NOMEM; + } + strlcpy(msg_ex->name, net_dev->name, + IPA_RESOURCE_NAME_MAX); + msg_ex->num_of_attribs = 1; + msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR; + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + msg_ex->attribs[0].offset = + WLAN_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + } else { + msg_ex->attribs[0].offset = + WLAN_IPA_WLAN_HDR_DES_MAC_OFFSET; + } + memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr, + IPA_MAC_ADDR_SIZE); + + if (qdf_ipa_send_msg(&meta, msg_ex, wlan_ipa_msg_free_fn)) { + ipa_info("%s: Evt: %d send ipa msg fail", + net_dev->name, type); + qdf_mem_free(msg_ex); + return QDF_STATUS_E_FAILURE; + } + ipa_ctx->stats.num_send_msg++; + + ipa_info("sap_num_connected_sta=%d", + ipa_ctx->sap_num_connected_sta); + + return QDF_STATUS_SUCCESS; + + case WLAN_CLIENT_DISCONNECT: + if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + ipa_debug("%s: IPA UC OFFLOAD NOT ENABLED", + msg_ex->name); + return QDF_STATUS_SUCCESS; + } + + qdf_mutex_acquire(&ipa_ctx->event_lock); + if (!ipa_ctx->sap_num_connected_sta) { + qdf_mutex_release(&ipa_ctx->event_lock); + ipa_err("%s: Evt: %d, Client already disconnected", + msg_ex->name, + QDF_IPA_MSG_META_MSG_TYPE(&meta)); + + return QDF_STATUS_SUCCESS; + } + if (!wlan_ipa_uc_find_add_assoc_sta(ipa_ctx, false, + sta_id, mac_addr)) { + qdf_mutex_release(&ipa_ctx->event_lock); + ipa_err("%s: STA ID %d NOT found, not valid", + msg_ex->name, sta_id); + + return QDF_STATUS_SUCCESS; + } + ipa_ctx->sap_num_connected_sta--; + + /* Disable IPA UC TX PIPE when last STA disconnected */ + if (!ipa_ctx->sap_num_connected_sta && + ipa_ctx->uc_loaded == true) { + if ((false == ipa_ctx->resource_unloading) && + wlan_ipa_is_fw_wdi_activated(ipa_ctx) && + !ipa_ctx->ipa_pipes_down) { + if (cds_is_driver_unloading()) { + /* + * We disable WDI pipes directly here + * since IPA_OPCODE_TX/RX_SUSPEND + * message will not be processed when + * unloading WLAN driver is in progress + */ + wlan_ipa_uc_disable_pipes(ipa_ctx); + } else { + wlan_ipa_uc_handle_last_discon(ipa_ctx); + } + } + + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config) && + ipa_ctx->sta_connected) { + qdf_mutex_release(&ipa_ctx->event_lock); + wlan_ipa_uc_offload_enable_disable(ipa_ctx, + SIR_STA_RX_DATA_OFFLOAD, + sta_session_id, false); + } else { + qdf_mutex_release(&ipa_ctx->event_lock); + } + } else { + qdf_mutex_release(&ipa_ctx->event_lock); + } + + ipa_info("sap_num_connected_sta=%d", + ipa_ctx->sap_num_connected_sta); + break; + + default: + return QDF_STATUS_SUCCESS; + } + + QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t); + msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta)); + if (!msg) { + ipa_err("msg allocation failed"); + return QDF_STATUS_E_NOMEM; + } + + QDF_IPA_SET_META_MSG_TYPE(&meta, type); + strlcpy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name, + IPA_RESOURCE_NAME_MAX); + qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN); + + ipa_debug("%s: Evt: %d", QDF_IPA_WLAN_MSG_NAME(msg), + QDF_IPA_MSG_META_MSG_TYPE(&meta)); + + if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) { + + ipa_err("%s: Evt: %d fail", + QDF_IPA_WLAN_MSG_NAME(msg), + QDF_IPA_MSG_META_MSG_TYPE(&meta)); + qdf_mem_free(msg); + + return QDF_STATUS_E_FAILURE; + } + + ipa_ctx->stats.num_send_msg++; + +end: + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_host_to_ipa_wlan_event() - convert wlan_ipa_wlan_event to ipa_wlan_event + * @wlan_ipa_event_type: event to be converted to an ipa_wlan_event + * + * Return: qdf_ipa_wlan_event representing the wlan_ipa_wlan_event + */ +static qdf_ipa_wlan_event +wlan_host_to_ipa_wlan_event(enum wlan_ipa_wlan_event wlan_ipa_event_type) +{ + qdf_ipa_wlan_event ipa_event; + + switch (wlan_ipa_event_type) { + case WLAN_IPA_CLIENT_CONNECT: + ipa_event = QDF_IPA_CLIENT_CONNECT; + break; + case WLAN_IPA_CLIENT_DISCONNECT: + ipa_event = QDF_IPA_CLIENT_DISCONNECT; + break; + case WLAN_IPA_AP_CONNECT: + ipa_event = QDF_IPA_AP_CONNECT; + break; + case WLAN_IPA_AP_DISCONNECT: + ipa_event = QDF_IPA_AP_DISCONNECT; + break; + case WLAN_IPA_STA_CONNECT: + ipa_event = QDF_IPA_STA_CONNECT; + break; + case WLAN_IPA_STA_DISCONNECT: + ipa_event = QDF_IPA_STA_DISCONNECT; + break; + case WLAN_IPA_CLIENT_CONNECT_EX: + ipa_event = QDF_IPA_CLIENT_CONNECT_EX; + break; + case WLAN_IPA_WLAN_EVENT_MAX: + default: + ipa_event = QDF_IPA_WLAN_EVENT_MAX; + break; + } + + return ipa_event; +} + +/** + * wlan_ipa_wlan_evt() - SSR wrapper for __wlan_ipa_wlan_evt + * @net_dev: Interface net device + * @device_mode: Net interface device mode + * @sta_id: station id for the event + * @session_id: session id for the event + * @ipa_event_type: event enum of type wlan_ipa_wlan_event + * @mac_address: MAC address associated with the event + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_wlan_evt(qdf_netdev_t net_dev, uint8_t device_mode, + uint8_t sta_id, uint8_t session_id, + enum wlan_ipa_wlan_event ipa_event_type, + uint8_t *mac_addr) +{ + qdf_ipa_wlan_event type = wlan_host_to_ipa_wlan_event(ipa_event_type); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* Data path offload only support for STA and SAP mode */ + if ((device_mode == QDF_STA_MODE) || + (device_mode == QDF_SAP_MODE)) + status = __wlan_ipa_wlan_evt(net_dev, device_mode, sta_id, + session_id, type, mac_addr); + + return status; +} + +/** + * wlan_ipa_uc_proc_pending_event() - Process IPA uC pending events + * @ipa_ctx: Global IPA IPA context + * @is_loading: Indicate if invoked during loading + * + * Return: None + */ +static void +wlan_ipa_uc_proc_pending_event(struct wlan_ipa_priv *ipa_ctx, bool is_loading) +{ + unsigned int pending_event_count; + struct wlan_ipa_uc_pending_event *pending_event = NULL; + + pending_event_count = qdf_list_size(&ipa_ctx->pending_event); + ipa_debug("Pending Event Count %d", pending_event_count); + if (!pending_event_count) { + ipa_debug("No Pending Event"); + return; + } + + qdf_list_remove_front(&ipa_ctx->pending_event, + (qdf_list_node_t **)&pending_event); + while (pending_event != NULL) { + struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + struct wlan_objmgr_vdev *vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + pending_event->session_id, + WLAN_IPA_ID); + if (pending_event->is_loading == is_loading && vdev) { + __wlan_ipa_wlan_evt(pending_event->net_dev, + pending_event->device_mode, + pending_event->sta_id, + pending_event->session_id, + pending_event->type, + pending_event->mac_addr); + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_IPA_ID); + qdf_mem_free(pending_event); + pending_event = NULL; + qdf_list_remove_front(&ipa_ctx->pending_event, + (qdf_list_node_t **)&pending_event); + } +} + +/** + * wlan_ipa_free_tx_desc_list() - Free IPA Tx desc list + * @ipa_ctx: IPA context + * + * Return: None + */ +static inline void wlan_ipa_free_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_tx_desc *tmp_desc; + qdf_ipa_rx_data_t *ipa_tx_desc; + qdf_list_node_t *node; + + while (qdf_list_remove_front(&ipa_ctx->tx_desc_list, &node) == + QDF_STATUS_SUCCESS) { + tmp_desc = qdf_container_of(node, struct wlan_ipa_tx_desc, + node); + + ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr; + if (ipa_tx_desc) + qdf_ipa_free_skb(ipa_tx_desc); + + qdf_mem_free(tmp_desc); + tmp_desc = NULL; + } +} + +/** + * wlan_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_ipa_alloc_tx_desc_list(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + uint32_t max_desc_cnt; + struct wlan_ipa_tx_desc *tmp_desc; + + max_desc_cnt = ipa_ctx->config->txbuf_count; + + qdf_list_create(&ipa_ctx->tx_desc_list, max_desc_cnt); + + qdf_spin_lock_bh(&ipa_ctx->q_lock); + for (i = 0; i < max_desc_cnt; i++) { + tmp_desc = qdf_mem_malloc(sizeof(*tmp_desc)); + + if (!tmp_desc) { + qdf_spin_unlock_bh(&ipa_ctx->q_lock); + goto alloc_fail; + } + + tmp_desc->id = i; + tmp_desc->ipa_tx_desc_ptr = NULL; + qdf_list_insert_back(&ipa_ctx->tx_desc_list, + &tmp_desc->node); + tmp_desc++; + } + + ipa_ctx->stats.num_tx_desc_q_cnt = 0; + ipa_ctx->stats.num_tx_desc_error = 0; + + qdf_spin_unlock_bh(&ipa_ctx->q_lock); + + return QDF_STATUS_SUCCESS; + +alloc_fail: + wlan_ipa_free_tx_desc_list(ipa_ctx); + return QDF_STATUS_E_NOMEM; + +} + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes + * @ipa_ctx: Global IPA IPA context + * @desc_fifo_sz: Number of descriptors + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + int32_t desc_fifo_sz) +{ + int i, ret = 0; + qdf_ipa_sys_connect_params_t *ipa; + + /*setup TX pipes */ + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + ipa = &ipa_ctx->sys_pipe[i].ipa_sys_params; + + ipa->client = wlan_ipa_iface_2_client[i].cons_client; + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = &ipa_ctx->iface_context[i]; + ipa->notify = wlan_ipa_i2w_cb; + + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + ipa->ipa_ep_cfg.hdr.hdr_len = + WLAN_IPA_UC_WLAN_TX_HDR_LEN; + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + ipa->ipa_ep_cfg.hdr.hdr_additional_const_len = + WLAN_IPA_UC_WLAN_8023_HDR_SIZE; + ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + } else { + ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_TX_HDR_LEN; + } + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + ret = wlan_ipa_wdi_setup_sys_pipe(ipa_ctx, ipa, + &ipa_ctx->sys_pipe[i].conn_hdl); + if (ret) { + ipa_err("Failed for pipe %d ret: %d", i, ret); + return ret; + } + ipa_ctx->sys_pipe[i].conn_hdl_valid = 1; + } + + return ret; +} +#else +/** + * wlan_ipa_setup_tx_sys_pipe() - Setup IPA Tx system pipes + * @ipa_ctx: Global IPA IPA context + * @desc_fifo_sz: Number of descriptors + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_tx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + int32_t desc_fifo_sz) +{ + /* + * The Tx system pipes are not needed for MCC when TX_FLOW_CONTROL_V2 + * is enabled, where per vdev descriptors are supported in firmware. + */ + return 0; +} +#endif + +/** + * wlan_ipa_setup_rx_sys_pipe() - Setup IPA Rx system pipes + * @ipa_ctx: Global IPA IPA context + * @desc_fifo_sz: Number of descriptors + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_rx_sys_pipe(struct wlan_ipa_priv *ipa_ctx, + int32_t desc_fifo_sz) +{ + int ret = 0; + qdf_ipa_sys_connect_params_t *ipa; + + /* + * Hard code it here, this can be extended if in case + * PROD pipe is also per interface. + * Right now there is no advantage of doing this. + */ + ipa = &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].ipa_sys_params; + + ipa->client = IPA_CLIENT_WLAN1_PROD; + + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = ipa_ctx; + ipa->notify = wlan_ipa_w2i_cb; + + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_len = WLAN_IPA_WLAN_RX_HDR_LEN; + ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + ret = qdf_ipa_setup_sys_pipe(ipa, + &ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl); + if (ret) { + ipa_err("Failed for RX pipe: %d", ret); + return ret; + } + ipa_ctx->sys_pipe[WLAN_IPA_RX_PIPE].conn_hdl_valid = 1; + + return ret; +} + +/** + * wlan_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes + * @ipa_ctx: Global IPA IPA context + * + * Return: None + */ +static void wlan_ipa_teardown_sys_pipe(struct wlan_ipa_priv *ipa_ctx) +{ + int ret, i; + + if (!ipa_ctx) + return; + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { + if (ipa_ctx->sys_pipe[i].conn_hdl_valid) { + ret = wlan_ipa_wdi_teardown_sys_pipe(ipa_ctx, + ipa_ctx->sys_pipe[i].conn_hdl); + if (ret) + ipa_err("Failed:%d", ret); + + ipa_ctx->sys_pipe[i].conn_hdl_valid = 0; + } + } + + wlan_ipa_free_tx_desc_list(ipa_ctx); +} + +/** + * wlan_ipa_setup_sys_pipe() - Setup all IPA system pipes + * @ipa_ctx: Global IPA IPA context + * + * Return: 0 on success, negative errno on error + */ +static int wlan_ipa_setup_sys_pipe(struct wlan_ipa_priv *ipa_ctx) +{ + int ret = 0; + uint32_t desc_fifo_sz; + + /* The maximum number of descriptors that can be provided to a BAM at + * once is one less than the total number of descriptors that the buffer + * can contain. + * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof + * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can + * be provided at once. + * Because of above requirement, one extra descriptor will be added to + * make sure hardware always has one descriptor. + */ + desc_fifo_sz = ipa_ctx->config->desc_size + + SPS_DESC_SIZE; + + ret = wlan_ipa_setup_tx_sys_pipe(ipa_ctx, desc_fifo_sz); + if (ret) { + ipa_err("Failed for TX pipe: %d", ret); + goto setup_sys_pipe_fail; + } + + if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + ret = wlan_ipa_setup_rx_sys_pipe(ipa_ctx, desc_fifo_sz); + if (ret) { + ipa_err("Failed for RX pipe: %d", ret); + goto setup_sys_pipe_fail; + } + } + + /* Allocate free Tx desc list */ + ret = wlan_ipa_alloc_tx_desc_list(ipa_ctx); + if (ret) + goto setup_sys_pipe_fail; + + return ret; + +setup_sys_pipe_fail: + wlan_ipa_teardown_sys_pipe(ipa_ctx); + + return ret; +} + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +QDF_STATUS wlan_ipa_send_mcc_scc_msg(struct wlan_ipa_priv *ipa_ctx, + bool mcc_mode) +{ + qdf_ipa_msg_meta_t meta; + qdf_ipa_wlan_msg_t *msg; + int ret; + + if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) + return QDF_STATUS_SUCCESS; + + /* Send SCC/MCC Switching event to IPA */ + QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(*msg); + msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta)); + if (msg == NULL) { + ipa_err("msg allocation failed"); + return QDF_STATUS_E_NOMEM; + } + + if (mcc_mode) { + QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_MCC); + ipa_ctx->stats.event[QDF_SWITCH_TO_MCC]++; + } else { + QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_SWITCH_TO_SCC); + ipa_ctx->stats.event[QDF_SWITCH_TO_SCC]++; + } + + WLAN_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "ipa_send_msg(Evt:%d)", + QDF_IPA_MSG_META_MSG_TYPE(&meta)); + + ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn); + + if (ret) { + ipa_err("ipa_send_msg(Evt:%d) - fail=%d", + QDF_IPA_MSG_META_MSG_TYPE(&meta), ret); + qdf_mem_free(msg); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static void wlan_ipa_mcc_work_handler(void *data) +{ + struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)data; + + wlan_ipa_send_mcc_scc_msg(ipa_ctx, ipa_ctx->mcc_mode); +} +#endif + +/** + * wlan_ipa_setup() - IPA initialization function + * @ipa_ctx: IPA context + * @ipa_cfg: IPA config + * + * Allocate ipa_ctx resources, ipa pipe resource and register + * wlan interface with IPA module. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wlan_ipa_setup(struct wlan_ipa_priv *ipa_ctx, + struct wlan_ipa_config *ipa_cfg) +{ + int ret, i; + struct wlan_ipa_iface_context *iface_context = NULL; + QDF_STATUS status; + + ipa_debug("enter"); + + gp_ipa = ipa_ctx; + ipa_ctx->num_iface = 0; + ipa_ctx->config = ipa_cfg; + + wlan_ipa_wdi_get_wdi_version(ipa_ctx); + + /* Create the interface context */ + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &ipa_ctx->iface_context[i]; + iface_context->ipa_ctx = ipa_ctx; + iface_context->cons_client = + wlan_ipa_iface_2_client[i].cons_client; + iface_context->prod_client = + wlan_ipa_iface_2_client[i].prod_client; + iface_context->iface_id = i; + iface_context->dev = NULL; + iface_context->device_mode = QDF_MAX_NO_OF_MODE; + iface_context->tl_context = NULL; + qdf_spinlock_create(&iface_context->interface_lock); + } + + qdf_create_work(0, &ipa_ctx->pm_work, wlan_ipa_pm_flush, ipa_ctx); + qdf_spinlock_create(&ipa_ctx->pm_lock); + qdf_spinlock_create(&ipa_ctx->q_lock); + qdf_spinlock_create(&ipa_ctx->pipes_down_lock); + qdf_nbuf_queue_init(&ipa_ctx->pm_queue_head); + qdf_list_create(&ipa_ctx->pending_event, 1000); + qdf_mutex_create(&ipa_ctx->event_lock); + qdf_mutex_create(&ipa_ctx->ipa_lock); + + status = wlan_ipa_wdi_setup_rm(ipa_ctx); + if (status != QDF_STATUS_SUCCESS) + goto fail_setup_rm; + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) + qdf_mem_zero(&ipa_ctx->sys_pipe[i], + sizeof(struct wlan_ipa_sys_pipe)); + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + qdf_mem_zero(&ipa_ctx->stats, sizeof(ipa_ctx->stats)); + ipa_ctx->sap_num_connected_sta = 0; + ipa_ctx->ipa_tx_packets_diff = 0; + ipa_ctx->ipa_rx_packets_diff = 0; + ipa_ctx->ipa_p_tx_packets = 0; + ipa_ctx->ipa_p_rx_packets = 0; + ipa_ctx->resource_loading = false; + ipa_ctx->resource_unloading = false; + ipa_ctx->sta_connected = 0; + ipa_ctx->ipa_pipes_down = true; + ipa_ctx->pipes_down_in_progress = false; + ipa_ctx->wdi_enabled = false; + /* Setup IPA system pipes */ + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + ret = wlan_ipa_setup_sys_pipe(ipa_ctx); + if (ret) + goto fail_create_sys_pipe; + + qdf_create_work(0, &ipa_ctx->mcc_work, + wlan_ipa_mcc_work_handler, ipa_ctx); + } + + status = wlan_ipa_wdi_init(ipa_ctx); + if (status == QDF_STATUS_E_BUSY) + status = wlan_ipa_uc_send_wdi_control_msg(false); + if (status != QDF_STATUS_SUCCESS) { + ipa_err("IPA WDI init failed: ret=%d", status); + goto fail_create_sys_pipe; + } + } else { + ret = wlan_ipa_setup_sys_pipe(ipa_ctx); + if (ret) + goto fail_create_sys_pipe; + } + + qdf_event_create(&ipa_ctx->ipa_resource_comp); + + ipa_debug("exit: success"); + + return QDF_STATUS_SUCCESS; + +fail_create_sys_pipe: + wlan_ipa_wdi_destroy_rm(ipa_ctx); + +fail_setup_rm: + qdf_spinlock_destroy(&ipa_ctx->pm_lock); + qdf_spinlock_destroy(&ipa_ctx->q_lock); + qdf_spinlock_destroy(&ipa_ctx->pipes_down_lock); + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &ipa_ctx->iface_context[i]; + qdf_spinlock_destroy(&iface_context->interface_lock); + } + qdf_mutex_destroy(&ipa_ctx->event_lock); + qdf_mutex_destroy(&ipa_ctx->ipa_lock); + qdf_list_destroy(&ipa_ctx->pending_event); + gp_ipa = NULL; + ipa_debug("exit: fail"); + + return QDF_STATUS_E_FAILURE; +} + +void wlan_ipa_flush(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_nbuf_t skb; + struct wlan_ipa_pm_tx_cb *pm_tx_cb; + + if (!wlan_ipa_is_enabled(ipa_ctx->config)) + return; + + qdf_cancel_work(&ipa_ctx->pm_work); + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + + while (((skb = qdf_nbuf_queue_remove(&ipa_ctx->pm_queue_head)) + != NULL)) { + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + pm_tx_cb = (struct wlan_ipa_pm_tx_cb *)skb->cb; + + if (pm_tx_cb->exception) { + dev_kfree_skb_any(skb); + } else { + if (pm_tx_cb->ipa_tx_desc) + ipa_free_skb(pm_tx_cb->ipa_tx_desc); + } + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + } + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); +} + +QDF_STATUS wlan_ipa_cleanup(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_iface_context *iface_context; + int i; + + if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) + wlan_ipa_teardown_sys_pipe(ipa_ctx); + + /* Teardown IPA sys_pipe for MCC */ + if (wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) { + wlan_ipa_teardown_sys_pipe(ipa_ctx); + qdf_cancel_work(&ipa_ctx->mcc_work); + } + + wlan_ipa_wdi_destroy_rm(ipa_ctx); + + wlan_ipa_flush(ipa_ctx); + + qdf_spinlock_destroy(&ipa_ctx->pm_lock); + qdf_spinlock_destroy(&ipa_ctx->q_lock); + qdf_spinlock_destroy(&ipa_ctx->pipes_down_lock); + + /* destroy the interface lock */ + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &ipa_ctx->iface_context[i]; + qdf_spinlock_destroy(&iface_context->interface_lock); + } + + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + wlan_ipa_wdi_cleanup(); + qdf_mutex_destroy(&ipa_ctx->event_lock); + qdf_mutex_destroy(&ipa_ctx->ipa_lock); + qdf_list_destroy(&ipa_ctx->pending_event); + + } + + gp_ipa = NULL; + + return QDF_STATUS_SUCCESS; +} + +struct wlan_ipa_iface_context +*wlan_ipa_get_iface(struct wlan_ipa_priv *ipa_ctx, uint8_t mode) +{ + struct wlan_ipa_iface_context *iface_ctx = NULL; + int i; + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + + if (iface_ctx->device_mode == mode) + return iface_ctx; + } + + return NULL; +} + +void wlan_ipa_set_mcc_mode(struct wlan_ipa_priv *ipa_ctx, bool mcc_mode) +{ + if (!wlan_ipa_uc_sta_is_enabled(ipa_ctx->config)) + return; + + if (ipa_ctx->mcc_mode == mcc_mode) + return; + + ipa_ctx->mcc_mode = mcc_mode; + qdf_sched_work(0, &ipa_ctx->mcc_work); +} + +/** + * wlan_ipa_uc_loaded_handler() - Process IPA uC loaded indication + * @ipa_ctx: ipa ipa local context + * + * Will handle IPA UC image loaded indication comes from IPA kernel + * + * Return: None + */ +static void wlan_ipa_uc_loaded_handler(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_objmgr_pdev *pdev = ipa_ctx->pdev; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + qdf_device_t qdf_dev = wlan_psoc_get_qdf_dev(psoc); + QDF_STATUS status; + + ipa_info("UC READY"); + + if (!qdf_dev) { + ipa_err("qdf device is NULL!"); + return; + } + + if (true == ipa_ctx->uc_loaded) { + ipa_info("UC already loaded"); + return; + } + + if (!qdf_dev) { + ipa_err("qdf_dev is null"); + return; + } + /* Connect pipe */ + status = wlan_ipa_wdi_setup(ipa_ctx, qdf_dev); + if (status) { + ipa_err("Failure to setup IPA pipes (status=%d)", + status); + return; + } + + cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev); + + /* If already any STA connected, enable IPA/FW PIPEs */ + if (ipa_ctx->sap_num_connected_sta) { + ipa_debug("Client already connected, enable IPA/FW PIPEs"); + wlan_ipa_uc_handle_first_con(ipa_ctx); + } +} + +/** + * wlan_ipa_uc_op_cb() - IPA uC operation callback + * @op_msg: operation message received from firmware + * @usr_ctxt: user context registered with TL (we register the IPA Global + * context) + * + * Return: None + */ +static void wlan_ipa_uc_op_cb(struct op_msg_type *op_msg, + struct wlan_ipa_priv *ipa_ctx) +{ + struct op_msg_type *msg = op_msg; + struct ipa_uc_fw_stats *uc_fw_stat; + + if (!op_msg) { + ipa_err("INVALID ARG"); + return; + } + + if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) { + ipa_err("INVALID OPCODE %d", msg->op_code); + qdf_mem_free(op_msg); + return; + } + + ipa_debug("OPCODE=%d", msg->op_code); + + if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_RESUME) || + (msg->op_code == WLAN_IPA_UC_OPCODE_RX_RESUME)) { + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + ipa_ctx->activated_fw_pipe++; + if (wlan_ipa_is_fw_wdi_activated(ipa_ctx)) { + ipa_ctx->resource_loading = false; + qdf_event_set(&ipa_ctx->ipa_resource_comp); + if (ipa_ctx->wdi_enabled == false) { + ipa_ctx->wdi_enabled = true; + if (wlan_ipa_uc_send_wdi_control_msg(true) == 0) + wlan_ipa_send_mcc_scc_msg(ipa_ctx, + ipa_ctx->mcc_mode); + } + wlan_ipa_uc_proc_pending_event(ipa_ctx, true); + if (ipa_ctx->pending_cons_req) + wlan_ipa_wdi_rm_notify_completion( + QDF_IPA_RM_RESOURCE_GRANTED, + QDF_IPA_RM_RESOURCE_WLAN_CONS); + ipa_ctx->pending_cons_req = false; + } + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_TX_SUSPEND) || + (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND)) { + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + + if (msg->op_code == WLAN_IPA_UC_OPCODE_RX_SUSPEND) { + wlan_ipa_uc_disable_pipes(ipa_ctx); + ipa_info("Disable FW TX PIPE"); + cdp_ipa_set_active(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + false, true); + } + + ipa_ctx->activated_fw_pipe--; + if (!ipa_ctx->activated_fw_pipe) { + /* + * Async return success from FW + * Disable/suspend all the PIPEs + */ + ipa_ctx->resource_unloading = false; + qdf_event_set(&ipa_ctx->ipa_resource_comp); + if (wlan_ipa_is_rm_enabled(ipa_ctx->config)) + wlan_ipa_wdi_rm_release_resource(ipa_ctx, + QDF_IPA_RM_RESOURCE_WLAN_PROD); + wlan_ipa_uc_proc_pending_event(ipa_ctx, false); + ipa_ctx->pending_cons_req = false; + } + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) && + (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_DEBUG)) { + uc_fw_stat = (struct ipa_uc_fw_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + /* WLAN FW WDI stats */ + wlan_ipa_print_fw_wdi_stats(ipa_ctx, uc_fw_stat); + } else if ((msg->op_code == WLAN_IPA_UC_OPCODE_STATS) && + (ipa_ctx->stat_req_reason == WLAN_IPA_UC_STAT_REASON_BW_CAL)) { + /* STATs from FW */ + uc_fw_stat = (struct ipa_uc_fw_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + ipa_ctx->ipa_tx_packets_diff = BW_GET_DIFF( + uc_fw_stat->tx_pkts_completed, + ipa_ctx->ipa_p_tx_packets); + ipa_ctx->ipa_rx_packets_diff = BW_GET_DIFF( + (uc_fw_stat->rx_num_ind_drop_no_space + + uc_fw_stat->rx_num_ind_drop_no_buf + + uc_fw_stat->rx_num_pkts_indicated), + ipa_ctx->ipa_p_rx_packets); + + ipa_ctx->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed; + ipa_ctx->ipa_p_rx_packets = + (uc_fw_stat->rx_num_ind_drop_no_space + + uc_fw_stat->rx_num_ind_drop_no_buf + + uc_fw_stat->rx_num_pkts_indicated); + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else if (msg->op_code == WLAN_IPA_UC_OPCODE_UC_READY) { + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + wlan_ipa_uc_loaded_handler(ipa_ctx); + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else if (wlan_ipa_uc_op_metering(ipa_ctx, op_msg)) { + ipa_err("Invalid message: op_code=%d, reason=%d", + msg->op_code, ipa_ctx->stat_req_reason); + } + + qdf_mem_free(op_msg); +} + +/** + * __wlan_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler + * @data: uC OP work + * + * Return: None + */ +static void __wlan_ipa_uc_fw_op_event_handler(void *data) +{ + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work = + (struct uc_op_work_struct *)data; + struct wlan_ipa_priv *ipa_ctx = gp_ipa; + + if (qdf_is_module_state_transitioning()) { + ipa_err("Module transition in progress"); + return; + } + + msg = uc_op_work->msg; + uc_op_work->msg = NULL; + ipa_debug("posted msg %d", msg->op_code); + + wlan_ipa_uc_op_cb(msg, ipa_ctx); +} + +/** + * wlan_ipa_uc_fw_op_event_handler - SSR wrapper for + * __wlan_ipa_uc_fw_op_event_handler + * @data: uC OP work + * + * Return: None + */ +static void wlan_ipa_uc_fw_op_event_handler(void *data) +{ + qdf_ssr_protect(__func__); + __wlan_ipa_uc_fw_op_event_handler(data); + qdf_ssr_unprotect(__func__); +} + +/** + * wlan_ipa_uc_op_event_handler() - IPA UC OP event handler + * @op_msg: operation message received from firmware + * @ipa_ctx: Global IPA context + * + * Return: None + */ +static void wlan_ipa_uc_op_event_handler(uint8_t *op_msg, void *ctx) +{ + struct wlan_ipa_priv *ipa_ctx = (struct wlan_ipa_priv *)ctx; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + + if (!ipa_ctx) + goto end; + + msg = (struct op_msg_type *)op_msg; + + if (msg->op_code >= WLAN_IPA_UC_OPCODE_MAX) { + ipa_err("Invalid OP Code (%d)", msg->op_code); + goto end; + } + + uc_op_work = &ipa_ctx->uc_op_work[msg->op_code]; + if (uc_op_work->msg) { + /* When the same uC OPCODE is already pended, just return */ + goto end; + } + + uc_op_work->msg = msg; + qdf_sched_work(0, &uc_op_work->work); + return; + +end: + qdf_mem_free(op_msg); +} + +QDF_STATUS wlan_ipa_uc_ol_init(struct wlan_ipa_priv *ipa_ctx, + qdf_device_t osdev) +{ + uint8_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) + return QDF_STATUS_SUCCESS; + + ipa_debug("enter"); + + for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) { + ipa_ctx->vdev_to_iface[i] = WLAN_IPA_MAX_SESSION; + ipa_ctx->vdev_offload_enabled[i] = false; + } + + if (cdp_ipa_get_resource(ipa_ctx->dp_soc, ipa_ctx->dp_pdev)) { + ipa_err("IPA UC resource alloc fail"); + status = QDF_STATUS_E_FAILURE; + goto fail_return; + } + + if (true == ipa_ctx->uc_loaded) { + status = wlan_ipa_wdi_setup(ipa_ctx, osdev); + if (status) { + ipa_err("Failure to setup IPA pipes (status=%d)", + status); + status = QDF_STATUS_E_FAILURE; + goto fail_return; + } + + cdp_ipa_set_doorbell_paddr(ipa_ctx->dp_soc, ipa_ctx->dp_pdev); + wlan_ipa_init_metering(ipa_ctx); + + if (wlan_ipa_init_perf_level(ipa_ctx) != QDF_STATUS_SUCCESS) + ipa_err("Failed to init perf level"); + } + + cdp_ipa_register_op_cb(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + wlan_ipa_uc_op_event_handler, (void *)ipa_ctx); + + for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) { + qdf_create_work(0, &ipa_ctx->uc_op_work[i].work, + wlan_ipa_uc_fw_op_event_handler, + &ipa_ctx->uc_op_work[i]); + ipa_ctx->uc_op_work[i].msg = NULL; + } + +fail_return: + ipa_debug("exit: status=%d", status); + return status; +} + +/** + * wlan_ipa_cleanup_pending_event() - Cleanup IPA pending event list + * @ipa_ctx: pointer to IPA IPA struct + * + * Return: none + */ +static void wlan_ipa_cleanup_pending_event(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_uc_pending_event *pending_event = NULL; + + while (qdf_list_remove_front(&ipa_ctx->pending_event, + (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) + qdf_mem_free(pending_event); +} + +QDF_STATUS wlan_ipa_uc_ol_deinit(struct wlan_ipa_priv *ipa_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i; + + ipa_debug("enter"); + + if (!wlan_ipa_uc_is_enabled(ipa_ctx->config)) + return status; + + if (!ipa_ctx->ipa_pipes_down) + wlan_ipa_uc_disable_pipes(ipa_ctx); + + if (true == ipa_ctx->uc_loaded) { + status = cdp_ipa_cleanup(ipa_ctx->dp_soc, + ipa_ctx->tx_pipe_handle, + ipa_ctx->rx_pipe_handle); + if (status) + ipa_err("Failure to cleanup IPA pipes (status=%d)", + status); + } + + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + wlan_ipa_cleanup_pending_event(ipa_ctx); + qdf_mutex_release(&ipa_ctx->ipa_lock); + + for (i = 0; i < WLAN_IPA_UC_OPCODE_MAX; i++) { + qdf_cancel_work(&ipa_ctx->uc_op_work[i].work); + qdf_mem_free(ipa_ctx->uc_op_work[i].msg); + ipa_ctx->uc_op_work[i].msg = NULL; + } + + ipa_debug("exit: ret=%d", status); + return status; +} + +bool wlan_ipa_is_fw_wdi_activated(struct wlan_ipa_priv *ipa_ctx) +{ + return (WLAN_IPA_UC_NUM_WDI_PIPE == ipa_ctx->activated_fw_pipe); +} + +/** + * wlan_ipa_uc_send_evt() - send event to ipa + * @net_dev: Interface net device + * @type: event type + * @mac_addr: pointer to mac address + * + * Send event to IPA driver + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_ipa_uc_send_evt(qdf_netdev_t net_dev, + qdf_ipa_wlan_event type, + uint8_t *mac_addr) +{ + struct wlan_ipa_priv *ipa_ctx = gp_ipa; + qdf_ipa_msg_meta_t meta; + qdf_ipa_wlan_msg_t *msg; + + QDF_IPA_MSG_META_MSG_LEN(&meta) = sizeof(qdf_ipa_wlan_msg_t); + msg = qdf_mem_malloc(QDF_IPA_MSG_META_MSG_LEN(&meta)); + if (!msg) { + ipa_err("msg allocation failed"); + return QDF_STATUS_E_NOMEM; + } + + QDF_IPA_SET_META_MSG_TYPE(&meta, type); + qdf_str_lcopy(QDF_IPA_WLAN_MSG_NAME(msg), net_dev->name, + IPA_RESOURCE_NAME_MAX); + qdf_mem_copy(QDF_IPA_WLAN_MSG_MAC_ADDR(msg), mac_addr, QDF_NET_ETH_LEN); + + if (qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn)) { + ipa_err("%s: Evt: %d fail", + QDF_IPA_WLAN_MSG_NAME(msg), + QDF_IPA_MSG_META_MSG_TYPE(&meta)); + qdf_mem_free(msg); + + return QDF_STATUS_E_FAILURE; + } + + ipa_ctx->stats.num_send_msg++; + + return QDF_STATUS_SUCCESS; +} + +void wlan_ipa_uc_cleanup_sta(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_iface_context *iface_ctx; + int i; + + ipa_debug("enter"); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + if (iface_ctx && iface_ctx->device_mode == QDF_STA_MODE && + iface_ctx->dev == net_dev && iface_ctx->tl_context) { + wlan_ipa_uc_send_evt(net_dev, QDF_IPA_STA_DISCONNECT, + net_dev->dev_addr); + wlan_ipa_cleanup_iface(iface_ctx); + } + } + + ipa_debug("exit"); +} + +QDF_STATUS wlan_ipa_uc_disconnect_ap(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_iface_context *iface_ctx; + QDF_STATUS status; + + ipa_debug("enter"); + + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_SAP_MODE); + if (iface_ctx) + status = wlan_ipa_uc_send_evt(net_dev, QDF_IPA_AP_DISCONNECT, + net_dev->dev_addr); + else + return QDF_STATUS_E_INVAL; + + ipa_debug("exit :%d", status); + + return status; +} + +void wlan_ipa_cleanup_dev_iface(struct wlan_ipa_priv *ipa_ctx, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_iface_context *iface_ctx; + int i; + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_ctx = &ipa_ctx->iface_context[i]; + if (iface_ctx->dev == net_dev) + break; + } + + if (iface_ctx) + wlan_ipa_cleanup_iface(iface_ctx); +} + +void wlan_ipa_uc_ssr_cleanup(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_iface_context *iface; + int i; + + ipa_info("enter"); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface = &ipa_ctx->iface_context[i]; + if (iface->dev) { + if (iface->device_mode == QDF_SAP_MODE) + wlan_ipa_uc_send_evt(iface->dev, + QDF_IPA_AP_DISCONNECT, + iface->dev->dev_addr); + else if (iface->device_mode == QDF_STA_MODE) + wlan_ipa_uc_send_evt(iface->dev, + QDF_IPA_STA_DISCONNECT, + iface->dev->dev_addr); + wlan_ipa_cleanup_iface(iface); + } + } +} + +void wlan_ipa_fw_rejuvenate_send_msg(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_ipa_msg_meta_t meta; + qdf_ipa_wlan_msg_t *msg; + int ret; + + meta.msg_len = sizeof(*msg); + msg = qdf_mem_malloc(meta.msg_len); + if (!msg) { + ipa_debug("msg allocation failed"); + return; + } + + QDF_IPA_SET_META_MSG_TYPE(&meta, QDF_FWR_SSR_BEFORE_SHUTDOWN); + ipa_debug("ipa_send_msg(Evt:%d)", + meta.msg_type); + ret = qdf_ipa_send_msg(&meta, msg, wlan_ipa_msg_free_fn); + + if (ret) { + ipa_err("ipa_send_msg(Evt:%d)-fail=%d", + meta.msg_type, ret); + qdf_mem_free(msg); + } + ipa_ctx->stats.num_send_msg++; +} diff --git a/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_main.c b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_main.c new file mode 100644 index 0000000000000000000000000000000000000000..505ac01d9b4d3c0dce76e8d45e3caeb0504aed30 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_main.c @@ -0,0 +1,619 @@ +/* + * 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. + */ + +/** + * DOC: contains ipa component main function definitions + */ + +#include "wlan_ipa_main.h" +#include "wlan_ipa_core.h" +#include "wlan_ipa_tgt_api.h" + +static struct wlan_ipa_config *g_ipa_config; +static bool g_ipa_hw_support; + +bool ipa_check_hw_present(void) +{ + /* Check if ipa hw is enabled */ + if (qdf_ipa_uc_reg_rdyCB(NULL) != -EPERM) { + g_ipa_hw_support = true; + return true; + } else { + return false; + } +} + +QDF_STATUS ipa_config_mem_alloc(void) +{ + struct wlan_ipa_config *ipa_cfg; + + ipa_cfg = qdf_mem_malloc(sizeof(*ipa_cfg)); + if (!ipa_cfg) { + ipa_err("Failed to allocate memory for ipa config"); + return QDF_STATUS_E_NOMEM; + } + + g_ipa_config = ipa_cfg; + + return QDF_STATUS_SUCCESS; +} + +void ipa_config_mem_free(void) +{ + if (!g_ipa_config) { + ipa_err("IPA config already freed"); + return; + } + + qdf_mem_free(g_ipa_config); + g_ipa_config = NULL; +} + +bool ipa_is_hw_support(void) +{ + return g_ipa_hw_support; +} + +void ipa_config_update(struct wlan_ipa_config *config) +{ + if (!g_ipa_config) { + ipa_err("IPA config already freed"); + return; + } + + qdf_mem_copy(g_ipa_config, config, sizeof(*g_ipa_config)); +} + +bool ipa_config_is_enabled(void) +{ + return g_ipa_config ? wlan_ipa_is_enabled(g_ipa_config) : 0; +} + +bool ipa_config_is_uc_enabled(void) +{ + return g_ipa_config ? wlan_ipa_uc_is_enabled(g_ipa_config) : 0; +} + +QDF_STATUS ipa_obj_setup(struct wlan_ipa_priv *ipa_ctx) +{ + return wlan_ipa_setup(ipa_ctx, g_ipa_config); +} + +QDF_STATUS ipa_obj_cleanup(struct wlan_ipa_priv *ipa_ctx) +{ + return wlan_ipa_cleanup(ipa_ctx); +} + +QDF_STATUS ipa_send_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev, + struct ipa_uc_offload_control_params *req) +{ + return tgt_ipa_uc_offload_enable_disable(pdev, req); +} + +void ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, void *dp_soc) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_IPA_ID); + + if (!pdev) { + ipa_err("Failed to get pdev handle"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); + return; + } + + ipa_obj->dp_soc = dp_soc; + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); +} + +void ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, void *txrx_handle) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_IPA_ID); + + if (!pdev) { + ipa_err("Failed to get pdev handle"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); + return; + } + + ipa_obj->dp_pdev = txrx_handle; + wlan_objmgr_pdev_release_ref(pdev, WLAN_IPA_ID); +} + +QDF_STATUS ipa_rm_set_perf_level(struct wlan_objmgr_pdev *pdev, + uint64_t tx_packets, uint64_t rx_packets) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_set_perf_level(ipa_obj, tx_packets, rx_packets); +} + +void ipa_uc_info(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_info(ipa_obj); +} + +void ipa_uc_stat(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_stat(ipa_obj); +} + +void ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_rt_debug_host_dump(ipa_obj); +} + +void ipa_dump_info(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_dump_info(ipa_obj); +} + +void ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, uint8_t reason) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_stat_request(ipa_obj, reason); +} + +void ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_stat_query(ipa_obj, ipa_tx_diff, ipa_rx_diff); +} + +void ipa_reg_sap_xmit_cb(struct wlan_objmgr_pdev *pdev, wlan_ipa_softap_xmit cb) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_reg_sap_xmit_cb(ipa_obj, cb); +} + +void ipa_reg_send_to_nw_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_send_to_nw cb) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_reg_send_to_nw_cb(ipa_obj, cb); +} + +void ipa_set_mcc_mode(struct wlan_objmgr_pdev *pdev, bool mcc_mode) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_set_mcc_mode(ipa_obj, mcc_mode); +} + +void ipa_set_dfs_cac_tx(struct wlan_objmgr_pdev *pdev, bool tx_block) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_set_dfs_cac_tx(ipa_obj, tx_block); +} + +void ipa_set_ap_ibss_fwd(struct wlan_objmgr_pdev *pdev, bool intra_bss) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_set_ap_ibss_fwd(ipa_obj, intra_bss); +} + +void ipa_uc_force_pipe_shutdown(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + wlan_ipa_uc_disable_pipes(ipa_obj); +} + +void ipa_flush(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_flush(ipa_obj); +} + +QDF_STATUS ipa_suspend(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_suspend(ipa_obj); +} + +QDF_STATUS ipa_resume(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_resume(ipa_obj); +} + +QDF_STATUS ipa_uc_ol_init(struct wlan_objmgr_pdev *pdev, + qdf_device_t osdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_uc_ol_init(ipa_obj, osdev); +} + +QDF_STATUS ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_uc_ol_deinit(ipa_obj); +} + +QDF_STATUS ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("ipa is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_send_mcc_scc_msg(ipa_obj, mcc_mode); +} + +QDF_STATUS ipa_wlan_evt(struct wlan_objmgr_pdev *pdev, qdf_netdev_t net_dev, + uint8_t device_mode, uint8_t sta_id, uint8_t session_id, + enum wlan_ipa_wlan_event ipa_event_type, + uint8_t *mac_addr) +{ + struct wlan_ipa_priv *ipa_obj; + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_wlan_evt(net_dev, device_mode, sta_id, session_id, + ipa_event_type, mac_addr); +} + +int ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + return wlan_ipa_uc_smmu_map(map, num_buf, buf_arr); +} + +bool ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug_rl("ipa is disabled"); + return false; + } + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err_rl("IPA object is NULL"); + return false; + } + + return wlan_ipa_is_fw_wdi_activated(ipa_obj); +} + +void ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_priv *ipa_obj; + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_cleanup_sta(ipa_obj, net_dev); +} + +QDF_STATUS ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_priv *ipa_obj; + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wlan_ipa_uc_disconnect_ap(ipa_obj, net_dev); +} + +void ipa_cleanup_dev_iface(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + struct wlan_ipa_priv *ipa_obj; + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_cleanup_dev_iface(ipa_obj, net_dev); +} + +void ipa_uc_ssr_cleanup(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_uc_ssr_cleanup(ipa_obj); +} + +void ipa_fw_rejuvenate_send_msg(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_ipa_priv *ipa_obj; + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + if (!ipa_obj) { + ipa_err("IPA object is NULL"); + return; + } + + return wlan_ipa_fw_rejuvenate_send_msg(ipa_obj); +} diff --git a/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_rm.c b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_rm.c new file mode 100644 index 0000000000000000000000000000000000000000..1a87e475c07af113d47e221a983a7301fcf5efd8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_rm.c @@ -0,0 +1,499 @@ +/* + * 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. + */ + +/* Include Files */ +#include "wlan_ipa_core.h" +#include "wlan_ipa_main.h" +#include "cdp_txrx_ipa.h" +#include "host_diag_core_event.h" + +QDF_STATUS wlan_ipa_set_perf_level(struct wlan_ipa_priv *ipa_ctx, + uint64_t tx_packets, + uint64_t rx_packets) +{ + int ret; + uint32_t next_bw; + uint64_t total_packets = tx_packets + rx_packets; + + if ((!wlan_ipa_is_enabled(ipa_ctx->config)) || + (!wlan_ipa_is_clk_scaling_enabled(ipa_ctx->config))) + return 0; + + if (total_packets > (ipa_ctx->config->bus_bw_high / 2)) + next_bw = ipa_ctx->config->ipa_bw_high; + else if (total_packets > (ipa_ctx->config->bus_bw_medium / 2)) + next_bw = ipa_ctx->config->ipa_bw_medium; + else + next_bw = ipa_ctx->config->ipa_bw_low; + + if (ipa_ctx->curr_cons_bw != next_bw) { + ipa_debug("Requesting IPA perf curr: %d, next: %d", + ipa_ctx->curr_cons_bw, next_bw); + ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc, + QDF_IPA_CLIENT_WLAN1_CONS, + next_bw); + if (ret) { + ipa_err("RM CONS set perf profile failed: %d", ret); + + return QDF_STATUS_E_FAILURE; + } + ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc, + QDF_IPA_CLIENT_WLAN1_PROD, + next_bw); + if (ret) { + ipa_err("RM PROD set perf profile failed: %d", ret); + return QDF_STATUS_E_FAILURE; + } + ipa_ctx->curr_cons_bw = next_bw; + ipa_ctx->stats.num_cons_perf_req++; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_ipa_init_perf_level(struct wlan_ipa_priv *ipa_ctx) +{ + int ret; + + /* Set lowest bandwidth to start with */ + if (wlan_ipa_is_clk_scaling_enabled(ipa_ctx->config)) + return wlan_ipa_set_perf_level(ipa_ctx, 0, 0); + + ipa_debug("IPA clk scaling disabled. Set perf level to maximum %d", + WLAN_IPA_MAX_BANDWIDTH); + + ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc, + QDF_IPA_CLIENT_WLAN1_CONS, + WLAN_IPA_MAX_BANDWIDTH); + if (ret) { + ipa_err("CONS set perf profile failed: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = cdp_ipa_set_perf_level(ipa_ctx->dp_soc, + QDF_IPA_CLIENT_WLAN1_PROD, + WLAN_IPA_MAX_BANDWIDTH); + if (ret) { + ipa_err("PROD set perf profile failed: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_METERING +void wlan_ipa_init_metering(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_event_create(&ipa_ctx->ipa_uc_sharing_stats_comp); + qdf_event_create(&ipa_ctx->ipa_uc_set_quota_comp); +} +#endif + +#ifndef CONFIG_IPA_WDI_UNIFIED_API +/** + * wlan_ipa_rm_cons_release() - WLAN consumer resource release handler + * + * Callback function registered with IPA that is called when IPA wants + * to release the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int wlan_ipa_rm_cons_release(void) +{ + return 0; +} + +/** + * wlan_ipa_wdi_rm_request() - Request resource from IPA + * @ipa_ctx: IPA context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ipa_wdi_rm_request(struct wlan_ipa_priv *ipa_ctx) +{ + int ret; + + if (!wlan_ipa_is_rm_enabled(ipa_ctx->config)) + return QDF_STATUS_SUCCESS; + + qdf_spin_lock_bh(&ipa_ctx->rm_lock); + + switch (ipa_ctx->rm_state) { + case WLAN_IPA_RM_GRANTED: + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + return QDF_STATUS_SUCCESS; + case WLAN_IPA_RM_GRANT_PENDING: + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + return QDF_STATUS_E_PENDING; + case WLAN_IPA_RM_RELEASED: + ipa_ctx->rm_state = WLAN_IPA_RM_GRANT_PENDING; + break; + } + + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + + ret = qdf_ipa_rm_inactivity_timer_request_resource( + QDF_IPA_RM_RESOURCE_WLAN_PROD); + + qdf_spin_lock_bh(&ipa_ctx->rm_lock); + if (ret == 0) { + ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED; + ipa_ctx->stats.num_rm_grant_imm++; + } + + if (ipa_ctx->wake_lock_released) { + qdf_wake_lock_acquire(&ipa_ctx->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + ipa_ctx->wake_lock_released = false; + } + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + + qdf_cancel_delayed_work(&ipa_ctx->wake_lock_work); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_ipa_wdi_rm_try_release(struct wlan_ipa_priv *ipa_ctx) +{ + int ret; + + if (!wlan_ipa_is_rm_enabled(ipa_ctx->config)) + return QDF_STATUS_SUCCESS; + + if (qdf_atomic_read(&ipa_ctx->tx_ref_cnt)) + return QDF_STATUS_E_AGAIN; + + qdf_spin_lock_bh(&ipa_ctx->pm_lock); + + if (!qdf_nbuf_is_queue_empty(&ipa_ctx->pm_queue_head)) { + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + return QDF_STATUS_E_AGAIN; + } + qdf_spin_unlock_bh(&ipa_ctx->pm_lock); + + qdf_spin_lock_bh(&ipa_ctx->rm_lock); + switch (ipa_ctx->rm_state) { + case WLAN_IPA_RM_GRANTED: + break; + case WLAN_IPA_RM_GRANT_PENDING: + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + return QDF_STATUS_E_PENDING; + case WLAN_IPA_RM_RELEASED: + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + return QDF_STATUS_SUCCESS; + } + + /* IPA driver returns immediately so set the state here to avoid any + * race condition. + */ + ipa_ctx->rm_state = WLAN_IPA_RM_RELEASED; + ipa_ctx->stats.num_rm_release++; + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + + ret = qdf_ipa_rm_inactivity_timer_release_resource( + QDF_IPA_RM_RESOURCE_WLAN_PROD); + + if (qdf_unlikely(ret != 0)) { + qdf_spin_lock_bh(&ipa_ctx->rm_lock); + ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED; + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + QDF_ASSERT(0); + ipa_warn("rm_inactivity_timer_release_resource ret fail"); + } + + /* + * If wake_lock is released immediately, kernel would try to suspend + * immediately as well, Just avoid ping-pong between suspend-resume + * while there is healthy amount of data transfer going on by + * releasing the wake_lock after some delay. + */ + qdf_sched_delayed_work(&ipa_ctx->wake_lock_work, + msecs_to_jiffies + (WLAN_IPA_RX_INACTIVITY_MSEC_DELAY)); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_ipa_uc_rm_notify_handler() - IPA uC resource notification handler + * @ipa_ctx: IPA context + * @event: IPA RM event + * + * Return: None + */ +static void +wlan_ipa_uc_rm_notify_handler(struct wlan_ipa_priv *ipa_ctx, + qdf_ipa_rm_event_t event) +{ + if (!wlan_ipa_is_rm_enabled(ipa_ctx->config)) + return; + + ipa_debug("event code %d", event); + + switch (event) { + case QDF_IPA_RM_RESOURCE_GRANTED: + /* Differed RM Granted */ + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if ((!ipa_ctx->resource_unloading) && + (!ipa_ctx->activated_fw_pipe)) { + wlan_ipa_uc_enable_pipes(ipa_ctx); + ipa_ctx->resource_loading = false; + } + qdf_mutex_release(&ipa_ctx->ipa_lock); + break; + + case QDF_IPA_RM_RESOURCE_RELEASED: + /* Differed RM Released */ + ipa_ctx->resource_unloading = false; + break; + + default: + ipa_err("invalid event code %d", event); + break; + } +} + +/** + * wlan_ipa_uc_rm_notify_defer() - Defer IPA uC notification + * * @data: IPA context + * + * This function is called when a resource manager event is received + * from firmware in interrupt context. This function will defer the + * handling to the OL RX thread + * + * Return: None + */ +static void wlan_ipa_uc_rm_notify_defer(void *data) +{ + struct wlan_ipa_priv *ipa_ctx = data; + qdf_ipa_rm_event_t event; + struct uc_rm_work_struct *uc_rm_work = &ipa_ctx->uc_rm_work; + + event = uc_rm_work->event; + + wlan_ipa_uc_rm_notify_handler(ipa_ctx, event); +} + +/** + * wlan_ipa_wake_lock_timer_func() - Wake lock work handler + * @data: IPA context + * + * When IPA resources are released in wlan_ipa_wdi_rm_try_release() we do + * not want to immediately release the wake lock since the system + * would then potentially try to suspend when there is a healthy data + * rate. Deferred work is scheduled and this function handles the + * work. When this function is called, if the IPA resource is still + * released then we release the wake lock. + * + * Return: None + */ +static void wlan_ipa_wake_lock_timer_func(void *data) +{ + struct wlan_ipa_priv *ipa_ctx = data; + + qdf_spin_lock_bh(&ipa_ctx->rm_lock); + + if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED) + goto end; + + ipa_ctx->wake_lock_released = true; + qdf_wake_lock_release(&ipa_ctx->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + +end: + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); +} + +/** + * wlan_ipa_rm_cons_request() - WLAN consumer resource request handler + * + * Callback function registered with IPA that is called when IPA wants + * to access the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int wlan_ipa_rm_cons_request(void) +{ + struct wlan_ipa_priv *ipa_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ipa_ctx = wlan_ipa_get_obj_context(); + + if (ipa_ctx->resource_loading) { + ipa_err("IPA resource loading in progress"); + ipa_ctx->pending_cons_req = true; + status = QDF_STATUS_E_PENDING; + } else if (ipa_ctx->resource_unloading) { + ipa_err("IPA resource unloading in progress"); + ipa_ctx->pending_cons_req = true; + status = QDF_STATUS_E_PERM; + } + + return qdf_status_to_os_return(status); +} + +/** + * wlan_ipa_rm_notify() - IPA resource manager notifier callback + * @user_data: user data registered with IPA + * @event: the IPA resource manager event that occurred + * @data: the data associated with the event + * + * Return: None + */ +static void wlan_ipa_rm_notify(void *user_data, qdf_ipa_rm_event_t event, + unsigned long data) +{ + struct wlan_ipa_priv *ipa_ctx = user_data; + + if (qdf_unlikely(!ipa_ctx)) + return; + + if (!wlan_ipa_is_rm_enabled(ipa_ctx->config)) + return; + + ipa_debug("Evt: %d", event); + + switch (event) { + case QDF_IPA_RM_RESOURCE_GRANTED: + if (wlan_ipa_uc_is_enabled(ipa_ctx->config)) { + /* RM Notification comes with ISR context + * it should be serialized into work queue to avoid + * ISR sleep problem + */ + ipa_ctx->uc_rm_work.event = event; + qdf_sched_work(0, &ipa_ctx->uc_rm_work.work); + break; + } + qdf_spin_lock_bh(&ipa_ctx->rm_lock); + ipa_ctx->rm_state = WLAN_IPA_RM_GRANTED; + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + ipa_ctx->stats.num_rm_grant++; + break; + + case QDF_IPA_RM_RESOURCE_RELEASED: + ipa_debug("RM Release"); + ipa_ctx->resource_unloading = false; + break; + + default: + ipa_err("Unknown RM Evt: %d", event); + break; + } +} + +QDF_STATUS wlan_ipa_wdi_setup_rm(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_ipa_rm_create_params_t create_params; + int ret; + + if (!wlan_ipa_is_rm_enabled(ipa_ctx->config)) + return 0; + + qdf_create_work(0, &ipa_ctx->uc_rm_work.work, + wlan_ipa_uc_rm_notify_defer, ipa_ctx); + qdf_mem_zero(&create_params, sizeof(create_params)); + create_params.name = QDF_IPA_RM_RESOURCE_WLAN_PROD; + create_params.reg_params.user_data = ipa_ctx; + create_params.reg_params.notify_cb = wlan_ipa_rm_notify; + create_params.floor_voltage = QDF_IPA_VOLTAGE_LEVEL; + + ret = qdf_ipa_rm_create_resource(&create_params); + if (ret) { + ipa_err("Create RM resource failed: %d", ret); + goto setup_rm_fail; + } + + qdf_mem_zero(&create_params, sizeof(create_params)); + create_params.name = QDF_IPA_RM_RESOURCE_WLAN_CONS; + create_params.request_resource = wlan_ipa_rm_cons_request; + create_params.release_resource = wlan_ipa_rm_cons_release; + create_params.floor_voltage = QDF_IPA_VOLTAGE_LEVEL; + + ret = qdf_ipa_rm_create_resource(&create_params); + if (ret) { + ipa_err("Create RM CONS resource failed: %d", ret); + goto delete_prod; + } + + qdf_ipa_rm_add_dependency(QDF_IPA_RM_RESOURCE_WLAN_PROD, + QDF_IPA_RM_RESOURCE_APPS_CONS); + + ret = qdf_ipa_rm_inactivity_timer_init(QDF_IPA_RM_RESOURCE_WLAN_PROD, + WLAN_IPA_RX_INACTIVITY_MSEC_DELAY); + if (ret) { + ipa_err("Timer init failed: %d", ret); + goto timer_init_failed; + } + + qdf_wake_lock_create(&ipa_ctx->wake_lock, "wlan_ipa"); + qdf_create_delayed_work(&ipa_ctx->wake_lock_work, + wlan_ipa_wake_lock_timer_func, ipa_ctx); + qdf_spinlock_create(&ipa_ctx->rm_lock); + ipa_ctx->rm_state = WLAN_IPA_RM_RELEASED; + ipa_ctx->wake_lock_released = true; + qdf_atomic_set(&ipa_ctx->tx_ref_cnt, 0); + + return QDF_STATUS_SUCCESS; + +timer_init_failed: + qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_APPS_CONS); + +delete_prod: + qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_PROD); + +setup_rm_fail: + return QDF_STATUS_E_FAILURE; +} + +void wlan_ipa_wdi_destroy_rm(struct wlan_ipa_priv *ipa_ctx) +{ + int ret; + + if (!wlan_ipa_is_rm_enabled(ipa_ctx->config)) + return; + + qdf_cancel_delayed_work(&ipa_ctx->wake_lock_work); + qdf_wake_lock_destroy(&ipa_ctx->wake_lock); + qdf_cancel_work(&ipa_ctx->uc_rm_work.work); + qdf_spinlock_destroy(&ipa_ctx->rm_lock); + + qdf_ipa_rm_inactivity_timer_destroy(QDF_IPA_RM_RESOURCE_WLAN_PROD); + + ret = qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_CONS); + if (ret) + ipa_err("RM CONS resource delete failed %d", ret); + + ret = qdf_ipa_rm_delete_resource(QDF_IPA_RM_RESOURCE_WLAN_PROD); + if (ret) + ipa_err("RM PROD resource delete failed %d", ret); +} + +bool wlan_ipa_is_rm_released(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_spin_lock_bh(&ipa_ctx->rm_lock); + + if (ipa_ctx->rm_state != WLAN_IPA_RM_RELEASED) { + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + return false; + } + + qdf_spin_unlock_bh(&ipa_ctx->rm_lock); + + return true; +} +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_stats.c b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..468def3d4468a2f96a6a180742d8434cf79c152a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/core/src/wlan_ipa_stats.c @@ -0,0 +1,965 @@ +/* + * 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. + */ + +/* Include Files */ +#include "wlan_ipa_main.h" +#include "wlan_ipa_core.h" +#include "cdp_txrx_ipa.h" +#include "qdf_platform.h" + +/** + * wlan_ipa_uc_rt_debug_host_fill - fill rt debug buffer + * @ctext: pointer to ipa context. + * + * If rt debug enabled, periodically called, and fill debug buffer + * + * Return: none + */ +static void wlan_ipa_uc_rt_debug_host_fill(void *ctext) +{ + struct wlan_ipa_priv *ipa_ctx = ctext; + struct uc_rt_debug_info *dump_info = NULL; + + if (!ipa_ctx) + return; + + qdf_mutex_acquire(&ipa_ctx->rt_debug_lock); + dump_info = &ipa_ctx->rt_bug_buffer[ + ipa_ctx->rt_buf_fill_index % WLAN_IPA_UC_RT_DEBUG_BUF_COUNT]; + + dump_info->time = (uint64_t)qdf_mc_timer_get_system_time(); + dump_info->ipa_excep_count = ipa_ctx->stats.num_rx_excep; + dump_info->rx_drop_count = ipa_ctx->ipa_rx_internal_drop_count; + dump_info->net_sent_count = ipa_ctx->ipa_rx_net_send_count; + dump_info->tx_fwd_count = ipa_ctx->ipa_tx_forward; + dump_info->tx_fwd_ok_count = ipa_ctx->stats.num_tx_fwd_ok; + dump_info->rx_discard_count = ipa_ctx->ipa_rx_discard; + dump_info->rx_destructor_call = ipa_ctx->ipa_rx_destructor_count; + ipa_ctx->rt_buf_fill_index++; + qdf_mutex_release(&ipa_ctx->rt_debug_lock); + + qdf_mc_timer_start(&ipa_ctx->rt_debug_fill_timer, + WLAN_IPA_UC_RT_DEBUG_FILL_INTERVAL); +} + +void wlan_ipa_uc_rt_debug_host_dump(struct wlan_ipa_priv *ipa_ctx) +{ + unsigned int dump_count; + unsigned int dump_index; + struct uc_rt_debug_info *dump_info = NULL; + + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + ipa_info("========= WLAN-IPA DEBUG BUF DUMP ==========\n"); + ipa_info(" TM : EXEP : DROP : NETS : FWOK" + ": TXFD : DSTR : DSCD\n"); + + qdf_mutex_acquire(&ipa_ctx->rt_debug_lock); + for (dump_count = 0; + dump_count < WLAN_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_count++) { + dump_index = (ipa_ctx->rt_buf_fill_index + dump_count) % + WLAN_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_info = &ipa_ctx->rt_bug_buffer[dump_index]; + ipa_info("%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n", + dump_info->time, dump_info->ipa_excep_count, + dump_info->rx_drop_count, dump_info->net_sent_count, + dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count, + dump_info->rx_destructor_call, + dump_info->rx_discard_count); + } + qdf_mutex_release(&ipa_ctx->rt_debug_lock); +} + +/** + * wlan_ipa_uc_rt_debug_handler - periodic memory health monitor handler + * @ctext: pointer to ipa context. + * + * periodically called by timer expire + * will try to alloc dummy memory and detect out of memory condition + * if out of memory detected, dump wlan-ipa stats + * + * Return: none + */ +static void wlan_ipa_uc_rt_debug_handler(void *ctext) +{ + struct wlan_ipa_priv *ipa_ctx = ctext; + void *dummy_ptr = NULL; + + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + /* Allocate dummy buffer periodically and free immediately. this will + * proactively detect OOM and if allocation fails dump ipa stats + */ + dummy_ptr = qdf_mem_malloc(WLAN_IPA_UC_DEBUG_DUMMY_MEM_SIZE); + if (!dummy_ptr) { + wlan_ipa_uc_rt_debug_host_dump(ipa_ctx); + wlan_ipa_uc_stat_request(ipa_ctx, + WLAN_IPA_UC_STAT_REASON_DEBUG); + } else { + qdf_mem_free(dummy_ptr); + } + + qdf_mc_timer_start(&ipa_ctx->rt_debug_timer, + WLAN_IPA_UC_RT_DEBUG_PERIOD); +} + +void wlan_ipa_uc_rt_debug_destructor(qdf_nbuf_t nbuff) +{ + struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context(); + + if (!ipa_ctx) { + ipa_err("invalid ipa context"); + return; + } + + ipa_ctx->ipa_rx_destructor_count++; +} + +void wlan_ipa_uc_rt_debug_deinit(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_mutex_destroy(&ipa_ctx->rt_debug_lock); + + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&ipa_ctx->rt_debug_fill_timer)) { + qdf_mc_timer_stop(&ipa_ctx->rt_debug_fill_timer); + } + qdf_mc_timer_destroy(&ipa_ctx->rt_debug_fill_timer); + + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&ipa_ctx->rt_debug_timer)) { + qdf_mc_timer_stop(&ipa_ctx->rt_debug_timer); + } + qdf_mc_timer_destroy(&ipa_ctx->rt_debug_timer); +} + +void wlan_ipa_uc_rt_debug_init(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_mutex_create(&ipa_ctx->rt_debug_lock); + ipa_ctx->rt_buf_fill_index = 0; + qdf_mem_zero(ipa_ctx->rt_bug_buffer, + sizeof(struct uc_rt_debug_info) * + WLAN_IPA_UC_RT_DEBUG_BUF_COUNT); + ipa_ctx->ipa_tx_forward = 0; + ipa_ctx->ipa_rx_discard = 0; + ipa_ctx->ipa_rx_net_send_count = 0; + ipa_ctx->ipa_rx_internal_drop_count = 0; + ipa_ctx->ipa_rx_destructor_count = 0; + + /* Reatime debug enable on feature enable */ + if (!wlan_ipa_is_rt_debugging_enabled(ipa_ctx->config)) { + ipa_debug("IPA RT debug is not enabled"); + return; + } + + qdf_mc_timer_init(&ipa_ctx->rt_debug_fill_timer, QDF_TIMER_TYPE_SW, + wlan_ipa_uc_rt_debug_host_fill, (void *)ipa_ctx); + qdf_mc_timer_start(&ipa_ctx->rt_debug_fill_timer, + WLAN_IPA_UC_RT_DEBUG_FILL_INTERVAL); + + qdf_mc_timer_init(&ipa_ctx->rt_debug_timer, QDF_TIMER_TYPE_SW, + wlan_ipa_uc_rt_debug_handler, (void *)ipa_ctx); + qdf_mc_timer_start(&ipa_ctx->rt_debug_timer, + WLAN_IPA_UC_RT_DEBUG_PERIOD); + +} + +/** + * wlan_ipa_dump_ipa_ctx() - dump entries in IPA IPA struct + * @ipa_ctx: IPA context + * + * Dump entries in struct ipa_ctx + * + * Return: none + */ +static void wlan_ipa_dump_ipa_ctx(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + + /* IPA IPA */ + ipa_info("\n==== IPA IPA ====\n" + "num_iface: %d\n" + "rm_state: %d\n" + "rm_lock: %pK\n" + "uc_rm_work: %pK\n" + "uc_op_work: %pK\n" + "wake_lock: %pK\n" + "wake_lock_work: %pK\n" + "wake_lock_released: %d\n" + "tx_ref_cnt: %d\n" + "pm_queue_head----\n" + "\thead: %pK\n" + "\ttail: %pK\n" + "\tqlen: %d\n" + "pm_work: %pK\n" + "pm_lock: %pK\n" + "suspended: %d\n", + ipa_ctx->num_iface, + ipa_ctx->rm_state, + &ipa_ctx->rm_lock, + &ipa_ctx->uc_rm_work, + &ipa_ctx->uc_op_work, + &ipa_ctx->wake_lock, + &ipa_ctx->wake_lock_work, + ipa_ctx->wake_lock_released, + ipa_ctx->tx_ref_cnt.counter, + ipa_ctx->pm_queue_head.head, + ipa_ctx->pm_queue_head.tail, + ipa_ctx->pm_queue_head.qlen, + &ipa_ctx->pm_work, + &ipa_ctx->pm_lock, + ipa_ctx->suspended); + + ipa_info("\nq_lock: %pK\n" + "pend_desc_head----\n" + "\tnext: %pK\n" + "\tprev: %pK\n" + "stats: %pK\n" + "curr_prod_bw: %d\n" + "curr_cons_bw: %d\n" + "activated_fw_pipe: %d\n" + "sap_num_connected_sta: %d\n" + "sta_connected: %d\n", + &ipa_ctx->q_lock, + ipa_ctx->pend_desc_head.next, + ipa_ctx->pend_desc_head.prev, + &ipa_ctx->stats, + ipa_ctx->curr_prod_bw, + ipa_ctx->curr_cons_bw, + ipa_ctx->activated_fw_pipe, + ipa_ctx->sap_num_connected_sta, + (unsigned int)ipa_ctx->sta_connected); + + ipa_info("\ntx_pipe_handle: 0x%x\n" + "rx_pipe_handle: 0x%x\n" + "resource_loading: %d\n" + "resource_unloading: %d\n" + "pending_cons_req: %d\n" + "pending_event----\n" + "\tanchor.next: %pK\n" + "\tanchor.prev: %pK\n" + "\tcount: %d\n" + "\tmax_size: %d\n" + "event_lock: %pK\n" + "ipa_tx_packets_diff: %d\n" + "ipa_rx_packets_diff: %d\n" + "ipa_p_tx_packets: %d\n" + "ipa_p_rx_packets: %d\n" + "stat_req_reason: %d\n", + ipa_ctx->tx_pipe_handle, + ipa_ctx->rx_pipe_handle, + ipa_ctx->resource_loading, + ipa_ctx->resource_unloading, + ipa_ctx->pending_cons_req, + ipa_ctx->pending_event.anchor.next, + ipa_ctx->pending_event.anchor.prev, + ipa_ctx->pending_event.count, + ipa_ctx->pending_event.max_size, + &ipa_ctx->event_lock, + ipa_ctx->ipa_tx_packets_diff, + ipa_ctx->ipa_rx_packets_diff, + ipa_ctx->ipa_p_tx_packets, + ipa_ctx->ipa_p_rx_packets, + ipa_ctx->stat_req_reason); + + ipa_info("\ncons_pipe_in----\n" + "\tsys: %pK\n" + "\tdl.comp_ring_base_pa: 0x%x\n" + "\tdl.comp_ring_size: %d\n" + "\tdl.ce_ring_base_pa: 0x%x\n" + "\tdl.ce_door_bell_pa: 0x%x\n" + "\tdl.ce_ring_size: %d\n" + "\tdl.num_tx_buffers: %d\n" + "prod_pipe_in----\n" + "\tsys: %pK\n" + "\tul.rdy_ring_base_pa: 0x%x\n" + "\tul.rdy_ring_size: %d\n" + "\tul.rdy_ring_rp_pa: 0x%x\n" + "uc_loaded: %d\n" + "wdi_enabled: %d\n" + "rt_debug_fill_timer: %pK\n" + "rt_debug_lock: %pK\n" + "ipa_lock: %pK\n", + &ipa_ctx->cons_pipe_in.sys, + (unsigned int)ipa_ctx->cons_pipe_in.u.dl.comp_ring_base_pa, + ipa_ctx->cons_pipe_in.u.dl.comp_ring_size, + (unsigned int)ipa_ctx->cons_pipe_in.u.dl.ce_ring_base_pa, + (unsigned int)ipa_ctx->cons_pipe_in.u.dl.ce_door_bell_pa, + ipa_ctx->cons_pipe_in.u.dl.ce_ring_size, + ipa_ctx->cons_pipe_in.u.dl.num_tx_buffers, + &ipa_ctx->prod_pipe_in.sys, + (unsigned int)ipa_ctx->prod_pipe_in.u.ul.rdy_ring_base_pa, + ipa_ctx->prod_pipe_in.u.ul.rdy_ring_size, + (unsigned int)ipa_ctx->prod_pipe_in.u.ul.rdy_ring_rp_pa, + ipa_ctx->uc_loaded, + ipa_ctx->wdi_enabled, + &ipa_ctx->rt_debug_fill_timer, + &ipa_ctx->rt_debug_lock, + &ipa_ctx->ipa_lock); + + ipa_info("\nvdev_to_iface----"); + for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) + ipa_info("\n\t[%d]=%d", i, ipa_ctx->vdev_to_iface[i]); + + QDF_TRACE(QDF_MODULE_ID_IPA, QDF_TRACE_LEVEL_INFO, + "\nvdev_offload_enabled----"); + for (i = 0; i < WLAN_IPA_MAX_SESSION; i++) + ipa_info("\n\t[%d]=%d", i, ipa_ctx->vdev_offload_enabled[i]); + + QDF_TRACE(QDF_MODULE_ID_IPA, QDF_TRACE_LEVEL_INFO, + "\nassoc_stas_map ----"); + for (i = 0; i < WLAN_IPA_MAX_STA_COUNT; i++) { + ipa_info("\n\t[%d]: is_reserved=%d, sta_id=%d", i, + ipa_ctx->assoc_stas_map[i].is_reserved, + ipa_ctx->assoc_stas_map[i].sta_id); + } +} + +/** + * wlan_ipa_dump_sys_pipe() - dump IPA IPA SYS Pipe struct + * @ipa_ctx: IPA IPA struct + * + * Dump entire struct wlan_ipa_sys_pipe + * + * Return: none + */ +static void wlan_ipa_dump_sys_pipe(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + + /* IPA SYS Pipes */ + ipa_info("==== IPA SYS Pipes ===="); + + for (i = 0; i < WLAN_IPA_MAX_SYSBAM_PIPE; i++) { + struct wlan_ipa_sys_pipe *sys_pipe; + qdf_ipa_sys_connect_params_t *ipa_sys_params; + + sys_pipe = &ipa_ctx->sys_pipe[i]; + ipa_sys_params = &sys_pipe->ipa_sys_params; + + ipa_info("\nsys_pipe[%d]----\n" + "\tconn_hdl: 0x%x\n" + "\tconn_hdl_valid: %d\n" + "\tnat_en: %d\n" + "\thdr_len %d\n" + "\thdr_additional_const_len: %d\n" + "\thdr_ofst_pkt_size_valid: %d\n" + "\thdr_ofst_pkt_size: %d\n" + "\thdr_little_endian: %d\n" + "\tmode: %d\n" + "\tclient: %d\n" + "\tdesc_fifo_sz: %d\n" + "\tpriv: %pK\n" + "\tnotify: %pK\n" + "\tskip_ep_cfg: %d\n" + "\tkeep_ipa_awake: %d\n", + i, + sys_pipe->conn_hdl, + sys_pipe->conn_hdl_valid, + QDF_IPA_SYS_PARAMS_NAT_EN(ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_LEN(ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_ADDITIONAL_CONST_LEN( + ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE_VALID( + ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_OFST_PKT_SIZE(ipa_sys_params), + QDF_IPA_SYS_PARAMS_HDR_LITTLE_ENDIAN(ipa_sys_params), + QDF_IPA_SYS_PARAMS_MODE(ipa_sys_params), + QDF_IPA_SYS_PARAMS_CLIENT(ipa_sys_params), + QDF_IPA_SYS_PARAMS_DESC_FIFO_SZ(ipa_sys_params), + QDF_IPA_SYS_PARAMS_PRIV(ipa_sys_params), + QDF_IPA_SYS_PARAMS_NOTIFY(ipa_sys_params), + QDF_IPA_SYS_PARAMS_SKIP_EP_CFG(ipa_sys_params), + QDF_IPA_SYS_PARAMS_KEEP_IPA_AWAKE(ipa_sys_params)); + } +} + +/** + * wlan_ipa_dump_iface_context() - dump IPA IPA Interface Context struct + * @ipa_ctx: IPA IPA struct + * + * Dump entire struct wlan_ipa_iface_context + * + * Return: none + */ +static void wlan_ipa_dump_iface_context(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + + /* IPA Interface Contexts */ + ipa_info("\n==== IPA Interface Contexts ====\n"); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + struct wlan_ipa_iface_context *iface_context; + + iface_context = &ipa_ctx->iface_context[i]; + + ipa_info("\niface_context[%d]----\n" + "\tipa_ctx: %pK\n" + "\ttl_context: %pK\n" + "\tcons_client: %d\n" + "\tprod_client: %d\n" + "\tiface_id: %d\n" + "\tsta_id: %d\n" + "\tinterface_lock: %pK\n" + "\tifa_address: 0x%x\n", + i, + iface_context->ipa_ctx, + iface_context->tl_context, + iface_context->cons_client, + iface_context->prod_client, + iface_context->iface_id, + iface_context->sta_id, + &iface_context->interface_lock, + iface_context->ifa_address); + } +} + +void wlan_ipa_dump_info(struct wlan_ipa_priv *ipa_ctx) +{ + wlan_ipa_dump_ipa_ctx(ipa_ctx); + wlan_ipa_dump_sys_pipe(ipa_ctx); + wlan_ipa_dump_iface_context(ipa_ctx); +} + +void wlan_ipa_uc_stat_query(struct wlan_ipa_priv *ipa_ctx, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + *ipa_tx_diff = 0; + *ipa_rx_diff = 0; + + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if ((ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) && + (false == ipa_ctx->resource_loading)) { + *ipa_tx_diff = ipa_ctx->ipa_tx_packets_diff; + *ipa_rx_diff = ipa_ctx->ipa_rx_packets_diff; + } + qdf_mutex_release(&ipa_ctx->ipa_lock); +} + +void wlan_ipa_uc_stat_request(struct wlan_ipa_priv *ipa_ctx, uint8_t reason) +{ + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if ((ipa_ctx->activated_fw_pipe == WLAN_IPA_UC_NUM_WDI_PIPE) && + (false == ipa_ctx->resource_loading)) { + ipa_ctx->stat_req_reason = reason; + cdp_ipa_get_stat(ipa_ctx->dp_soc, ipa_ctx->dp_pdev); + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else { + qdf_mutex_release(&ipa_ctx->ipa_lock); + } +} + +/** + * wlan_ipa_print_session_info - Print IPA session info + * @ipa_ctx: IPA context + * + * Return: None + */ +static void wlan_ipa_print_session_info(struct wlan_ipa_priv *ipa_ctx) +{ + struct wlan_ipa_uc_pending_event *event = NULL, *next = NULL; + struct wlan_ipa_iface_context *iface_context = NULL; + int i; + + ipa_info("\n==== IPA SESSION INFO ====\n" + "NUM IFACE: %d\n" + "RM STATE: %d\n" + "ACTIVATED FW PIPE: %d\n" + "SAP NUM STAs: %d\n" + "STA CONNECTED: %d\n" + "CONCURRENT MODE: %s\n" + "RSC LOADING: %d\n" + "RSC UNLOADING: %d\n" + "PENDING CONS REQ: %d\n" + "IPA PIPES DOWN: %d\n" + "IPA UC LOADED: %d\n" + "IPA WDI ENABLED: %d\n" + "NUM SEND MSG: %d\n" + "NUM FREE MSG: %d\n", + ipa_ctx->num_iface, + ipa_ctx->rm_state, + ipa_ctx->activated_fw_pipe, + ipa_ctx->sap_num_connected_sta, + ipa_ctx->sta_connected, + (ipa_ctx->mcc_mode ? "MCC" : "SCC"), + ipa_ctx->resource_loading, + ipa_ctx->resource_unloading, + ipa_ctx->pending_cons_req, + ipa_ctx->ipa_pipes_down, + ipa_ctx->uc_loaded, + ipa_ctx->wdi_enabled, + (unsigned int)ipa_ctx->stats.num_send_msg, + (unsigned int)ipa_ctx->stats.num_free_msg); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + iface_context = &ipa_ctx->iface_context[i]; + + if (!iface_context->tl_context) + continue; + + ipa_info("\nIFACE[%d]: sta_id:%d, mode:%d, offload:%d", + i, iface_context->sta_id, + iface_context->device_mode, + ipa_ctx->vdev_offload_enabled[iface_context-> + session_id]); + } + + for (i = 0; i < QDF_IPA_WLAN_EVENT_MAX; i++) + ipa_info("\nEVENT[%d]=%d", + i, ipa_ctx->stats.event[i]); + + i = 0; + qdf_list_peek_front(&ipa_ctx->pending_event, + (qdf_list_node_t **)&event); + while (event != NULL) { + ipa_info("PENDING EVENT[%d]: EVT:%s, sta_id:%d, MAC:%pM", + i, wlan_ipa_wlan_event_to_str(event->type), + event->sta_id, event->mac_addr); + + qdf_list_peek_next(&ipa_ctx->pending_event, + (qdf_list_node_t *)event, + (qdf_list_node_t **)&next); + event = next; + next = NULL; + i++; + } +} + +/** + * wlan_ipa_print_txrx_stats - Print IPA IPA TX/RX stats + * @ipa_ctx: IPA context + * + * Return: None + */ +static void wlan_ipa_print_txrx_stats(struct wlan_ipa_priv *ipa_ctx) +{ + int i; + struct wlan_ipa_iface_context *iface_context = NULL; + + ipa_info("\n==== IPA IPA TX/RX STATS ====\n" + "NUM RM GRANT: %llu\n" + "NUM RM RELEASE: %llu\n" + "NUM RM GRANT IMM: %llu\n" + "NUM CONS PERF REQ: %llu\n" + "NUM PROD PERF REQ: %llu\n" + "NUM RX DROP: %llu\n" + "NUM EXCP PKT: %llu\n" + "NUM TX FWD OK: %llu\n" + "NUM TX FWD ERR: %llu\n" + "NUM TX DESC Q CNT: %llu\n" + "NUM TX DESC ERROR: %llu\n" + "NUM TX COMP CNT: %llu\n" + "NUM TX QUEUED: %llu\n" + "NUM TX DEQUEUED: %llu\n" + "NUM MAX PM QUEUE: %llu\n" + "TX REF CNT: %d\n" + "SUSPENDED: %d\n" + "PEND DESC HEAD: %pK\n" + "TX DESC LIST: %pK\n", + ipa_ctx->stats.num_rm_grant, + ipa_ctx->stats.num_rm_release, + ipa_ctx->stats.num_rm_grant_imm, + ipa_ctx->stats.num_cons_perf_req, + ipa_ctx->stats.num_prod_perf_req, + ipa_ctx->stats.num_rx_drop, + ipa_ctx->stats.num_rx_excep, + ipa_ctx->stats.num_tx_fwd_ok, + ipa_ctx->stats.num_tx_fwd_err, + ipa_ctx->stats.num_tx_desc_q_cnt, + ipa_ctx->stats.num_tx_desc_error, + ipa_ctx->stats.num_tx_comp_cnt, + ipa_ctx->stats.num_tx_queued, + ipa_ctx->stats.num_tx_dequeued, + ipa_ctx->stats.num_max_pm_queue, + ipa_ctx->tx_ref_cnt.counter, + ipa_ctx->suspended, + &ipa_ctx->pend_desc_head, + &ipa_ctx->tx_desc_list); + + for (i = 0; i < WLAN_IPA_MAX_IFACE; i++) { + + iface_context = &ipa_ctx->iface_context[i]; + if (!iface_context->tl_context) + continue; + + ipa_info("IFACE[%d]: TX:%llu, TX DROP:%llu, TX ERR:%llu," + " TX CAC DROP:%llu, RX IPA EXCEP:%llu", + i, iface_context->stats.num_tx, + iface_context->stats.num_tx_drop, + iface_context->stats.num_tx_err, + iface_context->stats.num_tx_cac_drop, + iface_context->stats.num_rx_ipa_excep); + } +} + +void wlan_ipa_print_fw_wdi_stats(struct wlan_ipa_priv *ipa_ctx, + struct ipa_uc_fw_stats *uc_fw_stat) +{ + ipa_info("\n==== WLAN FW WDI TX STATS ====\n" + "COMP RING SIZE: %d\n" + "COMP RING DBELL IND VAL : %d\n" + "COMP RING DBELL CACHED VAL : %d\n" + "PKTS ENQ : %d\n" + "PKTS COMP : %d\n" + "IS SUSPEND : %d\n", + uc_fw_stat->tx_comp_ring_size, + uc_fw_stat->tx_comp_ring_dbell_ind_val, + uc_fw_stat->tx_comp_ring_dbell_cached_val, + uc_fw_stat->tx_pkts_enqueued, + uc_fw_stat->tx_pkts_completed, + uc_fw_stat->tx_is_suspend); + + ipa_info("\n==== WLAN FW WDI RX STATS ====\n" + "IND RING SIZE: %d\n" + "IND RING DBELL IND VAL : %d\n" + "IND RING DBELL CACHED VAL : %d\n" + "RDY IND CACHE VAL : %d\n" + "RFIL IND : %d\n" + "NUM PKT INDICAT : %d\n" + "BUF REFIL : %d\n" + "NUM DROP NO SPC : %d\n" + "NUM DROP NO BUF : %d\n" + "IS SUSPND : %d\n", + uc_fw_stat->rx_ind_ring_size, + uc_fw_stat->rx_ind_ring_dbell_ind_val, + uc_fw_stat->rx_ind_ring_dbell_ind_cached_val, + uc_fw_stat->rx_ind_ring_rd_idx_cached_val, + uc_fw_stat->rx_refill_idx, + uc_fw_stat->rx_num_pkts_indicated, + uc_fw_stat->rx_buf_refilled, + uc_fw_stat->rx_num_ind_drop_no_space, + uc_fw_stat->rx_num_ind_drop_no_buf, + uc_fw_stat->rx_is_suspend); +} + +/** + * wlan_ipa_print_ipa_wdi_stats - Print IPA WDI stats + * @ipa_ctx: IPA context + * + * Return: None + */ +static void wlan_ipa_print_ipa_wdi_stats(struct wlan_ipa_priv *ipa_ctx) +{ + qdf_ipa_hw_stats_wdi_info_data_t ipa_stat; + + qdf_ipa_get_wdi_stats(&ipa_stat); + + ipa_info("\n==== IPA WDI TX STATS ====\n" + "NUM PROCD : %d\n" + "CE DBELL : 0x%x\n" + "NUM DBELL FIRED : %d\n" + "COMP RNG FULL : %d\n" + "COMP RNG EMPT : %d\n" + "COMP RNG USE HGH : %d\n" + "COMP RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DBELL : %d\n" + "NUM UNEXP DBELL : %d\n" + "NUM BAM INT HDL : 0x%x\n" + "NUM QMB INT HDL : 0x%x\n", + ipa_stat.tx_ch_stats.num_pkts_processed, + ipa_stat.tx_ch_stats.copy_engine_doorbell_value, + ipa_stat.tx_ch_stats.num_db_fired, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow, + ipa_stat.tx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.tx_ch_stats.num_db, + ipa_stat.tx_ch_stats.num_unexpected_db, + ipa_stat.tx_ch_stats.num_bam_int_handled, + ipa_stat.tx_ch_stats.num_qmb_int_handled); + + ipa_info("\n==== IPA WDI RX STATS ====\n" + "MAX OST PKT : %d\n" + "NUM PKT PRCSD : %d\n" + "RNG RP : 0x%x\n" + "IND RNG FULL : %d\n" + "IND RNG EMPT : %d\n" + "IND RNG USE HGH : %d\n" + "IND RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DB : %d\n" + "NUM UNEXP DB : %d\n" + "NUM BAM INT HNDL : 0x%x\n", + ipa_stat.rx_ch_stats.max_outstanding_pkts, + ipa_stat.rx_ch_stats.num_pkts_processed, + ipa_stat.rx_ch_stats.rx_ring_rp_value, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow, + ipa_stat.rx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.rx_ch_stats.num_db, + ipa_stat.rx_ch_stats.num_unexpected_db, + ipa_stat.rx_ch_stats.num_bam_int_handled); +} + +void wlan_ipa_uc_info(struct wlan_ipa_priv *ipa_ctx) +{ + wlan_ipa_print_session_info(ipa_ctx); +} + +void wlan_ipa_uc_stat(struct wlan_ipa_priv *ipa_ctx) +{ + /* IPA IPA TX/RX stats */ + wlan_ipa_print_txrx_stats(ipa_ctx); + /* IPA WDI stats */ + wlan_ipa_print_ipa_wdi_stats(ipa_ctx); + /* WLAN FW WDI stats */ + wlan_ipa_uc_stat_request(ipa_ctx, WLAN_IPA_UC_STAT_REASON_DEBUG); +} + +#ifdef FEATURE_METERING +/** + * wlan_ipa_uc_sharing_stats_request() - Get IPA stats from IPA. + * @ipa_ctx: IPA context + * @reset_stats: reset stat countis after response + * + * Return: None + */ +static void wlan_ipa_uc_sharing_stats_request(struct wlan_ipa_priv *ipa_ctx, + uint8_t reset_stats) +{ + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if (false == ipa_ctx->resource_loading) { + qdf_mutex_release(&ipa_ctx->ipa_lock); + cdp_ipa_uc_get_share_stats(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + reset_stats); + } else { + qdf_mutex_release(&ipa_ctx->ipa_lock); + } +} + +/** + * wlan_ipa_uc_set_quota() - Set quota limit bytes from IPA. + * @ipa_ctx: IPA context + * @set_quota: when 1, FW starts quota monitoring + * @quota_bytes: quota limit in bytes + * + * Return: None + */ +static void wlan_ipa_uc_set_quota(struct wlan_ipa_priv *ipa_ctx, + uint8_t set_quota, + uint64_t quota_bytes) +{ + ipa_info("SET_QUOTA: set_quota=%d, quota_bytes=%llu", + set_quota, quota_bytes); + + qdf_mutex_acquire(&ipa_ctx->ipa_lock); + if (false == ipa_ctx->resource_loading) { + qdf_mutex_release(&ipa_ctx->ipa_lock); + } else { + cdp_ipa_uc_set_quota(ipa_ctx->dp_soc, ipa_ctx->dp_pdev, + quota_bytes); + qdf_mutex_release(&ipa_ctx->ipa_lock); + } +} + +QDF_STATUS wlan_ipa_uc_op_metering(struct wlan_ipa_priv *ipa_ctx, + struct op_msg_type *op_msg) +{ + struct op_msg_type *msg = op_msg; + struct ipa_uc_sharing_stats *uc_sharing_stats; + struct ipa_uc_quota_rsp *uc_quota_rsp; + struct ipa_uc_quota_ind *uc_quota_ind; + struct wlan_ipa_iface_context *iface_ctx; + + if (msg->op_code == WLAN_IPA_UC_OPCODE_SHARING_STATS) { + /* fill-up ipa_uc_sharing_stats structure from FW */ + uc_sharing_stats = (struct ipa_uc_sharing_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + memcpy(&(ipa_ctx->ipa_sharing_stats), uc_sharing_stats, + sizeof(struct ipa_uc_sharing_stats)); + + qdf_event_set(&ipa_ctx->ipa_uc_sharing_stats_comp); + } else if (msg->op_code == WLAN_IPA_UC_OPCODE_QUOTA_RSP) { + /* received set quota response */ + uc_quota_rsp = (struct ipa_uc_quota_rsp *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + memcpy(&(ipa_ctx->ipa_quota_rsp), uc_quota_rsp, + sizeof(struct ipa_uc_quota_rsp)); + + qdf_event_set(&ipa_ctx->ipa_uc_set_quota_comp); + } else if (msg->op_code == WLAN_IPA_UC_OPCODE_QUOTA_IND) { + /* hit quota limit */ + uc_quota_ind = (struct ipa_uc_quota_ind *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + ipa_ctx->ipa_quota_ind.quota_bytes = + uc_quota_ind->quota_bytes; + + /* send quota exceeded indication to IPA */ + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (iface_ctx) + qdf_ipa_broadcast_wdi_quota_reach_ind( + iface_ctx->dev->ifindex, + uc_quota_ind->quota_bytes); + else + ipa_err("Failed quota_reach_ind: NULL interface"); + } else { + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * __wlan_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. + * IPA calls to get WLAN stats or set quota limit. + * @priv: pointer to private data registered with IPA (we register a + * pointer to the IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void __wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt, + void *data) +{ + struct wlan_ipa_priv *ipa_ctx = wlan_ipa_get_obj_context(); + struct wlan_ipa_iface_context *iface_ctx; + qdf_ipa_get_wdi_sap_stats_t *wdi_sap_stats; + qdf_ipa_set_wifi_quota_t *ipa_set_quota; + QDF_STATUS status; + + ipa_debug("event=%d", evt); + + if (qdf_is_module_state_transitioning()) { + ipa_err_rl("Module transition in progress"); + return; + } + + iface_ctx = wlan_ipa_get_iface(ipa_ctx, QDF_STA_MODE); + if (!iface_ctx) { + ipa_err_rl("IPA uC share stats failed - no iface"); + return; + } + + switch (evt) { + case IPA_GET_WDI_SAP_STATS: + /* fill-up ipa_get_wdi_sap_stats structure after getting + * ipa_uc_fw_stats from FW + */ + wdi_sap_stats = data; + + qdf_event_reset(&ipa_ctx->ipa_uc_sharing_stats_comp); + wlan_ipa_uc_sharing_stats_request(ipa_ctx, + QDF_IPA_GET_WDI_SAP_STATS_RESET_STATS(wdi_sap_stats)); + status = qdf_wait_for_event_completion( + &ipa_ctx->ipa_uc_sharing_stats_comp, + IPA_UC_SHARING_STATES_WAIT_TIME); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ipa_err("IPA uC share stats request timed out"); + QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) + = 0; + } else { + QDF_IPA_GET_WDI_SAP_STATS_STATS_VALID(wdi_sap_stats) + = 1; + + QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_rx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV4_RX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_rx_bytes; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_rx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_RX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_rx_bytes; + QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_tx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV4_TX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv4_tx_bytes; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_PACKETS(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_tx_packets; + QDF_IPA_GET_WDI_SAP_STATS_IPV6_TX_BYTES(wdi_sap_stats) + = ipa_ctx->ipa_sharing_stats.ipv6_tx_bytes; + } + break; + + case IPA_SET_WIFI_QUOTA: + /* get ipa_set_wifi_quota structure from IPA and pass to FW + * through quota_exceeded field in ipa_uc_fw_stats + */ + ipa_set_quota = data; + + qdf_event_reset(&ipa_ctx->ipa_uc_set_quota_comp); + wlan_ipa_uc_set_quota(ipa_ctx, ipa_set_quota->set_quota, + ipa_set_quota->quota_bytes); + + status = qdf_wait_for_event_completion( + &ipa_ctx->ipa_uc_set_quota_comp, + IPA_UC_SET_QUOTA_WAIT_TIME); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ipa_err("IPA uC set quota request timed out"); + QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = 0; + } else { + QDF_IPA_SET_WIFI_QUOTA_BYTES(ipa_set_quota) = + ((uint64_t)(ipa_ctx->ipa_quota_rsp.quota_hi) + <<32)|ipa_ctx->ipa_quota_rsp.quota_lo; + QDF_IPA_SET_WIFI_QUOTA_SET_VALID(ipa_set_quota) = + ipa_ctx->ipa_quota_rsp.success; + } + break; + } +} + +/** + * wlan_ipa_wdi_meter_notifier_cb() - SSR wrapper for + * __wlan_ipa_wdi_meter_notifier_cb + * @priv: pointer to private data registered with IPA (we register a + * pointer to the IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +void wlan_ipa_wdi_meter_notifier_cb(qdf_ipa_wdi_meter_evt_type_t evt, + void *data) +{ + qdf_ssr_protect(__func__); + __wlan_ipa_wdi_meter_notifier_cb(evt, data); + qdf_ssr_unprotect(__func__); +} + +#endif /* FEATURE_METERING */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_obj_mgmt_api.h b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_obj_mgmt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b4e7e81b12ae122809f9bd45d66ac7ee8c5e9741 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_obj_mgmt_api.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 public API related to the wlan ipa called by north bound + */ + +#ifndef _WLAN_IPA_OBJ_MGMT_H_ +#define _WLAN_IPA_OBJ_MGMT_H_ + +#include "wlan_ipa_public_struct.h" +#include "wlan_objmgr_pdev_obj.h" + +#ifdef IPA_OFFLOAD + +/** + * ipa_init() - IPA module initialization + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_init(void); + +/** + * ipa_deinit() - IPA module deinitialization + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ipa_deinit(void); +#else + +static inline QDF_STATUS ipa_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ipa_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* IPA_OFFLOAD */ + +#endif /* _WLAN_IPA_OBJ_MGMT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_public_struct.h b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..ca3a01faf1eec21ef8f700516e9f64af671c965c --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_public_struct.h @@ -0,0 +1,91 @@ +/* + * 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: contains ipa public structure definitions + */ + +#ifndef _WLAN_IPA_PUBLIC_STRUCT_H_ +#define _WLAN_IPA_PUBLIC_STRUCT_H_ + +#include +#include +#include + +/** + * struct wlan_ipa_config + * @ipa_config: IPA config + * @desc_size: IPA descriptor size + * @txbuf_count: TX buffer count + * @bus_bw_high: Bus bandwidth high threshold + * @bus_bw_medium: Bus bandwidth medium threshold + * @bus_bw_low: Bus bandwidth low threshold + * @ipa_bw_high: IPA bandwidth high threshold + * @ipa_bw_medium: IPA bandwidth medium threshold + * @ipa_bw_low: IPA bandwidth low threshold + */ +struct wlan_ipa_config { + uint32_t ipa_config; + uint32_t desc_size; + uint32_t txbuf_count; + uint32_t bus_bw_high; + uint32_t bus_bw_medium; + uint32_t bus_bw_low; + uint32_t ipa_bw_high; + uint32_t ipa_bw_medium; + uint32_t ipa_bw_low; +}; + +/** + * enum wlan_ipa_wlan_event - WLAN IPA events + * @WLAN_IPA_CLIENT_CONNECT: Client Connects + * @WLAN_IPA_CLIENT_DISCONNECT: Client Disconnects + * @WLAN_IPA_AP_CONNECT: SoftAP is started + * @WLAN_IPA_AP_DISCONNECT: SoftAP is stopped + * @WLAN_IPA_STA_CONNECT: STA associates to AP + * @WLAN_IPA_STA_DISCONNECT: STA dissociates from AP + * @WLAN_IPA_CLIENT_CONNECT_EX: Peer associates/re-associates to softap + * @WLAN_IPA_WLAN_EVENT_MAX: Max value for the enum + */ +enum wlan_ipa_wlan_event { + WLAN_IPA_CLIENT_CONNECT, + WLAN_IPA_CLIENT_DISCONNECT, + WLAN_IPA_AP_CONNECT, + WLAN_IPA_AP_DISCONNECT, + WLAN_IPA_STA_CONNECT, + WLAN_IPA_STA_DISCONNECT, + WLAN_IPA_CLIENT_CONNECT_EX, + WLAN_IPA_WLAN_EVENT_MAX +}; + +/** + * struct ipa_uc_offload_control_params - ipa offload control params + * @offload_type: ipa offload type + * @vdev_id: vdev id + * @enable: ipa offload enable/disable + */ +struct ipa_uc_offload_control_params { + uint32_t offload_type; + uint32_t vdev_id; + uint32_t enable; +}; + +/* fp to send IPA UC offload cmd */ +typedef QDF_STATUS (*ipa_uc_offload_control_req)(struct wlan_objmgr_psoc *psoc, + struct ipa_uc_offload_control_params *req); +#endif /* end of _WLAN_IPA_PUBLIC_STRUCT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_tgt_api.h b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_tgt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..417b387cad9e98d3c5796149b3d59187feba8b9d --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_tgt_api.h @@ -0,0 +1,36 @@ +/* + * 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 wlan ipa to interact with target/WMI + */ + +#ifndef _WLAN_IPA_TGT_API_H_ +#define _WLAN_IPA_TGT_API_H_ + +#include "wlan_ipa_public_struct.h" + +/** + * tgt_ipa_uc_offload_enable_disable() - send ipa offload control to target if + * @pdev: objmgr pdev object + * @req: ipa offload control request + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_ipa_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev, + struct ipa_uc_offload_control_params *req); +#endif /* _WLAN_IPA_TGT_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..428b1bb21df32a2e9623ba343a9bf62a7900975b --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/inc/wlan_ipa_ucfg_api.h @@ -0,0 +1,545 @@ +/* + * 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. + */ +/** + * DOC: Declare public API related to the wlan ipa called by north bound + */ + +#ifndef _WLAN_IPA_UCFG_API_H_ +#define _WLAN_IPA_UCFG_API_H_ + +#include "wlan_ipa_public_struct.h" +#include "wlan_ipa_obj_mgmt_api.h" +#include "wlan_objmgr_pdev_obj.h" +#include "qdf_types.h" +#include "wlan_ipa_main.h" + +#ifdef IPA_OFFLOAD + +/** + * ucfg_ipa_is_present() - get IPA hw status + * + * ipa_uc_reg_rdyCB is not directly designed to check + * ipa hw status. This is an undocumented function which + * has confirmed with IPA team. + * + * Return: true - ipa hw present + * false - ipa hw not present + */ +bool ucfg_ipa_is_present(void); + +/** + * ucfg_ipa_is_enabled() - get IPA enable status + * + * Return: true - ipa is enabled + * false - ipa is not enabled + */ +bool ucfg_ipa_is_enabled(void); + +/** + * ucfg_ipa_uc_is_enabled() - get IPA uC enable status + * + * Return: true - ipa uC is enabled + * false - ipa uC is not enabled + */ +bool ucfg_ipa_uc_is_enabled(void); + +/** + * ucfg_ipa_update_config() - Update IPA component config + * + * Return: None + */ +void ucfg_ipa_update_config(struct wlan_ipa_config *config); + +/** + * ucfg_ipa_set_dp_handle() - register DP handle + * @psoc: psoc handle + * @dp_soc: data path soc handle + * + * Return: None + */ +void ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_soc); + +/** + * ucfg_ipa_set_txrx_handle() - register pdev txrx handler + * @psoc: psoc handle + * @psoc: psoc obj + * @txrx_handle: data path pdev txrx handle + * + * Return: None + */ +void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle); + +/** + * ucfg_ipa_set_perf_level() - Set IPA perf level + * @pdev: pdev obj + * @tx_packets: Number of packets transmitted in the last sample period + * @rx_packets: Number of packets received in the last sample period + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ipa_set_perf_level(struct wlan_objmgr_pdev *pdev, + uint64_t tx_packets, uint64_t rx_packets); + +/** + * ucfg_ipa_uc_info() - Print IPA uC resource and session information + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_uc_stat() - Print IPA uC stats + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev); + + +/** + * ucfg_ipa_uc_rt_debug_host_dump() - IPA rt debug host dump + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_dump_info() - Dump IPA context information + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_uc_stat_request() - Get IPA stats from IPA. + * @pdev: pdev obj + * @reason: STAT REQ Reason + * + * Return: None + */ +void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason); + +/** + * ucfg_ipa_uc_stat_query() - Query the IPA stats + * @pdev: pdev obj + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: None + */ +void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff); + +/** + * ucfg_ipa_reg_sap_xmit_cb() - Register upper layer SAP cb to transmit + * @pdev: pdev obj + * @cb: callback + * + * Return: None + */ +void ucfg_ipa_reg_sap_xmit_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_softap_xmit cb); + +/** + * ucfg_ipa_reg_send_to_nw_cb() - Register cb to send IPA Rx packet to network + * @pdev: pdev obj + * @cb: callback + * + * Return: None + */ +void ucfg_ipa_reg_send_to_nw_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_send_to_nw cb); + +/** + * ucfg_ipa_set_mcc_mode() - Set MCC mode + * @pdev: pdev obj + * @mcc_mode: 0=MCC/1=SCC + * + * Return: void + */ +void ucfg_ipa_set_mcc_mode(struct wlan_objmgr_pdev *pdev, bool mcc_mode); + +/** + * ucfg_ipa_set_dfs_cac_tx() - Set DFS cac tx block + * @pdev: pdev obj + * @tx_block: dfs cac tx block + * + * Return: void + */ +void ucfg_ipa_set_dfs_cac_tx(struct wlan_objmgr_pdev *pdev, bool tx_block); + +/** + * ucfg_ipa_set_ap_ibss_fwd() - Set AP intra bss forward + * @pdev: pdev obj + * @intra_bss: enable or disable ap intra bss forward + * + * Return: void + */ +void ucfg_ipa_set_ap_ibss_fwd(struct wlan_objmgr_pdev *pdev, bool intra_bss); + +/** + * ucfg_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe + * @pdev: pdev obj + * + * Return: void + */ +void ucfg_ipa_uc_force_pipe_shutdown(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_flush() - flush IPA exception path SKB's + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_flush(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_suspend() - Suspend IPA + * @pdev: pdev obj + * + * Return: QDF STATUS + */ +QDF_STATUS ucfg_ipa_suspend(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_resume() - Resume IPA + * @pdev: pdev obj + * + * Return: QDF STATUS + */ +QDF_STATUS ucfg_ipa_resume(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_uc_ol_init() - Initialize IPA uC offload + * @pdev: pdev obj + * @osdev: OS dev + * + * Return: QDF STATUS + */ +QDF_STATUS ucfg_ipa_uc_ol_init(struct wlan_objmgr_pdev *pdev, + qdf_device_t osdev); + +/** + * ucfg_ipa_uc_ol_deinit() - Deinitialize IPA uC offload + * @pdev: pdev obj + * + * Return: QDF STATUS + */ +QDF_STATUS ucfg_ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_send_mcc_scc_msg() - Send IPA WLAN_SWITCH_TO_MCC/SCC message + * @mcc_mode: 0=MCC/1=SCC + * + * Return: QDF STATUS + */ +QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode); + +/** + * ucfg_ipa_wlan_evt() - IPA event handler + * @pdev: pdev obj + * @net_dev: Interface net device + * @device_mode: Net interface device mode + * @sta_id: station id for the event + * @session_id: session id for the event + * @type: event enum of type ipa_wlan_event + * @mac_address: MAC address associated with the event + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_ipa_wlan_evt(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev, uint8_t device_mode, + uint8_t sta_id, uint8_t session_id, + enum wlan_ipa_wlan_event ipa_event_type, + uint8_t *mac_addr); + +/** + * ucfg_ipa_uc_smmu_map() - 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 + * + * Return: Status of map operation + */ +int ucfg_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr); + +/** + * ucfg_ipa_is_fw_wdi_activated - Is FW WDI activated? + * @pdev: pdev obj + * + * Return: true if FW WDI activated, false otherwise + */ +bool ucfg_ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_uc_cleanup_sta() - disconnect and cleanup sta iface + * @pdev: pdev obj + * @net_dev: Interface net device + * + * Send disconnect sta event to IPA driver and cleanup IPA iface, + * if not yet done + * + * Return: void + */ +void ucfg_ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + +/** + * ucfg_ipa_uc_disconnect_ap() - send ap disconnect event + * @pdev: pdev obj + * @net_dev: Interface net device + * + * Send disconnect ap event to IPA driver during SSR + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + +/** + * ucfg_ipa_cleanup_dev_iface() - Clean up net dev IPA interface + * @pdev: pdev obj + * @net_dev: Interface net device + * + * + * Return: None + */ +void ucfg_ipa_cleanup_dev_iface(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev); + +/** + * ucfg_ipa_uc_ssr_cleanup() - Handle IPA cleanup for SSR + * @pdev: pdev obj + * + * From hostside do cleanup such as deregister IPA interafces + * and send disconnect events so that it will be sync after SSR + * + * Return: None + */ +void ucfg_ipa_uc_ssr_cleanup(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ipa_fw_rejuvenate_send_msg() - Send msg to IPA driver in FW rejuvenate + * @pdev: pdev obj + * + * Return: None + */ +void ucfg_ipa_fw_rejuvenate_send_msg(struct wlan_objmgr_pdev *pdev); + +#else + +static inline bool ucfg_ipa_is_present(void) +{ + return false; +} + +static inline void ucfg_ipa_update_config(struct wlan_ipa_config *config) +{ +} + +static inline bool ucfg_ipa_is_enabled(void) +{ + return false; +} + +static inline bool ucfg_ipa_uc_is_enabled(void) +{ + return false; +} + +static inline +QDF_STATUS ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_soc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_set_perf_level(struct wlan_objmgr_pdev *pdev, + uint64_t tx_packets, uint64_t rx_packets) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason) +{ +} + +static inline +void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ +} + +static inline +void ucfg_ipa_reg_sap_xmit_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_softap_xmit cb) +{ +} + +static inline +void ucfg_ipa_reg_send_to_nw_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_send_to_nw cb) +{ +} + +static inline +void ucfg_ipa_set_mcc_mode(struct wlan_objmgr_pdev *pdev, bool mcc_mode) +{ +} + +static inline +void ucfg_ipa_set_dfs_cac_tx(struct wlan_objmgr_pdev *pdev, bool tx_block) +{ +} + +static inline +void ucfg_ipa_set_ap_ibss_fwd(struct wlan_objmgr_pdev *pdev, bool intra_bss) +{ +} + +static inline +void ucfg_ipa_uc_force_pipe_shutdown(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_flush(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +QDF_STATUS ucfg_ipa_suspend(struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_resume(struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_uc_ol_init(struct wlan_objmgr_pdev *pdev, + qdf_device_t osdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_ipa_wlan_evt(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev, uint8_t device_mode, + uint8_t sta_id, uint8_t session_id, + enum wlan_ipa_wlan_event ipa_event_type, + uint8_t *mac_addr) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +int ucfg_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + return 0; +} + +static inline +bool ucfg_ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev) +{ + return false; +} + +static inline +void ucfg_ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ +} + +static inline +QDF_STATUS ucfg_ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_ipa_cleanup_dev_iface(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ +} + +static inline +void ucfg_ipa_uc_ssr_cleanup(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline +void ucfg_ipa_fw_rejuvenate_send_msg(struct wlan_objmgr_pdev *pdev) +{ +} +#endif /* IPA_OFFLOAD */ +#endif /* _WLAN_IPA_UCFG_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c new file mode 100644 index 0000000000000000000000000000000000000000..8ca5779d33ffae6416050b31688482cc5fccd5df --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c @@ -0,0 +1,192 @@ +/* + * 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: public API related to the wlan ipa called by north bound HDD/OSIF + */ + +#include "wlan_ipa_obj_mgmt_api.h" +#include "wlan_ipa_main.h" +#include "wlan_objmgr_global_obj.h" +#include "target_if_ipa.h" + +/** + * ipa_pdev_obj_destroy_notification() - IPA pdev object destroy notification + * @pdev: pdev handle + * @arg_list: arguments list + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +ipa_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, + void *arg_list) +{ + QDF_STATUS status; + struct wlan_ipa_priv *ipa_obj; + + if (!ipa_config_is_enabled()) { + ipa_debug("IPA is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_IPA); + if (!ipa_obj) { + ipa_err("Failed to get ipa pdev object"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_pdev_component_obj_detach(pdev, + WLAN_UMAC_COMP_IPA, + ipa_obj); + if (QDF_IS_STATUS_ERROR(status)) + ipa_err("Failed to detatch ipa pdev object"); + + ipa_obj_cleanup(ipa_obj); + qdf_mem_free(ipa_obj); + + return status; +} + +/** + * ipa_pdev_obj_create_notification() - IPA pdev object creation notification + * @pdev: pdev handle + * @arg_list: arguments list + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +ipa_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, + void *arg_list) +{ + QDF_STATUS status; + struct wlan_ipa_priv *ipa_obj; + + ipa_debug("ipa pdev created"); + + if (!ipa_config_is_enabled()) { + ipa_info("IPA is disabled"); + return QDF_STATUS_SUCCESS; + } + + ipa_obj = qdf_mem_malloc(sizeof(*ipa_obj)); + if (!ipa_obj) { + ipa_err("Failed to allocate memory for ipa pdev object"); + return QDF_STATUS_E_NOMEM; + } + + status = wlan_objmgr_pdev_component_obj_attach(pdev, + WLAN_UMAC_COMP_IPA, + (void *)ipa_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + ipa_err("Failed to attach pdev ipa component"); + qdf_mem_free(ipa_obj); + return status; + } + + ipa_obj->pdev = pdev; + + status = ipa_obj_setup(ipa_obj); + if (QDF_IS_STATUS_ERROR(status)) { + ipa_err("Failed to setup ipa component"); + wlan_objmgr_pdev_component_obj_detach(pdev, + WLAN_UMAC_COMP_IPA, + ipa_obj); + qdf_mem_free(ipa_obj); + return status; + } + + target_if_ipa_register_tx_ops(&ipa_obj->ipa_tx_op); + + ipa_debug("ipa pdev attached"); + + return status; +} + +QDF_STATUS ipa_init(void) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ipa_info("ipa module dispatcher init"); + + if (!ipa_check_hw_present()) { + ipa_info("ipa hw not present"); + return status; + } + + status = ipa_config_mem_alloc(); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_IPA, + ipa_pdev_obj_create_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + ipa_err("Failed to register pdev create handler for ipa"); + + return status; + } + + status = wlan_objmgr_register_pdev_destroy_handler(WLAN_UMAC_COMP_IPA, + ipa_pdev_obj_destroy_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + ipa_err("Failed to register pdev destroy handler for ipa"); + goto fail_delete_pdev; + } + + return status; + +fail_delete_pdev: + wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_IPA, + ipa_pdev_obj_create_notification, NULL); + + return status; +} + +QDF_STATUS ipa_deinit(void) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ipa_info("ipa module dispatcher deinit"); + + if (!ipa_is_hw_support()) { + ipa_info("ipa hw is not present"); + return status; + } + + if (!ipa_config_is_enabled()) { + ipa_info("ipa is disabled"); + ipa_config_mem_free(); + return status; + } + + status = wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_IPA, + ipa_pdev_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + ipa_err("Failed to unregister pdev destroy handler"); + + status = wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_IPA, + ipa_pdev_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + ipa_err("Failed to unregister pdev create handler"); + + ipa_config_mem_free(); + + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_tgt_api.c b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_tgt_api.c new file mode 100644 index 0000000000000000000000000000000000000000..c9c1e97bef995f4c3a68e35643bca9ad11ba5bd7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_tgt_api.c @@ -0,0 +1,45 @@ +/* + * 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 ipa to interact with target/WMI + */ + +#include "wlan_ipa_tgt_api.h" +#include "wlan_ipa_main.h" +#include "wlan_ipa_public_struct.h" +#include +#include + +QDF_STATUS tgt_ipa_uc_offload_enable_disable(struct wlan_objmgr_pdev *pdev, + struct ipa_uc_offload_control_params *req) +{ + struct wlan_ipa_priv *ipa_obj; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + IPA_ENTER(); + + ipa_obj = ipa_pdev_get_priv_obj(pdev); + psoc = wlan_pdev_get_psoc(pdev); + + if (ipa_obj->ipa_tx_op) + status = ipa_obj->ipa_tx_op(psoc, req); + + IPA_EXIT(); + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..5888ce9e5629b81289aea471ccfcb61a280069d3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ipa/dispatcher/src/wlan_ipa_ucfg_api.c @@ -0,0 +1,206 @@ +/* + * 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. + */ +/** + * DOC: public API related to the wlan ipa called by north bound HDD/OSIF + */ + +#include "wlan_ipa_ucfg_api.h" +#include "wlan_ipa_main.h" + +bool ucfg_ipa_is_present(void) +{ + return ipa_is_hw_support(); +} + +bool ucfg_ipa_is_enabled(void) +{ + return ipa_config_is_enabled(); +} + +bool ucfg_ipa_uc_is_enabled(void) +{ + return ipa_config_is_uc_enabled(); +} + +void ucfg_ipa_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ + return ipa_set_txrx_handle(psoc, txrx_handle); +} + +void ucfg_ipa_set_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_soc) +{ + return ipa_set_dp_handle(psoc, dp_soc); +} + +void ucfg_ipa_update_config(struct wlan_ipa_config *config) +{ + ipa_config_update(config); +} + +QDF_STATUS ucfg_ipa_set_perf_level(struct wlan_objmgr_pdev *pdev, + uint64_t tx_packets, uint64_t rx_packets) +{ + return ipa_rm_set_perf_level(pdev, tx_packets, rx_packets); +} + +void ucfg_ipa_uc_info(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_info(pdev); +} + +void ucfg_ipa_uc_stat(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_stat(pdev); +} + +void ucfg_ipa_uc_rt_debug_host_dump(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_rt_debug_host_dump(pdev); +} + +void ucfg_ipa_dump_info(struct wlan_objmgr_pdev *pdev) +{ + return ipa_dump_info(pdev); +} + +void ucfg_ipa_uc_stat_request(struct wlan_objmgr_pdev *pdev, + uint8_t reason) +{ + return ipa_uc_stat_request(pdev, reason); +} + +void ucfg_ipa_uc_stat_query(struct wlan_objmgr_pdev *pdev, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + return ipa_uc_stat_query(pdev, ipa_tx_diff, ipa_rx_diff); +} + +void ucfg_ipa_reg_sap_xmit_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_softap_xmit cb) +{ + return ipa_reg_sap_xmit_cb(pdev, cb); +} + +void ucfg_ipa_reg_send_to_nw_cb(struct wlan_objmgr_pdev *pdev, + wlan_ipa_send_to_nw cb) +{ + return ipa_reg_send_to_nw_cb(pdev, cb); + +} + +void ucfg_ipa_set_mcc_mode(struct wlan_objmgr_pdev *pdev, bool mcc_mode) +{ + return ipa_set_mcc_mode(pdev, mcc_mode); +} + +void ucfg_ipa_set_dfs_cac_tx(struct wlan_objmgr_pdev *pdev, bool tx_block) +{ + return ipa_set_dfs_cac_tx(pdev, tx_block); +} + +void ucfg_ipa_set_ap_ibss_fwd(struct wlan_objmgr_pdev *pdev, bool intra_bss) +{ + return ipa_set_ap_ibss_fwd(pdev, intra_bss); +} + +void ucfg_ipa_uc_force_pipe_shutdown(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_force_pipe_shutdown(pdev); +} + +void ucfg_ipa_flush(struct wlan_objmgr_pdev *pdev) +{ + return ipa_flush(pdev); +} + +QDF_STATUS ucfg_ipa_suspend(struct wlan_objmgr_pdev *pdev) +{ + return ipa_suspend(pdev); +} + +QDF_STATUS ucfg_ipa_resume(struct wlan_objmgr_pdev *pdev) +{ + return ipa_resume(pdev); +} + +QDF_STATUS ucfg_ipa_uc_ol_init(struct wlan_objmgr_pdev *pdev, + qdf_device_t osdev) +{ + return ipa_uc_ol_init(pdev, osdev); +} + +QDF_STATUS ucfg_ipa_uc_ol_deinit(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_ol_deinit(pdev); +} + +QDF_STATUS ucfg_ipa_send_mcc_scc_msg(struct wlan_objmgr_pdev *pdev, + bool mcc_mode) +{ + return ipa_send_mcc_scc_msg(pdev, mcc_mode); +} + +QDF_STATUS ucfg_ipa_wlan_evt(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev, uint8_t device_mode, + uint8_t sta_id, uint8_t session_id, + enum wlan_ipa_wlan_event ipa_event_type, + uint8_t *mac_addr) +{ + return ipa_wlan_evt(pdev, net_dev, device_mode, sta_id, session_id, + ipa_event_type, mac_addr); +} + +int ucfg_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + return ipa_uc_smmu_map(map, num_buf, buf_arr); +} + +bool ucfg_ipa_is_fw_wdi_activated(struct wlan_objmgr_pdev *pdev) +{ + return ipa_is_fw_wdi_activated(pdev); +} + +void ucfg_ipa_uc_cleanup_sta(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + return ipa_uc_cleanup_sta(pdev, net_dev); +} + +QDF_STATUS ucfg_ipa_uc_disconnect_ap(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + return ipa_uc_disconnect_ap(pdev, net_dev); +} + +void ucfg_ipa_cleanup_dev_iface(struct wlan_objmgr_pdev *pdev, + qdf_netdev_t net_dev) +{ + return ipa_cleanup_dev_iface(pdev, net_dev); +} + +void ucfg_ipa_uc_ssr_cleanup(struct wlan_objmgr_pdev *pdev) +{ + return ipa_uc_ssr_cleanup(pdev); +} + +void ucfg_ipa_fw_rejuvenate_send_msg(struct wlan_objmgr_pdev *pdev) +{ + return ipa_fw_rejuvenate_send_msg(pdev); +} diff --git a/drivers/staging/qcacld-3.0/components/mlme/core/inc/wlan_mlme_main.h b/drivers/staging/qcacld-3.0/components/mlme/core/inc/wlan_mlme_main.h new file mode 100644 index 0000000000000000000000000000000000000000..9b69c61d65369ffa38ed17ae8f791cea67b4915c --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/mlme/core/inc/wlan_mlme_main.h @@ -0,0 +1,223 @@ +/* + * 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. + */ +/** + * DOC: declare internal APIs related to the mlme component + */ + +#ifndef _WLAN_MLME_MAIN_H_ +#define _WLAN_MLME_MAIN_H_ + +#include +#include +#include + +#define mlme_fatal(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_MLME, params) +#define mlme_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_MLME, params) +#define mlme_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_MLME, params) +#define mlme_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_MLME, params) +#define mlme_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_MLME, params) + +/** + * struct peer_mlme_priv_obj - peer MLME component object + * @ucast_key_cipher: unicast crypto type. + * @is_pmf_enabled: True if PMF is enabled + */ +struct peer_mlme_priv_obj { + uint32_t ucast_key_cipher; + bool is_pmf_enabled; +}; + +/** + * struct vdev_mlme_obj - VDEV MLME component object + * @dynamic_cfg: current configuration of nss, chains for vdev. + * @ini_cfg: Max configuration of nss, chains supported for vdev. + * @sta_dynamic_oce_value: Dyanmic oce flags value for sta + */ +struct vdev_mlme_priv_obj { + struct mlme_nss_chains dynamic_cfg; + struct mlme_nss_chains ini_cfg; + uint8_t sta_dynamic_oce_value; +}; + + +/** + * wlan_vdev_mlme_get_priv_obj() - Update the oce flags to FW + * @vdev: pointer to vdev object + * + * Return: vdev_mlme_priv_obj- Mlme private object + */ +struct vdev_mlme_priv_obj * +wlan_vdev_mlme_get_priv_obj(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_update_oce_flags() - Update the oce flags to FW + * @pdev: pointer to pdev object + * @cfg_value: INI value + * + * Return: void + */ +void wlan_mlme_update_oce_flags(struct wlan_objmgr_pdev *pdev, + uint8_t cfg_value); + +/** + * mlme_get_dynamic_vdev_config() - get the vdev dynamic config params + * @vdev: vdev pointer + * + * Return: pointer to the dynamic vdev config structure + */ +struct mlme_nss_chains *mlme_get_dynamic_vdev_config( + struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_ini_vdev_config() - get the vdev ini config params + * @vdev: vdev pointer + * + * Return: pointer to the ini vdev config structure + */ +struct mlme_nss_chains *mlme_get_ini_vdev_config( + struct wlan_objmgr_vdev *vdev); + +/** + * mlme_vdev_object_created_notification(): mlme vdev create handler + * @vdev: vdev which is going to created by objmgr + * @arg: argument for vdev create handler + * + * Register this api with objmgr to detect vdev is created + * + * Return: QDF_STATUS status in case of success else return error + */ + +QDF_STATUS +mlme_vdev_object_created_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * mlme_vdev_object_destroyed_notification(): mlme vdev delete handler + * @psoc: vdev which is going to delete by objmgr + * @arg: argument for vdev delete handler + * + * Register this api with objmgr to detect vdev is deleted + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +mlme_vdev_object_destroyed_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * wlan_peer_set_unicast_cipher() - set unicast cipher + * @peer: PEER object + * @value: value to be set + * + * Return: void + */ +static inline +void wlan_peer_set_unicast_cipher(struct wlan_objmgr_peer *peer, uint32_t value) +{ + 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_err(" peer mlme component object is NULL"); + return; + } + peer_priv->ucast_key_cipher = value; +} + +/** + * wlan_peer_get_unicast_cipher() - get unicast cipher + * @peer: PEER object + * + * Return: ucast_key_cipher value + */ +static inline +uint32_t wlan_peer_get_unicast_cipher(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_err("peer mlme component object is NULL"); + return 0; + } + + return peer_priv->ucast_key_cipher; +} + +/** + * wma_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_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); +#endif diff --git a/drivers/staging/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c b/drivers/staging/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c new file mode 100644 index 0000000000000000000000000000000000000000..12be8728086b4580ea70e96f06882123e4d462ef --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c @@ -0,0 +1,330 @@ +/* + * 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. + */ +/** + * DOC: define internal APIs related to the mlme component + */ +#include "wlan_mlme_main.h" +#include "wmi_unified.h" +#include "wlan_utility.h" +#include "wma_types.h" +#include "wma.h" +#include "wma_internal.h" + +struct vdev_mlme_priv_obj * +wlan_vdev_mlme_get_priv_obj(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_priv_obj *vdev_mlme; + + if (!vdev) { + mlme_err("vdev is NULL"); + return NULL; + } + + vdev_mlme = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (!vdev_mlme) { + mlme_err(" MLME component object is NULL"); + return NULL; + } + + return vdev_mlme; +} + +struct mlme_nss_chains *mlme_get_dynamic_vdev_config( + struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_priv_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_priv_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev component object is NULL"); + return NULL; + } + + return &vdev_mlme->dynamic_cfg; +} + +/** + * 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; + struct vdev_mlme_priv_obj *vdev_mlme; + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) { + vdev_mlme = wlan_vdev_mlme_get_priv_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev component object is NULL"); + return; + } + dynamic_fw_value = &vdev_mlme->sta_dynamic_oce_value; + if (*updated_fw_value == *dynamic_fw_value) { + mlme_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_err("Failed to send OCE update to FW"); + } +} + +void wlan_mlme_update_oce_flags(struct wlan_objmgr_pdev *pdev, + uint8_t cfg_value) +{ + uint16_t sap_connected_peer, go_connected_peer; + struct wlan_objmgr_psoc *psoc = NULL; + 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); + + if (sap_connected_peer || go_connected_peer) { + updated_fw_value = cfg_value; + updated_fw_value &= + ~(WMI_VDEV_OCE_PROBE_REQUEST_RATE_FEATURE_BITMAP); + updated_fw_value &= + ~(WMI_VDEV_OCE_PROBE_REQUEST_DEFERRAL_FEATURE_BITMAP); + mlme_debug("Disable STA OCE probe req rate and defferal updated_fw_value :%d", + updated_fw_value); + } else { + updated_fw_value = cfg_value; + mlme_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); +} + +struct mlme_nss_chains *mlme_get_ini_vdev_config( + struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_priv_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_priv_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev component object is NULL"); + return NULL; + } + + return &vdev_mlme->ini_cfg; +} + +QDF_STATUS +mlme_vdev_object_created_notification(struct wlan_objmgr_vdev *vdev, + void *arg) +{ + struct vdev_mlme_priv_obj *vdev_mlme; + QDF_STATUS status; + + if (!vdev) { + mlme_err(" VDEV is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev_mlme = qdf_mem_malloc(sizeof(*vdev_mlme)); + if (!vdev_mlme) { + mlme_err(" MLME component object alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + status = wlan_objmgr_vdev_component_obj_attach(vdev, + WLAN_UMAC_COMP_MLME, + (void *)vdev_mlme, + QDF_STATUS_SUCCESS); + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("unable to attach vdev priv obj to vdev obj"); + qdf_mem_free(vdev_mlme); + } + + return status; +} + +QDF_STATUS +mlme_vdev_object_destroyed_notification(struct wlan_objmgr_vdev *vdev, + void *arg) +{ + struct vdev_mlme_priv_obj *vdev_mlme; + QDF_STATUS status; + + if (!vdev) { + mlme_err(" VDEV is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev_mlme = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (!vdev_mlme) { + mlme_err(" VDEV MLME component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_MLME, + vdev_mlme); + + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("unable to detach vdev priv obj to vdev obj"); + + qdf_mem_free(vdev_mlme); + + return 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) +{ + struct wlan_objmgr_peer *peer; + uint32_t key_cipher; + + if (!psoc || !mic_len || !mic_hdr_len || !peer_mac) { + mlme_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_debug("Peer of peer_mac %pM not found", peer_mac); + return QDF_STATUS_E_INVAL; + } + key_cipher = wlan_peer_get_unicast_cipher(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + + if (key_cipher == WMI_CIPHER_AES_GCM) { + *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_debug("peer %pM hdr_len %d mic_len %d key_cipher %d", peer_mac, + *mic_hdr_len, *mic_len, key_cipher); + + return QDF_STATUS_SUCCESS; +} + +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_err(" peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = qdf_mem_malloc(sizeof(*peer_priv)); + if (!peer_priv) { + mlme_err(" peer_priv component object alloc failed"); + 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_err("unable to attach peer_priv obj to peer obj"); + qdf_mem_free(peer_priv); + } + + 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_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_err(" peer MLME component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_peer_component_obj_detach(peer, + WLAN_UMAC_COMP_MLME, + peer_priv); + + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("unable to detach peer_priv obj to peer obj"); + + qdf_mem_free(peer_priv); + + return status; +} + +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_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_err("peer mlme component object is NULL"); + return false; + } + + return peer_priv->is_pmf_enabled; +} diff --git a/drivers/staging/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/drivers/staging/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..17472ec8212b97eadd127285751f6050e24d2eb1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h @@ -0,0 +1,105 @@ +/* + * 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 UCFG APIs exposed by the mlme component + */ + +#ifndef _WLAN_MLME_UCFG_API_H_ +#define _WLAN_MLME_UCFG_API_H_ + +#include +#include +#include + +/** + * 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 contex. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_mlme_deinit(void); + +/** + * 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 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 mlme_nss_chains * +ucfg_mlme_get_dynamic_vdev_config(struct wlan_objmgr_vdev *vdev) +{ + return mlme_get_dynamic_vdev_config(vdev); +} + +/** + * ucfg_mlme_update_oce_flags: Update the OCE flags + * + * @pdev: pointer to pdev object + * @cfg_value: INI value of oce feature flag + * + * 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, + uint8_t cfg_value) +{ + wlan_mlme_update_oce_flags(pdev, cfg_value); +} + +/** + * ucfg_mlme_force_objmgr_vdev_peer_cleanup() - Cleanup ObjMgr Vdev peers + * during SSR + * @vdev_id: vdev ID + * + * Return: none + */ + +void ucfg_mlme_force_objmgr_vdev_peer_cleanup(uint8_t vdev_id); + +#endif /* _WLAN_MLME_UCFG_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c b/drivers/staging/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..7505011c1b894d32d241d71519429c09093e28f9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c @@ -0,0 +1,108 @@ +/* + * 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. + */ +/** + * DOC: define UCFG APIs exposed by the mlme component + */ + +#include +#include +#include +#include +#include + +QDF_STATUS ucfg_mlme_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_vdev_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("vdev create register notification failed"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_MLME, + mlme_vdev_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("vdev destroy register notification failed"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_register_peer_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_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_err("peer destroy register notification failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mlme_deinit(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_unregister_peer_destroy_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_destroyed_notification, + NULL); + + status = wlan_objmgr_unregister_peer_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_created_notification, + NULL); + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_MLME, + mlme_vdev_object_destroyed_notification, + NULL); + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_vdev_object_created_notification, + NULL); + + return status; +} + +void ucfg_mlme_force_objmgr_vdev_peer_cleanup(uint8_t vdev_id) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + mlme_err("Invalid wma handle"); + return; + } + wma_force_objmgr_vdev_peer_cleanup(wma_handle, vdev_id); +} + diff --git a/drivers/staging/qcacld-3.0/components/ocb/core/inc/wlan_ocb_main.h b/drivers/staging/qcacld-3.0/components/ocb/core/inc/wlan_ocb_main.h new file mode 100644 index 0000000000000000000000000000000000000000..0e66c828ed0d0adebc3f03b50216fbcab5e5e1e1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ocb/core/inc/wlan_ocb_main.h @@ -0,0 +1,248 @@ +/* + * 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: 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_log(level, args...) \ + QDF_TRACE(QDF_MODULE_ID_OCB, level, ## args) +#define ocb_logfl(level, format, args...) \ + ocb_log(level, FL(format), ## args) +#define ocb_alert(format, args...) \ + ocb_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define ocb_err(format, args...) \ + ocb_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define ocb_warn(format, args...) \ + ocb_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define ocb_notice(format, args...) \ + ocb_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define ocb_info(format, args...) \ + ocb_logfl(QDF_TRACE_LEVEL_INFO_HIGH, format, ## args) +#define ocb_debug(format, args...) \ + ocb_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +/** + * 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: pdev data path handle + * @ocb_cbs: legacy callback functions + * @ocb_txops: tx opertions for target interface + * @ocb_rxops: rx opertions 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; + void *dp_pdev; + 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 + * @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/drivers/staging/qcacld-3.0/components/ocb/core/src/wlan_ocb_main.c b/drivers/staging/qcacld-3.0/components/ocb/core/src/wlan_ocb_main.c new file mode 100644 index 0000000000000000000000000000000000000000..928641b14fd2c44d950bbdfb6998092d7a2ec0c7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ocb/core/src/wlan_ocb_main.c @@ -0,0 +1,574 @@ +/* + * 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: 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_cmd_type_str() - parse cmd to string + * @cmd_type: ocb cmd type + * + * This function parse ocb cmd 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 cdp_vdev *dp_vdev; + 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; + } + + dp_vdev = cdp_get_vdev_from_vdev_id(dp_soc, dp_pdev, vdev_id); + if (!dp_vdev) { + ocb_err("DP vdev handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + ocb_set_chan.ocb_channel_count = config->channel_count; + + /* release old settings */ + ocb_channel_info = cdp_get_ocb_chan_info(dp_soc, dp_vdev); + 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) { + ocb_err("Failed to allocate buffer for chan 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, dp_vdev, 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->dp_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: repsonse 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("%s: send TSF timer.", __func__); + 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: repsonse 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("%s: send DCC stats", __func__); + 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: repsonse 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("%s: NDL update response", __func__); + 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: repsonse 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("%s: DCC stats indication", __func__); + 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); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to post vdev start message"); + + 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) { + ocb_err("Failed to allocate memory for ocb pdev object"); + 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 detatch ocb pdev object"); + + qdf_mem_free(ocb_obj); + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_public_structs.h b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_public_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..b23fe512001a74aced421a7671c183b82161b227 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_public_structs.h @@ -0,0 +1,350 @@ +/* + * 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: contains ocb structure definitions + */ + +#ifndef _WLAN_OCB_STRUCTS_H_ +#define _WLAN_OCB_STRUCTS_H_ +#include + +/* number of vdevs that can support OCB */ +#define OCB_VDEVS_NUM 1 + +/* maximum number of channels that can do OCB */ +#define OCB_CHANNELS_NUM 2 + +/* maximum number of channels in an OCB schedule */ +#define OCB_SCHEDULES_NUM 2 + +/* 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) + +#define OCB_CHANNEL_MAX (5) +#define OCB_MAX_NUM_AC (4) + +/** + * 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[OCB_MAX_NUM_AC]; + 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_callback - 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/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_tgt_api.h b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_tgt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..4456f603b944bcd56be9517edee000a017d18197 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_ucfg_api.h b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_ucfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..de90f5b2a29d2e8a6c3808ae6067b73c35036291 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_ucfg_api.h @@ -0,0 +1,290 @@ +/* + * 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: 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 resposne + * @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 + * @context: 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_handle() - register pdev txrx handler + * @soc: soc handle + * @txrx_handle: data path pdev txrx handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle); +#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_handle() - register pdev txrx handler + * @soc: soc handle + * @txrx_handle: data path pdev txrx handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +static inline +QDF_STATUS ucfg_ocb_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_tgt_api.c b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_tgt_api.c new file mode 100644 index 0000000000000000000000000000000000000000..e55027efad78dadc86bf24bd013d62a43f480992 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_tgt_api.c @@ -0,0 +1,344 @@ +/* + * 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 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) { + ocb_err("Memory malloc failed for channel config status"); + 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 succcess + */ +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) { + ocb_err("Memory malloc failed for tsf timer"); + 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) { + ocb_err("Memory malloc failed for ndl update response"); + 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 + * @bool: 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) { + ocb_err("Memory malloc failed for dcc indication"); + 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/drivers/staging/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_ucfg_api.c b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_ucfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..de87d31e6b3fadfaa3f756d6bbceb3feb31ea74a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_ucfg_api.c @@ -0,0 +1,629 @@ +/* + * 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 ocb north bound interface definitions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_ocb_main.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_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ + 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 = txrx_handle; + + 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_CHAN_TO_BAND(wlan_reg_freq_to_chan(pdev, + config->channels[i].chan_freq)) + == 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_RUN) { + /* 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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_apf.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_apf.h new file mode 100644 index 0000000000000000000000000000000000000000..64dfa341d922fe686b6a5a1405f35971699766ed --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_arp.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_arp.h new file mode 100644 index 0000000000000000000000000000000000000000..d577cd2b8d3eb0f60abf3d8d3189ab67a802e3bb --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_arp.h @@ -0,0 +1,86 @@ +/* + * 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 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_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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_gtk.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_gtk.h new file mode 100644 index 0000000000000000000000000000000000000000..44774872e9de4412665944314356844086d52c65 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_gtk.h @@ -0,0 +1,78 @@ +/* + * 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 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: 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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_hw_filter.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_hw_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..6739cd0cf0de6ab847618242cea9c30504773aae --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_lphb.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_lphb.h new file mode 100644 index 0000000000000000000000000000000000000000..00cacccb9fd4d7942b227a157a5efb0e259fab05 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_main.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_main.h new file mode 100644 index 0000000000000000000000000000000000000000..85acc0e265b112009d62a4cdc2f1701b586aa1fb --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_main.h @@ -0,0 +1,392 @@ +/* + * 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 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_enter() pmo_debug("enter") +#define pmo_exit() pmo_debug("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_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 + * @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_update_dp_handle() - update vdev data path handle + * @vdev: objmgr vdev handle + * @dp_hdl: Vdev data path handle + * + * Return: None + */ +static inline +void pmo_core_vdev_update_dp_handle(struct wlan_objmgr_vdev *vdev, + void *dp_hdl) +{ + 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->vdev_dp_hdl = dp_hdl; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} + +/** + * pmo_core_vdev_get_dp_handle() - Get vdev data path handle + * @vdev: objmgr vdev handle + * + * Return: Vdev data path handle + */ +static inline +void *pmo_core_vdev_get_dp_handle(struct wlan_objmgr_vdev *vdev) +{ + void *dp_hdl; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + dp_hdl = vdev_ctx->vdev_dp_hdl; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + 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_handle() - update psoc pdev txrx layer handle + * @psoc: objmgr psoc handle + * @txrx_hdl: pdev txrx context handle + * + * Return: None + */ +void pmo_core_psoc_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_hdl); + +/** + * pmo_core_psoc_get_txrx_handle() - Get psoc pdev txrx handle + * @psoc: objmgr psoc handle + * + * Return: pdev txrx handle + */ +void *pmo_core_psoc_get_txrx_handle(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_is_vdev_up() - API to check whether vdev is UP + * @vdev: objmgr vdev handle + * + * Return:true if vdev is up else false + */ +static inline +bool pmo_is_vdev_up(struct wlan_objmgr_vdev *vdev) +{ + enum wlan_vdev_state state = WLAN_VDEV_S_INIT; + + if (!vdev) { + pmo_err("vdev context is invalid!"); + return false; + } + state = wlan_vdev_mlme_get_state(vdev); + + return state == WLAN_VDEV_S_RUN; +} + +/** + * 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; +} + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_MAIN_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h new file mode 100644 index 0000000000000000000000000000000000000000..fd0cca9fba4489a15cbe091a5cf34a4ce1d721f1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h @@ -0,0 +1,162 @@ +/* + * 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 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_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 + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @gtk_req: pmo gtk req param + * + * 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_enhance_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_enhance_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 + * @gtk_req: pmo gtk req param + * @action: true for enable els false + * + * 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 + * @gtk_req: pmo gtk req param + * @action: true for enable els false + * + * 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_get_mc_addr_list_count() -set mc address count + * @psoc: objmgr psoc + * @vdev_id: vdev id + * + * Return: set mc address count + */ +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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_ns.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_ns.h new file mode 100644 index 0000000000000000000000000000000000000000..26662dd749696606fd48cca1457bc59ea9cc76f4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_ns.h @@ -0,0 +1,87 @@ +/* + * 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 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_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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_objmgr.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_objmgr.h new file mode 100644 index 0000000000000000000000000000000000000000..44600253e9a863a27ad0be11fb23eff3a7393d4d --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_objmgr.h @@ -0,0 +1,221 @@ +/* + * 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: 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_vdev_put_ref(vdev) wlan_objmgr_vdev_release_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 wlan_objmgr_vdev * +pmo_psoc_get_vdev(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + + 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; +} + +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/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_pkt_filter.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_pkt_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..7a3db9b5bac27da6594e7aa28071dcfbda59639e --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_pkt_filter.h @@ -0,0 +1,69 @@ +/* + * 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 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_set_pkt_fltr_req() - Set packet filter + * @vdev: objmgr vdev + * @pmo_set_pkt_fltr_req: + * @vdev_id: + * API to set packet filter + * + * Return: QQDF_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 + * @vdev: objmgr vdev + * @pmo_clr_pkt_fltr_req: + * @vdev_id: + * + * API to clear packet filter + * + * Return: QQDF_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_req, + uint8_t vdev_id); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* _WLAN_PMO_PKT_FILTER_H_ */ + diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_priv.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..1951973e85a10bc4c40b3ef22ee9c46b3b4d1913 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_priv.h @@ -0,0 +1,155 @@ +/* + * 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 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" + +/** + * 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_hdl: txrx pdev handle + * @pause_bitmap_notifier: registered callback to update pause bitmap value + * @pmo_get_pause_bitmap: registered callback to get pause bitmap value + * @get_cfg_int: register callback to get integer from cfg + * @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; + void *txrx_hdl; + pmo_notify_pause_bitmap pause_bitmap_notifier; + pmo_get_pause_bitmap get_pause_bitmap; + pmo_is_device_in_low_pwr_mode is_device_in_low_pwr_mode; + pmo_get_cfg_int get_cfg_int; + 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 componenets + * @pmo_suspend_handler_arg: suspend handler argument sfor all componenets + * @pmo_resume_handler: resume handler table for all componenets + * @pmo_resume_handler_arg: resume handler argument for all componenets + * @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_params: place holder for gtk request for vdev + * @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 + * @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 + * @nlo_in_progress: true when pno/nlo in progress else false + * @nlo_match_received: true when nlo match recevied from fwr else false + * @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 + * @vdev_dp_hdl: vdev data path handle + * @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 + */ +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; + qdf_atomic_t gtk_err_enable; + bool ptrn_match_enable; + uint8_t num_wow_default_patterns; + uint8_t num_wow_user_patterns; + bool nlo_in_progress; + bool nlo_match_received; + 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; + void *vdev_dp_hdl; + uint32_t dyn_listen_interval; + bool restore_dtim_setting; + qdf_spinlock_t pmo_vdev_lock; +}; + +/** + * enum pmo_cfg_int_type: Mapping for Mac config param ID's + * @PMO_CFG_DTIM_PERIOD: CFG ID for Dtim Period value + * @PMO_CFG_LISTEN_INTERVAL: CFG ID for Listen Interval value + */ +enum pmo_cfg_int_type { + PMO_CFG_DTIM_PERIOD = 0x5, + PMO_CFG_LISTEN_INTERVAL = 0x26, +}; +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_PRIV_STRUCT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_static_config.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_static_config.h new file mode 100644 index 0000000000000000000000000000000000000000..9265ea6b1db62220a76c4e9f64943f4c41913d54 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_static_config.h @@ -0,0 +1,120 @@ +/* + * 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 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_id: vdev id + * + * 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 + * + * This is called to push action frames wow patterns from local + * cache to firmware. + * + * Return: None + */ +void pmo_register_action_frame_patterns( + struct wlan_objmgr_vdev *vdev); + +/** + * pmo_update_target_service(): API to update wmi target service info to PMO. + * @psoc: objmgr psoc + * @wmi_service: wmi service number + * @value: true when wmi service is enabled in firmware otherwise false. + * + * Return void + */ +void pmo_update_target_service(struct wlan_objmgr_psoc *psoc, + WMI_SERVICE service, bool value); + +/** + * pmo_update_ra_limit() - update ra limit based on apf filter + * enabled or not + * @psoc: objmgr psoc + * @apf_enabled: true when apf service is enabled else false + * + * Return: none + */ +void pmo_update_ra_limit(struct wlan_objmgr_psoc *psoc, bool apf_enabled); + +/** + * 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); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_STATIC_CONFIG_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_suspend_resume.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_suspend_resume.h new file mode 100644 index 0000000000000000000000000000000000000000..18289df20d94ce6997b1e101f1ab70c76a89ad0e --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_suspend_resume.h @@ -0,0 +1,398 @@ +/* + * 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 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 dyanmic wake events + * @wma: wma 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() -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; +} + +/** + * pmo_core_update_power_save_mode() - update power save mode + * @vdev: objmgr vdev 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_psoc_get_qpower_config() - get qpower configuration + * @psoc: objmgr psoc handle + * + * Power Save Offload configuration: + * 0 -> Power save offload is disabled + * 1 -> Legacy Power save enabled + Deep sleep Disabled + * 2 -> QPower enabled + Deep sleep Disabled + * 3 -> Legacy Power save enabled + Deep sleep Enabled + * 4 -> QPower enabled + Deep sleep Enabled + * 5 -> Duty cycling QPower enabled + * + * Return: enum powersave_qpower_mode with below values + * QPOWER_DISABLED if QPOWER is disabled + * QPOWER_ENABLED if QPOWER is enabled + * QPOWER_DUTY_CYCLING if DUTY CYCLING QPOWER is enabled + */ +static inline +enum pmo_power_save_qpower_mode pmo_core_psoc_get_qpower_config( + struct wlan_objmgr_psoc *psoc) +{ + uint8_t ps_mode = pmo_core_psoc_get_power_save_mode(psoc); + + switch (ps_mode) { + case pmo_ps_qpower_no_deep_sleep: + case pmo_ps_qpower_deep_sleep: + pmo_debug("QPOWER is enabled in power save mode %d", ps_mode); + return pmo_qpower_enabled; + case pmo_ps_duty_cycling_qpower: + pmo_debug("DUTY cycling QPOWER is enabled in power save mode %d", + ps_mode); + return pmo_qpower_duty_cycling; + default: + pmo_debug("QPOWER is disabled in power save mode %d", + ps_mode); + return pmo_qpower_disabled; + } +} + +/** + * 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; +} + +/** + * 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 + */ +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; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * pmo_is_vdev_in_ibss_mode() - check that vdev is in ibss mode or not + * @vdev: objmgr vdev handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in IBSS mode or not. + * + * Return: True/False + */ +static inline +bool pmo_is_vdev_in_ibss_mode(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE mode; + + mode = pmo_get_vdev_opmode(vdev); + + return (mode == QDF_IBSS_MODE) ? true : false; +} +#else +static inline bool pmo_is_vdev_in_ibss_mode(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * pmo_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 + * + * 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 + * + * 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 + * + * Return: none + */ +void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack); + +/** + * 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); +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_SUSPEND_RESUME_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_wow.h b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_wow.h new file mode 100644 index 0000000000000000000000000000000000000000..353d15d04695a42ff243da259a1fe44d1aab3d89 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/inc/wlan_pmo_wow.h @@ -0,0 +1,705 @@ +/* + * 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 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 patern 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 5 +/* Default Listen Interval */ +#define PMO_DEFAULT_LISTEN_INTERVAL 1 + +/** + * 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_get_wow_default_ptrn() -Set wow default ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * 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; +} + +void pmo_dump_wow_ptrn(struct pmo_wow_add_pattern *ptrn); +/** + * 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 + * @ptrn: 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_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_mode_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 + * + * Return: None + */ +static inline +void pmo_core_set_wow_nack(struct pmo_psoc_priv_obj *psoc_ctx, bool value) +{ + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.wow_nack = value; + 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_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: true if wow initial wake up is received else false + * + * Return: None + */ +static inline +void pmo_core_update_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx, + bool value) +{ + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.wow_initial_wake_up = value; + qdf_spin_unlock_bh(&psoc_ctx->lock); +} + +/** + * pmo_core_get_wow_initial_wake_up() - Get wow initial wake up + * @psoc_ctx: Pointer to objmgr psoc handle + * + * Return: true if wow initial wake up is received else false + */ +static inline +bool pmo_core_get_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx) +{ + bool value; + + qdf_spin_lock_bh(&psoc_ctx->lock); + value = psoc_ctx->wow.wow_initial_wake_up; + qdf_spin_unlock_bh(&psoc_ctx->lock); + + return value; +} + +#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 + * @posc: 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 + +#ifdef WLAN_FEATURE_NAN +/** + * pmo_is_nan_enabled() - check if NaN is enabled + * @posc: 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 NaN is enabled else false + */ +static inline +bool pmo_core_is_nan_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.nan_enable; +} +#else +static inline +bool pmo_core_is_nan_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); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_WOW_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_apf.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_apf.c new file mode 100644 index 0000000000000000000000000000000000000000..8acc3c11f9c81732fe64f96b92c5c41c468a2620 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_arp.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_arp.c new file mode 100644 index 0000000000000000000000000000000000000000..b143e952a4ab7ba991bf5fc398cace2549b2569e --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_arp.c @@ -0,0 +1,412 @@ +/* + * 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 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; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + request = qdf_mem_malloc(sizeof(*request)); + if (!request) { + pmo_err("cannot allocate arp 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: %pM bss peer mac addr: %pM", + wlan_vdev_mlme_get_macaddr(vdev), + peer_bssid.bytes); + + request->enable = PMO_OFFLOAD_ENABLE; + request->is_offload_applied = false; + /* converting u32 to IPV4 address */ + for (index = 0; index < PMO_IPV4_ADDR_LEN; 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: + pmo_exit(); + + 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; + + 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_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: + if (psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is enabled, skip in mode %d", + trigger); + status = QDF_STATUS_SUCCESS; + goto out; + } + /* 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: + pmo_exit(); + + 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: + if (psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is enabled, skip in mode: %d", + trigger); + status = QDF_STATUS_SUCCESS; + goto out; + } + /* 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)) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_cache_arp_offload_req(struct pmo_arp_req *arp_req) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + pmo_enter(); + 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 = pmo_psoc_get_vdev(arp_req->psoc, arp_req->vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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: + pmo_vdev_put_ref(vdev); +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; + + 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 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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; + + 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("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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_gtk.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_gtk.c new file mode 100644 index 0000000000000000000000000000000000000000..aef7eb33a50a7143ced1385d161d98bf86799a9e --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_gtk.c @@ -0,0 +1,359 @@ +/* + * 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 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; + + 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)) + 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)) + 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:%pM, peer mac:%pM are not same", + vdev_ctx->vdev_gtk_req.bssid.bytes, + 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; + + 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; + + pmo_enter(); + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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; + + pmo_enter(); + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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) { + pmo_err("op_gtk_req is NULL"); + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + status = pmo_core_do_enable_gtk_offload(vdev, vdev_ctx, op_gtk_req); +dec_ref: + pmo_vdev_put_ref(vdev); +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) { + pmo_err("op_gtk_req is NULL"); + status = QDF_STATUS_E_NOMEM; + goto dec_ref; + } + + status = pmo_core_do_disable_gtk_offload(vdev, vdev_ctx, op_gtk_req); +dec_ref: + pmo_vdev_put_ref(vdev); +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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + return status; +} + diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_hw_filter.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_hw_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..60571f5610a697c5ba8b42af8efe831eda7b16f7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_hw_filter.c @@ -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: 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)) { + status = QDF_STATUS_E_NOSUPPORT; + 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); + + pmo_vdev_put_ref(vdev); + +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)) { + status = QDF_STATUS_E_NOSUPPORT; + 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); + + pmo_vdev_put_ref(vdev); + +exit_with_status: + pmo_exit(); + + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_lphb.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_lphb.c new file mode 100644 index 0000000000000000000000000000000000000000..2ee672a9ee80f046f4587f34e3aa969bc755647a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_lphb.c @@ -0,0 +1,243 @@ +/* + * 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 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 == NULL) { + 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 == NULL) { + 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/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_main.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_main.c new file mode 100644 index 0000000000000000000000000000000000000000..2c655d4c05a861870f2fa097a9819fe90cdf1de1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_main.c @@ -0,0 +1,238 @@ +/* + * 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: 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" + +static struct wlan_pmo_ctx *gp_pmo_ctx; + +QDF_STATUS pmo_allocate_ctx(void) +{ + /* If it is already created, ignore */ + if (gp_pmo_ctx != NULL) { + 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) { + pmo_err("unable to allocate pmo_ctx"); + QDF_ASSERT(0); + 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; +} + +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_vdev_get_bsspeer(vdev); + 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); + + 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_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_hdl) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->txrx_hdl = txrx_hdl; + } +} + +void *pmo_core_psoc_get_txrx_handle(struct wlan_objmgr_psoc *psoc) +{ + void *txrx_hdl = NULL; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + txrx_hdl = psoc_ctx->txrx_hdl; + } + + return txrx_hdl; +} diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c new file mode 100644 index 0000000000000000000000000000000000000000..d68de019b2431098b95f8014fb6d716da86c4ff5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c @@ -0,0 +1,686 @@ +/* + * 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 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++) { + pmo_debug("%pM", ip->mc_addr[i].bytes); + /* + * 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 %pM", + 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, mlist[%pM]", + j, op_list->mc_addr[i].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; + + 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, true); + + pmo_vdev_put_ref(vdev); + +exit_with_status: + pmo_exit(); + + 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); + + pmo_vdev_put_ref(vdev); + +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; + + pmo_enter(); + + 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]); + } + + pmo_exit(); + + 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; + + pmo_enter(); + 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]); + } + + pmo_exit(); + + 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; + + pmo_enter(); + 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: + pmo_exit(); + + 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; + + pmo_enter(); + 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_err("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_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 = false; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +out: + pmo_exit(); + + 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) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct pmo_vdev_priv_obj *vdev_ctx; + uint8_t mc_cnt; + + vdev = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + return PMO_INVALID_MC_ADDR_COUNT; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_warn("failed to get vdev reference"); + 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); + + pmo_vdev_put_ref(vdev); + + return mc_cnt; +} + +void pmo_core_set_mc_addr_list_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t count) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_vdev *vdev; + + vdev = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + return; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_warn("failed to get vdev reference"); + 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); + + pmo_vdev_put_ref(vdev); +} + +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; + } + + 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; + + pmo_enter(); + + if (!mc_list_config->psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev = pmo_psoc_get_vdev(mc_list_config->psoc, mc_list_config->vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_warn("failed to get vdev reference"); + status = QDF_STATUS_E_INVAL; + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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; + + pmo_enter(); + if (!psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_warn("failed to get vdev reference"); + status = QDF_STATUS_E_INVAL; + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + op_mc_list_req = qdf_mem_malloc(sizeof(*op_mc_list_req)); + if (!op_mc_list_req) { + pmo_err("op_mc_list_req is NULL"); + 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: + pmo_exit(); + + 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; + + pmo_enter(); + + status = pmo_psoc_get_ref(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto exit_with_status; + + vdev = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto put_psoc; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + 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)) { + 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: + pmo_vdev_put_ref(vdev); + +put_psoc: + pmo_psoc_put_ref(psoc); + +exit_with_status: + pmo_exit(); + + 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) { + pmo_err("out of memory"); + 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; + + pmo_enter(); + + if (!psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + vdev = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + status = pmo_core_mc_addr_flitering_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto put_ref; + + if (!wlan_vdev_is_up(vdev)) { + status = QDF_STATUS_E_INVAL; + goto put_ref; + } + + pmo_debug("disable mclist trigger: %d", trigger); + + status = pmo_core_handle_disable_mc_list_trigger(vdev, trigger); + +put_ref: + pmo_vdev_put_ref(vdev); + +out: + pmo_exit(); + + 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 = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto put_psoc; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + 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: + pmo_vdev_put_ref(vdev); + +put_psoc: + pmo_psoc_put_ref(psoc); + +exit_with_status: + pmo_exit(); + + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_ns.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_ns.c new file mode 100644 index 0000000000000000000000000000000000000000..3e4ee19f8ef690ac64f1178293e0ce16547cb97b --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_ns.c @@ -0,0 +1,494 @@ +/* + * 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 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], PMO_MAC_IPV6_ADDR_LEN); + + 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; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + qdf_mem_zero(&request, sizeof(request)); + pmo_core_fill_ns_addr(&request, ns_req); + + request.enable = PMO_OFFLOAD_ENABLE; + request.is_offload_applied = false; + qdf_mem_copy(&request.self_macaddr.bytes, + wlan_vdev_mlme_get_macaddr(vdev), + QDF_MAC_ADDR_SIZE); + + /* set number of ns offload address count */ + request.num_ns_offload_count = ns_req->count; + + peer = wlan_vdev_get_bsspeer(vdev); + if (!peer) { + pmo_err("peer is null"); + status = QDF_STATUS_E_INVAL; + goto out; + } + pmo_debug("vdev self mac addr: %pM bss peer mac addr: %pM", + wlan_vdev_mlme_get_macaddr(vdev), + wlan_peer_get_macaddr(peer)); + /* get peer and peer mac accdress aka ap mac address */ + qdf_mem_copy(&request.bssid, + wlan_peer_get_macaddr(peer), + QDF_MAC_ADDR_SIZE); + /* 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: + pmo_exit(); + + 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; + + 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_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: + if (psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is enabled, skip in mode: %d", + trigger); + goto out; + } + /* 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: + pmo_exit(); + + 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: + if (psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is enabled, skip in mode: %d", + trigger); + goto out; + } + /* config arp/ns when active offload is disable */ + 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 (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) { + pmo_debug("ns offload dynamically 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)) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_cache_ns_offload_req( + struct pmo_ns_req *ns_req) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + pmo_enter(); + 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 = pmo_psoc_get_vdev(ns_req->psoc, ns_req->vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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: + pmo_vdev_put_ref(vdev); +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; + 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; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + 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. + */ + vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic = + true; + goto skip_ns_dynamic_check; + } + + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) { + pmo_debug("ns offload dynamically disable"); + 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 out; + } + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + 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; + + 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); + + 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. + */ + vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic = + false; + goto skip_ns_dynamic_check; + } + + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) { + pmo_debug("ns offload dynamically disable"); + 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: + pmo_vdev_put_ref(vdev); +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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_pkt_filter.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_pkt_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..2624c5cabf92f2c831d7370ae46132d3208c9ae5 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_static_config.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_static_config.c new file mode 100644 index 0000000000000000000000000000000000000000..928b3eb5b2d841587209360a67ce8c8f11fdb4a1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_static_config.c @@ -0,0 +1,441 @@ +/* + * 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 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}; + +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; + const char *iface_type; + struct pmo_psoc_priv_obj *psoc_ctx; + pmo_is_device_in_low_pwr_mode is_low_pwr_mode; + + 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); + + 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: + iface_type = "STA"; + pmo_set_sta_wow_bitmask(event_bitmap, PMO_WOW_MAX_EVENT_BM_LEN); + break; + + case QDF_IBSS_MODE: + iface_type = "IBSS"; + pmo_set_sta_wow_bitmask(event_bitmap, PMO_WOW_MAX_EVENT_BM_LEN); + 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: + iface_type = "SAP"; + pmo_set_sap_wow_bitmask(event_bitmap, PMO_WOW_MAX_EVENT_BM_LEN); + break; + + case QDF_NDI_MODE: +#ifdef WLAN_FEATURE_NAN_DATAPATH + iface_type = "NAN"; + /* wake up host when Nan Management Frame is received */ + pmo_set_wow_event_bitmap(WOW_NAN_DATA_EVENT, + PMO_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + /* wake up host when NDP data packet is received */ + pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + event_bitmap); +#endif + 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 arp_offset = 20; + uint8_t mac_mask[PMO_80211_ADDR_LEN]; + struct pmo_vdev_priv_obj *vdev_ctx; + + 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, PMO_80211_ADDR_LEN, 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), + PMO_80211_ADDR_LEN, 0, mac_mask, + PMO_80211_ADDR_LEN, false); + if (ret != QDF_STATUS_SUCCESS) { + pmo_err("Failed to add WOW unicast pattern ret %d", ret); + return ret; + } + + /* + * Setup all ARP pkt pattern. This is dummy pattern hence the length + * is zero. Pattern ID should be unique per vdev. + */ + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn(vdev_ctx), + arp_ptrn, 0, arp_offset, arp_mask, 0, false); + if (ret != QDF_STATUS_SUCCESS) + pmo_err("Failed to add WOW ARP pattern ret %d", 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 arp_offset = 12; + uint8_t mac_mask[PMO_80211_ADDR_LEN]; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + qdf_mem_set(&mac_mask, PMO_80211_ADDR_LEN, 0xFF); + /* + * Set up unicast wow pattern + * WoW pattern ID should be unique for each vdev + * Different WoW patterns can use same pattern ID + */ + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn(vdev_ctx), + wlan_vdev_mlme_get_macaddr(vdev), + PMO_80211_ADDR_LEN, 0, mac_mask, + PMO_80211_ADDR_LEN, false); + if (ret != QDF_STATUS_SUCCESS) { + 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 + * 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) { + /* 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) { + /* 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); + } + } + +} + +/** + * set_action_id_drop_pattern_for_spec_mgmt() - Set action id of action + * frames for spectrum mgmt frames to be droppped 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 droppped 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; +} + +void pmo_register_action_frame_patterns(struct wlan_objmgr_vdev *vdev) +{ + + struct pmo_action_wakeup_set_params cmd = {0}; + int i = 0; + QDF_STATUS status; + + cmd.vdev_id = pmo_vdev_get_id(vdev); + cmd.operation = pmo_action_wakeup_set; + + cmd.action_category_map[i++] = 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); + + for (i = 0; i < PMO_SUPPORTED_ACTION_CATE_ELE_LIST; i++) { + if (i < ALLOWED_ACTION_FRAME_MAP_WORDS) + pmo_debug("%s: %d action Wakeup pattern 0x%x in fw", + __func__, i, cmd.action_category_map[i]); + else + cmd.action_category_map[i] = 0; + } + + pmo_debug("Spectrum mgmt action id drop bitmap: 0x%x", + cmd.action_per_category[PMO_MAC_ACTION_SPECTRUM_MGMT]); + pmo_debug("Public action id drop bitmap: 0x%x", + 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); +} + diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_suspend_resume.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_suspend_resume.c new file mode 100644 index 0000000000000000000000000000000000000000..7f7e12672379098f36de72b6899923e81756509a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_suspend_resume.c @@ -0,0 +1,1507 @@ +/* + * 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: 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_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 "cds_api.h" +#include "wlan_pmo_static_config.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; + uint32_t beacon_interval_mod; + struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; + struct pmo_psoc_priv_obj *psoc_priv = pmo_vdev_get_psoc_priv(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 { + int cfg_value = 0; + /* Get Listen Interval */ + if ((psoc_priv->get_cfg_int) && + (psoc_priv->get_cfg_int(PMO_CFG_LISTEN_INTERVAL, + &cfg_value) != QDF_STATUS_SUCCESS)) { + pmo_err("Failed to get value for listen interval"); + cfg_value = PMO_DEFAULT_LISTEN_INTERVAL; + } + *listen_interval = cfg_value; + } + 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; + + 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, + psoc_cfg->wow_data_inactivity_timeout); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_debug("Failed to Set wow inactivity timeout vdevId %d", + vdev_id); + } + + non_wow_inactivity_time = psoc_cfg->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); + struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; + + 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, + psoc_cfg->ps_data_inactivity_timeout); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_debug("Failed to Set inactivity timeout vdevId %d", + vdev_id); + } + + pmo_exit(); +} + +/** + * 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) +{ + uint32_t listen_interval = PMO_DEFAULT_LISTEN_INTERVAL; + QDF_STATUS ret; + uint8_t vdev_id; + enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); + + 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; + QDF_STATUS status; + + 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 = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) + continue; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + 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); + pmo_vdev_put_ref(vdev); + } +} + +/** + * 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 = pmo_psoc_get_vdev(psoc, vdev_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); + } + +} + +/** + * pmo_core_psoc_configure_suspend(): configure suspend req events + * @psoc: objmgr psoc + * + * 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) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_enter(); + + psoc_ctx = pmo_psoc_get_priv(psoc); + + if (pmo_core_is_wow_applicable(psoc)) { + pmo_debug("WOW Suspend"); + pmo_core_apply_lphb(psoc); + + 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); + } + + 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; + } + + /* Suspend all components before sending target suspend command */ + status = pmo_suspend_all_components(psoc, type); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to suspend all component"); + goto dec_psoc_ref; + } + + status = pmo_core_psoc_configure_suspend(psoc); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to configure suspend"); + +dec_psoc_ref: + pmo_psoc_put_ref(psoc); +out: + pmo_exit(); + + 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; + struct pmo_psoc_priv_obj *psoc_priv = pmo_vdev_get_psoc_priv(vdev); + + 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 ((psoc_priv->get_cfg_int) && + (psoc_priv->get_cfg_int(PMO_CFG_LISTEN_INTERVAL, + &cfg_data_val) != QDF_STATUS_SUCCESS)) { + pmo_err("Failed to get value for listen interval"); + cfg_data_val = PMO_DEFAULT_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; + QDF_STATUS status; + + 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 = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) + continue; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + 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); + pmo_vdev_put_ref(vdev); + } +} + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +/** + * pmo_unpause_vdev - unpause all vdev + * @psoc: objmgr psoc handle + * + * 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; + struct wlan_objmgr_vdev *vdev; + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) + continue; + + /* 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), + pmo_core_vdev_get_dp_handle(vdev), + 0xffffffff); + 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 + * + * 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) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_enter(); + + psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_core_set_resume_dtim(psoc); + pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false); + pmo_unpause_all_vdev(psoc, psoc_ctx); + + pmo_exit(); + + 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; + } + + /* Resume all components */ + status = pmo_resume_all_components(psoc, type); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to resume all the components"); + goto dec_psoc_ref; + } + + status = pmo_core_psoc_configure_resume(psoc); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to configure resume"); + +dec_psoc_ref: + 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 + * + * 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) +{ + int host_credits, wmi_pending_cmds; + struct pmo_wow_cmd_params param = {0}; + QDF_STATUS status; + + pmo_enter(); + qdf_event_reset(&psoc_ctx->wow.target_suspend); + pmo_core_set_wow_nack(psoc_ctx, false); + 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 fall-through to default */ + 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); + /* intentional fall-through to default */ + 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; + } + + 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; + } + + if (psoc_ctx->wow.wow_state != pmo_wow_state_legacy_d0) + 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 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)); + pmo_tgt_update_target_suspend_flag(psoc, false); + qdf_trigger_self_recovery(); + goto out; + } + + if (pmo_core_get_wow_nack(psoc_ctx)) { + pmo_err("FW not ready to WOW"); + pmo_tgt_update_target_suspend_flag(psoc, false); + status = QDF_STATUS_E_AGAIN; + goto out; + } + + 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(); + } + pmo_debug("WOW enabled successfully in fw: credits:%d pending_cmds: %d", + host_credits, wmi_pending_cmds); + + pmo_core_update_wow_enable_cmd_sent(psoc_ctx, true); + +out: + pmo_exit(); + + 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; + + pmo_enter(); + + psoc_ctx = pmo_psoc_get_priv(psoc); + + 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); + qdf_trigger_self_recovery(); + } + +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; + + pmo_enter(); + 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); + pmo_debug("wow mode selected %d", wow_mode_selected); + + if (wow_mode_selected) + status = pmo_core_enable_wow_in_fw(psoc, psoc_ctx, wow_params); + else + status = pmo_core_psoc_suspend_target(psoc, 0); + + pmo_psoc_put_ref(psoc); +out: + pmo_exit(); + + return status; +} + +#ifdef FEATURE_RUNTIME_PM +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; + void *txrx_pdev; + void *htc_ctx; + QDF_STATUS status; + struct pmo_wow_enable_params wow_params = {0}; + + 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); + txrx_pdev = pmo_core_psoc_get_txrx_handle(psoc); + htc_ctx = pmo_core_psoc_get_htc_handle(psoc); + if (!hif_ctx || !dp_soc || !txrx_pdev || !htc_ctx) { + pmo_err("Invalid hif: %pK, dp: %pK, txrx: %pK, htc: %pK", + hif_ctx, dp_soc, txrx_pdev, 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; + + if (hif_pre_runtime_suspend(hif_ctx)) + goto runtime_failure; + + status = cdp_runtime_suspend(dp_soc, txrx_pdev); + if (status != QDF_STATUS_SUCCESS) + goto runtime_failure; + + if (htc_runtime_suspend(htc_ctx)) + goto cdp_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); + 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; + + if (hif_runtime_suspend(hif_ctx)) + goto pmo_bus_resume; + + if (pld_cb && pld_cb()) + goto resume_hif; + + hif_process_runtime_suspend_success(hif_ctx); + + goto dec_psoc_ref; + +resume_hif: + QDF_BUG(!hif_runtime_resume(hif_ctx)); + +pmo_bus_resume: + QDF_BUG(QDF_STATUS_SUCCESS == + pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND)); + +pmo_resume_configure: + QDF_BUG(QDF_STATUS_SUCCESS == + pmo_core_psoc_configure_resume(psoc)); + +resume_htc: + QDF_BUG(QDF_STATUS_SUCCESS == + pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false)); + + QDF_BUG(!htc_runtime_resume(htc_ctx)); + +cdp_runtime_resume: + QDF_BUG(QDF_STATUS_SUCCESS == + cdp_runtime_resume(dp_soc, txrx_pdev)); + +runtime_failure: + hif_process_runtime_suspend_failure(hif_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) +{ + void *hif_ctx; + void *dp_soc; + void *txrx_pdev; + void *htc_ctx; + QDF_STATUS status; + + 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); + txrx_pdev = pmo_core_psoc_get_txrx_handle(psoc); + htc_ctx = pmo_core_psoc_get_htc_handle(psoc); + if (!hif_ctx || !dp_soc || !txrx_pdev || !htc_ctx) { + pmo_err("Invalid hif: %pK, dp: %pK, txrx: %pK, htc: %pK", + hif_ctx, dp_soc, txrx_pdev, htc_ctx); + status = QDF_STATUS_E_INVAL; + goto dec_psoc_ref; + } + + hif_pre_runtime_resume(hif_ctx); + + if (pld_cb) + QDF_BUG(!pld_cb()); + + QDF_BUG(!hif_runtime_resume(hif_ctx)); + + status = pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND); + QDF_BUG(status == QDF_STATUS_SUCCESS); + + status = pmo_core_psoc_configure_resume(psoc); + QDF_BUG(status == QDF_STATUS_SUCCESS); + + status = pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false); + QDF_BUG(status == QDF_STATUS_SUCCESS); + + QDF_BUG(!htc_runtime_resume(htc_ctx)); + + status = cdp_runtime_resume(dp_soc, txrx_pdev); + QDF_BUG(status == QDF_STATUS_SUCCESS); + + hif_process_runtime_resume_success(hif_ctx); + +dec_psoc_ref: + pmo_psoc_put_ref(psoc); + +out: + pmo_exit(); + + 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; + + pmo_enter(); + qdf_event_reset(&psoc_ctx->wow.target_resume); + + status = pmo_tgt_psoc_send_host_wakeup_ind(psoc); + if (status) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + pmo_debug("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)); + qdf_trigger_self_recovery(); + } else { + pmo_debug("Host wakeup received"); + } + + if (status == QDF_STATUS_SUCCESS) + pmo_tgt_update_target_suspend_flag(psoc, false); +out: + pmo_exit(); + + 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; + + pmo_enter(); + 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(psoc_ctx, false); + 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: + pmo_exit(); + + 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; + + pmo_enter(); + 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)); + qdf_trigger_self_recovery(); + } else { + pmo_debug("Host wakeup received"); + } + + if (status == QDF_STATUS_SUCCESS) + pmo_tgt_update_target_suspend_flag(psoc, false); +out: + pmo_exit(); + + 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; + + pmo_enter(); + 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; + } + + 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, false); + + if (wow_mode) + status = pmo_core_psoc_disable_wow_in_fw(psoc, psoc_ctx); + else + status = pmo_core_psoc_resume_target(psoc, psoc_ctx); + + pmo_psoc_put_ref(psoc); + +out: + pmo_exit(); + + return status; +} + +void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)context; + QDF_STATUS status; + + pmo_enter(); + 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); + qdf_event_set(&psoc_ctx->wow.target_suspend); + if (wow_nack && !pmo_tgt_psoc_get_runtime_pm_in_progress(psoc)) { + qdf_wake_lock_timeout_acquire(&psoc_ctx->wow.wow_wake_lock, + PMO_WAKE_LOCK_TIMEOUT); + } + + 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; + + pmo_enter(); + if (!psoc) { + pmo_err("psoc is null"); + goto out; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + psoc_ctx->wow.wow_state = pmo_wow_state_none; + qdf_event_set(&psoc_ctx->wow.target_resume); +out: + pmo_exit(); +} + +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, false); + + pmo_psoc_put_ref(psoc); +out: + pmo_exit(); + + 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; + QDF_STATUS status; + + pmo_enter(); + if (!psoc) { + pmo_err("cb ctx/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_update_wow_initial_wake_up(psoc_ctx, true); + + pmo_psoc_put_ref(psoc); + +out: + pmo_exit(); +} + +QDF_STATUS pmo_core_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t new_li) +{ + uint32_t listen_interval; + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_priv_obj *psoc_ctx; + uint8_t vdev_id; + + 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 : PMO_DEFAULT_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 (psoc_ctx->get_cfg_int && + (QDF_STATUS_SUCCESS != psoc_ctx->get_cfg_int( + PMO_CFG_LISTEN_INTERVAL, + &listen_interval))) { + pmo_err("Failed to get listen interval"); + } + } + } + + pmo_debug("Set Listen Interval %d for vdevId %d", listen_interval, + vdev_id); + 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: + pmo_vdev_put_ref(vdev); +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_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; + + /* 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"); + pmo_vdev_put_ref(vdev); + 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); + } + } + + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + return status; +} diff --git a/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_wow.c b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_wow.c new file mode 100644 index 0000000000000000000000000000000000000000..d3c5d362ac6821384cd34146d3d8da4a3d347682 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/core/src/wlan_pmo_wow.c @@ -0,0 +1,480 @@ +/* + * 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: 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" + +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; + + pmo_enter(); + 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 cofigured by pmo */ + for (id = 0; id < pattern_count; id++) + status = pmo_tgt_del_wow_pattern(vdev, id, false); + + /* clear all user patterns cofigured 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); + + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + 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 cofigured 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, ptrn->session_id); + /* + * 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); + + pmo_vdev_put_ref(vdev); +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: + pmo_vdev_put_ref(vdev); +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) +{ + QDF_STATUS status; + 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 = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + pmo_set_wow_event_bitmap(wow_event, PMO_WOW_MAX_EVENT_BM_LEN, bitmap); + + pmo_tgt_enable_wow_wakeup_event(vdev, bitmap); + + pmo_vdev_put_ref(vdev); + +out: + pmo_exit(); +} + +void pmo_core_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event) +{ + QDF_STATUS status; + 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 = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) { + pmo_err("vdev is NULL"); + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + pmo_set_wow_event_bitmap(wow_event, PMO_WOW_MAX_EVENT_BM_LEN, bitmap); + + pmo_tgt_disable_wow_wakeup_event(vdev, bitmap); + + pmo_vdev_put_ref(vdev); + +out: + pmo_exit(); +} + +/** + * 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; + QDF_STATUS status; + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) + continue; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + vdev_opmode = pmo_get_vdev_opmode(vdev); + is_beaconing = pmo_is_vdev_in_beaconning_mode(vdev_opmode) && + pmo_is_vdev_up(vdev); + + pmo_vdev_put_ref(vdev); + + 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; + QDF_STATUS status; + + 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 (pmo_core_is_nan_enabled(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 = pmo_psoc_get_vdev(psoc, vdev_id); + if (!vdev) + continue; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + if (wlan_vdev_is_up(vdev)) { + 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; + } + + pmo_vdev_put_ref(vdev); + + 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_MAGIC_PKT_RECVD_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); +} + +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); +} + +uint8_t pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + bool apf = false; + bool arp_ns = false; + bool pkt_filter = false; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + apf = pmo_intersect_apf(psoc_ctx); + arp_ns = pmo_intersect_arp_ns_offload(psoc_ctx); + pkt_filter = pmo_intersect_packet_filter(psoc_ctx); + } + + if (!apf && !pkt_filter) + return PMO_WOW_FILTERS_MAX; + + if (arp_ns) + return PMO_WOW_FILTERS_ARP_NS; + + return PMO_WOW_FILTERS_PKT_OR_APF; +} + diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..4a789213aada4aff837451ef5d60e8c3cef26479 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h @@ -0,0 +1,58 @@ +/* + * 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 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_req - 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 + */ +struct pmo_arp_offload_params { + uint8_t enable; + uint8_t host_ipv4_addr[PMO_IPV4_ADDR_LEN]; + struct qdf_mac_addr bssid; + bool is_offload_applied; +}; + +#endif /* end of _WLAN_PMO_ARP_PUBLIC_STRUCT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..0a4ee28e66199b33db42e54b009977393ed5ba9c --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h @@ -0,0 +1,344 @@ +/* + * 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 various struct, macros which are common for + * various pmo related features. + * + * Note: This file shall not contain public API's prototype/declartions. + * + */ + +#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 "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_peer_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_ADDR_LEN 4 + +#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_MAC_IPV6_ADDR_LEN 16 +#define PMO_IPV6_ADDR_VALID 1 +#define PMO_IPV6_ADDR_UC_TYPE 0 +#define PMO_IPV6_ADDR_AC_TYPE 1 + +#define PMO_80211_ADDR_LEN 6 /* size of 802.11 address */ + +#define PMO_WOW_REQUIRED_CREDITS 1 + +/** + * enum pmo_offload_type: tell offload type + * @pmo_arp_offload: arp offload + * @pmo_ns_offload: ns offload + * @pmo_gtk_offload: gtk offload + */ +enum pmo_offload_type { + pmo_arp_offload = 0, + pmo_ns_offload, + pmo_gtk_offload, +}; + +/** + * 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_max_param: Max vdev param id + */ +enum pmo_vdev_param_id { + pmo_vdev_param_listen_interval = 0, + pmo_vdev_param_dtim_policy, + 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 + * @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, +}; + +/** + * @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_qpower_pspoll_count: No of PS-Poll to send before + STA wakes up in QPower Mode. + * @pmo_sta_ps_enable_qpower: Enable QPower + * @pmo_sta_ps_param_qpower_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 + */ +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_qpower_pspoll_count = 5, + pmo_sta_ps_enable_qpower = 6, + pmo_sta_ps_param_qpower_max_tx_before_wake = 7, + pmo_sta_ps_param_ito_repeat_count = 8, +}; + +/** + * enum powersave_qpower_mode: QPOWER modes + * @pmo_qpower_disabled: Qpower is disabled + * @pmo_qpower_enabled: Qpower is enabled + * @pmo_qpower_duty_cycling: Qpower is enabled with duty cycling + */ +enum pmo_power_save_qpower_mode { + pmo_qpower_disabled = 0, + pmo_qpower_enabled = 1, + pmo_qpower_duty_cycling = 2 +}; + +/** + * enum powersave_qpower_mode: powersave_mode + * @pmo_ps_not_supported: Power save is not supported + * @pmo_ps_legacy_no_deep_sleep: Legacy pwr save enabled and deep sleep disabled + * @pmo_ps_qpower_no_deep_sleep: QPOWER enabled and deep sleep disabled + * @pmo_ps_legacy_deep_sleep: Legacy power save enabled and deep sleep enabled + * @pmo_ps_qpower_deep_sleep: QPOWER enabled and deep sleep enabled + * @pmo_ps_duty_cycling_qpower: QPOWER enabled in duty cycling mode + */ +enum pmo_powersave_mode { + pmo_ps_not_supported = 0, + pmo_ps_legacy_no_deep_sleep = 1, + pmo_ps_qpower_no_deep_sleep = 2, + pmo_ps_legacy_deep_sleep = 3, + pmo_ps_qpower_deep_sleep = 4, + pmo_ps_duty_cycling_qpower = 5 +}; + +/** + * enum 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 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 +}; + +#define PMO_TARGET_SUSPEND_TIMEOUT 6000 +#define PMO_WAKE_LOCK_TIMEOUT 1000 +#define PMO_RESUME_TIMEOUT 6000 + +/** + * 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 pmo_wow_enable_params { + bool is_unit_test; + enum pmo_wow_interface_pause interface_pause; + enum pmo_wow_resume_trigger resume_trigger; +}; + +/** + * typedef for psoc suspend handler + */ +typedef QDF_STATUS(*pmo_psoc_suspend_handler) + (struct wlan_objmgr_psoc *psoc, void *arg); +/** + * typedef for psoc resume handler + */ +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_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_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_offload_trigger_max, +}; + +/** + * enum pmo_auto_pwr_detect_failure_mode_t - 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 +}; + +/** + * 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 + * @bmiss_enable: true when wake up on bmiss is enabled else false + * @nan_enable: true when nan is enabled else false + * @lpass_enable: true when lpass is enabled else false + * @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 + * @power_save_mode: power save mode for psoc + * @auto_power_save_fail_mode: auto detect power save failure + * @wow_data_inactivity_timeout: power save wow data inactivity timeout + * @ps_data_inactivity_timeout: Power save data inactivity timeout for non + * wow mode + * @ito_repeat_count: Indicates ito repeated count + */ +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; + uint16_t ra_ratelimit_interval; + bool magic_ptrn_enable; + bool deauth_enable; + bool disassoc_enable; + bool bmiss_enable; + bool nan_enable; + bool lpass_enable; + uint8_t sta_dynamic_dtim; + uint8_t sta_mod_dtim; + uint8_t sta_max_li_mod_dtim; + uint8_t power_save_mode; + enum pmo_auto_pwr_detect_failure_mode auto_power_save_fail_mode; + uint8_t wow_data_inactivity_timeout; + uint8_t ps_data_inactivity_timeout; + uint8_t ito_repeat_count; +}; + +/** + * 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; +}; + +#endif /* end of _WLAN_PMO_COMMONP_STRUCT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gtk_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gtk_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..9112d466640e5f1727710008904871e42f47424c --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gtk_public_struct.h @@ -0,0 +1,100 @@ +/* + * 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 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_LEGACY 16 +#define PMO_KEK_LEN 64 +#define PMO_KCK_LEN 16 +#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 + * @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 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 + * @psoc: objmgr psoc + * @vdev_id: vdev id on which arp offload needed + * @status_flag: status flags + * @refresh_cnt: number of successful GTK refresh exchanges since SET operation + * @igtk_key_index: igtk key index + * @igtk_key_length: igtk key length + * @igtk_key_rsc: igtk key index + * @igtk_key: igtk key length + */ +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 for gtk response callback + */ +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 resposne 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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_hw_filter_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_hw_filter_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..8315bb0d207bc9808f4fee2d15ec7db41115055b --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_hw_filter_public_struct.h @@ -0,0 +1,56 @@ +/* + * 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: This file shall contain all public parameter (struct/macro/enum) + * definitions to support hardware filtering configuration. No APIs, or + * implememtations of APIs, shall be contained within. + */ + +#ifndef _WLAN_PMO_HW_FILTER_PUBLIC_STRUCT_H +#define _WLAN_PMO_HW_FILTER_PUBLIC_STRUCT_H + +/** + * pmo_hw_filter_mode - bitmap for enabled hardware filters + * @HW_FILTER_DISABLED: hardware filter is completely disabled + * @HW_FILTER_NON_ARP_BC: drop all broadcast frames, except ARP + * @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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_lphb_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_lphb_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..4cd0df3a85f8c95d49272368c56011d4c0d229f9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_lphb_public_struct.h @@ -0,0 +1,174 @@ +/* + * 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 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 + * @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 + */ +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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_mc_addr_filtering_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_mc_addr_filtering_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..6f922991d03f8e040b104d52925de96f350bcad4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_mc_addr_filtering_public_struct.h @@ -0,0 +1,71 @@ +/* + * 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: 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; + uint8_t 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 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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..7aa44d419fab6b0d05712eae99ad5a773344cf89 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h @@ -0,0 +1,99 @@ +/* + * 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 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 + */ +struct pmo_ns_offload_params { + uint8_t enable; + uint32_t num_ns_offload_count; + uint8_t src_ipv6_addr[PMO_MAC_IPV6_ADDR_LEN]; + uint8_t self_ipv6_addr[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] + [PMO_MAC_IPV6_ADDR_LEN]; + uint8_t target_ipv6_addr[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] + [PMO_MAC_IPV6_ADDR_LEN]; + 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 + */ +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] + [PMO_MAC_IPV6_ADDR_LEN]; + 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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b1255823cf6d6f3e1c1b32046e4907b7676601f4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h @@ -0,0 +1,460 @@ +/* + * 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 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) contex. + * + * 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 + * @psco: 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 + * + * 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); + +/** + * 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); + +/** + * pmo_register_get_cfg_int_callback(): API to register callback for getting + * cfg integer from mlme + * @psoc: objmgr psoc handle + * @handler: get cfg integer callback notifier + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_register_get_cfg_int_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_cfg_int handler); + +/** + * pmo_unregister_get_cfg_int_callback(): API to unregister callback that gets + * cfg integer from mlme + * @psoc: objmgr psoc handle + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_unregister_get_cfg_int_callback(struct wlan_objmgr_psoc *psoc); + +#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) +{ + 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_cfg_int_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_cfg_int handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_get_cfg_int_callback(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; +} + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_OBJ_MGMT_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..6cb2b1d25f83abb43f6bff88838fa680b6013d4f --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h @@ -0,0 +1,220 @@ +/* + * 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 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 for vdev notifying the vdev pause bitmap new value to mlme + */ +typedef void (*pmo_notify_pause_bitmap)(uint8_t vdev_id, uint16_t value); + +/** + * typedef for function that gets cfg integer from mlme + */ +typedef QDF_STATUS (*pmo_get_cfg_int)(int cfg_id, int *value); + +/** + * typedef for function that gets dtim period from mlme + */ +typedef QDF_STATUS (*pmo_get_dtim_period)(uint8_t vdev_id, uint8_t *value); + +/** + * typedef for function that gets beacon interval from mlme + */ +typedef QDF_STATUS (*pmo_get_beacon_interval)(uint8_t vdev_id, uint16_t *value); + +/** + * typedef for getting vdev pause bitmap + */ +typedef uint16_t(*pmo_get_pause_bitmap)(uint8_t vdev_id); + +/** + * typedef to know is deviec is in power save mode + */ +typedef bool (*pmo_is_device_in_low_pwr_mode)(uint8_t vdev_id); + +/* + * typedef for pld auto suspend callback during runtime suspend + */ +typedef int (*pmo_pld_auto_suspend_cb)(void); + +/* + * typedef for pld auto resume callback during runtime resume + */ +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_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_wakeup_event_req: fp to send enable wow wakeup events req + * @send_disable_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_set_sta_ps_param: fp to send sta vdev ps power set req + * @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 + * @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 + */ +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); + 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); + 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); + 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); + 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); + +}; + +#endif /* end of _WLAN_PMO_OBJ_MGMT_PUBLIC_STRUCT_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..6ed76bd4a2a10c19e358c00e59dc6088cc5e748e --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_public_struct.h @@ -0,0 +1,141 @@ +/* + * 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: 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 protocal 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_cfg - 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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..c265b9b3bf92e760d9f0cd8db5f0a0fc89d76b33 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h @@ -0,0 +1,437 @@ +/* + * 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: 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); + +/** + * 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); + +/** + * 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 + * @multicastAddr: 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 + * @multicastAddr: 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 + * @gtk_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); + +/** + * pmo_tgt_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_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_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: Pending WMI commands on success else EAGAIN on error + */ +void pmo_tgt_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * 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); + +#endif /* end of _WLAN_PMO_TGT_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..54774b88076a8a0dcd6d6a45f3377d4947f18698 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h @@ -0,0 +1,1170 @@ +/* + * 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 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_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_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_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); + +/** + * pmo_ucfg_enable_wakeup_event() - enable wow wakeup events + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @wow_event: wow event to enable + * + * Return: none + */ +void pmo_ucfg_enable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event); + +/** + * pmo_ucfg_disable_wakeup_event() - disable wow wakeup events + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @wow_event: wow event to disable + * + * Return: none + */ +void pmo_ucfg_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event); + +/** + * pmo_ucfg_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 pmo_ucfg_cache_arp_offload_req(struct pmo_arp_req *arp_req); + +/** + * pmo_ucfg_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 pmo_ucfg_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_ucfg_enable_arp_offload_in_fwr(): API to enable arp req in fwr + * @vdev: objmgr vdev param + * @trigger: triger 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 pmo_ucfg_enable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_ucfg_disable_arp_offload_in_fwr(): API to disable arp req in fwr + * @vdev: objmgr vdev param + * @trigger: triger 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 pmo_ucfg_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_ucfg_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_ucfg_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params); + +/** + * pmo_ucfg_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 pmo_ucfg_cache_ns_offload_req(struct pmo_ns_req *ns_req); + +/** + * pmo_ucfg_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 pmo_ucfg_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_ucfg_enable_ns_offload_in_fwr(): API to enable ns req in fwr + * @arp_req: pmo arp req param + * @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 pmo_ucfg_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_ucfg_disable_ns_offload_in_fwr(): API to disable ns req in fwr + * @arp_req: pmo arp req param + * @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 pmo_ucfg_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_ucfg_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_ucfg_get_ns_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ns_offload_params *params); + +/** + * pmo_ucfg_ns_addr_scope() - Convert linux specific IPv6 addr scope to + * WLAN driver specific value + * @scope: linux specific IPv6 addr scope + * + * Return: PMO identifier of linux IPv6 addr scope + */ +enum pmo_ns_addr_scope +pmo_ucfg_ns_addr_scope(uint32_t ipv6_scope); + +/** + * pmo_ucfg_enable_hw_filter_in_fwr() - enable previously configured hw filter + * @vdev: objmgr vdev to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_ucfg_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_ucfg_disable_hw_filter_in_fwr() - disable previously configured hw filter + * @vdev: objmgr vdev to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_ucfg_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_ucfg_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 pmo_ucfg_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_ucfg_cache_mc_addr_list(): API to cache mc addr list in pmo vdev priv obj + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @gtk_req: pmo gtk req param + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_ucfg_cache_mc_addr_list( + struct pmo_mc_addr_list_params *mc_list_config); + +/** + * pmo_ucfg_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_ucfg_flush_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * pmo_ucfg_enhance_mc_filter_enable() - enable enhanced multicast filtering + * @vdev: the vdev to enable enhanced multicast filtering for + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +pmo_ucfg_enhanced_mc_filter_enable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enhanced_mc_filter_enable(vdev); +} + +/** + * pmo_ucfg_enhance_mc_filter_disable() - disable enhanced multicast filtering + * @vdev: the vdev to disable enhanced multicast filtering for + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +pmo_ucfg_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enhanced_mc_filter_disable(vdev); +} + +/** + * pmo_ucfg_enable_mc_addr_filtering_in_fwr(): Enable cached mc add list in fwr + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @gtk_req: pmo gtk req param + * @action: true for enable els false + * + * API to enable cached mc add list in fwr + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_ucfg_enable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger); + +/** + * pmo_ucfg_disable_mc_addr_filtering_in_fwr(): Disable cached mc addr list + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @gtk_req: pmo gtk req param + * @action: true for enable els false + * + * API to disable cached mc add list in fwr + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_ucfg_disable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger); + +/** + * pmo_ucfg_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 +pmo_ucfg_get_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct pmo_mc_addr_list *mc_list_req); + +/** + * pmo_ucfg_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_ucfg_cache_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req); + +/** + * pmo_ucfg_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_ucfg_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_ucfg_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_ucfg_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_ucfg_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_ucfg_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_ucfg_set_pkt_filter() - Set packet filter + * @psoc: objmgr psoc handle + * @pmo_set_pkt_fltr_req: + * @vdev_id: vdev id + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_ucfg_set_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id); + +/** + * pmo_ucfg_clear_pkt_filter() - Clear packet filter + * @psoc: objmgr psoc handle + * @pmo_clr_pkt_fltr_req: + * @vdev_id: vdev id + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_ucfg_clear_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id); + +/** + * pmo_ucfg_get_gtk_rsp(): API to send gtk response request to fwr + * @vdev: objmgr vdev handle + * @gtk_rsp: 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_ucfg_get_gtk_rsp(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_rsp_req *gtk_rsp_req); + +/** + * pmo_ucfg_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 pmo_ucfg_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev, + bool value); + +/** + * pmo_ucfg_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 pmo_ucfg_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev, + bool value); + +/** + * pmo_ucfg_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 pmo_ucfg_lphb_config_req(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx, + pmo_lphb_callback callback); + +/** + * pmo_ucfg_psoc_update_power_save_mode() - update power save mode + * @vdev: objmgr vdev handle + * @value:vdev power save mode + * + * Return: None + */ +void pmo_ucfg_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * pmo_ucfg_psoc_update_dp_handle() - update psoc data path handle + * @psoc: objmgr psoc handle + * @dp_hdl: psoc data path handle + * + * Return: None + */ +void pmo_ucfg_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_hdl); + +/** + * pmo_ucfg_vdev_update_dp_handle() - update vdev data path handle + * @vdev: objmgr vdev handle + * @dp_hdl: vdev data path handle + * + * Return: None + */ +void pmo_ucfg_vdev_update_dp_handle(struct wlan_objmgr_vdev *vdev, + void *dp_hdl); + +/** + * pmo_ucfg_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 pmo_ucfg_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc, + void *htc_handle); + +/** + * pmo_ucfg_psoc_set_hif_handle() - Set psoc hif layer handle + * @psoc: objmgr psoc handle + * @hif_handle: hif context handle + * + * Return: None + */ +void pmo_ucfg_psoc_set_hif_handle(struct wlan_objmgr_psoc *psoc, + void *hif_handle); + +/** + * pmo_ucfg_psoc_set_txrx_handle() - Set psoc pdev txrx layer handle + * @psoc: objmgr psoc handle + * @txrx_handle: pdev txrx context handle + * + * Return: None + */ +void pmo_ucfg_psoc_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle); + +/** + * pmo_ucfg_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 pmo_ucfg_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * pmo_ucfg_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 pmo_ucfg_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * pmo_ucfg_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_ucfg_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_ucfg_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 pmo_ucfg_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb); + +/** + * pmo_ucfg_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 pmo_ucfg_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_resume_cb pld_cb); +#endif + +/** + * pmo_ucfg_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_ucfg_psoc_suspend_target(struct wlan_objmgr_psoc *psoc, + int disable_target_intr); + +QDF_STATUS pmo_ucfg_add_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn); + +/** + * 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 pmo_ucfg_del_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + uint8_t pattern_id); + +/** + * pmo_ucfg_psoc_bus_resume() -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_ucfg_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * pmo_ucfg_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 pmo_ucfg_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_ucfg_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 pmo_ucfg_psoc_handle_initial_wake_up(void *cb_ctx); + +/** + * pmo_ucfg_psoc_is_target_wake_up_received() - Get initial wake up status + * @psoc: objmgr psoc handle + * + * Return: 0 on success else error code + */ +int pmo_ucfg_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_ucfg_psoc_is_target_wake_up_received() - Clear initial wake up status + * @psoc: objmgr psoc handle + * + * Return: 0 on success else error code + */ +int pmo_ucfg_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_ucfg_psoc_target_suspend_acknowledge() - Clear initial wake up status + * @psoc: objmgr psoc handle + * + * Return: None + */ +void pmo_ucfg_psoc_target_suspend_acknowledge(void *context, bool wow_nack); + +/** + * pmo_ucfg_psoc_wakeup_host_event_received() - got host wake up evennt from fwr + * @psoc: objmgr psoc handle + * + * Return: None + */ +void pmo_ucfg_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_ucfg_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 pmo_ucfg_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t listen_interval); + +/** + * pmo_ucfg_config_modulated_dtim() - function to configure modulated dtim + * @vdev: objmgr vdev handle + * @param_value: New modulated dtim value passed by user + * + * This function configures the modulated dtim in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_ucfg_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim); +#else +static inline uint32_t +ucfg_pmo_get_apf_instruction_size(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 +pmo_ucfg_enable_wakeup_event( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint32_t *bitmap) +{ +} + +static inline void +pmo_ucfg_disable_wakeup_event( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint32_t bitmap) +{ +} + +static inline QDF_STATUS +pmo_ucfg_cache_arp_offload_req(struct pmo_arp_req *arp_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_enable_arp_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_disable_arp_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_cache_ns_offload_req(struct pmo_ns_req *ns_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_enable_ns_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_disable_ns_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_ns_addr_scope(uint32_t ipv6_scope) +{ + return PMO_NS_ADDR_SCOPE_INVALID; +} + +static inline QDF_STATUS +pmo_ucfg_cache_mc_addr_list( + struct pmo_mc_addr_list_params *mc_list_config) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_flush_mc_addr_list( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_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 +pmo_ucfg_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_cache_gtk_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_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 +pmo_ucfg_get_gtk_rsp( + struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_rsp_req *gtk_rsp_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +pmo_ucfg_update_extscan_in_progress( + struct wlan_objmgr_vdev *vdev, + bool value) +{ +} + +static inline void +pmo_ucfg_update_p2plo_in_progress( + struct wlan_objmgr_vdev *vdev, + bool value) +{ +} + +static inline QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_psoc_update_power_save_mode( + struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ +} + +static inline void +pmo_ucfg_psoc_update_dp_handle( + struct wlan_objmgr_psoc *psoc, + void *dp_handle) +{ +} + +static inline void +pmo_ucfg_vdev_update_dp_handle( + struct wlan_objmgr_vdev *vdev, + void *dp_handle) +{ +} + +static inline void +pmo_ucfg_psoc_update_htc_handle( + struct wlan_objmgr_psoc *psoc, + void *htc_handle) +{ +} + +static inline void +pmo_ucfg_psoc_set_hif_handle( + struct wlan_objmgr_psoc *psoc, + void *hif_handle) +{ +} + +static inline void +pmo_ucfg_psoc_set_txrx_handle( + struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ +} + +static inline void +pmo_ucfg_psoc_handle_initial_wake_up(void *cb_ctx) +{ +} + +static inline QDF_STATUS +pmo_ucfg_psoc_user_space_suspend_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_psoc_user_space_resume_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_psoc_bus_runtime_suspend( + struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_psoc_suspend_target( + struct wlan_objmgr_psoc *psoc, + int disable_target_intr) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_add_wow_user_pattern( + struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_del_wow_user_pattern( + struct wlan_objmgr_vdev *vdev, + uint8_t pattern_id) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_pmo_del_wow_pattern(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_psoc_bus_resume_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +pmo_ucfg_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline int +pmo_ucfg_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline int +pmo_ucfg_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline void +pmo_ucfg_psoc_target_suspend_acknowledge(void *context, bool wow_nack) +{ +} + +static inline void +pmo_ucfg_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS +pmo_ucfg_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_enhanced_mc_filter_enable(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t listen_interval) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_ucfg_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_UCFG_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..6e3bb0991dcfdce4f6e5f9426c9223ddbc777098 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h @@ -0,0 +1,283 @@ +/* + * 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 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_ + +#define PMO_WOW_FILTERS_MAX 22 + +#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_VHT 21 +#define PMO_MAC_ACTION_MAX 256 + +#define PMO_MAC_ACTION_MEASURE_REQUEST_ID 0 +#define PMO_MAC_ACTION_TPC_REQUEST_ID 2 +/* + * 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_VHT 21 1 + * ----------------------------+------+-------+ + */ +#define 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_VHT)) + +#define ALLOWED_ACTION_FRAMES_BITMAP1 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP2 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP3 0x0 +#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) + +/* 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 | + * ----------------------------------+-----+------+ + * SIR_MAC_ACTION_MEASURE_REQUEST_ID 0 1 + * SIR_MAC_ACTION_TPC_REQUEST_ID 2 1 + * ----------------------------------+-----+------+ + */ +#define DROP_SPEC_MGMT_ACTION_FRAME_BITMAP \ + ((1 << PMO_MAC_ACTION_MEASURE_REQUEST_ID) |\ + (1 << PMO_MAC_ACTION_TPC_REQUEST_ID)) +#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_opertion: 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_opertion { + 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 + * @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. + * @pmo_lphb_callback: 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 + * + * 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; + int wow_nack; + bool 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; +}; + +/* 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 + * @session_id: session id + */ +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]; + uint8_t session_id; +}; + +/** + * 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 + */ +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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c new file mode 100644 index 0000000000000000000000000000000000000000..cd0f7cf2f4b7b739ff3796db6f6fefb60b0974e0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c @@ -0,0 +1,907 @@ +/* + * 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: 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 == NULL) { + pmo_err("Failed to allocate pmo_psoc"); + 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; + } + /* 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; +} + +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 == NULL) { + pmo_err("Failed to allocate 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->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); + +out: + pmo_exit(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_vdev_ready(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + pmo_enter(); + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* Register static configuration with firmware */ + pmo_register_wow_wakeup_events(vdev); + pmo_register_action_frame_patterns(vdev); + + /* Register default wow patterns with firmware */ + pmo_register_wow_default_patterns(vdev); + + pmo_vdev_put_ref(vdev); + + pmo_exit(); + + /* + * 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; + + pmo_enter(); + + 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); + qdf_mem_free(vdev_ctx); + + pmo_exit(); + + 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_enter(); + + 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 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); + QDF_ASSERT(0); + 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: + pmo_exit(); + + 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_enter(); + + 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: + pmo_exit(); + + 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_cfg_int_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_cfg_int 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_cfg_int 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_cfg_int = handler; + } + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_unregister_get_cfg_int_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_cfg_int = 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; +} diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c new file mode 100644 index 0000000000000000000000000000000000000000..50734d91be960398590be3d403bac8fd76eccf32 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c @@ -0,0 +1,174 @@ +/* + * 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_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; + + 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) { + pmo_err("unable to allocate arp_offload_req"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + pmo_err("unable to allocate 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"); + 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); + pmo_exit(); + + 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) { + pmo_err("unable to allocate arp_offload_req"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + pmo_err("unable to allocate 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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_gtk.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_gtk.c new file mode 100644 index 0000000000000000000000000000000000000000..18132ea905f75c13505343a80c890d792fea35db --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_gtk.c @@ -0,0 +1,179 @@ +/* + * 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 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) { + pmo_err("cannot allocate 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, + PMO_KCK_LEN); + qdf_mem_copy(op_gtk_req->kek, gtk_req->kek, + PMO_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 = pmo_psoc_get_vdev(psoc, rsp_param->vdev_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; + } + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + 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: + pmo_vdev_put_ref(vdev); +out: + pmo_exit(); + + return status; +} + diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_hw_filter.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_hw_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..396d3074dfd1840e35ce822e25569e5166042daa --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_lphb.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_lphb.c new file mode 100644 index 0000000000000000000000000000000000000000..f363e5614a4c847f185b2ec14b338951bd9dbdf4 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.c new file mode 100644 index 0000000000000000000000000000000000000000..8fd98098202d2b46e68795d1f6064b6fcf97ef37 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.c @@ -0,0 +1,158 @@ +/* + * 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_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; + + pmo_enter(); + + 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; + + pmo_enter(); + + 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: + pmo_exit(); + + 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; + + pmo_enter(); + + 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: + pmo_exit(); + + return status; +} + + diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c new file mode 100644 index 0000000000000000000000000000000000000000..6d7b9cad5707cc7a91a372e07bf89c915f66c234 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c @@ -0,0 +1,174 @@ +/* + * 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 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; + + 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) { + pmo_err("unable to allocate arp_offload_req"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + pmo_err("unable to allocate 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"); + 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); + pmo_exit(); + + 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) { + pmo_err("unable to allocate arp_offload_req"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + pmo_err("unable to allocate 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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_pkt_filter.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_pkt_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..0ae1146b16908792b86387571829b2b348243647 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_pkt_filter.c @@ -0,0 +1,157 @@ +/* + * 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_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 == NULL) { + pmo_err("Not able to allocate memory for Receive Filter Set Filter request"); + 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 == NULL) { + pmo_err("Not able to allocate memory for Receive Filter Set Filter request"); + 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/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_static_config.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_static_config.c new file mode 100644 index 0000000000000000000000000000000000000000..99d1b97109d3382bedba7c0aee74a7c1f64ec8c8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_static_config.c @@ -0,0 +1,127 @@ +/* + * 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_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; + + pmo_enter(); + 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: + pmo_exit(); + + 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; + + pmo_enter(); + + 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: + pmo_exit(); + + return status; +} + diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c new file mode 100644 index 0000000000000000000000000000000000000000..c54a778a7a7fc1150e31cc1f35d7dfcbd0f3d02b --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c @@ -0,0 +1,239 @@ +/* + * 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_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; +} + +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; + + pmo_enter(); + + 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: + pmo_exit(); + + 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); +} + +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); +} + diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_wow.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_wow.c new file mode 100644 index 0000000000000000000000000000000000000000..d527be03f54ba3457e11c9e4d166cb3415fa6993 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_wow.c @@ -0,0 +1,167 @@ +/* + * 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_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; + + pmo_enter(); + + 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%x%x%x%x 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: + pmo_exit(); + + 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; + + pmo_enter(); + + 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: + pmo_exit(); + + 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; + + pmo_enter(); + 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: + pmo_exit(); + + 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; + + pmo_enter(); + 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); +out: + pmo_exit(); + + return status; +} + diff --git a/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..a8251e0e9adfda273561bdabf24f2e08c5441151 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c @@ -0,0 +1,450 @@ +/* + * 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: 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" + +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); +} + +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); +} + +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) +{ + return wlan_vdev_is_up(vdev); +} + +bool ucfg_pmo_is_vdev_supports_offload(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_is_vdev_supports_offload(vdev); +} + +void pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_cache_arp_offload_req(struct pmo_arp_req *arp_req) +{ + return pmo_core_cache_arp_offload_req(arp_req); +} + +QDF_STATUS pmo_ucfg_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_flush_arp_offload_req(vdev); +} + +QDF_STATUS pmo_ucfg_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 pmo_ucfg_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 +pmo_ucfg_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params) +{ + return pmo_core_get_arp_offload_params(vdev, params); +} + +QDF_STATUS pmo_ucfg_cache_ns_offload_req(struct pmo_ns_req *ns_req) +{ + return pmo_core_cache_ns_offload_req(ns_req); +} + +QDF_STATUS pmo_ucfg_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_flush_ns_offload_req(vdev); +} + +QDF_STATUS pmo_ucfg_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 pmo_ucfg_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); +} + +QDF_STATUS +pmo_ucfg_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 +pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_max_mc_addr_supported(psoc); +} + +QDF_STATUS +pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_flush_gtk_offload_req(vdev); +} + +QDF_STATUS pmo_ucfg_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enable_gtk_offload_in_fwr(vdev); +} + +QDF_STATUS pmo_ucfg_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_disable_gtk_offload_in_fwr(vdev); +} + +QDF_STATUS pmo_ucfg_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 pmo_ucfg_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); +} + +QDF_STATUS pmo_ucfg_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 pmo_ucfg_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev, + bool value) +{ + pmo_core_update_extscan_in_progress(vdev, value); +} + +void pmo_ucfg_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev, + bool value) +{ + pmo_core_update_p2plo_in_progress(vdev, value); +} + +QDF_STATUS pmo_ucfg_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 pmo_ucfg_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + pmo_core_psoc_update_power_save_mode(psoc, value); +} + +void pmo_ucfg_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_handle) +{ + pmo_core_psoc_update_dp_handle(psoc, dp_handle); +} + +void pmo_ucfg_vdev_update_dp_handle(struct wlan_objmgr_vdev *vdev, + void *dp_handle) +{ + pmo_core_vdev_update_dp_handle(vdev, dp_handle); +} + +void pmo_ucfg_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc, + void *htc_handle) +{ + pmo_core_psoc_update_htc_handle(psoc, htc_handle); +} + +void pmo_ucfg_psoc_set_hif_handle(struct wlan_objmgr_psoc *psoc, + void *hif_handle) +{ + pmo_core_psoc_set_hif_handle(psoc, hif_handle); +} + +void pmo_ucfg_psoc_set_txrx_handle(struct wlan_objmgr_psoc *psoc, + void *txrx_handle) +{ + pmo_core_psoc_set_txrx_handle(psoc, txrx_handle); +} + +void pmo_ucfg_psoc_handle_initial_wake_up(void *cb_ctx) +{ + return pmo_core_psoc_handle_initial_wake_up(cb_ctx); +} + +QDF_STATUS pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_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 pmo_ucfg_psoc_suspend_target(struct wlan_objmgr_psoc *psoc, + int disable_target_intr) +{ + return pmo_core_psoc_suspend_target(psoc, disable_target_intr); +} + +QDF_STATUS pmo_ucfg_add_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn) +{ + return pmo_core_add_wow_user_pattern(vdev, ptrn); +} + +QDF_STATUS +ucfg_pmo_del_wow_pattern(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_del_wow_pattern(vdev); +} + +QDF_STATUS pmo_ucfg_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 pmo_ucfg_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return pmo_core_psoc_bus_resume_req(psoc, type); +} + +bool pmo_ucfg_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_get_wow_bus_suspend(psoc); +} + +int pmo_ucfg_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_psoc_is_target_wake_up_received(psoc); +} + +int pmo_ucfg_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_psoc_clear_target_wake_up(psoc); +} + +void pmo_ucfg_psoc_target_suspend_acknowledge(void *context, bool wow_nack) +{ + pmo_core_psoc_target_suspend_acknowledge(context, wow_nack); +} + +void pmo_ucfg_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc) +{ + pmo_core_psoc_wakeup_host_event_received(psoc); +} + +QDF_STATUS pmo_ucfg_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enable_hw_filter_in_fwr(vdev); +} + +QDF_STATUS pmo_ucfg_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_disable_hw_filter_in_fwr(vdev); +} + +QDF_STATUS pmo_ucfg_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t listen_interval) +{ + return pmo_core_config_listen_interval(vdev, listen_interval); +} + +QDF_STATUS pmo_ucfg_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim) +{ + return pmo_core_config_modulated_dtim(vdev, mod_dtim); +} + diff --git a/drivers/staging/qcacld-3.0/components/target_if/action_oui/inc/target_if_action_oui.h b/drivers/staging/qcacld-3.0/components/target_if/action_oui/inc/target_if_action_oui.h new file mode 100644 index 0000000000000000000000000000000000000000..4bd65b7d0672da92152bb288b21311681c0054ff --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/action_oui/src/target_if_action_oui.c b/drivers/staging/qcacld-3.0/components/target_if/action_oui/src/target_if_action_oui.c new file mode 100644 index 0000000000000000000000000000000000000000..4893b633e16cfbd48c28a94aaca636b38c44beab --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/disa/inc/target_if_disa.h b/drivers/staging/qcacld-3.0/components/target_if/disa/inc/target_if_disa.h new file mode 100644 index 0000000000000000000000000000000000000000..c501b6cb6e7a9ac85fab7d94caab139f7f2b5d8a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/disa/inc/target_if_disa.h @@ -0,0 +1,80 @@ +/* + * 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 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_handler() - 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_register_ev_handler() - 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/drivers/staging/qcacld-3.0/components/target_if/disa/src/target_if_disa.c b/drivers/staging/qcacld-3.0/components/target_if/disa/src/target_if_disa.c new file mode 100644 index 0000000000000000000000000000000000000000..055497d677578e4dc4ddfbb5e96a291196b121ca --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/disa/src/target_if_disa.c @@ -0,0 +1,140 @@ +/* + * 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: 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 == NULL) { + target_if_err("%s: invalid pointer", __func__); + 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 (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/drivers/staging/qcacld-3.0/components/target_if/ipa/inc/target_if_ipa.h b/drivers/staging/qcacld-3.0/components/target_if/ipa/inc/target_if_ipa.h new file mode 100644 index 0000000000000000000000000000000000000000..3055bf0b4d2e4713a13ed7019c4f0a3f2c90f48c --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/ipa/inc/target_if_ipa.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: Declare various api/struct which shall be used + * by ipa component for wmi cmd (tx path) + */ + +#ifndef _TARGET_IF_IPA_H_ +#define _TARGET_IF_IPA_H_ + +#ifdef IPA_OFFLOAD + +#include "wlan_ipa_public_struct.h" + +/** + * target_if_ipa_register_tx_ops() - Register IPA component TX OPS + * @ipa_tx_op: IPA if transmit op + * + * Return: None + */ +void target_if_ipa_register_tx_ops(ipa_uc_offload_control_req *ipa_tx_op); + +#endif /* IPA_OFFLOAD */ +#endif /* _TARGET_IF_IPA_H_ */ + diff --git a/drivers/staging/qcacld-3.0/components/target_if/ipa/src/target_if_ipa.c b/drivers/staging/qcacld-3.0/components/target_if/ipa/src/target_if_ipa.c new file mode 100644 index 0000000000000000000000000000000000000000..bde980809f0f801927a03fd6b07a2fea137a680e --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/ipa/src/target_if_ipa.c @@ -0,0 +1,50 @@ +/* + * 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: Target interface file for disa component to + * Implement api's which shall be used by ipa component + * in target if internally. + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * target_if_ipa_uc_offload_control_req() - send IPA offload control to FW + * @psoc: pointer to PSOC object + * @req: IPA UC offload enable/disable control param + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_ipa_uc_offload_control_req(struct wlan_objmgr_psoc *psoc, + struct ipa_uc_offload_control_params *req) +{ + return wmi_unified_ipa_offload_control_cmd( + get_wmi_unified_hdl_from_psoc(psoc), req); +} + +void target_if_ipa_register_tx_ops(ipa_uc_offload_control_req *ipa_tx_op) +{ + *ipa_tx_op = target_if_ipa_uc_offload_control_req; +} diff --git a/drivers/staging/qcacld-3.0/components/target_if/ocb/inc/target_if_ocb.h b/drivers/staging/qcacld-3.0/components/target_if/ocb/inc/target_if_ocb.h new file mode 100644 index 0000000000000000000000000000000000000000..13f9afb9c85053ebcadecc31129da86531d01736 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/ocb/src/target_if_ocb.c b/drivers/staging/qcacld-3.0/components/target_if/ocb/src/target_if_ocb.c new file mode 100644 index 0000000000000000000000000000000000000000..e727a9b781feab2c468708b4074ad0a7948a238c --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/ocb/src/target_if_ocb.c @@ -0,0 +1,699 @@ +/* + * 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 + * + */ + +#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) { + target_if_err("Error allocating memory for the response."); + 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) +{ + int 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 (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 (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 (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 (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 (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) +{ + int rc; + + rc = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_stats_event_id); + if (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 (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 (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 (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 (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/drivers/staging/qcacld-3.0/components/target_if/pmo/inc/target_if_pmo.h b/drivers/staging/qcacld-3.0/components/target_if/pmo/inc/target_if_pmo.h new file mode 100644 index 0000000000000000000000000000000000000000..d5b772c21549daf707f50c121d655a0454b0e154 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/pmo/inc/target_if_pmo.h @@ -0,0 +1,462 @@ +/* + * 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: 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 + * @enable: enable/disable + * + * 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 + * @enable: enable/disable + * + * 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 + * @action: 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 + * @multicastAddr: 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 + * @multicastAddr: 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 + * @multicastAddr: mcast address + * + * 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 + * @multicastAddr: mcast address + * + * 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 + * @handle: Pointer to wma handle + * @vdev_id: VDEV ID + * + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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); + +/** + * 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: return wmi pending commands + */ +void target_if_pmo_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * 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_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); + +#endif + diff --git a/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_arp.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_arp.c new file mode 100644 index 0000000000000000000000000000000000000000..c8e4aefe4c904c2d225dd2a672280c021c8e3617 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_gtk.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_gtk.c new file mode 100644 index 0000000000000000000000000000000000000000..d279984e2de1bea5acbbbc9c5d17d250d8b5269a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_gtk.c @@ -0,0 +1,158 @@ +/* + * 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_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) { + target_if_err("memory allocation failed"); + 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/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_hw_filter.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_hw_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..d378f1cdc44f7f846a3eb5874420200b45c6ec59 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_lphb.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_lphb.c new file mode 100644 index 0000000000000000000000000000000000000000..c02d2641b99fb9fd6e9a8ec7fa055bc19292617a --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_lphb.c @@ -0,0 +1,334 @@ +/* + * 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_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) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + wmi_hb_set_enable_cmd_fixed_param hb_enable_fp; + wmi_unified_t wmi_handle; + + if (ts_lphb_enable == NULL) { + 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; + } + + status = wmi_unified_lphb_config_hbenable_cmd(wmi_handle, + &hb_enable_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + return QDF_STATUS_SUCCESS; +error: + + 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) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + wmi_hb_set_tcp_params_cmd_fixed_param hb_tcp_params_fp = {0}; + wmi_unified_t wmi_handle; + + if (ts_lphb_tcp_param == NULL) { + 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= %pM, 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, + 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; + } + + status = wmi_unified_lphb_config_tcp_params_cmd(wmi_handle, + &hb_tcp_params_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + 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) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param hb_tcp_filter_fp = {0}; + wmi_unified_t wmi_handle; + + if (ts_lphb_tcp_filter == NULL) { + 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; + } + + status = wmi_unified_lphb_config_tcp_pkt_filter_cmd(wmi_handle, + &hb_tcp_filter_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + 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) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + wmi_hb_set_udp_params_cmd_fixed_param hb_udp_params_fp = {0}; + wmi_unified_t wmi_handle; + + if (ts_lphb_udp_param == NULL) { + 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= %pM", + 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, + 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; + } + + status = wmi_unified_lphb_config_udp_params_cmd(wmi_handle, + &hb_udp_params_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +/** + * target_if_pmo_lphb_send_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) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + wmi_hb_set_udp_pkt_filter_cmd_fixed_param hb_udp_filter_fp = {0}; + wmi_unified_t wmi_handle; + + if (ts_lphb_udp_filter == NULL) { + 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((void *)&hb_udp_filter_fp.filter, + (void *)&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; + } + + status = wmi_unified_lphb_config_udp_pkt_filter_cmd(wmi_handle, + &hb_udp_filter_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +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) { + target_if_err("Invalid LPHB indication buffer"); + 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/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_main.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_main.c new file mode 100644 index 0000000000000000000000000000000000000000..834f88f68829c177357f434e06c5c502498e0162 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_main.c @@ -0,0 +1,112 @@ +/* + * 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: 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" + +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; + 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->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->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; + +} + diff --git a/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_mc_addr_filtering.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_mc_addr_filtering.c new file mode 100644 index 0000000000000000000000000000000000000000..8d0f768856cffac7996f4dc8fa94a4f61bbeabb3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_mc_addr_filtering.c @@ -0,0 +1,203 @@ +/* + * 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_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.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"); + 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"); + + 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.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"); + 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"); + + return status; +} + + diff --git a/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_ns.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_ns.c new file mode 100644 index 0000000000000000000000000000000000000000..0f23bb1905d7dac3cb26aee854feb9ab50c32053 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_pkt_filter.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_pkt_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..85725b936de2094e7a02cd8df61366ed771cf4a5 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_static_config.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_static_config.c new file mode 100644 index 0000000000000000000000000000000000000000..79d11386ab0bd63b1b4372695f9484c3d2fc950f --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_suspend_resume.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_suspend_resume.c new file mode 100644 index 0000000000000000000000000000000000000000..52f9720c373b654bde38e023a28bb63465bced2c --- /dev/null +++ b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_suspend_resume.c @@ -0,0 +1,333 @@ +/* + * 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: 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" + +#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; + 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.if_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); +} + +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_qpower: + param_id = WMI_STA_PS_ENABLE_QPOWER; + 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; + 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 = 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); +} + +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(SIR_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); +} + +QDF_STATUS target_if_pmo_psoc_send_host_wakeup_ind( + 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_host_wakeup_ind_to_fw_cmd(wmi_handle); +} + +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); +} + +#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 diff --git a/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_wow.c b/drivers/staging/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_wow.c new file mode 100644 index 0000000000000000000000000000000000000000..6c2481eeb8fc5409e70ec128a39af69e04328625 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/configs/default_defconfig b/drivers/staging/qcacld-3.0/configs/default_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..ea4b63bbbae8ead920f17225978acd9b922ac368 --- /dev/null +++ b/drivers/staging/qcacld-3.0/configs/default_defconfig @@ -0,0 +1,670 @@ +ifeq ($(CONFIG_CNSS_QCA6290), 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_IPA3 := n +endif + +ifeq ($(CONFIG_CLD_HL_SDIO_CORE), y) + CONFIG_QCA_WIFI_SDIO := y +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 + +# 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_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 +endif + +#Flag to enable Legacy Fast Roaming2(LFR2) +CONFIG_QCACLD_WLAN_LFR2 := y +#Flag to enable Legacy Fast Roaming3(LFR3) +ifneq ($(CONFIG_ARCH_SDX20), y) +CONFIG_QCACLD_WLAN_LFR3 := 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 + +#Flag to enable set coex configuration +ifeq ($(CONFIG_ARCH_QCS405), y) +CONFIG_QCACLD_FEATURE_COEX_CONFIG := y +endif + +#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_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 Protected Management Frames (11w) feature + CONFIG_WLAN_FEATURE_11W := y + #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 Protected Management Frames (11w) feature +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_WLAN_FEATURE_11W := y +endif +ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_WLAN_FEATURE_11W := y +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 + +ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable NAN Data path + CONFIG_WLAN_FEATURE_NAN_DATAPATH := y + CONFIG_NAN_CONVERGENCE := y +endif + +#Flag to enable Linux QCMBR feature as default feature +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_LINUX_QCMBR :=y +endif + +CONFIG_MPC_UT_FRAMEWORK := y + +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) +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 SAE + CONFIG_WLAN_FEATURE_SAE := 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 + 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 +endif + +ifeq ($(CONFIG_HIF_PCI), y) +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 + +# NOTE: CONFIG_64BIT_PADDR requires CONFIG_HELIUMPLUS +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_AR900B := 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) +CONFIG_SHADOW_V2 := y +CONFIG_QCA6290_HEADERS_DEF := y +CONFIG_QCA_WIFI_QCA6290 := 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 + + CONFIG_WLAN_MWS_INFO_DEBUGFS := y +endif + +# Feature flags which are not (currently) configurable via Kconfig + +#Whether to build debug version +BUILD_DEBUG_VERSION := y + +#Enable this flag to build driver in diag version +BUILD_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 + +#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 + CONFIG_PLD_USB_CNSS := y +endif + +#Enable SDIO specific APIS +ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_HIF_SDIO := y +endif + +#Enable pci read/write config functions +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_PCI := 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_QCA_IBSS_SUPPORT := 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 + +#Enable WDI Event support +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +CONFIG_WDI_EVENT_ENABLE := n +else +CONFIG_WDI_EVENT_ENABLE := 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 + +#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 := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := 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 + +ifeq ($(CONFIG_ARCH_SDMMAGPIE), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_LITO), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_ATOLL), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_TRINKET), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_SM6150), 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 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 DFS Master feature +CONFIG_WLAN_DFS_MASTER_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 + +CONFIG_WIFI_POS_CONVERGED := y +ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) +CONFIG_WIFI_POS_LEGACY := y +endif + +CONFIG_CP_STATS := 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 := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_MCL := y +CONFIG_MCL_REGDB := y +CONFIG_LEGACY_CHAN_ENUM := 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_CONVERGED_TDLS_ENABLE := 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 + +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_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_UNIT_TEST := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := 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 +#Enable Beacon Reception Stats +CONFIG_FEATURE_BECN_STATS := y + +#enable MPTA helper for QCS405 +ifeq ($(CONFIG_ARCH_QCS405), y) +CONFIG_QCACLD_FEATURE_MPTA_HELPER := y +endif diff --git a/drivers/staging/qcacld-3.0/configs/genoa.snoc.debug_defconfig b/drivers/staging/qcacld-3.0/configs/genoa.snoc.debug_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..76c0b6ad03c050fedb3a78a32f2848eaa1552ed3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/configs/genoa.snoc.debug_defconfig @@ -0,0 +1,179 @@ +# 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_WLAN_FEATURE_11W := y +CONFIG_QCOM_LTE_COEX := y +CONFIG_WLAN_FEATURE_LPSS := y +CONFIG_QCACLD_FEATURE_NAN := y +CONFIG_WLAN_FEATURE_NAN_DATAPATH := y +CONFIG_NAN_CONVERGENCE := y +CONFIG_POWER_MANAGEMENT_OFFLOAD := y +CONFIG_LFR_SUBNET_DETECTION := y +CONFIG_MCC_TO_SCC_SWITCH := y +CONFIG_QCOM_ESE := y +CONFIG_QCA_IBSS_SUPPORT := 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_LEGACY_CHAN_ENUM := 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_CONVERGED_TDLS_ENABLE := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := 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 := y +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 := y +CONFIG_DESC_DUP_DETECT_DEBUG := y +CONFIG_DEBUG_RX_RING_BUFFER := y +CONFIG_DP_TRACE := 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 +BUILD_DEBUG_VERSION := y +BUILD_DIAG_VERSION := y +CONFIG_FEATURE_TSO_DEBUG := y +CONFIG_MPC_UT_FRAMEWORK := y +CONFIG_FEATURE_EPPING := y +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_REMOVE_PKT_LOG := n +CONFIG_FEATURE_STATS_EXT := y +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y +CONFIG_TRACE_RECORD_FEATURE := y +CONFIG_WLAN_FEATURE_P2P_DEBUG := y +CONFIG_WLAN_NUD_TRACKING := y +CONFIG_CP_STATS := 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_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:= y +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +CONFIG_FEATURE_PKTLOG := y +CONFIG_WLAN_DEBUG_CRASH_INJECT := y +PANIC_ON_BUG := y +WLAN_WARN_ON_ASSERT := y +CONFIG_FEATURE_MEMDUMP_ENABLE := y +CONFIG_WLAN_LOGGING_SOCK_SVC := 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 +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 +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +CONFIG_FEATURE_WLAN_LPHB := y +endif +CONFIG_FEATURE_WLAN_EXTSCAN := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_MCL := y +CONFIG_MCL_REGDB := y +CONFIG_WLAN_OFFLOAD_PACKETS := y +CONFIG_WLAN_SYNC_TSF := y +CONFIG_WLAN_FEATURE_DISA := y +CONFIG_WLAN_FEATURE_FIPS := y +CONFIG_WLAN_FEATURE_SAE := y + +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +CONFIG_GTK_OFFLOAD := y +endif +CONFIG_QCACLD_FEATURE_APF := y + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +ifeq ($(CONFIG_ARCH_SDM845), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +################################### diff --git a/drivers/staging/qcacld-3.0/configs/genoa.snoc.perf_defconfig b/drivers/staging/qcacld-3.0/configs/genoa.snoc.perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..0ea581929288bab8759f8efb9f229a0bda1647d5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/configs/genoa.snoc.perf_defconfig @@ -0,0 +1,186 @@ +# Protocol specific features +CONFIG_QCACLD_WLAN_LFR2 := y +CONFIG_QCACLD_WLAN_LFR3 := n +CONFIG_QCOM_TDLS := y +CONFIG_QCACLD_FEATURE_GREEN_AP := y +CONFIG_QCOM_VOWIFI_11R := y +CONFIG_WLAN_FEATURE_FILS := y +CONFIG_WLAN_FEATURE_11W := y +CONFIG_QCOM_LTE_COEX := y +CONFIG_WLAN_FEATURE_LPSS := y +CONFIG_QCACLD_FEATURE_NAN := y +CONFIG_WLAN_FEATURE_NAN_DATAPATH := y +CONFIG_NAN_CONVERGENCE := y +CONFIG_POWER_MANAGEMENT_OFFLOAD := y +CONFIG_LFR_SUBNET_DETECTION := y +CONFIG_MCC_TO_SCC_SWITCH := y +CONFIG_QCOM_ESE := y +CONFIG_QCA_IBSS_SUPPORT := 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_LEGACY_CHAN_ENUM := y +CONFIG_NAPIER_SCAN := 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_CONVERGED_TDLS_ENABLE := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := 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 := y +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_DP_TRACE := 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 +BUILD_DEBUG_VERSION := y +BUILD_DIAG_VERSION := y +CONFIG_FEATURE_TSO_DEBUG := n +CONFIG_MPC_UT_FRAMEWORK := n +CONFIG_FEATURE_EPPING := n +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_REMOVE_PKT_LOG := n +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_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 := 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 := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_MCL := y +CONFIG_MCL_REGDB := y +CONFIG_WLAN_OFFLOAD_PACKETS := y +CONFIG_WLAN_SYNC_TSF := y +CONFIG_WLAN_FEATURE_DISA := y +CONFIG_WLAN_FEATURE_FIPS := y +CONFIG_WLAN_FEATURE_SAE := y +CONFIG_GTK_OFFLOAD := y + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +ifeq ($(CONFIG_ARCH_SDM845), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := 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 + + +################################### diff --git a/drivers/staging/qcacld-3.0/configs/qcs40x.snoc.perf_defconfig b/drivers/staging/qcacld-3.0/configs/qcs40x.snoc.perf_defconfig new file mode 100644 index 0000000000000000000000000000000000000000..6a7afb6382f5f557e95b91b51667478b6660efcd --- /dev/null +++ b/drivers/staging/qcacld-3.0/configs/qcs40x.snoc.perf_defconfig @@ -0,0 +1,187 @@ +# 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 := n +CONFIG_WLAN_FEATURE_11W := y +CONFIG_QCOM_LTE_COEX := n +CONFIG_WLAN_FEATURE_LPSS := n +CONFIG_QCACLD_FEATURE_NAN := n +CONFIG_WLAN_FEATURE_NAN_DATAPATH := n +CONFIG_NAN_CONVERGENCE := n +CONFIG_POWER_MANAGEMENT_OFFLOAD := y +CONFIG_LFR_SUBNET_DETECTION := y +CONFIG_MCC_TO_SCC_SWITCH := y +CONFIG_QCOM_ESE := y +CONFIG_QCA_IBSS_SUPPORT := n +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_LEGACY_CHAN_ENUM := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_SUPPORT_11AX := n +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_CONVERGED_TDLS_ENABLE := 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 + +# 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 +BUILD_DEBUG_VERSION := n +BUILD_DIAG_VERSION := y +CONFIG_FEATURE_TSO_DEBUG := y +CONFIG_MPC_UT_FRAMEWORK := n +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_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 := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_MCL := y +CONFIG_MCL_REGDB := 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 := y +CONFIG_WLAN_FEATURE_FIPS := y +CONFIG_WLAN_FEATURE_SAE := y +CONFIG_GTK_OFFLOAD := y +CONFIG_QCACLD_FEATURE_COEX_CONFIG := y +CONFIG_QCACLD_FEATURE_MPTA_HELPER := y + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := 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 + + +################################### diff --git a/drivers/staging/qcacld-3.0/core/bmi/inc/bmi.h b/drivers/staging/qcacld-3.0/core/bmi/inc/bmi.h new file mode 100644 index 0000000000000000000000000000000000000000..920cb5eb34aea820897f36a61ebb73b4a3584ca6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/inc/bmi.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +/* ================================================================ */ +/* 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; +QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx); +void ol_cds_free(void); + +/** + * struct hif_config_info - Place Holder for hif confiruation + * @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; +}; + +void ol_init_ini_config(struct ol_context *ol_ctx, + struct ol_config_info *cfg); +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); +#endif /* _BMI_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/inc/ol_fw.h b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_fw.h new file mode 100644 index 0000000000000000000000000000000000000000..407ac7799e50ef5ae5a05a57957ac1d61ed58425 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_fw.h @@ -0,0 +1,42 @@ +/* + * 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) + +void ol_target_failure(void *instance, QDF_STATUS status); + +void ol_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx); +QDF_STATUS ol_get_fw_files(struct ol_context *ol_ctx); +QDF_STATUS ol_extra_initialization(struct ol_context *ol_ctx); +#endif /* _OL_FW_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/inc/ol_if_athvar.h b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_if_athvar.h new file mode 100644 index 0000000000000000000000000000000000000000..0f8f03b205d2903a0e734cc3cd5f8aba06292b21 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_if_athvar.h @@ -0,0 +1,63 @@ +/* + * 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 +#include "qdf_types.h" +#include "qdf_lock.h" +#include "wmi_unified_api.h" +#include "htc_api.h" +#include "bmi_msg.h" +#include "ol_params.h" +#include + +#include "ol_ctrl_addba_api.h" + +struct ol_version { + uint32_t host_ver; + uint32_t target_ver; + uint32_t wlan_ver; + uint32_t wlan_ver_1; + uint32_t abi_ver; +}; + +enum ol_ath_tx_ecodes { + TX_IN_PKT_INCR = 0, + TX_OUT_HDR_COMPL, + TX_OUT_PKT_COMPL, + PKT_ENCAP_FAIL, + TX_PKT_BAD, + RX_RCV_MSG_RX_IND, + RX_RCV_MSG_PEER_MAP, + RX_RCV_MSG_TYPE_TEST +}; + +/* + * structure to hold the packet error count for CE and hif layer + */ +struct ol_ath_stats { + int hif_pipe_no_resrc_count; + int ce_ring_delta_fail_count; +}; + +#endif /* _DEV_OL_ATH_ATHVAR_H */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/bmi.c b/drivers/staging/qcacld-3.0/core/bmi/src/bmi.c new file mode 100644 index 0000000000000000000000000000000000000000..6c3d2fd24d54670a6d29daacc2cf34b17ddf7e2d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/bmi.c @@ -0,0 +1,575 @@ +/* + * 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. + */ + +#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 opperation + * @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; + + 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) { + remaining = remaining + (4 - (remaining & 0x3)); + memcpy(aligned_buf, src, remaining); + 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); + + 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; + + cds_free_context(QDF_MODULE_ID_BMI, ol_info); +} diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/bmi_1.c b/drivers/staging/qcacld-3.0/core/bmi/src/bmi_1.c new file mode 100644 index 0000000000000000000000000000000000000000..76f0c0edbf28fd3733b3c37aa3de2925d926ff92 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/bmi_1.c @@ -0,0 +1,332 @@ +/* + * 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. + */ + +#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("bmi_done_local 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/drivers/staging/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h b/drivers/staging/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h new file mode 100644 index 0000000000000000000000000000000000000000..4bdf553cfe4dc1f9dcf270f1bd35c6ebcb383d06 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h @@ -0,0 +1,872 @@ +/* + * 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. + */ + +#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 encouter 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 skiped 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 skiped 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 skiped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; +#endif +#endif /* #ifndef _AR6320V2_DBG_REGTABLE_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/i_bmi.h b/drivers/staging/qcacld-3.0/core/bmi/src/i_bmi.h new file mode 100644 index 0000000000000000000000000000000000000000..7dd5e999adfb7e8c107ece5e46726cc0540be64a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/i_bmi.h @@ -0,0 +1,211 @@ +/* + * 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. + */ + +/* =================================================================== + * Internal BMI Header File + */ + +#ifndef _I_BMI_H_ +#define _I_BMI_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 0x00005000 + +#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 + * @cal_in_flash: For Firmware Flash Download + * @qdf_dev: QDF Device + * @scn: HIF Context + * @ramdump_work: Work for Ramdump collection + * @fw_indication_work: Work for Fw inciation + * @tgt_def: Target Defnition pointer + * + * 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; + struct hif_opaque_softc *scn; + struct targetdef_t { + struct targetdef_s *targetdef; + } tgt_def; +}; + +#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(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/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw.c b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw.c new file mode 100644 index 0000000000000000000000000000000000000000..5e52f5efb309c5f9c5a721e4ee7f45e34ba8c80b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw.c @@ -0,0 +1,1897 @@ +/* + * Copyright (c) 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. + */ + +#include +#include "ol_if_athvar.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 formated 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 = EOK; + 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) { + BMI_ERR("%s: Memory allocation failed", __func__); + 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 != EOK) + 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 != EOK) { + 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 != EOK) + 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 != EOK) + BMI_ERR("%s, BMI operation failed: %d", __func__, __LINE__); + else + BMI_INFO("transferring file: %s size %d bytes done!", + (filename != NULL) ? 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) +{ + int ret; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + /* Wait until suspend and resume are completed before loading FW */ + pld_lock_pm_sem(qdf_dev->dev); + + ret = __ol_transfer_bin_file(ol_ctx, file, address, compressed); + + pld_release_pm_sem(qdf_dev->dev); + + 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 !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); +} +#else +static inline void ol_get_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) { + BMI_ERR("%s qdf_dev is NULL", __func__); + 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) { + BMI_ERR("%s Memory for Ramdump Allocation failed", __func__); + 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); + + qdf_mem_free(info); + return ret; +} + +void ramdump_work_handler(void *data) +{ +#ifdef WLAN_DEBUG + int ret; +#endif + 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); + + 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); + + 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__); + + /* + * 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); + return; + +out_fail: + /* 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); +} + +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); +} + +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; + 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 suppor this code path!"); + return; + } + + qdf_event_set(&wma->recovery_event); + + if (TARGET_STATUS_RESET == target_status) { + BMI_ERR("Target is already asserted, ignore!"); + return; + } + + 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); + return; + } + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + BMI_ERR("%s: Recovery in progress, ignore!\n", __func__); + return; + } + + if (cds_is_load_or_unload_in_progress()) { + BMI_ERR("%s: Loading/Unloading is in progress, ignore!", + __func__); + return; + } + 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); + return; + } + } else if (-1 == ret) { + return; + } + + 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__); +} + +#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; + 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; + } + OS_DELAY(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 == EOK) { + /* 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 == EOK) { + 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) != EOK) { + 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) == EOK) { + 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) != EOK) { + 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)) != EOK) { + 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; + 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 + * @sc: 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)); +} diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw_common.c b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw_common.c new file mode 100644 index 0000000000000000000000000000000000000000..b3805e1d0d0f3587fa990dc277c8937c0822005e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw_common.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 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. + */ + +#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 +#if defined(CONFIG_CNSS) +#include +#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_MBOX_BLOCK_SIZE, + blocksizes, sizeof(blocksizes)); + if (status != EOK) { + 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 != EOK) { + 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 != EOK) { + 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 != EOK) { + 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/drivers/staging/qcacld-3.0/core/cds/inc/cds_api.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_api.h new file mode 100644 index 0000000000000000000000000000000000000000..08ed54650966ff68cec4adcbf1f22abfa349c181 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_api.h @@ -0,0 +1,600 @@ +/* + * Copyright (c) 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. + */ + +#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 "reg_services_public_struct.h" +#include +#include +#include +#include +#include +#include +#include + +/* 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_MODULE_STOPPING: Module stop 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_STOPPING = BIT(6), +}; + +#define __CDS_IS_DRIVER_STATE(_state, _mask) (((_state) & (_mask)) == (_mask)) + +/** + * enum cds_fw_state - Firmware state + * @CDS_FW_STATE_UNINITIALIZED: Firmware is in uninitialized state. + */ +enum cds_fw_state { + CDS_FW_STATE_UNINITIALIZED = 0, +}; + +#define __CDS_IS_FW_STATE(_state, _mask) (((_state) & (_mask)) == (_mask)) + +/** + * struct cds_sme_cbacks - list of sme functions registered with + * CDS + * @sme_get_valid_channels: gets the valid channel list for current reg domain + * @sme_get_nss_for_vdev: gets the nss allowed for the vdev type + */ +struct cds_sme_cbacks { + QDF_STATUS (*sme_get_valid_channels)(void*, uint8_t *, uint32_t *); + void (*sme_get_nss_for_vdev)(void*, enum QDF_OPMODE, + uint8_t *, uint8_t *); +}; + +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_set_fw_state() - Set current firmware state + * @state: Firmware state to be set to. + * + * This API sets firmware state to state. This API only sets the state and + * doesn't clear states, please make sure to use cds_clear_firmware_state + * to clear any state if required. + * + * Return: None + */ +void cds_set_fw_state(enum cds_fw_state); + +/** + * cds_clear_fw_state() - Clear current fw state + * @state: Driver state to be cleared. + * + * This API clears fw state. This API only clears the state, please make + * sure to use cds_set_fw_state to set any new states. + * + * Return: None + */ +void cds_clear_fw_state(enum cds_fw_state); + +/** + * cds_get_fw_state() - Get current firmware state + * + * This API returns current firmware state stored in global context. + * + * Return: Firmware state enum + */ +enum cds_fw_state cds_get_fw_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_module_stop_in_progress() - Is module stopping + * + * Return: true if module stop is in progress. + */ +static inline bool cds_is_module_stop_in_progress(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_MODULE_STOPPING); +} + +/** + * 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_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_module_stop_in_progress() - Setting module stop in progress + * + * @value: value to set + * + * Return: none + */ +static inline void cds_set_module_stop_in_progress(bool value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_MODULE_STOPPING); + else + cds_clear_driver_state(CDS_DRIVER_STATE_MODULE_STOPPING); +} + +/** + * 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_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); + +void *cds_get_context(QDF_MODULE_ID module_id); + +uint8_t cds_get_datapath_handles(void **soc, struct cdp_pdev **pdev, + struct cdp_vdev **vdev, uint8_t sessionId); +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); + +QDF_STATUS cds_get_vdev_types(enum QDF_OPMODE mode, uint32_t *type, + uint32_t *subType); + +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 + +uint64_t cds_get_monotonic_boottime(void); + +/** + * 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(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 +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 + * + * 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; +} + +/** + * cds_get_arp_stats_gw_ip() - get arp stats track IP + * @context: osif dev + * + * Return: ARP stats IP to track. + */ +uint32_t cds_get_arp_stats_gw_ip(void *context); +/** + * cds_get_connectivity_stats_pkt_bitmap() - get pkt-type bitmap + * @context: osif dev context + * + * Return: pkt bitmap to track + */ +uint32_t cds_get_connectivity_stats_pkt_bitmap(void *context); +void cds_incr_arp_stats_tx_tgt_delivered(void); +void cds_incr_arp_stats_tx_tgt_acked(void); + +/** + * 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); +#endif /* if !defined __CDS_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_config.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_config.h new file mode 100644 index 0000000000000000000000000000000000000000..f9c2cd9e2b244b685b209f5ee0c9d5d9750cf355 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_config.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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_pmo_common_public_struct.h" + +/** + * enum cfg_sub_20_channel_width: ini values for su 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, +}; + +/** + * 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 +}; + +/** + * struct cds_config_info - Place Holder for cds configuration + * @max_station: Max station supported + * @max_bssid: Max Bssid Supported + * @powersave_offload_enabled: Indicate if powersave offload is enabled + * @sta_maxlimod_dtim: station max listen interval + * @sta_mod_dtim: station mode DTIM + * @sta_dynamic_dtim: station dynamic DTIM + * @driver_type: Enumeration of Driver Type whether FTM or Mission mode + * @wow_enable: Indicate whether wow is enabled or not + * currently rest of bits are not used + * @ssdp: Indicate ssdp is enabled or not + * @enable_mc_list : To Check if Multicast list filtering is enabled in FW + * @dfs_phyerr_filter_offload: DFS Phyerror Filtering offload status from ini + * 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 + * @ra_ratelimit_interval: RA rate limit value + * @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 + * @uc_txbuf_count: IPA Micro controller data path offload TX buffer count + * @uc_txbuf_size: IPA Micro controller data path offload TX buffer size + * @uc_rxind_ringcount: IPA Micro controller data path offload RX indication + * ring count + * @uc_tx_partition_base: IPA Micro controller datapath offload TX partition + * base + * @enable_rxthread: Rx processing in thread from TXRX + * @ip_tcp_udp_checksum_offload: checksum offload enabled or not + * @ce_classify_enabled: CE based classification enabled + * @max_scan: Maximum number of parallel scans + * @tx_flow_stop_queue_th: Threshold to stop queue in percentage + * @tx_flow_start_queue_offset: Start queue offset in percentage + * @is_lpass_enabled: Indicate whether LPASS is enabled or not + * @is_nan_enabled: Indicate whether NAN is enabled or not + * @bool apf_packet_filter_enable; Indicate apf filter enabled or not + * @tx_chain_mask_cck: Tx chain mask enabled or not + * @self_gen_frm_pwr: Self gen from power + * @sub_20_channel_width: Sub 20 MHz ch width, ini intersected with fw cap + * @flow_steering_enabled: Receive flow steering. + * @is_fw_timeout: Indicate whether crash host when fw timesout or not + * @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 + * @auto_power_save_fail_mode: auto detect power save failure mode + * @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 + * @delay_before_vdev_stop: wait time for tx complete before vdev stop + * Structure for holding cds ini parameters. + */ + +struct cds_config_info { + uint16_t max_station; + uint16_t max_bssid; + uint8_t powersave_offload_enabled; + uint8_t sta_maxlimod_dtim; + uint8_t sta_mod_dtim; + uint8_t sta_dynamic_dtim; + enum qdf_driver_type driver_type; + uint8_t wow_enable; + bool ssdp; + bool enable_mc_list; + uint8_t dfs_phyerr_filter_offload; + uint8_t ap_disable_intrabss_fwd; + uint8_t ap_maxoffload_peers; + uint8_t ap_maxoffload_reorderbuffs; +#ifdef FEATURE_WLAN_RA_FILTERING + uint16_t ra_ratelimit_interval; + bool is_ra_ratelimit_enabled; +#endif + uint8_t reorder_offload; + int32_t dfs_pri_multiplier; + uint8_t uc_offload_enabled; + uint32_t uc_txbuf_count; + uint32_t uc_txbuf_size; + uint32_t uc_rxind_ringcount; + uint32_t uc_tx_partition_base; + bool enable_rxthread; + bool ip_tcp_udp_checksum_offload; + bool ce_classify_enabled; + uint8_t max_scan; +#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 +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif +#ifdef WLAN_FEATURE_NAN + bool is_nan_enabled; +#endif + bool apf_packet_filter_enable; + bool tx_chain_mask_cck; + uint16_t self_gen_frm_pwr; + enum cfg_sub_20_channel_width sub_20_channel_width; + bool flow_steering_enabled; + uint8_t max_msdus_per_rxinorderind; + bool self_recovery_enabled; + bool fw_timeout_crash; + struct ol_tx_sched_wrr_ac_specs_t ac_specs[TX_WMM_AC_NUM]; + enum active_apf_mode active_uc_apf_mode; + enum active_apf_mode active_mc_bc_apf_mode; + enum pmo_auto_pwr_detect_failure_mode auto_power_save_fail_mode; + uint8_t ito_repeat_count; + bool force_target_assert_enabled; + uint8_t bandcapability; + bool rps_enabled; + uint8_t delay_before_vdev_stop; + bool enable_peer_unmap_conf_support; + bool enable_tx_compl_tsf64; + bool enable_three_way_coex_config_legacy; +}; + +#ifdef WLAN_FEATURE_FILS_SK +#define MAX_PMK_LEN 48 +#define MAX_PMKID_LEN 16 +#define FILS_MAX_KEYNAME_NAI_LENGTH 253 +#define FILS_MAX_REALM_LEN 255 +#define FILS_MAX_RRK_LENGTH 64 +#define FILS_MAX_RIK_LENGTH FILS_MAX_RRK_LENGTH + +struct cds_fils_connection_info { + bool is_fils_connection; + uint8_t keyname_nai[FILS_MAX_KEYNAME_NAI_LENGTH]; + uint32_t key_nai_length; + uint16_t sequence_number; + uint8_t r_rk[FILS_MAX_RRK_LENGTH]; + uint32_t r_rk_length; + uint8_t realm[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[16]; +}; +#endif +#endif /* !defined( __CDS_CONFIG_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_crypto.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_crypto.h new file mode 100644 index 0000000000000000000000000000000000000000..0d507be22bb43bd41dbf3104f601a45de7f836b4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_crypto.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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. + */ + +#if !defined(__CDS_CRYPTO_H) +#define __CDS_CRYPTO_H + +/** + * DOC: cds_crypto.h + * + * Crypto APIs + * + */ + +#include + +static inline struct crypto_cipher * +cds_crypto_alloc_cipher(const char *alg_name, u32 type, u32 mask) +{ + return crypto_alloc_cipher(alg_name, type, mask); +} + +static inline void cds_crypto_free_cipher(struct crypto_cipher *tfm) +{ + crypto_free_cipher(tfm); +} + +#endif /* if !defined __CDS_CRYPTO_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h new file mode 100644 index 0000000000000000000000000000000000000000..aa2312665b5b6c232e8b5d54be18e7dda45d5ce1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h @@ -0,0 +1,2051 @@ +/* + * 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. + */ + +#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_ + +/* + * 802.11 protocol definitions. + */ + +#define IEEE80211_IS_IPV4_MULTICAST(_a) (*(_a) == 0x01) + +#define IEEE80211_IS_IPV6_MULTICAST(_a) \ + ((_a)[0] == 0x33 && \ + (_a)[1] == 0x33) + +#define IEEE80211_IS_BROADCAST(_a) \ + ((_a)[0] == 0xff && \ + (_a)[1] == 0xff && \ + (_a)[2] == 0xff && \ + (_a)[3] == 0xff && \ + (_a)[4] == 0xff && \ + (_a)[5] == 0xff) + +/* IEEE 802.11 PLCP header */ +struct ieee80211_plcp_hdr { + uint16_t i_sfd; + uint8_t i_signal; + uint8_t i_service; + uint16_t i_length; + uint16_t i_crc; +} __packed; + +#define IEEE80211_PLCP_SFD 0xF3A0 +#define IEEE80211_PLCP_SERVICE 0x00 + +/* + * 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[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + }; + uint8_t i_addr_all[3 * IEEE80211_ADDR_LEN]; + }; + uint8_t i_seq[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; + +struct ieee80211_qosframe { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_qos[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __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[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; +} __packed; + +struct ieee80211_qosframe_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; + 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[IEEE80211_ADDR_LEN]; + +} __packed; /* For TxBF RC */ + +struct ieee80211_qosframe_htc { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_qos[2]; + uint8_t i_htc[4]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; +struct ieee80211_qosframe_htc_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; + uint8_t i_qos[2]; + uint8_t i_htc[4]; +} __packed; +struct ieee80211_htc { + uint8_t i_htc[4]; +}; +/*HTC frame for TxBF*/ + +struct ieee80211_ctlframe_addr2 { + uint8_t i_fc[2]; + uint8_t i_aidordur[2]; /* AID or duration */ + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; +} __packed; + +#define IEEE80211_WHQ(wh) ((struct ieee80211_qosframe *)(wh)) +#define IEEE80211_WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) +#define IEEE80211_WHQ4(wh) ((struct ieee80211_qosframe_addr4 *)(wh)) + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#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 +/* for TYPE_MGT */ +#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 +#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 +#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 +#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 +#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 +#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 +#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 +#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 +#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 +#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 +#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 +#define IEEE80211_FCO_SUBTYPE_ACTION_NO_ACK 0xe0 +/* for TYPE_CTL */ +#define IEEE80211_FCO_SUBTYPE_Control_Wrapper 0x70 /* For TxBF RC */ +#define IEEE80211_FC0_SUBTYPE_BAR 0x80 +#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 +#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 +#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 +#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 +#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 +/* for TYPE_DATA (bit combination) */ +#define IEEE80211_FC0_SUBTYPE_DATA 0x00 +#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 +#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 +#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 +#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 +#define IEEE80211_FC0_SUBTYPE_CFACK 0x50 +#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60 +#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 +#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0 + +#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_WEP 0x40 +#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_SEQ_LEQ(a, b) ((int)((a) - (b)) <= 0) + +#define IEEE80211_QOS_TXOP 0x00ff + +#define IEEE80211_QOS_AMSDU 0x80 +#define IEEE80211_QOS_AMSDU_S 7 +#define IEEE80211_QOS_ACKPOLICY 0x60 +#define IEEE80211_QOS_ACKPOLICY_S 5 +#define IEEE80211_QOS_EOSP 0x10 +#define IEEE80211_QOS_EOSP_S 4 +#define IEEE80211_QOS_TID 0x0f +#define IEEE80211_MFP_TID 0xff + +#define IEEE80211_HTC0_TRQ 0x02 +#define IEEE80211_HTC2_CalPos 0x03 +#define IEEE80211_HTC2_CalSeq 0x0C +#define IEEE80211_HTC2_CSI_NONCOMP_BF 0x80 +#define IEEE80211_HTC2_CSI_COMP_BF 0xc0 + +/* Set bits 14 and 15 to 1 when duration field carries Association ID */ +#define IEEE80211_FIELD_TYPE_AID 0xC000 + +#define IEEE80211_IS_BEACON(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_BEACON)) +#define IEEE80211_IS_DATA(_frame) (((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) + +#define IEEE80211_IS_MFP_FRAME(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + ((_frame)->i_fc[1] & IEEE80211_FC1_WEP) && \ + ((((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_DEAUTH) || \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_DISASSOC) || \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_ACTION))) +#define IEEE80211_IS_AUTH(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_AUTH)) + +/* MCS Set */ +#define IEEE80211_RX_MCS_1_STREAM_BYTE_OFFSET 0 +#define IEEE80211_RX_MCS_2_STREAM_BYTE_OFFSET 1 +#define IEEE80211_RX_MCS_3_STREAM_BYTE_OFFSET 2 +#define IEEE80211_RX_MCS_ALL_NSTREAM_RATES 0xff +#define IEEE80211_TX_MCS_OFFSET 12 + +#define IEEE80211_TX_MCS_SET_DEFINED 0x80 +#define IEEE80211_TX_RX_MCS_SET_NOT_EQUAL 0x40 +#define IEEE80211_TX_1_SPATIAL_STREAMS 0x0 +#define IEEE80211_TX_2_SPATIAL_STREAMS 0x10 +#define IEEE80211_TX_3_SPATIAL_STREAMS 0x20 +#define IEEE80211_TX_4_SPATIAL_STREAMS 0x30 + +#define IEEE80211_TX_MCS_SET 0xf8 + +/* + * Subtype data: If bit 6 is set then the data frame contains no actual data. + */ +#define IEEE80211_FC0_SUBTYPE_NO_DATA_MASK 0x40 +#define IEEE80211_CONTAIN_DATA(_subtype) \ + (!((_subtype) & IEEE80211_FC0_SUBTYPE_NO_DATA_MASK)) + +#define IEEE8023_MAX_LEN 0x600 /* 1536 - larger is Ethernet II */ +#define RFC1042_SNAP_ORGCODE_0 0x00 +#define RFC1042_SNAP_ORGCODE_1 0x00 +#define RFC1042_SNAP_ORGCODE_2 0x00 + +#define BTEP_SNAP_ORGCODE_0 0x00 +#define BTEP_SNAP_ORGCODE_1 0x00 +#define BTEP_SNAP_ORGCODE_2 0xf8 + +/* BT 3.0 */ +#define BTAMP_SNAP_ORGCODE_0 0x00 +#define BTAMP_SNAP_ORGCODE_1 0x19 +#define BTAMP_SNAP_ORGCODE_2 0x58 + +/* Aironet OUI Codes */ +#define AIRONET_SNAP_CODE_0 0x00 +#define AIRONET_SNAP_CODE_1 0x40 +#define AIRONET_SNAP_CODE_2 0x96 + +#define IEEE80211_LSIG_LEN 3 +#define IEEE80211_HTSIG_LEN 6 +#define IEEE80211_SB_LEN 2 + +/* + * Information element header format + */ +struct ieee80211_ie_header { + uint8_t element_id; /* Element Id */ + uint8_t length; /* IE Length */ +} __packed; + +/* + * Country information element. + */ +#define IEEE80211_COUNTRY_MAX_TRIPLETS (83) +struct ieee80211_ie_country { + uint8_t country_id; + uint8_t country_len; + uint8_t country_str[3]; + uint8_t country_triplet[IEEE80211_COUNTRY_MAX_TRIPLETS * 3]; +} __packed; + +/* does frame have QoS sequence control data */ +#define IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +#define WME_QOSINFO_UAPSD 0x80 /* Mask for U-APSD field */ +#define WME_QOSINFO_COUNT 0x0f /* Mask for Param Set Count field */ +/* + * WME/802.11e information element. + */ +struct ieee80211_ie_wme { + uint8_t wme_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t wme_len; /* length in bytes */ + uint8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t wme_type; /* OUI type */ + uint8_t wme_subtype; /* OUI subtype */ + uint8_t wme_version; /* spec revision */ + uint8_t wme_info; /* QoS info */ +} __packed; + +/* + * TS INFO part of the tspec element is a collection of bit flags + */ +#if _BYTE_ORDER == _BIG_ENDIAN +struct ieee80211_tsinfo_bitmap { + uint8_t one : 1, direction : 2, tid : 4, reserved1 : 1; + uint8_t reserved2 : 2, dot1Dtag : 3, psb : 1, reserved3 : 1, zero : 1; + uint8_t reserved5 : 7, reserved4 : 1; +} __packed; +#else +struct ieee80211_tsinfo_bitmap { + uint8_t reserved1 : 1, tid : 4, direction : 2, one : 1; + uint8_t zero : 1, reserved3 : 1, psb : 1, dot1Dtag : 3, reserved2 : 2; + uint8_t reserved4 : 1, reserved5 : 7; +} __packed; +#endif + +/* + * WME/802.11e Tspec Element + */ +struct ieee80211_wme_tspec { + uint8_t ts_id; + uint8_t ts_len; + uint8_t ts_oui[3]; + uint8_t ts_oui_type; + uint8_t ts_oui_subtype; + uint8_t ts_version; + uint8_t ts_tsinfo[3]; + uint8_t ts_nom_msdu[2]; + uint8_t ts_max_msdu[2]; + uint8_t ts_min_svc[4]; + uint8_t ts_max_svc[4]; + uint8_t ts_inactv_intv[4]; + uint8_t ts_susp_intv[4]; + uint8_t ts_start_svc[4]; + uint8_t ts_min_rate[4]; + uint8_t ts_mean_rate[4]; + uint8_t ts_peak_rate[4]; + uint8_t ts_max_burst[4]; + uint8_t ts_delay[4]; + uint8_t ts_min_phy[4]; + uint8_t ts_surplus[2]; + uint8_t ts_medium_time[2]; +} __packed; + +/* + * WME AC parameter field + */ +struct ieee80211_wme_acparams { + uint8_t acp_aci_aifsn; + uint8_t acp_logcwminmax; + uint16_t acp_txop; +} __packed; + +#define IEEE80211_WME_PARAM_LEN 24 +#define WME_NUM_AC 4 /* 4 AC categories */ + +#define WME_PARAM_ACI 0x60 /* Mask for ACI field */ +#define WME_PARAM_ACI_S 5 /* Shift for ACI field */ +#define WME_PARAM_ACM 0x10 /* Mask for ACM bit */ +#define WME_PARAM_ACM_S 4 /* Shift for ACM bit */ +#define WME_PARAM_AIFSN 0x0f /* Mask for aifsn field */ +#define WME_PARAM_AIFSN_S 0 /* Shift for aifsn field */ +#define WME_PARAM_LOGCWMIN 0x0f /* Mask for CwMin field (in log) */ +#define WME_PARAM_LOGCWMIN_S 0 /* Shift for CwMin field */ +#define WME_PARAM_LOGCWMAX 0xf0 /* Mask for CwMax field (in log) */ +#define WME_PARAM_LOGCWMAX_S 4 /* Shift for CwMax field */ + +#define WME_AC_TO_TID(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define TID_TO_WME_AC(_tid) ( \ + (((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ + WME_AC_VO) + +/* + * WME Parameter Element + */ +struct ieee80211_wme_param { + uint8_t param_id; + uint8_t param_len; + uint8_t param_oui[3]; + uint8_t param_oui_type; + uint8_t param_oui_sybtype; + uint8_t param_version; + uint8_t param_qosInfo; + uint8_t param_reserved; + struct ieee80211_wme_acparams params_acParams[WME_NUM_AC]; +} __packed; + +/* + * WME U-APSD qos info field defines + */ +#define WME_CAPINFO_UAPSD_EN 0x00000080 +#define WME_CAPINFO_UAPSD_VO 0x00000001 +#define WME_CAPINFO_UAPSD_VI 0x00000002 +#define WME_CAPINFO_UAPSD_BK 0x00000004 +#define WME_CAPINFO_UAPSD_BE 0x00000008 +#define WME_CAPINFO_UAPSD_ACFLAGS_SHIFT 0 +#define WME_CAPINFO_UAPSD_ACFLAGS_MASK 0xF +#define WME_CAPINFO_UAPSD_MAXSP_SHIFT 5 +#define WME_CAPINFO_UAPSD_MAXSP_MASK 0x3 +#define WME_CAPINFO_IE_OFFSET 8 +#define WME_UAPSD_MAXSP(_qosinfo) (((_qosinfo) >> WME_CAPINFO_UAPSD_MAXSP_SHIFT) & WME_CAPINFO_UAPSD_MAXSP_MASK) +#define WME_UAPSD_AC_ENABLED(_ac, _qosinfo) ((1 << (3 - (_ac))) & \ + (((_qosinfo) >> WME_CAPINFO_UAPSD_ACFLAGS_SHIFT) & WME_CAPINFO_UAPSD_ACFLAGS_MASK)) + +/* Mask used to determined whether all queues are UAPSD-enabled */ +#define WME_CAPINFO_UAPSD_ALL (WME_CAPINFO_UAPSD_VO | \ + WME_CAPINFO_UAPSD_VI | \ + WME_CAPINFO_UAPSD_BK | \ + WME_CAPINFO_UAPSD_BE) +#define WME_CAPINFO_UAPSD_NONE 0 + +#define WME_UAPSD_AC_MAX_VAL 1 +#define WME_UAPSD_AC_INVAL (WME_UAPSD_AC_MAX_VAL + 1) + +/* + * Atheros Advanced Capability information element. + */ +struct ieee80211_ie_athAdvCap { + uint8_t athAdvCap_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t athAdvCap_len; /* length in bytes */ + uint8_t athAdvCap_oui[3]; /* 0x00, 0x03, 0x7f */ + uint8_t athAdvCap_type; /* OUI type */ + uint16_t athAdvCap_version; /* spec revision */ + uint8_t athAdvCap_capability; /* Capability info */ + uint16_t athAdvCap_defKeyIndex; +} __packed; + +/* + * Atheros Extended Capability information element. + */ +struct ieee80211_ie_ath_extcap { + uint8_t ath_extcap_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t ath_extcap_len; /* length in bytes */ + uint8_t ath_extcap_oui[3]; /* 0x00, 0x03, 0x7f */ + uint8_t ath_extcap_type; /* OUI type */ + uint8_t ath_extcap_subtype; /* OUI subtype */ + uint8_t ath_extcap_version; /* spec revision */ + uint32_t ath_extcap_extcap : 16, /* B0-15 extended capabilities */ + ath_extcap_weptkipaggr_rxdelim : 8, /* B16-23 num delimiters for receiving WEP/TKIP aggregates */ + ath_extcap_reserved : 8; /* B24-31 reserved */ +} __packed; + +/* + * Atheros XR information element. + */ +struct ieee80211_xr_param { + uint8_t param_id; + uint8_t param_len; + uint8_t param_oui[3]; + uint8_t param_oui_type; + uint8_t param_oui_sybtype; + uint8_t param_version; + uint8_t param_Info; + uint8_t param_base_bssid[IEEE80211_ADDR_LEN]; + uint8_t param_xr_bssid[IEEE80211_ADDR_LEN]; + uint16_t param_xr_beacon_interval; + uint8_t param_base_ath_capability; + uint8_t param_xr_ath_capability; +} __packed; + +/* + * SFA information element. + */ +struct ieee80211_ie_sfa { + uint8_t sfa_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t sfa_len; /* length in bytes */ + uint8_t sfa_oui[3]; /* 0x00, 0x40, 0x96 */ + uint8_t sfa_type; /* OUI type */ + uint8_t sfa_caps; /* Capabilities */ +} __packed; + +/* Atheros capabilities */ +#define IEEE80211_ATHC_TURBOP 0x0001 /* Turbo Prime */ +#define IEEE80211_ATHC_COMP 0x0002 /* Compression */ +#define IEEE80211_ATHC_FF 0x0004 /* Fast Frames */ +#define IEEE80211_ATHC_XR 0x0008 /* Xtended Range support */ +#define IEEE80211_ATHC_AR 0x0010 /* Advanced Radar support */ +#define IEEE80211_ATHC_BURST 0x0020 /* Bursting - not negotiated */ +#define IEEE80211_ATHC_WME 0x0040 /* CWMin tuning */ +#define IEEE80211_ATHC_BOOST 0x0080 /* Boost */ +#define IEEE80211_ATHC_TDLS 0x0100 /* TDLS */ + +/* Atheros extended capabilities */ +/* OWL device capable of WDS workaround */ +#define IEEE80211_ATHEC_OWLWDSWAR 0x0001 +#define IEEE80211_ATHEC_WEPTKIPAGGR 0x0002 +#define IEEE80211_ATHEC_EXTRADELIMWAR 0x0004 +/* + * Management Frames + */ + +/* + * *** Platform-specific code?? *** + * In Vista one must use bit fields of type (unsigned short = uint16_t) to + * ensure data structure is of the correct size. ANSI C used to specify only + * "int" bit fields, which led to a larger structure size in Windows (32 bits). + * + * We must make sure the following construction is valid in all OS's. + */ +union ieee80211_capability { + struct { + uint16_t ess : 1; + uint16_t ibss : 1; + uint16_t cf_pollable : 1; + uint16_t cf_poll_request : 1; + uint16_t privacy : 1; + uint16_t short_preamble : 1; + uint16_t pbcc : 1; + uint16_t channel_agility : 1; + uint16_t spectrum_management : 1; + uint16_t qos : 1; + uint16_t short_slot_time : 1; + uint16_t apsd : 1; + uint16_t reserved2 : 1; + uint16_t dsss_ofdm : 1; + uint16_t del_block_ack : 1; + uint16_t immed_block_ack : 1; + }; + + uint16_t value; +} __packed; + +struct ieee80211_beacon_frame { + uint8_t timestamp[8]; /* the value of sender's TSFTIMER */ + uint16_t beacon_interval; /* the number of time units between target beacon transmission times */ + union ieee80211_capability capability; +/* Value of capability for every bit + #define IEEE80211_CAPINFO_ESS 0x0001 + #define IEEE80211_CAPINFO_IBSS 0x0002 + #define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 + #define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 + #define IEEE80211_CAPINFO_PRIVACY 0x0010 + #define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 + #define IEEE80211_CAPINFO_PBCC 0x0040 + #define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 + #define IEEE80211_CAPINFO_SPECTRUM_MGMT 0x0100 + #define IEEE80211_CAPINFO_QOS 0x0200 + #define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 + #define IEEE80211_CAPINFO_APSD 0x0800 + #define IEEE80211_CAPINFO_RADIOMEAS 0x1000 + #define IEEE80211_CAPINFO_DSSSOFDM 0x2000 + bits 14-15 are reserved + */ + struct ieee80211_ie_header info_elements; +} __packed; + +/* + * Management Action Frames + */ + +/* generic frame format */ +struct ieee80211_action { + uint8_t ia_category; + uint8_t ia_action; +} __packed; + +/* spectrum action frame header */ +struct ieee80211_action_measrep_header { + struct ieee80211_action action_header; + uint8_t dialog_token; +} __packed; + +/* categories */ +#define IEEE80211_ACTION_CAT_SPECTRUM 0 /* Spectrum management */ +#define IEEE80211_ACTION_CAT_QOS 1 /* IEEE QoS */ +#define IEEE80211_ACTION_CAT_DLS 2 /* DLS */ +#define IEEE80211_ACTION_CAT_BA 3 /* BA */ +#define IEEE80211_ACTION_CAT_PUBLIC 4 /* Public Action Frame */ +#define IEEE80211_ACTION_CAT_HT 7 /* HT per IEEE802.11n-D1.06 */ +#define IEEE80211_ACTION_CAT_SA_QUERY 8 /* SA Query per IEEE802.11w, PMF */ +#define IEEE80211_ACTION_CAT_WMM_QOS 17 /* QoS from WMM specification */ +#define IEEE80211_ACTION_CAT_VHT 21 /* VHT Action */ + +/* Spectrum Management actions */ +#define IEEE80211_ACTION_MEAS_REQUEST 0 /* Measure channels */ +#define IEEE80211_ACTION_MEAS_REPORT 1 +#define IEEE80211_ACTION_TPC_REQUEST 2 /* Transmit Power control */ +#define IEEE80211_ACTION_TPC_REPORT 3 +#define IEEE80211_ACTION_CHAN_SWITCH 4 /* 802.11h Channel Switch Announcement */ + +/* HT actions */ +#define IEEE80211_ACTION_HT_TXCHWIDTH 0 /* recommended transmission channel width */ +#define IEEE80211_ACTION_HT_SMPOWERSAVE 1 /* Spatial Multiplexing (SM) Power Save */ +#define IEEE80211_ACTION_HT_CSI 4 /* CSI Frame */ +#define IEEE80211_ACTION_HT_NONCOMP_BF 5 /* Non-compressed Beamforming */ +#define IEEE80211_ACTION_HT_COMP_BF 6 /* Compressed Beamforming */ + +/* VHT actions */ +#define IEEE80211_ACTION_VHT_OPMODE 2 /* Operating mode notification */ + +/* Spectrum channel switch action frame after IE*/ +/* Public Actions*/ +#define IEEE80211_ACTION_TDLS_DISCRESP 14 /* TDLS Discovery Response frame */ + +/* HT - recommended transmission channel width */ +struct ieee80211_action_ht_txchwidth { + struct ieee80211_action at_header; + uint8_t at_chwidth; +} __packed; + +#define IEEE80211_A_HT_TXCHWIDTH_20 0 +#define IEEE80211_A_HT_TXCHWIDTH_2040 1 + +/* HT - Spatial Multiplexing (SM) Power Save */ +struct ieee80211_action_ht_smpowersave { + struct ieee80211_action as_header; + uint8_t as_control; +} __packed; + +/*HT - CSI Frame */ /* for TxBF RC */ +#define MIMO_CONTROL_LEN 6 +struct ieee80211_action_ht_CSI { + struct ieee80211_action as_header; + uint8_t mimo_control[MIMO_CONTROL_LEN]; +} __packed; + +/*HT - V/CV report frame*/ +struct ieee80211_action_ht_txbf_rpt { + struct ieee80211_action as_header; + uint8_t mimo_control[MIMO_CONTROL_LEN]; +} __packed; + +/* + * 802.11ac Operating Mode Notification + */ +struct ieee80211_ie_op_mode { +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t rx_nss_type : 1, rx_nss : 3, reserved : 2, ch_width : 2; +#else + uint8_t ch_width : 2, reserved : 2, rx_nss : 3, rx_nss_type : 1; +#endif +} __packed; + +struct ieee80211_ie_op_mode_ntfy { + uint8_t elem_id; + uint8_t elem_len; + struct ieee80211_ie_op_mode opmode; +} __packed; + +/* VHT - recommended Channel width and Nss */ +struct ieee80211_action_vht_opmode { + struct ieee80211_action at_header; + struct ieee80211_ie_op_mode at_op_mode; +} __packed; + +/* values defined for 'as_control' field per 802.11n-D1.06 */ +#define IEEE80211_A_HT_SMPOWERSAVE_DISABLED 0x00 /* SM Power Save Disabled, SM packets ok */ +#define IEEE80211_A_HT_SMPOWERSAVE_ENABLED 0x01 /* SM Power Save Enabled bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_MODE 0x02 /* SM Power Save Mode bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_RESERVED 0xFC /* SM Power Save Reserved bits */ + +/* values defined for SM Power Save Mode bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_STATIC 0x00 /* Static, SM packets not ok */ +#define IEEE80211_A_HT_SMPOWERSAVE_DYNAMIC 0x02 /* Dynamic, SM packets ok if preceded by RTS */ + +/* DLS actions */ +#define IEEE80211_ACTION_DLS_REQUEST 0 +#define IEEE80211_ACTION_DLS_RESPONSE 1 +#define IEEE80211_ACTION_DLS_TEARDOWN 2 + +struct ieee80211_dls_request { + struct ieee80211_action hdr; + uint8_t dst_addr[IEEE80211_ADDR_LEN]; + uint8_t src_addr[IEEE80211_ADDR_LEN]; + uint16_t capa_info; + uint16_t timeout; +} __packed; + +struct ieee80211_dls_response { + struct ieee80211_action hdr; + uint16_t statuscode; + uint8_t dst_addr[IEEE80211_ADDR_LEN]; + uint8_t src_addr[IEEE80211_ADDR_LEN]; +} __packed; + +/* BA - ADDBA request */ +struct ieee80211_action_ba_addbarequest { + struct ieee80211_action rq_header; + uint8_t rq_dialogtoken; + struct ieee80211_ba_parameterset rq_baparamset; + uint16_t rq_batimeout; /* in TUs */ + struct ieee80211_ba_seqctrl rq_basequencectrl; +} __packed; + +/* BA - ADDBA response */ +struct ieee80211_action_ba_addbaresponse { + struct ieee80211_action rs_header; + uint8_t rs_dialogtoken; + uint16_t rs_statuscode; + struct ieee80211_ba_parameterset rs_baparamset; + uint16_t rs_batimeout; /* in TUs */ +} __packed; + +/* BA - DELBA */ +struct ieee80211_action_ba_delba { + struct ieee80211_action dl_header; + struct ieee80211_delba_parameterset dl_delbaparamset; + uint16_t dl_reasoncode; +} __packed; + +/* MGT Notif actions */ +#define IEEE80211_WMM_QOS_ACTION_SETUP_REQ 0 +#define IEEE80211_WMM_QOS_ACTION_SETUP_RESP 1 +#define IEEE80211_WMM_QOS_ACTION_TEARDOWN 2 + +#define IEEE80211_WMM_QOS_DIALOG_TEARDOWN 0 +#define IEEE80211_WMM_QOS_DIALOG_SETUP 1 + +#define IEEE80211_WMM_QOS_TSID_DATA_TSPEC 6 +#define IEEE80211_WMM_QOS_TSID_SIG_TSPEC 7 + +struct ieee80211_action_wmm_qos { + struct ieee80211_action ts_header; + uint8_t ts_dialogtoken; + uint8_t ts_statuscode; + struct ieee80211_wme_tspec ts_tspecie; +} __packed; + +/* + * Control frames. + */ +struct ieee80211_frame_min { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +/* + * BAR frame format + */ +#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ +#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ +#define IEEE80211_BAR_CTL_NOACK 0x0001 /* no-ack policy */ +#define IEEE80211_BAR_CTL_COMBA 0x0004 /* compressed block-ack */ + +/* + * SA Query Action mgmt Frame + */ +struct ieee80211_action_sa_query { + struct ieee80211_action sa_header; + uint16_t sa_transId; +}; + +typedef enum ieee80211_action_sa_query_type { + IEEE80211_ACTION_SA_QUERY_REQUEST, + IEEE80211_ACTION_SA_QUERY_RESPONSE +} ieee80211_action_sa_query_type_t; + +struct ieee80211_frame_bar { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + uint16_t i_ctl; + uint16_t i_seq; + /* FCS */ +} __packed; + +struct ieee80211_frame_rts { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_cts { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_ack { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_pspoll { + uint8_t i_fc[2]; + uint8_t i_aid[2]; + uint8_t i_bssid[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */ + uint8_t i_fc[2]; + uint8_t i_dur[2]; /* should be zero */ + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_bssid[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +/* + * BEACON management packets + * + * octet timestamp[8] + * octet beacon interval[2] + * octet capability information[2] + * information element + * octet elemid + * octet length + * octet information[length] + */ + +typedef uint8_t *ieee80211_mgt_beacon_t; + +#define IEEE80211_BEACON_INTERVAL(beacon) \ + ((beacon)[8] | ((beacon)[9] << 8)) +#define IEEE80211_BEACON_CAPABILITY(beacon) \ + ((beacon)[10] | ((beacon)[11] << 8)) + +#define IEEE80211_CAPINFO_ESS 0x0001 +#define IEEE80211_CAPINFO_IBSS 0x0002 +#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 +#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 +#define IEEE80211_CAPINFO_PRIVACY 0x0010 +#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 +#define IEEE80211_CAPINFO_PBCC 0x0040 +#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 +#define IEEE80211_CAPINFO_SPECTRUM_MGMT 0x0100 +#define IEEE80211_CAPINFO_QOS 0x0200 +#define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 +#define IEEE80211_CAPINFO_APSD 0x0800 +#define IEEE80211_CAPINFO_RADIOMEAS 0x1000 +#define IEEE80211_CAPINFO_DSSSOFDM 0x2000 +/* bits 14-15 are reserved */ + +/* + * 802.11i/WPA information element (maximally sized). + */ +struct ieee80211_ie_wpa { + uint8_t wpa_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t wpa_len; /* length in bytes */ + uint8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t wpa_type; /* OUI type */ + uint16_t wpa_version; /* spec revision */ + uint32_t wpa_mcipher[1]; /* multicast/group key cipher */ + uint16_t wpa_uciphercnt; /* # pairwise key ciphers */ + uint32_t wpa_uciphers[8]; /* ciphers */ + uint16_t wpa_authselcnt; /* authentication selector cnt */ + uint32_t wpa_authsels[8]; /* selectors */ + uint16_t wpa_caps; /* 802.11i capabilities */ + uint16_t wpa_pmkidcnt; /* 802.11i pmkid count */ + uint16_t wpa_pmkids[8]; /* 802.11i pmkids */ +} __packed; + +#ifndef _BYTE_ORDER +#error "Don't know native byte order" +#endif + +#ifndef IEEE80211N_IE +/* Temporary vendor specific IE for 11n pre-standard interoperability */ +#define VENDOR_HT_OUI 0x00904c +#define VENDOR_HT_CAP_ID 51 +#define VENDOR_HT_INFO_ID 52 +#endif + +#ifdef ATH_SUPPORT_TxBF +union ieee80211_hc_txbf { + struct { +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t reserved : 3, + channel_estimation_cap : 2, + csi_max_rows_bfer : 2, + comp_bfer_antennas : 2, + noncomp_bfer_antennas : 2, + csi_bfer_antennas : 2, + minimal_grouping : 2, + explicit_comp_bf : 2, + explicit_noncomp_bf : 2, + explicit_csi_feedback : 2, + explicit_comp_steering : 1, + explicit_noncomp_steering : 1, + explicit_csi_txbf_capable : 1, + calibration : 2, + implicit_txbf_capable : 1, + tx_ndp_capable : 1, + rx_ndp_capable : 1, + tx_staggered_sounding : 1, + rx_staggered_sounding : 1, implicit_rx_capable : 1; +#else + uint32_t implicit_rx_capable : 1, + rx_staggered_sounding : 1, + tx_staggered_sounding : 1, + rx_ndp_capable : 1, + tx_ndp_capable : 1, + implicit_txbf_capable : 1, + calibration : 2, + explicit_csi_txbf_capable : 1, + explicit_noncomp_steering : 1, + explicit_comp_steering : 1, + explicit_csi_feedback : 2, + explicit_noncomp_bf : 2, + explicit_comp_bf : 2, + minimal_grouping : 2, + csi_bfer_antennas : 2, + noncomp_bfer_antennas : 2, + comp_bfer_antennas : 2, + csi_max_rows_bfer : 2, channel_estimation_cap : 2, reserved : 3; +#endif + }; + + uint32_t value; +} __packed; +#endif + +struct ieee80211_ie_htcap_cmn { + uint16_t hc_cap; /* HT capabilities */ +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t hc_reserved : 3, /* B5-7 reserved */ + hc_mpdudensity : 3, /* B2-4 MPDU density (aka Minimum MPDU Start Spacing) */ + hc_maxampdu : 2; /* B0-1 maximum rx A-MPDU factor */ +#else + uint8_t hc_maxampdu : 2, /* B0-1 maximum rx A-MPDU factor */ + hc_mpdudensity : 3, /* B2-4 MPDU density (aka Minimum MPDU Start Spacing) */ + hc_reserved : 3; /* B5-7 reserved */ +#endif + uint8_t hc_mcsset[16]; /* supported MCS set */ + uint16_t hc_extcap; /* extended HT capabilities */ +#ifdef ATH_SUPPORT_TxBF + union ieee80211_hc_txbf hc_txbf; /* txbf capabilities */ +#else + uint32_t hc_txbf; /* txbf capabilities */ +#endif + uint8_t hc_antenna; /* antenna capabilities */ +} __packed; + +/* + * 802.11n HT Capability IE + */ +struct ieee80211_ie_htcap { + uint8_t hc_id; /* element ID */ + uint8_t hc_len; /* length in bytes */ + struct ieee80211_ie_htcap_cmn hc_ie; +} __packed; + +/* + * Temporary vendor private HT Capability IE + */ +struct vendor_ie_htcap { + uint8_t hc_id; /* element ID */ + uint8_t hc_len; /* length in bytes */ + uint8_t hc_oui[3]; + uint8_t hc_ouitype; + struct ieee80211_ie_htcap_cmn hc_ie; +} __packed; + +/* HT capability flags */ +#define IEEE80211_HTCAP_C_ADVCODING 0x0001 +#define IEEE80211_HTCAP_C_CHWIDTH40 0x0002 +#define IEEE80211_HTCAP_C_SMPOWERSAVE_STATIC 0x0000 /* Capable of SM Power Save (Static) */ +#define IEEE80211_HTCAP_C_SMPOWERSAVE_DYNAMIC 0x0004 /* Capable of SM Power Save (Dynamic) */ +#define IEEE80211_HTCAP_C_SM_RESERVED 0x0008 /* Reserved */ +#define IEEE80211_HTCAP_C_SM_ENABLED 0x000c /* SM enabled, no SM Power Save */ +#define IEEE80211_HTCAP_C_GREENFIELD 0x0010 +#define IEEE80211_HTCAP_C_SHORTGI20 0x0020 +#define IEEE80211_HTCAP_C_SHORTGI40 0x0040 +#define IEEE80211_HTCAP_C_TXSTBC 0x0080 +#define IEEE80211_HTCAP_C_TXSTBC_S 7 +#define IEEE80211_HTCAP_C_RXSTBC 0x0300 /* 2 bits */ +#define IEEE80211_HTCAP_C_RXSTBC_S 8 +#define IEEE80211_HTCAP_C_DELAYEDBLKACK 0x0400 +#define IEEE80211_HTCAP_C_MAXAMSDUSIZE 0x0800 /* 1 = 8K, 0 = 3839B */ +#define IEEE80211_HTCAP_C_DSSSCCK40 0x1000 +#define IEEE80211_HTCAP_C_PSMP 0x2000 +#define IEEE80211_HTCAP_C_INTOLERANT40 0x4000 +#define IEEE80211_HTCAP_C_LSIGTXOPPROT 0x8000 + +#define IEEE80211_HTCAP_C_SM_MASK 0x000c /* Spatial Multiplexing (SM) capabitlity bitmask */ + +/* B0-1 maximum rx A-MPDU factor 2^(13+Max Rx A-MPDU Factor) */ +enum { + IEEE80211_HTCAP_MAXRXAMPDU_8192, /* 2 ^ 13 */ + IEEE80211_HTCAP_MAXRXAMPDU_16384, /* 2 ^ 14 */ + IEEE80211_HTCAP_MAXRXAMPDU_32768, /* 2 ^ 15 */ + IEEE80211_HTCAP_MAXRXAMPDU_65536, /* 2 ^ 16 */ +}; +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 + +/* B2-4 MPDU density (usec) */ +enum { + IEEE80211_HTCAP_MPDUDENSITY_NA, /* No time restriction */ + IEEE80211_HTCAP_MPDUDENSITY_0_25, /* 1/4 usec */ + IEEE80211_HTCAP_MPDUDENSITY_0_5, /* 1/2 usec */ + IEEE80211_HTCAP_MPDUDENSITY_1, /* 1 usec */ + IEEE80211_HTCAP_MPDUDENSITY_2, /* 2 usec */ + IEEE80211_HTCAP_MPDUDENSITY_4, /* 4 usec */ + IEEE80211_HTCAP_MPDUDENSITY_8, /* 8 usec */ + IEEE80211_HTCAP_MPDUDENSITY_16, /* 16 usec */ +}; + +/* HT extended capability flags */ +#define IEEE80211_HTCAP_EXTC_PCO 0x0001 +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_RSVD 0x0000 +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_400 0x0002 /* 20-40 switch time */ +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_1500 0x0004 /* in us */ +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_5000 0x0006 +#define IEEE80211_HTCAP_EXTC_RSVD_1 0x00f8 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_NONE 0x0000 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_RSVD 0x0100 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_UNSOL 0x0200 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_FULL 0x0300 +#define IEEE80211_HTCAP_EXTC_RSVD_2 0xfc00 +#ifdef ATH_SUPPORT_TxBF +#define IEEE80211_HTCAP_EXTC_HTC_SUPPORT 0x0400 +#endif + +struct ieee80211_ie_htinfo_cmn { + uint8_t hi_ctrlchannel; /* control channel */ +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t hi_serviceinterval : 3, /* B5-7 svc interval granularity */ + hi_ctrlaccess : 1, /* B4 controlled access only */ + hi_rifsmode : 1, /* B3 rifs mode */ + hi_txchwidth : 1, /* B2 recommended xmiss width set */ + hi_extchoff : 2; /* B0-1 extension channel offset */ + +/* + + * The following 2 consecutive bytes are defined in word in 80211n spec. + + * Some processors store MSB byte into lower memory address which causes wrong + + * wrong byte sequence in beacon. Thus we break into byte definition which should + + * avoid the problem for all processors + + */ + + uint8_t hi_reserved3 : 3, /* B5-7 reserved */ + hi_obssnonhtpresent : 1, /* B4 OBSS non-HT STA present */ + hi_txburstlimit : 1, /* B3 transmit burst limit */ + hi_nongfpresent : 1, /* B2 non greenfield devices present */ + hi_opmode : 2; /* B0-1 operating mode */ + + uint8_t hi_reserved0; /* B0-7 (B8-15 in 11n) reserved */ + +/* The following 2 consecutive bytes are defined in word in 80211n spec. */ + + uint8_t hi_dualctsprot : 1, /* B7 dual CTS protection */ + hi_dualbeacon : 1, /* B6 dual beacon */ + hi_reserved2 : 6; /* B0-5 reserved */ + uint8_t hi_reserved1 : 4, /* B4-7 (B12-15 in 11n) reserved */ + hi_pcophase : 1, /* B3 (B11 in 11n) pco phase */ + hi_pcoactive : 1, /* B2 (B10 in 11n) pco active */ + hi_lsigtxopprot : 1, /* B1 (B9 in 11n) l-sig txop protection full support */ + hi_stbcbeacon : 1; /* B0 (B8 in 11n) STBC beacon */ +#else + uint8_t hi_extchoff : 2, /* B0-1 extension channel offset */ + hi_txchwidth : 1, /* B2 recommended xmiss width set */ + hi_rifsmode : 1, /* B3 rifs mode */ + hi_ctrlaccess : 1, /* B4 controlled access only */ + hi_serviceinterval : 3; /* B5-7 svc interval granularity */ + uint16_t hi_opmode : 2, /* B0-1 operating mode */ + hi_nongfpresent : 1, /* B2 non greenfield devices present */ + hi_txburstlimit : 1, /* B3 transmit burst limit */ + hi_obssnonhtpresent : 1, /* B4 OBSS non-HT STA present */ + hi_reserved0 : 11; /* B5-15 reserved */ + uint16_t hi_reserved2 : 6, /* B0-5 reserved */ + hi_dualbeacon : 1, /* B6 dual beacon */ + hi_dualctsprot : 1, /* B7 dual CTS protection */ + hi_stbcbeacon : 1, /* B8 STBC beacon */ + hi_lsigtxopprot : 1, /* B9 l-sig txop protection full support */ + hi_pcoactive : 1, /* B10 pco active */ + hi_pcophase : 1, /* B11 pco phase */ + hi_reserved1 : 4; /* B12-15 reserved */ +#endif + uint8_t hi_basicmcsset[16]; /* basic MCS set */ +} __packed; + +/* + * 802.11n HT Information IE + */ +struct ieee80211_ie_htinfo { + uint8_t hi_id; /* element ID */ + uint8_t hi_len; /* length in bytes */ + struct ieee80211_ie_htinfo_cmn hi_ie; +} __packed; + +/* + * Temporary vendor private HT Information IE + */ +struct vendor_ie_htinfo { + uint8_t hi_id; /* element ID */ + uint8_t hi_len; /* length in bytes */ + uint8_t hi_oui[3]; + uint8_t hi_ouitype; + struct ieee80211_ie_htinfo_cmn hi_ie; +} __packed; + +/* extension channel offset (2 bit signed number) */ +enum { + IEEE80211_HTINFO_EXTOFFSET_NA = 0, /* 0 no extension channel is present */ + IEEE80211_HTINFO_EXTOFFSET_ABOVE = 1, /* +1 extension channel above control channel */ + IEEE80211_HTINFO_EXTOFFSET_UNDEF = 2, /* -2 undefined */ + IEEE80211_HTINFO_EXTOFFSET_BELOW = 3 /* -1 extension channel below control channel */ +}; + +/* recommended transmission width set */ +enum { + IEEE80211_HTINFO_TXWIDTH_20, + IEEE80211_HTINFO_TXWIDTH_2040 +}; + +/* operating flags */ +#define IEEE80211_HTINFO_OPMODE_PURE 0x00 /* no protection */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_OPT 0x01 /* prot optional (legacy device maybe present) */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_40 0x02 /* prot required (20 MHz) */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_ALL 0x03 /* prot required (legacy devices present) */ +#define IEEE80211_HTINFO_OPMODE_NON_GF_PRESENT 0x04 /* non-greenfield devices present */ + +#define IEEE80211_HTINFO_OPMODE_MASK 0x03 /* For protection 0x00-0x03 */ + +/* Non-greenfield STAs present */ +enum { + IEEE80211_HTINFO_NON_GF_NOT_PRESENT, /* Non-greenfield STAs not present */ + IEEE80211_HTINFO_NON_GF_PRESENT, /* Non-greenfield STAs present */ +}; + +/* Transmit Burst Limit */ +enum { + IEEE80211_HTINFO_TXBURST_UNLIMITED, /* Transmit Burst is unlimited */ + IEEE80211_HTINFO_TXBURST_LIMITED, /* Transmit Burst is limited */ +}; + +/* OBSS Non-HT STAs present */ +enum { + IEEE80211_HTINFO_OBSS_NONHT_NOT_PRESENT, /* OBSS Non-HT STAs not present */ + IEEE80211_HTINFO_OBSS_NONHT_PRESENT, /* OBSS Non-HT STAs present */ +}; + +/* misc flags */ +#define IEEE80211_HTINFO_DUALBEACON 0x0040 /* B6 dual beacon */ +#define IEEE80211_HTINFO_DUALCTSPROT 0x0080 /* B7 dual stbc protection */ +#define IEEE80211_HTINFO_STBCBEACON 0x0100 /* B8 secondary beacon */ +#define IEEE80211_HTINFO_LSIGTXOPPROT 0x0200 /* B9 lsig txop prot full support */ +#define IEEE80211_HTINFO_PCOACTIVE 0x0400 /* B10 pco active */ +#define IEEE80211_HTINFO_PCOPHASE 0x0800 /* B11 pco phase */ + +/* Secondary Channel offset for for 40MHz direct link */ +#define IEEE80211_SECONDARY_CHANNEL_ABOVE 1 +#define IEEE80211_SECONDARY_CHANNEL_BELOW 3 + +#define IEEE80211_TDLS_CHAN_SX_PROHIBIT 0x00000002 /* bit-2 TDLS Channel Switch Prohibit */ + +/* RIFS mode */ +enum { + IEEE80211_HTINFO_RIFSMODE_PROHIBITED, /* use of rifs prohibited */ + IEEE80211_HTINFO_RIFSMODE_ALLOWED, /* use of rifs permitted */ +}; + +/* + * Management information element payloads. + */ +enum { + IEEE80211_ELEMID_SSID = 0, + IEEE80211_ELEMID_RATES = 1, + IEEE80211_ELEMID_FHPARMS = 2, + IEEE80211_ELEMID_DSPARMS = 3, + IEEE80211_ELEMID_CFPARMS = 4, + IEEE80211_ELEMID_TIM = 5, + IEEE80211_ELEMID_IBSSPARMS = 6, + IEEE80211_ELEMID_COUNTRY = 7, + IEEE80211_ELEMID_REQINFO = 10, + IEEE80211_ELEMID_QBSS_LOAD = 11, + IEEE80211_ELEMID_TCLAS = 14, + IEEE80211_ELEMID_CHALLENGE = 16, + /* 17-31 reserved for challenge text extension */ + IEEE80211_ELEMID_PWRCNSTR = 32, + IEEE80211_ELEMID_PWRCAP = 33, + IEEE80211_ELEMID_TPCREQ = 34, + IEEE80211_ELEMID_TPCREP = 35, + IEEE80211_ELEMID_SUPPCHAN = 36, + IEEE80211_ELEMID_CHANSWITCHANN = 37, + IEEE80211_ELEMID_MEASREQ = 38, + IEEE80211_ELEMID_MEASREP = 39, + IEEE80211_ELEMID_QUIET = 40, + IEEE80211_ELEMID_IBSSDFS = 41, + IEEE80211_ELEMID_ERP = 42, + IEEE80211_ELEMID_TCLAS_PROCESS = 44, + IEEE80211_ELEMID_HTCAP_ANA = 45, + IEEE80211_ELEMID_RESERVED_47 = 47, + IEEE80211_ELEMID_RSN = 48, + IEEE80211_ELEMID_XRATES = 50, + IEEE80211_ELEMID_HTCAP = 51, + IEEE80211_ELEMID_HTINFO = 52, + IEEE80211_ELEMID_MOBILITY_DOMAIN = 54, + IEEE80211_ELEMID_FT = 55, + IEEE80211_ELEMID_TIMEOUT_INTERVAL = 56, + IEEE80211_ELEMID_EXTCHANSWITCHANN = 60, + IEEE80211_ELEMID_HTINFO_ANA = 61, + IEEE80211_ELEMID_SECCHANOFFSET = 62, + IEEE80211_ELEMID_WAPI = 68, /*IE for WAPI */ + IEEE80211_ELEMID_TIME_ADVERTISEMENT = 69, + IEEE80211_ELEMID_RRM = 70, /* Radio resource measurement */ + IEEE80211_ELEMID_2040_COEXT = 72, + IEEE80211_ELEMID_2040_INTOL = 73, + IEEE80211_ELEMID_OBSS_SCAN = 74, + IEEE80211_ELEMID_MMIE = 76, /* 802.11w Management MIC IE */ + IEEE80211_ELEMID_FMS_DESCRIPTOR = 86, /* 802.11v FMS descriptor IE */ + IEEE80211_ELEMID_FMS_REQUEST = 87, /* 802.11v FMS request IE */ + IEEE80211_ELEMID_FMS_RESPONSE = 88, /* 802.11v FMS response IE */ + IEEE80211_ELEMID_BSSMAX_IDLE_PERIOD = 90, /* BSS MAX IDLE PERIOD */ + IEEE80211_ELEMID_TFS_REQUEST = 91, + IEEE80211_ELEMID_TFS_RESPONSE = 92, + IEEE80211_ELEMID_TIM_BCAST_REQUEST = 94, + IEEE80211_ELEMID_TIM_BCAST_RESPONSE = 95, + IEEE80211_ELEMID_INTERWORKING = 107, + IEEE80211_ELEMID_XCAPS = 127, + IEEE80211_ELEMID_RESERVED_133 = 133, + IEEE80211_ELEMID_TPC = 150, + IEEE80211_ELEMID_CCKM = 156, + IEEE80211_ELEMID_VHTCAP = 191, /* VHT Capabilities */ + IEEE80211_ELEMID_VHTOP = 192, /* VHT Operation */ + IEEE80211_ELEMID_EXT_BSS_LOAD = 193, /* Extended BSS Load */ + IEEE80211_ELEMID_WIDE_BAND_CHAN_SWITCH = 194, /* Wide Band Channel Switch */ + IEEE80211_ELEMID_VHT_TX_PWR_ENVLP = 195, /* VHT Transmit Power Envelope */ + IEEE80211_ELEMID_CHAN_SWITCH_WRAP = 196, /* Channel Switch Wrapper */ + IEEE80211_ELEMID_AID = 197, /* AID */ + IEEE80211_ELEMID_QUIET_CHANNEL = 198, /* Quiet Channel */ + IEEE80211_ELEMID_OP_MODE_NOTIFY = 199, /* Operating Mode Notification */ + IEEE80211_ELEMID_VENDOR = 221, /* vendor private */ +}; + +#define IEEE80211_MAX_IE_LEN 255 +#define IEEE80211_RSN_IE_LEN 22 + +#define IEEE80211_CHANSWITCHANN_BYTES 5 +#define IEEE80211_EXTCHANSWITCHANN_BYTES 6 + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +struct ieee80211_tim_ie { + uint8_t tim_ie; /* IEEE80211_ELEMID_TIM */ + uint8_t tim_len; + uint8_t tim_count; /* DTIM count */ + uint8_t tim_period; /* DTIM period */ + uint8_t tim_bitctl; /* bitmap control */ + uint8_t tim_bitmap[1]; /* variable-length bitmap */ +} __packed; +#endif + +/* Country IE channel triplet */ +struct country_ie_triplet { + union { + uint8_t schan; /* starting channel */ + uint8_t regextid; /* Regulatory Extension Identifier */ + }; + union { + uint8_t nchan; /* number of channels */ + uint8_t regclass; /* Regulatory Class */ + }; + union { + uint8_t maxtxpwr; /* tx power */ + uint8_t coverageclass; /* Coverage Class */ + }; +} __packed; + +struct ieee80211_country_ie { + uint8_t ie; /* IEEE80211_ELEMID_COUNTRY */ + uint8_t len; + uint8_t cc[3]; /* ISO CC+(I)ndoor/(O)utdoor */ + struct country_ie_triplet triplet[1]; +} __packed; + +struct ieee80211_fh_ie { + uint8_t ie; /* IEEE80211_ELEMID_FHPARMS */ + uint8_t len; + uint16_t dwell_time; /* endianness?? */ + uint8_t hop_set; + uint8_t hop_pattern; + uint8_t hop_index; +} __packed; + +struct ieee80211_ds_ie { + uint8_t ie; /* IEEE80211_ELEMID_DSPARMS */ + uint8_t len; + uint8_t current_channel; +} __packed; + +struct ieee80211_erp_ie { + uint8_t ie; /* IEEE80211_ELEMID_ERP */ + uint8_t len; + uint8_t value; +} __packed; + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +struct ieee80211_quiet_ie { + uint8_t ie; /* IEEE80211_ELEMID_QUIET */ + uint8_t len; + uint8_t tbttcount; /* quiet start */ + uint8_t period; /* beacon intervals between quiets */ + uint16_t duration; /* TUs of each quiet */ + uint16_t offset; /* TUs of from TBTT of quiet start */ +} __packed; +#endif + +struct ieee80211_channelswitch_ie { + uint8_t ie; /* IEEE80211_ELEMID_CHANSWITCHANN */ + uint8_t len; + uint8_t switchmode; + uint8_t newchannel; + uint8_t tbttcount; +} __packed; + +/* channel switch action frame format definition */ +struct ieee80211_action_spectrum_channel_switch { + struct ieee80211_action csa_header; + struct ieee80211_channelswitch_ie csa_element; +} __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; + +struct ieee80211_tpc_ie { + uint8_t ie; + uint8_t len; + uint8_t pwrlimit; +} __packed; + +/* + * MHDRIE included in TKIP MFP protected management frames + */ +struct ieee80211_ese_mhdr_ie { + uint8_t mhdr_id; + uint8_t mhdr_len; + uint8_t mhdr_oui[3]; + uint8_t mhdr_oui_type; + uint8_t mhdr_fc[2]; + uint8_t mhdr_bssid[IEEE80211_ADDR_LEN]; +} __packed; + +/* + * SSID IE + */ +struct ieee80211_ie_ssid { + uint8_t ssid_id; + uint8_t ssid_len; + uint8_t ssid[32]; +} __packed; + +/* + * Supported rates + */ +#define IEEE80211_MAX_SUPPORTED_RATES 8 + +struct ieee80211_ie_rates { + uint8_t rate_id; /* Element Id */ + uint8_t rate_len; /* IE Length */ + uint8_t rate[IEEE80211_MAX_SUPPORTED_RATES]; /* IE Length */ +} __packed; + +/* + * Extended rates + */ +#define IEEE80211_MAX_EXTENDED_RATES 256 + +struct ieee80211_ie_xrates { + uint8_t xrate_id; /* Element Id */ + uint8_t xrate_len; /* IE Length */ + uint8_t xrate[IEEE80211_MAX_EXTENDED_RATES]; /* IE Length */ +} __packed; + +/* + * WPS SSID list information element (maximally sized). + */ +struct ieee80211_ie_ssidl { + uint8_t ssidl_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t ssidl_len; /* length in bytes */ + uint8_t ssidl_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t ssidl_type; /* OUI type */ + uint8_t ssidl_prim_cap; /* Primary capabilities */ + uint8_t ssidl_count; /* # of secondary SSIDs */ + uint16_t ssidl_value[248]; +} __packed; + +#if _BYTE_ORDER == _BIG_ENDIAN +struct ieee80211_sec_ssid_cap { + uint32_t reserved0 : 1, + akmlist : 6, reserved1 : 4, reeserved2 : 2, ucipher : 15, mcipher : 4; +}; +#else +struct ieee80211_sec_ssid_cap { + uint32_t mcipher : 4, + ucipher : 15, reserved2 : 2, reserved1 : 4, akmlist : 6, reserved0 : 1; +}; +#endif + +struct ieee80211_ie_qbssload { + uint8_t elem_id; /* IEEE80211_ELEMID_QBSS_LOAD */ + uint8_t length; /* length in bytes */ + uint16_t station_count; /* number of station associated */ + uint8_t channel_utilization; /* channel busy time in 0-255 scale */ + uint16_t aac; /* available admission capacity */ +} __packed; + +#define SEC_SSID_HEADER_LEN 6 +#define SSIDL_IE_HEADER_LEN 6 + +struct ieee80211_sec_ssid { + uint8_t sec_ext_cap; + struct ieee80211_sec_ssid_cap sec_cap; + uint8_t sec_ssid_len; + uint8_t sec_ssid[32]; +} __packed; + +/* Definitions of SSIDL IE */ +enum { + CAP_MCIPHER_ENUM_NONE = 0, + CAP_MCIPHER_ENUM_WEP40, + CAP_MCIPHER_ENUM_WEP104, + CAP_MCIPHER_ENUM_TKIP, + CAP_MCIPHER_ENUM_CCMP, + CAP_MCIPHER_ENUM_CKIP_CMIC, + CAP_MCIPHER_ENUM_CKIP, + CAP_MCIPHER_ENUM_CMIC +}; + +#define CAP_UCIPHER_BIT_NONE 0x0001 +#define CAP_UCIPHER_BIT_WEP40 0x0002 +#define CAP_UCIPHER_BIT_WEP104 0x0004 +#define CAP_UCIPHER_BIT_TKIP 0x0008 +#define CAP_UCIPHER_BIT_CCMP 0x0010 +#define CAP_UCIPHER_BIT_CKIP_CMIC 0x0020 +#define CAP_UCIPHER_BIT_CKIP 0x0040 +#define CAP_UCIPHER_BIT_CMIC 0x0080 +#define CAP_UCIPHER_BIT_WPA2_WEP40 0x0100 +#define CAP_UCIPHER_BIT_WPA2_WEP104 0x0200 +#define CAP_UCIPHER_BIT_WPA2_TKIP 0x0400 +#define CAP_UCIPHER_BIT_WPA2_CCMP 0x0800 +#define CAP_UCIPHER_BIT_WPA2_CKIP_CMIC 0x1000 +#define CAP_UCIPHER_BIT_WPA2_CKIP 0x2000 +#define CAP_UCIPHER_BIT_WPA2_CMIC 0x4000 + +#define CAP_AKM_BIT_WPA1_1X 0x01 +#define CAP_AKM_BIT_WPA1_PSK 0x02 +#define CAP_AKM_BIT_WPA2_1X 0x04 +#define CAP_AKM_BIT_WPA2_PSK 0x08 +#define CAP_AKM_BIT_WPA1_CCKM 0x10 +#define CAP_AKM_BIT_WPA2_CCKM 0x20 + +#define IEEE80211_CHALLENGE_LEN 128 + +#define IEEE80211_SUPPCHAN_LEN 26 + +#define IEEE80211_RATE_BASIC 0x80 +#define IEEE80211_RATE_VAL 0x7f + +/* EPR information element flags */ +#define IEEE80211_ERP_NON_ERP_PRESENT 0x01 +#define IEEE80211_ERP_USE_PROTECTION 0x02 +#define IEEE80211_ERP_LONG_PREAMBLE 0x04 + +/* Atheros private advanced capabilities info */ +#define ATHEROS_CAP_TURBO_PRIME 0x01 +#define ATHEROS_CAP_COMPRESSION 0x02 +#define ATHEROS_CAP_FAST_FRAME 0x04 +/* bits 3-6 reserved */ +#define ATHEROS_CAP_BOOST 0x80 + +#define ATH_OUI 0x7f0300 /* Atheros OUI */ +#define ATH_OUI_TYPE 0x01 +#define ATH_OUI_SUBTYPE 0x01 +#define ATH_OUI_VERSION 0x00 +#define ATH_OUI_TYPE_XR 0x03 +#define ATH_OUI_VER_XR 0x01 +#define ATH_OUI_EXTCAP_TYPE 0x04 /* Atheros Extended Cap Type */ +#define ATH_OUI_EXTCAP_SUBTYPE 0x01 /* Atheros Extended Cap Sub-type */ +#define ATH_OUI_EXTCAP_VERSION 0x00 /* Atheros Extended Cap Version */ + +#define WPA_OUI 0xf25000 +#define WPA_VERSION 1 /* current supported version */ +#define CSCO_OUI 0x964000 /* Cisco OUI */ +#define AOW_OUI 0x4a0100 /* AoW OUI, workaround */ +#define AOW_OUI_TYPE 0x01 +#define AOW_OUI_VERSION 0x01 + +#define WSC_OUI 0x0050f204 + +#define WPA_CSE_NULL 0x00 +#define WPA_CSE_WEP40 0x01 +#define WPA_CSE_TKIP 0x02 +#define WPA_CSE_CCMP 0x04 +#define WPA_CSE_WEP104 0x05 + +#define WPA_ASE_NONE 0x00 +#define WPA_ASE_8021X_UNSPEC 0x01 +#define WPA_ASE_8021X_PSK 0x02 +#define WPA_ASE_FT_IEEE8021X 0x20 +#define WPA_ASE_FT_PSK 0x40 +#define WPA_ASE_SHA256_IEEE8021X 0x80 +#define WPA_ASE_SHA256_PSK 0x100 +#define WPA_ASE_WPS 0x200 + +#define RSN_OUI 0xac0f00 +#define RSN_VERSION 1 /* current supported version */ + +#define RSN_CSE_NULL 0x00 +#define RSN_CSE_WEP40 0x01 +#define RSN_CSE_TKIP 0x02 +#define RSN_CSE_WRAP 0x03 +#define RSN_CSE_CCMP 0x04 +#define RSN_CSE_WEP104 0x05 +#define RSN_CSE_AES_CMAC 0x06 + +#define RSN_ASE_NONE 0x00 +#define RSN_ASE_8021X_UNSPEC 0x01 +#define RSN_ASE_8021X_PSK 0x02 +#define RSN_ASE_FT_IEEE8021X 0x20 +#define RSN_ASE_FT_PSK 0x40 +#define RSN_ASE_SHA256_IEEE8021X 0x80 +#define RSN_ASE_SHA256_PSK 0x100 +#define RSN_ASE_WPS 0x200 + +#define AKM_SUITE_TYPE_IEEE8021X 0x01 +#define AKM_SUITE_TYPE_PSK 0x02 +#define AKM_SUITE_TYPE_FT_IEEE8021X 0x03 +#define AKM_SUITE_TYPE_FT_PSK 0x04 +#define AKM_SUITE_TYPE_SHA256_IEEE8021X 0x05 +#define AKM_SUITE_TYPE_SHA256_PSK 0x06 + +#define RSN_CAP_PREAUTH 0x01 +#define RSN_CAP_PTKSA_REPLAYCOUNTER 0x0c +#define RSN_CAP_GTKSA_REPLAYCOUNTER 0x30 +#define RSN_CAP_MFP_REQUIRED 0x40 +#define RSN_CAP_MFP_ENABLED 0x80 + +#define CCKM_OUI 0x964000 +#define CCKM_ASE_UNSPEC 0 +#define WPA_CCKM_AKM 0x00964000 +#define RSN_CCKM_AKM 0x00964000 + +#define WME_OUI 0xf25000 +#define WME_OUI_TYPE 0x02 +#define WME_INFO_OUI_SUBTYPE 0x00 +#define WME_PARAM_OUI_SUBTYPE 0x01 +#define WME_TSPEC_OUI_SUBTYPE 0x02 + +#define WME_PARAM_OUI_VERSION 1 +#define WME_TSPEC_OUI_VERSION 1 +#define WME_VERSION 1 + +/* WME stream classes */ +#define WME_AC_BE 0 /* best effort */ +#define WME_AC_BK 1 /* background */ +#define WME_AC_VI 2 /* video */ +#define WME_AC_VO 3 /* voice */ + +/* WCN IE */ +#define WCN_OUI 0xf25000 /* Microsoft OUI */ +#define WCN_OUI_TYPE 0x04 /* WCN */ + +/* Atheros htoui for ht vender ie; use Epigram OUI for compatibility with pre11n devices */ +#define ATH_HTOUI 0x00904c + +#define SFA_OUI 0x964000 +#define SFA_OUI_TYPE 0x14 +#define SFA_IE_CAP_MFP 0x01 +#define SFA_IE_CAP_DIAG_CHANNEL 0x02 +#define SFA_IE_CAP_LOCATION_SVCS 0x04 +#define SFA_IE_CAP_EXP_BANDWIDTH 0x08 + +#define WPA_OUI_BYTES 0x00, 0x50, 0xf2 +#define RSN_OUI_BYTES 0x00, 0x0f, 0xac +#define WME_OUI_BYTES 0x00, 0x50, 0xf2 +#define ATH_OUI_BYTES 0x00, 0x03, 0x7f +#define SFA_OUI_BYTES 0x00, 0x40, 0x96 +#define CCKM_OUI_BYTES 0x00, 0x40, 0x96 +#define WPA_SEL(x) (((x)<<24)|WPA_OUI) +#define RSN_SEL(x) (((x)<<24)|RSN_OUI) +#define SFA_SEL(x) (((x)<<24)|SFA_OUI) +#define CCKM_SEL(x) (((x)<<24)|CCKM_OUI) + +#define IEEE80211_RV(v) ((v) & IEEE80211_RATE_VAL) + +/* + * AUTH management packets + * + * octet algo[2] + * octet seq[2] + * octet status[2] + * octet chal.id + * octet chal.length + * octet chal.text[253] + */ + +typedef uint8_t *ieee80211_mgt_auth_t; + +#define IEEE80211_AUTH_ALGORITHM(auth) \ + ((auth)[0] | ((auth)[1] << 8)) +#define IEEE80211_AUTH_TRANSACTION(auth) \ + ((auth)[2] | ((auth)[3] << 8)) +#define IEEE80211_AUTH_STATUS(auth) \ + ((auth)[4] | ((auth)[5] << 8)) + +#define IEEE80211_AUTH_ALG_OPEN 0x0000 +#define IEEE80211_AUTH_ALG_SHARED 0x0001 +#define IEEE80211_AUTH_ALG_FT 0x0002 +#define IEEE80211_AUTH_ALG_LEAP 0x0080 + +enum { + IEEE80211_AUTH_OPEN_REQUEST = 1, + IEEE80211_AUTH_OPEN_RESPONSE = 2, +}; + +enum { + IEEE80211_AUTH_SHARED_REQUEST = 1, + IEEE80211_AUTH_SHARED_CHALLENGE = 2, + IEEE80211_AUTH_SHARED_RESPONSE = 3, + IEEE80211_AUTH_SHARED_PASS = 4, +}; + +/* + * 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, +}; + +/* private IEEE80211_STATUS */ +#define IEEE80211_STATUS_CANCEL -1 +#define IEEE80211_STATUS_INVALID_IE -2 +#define IEEE80211_STATUS_INVALID_CHANNEL -3 + +#define IEEE80211_WEP_KEYLEN 5 /* 40bit */ +#define IEEE80211_WEP_IVLEN 3 /* 24bit */ +#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ +#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ +#define IEEE80211_WEP_NKID 4 /* number of key ids */ + +/* + * 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 */ + +#define IEEE80211_CCMP_HEADERLEN 8 +#define IEEE80211_CCMP_MICLEN 8 +#define WLAN_IEEE80211_GCMP_HEADERLEN 8 +#define WLAN_IEEE80211_GCMP_MICLEN 16 + +/* + * 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_ELEMENTIDLEN 1 +#define IEEE80211_MMIE_LENGTHLEN 1 +#define IEEE80211_MMIE_KEYIDLEN 2 +#define IEEE80211_MMIE_IPNLEN 6 +#define IEEE80211_MMIE_MICLEN 8 + +#define IEEE80211_CRC_LEN 4 + +#define IEEE80211_8021Q_HEADER_LEN 4 +/* + * Maximum acceptable MTU is: + * IEEE80211_MAX_LEN - WEP overhead - CRC - + * QoS overhead - RSN/WPA overhead + * Min is arbitrarily chosen > IEEE80211_MIN_LEN. The default + * mtu is Ethernet-compatible; it's set by ether_ifattach. + */ +#define IEEE80211_MTU_MAX 2290 +#define IEEE80211_MTU_MIN 32 + +/* Rather than using this default value, customer platforms can provide a custom value for this constant. + Coustomer platform will use the different define value by themself */ +#ifndef IEEE80211_MAX_MPDU_LEN +#define IEEE80211_MAX_MPDU_LEN (3840 + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) +#endif +#define IEEE80211_ACK_LEN \ + (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) +#define IEEE80211_MIN_LEN \ + (sizeof(struct ieee80211_frame_min) + IEEE80211_CRC_LEN) + +/* An 802.11 data frame can be one of three types: + 1. An unaggregated frame: The maximum length of an unaggregated data frame is 2324 bytes + headers. + 2. A data frame that is part of an AMPDU: The maximum length of an AMPDU may be upto 65535 bytes, but data frame is limited to 2324 bytes + header. + 3. An AMSDU: The maximum length of an AMSDU is eihther 3839 or 7095 bytes. + The maximum frame length supported by hardware is 4095 bytes. + A length of 3839 bytes is chosen here to support unaggregated data frames, any size AMPDUs and 3839 byte AMSDUs. + */ +#define IEEE80211N_MAX_FRAMELEN 3839 +#define IEEE80211N_MAX_LEN (IEEE80211N_MAX_FRAMELEN + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) + +#define IEEE80211_TX_CHAINMASK_MIN 1 +#define IEEE80211_TX_CHAINMASK_MAX 7 + +#define IEEE80211_RX_CHAINMASK_MIN 1 +#define IEEE80211_RX_CHAINMASK_MAX 7 + +/* + * The 802.11 spec says at most 2007 stations may be + * associated at once. For most AP's this is way more + * than is feasible so we use a default of 128. This + * number may be overridden by the driver and/or by + * user configuration. + */ +#define IEEE80211_AID_MAX 2007 +#define IEEE80211_AID_DEF 128 + +#define IEEE80211_AID(b) ((b) & ~0xc000) + +/* + * RTS frame length parameters. The default is specified in + * the 802.11 spec. The max may be wrong for jumbo frames. + */ +#define IEEE80211_RTS_DEFAULT 512 +#define IEEE80211_RTS_MIN 0 +#define IEEE80211_RTS_MAX 2347 + +/* + * Fragmentation limits + */ +#define IEEE80211_FRAGMT_THRESHOLD_MIN 540 /* min frag threshold */ +#define IEEE80211_FRAGMT_THRESHOLD_MAX 2346 /* max frag threshold */ + +/* + * Regulatory extension identifier for country IE. + */ +#define IEEE80211_REG_EXT_ID 201 + +/* + * overlapping BSS + */ +#define IEEE80211_OBSS_SCAN_PASSIVE_DWELL_DEF 20 +#define IEEE80211_OBSS_SCAN_ACTIVE_DWELL_DEF 10 +#define IEEE80211_OBSS_SCAN_INTERVAL_DEF 300 +#define IEEE80211_OBSS_SCAN_PASSIVE_TOTAL_DEF 200 +#define IEEE80211_OBSS_SCAN_ACTIVE_TOTAL_DEF 20 +#define IEEE80211_OBSS_SCAN_THRESH_DEF 25 +#define IEEE80211_OBSS_SCAN_DELAY_DEF 5 + +/* + * overlapping BSS scan ie + */ +struct ieee80211_ie_obss_scan { + uint8_t elem_id; + uint8_t elem_len; + uint16_t scan_passive_dwell; + uint16_t scan_active_dwell; + uint16_t scan_interval; + uint16_t scan_passive_total; + uint16_t scan_active_total; + uint16_t scan_delay; + uint16_t scan_thresh; +} __packed; + +/* + * Extended capability ie + */ +struct ieee80211_ie_ext_cap { + uint8_t elem_id; + uint8_t elem_len; + uint32_t ext_capflags; + uint32_t ext_capflags2; +} __packed; + +/* Extended capability IE flags */ +#define IEEE80211_EXTCAPIE_2040COEXTMGMT 0x00000001 +#define IEEE80211_EXTCAPIE_TFS 0x00010000 +#define IEEE80211_EXTCAPIE_FMS 0x00000800 +#define IEEE80211_EXTCAPIE_WNMSLEEPMODE 0x00020000 +#define IEEE80211_EXTCAPIE_TIMBROADCAST 0x00040000 +#define IEEE80211_EXTCAPIE_PROXYARP 0x00001000 +#define IEEE80211_EXTCAPIE_BSSTRANSITION 0x00080000 +/* Tunneled Direct Link Setup (TDLS) extended capability bits */ +#define IEEE80211_EXTCAPIE_PEER_UAPSD_BUF_STA 0x10000000 +#define IEEE80211_EXTCAPIE_TDLS_PEER_PSM 0x20000000 +#define IEEE80211_EXTCAPIE_TDLS_CHAN_SX 0x40000000 +/* 2nd Extended capability IE flags bit32-bit63*/ +#define IEEE80211_EXTCAPIE_TDLSSUPPORT 0x00000020 /* bit-37 TDLS Support */ +#define IEEE80211_EXTCAPIE_TDLSPROHIBIT 0x00000040 /* bit-38 TDLS Prohibit Support */ +#define IEEE80211_EXTCAPIE_TDLSCHANSXPROHIBIT 0x00000080 /* bit-39 TDLS Channel Switch Prohibit */ +#define IEEE80211_EXTCAPIE_TDLS_WIDE_BAND 0x20000080 /* bit-61 TDLS Wide Bandwidth support */ +#define IEEE80211_EXTCAPIE_OP_MODE_NOTIFY 0x40000000 /* bit-62 Operating Mode notification */ + +/* + * These caps are populated when we receive beacon/probe response + * This is used to maintain local TDLS cap bit masks + */ + +#define IEEE80211_TDLS_PROHIBIT 0x00000001 /* bit-1 TDLS Prohibit Support */ + +/* + * 20/40 BSS coexistence ie + */ +struct ieee80211_ie_bss_coex { + uint8_t elem_id; + uint8_t elem_len; +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t reserved1 : 1, + reserved2 : 1, + reserved3 : 1, + obss_exempt_grant : 1, + obss_exempt_req : 1, + ht20_width_req : 1, ht40_intolerant : 1, inf_request : 1; +#else + uint8_t inf_request : 1, + ht40_intolerant : 1, + ht20_width_req : 1, + obss_exempt_req : 1, + obss_exempt_grant : 1, reserved3 : 1, reserved2 : 1, reserved1 : 1; +#endif +} __packed; + +/* + * 20/40 BSS intolerant channel report ie + */ +struct ieee80211_ie_intolerant_report { + uint8_t elem_id; + uint8_t elem_len; + uint8_t reg_class; + uint8_t chan_list[1]; /* variable-length channel list */ +} __packed; + +/* + * 20/40 coext management action frame + */ +struct ieee80211_action_bss_coex_frame { + struct ieee80211_action ac_header; + struct ieee80211_ie_bss_coex coex; + struct ieee80211_ie_intolerant_report chan_report; +} __packed; + +typedef enum ieee80211_tie_interval_type { + IEEE80211_TIE_INTERVAL_TYPE_RESERVED = 0, + IEEE80211_TIE_INTERVAL_TYPE_REASSOC_DEADLINE_INTERVAL = 1, + IEEE80211_TIE_INTERVAL_TYPE_KEY_LIFETIME_INTERVAL = 2, + IEEE80211_TIE_INTERVAL_TYPE_ASSOC_COMEBACK_TIME = 3, +} ieee80211_tie_interval_type_t; + +struct ieee80211_ie_timeout_interval { + uint8_t elem_id; + uint8_t elem_len; + uint8_t interval_type; + uint32_t value; +} __packed; + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +/* Management MIC information element (IEEE 802.11w) */ +struct ieee80211_mmie { + uint8_t element_id; + uint8_t length; + uint16_t key_id; + uint8_t sequence_number[6]; + uint8_t mic[8]; +} __packed; +#endif + +/* + * 802.11n Secondary Channel Offset element + */ +#define IEEE80211_SEC_CHAN_OFFSET_SCN 0 /* no secondary channel */ +#define IEEE80211_SEC_CHAN_OFFSET_SCA 1 /* secondary channel above */ +#define IEEE80211_SEC_CHAN_OFFSET_SCB 3 /* secondary channel below */ + +struct ieee80211_ie_sec_chan_offset { + uint8_t elem_id; + uint8_t len; + uint8_t sec_chan_offset; +} __packed; + +/* + * 802.11ac Transmit Power Envelope element + */ +#define IEEE80211_VHT_TXPWR_IS_SUB_ELEMENT 1 /* It checks whether its sub element */ +#define IEEE80211_VHT_TXPWR_MAX_POWER_COUNT 4 /* Max TX power elements valid */ +#define IEEE80211_VHT_TXPWR_NUM_POWER_SUPPORTED 3 /* Max TX power elements supported */ +#define IEEE80211_VHT_TXPWR_LCL_MAX_PWR_UNITS_SHFT 3 /* B3-B5 Local Max transmit power units */ + +struct ieee80211_ie_vht_txpwr_env { + uint8_t elem_id; + uint8_t elem_len; + uint8_t txpwr_info; /* Transmit Power Information */ + uint8_t local_max_txpwr[4]; /* Local Max TxPower for 20,40,80,160MHz */ +} __packed; + +/* + * 802.11ac Wide Bandwidth Channel Switch Element + */ + +#define IEEE80211_VHT_EXTCH_SWITCH 1 /* For extension channel switch */ +#define CHWIDTH_VHT20 20 /* Channel width 20 */ +#define CHWIDTH_VHT40 40 /* Channel width 40 */ +#define CHWIDTH_VHT80 80 /* Channel width 80 */ +#define CHWIDTH_VHT160 160 /* Channel width 160 */ + +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; + +#define IEEE80211_RSSI_RX 0x00000001 +#define IEEE80211_RSSI_TX 0x00000002 +#define IEEE80211_RSSI_EXTCHAN 0x00000004 +#define IEEE80211_RSSI_BEACON 0x00000008 +#define IEEE80211_RSSI_RXDATA 0x00000010 + +#define IEEE80211_RATE_TX 0 +#define IEEE80211_RATE_RX 1 +#define IEEE80211_LASTRATE_TX 2 +#define IEEE80211_LASTRATE_RX 3 +#define IEEE80211_RATECODE_TX 4 +#define IEEE80211_RATECODE_RX 5 + +#define IEEE80211_MAX_RATE_PER_CLIENT 8 +/* Define for the P2P Wildcard SSID */ +#define IEEE80211_P2P_WILDCARD_SSID "DIRECT-" + +#define IEEE80211_P2P_WILDCARD_SSID_LEN (sizeof(IEEE80211_P2P_WILDCARD_SSID) - 1) + +#endif /* CDS_COMMON_IEEE80211_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_defines.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..82b14b8610188df460268b3375fcb53310b32662 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_defines.h @@ -0,0 +1,1365 @@ +/* + * Copyright (c) 2011, 2014-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 CDS_IEEE80211_DEFINES_H_ +#define CDS_IEEE80211_DEFINES_H_ + +#include "cds_ieee80211_common.h" + +/* + * Public defines for Atheros Upper MAC Layer + */ + +/** + * @brief Opaque handle of 802.11 protocal layer. + */ +struct ieee80211com; +typedef struct ieee80211com *wlan_dev_t; + +/** + * @brief Opaque handle to App IE module. + */ +struct wlan_mlme_app_ie; +typedef struct wlan_mlme_app_ie *wlan_mlme_app_ie_t; + +/** + * @brief Opaque handle of network instance (vap) in 802.11 protocal layer. + */ +struct ieee80211vap; +typedef struct ieee80211vap *wlan_if_t; + +struct ieee80211vapprofile; +typedef struct ieee80211vapprofile *wlan_if_info_t; + +/** + * @brief Opaque handle of a node in the wifi network. + */ +struct ieee80211_node; +typedef struct ieee80211_node *wlan_node_t; + +/** + * @brief Opaque handle of OS interface (ifp in the case of unix ). + */ +struct _os_if_t; +typedef struct _os_if_t *os_if_t; + +/** + * + * @brief Opaque handle. + */ +typedef void *os_handle_t; + +/** + * @brief Opaque handle of a channel. + */ +struct ieee80211_channel; +typedef struct ieee80211_channel *wlan_chan_t; + +/** + * @brief Opaque handle scan_entry. + */ +struct ieee80211_scan_entry; +typedef struct ieee80211_scan_entry *wlan_scan_entry_t; + +/* AoW related defines */ +#define AOW_MAX_RECEIVER_COUNT 10 + +#define IEEE80211_NWID_LEN 32 +#define IEEE80211_ISO_COUNTRY_LENGTH 3 /* length of 11d ISO country string */ + +typedef struct _ieee80211_ssid { + int len; + uint8_t ssid[IEEE80211_NWID_LEN]; +} ieee80211_ssid; + +typedef struct ieee80211_tx_status { + int ts_flags; +#define IEEE80211_TX_ERROR 0x01 +#define IEEE80211_TX_XRETRY 0x02 + + int ts_retries; /* number of retries to successfully transmit this frame */ +#ifdef ATH_SUPPORT_TxBF + uint8_t ts_txbfstatus; +#define AR_BW_Mismatch 0x1 +#define AR_Stream_Miss 0x2 +#define AR_CV_Missed 0x4 +#define AR_Dest_Miss 0x8 +#define AR_Expired 0x10 +#define AR_TxBF_Valid_HW_Status (AR_BW_Mismatch|AR_Stream_Miss|AR_CV_Missed|AR_Dest_Miss|AR_Expired) +#define TxBF_STATUS_Sounding_Complete 0x20 +#define TxBF_STATUS_Sounding_Request 0x40 +#define TxBF_Valid_SW_Status (TxBF_STATUS_Sounding_Complete | TxBF_STATUS_Sounding_Request) +#define TxBF_Valid_Status (AR_TxBF_Valid_HW_Status | TxBF_Valid_SW_Status) + uint32_t ts_tstamp; /* tx time stamp */ +#endif +#ifdef ATH_SUPPORT_FLOWMAC_MODULE + uint8_t ts_flowmac_flags; +#define IEEE80211_TX_FLOWMAC_DONE 0x01 +#endif + uint32_t ts_rateKbps; +} ieee80211_xmit_status; + +#ifndef EXTERNAL_USE_ONLY +typedef struct ieee80211_rx_status { + int rs_numchains; + int rs_flags; +#define IEEE80211_RX_FCS_ERROR 0x01 +#define IEEE80211_RX_MIC_ERROR 0x02 +#define IEEE80211_RX_DECRYPT_ERROR 0x04 +/* holes in flags here between, ATH_RX_XXXX to IEEE80211_RX_XXX */ +#define IEEE80211_RX_KEYMISS 0x200 + int rs_rssi; /* RSSI (noise floor ajusted) */ + int rs_abs_rssi; /* absolute RSSI */ + int rs_datarate; /* data rate received */ + int rs_rateieee; + int rs_ratephy; + +#define IEEE80211_MAX_ANTENNA 3 /* Keep the same as ATH_MAX_ANTENNA */ + uint8_t rs_rssictl[IEEE80211_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ + uint8_t rs_rssiextn[IEEE80211_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ + uint8_t rs_isvalidrssi; /* rs_rssi is valid or not */ + + enum ieee80211_phymode rs_phymode; + int rs_freq; + + union { + uint8_t data[8]; + uint64_t tsf; + } rs_tstamp; + + /* + * Detail channel structure of recv frame. + * It could be NULL if not available + */ + 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; /* txbf report time stamp */ +#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; /* Crypto bytes decapped/demic'ed. */ + uint8_t rs_padspace; /* No. of padding bytes present after header + in wbuf. */ + uint8_t rs_qosdecapcount; /* QoS/HTC bytes decapped. */ + + /* 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]; + +} ieee80211_recv_status; +#endif /* EXTERNAL_USE_ONLY */ + +/* + * flags to be passed to ieee80211_vap_create function . + */ +#define IEEE80211_CLONE_BSSID 0x0001 /* allocate unique mac/bssid */ +#define IEEE80211_CLONE_NOBEACONS 0x0002 /* don't setup beacon timers */ +#define IEEE80211_CLONE_WDS 0x0004 /* enable WDS processing */ +#define IEEE80211_CLONE_WDSLEGACY 0x0008 /* legacy WDS operation */ +#define IEEE80211_PRIMARY_VAP 0x0010 /* primary vap */ +#define IEEE80211_P2PDEV_VAP 0x0020 /* p2pdev vap */ +#define IEEE80211_P2PGO_VAP 0x0040 /* p2p-go vap */ +#define IEEE80211_P2PCLI_VAP 0x0080 /* p2p-client vap */ +#define IEEE80211_CLONE_MACADDR 0x0100 /* create vap w/ specified mac/bssid */ +#define IEEE80211_CLONE_MATADDR 0x0200 /* create vap w/ specified MAT addr */ +#define IEEE80211_WRAP_VAP 0x0400 /* wireless repeater ap vap */ + +/* + * For the new multi-vap scan feature, there is a set of default priority tables + * for each OpMode. + * The following are the default list of the VAP Scan Priority Mapping based on OpModes. + * NOTE: the following are only used when "#if ATH_SUPPORT_MULTIPLE_SCANS" is true. + */ +/* For IBSS opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_IBSS_BASE 0 +/* For STA opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_STA_BASE 0 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_STA_P2P_CLIENT 1 +/* For HostAp opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_BASE 0 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_P2P_GO 1 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_P2P_DEVICE 2 +/* For BTAmp opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_BTAMP_BASE 0 + +typedef enum _ieee80211_dev_vap_event { + IEEE80211_VAP_CREATED = 1, + IEEE80211_VAP_STOPPED, + IEEE80211_VAP_DELETED +} ieee80211_dev_vap_event; + +typedef struct _wlan_dev_event_handler_table { + void (*wlan_dev_vap_event)(void *event_arg, wlan_dev_t, os_if_t, ieee80211_dev_vap_event); /* callback to receive vap events */ +#ifdef ATH_SUPPORT_SPECTRAL + void (*wlan_dev_spectral_indicate)(void *, void *, uint32_t); +#endif +} wlan_dev_event_handler_table; + +typedef enum _ieee80211_ap_stopped_reason { + IEEE80211_AP_STOPPED_REASON_DUMMY = 0, /* Dummy placeholder. Should not use */ + IEEE80211_AP_STOPPED_REASON_CHANNEL_DFS = 1, +} ieee80211_ap_stopped_reason; + +typedef int IEEE80211_REASON_CODE; +typedef int IEEE80211_STATUS; + +/* + * scan API related structs. + */ +typedef enum _ieee80211_scan_type { + IEEE80211_SCAN_BACKGROUND, + IEEE80211_SCAN_FOREGROUND, + IEEE80211_SCAN_SPECTRAL, + IEEE80211_SCAN_REPEATER_BACKGROUND, + IEEE80211_SCAN_REPEATER_EXT_BACKGROUND, + IEEE80211_SCAN_RADIO_MEASUREMENTS, +} ieee80211_scan_type; + +/* + * Priority numbers must be sequential, starting with 0. + */ +typedef enum ieee80211_scan_priority_t { + IEEE80211_SCAN_PRIORITY_VERY_LOW = 0, + IEEE80211_SCAN_PRIORITY_LOW, + IEEE80211_SCAN_PRIORITY_MEDIUM, + IEEE80211_SCAN_PRIORITY_HIGH, + IEEE80211_SCAN_PRIORITY_VERY_HIGH, + + IEEE80211_SCAN_PRIORITY_COUNT /* number of priorities supported */ +} IEEE80211_SCAN_PRIORITY; + +typedef uint16_t IEEE80211_SCAN_REQUESTOR; +typedef uint32_t IEEE80211_SCAN_ID; + +#define IEEE80211_SCAN_ID_NONE 0 + +/* All P2P scans currently use medium priority */ +#define IEEE80211_P2P_DEFAULT_SCAN_PRIORITY IEEE80211_SCAN_PRIORITY_MEDIUM +#define IEEE80211_P2P_SCAN_PRIORITY_HIGH IEEE80211_SCAN_PRIORITY_HIGH + +/* Masks identifying types/ID of scans */ +#define IEEE80211_SPECIFIC_SCAN 0x00000000 +#define IEEE80211_VAP_SCAN 0x01000000 +#define IEEE80211_ALL_SCANS 0x04000000 + +/** + * host scan bit. only relevant for host/target architecture. + * do not reuse this bit definition. target uses this . + * + */ +#define IEEE80211_HOST_SCAN 0x80000000 +#define IEEE80211_SCAN_CLASS_MASK 0xFF000000 + +#define IEEE80211_SCAN_PASSIVE 0x0001 /* passively scan all the channels */ +#define IEEE80211_SCAN_ACTIVE 0x0002 /* actively scan all the channels (regdomain rules still apply) */ +#define IEEE80211_SCAN_2GHZ 0x0004 /* scan 2GHz band */ +#define IEEE80211_SCAN_5GHZ 0x0008 /* scan 5GHz band */ +#define IEEE80211_SCAN_ALLBANDS (IEEE80211_SCAN_5GHZ | IEEE80211_SCAN_2GHZ) +#define IEEE80211_SCAN_CONTINUOUS 0x0010 /* keep scanning until maxscantime expires */ +#define IEEE80211_SCAN_FORCED 0x0020 /* forced scan (OS request) - should proceed even in the presence of data traffic */ +#define IEEE80211_SCAN_NOW 0x0040 /* scan now (User request) - should proceed even in the presence of data traffic */ +#define IEEE80211_SCAN_ADD_BCAST_PROBE 0x0080 /* add wildcard ssid and broadcast probe request if there is none */ +#define IEEE80211_SCAN_EXTERNAL 0x0100 /* scan requested by OS */ +#define IEEE80211_SCAN_BURST 0x0200 /* scan multiple channels before returning to BSS channel */ +#define IEEE80211_SCAN_CHAN_EVENT 0x0400 /* scan chan event for offload architectures */ +#define IEEE80211_SCAN_FILTER_PROBE_REQ 0x0800 /* Filter probe requests- applicable only for offload architectures */ + +#define IEEE80211_SCAN_PARAMS_MAX_SSID 10 +#define IEEE80211_SCAN_PARAMS_MAX_BSSID 10 + +/* flag definitions passed to scan_cancel API */ + +#define IEEE80211_SCAN_CANCEL_ASYNC 0x0 /* asynchronouly wait for scan SM to complete cancel */ +#define IEEE80211_SCAN_CANCEL_WAIT 0x1 /* wait for scan SM to complete cancel */ +#define IEEE80211_SCAN_CANCEL_SYNC 0x2 /* synchronously execute cancel scan */ + +#ifndef EXTERNAL_USE_ONLY +typedef bool (*ieee80211_scan_termination_check)(void *arg); + +typedef struct _ieee80211_scan_params { + ieee80211_scan_type type; + int min_dwell_time_active; /* min time in msec on active channels */ + int max_dwell_time_active; /* max time in msec on active channels (if no response) */ + int min_dwell_time_passive; /* min time in msec on passive channels */ + int max_dwell_time_passive; /* max time in msec on passive channels (if no response) */ + int min_rest_time; /* min time in msec on the BSS channel, only valid for BG scan */ + int max_rest_time; /* max time in msec on the BSS channel, only valid for BG scan */ + int max_offchannel_time; /* max time away from BSS channel, in ms */ + int repeat_probe_time; /* time before sending second probe request */ + int idle_time; /* time in msec on bss channel before switching channel */ + int max_scan_time; /* maximum time in msec allowed for scan */ + int probe_delay; /* delay in msec before sending probe request */ + int offchan_retry_delay; /* delay in msec before retrying off-channel switch */ + int min_beacon_count; /* number of home AP beacons to receive before leaving the home channel */ + int max_offchan_retries; /* maximum number of times to retry off-channel switch */ + int beacon_timeout; /* maximum time to wait for beacons */ + int flags; /* scan flags */ + int num_channels; /* number of channels to scan */ + bool multiple_ports_active; /* driver has multiple ports active in the home channel */ + bool restricted_scan; /* Perform restricted scan */ + bool chan_list_allocated; + IEEE80211_SCAN_PRIORITY p2p_scan_priority; /* indicates the scan priority if this is a P2P-related scan */ + uint32_t *chan_list; /* array of ieee channels (or) frequencies to scan */ + int num_ssid; /* number of desired ssids */ + ieee80211_ssid ssid_list[IEEE80211_SCAN_PARAMS_MAX_SSID]; + int num_bssid; /* number of desired bssids */ + uint8_t bssid_list[IEEE80211_SCAN_PARAMS_MAX_BSSID][IEEE80211_ADDR_LEN]; + struct ieee80211_node *bss_node; /* BSS node */ + int ie_len; /* length of the ie data to be added to probe req */ + uint8_t *ie_data; /* pointer to ie data */ + ieee80211_scan_termination_check check_termination_function; /* function checking for termination condition */ + void *check_termination_context; /* context passed to function above */ +} ieee80211_scan_params; + +/* Data types used to specify scan priorities */ +typedef uint32_t IEEE80211_PRIORITY_MAPPING[IEEE80211_SCAN_PRIORITY_COUNT]; + +/************************************** + * Called before attempting to roam. Modifies the rssiAdder of a BSS + * based on the preferred status of a BSS. + * + * According to CCX spec, AP in the neighbor list is not meant for giving extra + * weightage in roaming. By doing so, roaming becomes sticky. See bug 21220. + * Change the weightage to 0. Cisco may ask in future for a user control of + * this weightage. + */ +#define PREFERRED_BSS_RANK 20 +#define NEIGHBOR_BSS_RANK 0 /* must be less than preferred BSS rank */ + +/* + * The utility of the BSS is the metric used in the selection + * of a BSS. The Utility of the BSS is reduced if we just left the BSS. + * The Utility of the BSS is not reduced if we have left the + * BSS for 8 seconds (8000ms) or more. + * 2^13 milliseconds is a close approximation to avoid expensive division + */ +#define LAST_ASSOC_TIME_DELTA_REQUIREMENT (1 << 13) /* 8192 */ + +#define QBSS_SCALE_MAX 255 /* Qbss channel load Max value */ +#define QBSS_SCALE_DOWN_FACTOR 2 /* scale factor to reduce Qbss channel load */ +#define QBSS_HYST_ADJ 60 /* Qbss Weightage factor for the current AP */ + +/* + * Flags used to set field APState + */ +#define AP_STATE_GOOD 0x00 +#define AP_STATE_BAD 0x01 +#define AP_STATE_RETRY 0x10 +#define BAD_AP_TIMEOUT 6000 /* In milli seconds */ +/* + * To disable BAD_AP status check on any scan entry + */ +#define BAD_AP_TIMEOUT_DISABLED 0 + +/* + * BAD_AP timeout specified in seconds + */ +#define BAD_AP_TIMEOUT_IN_SECONDS 10 + +/* + * State values used to represent our assoc_state with ap (discrete, not bitmasks) + */ +#define AP_ASSOC_STATE_NONE 0 +#define AP_ASSOC_STATE_AUTH 1 +#define AP_ASSOC_STATE_ASSOC 2 + +/* + * Entries in the scan list are considered obsolete after 75 seconds. + */ +#define IEEE80211_SCAN_ENTRY_EXPIRE_TIME 75000 + +/* + * idle time is only valid for scan type IEEE80211_SCAN_BACKGROUND. + * if idle time is set then the scanner would change channel from BSS + * channel to foreign channel only if both resttime is expired and + * the theres was not traffic for idletime msec on the bss channel. + * value of 0 for idletime would cause the channel to switch from BSS + * channel to foreign channel as soon as the resttime is expired. + * + * if maxscantime is nonzero and if the scanner can not complete the + * scan in maxscantime msec then the scanner will cancel the scan and + * post IEEE80211_SCAN_COMPLETED event with reason SCAN_TIMEDOUT. + * + */ + +/* + * chanlist can be either ieee channels (or) frequencies. + * if a value is less than 1000 implementation assumes it + * as ieee channel # otherwise implementation assumes it + * as frequency in Mhz. + */ + +typedef enum _ieee80211_scan_event_type { + IEEE80211_SCAN_STARTED, + IEEE80211_SCAN_COMPLETED, + IEEE80211_SCAN_RADIO_MEASUREMENT_START, + IEEE80211_SCAN_RADIO_MEASUREMENT_END, + IEEE80211_SCAN_RESTARTED, + IEEE80211_SCAN_HOME_CHANNEL, + IEEE80211_SCAN_FOREIGN_CHANNEL, + IEEE80211_SCAN_BSSID_MATCH, + IEEE80211_SCAN_FOREIGN_CHANNEL_GET_NF, + IEEE80211_SCAN_DEQUEUED, + IEEE80211_SCAN_PREEMPTED, + + IEEE80211_SCAN_EVENT_COUNT +} ieee80211_scan_event_type; + +typedef enum ieee80211_scan_completion_reason { + IEEE80211_REASON_NONE, + IEEE80211_REASON_COMPLETED, + IEEE80211_REASON_CANCELLED, + IEEE80211_REASON_TIMEDOUT, + IEEE80211_REASON_TERMINATION_FUNCTION, + IEEE80211_REASON_MAX_OFFCHAN_RETRIES, + IEEE80211_REASON_PREEMPTED, + IEEE80211_REASON_RUN_FAILED, + IEEE80211_REASON_INTERNAL_STOP, + + IEEE80211_REASON_COUNT +} ieee80211_scan_completion_reason; + +typedef struct _ieee80211_scan_event { + ieee80211_scan_event_type type; + ieee80211_scan_completion_reason reason; + wlan_chan_t chan; + IEEE80211_SCAN_REQUESTOR requestor; /* Requestor ID passed to the scan_start function */ + IEEE80211_SCAN_ID scan_id; /* Specific ID of the scan reporting the event */ +} ieee80211_scan_event; + +typedef enum _ieee80211_scan_request_status { + IEEE80211_SCAN_STATUS_QUEUED, + IEEE80211_SCAN_STATUS_RUNNING, + IEEE80211_SCAN_STATUS_PREEMPTED, + IEEE80211_SCAN_STATUS_COMPLETED +} ieee80211_scan_request_status; + +/* + * the sentry field of tht ieee80211_scan_event is only valid if the + * event type is IEEE80211_SCAN_BSSID_MATCH. + */ + +typedef void (*ieee80211_scan_event_handler)(wlan_if_t vaphandle, + ieee80211_scan_event *event, + void *arg); + +typedef struct _ieee80211_scan_info { + ieee80211_scan_type type; + IEEE80211_SCAN_REQUESTOR requestor; /* Originator ID passed to the scan_start function */ + IEEE80211_SCAN_ID scan_id; /* Specific ID of the scan reporting the event */ + IEEE80211_SCAN_PRIORITY priority; /* Requested priority level (low/medium/high) */ + ieee80211_scan_request_status scheduling_status; /* Queued/running/preempted/completed */ + int min_dwell_time_active; /* min time in msec on active channels */ + int max_dwell_time_active; /* max time in msec on active channel (if no response) */ + int min_dwell_time_passive; /* min time in msec on passive channels */ + int max_dwell_time_passive; /* max time in msec on passive channel */ + int min_rest_time; /* min time in msec on the BSS channel, only valid for BG scan */ + int max_rest_time; /* max time in msec on the BSS channel, only valid for BG scan */ + int max_offchannel_time; /* max time away from BSS channel, in ms */ + int repeat_probe_time; /* time before sending second probe request */ + int min_beacon_count; /* number of home AP beacons to receive before leaving the home channel */ + int flags; /* scan flags */ + systime_t scan_start_time; /* system time when last scani started */ + int scanned_channels; /* number of scanned channels */ + int default_channel_list_length; /* number of channels in the default channel list */ + int channel_list_length; /* number of channels in the channel list used for the current scan */ + uint8_t in_progress : 1, /* if the scan is in progress */ + cancelled : 1, /* if the scan is cancelled */ + preempted : 1, /* if the scan is preempted */ + restricted : 1; /* if the scan is restricted */ +} ieee80211_scan_info; + +typedef struct _ieee80211_scan_request_info { + wlan_if_t vaphandle; + IEEE80211_SCAN_REQUESTOR requestor; + IEEE80211_SCAN_PRIORITY requested_priority; + IEEE80211_SCAN_PRIORITY absolute_priority; + IEEE80211_SCAN_ID scan_id; + ieee80211_scan_request_status scheduling_status; + ieee80211_scan_params params; + systime_t request_timestamp; + uint32_t maximum_duration; +} ieee80211_scan_request_info; + +#endif /* EXTERNAL_USE_ONLY */ + +#ifndef EXTERNAL_USE_ONLY +typedef void (*ieee80211_acs_event_handler)(void *arg, wlan_chan_t channel); +#endif /* EXTERNAL_USE_ONLY */ + +#define MAX_CHAINS 3 + +typedef struct _wlan_rssi_info { + int8_t avg_rssi; /* average rssi */ + uint8_t valid_mask; /* bitmap of valid elements in rssi_ctrl/ext array */ + int8_t rssi_ctrl[MAX_CHAINS]; + int8_t rssi_ext[MAX_CHAINS]; +} wlan_rssi_info; + +typedef enum _wlan_rssi_type { + WLAN_RSSI_TX, + WLAN_RSSI_RX, + WLAN_RSSI_BEACON, /* rssi of the beacon, only valid for STA/IBSS vap */ + WLAN_RSSI_RX_DATA +} wlan_rssi_type; + +typedef enum _ieee80211_rate_type { + IEEE80211_RATE_TYPE_LEGACY, + IEEE80211_RATE_TYPE_MCS, +} ieee80211_rate_type; + +typedef struct _ieee80211_rate_info { + ieee80211_rate_type type; + uint32_t rate; /* average rate in kbps */ + uint32_t lastrate; /* last packet rate in kbps */ + uint8_t mcs; /* mcs index . is valid if rate type is MCS20 or MCS40 */ + uint8_t maxrate_per_client; +} ieee80211_rate_info; + +typedef enum _ieee80211_node_param_type { + IEEE80211_NODE_PARAM_TX_POWER, + IEEE80211_NODE_PARAM_ASSOCID, + IEEE80211_NODE_PARAM_INACT, /* inactivity timer value */ + IEEE80211_NODE_PARAM_AUTH_MODE, /* auth mode */ + IEEE80211_NODE_PARAM_CAP_INFO, /* auth mode */ +} ieee80211_node_param_type; + +/* + * Per/node (station) statistics available when operating as an AP. + */ +struct ieee80211_nodestats { + uint32_t ns_rx_data; /* rx data frames */ + uint32_t ns_rx_mgmt; /* rx management frames */ + uint32_t ns_rx_ctrl; /* rx control frames */ + uint32_t ns_rx_ucast; /* rx unicast frames */ + uint32_t ns_rx_mcast; /* rx multi/broadcast frames */ + uint64_t ns_rx_bytes; /* rx data count (bytes) */ + uint64_t ns_rx_beacons; /* rx beacon frames */ + uint32_t ns_rx_proberesp; /* rx probe response frames */ + + uint32_t ns_rx_dup; /* rx discard 'cuz dup */ + uint32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */ + uint32_t ns_rx_wepfail; /* rx wep processing failed */ + uint32_t ns_rx_demicfail; /* rx demic failed */ + + /* We log MIC and decryption failures against Transmitter STA stats. + Though the frames may not actually be sent by STAs corresponding + to TA, the stats are still valuable for some customers as a sort + of rough indication. + Also note that the mapping from TA to STA may fail sometimes. */ + uint32_t ns_rx_tkipmic; /* rx TKIP MIC failure */ + uint32_t ns_rx_ccmpmic; /* rx CCMP MIC failure */ + uint32_t ns_rx_wpimic; /* rx WAPI MIC failure */ + uint32_t ns_rx_tkipicv; /* rx ICV check failed (TKIP) */ + uint32_t ns_rx_decap; /* rx decapsulation failed */ + uint32_t ns_rx_defrag; /* rx defragmentation failed */ + uint32_t ns_rx_disassoc; /* rx disassociation */ + uint32_t ns_rx_deauth; /* rx deauthentication */ + uint32_t ns_rx_action; /* rx action */ + uint32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */ + uint32_t ns_rx_unauth; /* rx on unauthorized port */ + uint32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */ + + uint32_t ns_tx_data; /* tx data frames */ + uint32_t ns_tx_data_success; /* tx data frames successfully + transmitted (unicast only) */ + uint32_t ns_tx_mgmt; /* tx management frames */ + uint32_t ns_tx_ucast; /* tx unicast frames */ + uint32_t ns_tx_mcast; /* tx multi/broadcast frames */ + uint64_t ns_tx_bytes; /* tx data count (bytes) */ + uint64_t ns_tx_bytes_success; /* tx success data count - unicast only + (bytes) */ + uint32_t ns_tx_probereq; /* tx probe request frames */ + uint32_t ns_tx_uapsd; /* tx on uapsd queue */ + uint32_t ns_tx_discard; /* tx dropped by NIC */ + + uint32_t ns_tx_novlantag; /* tx discard 'cuz no tag */ + uint32_t ns_tx_vlanmismatch; /* tx discard 'cuz bad tag */ + + uint32_t ns_tx_eosplost; /* uapsd EOSP retried out */ + + uint32_t ns_ps_discard; /* ps discard 'cuz of age */ + + uint32_t ns_uapsd_triggers; /* uapsd triggers */ + uint32_t ns_uapsd_duptriggers; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_ignoretriggers; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_active; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_triggerenabled; /* uapsd duplicate triggers */ + + /* MIB-related state */ + uint32_t ns_tx_assoc; /* [re]associations */ + uint32_t ns_tx_assoc_fail; /* [re]association failures */ + uint32_t ns_tx_auth; /* [re]authentications */ + uint32_t ns_tx_auth_fail; /* [re]authentication failures */ + uint32_t ns_tx_deauth; /* deauthentications */ + uint32_t ns_tx_deauth_code; /* last deauth reason */ + uint32_t ns_tx_disassoc; /* disassociations */ + uint32_t ns_tx_disassoc_code; /* last disassociation reason */ + uint32_t ns_psq_drops; /* power save queue drops */ +}; + +/* + * station power save mode. + */ +typedef enum ieee80211_psmode { + IEEE80211_PWRSAVE_NONE = 0, /* no power save */ + IEEE80211_PWRSAVE_LOW, + IEEE80211_PWRSAVE_NORMAL, + IEEE80211_PWRSAVE_MAXIMUM, + IEEE80211_PWRSAVE_WNM /* WNM-Sleep Mode */ +} ieee80211_pwrsave_mode; + +/* station power save pspoll handling */ +typedef enum { + IEEE80211_CONTINUE_PSPOLL_FOR_MORE_DATA, + IEEE80211_WAKEUP_FOR_MORE_DATA, +} ieee80211_pspoll_moredata_handling; + +/* + * apps power save state. + */ +typedef enum { + APPS_AWAKE = 0, + APPS_PENDING_SLEEP, + APPS_SLEEP, + APPS_FAKE_SLEEP, /* Pending blocking sleep */ + APPS_FAKING_SLEEP, /* Blocking sleep */ + APPS_UNKNOWN_PWRSAVE, +} ieee80211_apps_pwrsave_state; + +typedef enum _iee80211_mimo_powersave_mode { + IEEE80211_MIMO_POWERSAVE_NONE, /* no mimo power save */ + IEEE80211_MIMO_POWERSAVE_STATIC, /* static mimo power save */ + IEEE80211_MIMO_POWERSAVE_DYNAMIC /* dynamic mimo powersave */ +} ieee80211_mimo_powersave_mode; + +#ifdef ATH_COALESCING +typedef enum _ieee80211_coalescing_state { + IEEE80211_COALESCING_DISABLED = 0, /* Coalescing is disabled */ + IEEE80211_COALESCING_DYNAMIC = 1, /* Dynamically move to Enabled state based on Uruns */ + IEEE80211_COALESCING_ENABLED = 2, /* Coalescing is enabled */ +} ieee80211_coalescing_state; + +#define IEEE80211_TX_COALESCING_THRESHOLD 5 /* Number of underrun errors to trigger coalescing */ +#endif + +typedef enum _ieee80211_cap { + IEEE80211_CAP_SHSLOT, /* CAPABILITY: short slot */ + IEEE80211_CAP_SHPREAMBLE, /* CAPABILITY: short premable */ + IEEE80211_CAP_MULTI_DOMAIN, /* CAPABILITY: multiple domain */ + IEEE80211_CAP_WMM, /* CAPABILITY: WMM */ + IEEE80211_CAP_HT, /* CAPABILITY: HT */ + IEEE80211_CAP_PERF_PWR_OFLD, /* CAPABILITY: power performance offload support */ + IEEE80211_CAP_11AC, /* CAPABILITY: 11ac support */ +} ieee80211_cap; + +typedef enum _ieee80211_device_param { + IEEE80211_DEVICE_RSSI_CTL, + IEEE80211_DEVICE_NUM_TX_CHAIN, + IEEE80211_DEVICE_NUM_RX_CHAIN, + IEEE80211_DEVICE_TX_CHAIN_MASK, + IEEE80211_DEVICE_RX_CHAIN_MASK, + IEEE80211_DEVICE_TX_CHAIN_MASK_LEGACY, + IEEE80211_DEVICE_RX_CHAIN_MASK_LEGACY, + IEEE80211_DEVICE_BMISS_LIMIT, /* # of beacon misses for HW to generate BMISS intr */ + IEEE80211_DEVICE_PROTECTION_MODE, /* protection mode */ + IEEE80211_DEVICE_BLKDFSCHAN, /* block the use of DFS channels */ + IEEE80211_DEVICE_GREEN_AP_PS_ENABLE, + IEEE80211_DEVICE_GREEN_AP_PS_TIMEOUT, + IEEE80211_DEVICE_GREEN_AP_PS_ON_TIME, + IEEE80211_DEVICE_CWM_EXTPROTMODE, + IEEE80211_DEVICE_CWM_EXTPROTSPACING, + IEEE80211_DEVICE_CWM_ENABLE, + IEEE80211_DEVICE_CWM_EXTBUSYTHRESHOLD, + IEEE80211_DEVICE_DOTH, + IEEE80211_DEVICE_ADDBA_MODE, + IEEE80211_DEVICE_COUNTRYCODE, + IEEE80211_DEVICE_MULTI_CHANNEL, /* turn on/off off channel support */ + IEEE80211_DEVICE_MAX_AMSDU_SIZE, /* Size of AMSDU to be sent on the air */ + IEEE80211_DEVICE_P2P, /* Enable or Disable P2P */ + IEEE80211_DEVICE_OVERRIDE_SCAN_PROBERESPONSE_IE, /* Override scan Probe response IE, 0: Don't over-ride */ + IEEE80211_DEVICE_2G_CSA, + IEEE80211_DEVICE_PWRTARGET, + IEEE80211_DEVICE_OFF_CHANNEL_SUPPORT, +} ieee80211_device_param; + +typedef enum _ieee80211_param { + IEEE80211_BEACON_INTVAL, /* in TUs */ + IEEE80211_LISTEN_INTVAL, /* number of beacons */ + IEEE80211_DTIM_INTVAL, /* number of beacons */ + IEEE80211_BMISS_COUNT_RESET, /* number of beacon miss intrs before reset */ + IEEE80211_BMISS_COUNT_MAX, /* number of beacon miss intrs for bmiss notificationst */ + IEEE80211_ATIM_WINDOW, /* ATIM window */ + IEEE80211_SHORT_SLOT, /* short slot on/off */ + IEEE80211_SHORT_PREAMBLE, /* short preamble on/off */ + IEEE80211_RTS_THRESHOLD, /* rts threshold, 0 means no rts threshold */ + IEEE80211_FRAG_THRESHOLD, /* fragmentation threshold, 0 means no rts threshold */ + IEEE80211_FIXED_RATE, /* + * rate code series(0: auto rate, 32 bit value: rate + * codes for 4 rate series. each byte for one rate series) + */ + IEEE80211_MCAST_RATE, /* rate in Kbps */ + IEEE80211_TXPOWER, /* in 0.5db units */ + IEEE80211_AMPDU_DENCITY, /* AMPDU dencity */ + IEEE80211_AMPDU_LIMIT, /* AMPDU limit */ + IEEE80211_MAX_AMPDU, /* Max AMPDU Exp */ + IEEE80211_VHT_MAX_AMPDU, /* VHT Max AMPDU Exp */ + IEEE80211_WPS_MODE, /* WPS mode */ + IEEE80211_TSN_MODE, /* TSN mode */ + IEEE80211_MULTI_DOMAIN, /* Multiple domain */ + IEEE80211_SAFE_MODE, /* Safe mode */ + IEEE80211_NOBRIDGE_MODE, /* No bridging done, all frames sent up the stack */ + IEEE80211_PERSTA_KEYTABLE_SIZE, /* IBSS-only, read-only: persta key table size */ + IEEE80211_RECEIVE_80211, /* deliver std 802.11 frames 802.11 instead of ethernet frames on the rx */ + IEEE80211_SEND_80211, /* OS sends std 802.11 frames 802.11 instead of ethernet frames on tx side */ + IEEE80211_MIN_BEACON_COUNT, /* minimum number beacons to tx/rx before vap can pause */ + IEEE80211_IDLE_TIME, /* minimun no activity time before vap can pause */ + IEEE80211_MIN_FRAMESIZE, /* smallest frame size we are allowed to receive */ + /* features. 0:feature is off. 1:feature is on. */ + IEEE80211_FEATURE_WMM, /* WMM */ + IEEE80211_FEATURE_WMM_PWRSAVE, /* WMM Power Save */ + IEEE80211_FEATURE_UAPSD, /* UAPSD setting (BE/BK/VI/VO) */ + IEEE80211_FEATURE_WDS, /* dynamic WDS feature */ + IEEE80211_FEATURE_PRIVACY, /* encryption */ + IEEE80211_FEATURE_DROP_UNENC, /* drop un encrypted frames */ + IEEE80211_FEATURE_COUNTER_MEASURES, /* turn on counter measures */ + IEEE80211_FEATURE_HIDE_SSID, /* turn on hide ssid feature */ + IEEE80211_FEATURE_APBRIDGE, /* turn on internal mcast traffic bridging for AP */ + IEEE80211_FEATURE_PUREB, /* turn on pure B mode for AP */ + IEEE80211_FEATURE_PUREG, /* turn on pure G mode for AP */ + IEEE80211_FEATURE_REGCLASS, /* add regulatory class IE in AP */ + IEEE80211_FEATURE_COUNTRY_IE, /* add country IE for vap in AP */ + IEEE80211_FEATURE_IC_COUNTRY_IE, /* add country IE for ic in AP */ + IEEE80211_FEATURE_DOTH, /* enable 802.11h */ + IEEE80211_FEATURE_PURE11N, /* enable pure 11n mode */ + IEEE80211_FEATURE_PRIVATE_RSNIE, /* enable OS shim to setup RSN IE */ + IEEE80211_FEATURE_COPY_BEACON, /* keep a copy of beacon */ + IEEE80211_FEATURE_PSPOLL, /* enable/disable pspoll mode in power save SM */ + IEEE80211_FEATURE_CONTINUE_PSPOLL_FOR_MOREDATA, /* enable/disable option to contunue sending ps polls when there is more data */ + IEEE80211_FEATURE_AMPDU, /* Enable or Disable Aggregation */ +#ifdef ATH_COALESCING + IEEE80211_FEATURE_TX_COALESCING, /* enable tx coalescing */ +#endif + IEEE80211_FEATURE_VAP_IND, /* Repeater independent VAP */ + IEEE80211_FIXED_RETRIES, /* fixed retries 0-4 */ + IEEE80211_SHORT_GI, /* short gi on/off */ + IEEE80211_HT40_INTOLERANT, + IEEE80211_CHWIDTH, + IEEE80211_CHEXTOFFSET, + IEEE80211_DISABLE_2040COEXIST, + IEEE80211_DISABLE_HTPROTECTION, + IEEE80211_STA_QUICKKICKOUT, + IEEE80211_CHSCANINIT, + IEEE80211_FEATURE_STAFWD, /* dynamic AP Client feature */ + IEEE80211_DRIVER_CAPS, + IEEE80211_UAPSD_MAXSP, /* UAPSD service period setting (0:unlimited, 2,4,6) */ + IEEE80211_WEP_MBSSID, + IEEE80211_MGMT_RATE, /* ieee rate to be used for management */ + IEEE80211_RESMGR_VAP_AIR_TIME_LIMIT, /* When multi-channel enabled, restrict air-time allocated to a VAP */ + IEEE80211_TDLS_MACADDR1, /* Upper 4 bytes of device's MAC address */ + IEEE80211_TDLS_MACADDR2, /* Lower 2 bytes of device's MAC address */ + IEEE80211_TDLS_ACTION, /* TDLS action requested */ + IEEE80211_AUTO_ASSOC, + IEEE80211_PROTECTION_MODE, /* per VAP protection mode */ + IEEE80211_AUTH_INACT_TIMEOUT, /* inactivity time while waiting for 802.11x auth to complete */ + IEEE80211_INIT_INACT_TIMEOUT, /* inactivity time while waiting for 802.11 auth/assoc to complete */ + IEEE80211_RUN_INACT_TIMEOUT, /* inactivity time when fully authed */ + IEEE80211_PROBE_INACT_TIMEOUT, /* inactivity counter value below which starts probing */ + IEEE80211_QBSS_LOAD, + IEEE80211_WNM_CAP, + IEEE80211_WNM_BSS_CAP, + IEEE80211_WNM_TFS_CAP, + IEEE80211_WNM_TIM_CAP, + IEEE80211_WNM_SLEEP_CAP, + IEEE80211_WNM_FMS_CAP, + IEEE80211_AP_REJECT_DFS_CHAN, /* AP to reject resuming on DFS Channel */ + IEEE80211_ABOLT, + IEEE80211_COMP, + IEEE80211_FF, + IEEE80211_TURBO, + IEEE80211_BURST, + IEEE80211_AR, + IEEE80211_SLEEP, + IEEE80211_EOSPDROP, + IEEE80211_MARKDFS, + IEEE80211_WDS_AUTODETECT, + IEEE80211_WEP_TKIP_HT, + IEEE80211_ATH_RADIO, + IEEE80211_IGNORE_11DBEACON, + /* Video debug feature */ + IEEE80211_VI_DBG_CFG, /* Video debug configuration - Bit0- enable dbg, Bit1 - enable stats log */ + IEEE80211_VI_DBG_NUM_STREAMS, /* Total number of receive streams */ + IEEE80211_VI_STREAM_NUM, /* the stream number whose marker parameters are being set */ + IEEE80211_VI_DBG_NUM_MARKERS, /* total number of markers used to filter pkts */ + IEEE80211_VI_MARKER_NUM, /* the marker number whose parameters (offset, size & match) are being set */ + IEEE80211_VI_MARKER_OFFSET_SIZE, /* byte offset from skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_MARKER_MATCH, /* marker pattern match used in filtering */ + IEEE80211_VI_RXSEQ_OFFSET_SIZE, /* Rx Seq num offset skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_RX_SEQ_RSHIFT, /* right-shift value in case field is not word aligned */ + IEEE80211_VI_RX_SEQ_MAX, /* maximum Rx Seq number (to check wrap around) */ + IEEE80211_VI_RX_SEQ_DROP, /* Indicator to the debug app that a particular seq num has been dropped */ + IEEE80211_VI_TIME_OFFSET_SIZE, /* Timestamp offset skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_RESTART, /* If set to 1 resets all internal variables/counters & restarts debug tool */ + IEEE80211_VI_RXDROP_STATUS, /* Total RX drops in wireless */ + IEEE80211_TRIGGER_MLME_RESP, /* Option for App to trigger mlme response */ +#ifdef ATH_SUPPORT_TxBF + IEEE80211_TXBF_AUTO_CVUPDATE, /* auto CV update enable */ + IEEE80211_TXBF_CVUPDATE_PER, /* per threshold to initial CV update */ +#endif + IEEE80211_MAX_CLIENT_NUMBERS, + IEEE80211_SMARTNET, + IEEE80211_FEATURE_MFP_TEST, /* MFP test */ + IEEE80211_WEATHER_RADAR, /* weather radar channel skip */ + IEEE80211_WEP_KEYCACHE, /* WEP KEYCACHE is enable */ + IEEE80211_SEND_DEAUTH, /* send deauth instead of disassoc while doing interface down */ + IEEE80211_SET_TXPWRADJUST, + IEEE80211_RRM_CAP, + IEEE80211_RRM_DEBUG, + IEEE80211_RRM_STATS, + IEEE80211_RRM_SLWINDOW, + IEEE80211_FEATURE_OFF_CHANNEL_SUPPORT, + IEEE80211_FIXED_VHT_MCS, /* VHT mcs index */ + IEEE80211_FIXED_NSS, /* Spatial Streams count */ + IEEE80211_SUPPORT_LDPC, /* LDPC Support */ + IEEE80211_SUPPORT_TX_STBC, /* TX STBC enable/disable */ + IEEE80211_SUPPORT_RX_STBC, /* RX STBC enable/disable */ + IEEE80211_DEFAULT_KEYID, /* XMIT default key */ + IEEE80211_OPMODE_NOTIFY_ENABLE, /* Op mode notification enable/disable */ + IEEE80211_ENABLE_RTSCTS, /* Enable/Disable RTS-CTS */ + IEEE80211_VHT_MCSMAP, /* VHT MCS Map */ + IEEE80211_GET_ACS_STATE, /* get acs state */ + IEEE80211_GET_CAC_STATE, /* get cac state */ +} ieee80211_param; + +#define IEEE80211_PROTECTION_NONE 0 +#define IEEE80211_PROTECTION_CTSTOSELF 1 +#define IEEE80211_PROTECTION_RTS_CTS 2 + +typedef enum _ieee80211_privacy_filter { + IEEE80211_PRIVACY_FILTER_ALLWAYS, + IEEE80211_PRIVACY_FILTER_KEY_UNAVAILABLE, +} ieee80211_privacy_filter; + +typedef enum _ieee80211_privacy_filter_packet_type { + IEEE80211_PRIVACY_FILTER_PACKET_UNICAST, + IEEE80211_PRIVACY_FILTER_PACKET_MULTICAST, + IEEE80211_PRIVACY_FILTER_PACKET_BOTH +} ieee80211_privacy_filter_packet_type; + +typedef struct _ieee80211_privacy_excemption_filter { + uint16_t ether_type; /* type of ethernet to apply this filter, in host byte order */ + ieee80211_privacy_filter filter_type; + ieee80211_privacy_filter_packet_type packet_type; +} ieee80211_privacy_exemption; + +/* + * Authentication mode. + * NB: the usage of auth modes NONE, AUTO are deprecated, + * they are implemented through combinations of other auth modes + * and cipher types. The deprecated values are preserved here to + * maintain binary compatibility with applications like + * wpa_supplicant and hostapd. + */ +typedef enum _ieee80211_auth_mode { + IEEE80211_AUTH_NONE = 0, /* deprecated */ + IEEE80211_AUTH_OPEN = 1, /* open */ + IEEE80211_AUTH_SHARED = 2, /* shared-key */ + IEEE80211_AUTH_8021X = 3, /* 802.1x */ + IEEE80211_AUTH_AUTO = 4, /* deprecated */ + IEEE80211_AUTH_WPA = 5, /* WPA */ + IEEE80211_AUTH_RSNA = 6, /* WPA2/RSNA */ + IEEE80211_AUTH_CCKM = 7, /* CCK */ + IEEE80211_AUTH_WAPI = 8, /* WAPI */ +} ieee80211_auth_mode; + +#define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WAPI+1) + +/* + * Cipher types. + * NB: The values are preserved here to maintain binary compatibility + * with applications like wpa_supplicant and hostapd. + */ +typedef enum _ieee80211_cipher_type { + IEEE80211_CIPHER_WEP = 0, + IEEE80211_CIPHER_TKIP = 1, + IEEE80211_CIPHER_AES_OCB = 2, + IEEE80211_CIPHER_AES_CCM = 3, + IEEE80211_CIPHER_WAPI = 4, + IEEE80211_CIPHER_CKIP = 5, + IEEE80211_CIPHER_AES_CMAC = 6, + IEEE80211_CIPHER_NONE = 7, +} ieee80211_cipher_type; + +#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+1) + +/* key direction */ +typedef enum _ieee80211_key_direction { + IEEE80211_KEY_DIR_TX, + IEEE80211_KEY_DIR_RX, + IEEE80211_KEY_DIR_BOTH +} ieee80211_key_direction; + +#define IEEE80211_KEYIX_NONE ((uint16_t) -1) + +typedef struct _ieee80211_keyval { + ieee80211_cipher_type keytype; + ieee80211_key_direction keydir; + u_int persistent : 1, /* persistent key */ + mfp : 1; /* management frame protection */ + uint16_t keylen; /* length of the key data fields */ + uint8_t *macaddr; /* mac address of length IEEE80211_ADDR_LEN . all bytes are 0xff for multicast key */ + uint64_t keyrsc; + uint64_t keytsc; + uint16_t txmic_offset; /* TKIP/SMS4 only: offset to tx mic key */ + uint16_t rxmic_offset; /* TKIP/SMS4 only: offset to rx mic key */ + uint8_t *keydata; +#ifdef ATH_SUPPORT_WAPI + uint8_t key_used; /*index for WAPI rekey labeling */ +#endif +} ieee80211_keyval; + +#define IEEE80211_AES_CMAC_LEN 128 +typedef enum _ieee80211_rsn_param { + IEEE80211_UCAST_CIPHER_LEN, + IEEE80211_MCAST_CIPHER_LEN, + IEEE80211_MCASTMGMT_CIPHER_LEN, + IEEE80211_KEYMGT_ALGS, + IEEE80211_RSN_CAPS +} ieee80211_rsn_param; + +#define IEEE80211_PMKID_LEN 16 + +typedef struct _ieee80211_pmkid_entry { + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint8_t pmkid[IEEE80211_PMKID_LEN]; +} ieee80211_pmkid_entry; + +typedef enum _wlan_wme_param { + WLAN_WME_CWMIN, + WLAN_WME_CWMAX, + WLAN_WME_AIFS, + WLAN_WME_TXOPLIMIT, + WLAN_WME_ACM, /*bss only */ + WLAN_WME_ACKPOLICY /*bss only */ +} wlan_wme_param; + +typedef enum _ieee80211_frame_type { + IEEE80211_FRAME_TYPE_PROBEREQ, + IEEE80211_FRAME_TYPE_BEACON, + IEEE80211_FRAME_TYPE_PROBERESP, + IEEE80211_FRAME_TYPE_ASSOCREQ, + IEEE80211_FRAME_TYPE_ASSOCRESP, + IEEE80211_FRAME_TYPE_AUTH +} ieee80211_frame_type; + +#define IEEE80211_FRAME_TYPE_MAX (IEEE80211_FRAME_TYPE_AUTH+1) + +typedef enum _ieee80211_ampdu_mode { + IEEE80211_AMPDU_MODE_OFF, /* disable AMPDU */ + IEEE80211_AMPDU_MODE_ON, /* enable AMPDU */ + IEEE80211_AMPDU_MODE_WDSVAR /* enable AMPDU with 4addr WAR */ +} ieee80211_ampdu_mode; + +typedef enum _ieee80211_reset_type { + IEEE80211_RESET_TYPE_DEVICE = 0, /* device reset on error: tx timeout and etc. */ + IEEE80211_RESET_TYPE_DOT11_INTF, /* dot11 reset: only reset one network interface (vap) */ + IEEE80211_RESET_TYPE_INTERNAL, /* internal reset */ +} ieee80211_reset_type; + +typedef struct _ieee80211_reset_request { + ieee80211_reset_type type; + + u_int reset_hw : 1, /* reset the actual H/W */ + /* + * The following fields are only valid for DOT11 reset, i.e., + * IEEE80211_RESET_TYPE_DOT11_INTF + */ + reset_phy : 1, /* reset PHY */ + reset_mac : 1, /* reset MAC */ + set_default_mib : 1, /* set default MIB variables */ + no_flush : 1; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + enum ieee80211_phymode phy_mode; +} ieee80211_reset_request; + +#define IEEE80211_MSG_MAX 63 +#define IEEE80211_MSG_SMARTANT 7 /* Bit 7 (0x80)for Smart Antenna debug */ +enum { + /* IEEE80211_PARAM_DBG_LVL */ + IEEE80211_MSG_TDLS = 0, /* TDLS */ + IEEE80211_MSG_ACS, /* auto channel selection */ + IEEE80211_MSG_SCAN_SM, /* scan state machine */ + IEEE80211_MSG_SCANENTRY, /* scan entry */ + IEEE80211_MSG_WDS, /* WDS handling */ + IEEE80211_MSG_ACTION, /* action management frames */ + IEEE80211_MSG_ROAM, /* sta-mode roaming */ + IEEE80211_MSG_INACT, /* inactivity handling */ + IEEE80211_MSG_DOTH = 8, /* 11.h */ + IEEE80211_MSG_IQUE, /* IQUE features */ + IEEE80211_MSG_WME, /* WME protocol */ + IEEE80211_MSG_ACL, /* ACL handling */ + IEEE80211_MSG_WPA, /* WPA/RSN protocol */ + IEEE80211_MSG_RADKEYS, /* dump 802.1x keys */ + IEEE80211_MSG_RADDUMP, /* dump 802.1x radius packets */ + IEEE80211_MSG_RADIUS, /* 802.1x radius client */ + IEEE80211_MSG_DOT1XSM = 16, /* 802.1x state machine */ + IEEE80211_MSG_DOT1X, /* 802.1x authenticator */ + IEEE80211_MSG_POWER, /* power save handling */ + IEEE80211_MSG_STATE, /* state machine */ + IEEE80211_MSG_OUTPUT, /* output handling */ + IEEE80211_MSG_SCAN, /* scanning */ + IEEE80211_MSG_AUTH, /* authentication handling */ + IEEE80211_MSG_ASSOC, /* association handling */ + IEEE80211_MSG_NODE = 24, /* node handling */ + IEEE80211_MSG_ELEMID, /* element id parsing */ + IEEE80211_MSG_XRATE, /* rate set handling */ + IEEE80211_MSG_INPUT, /* input handling */ + IEEE80211_MSG_CRYPTO, /* crypto work */ + IEEE80211_MSG_DUMPPKTS, /* IFF_LINK2 equivalant */ + IEEE80211_MSG_DEBUG, /* IFF_DEBUG equivalent */ + IEEE80211_MSG_MLME, /* MLME */ + /* IEEE80211_PARAM_DBG_LVL_HIGH */ + IEEE80211_MSG_RRM = 32, /* Radio resource measurement */ + IEEE80211_MSG_WNM, /* Wireless Network Management */ + IEEE80211_MSG_P2P_PROT, /* P2P Protocol driver */ + IEEE80211_MSG_PROXYARP, /* 11v Proxy ARP */ + IEEE80211_MSG_L2TIF, /* Hotspot 2.0 L2 TIF */ + IEEE80211_MSG_WIFIPOS, /* WifiPositioning Feature */ + IEEE80211_MSG_WRAP, /* WRAP or Wireless ProxySTA */ + IEEE80211_MSG_DFS, /* DFS debug mesg */ + + IEEE80211_MSG_NUM_CATEGORIES, /* total ieee80211 messages */ + IEEE80211_MSG_UNMASKABLE = IEEE80211_MSG_MAX, /* anything */ + IEEE80211_MSG_ANY = IEEE80211_MSG_MAX, /* anything */ +}; + +/* verbosity levels */ +#define IEEE80211_VERBOSE_OFF 100 +#define IEEE80211_VERBOSE_FORCE 1 +#define IEEE80211_VERBOSE_SERIOUS 2 +#define IEEE80211_VERBOSE_NORMAL 3 +#define IEEE80211_VERBOSE_LOUD 4 +#define IEEE80211_VERBOSE_DETAILED 5 +#define IEEE80211_VERBOSE_COMPLEX 6 +#define IEEE80211_VERBOSE_FUNCTION 7 +#define IEEE80211_VERBOSE_TRACE 8 + +#define IEEE80211_DEBUG_DEFAULT IEEE80211_MSG_DEBUG + +/* + * the lower 4 bits of the msg flags are used for extending the + * debug flags. + */ + +/* + * flag definitions for wlan_mlme_stop_bss(vap) API. + */ +#define WLAN_MLME_STOP_BSS_F_SEND_DEAUTH 0x01 +#define WLAN_MLME_STOP_BSS_F_CLEAR_ASSOC_STATE 0x02 +#define WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET 0x04 +#define WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE 0x08 +#define WLAN_MLME_STOP_BSS_F_NO_RESET 0x10 +#define WLAN_MLME_STOP_BSS_F_STANDBY 0x20 + +/* + * WAPI commands to authenticator + */ +#define WAPI_WAI_REQUEST (uint16_t)0x00F1 +#define WAPI_UNICAST_REKEY (uint16_t)0x00F2 +#define WAPI_STA_AGING (uint16_t)0x00F3 +#define WAPI_MULTI_REKEY (uint16_t)0x00F4 +#define WAPI_STA_STATS (uint16_t)0x00F5 + +/* + * IEEE80211 PHY Statistics. + */ +struct ieee80211_phy_stats { + uint64_t ips_tx_packets; /* frames successfully transmitted */ + uint64_t ips_tx_multicast; /* multicast/broadcast frames successfully transmitted */ + uint64_t ips_tx_fragments; /* fragments successfully transmitted */ + uint64_t ips_tx_xretries; /* frames that are xretried. NB: not number of retries */ + uint64_t ips_tx_retries; /* frames transmitted after retries. NB: not number of retries */ + uint64_t ips_tx_multiretries; /* frames transmitted after more than one retry. */ + uint64_t ips_tx_timeout; /* frames that expire the dot11MaxTransmitMSDULifetime */ + uint64_t ips_rx_packets; /* frames successfully received */ + uint64_t ips_rx_multicast; /* multicast/broadcast frames successfully received */ + uint64_t ips_rx_fragments; /* fragments successfully received */ + uint64_t ips_rx_timeout; /* frmaes that expired the dot11MaxReceiveLifetime */ + uint64_t ips_rx_dup; /* duplicated fragments */ + uint64_t ips_rx_mdup; /* multiple duplicated fragments */ + uint64_t ips_rx_promiscuous; /* frames that are received only because promiscuous filter is on */ + uint64_t ips_rx_promiscuous_fragments; /* fragments that are received only because promiscuous filter is on */ + uint64_t ips_tx_rts; /* RTS success count */ + uint64_t ips_tx_shortretry; /* tx on-chip retries (short). RTSFailCnt */ + uint64_t ips_tx_longretry; /* tx on-chip retries (long). DataFailCnt */ + uint64_t ips_rx_crcerr; /* rx failed 'cuz of bad CRC */ + uint64_t ips_rx_fifoerr; /* rx failed 'cuz of FIFO overrun */ + uint64_t ips_rx_decrypterr; /* rx decryption error */ +}; + +struct ieee80211_chan_stats { + uint32_t chan_clr_cnt; + uint32_t cycle_cnt; + uint32_t phy_err_cnt; +}; + +struct ieee80211_mac_stats { + uint64_t ims_tx_packets; /* frames successfully transmitted */ + uint64_t ims_rx_packets; /* frames successfully received */ + uint64_t ims_tx_bytes; /* bytes successfully transmitted */ + uint64_t ims_rx_bytes; /* bytes successfully received */ + + /* TODO: For the byte counts below, we need to handle some scenarios + such as encryption related decaps, etc */ + uint64_t ims_tx_data_packets; /* data frames successfully transmitted */ + uint64_t ims_rx_data_packets; /* data frames successfully received */ + uint64_t ims_tx_data_bytes; /* data bytes successfully transmitted, + inclusive of FCS. */ + uint64_t ims_rx_data_bytes; /* data bytes successfully received, + inclusive of FCS. */ + + uint64_t ims_tx_datapyld_bytes; /* data payload bytes successfully + transmitted */ + uint64_t ims_rx_datapyld_bytes; /* data payload successfully + received */ + + /* Decryption errors */ + uint64_t ims_rx_unencrypted; /* rx w/o wep and privacy on */ + uint64_t ims_rx_badkeyid; /* rx w/ incorrect keyid */ + uint64_t ims_rx_decryptok; /* rx decrypt okay */ + uint64_t ims_rx_decryptcrc; /* rx decrypt failed on crc */ + uint64_t ims_rx_wepfail; /* rx wep processing failed */ + uint64_t ims_rx_tkipreplay; /* rx seq# violation (TKIP) */ + uint64_t ims_rx_tkipformat; /* rx format bad (TKIP) */ + uint64_t ims_rx_tkipmic; /* rx MIC check failed (TKIP) */ + uint64_t ims_rx_tkipicv; /* rx ICV check failed (TKIP) */ + uint64_t ims_rx_ccmpreplay; /* rx seq# violation (CCMP) */ + uint64_t ims_rx_ccmpformat; /* rx format bad (CCMP) */ + uint64_t ims_rx_ccmpmic; /* rx MIC check failed (CCMP) */ +/*this file can be included by applications as 80211stats that has no such MACRO definition*/ +/* #if ATH_SUPPORT_WAPI */ + uint64_t ims_rx_wpireplay; /* rx seq# violation (WPI) */ + uint64_t ims_rx_wpimic; /* rx MIC check failed (WPI) */ +/* #endif */ + /* Other Tx/Rx errors */ + uint64_t ims_tx_discard; /* tx dropped by NIC */ + uint64_t ims_rx_discard; /* rx dropped by NIC */ + + uint64_t ims_rx_countermeasure; /* rx TKIP countermeasure activation count */ +}; + +/* + * Summary statistics. + */ +struct ieee80211_stats { + uint32_t is_rx_badversion; /* rx frame with bad version */ + uint32_t is_rx_tooshort; /* rx frame too short */ + uint32_t is_rx_wrongbss; /* rx from wrong bssid */ + uint32_t is_rx_wrongdir; /* rx w/ wrong direction */ + uint32_t is_rx_mcastecho; /* rx discard 'cuz mcast echo */ + uint32_t is_rx_notassoc; /* rx discard 'cuz sta !assoc */ + uint32_t is_rx_noprivacy; /* rx w/ wep but privacy off */ + uint32_t is_rx_decap; /* rx decapsulation failed */ + uint32_t is_rx_mgtdiscard; /* rx discard mgt frames */ + uint32_t is_rx_ctl; /* rx discard ctrl frames */ + uint32_t is_rx_beacon; /* rx beacon frames */ + uint32_t is_rx_rstoobig; /* rx rate set truncated */ + uint32_t is_rx_elem_missing; /* rx required element missing */ + uint32_t is_rx_elem_toobig; /* rx element too big */ + uint32_t is_rx_elem_toosmall; /* rx element too small */ + uint32_t is_rx_elem_unknown; /* rx element unknown */ + uint32_t is_rx_badchan; /* rx frame w/ invalid chan */ + uint32_t is_rx_chanmismatch; /* rx frame chan mismatch */ + uint32_t is_rx_nodealloc; /* rx frame dropped */ + uint32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */ + uint32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */ + uint32_t is_rx_auth_fail; /* rx sta auth failure */ + uint32_t is_rx_auth_countermeasures; /* rx auth discard 'cuz CM */ + uint32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */ + uint32_t is_rx_assoc_notauth; /* rx assoc w/o auth */ + uint32_t is_rx_assoc_capmismatch; /* rx assoc w/ cap mismatch */ + uint32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */ + uint32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */ + uint32_t is_rx_deauth; /* rx deauthentication */ + uint32_t is_rx_disassoc; /* rx disassociation */ + uint32_t is_rx_action; /* rx action mgt */ + uint32_t is_rx_badsubtype; /* rx frame w/ unknown subtype */ + uint32_t is_rx_nobuf; /* rx failed for lack of buf */ + uint32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame */ + uint32_t is_rx_bad_auth; /* rx bad auth request */ + uint32_t is_rx_unauth; /* rx on unauthorized port */ + uint32_t is_rx_badcipher; /* rx failed 'cuz key type */ + uint32_t is_tx_nodefkey; /* tx failed 'cuz no defkey */ + uint32_t is_tx_noheadroom; /* tx failed 'cuz no space */ + uint32_t is_rx_nocipherctx; /* rx failed 'cuz key !setup */ + uint32_t is_rx_acl; /* rx discard 'cuz acl policy */ + uint32_t is_rx_ffcnt; /* rx fast frames */ + uint32_t is_rx_badathtnl; /* driver key alloc failed */ + uint32_t is_rx_nowds; /* 4-addr packets received with no wds enabled */ + uint32_t is_tx_nobuf; /* tx failed for lack of buf */ + uint32_t is_tx_nonode; /* tx failed for no node */ + uint32_t is_tx_unknownmgt; /* tx of unknown mgt frame */ + uint32_t is_tx_badcipher; /* tx failed 'cuz key type */ + uint32_t is_tx_ffokcnt; /* tx fast frames sent success */ + uint32_t is_tx_fferrcnt; /* tx fast frames sent success */ + uint32_t is_scan_active; /* active scans started */ + uint32_t is_scan_passive; /* passive scans started */ + uint32_t is_node_timeout; /* nodes timed out inactivity */ + uint32_t is_crypto_nomem; /* no memory for crypto ctx */ + uint32_t is_crypto_tkip; /* tkip crypto done in s/w */ + uint32_t is_crypto_tkipenmic; /* tkip en-MIC done in s/w */ + uint32_t is_crypto_tkipdemic; /* tkip de-MIC done in s/w */ + uint32_t is_crypto_tkipcm; /* tkip counter measures */ + uint32_t is_crypto_ccmp; /* ccmp crypto done in s/w */ + uint32_t is_crypto_wep; /* wep crypto done in s/w */ + uint32_t is_crypto_setkey_cipher; /* cipher rejected key */ + uint32_t is_crypto_setkey_nokey; /* no key index for setkey */ + uint32_t is_crypto_delkey; /* driver key delete failed */ + uint32_t is_crypto_badcipher; /* unknown cipher */ + uint32_t is_crypto_nocipher; /* cipher not available */ + uint32_t is_crypto_attachfail; /* cipher attach failed */ + uint32_t is_crypto_swfallback; /* cipher fallback to s/w */ + uint32_t is_crypto_keyfail; /* driver key alloc failed */ + uint32_t is_crypto_enmicfail; /* en-MIC failed */ + uint32_t is_ibss_capmismatch; /* merge failed-cap mismatch */ + uint32_t is_ibss_norate; /* merge failed-rate mismatch */ + uint32_t is_ps_unassoc; /* ps-poll for unassoc. sta */ + uint32_t is_ps_badaid; /* ps-poll w/ incorrect aid */ + uint32_t is_ps_qempty; /* ps-poll w/ nothing to send */ +}; + +typedef enum _ieee80211_send_frame_type { + IEEE80211_SEND_NULL, + IEEE80211_SEND_QOSNULL, +} ieee80211_send_frame_type; + +typedef struct _ieee80211_tspec_info { + uint8_t traffic_type; + uint8_t direction; + uint8_t dot1Dtag; + uint8_t tid; + uint8_t acc_policy_edca; + uint8_t acc_policy_hcca; + uint8_t aggregation; + uint8_t psb; + uint8_t ack_policy; + uint16_t norminal_msdu_size; + uint16_t max_msdu_size; + uint32_t min_srv_interval; + uint32_t max_srv_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t srv_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; + uint16_t medium_time; +} ieee80211_tspec_info; + +#ifndef EXTERNAL_USE_ONLY +/* + * Manual ADDBA support + */ +enum { + ADDBA_SEND = 0, + ADDBA_STATUS = 1, + DELBA_SEND = 2, + ADDBA_RESP = 3, + ADDBA_CLR_RESP = 4, + SINGLE_AMSDU = 5, +}; + +enum { + ADDBA_MODE_AUTO = 0, + ADDBA_MODE_MANUAL = 1, +}; + +struct ieee80211_addba_delba_request { + wlan_dev_t ic; + uint8_t action; + uint8_t tid; + uint16_t status; + uint16_t aid; + uint32_t arg1; + uint32_t arg2; +}; +#endif /* EXTERNAL_USE_ONLY */ + +#ifdef ATH_BT_COEX +typedef enum _ieee80211_bt_coex_info_type { + IEEE80211_BT_COEX_INFO_SCHEME = 0, + IEEE80211_BT_COEX_INFO_BTBUSY = 1, +} ieee80211_bt_coex_info_type; +#endif + +struct tkip_countermeasure { + uint16_t mic_count_in_60s; + uint32_t timestamp; +}; + +enum _ieee80211_qos_frame_direction { + IEEE80211_RX_QOS_FRAME = 0, + IEEE80211_TX_QOS_FRAME = 1, + IEEE80211_TX_COMPLETE_QOS_FRAME = 2 +}; + +typedef struct ieee80211_vap_opmode_count { + int total_vaps; + int ibss_count; + int sta_count; + int wds_count; + int ahdemo_count; + int ap_count; + int monitor_count; + int btamp_count; + int unknown_count; +} ieee80211_vap_opmode_count; + +struct ieee80211_app_ie_t { + uint32_t length; + uint8_t *ie; +}; + +/* + * MAC ACL operations. + */ +enum { + IEEE80211_MACCMD_POLICY_OPEN = 0, /* set policy: no ACL's */ + IEEE80211_MACCMD_POLICY_ALLOW = 1, /* set policy: allow traffic */ + IEEE80211_MACCMD_POLICY_DENY = 2, /* set policy: deny traffic */ + IEEE80211_MACCMD_FLUSH = 3, /* flush ACL database */ + IEEE80211_MACCMD_DETACH = 4, /* detach ACL policy */ + IEEE80211_MACCMD_POLICY_RADIUS = 5, /* set policy: RADIUS managed ACLs */ +}; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_if_upperproto.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_if_upperproto.h new file mode 100644 index 0000000000000000000000000000000000000000..26c723b64782008e962b79f06e2d6bc719298690 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_if_upperproto.h @@ -0,0 +1,229 @@ +/* + * 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. + */ + +/* #ifndef _NET_IF_ETHERSUBR_H_ */ +/* #define _NET_IF_ETHERSUBR_H_ */ +#ifndef _NET_IF_UPPERPROTO_H_ +#define _NET_IF_UPPERPROTO_H_ + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +#define ETHER_TYPE_LEN 2 /* length of the Ethernet type field */ +#define ETHER_CRC_LEN 4 /* length of the Ethernet CRC */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN) +#define ETHER_MAX_LEN 1518 + +#define ETHERMTU (ETHER_MAX_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) + +/* + * Structure of a 10Mb/s Ethernet header. + */ +#ifndef _NET_ETHERNET_H_ +struct ether_header { + uint8_t ether_dhost[ETHER_ADDR_LEN]; + uint8_t ether_shost[ETHER_ADDR_LEN]; + uint16_t ether_type; +} __packed; +#endif + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 /* Appletalk AARP protocol */ +#endif +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 /* IPX over DIX protocol */ +#endif +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* ARP protocol */ +#endif +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86dd /* IPv6 */ +#endif +#ifndef ETHERTYPE_8021Q +#define ETHERTYPE_8021Q 0x8100 /* 802.1Q vlan protocol */ +#endif +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* VLAN TAG protocol */ +#endif +#ifndef TX_QUEUE_FOR_EAPOL_FRAME +#define TX_QUEUE_FOR_EAPOL_FRAME 0x7 /* queue eapol frame to queue 7 to avoid aggregation disorder */ +#endif + +/* + * define WAI ethertype + */ +#ifndef ETHERTYPE_WAI +#define ETHERTYPE_WAI 0x88b4 /* WAI/WAPI */ +#endif + +#define ETHERTYPE_OCB_TX 0x8151 +#define ETHERTYPE_OCB_RX 0x8152 + +/* + * Structure of a 48-bit Ethernet address. + */ +#if 0 +#ifndef _NET_ETHERNET_H_ +struct ether_addr { + uint8_t octet[ETHER_ADDR_LEN]; +} __packed; +#endif +#endif + +#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */ +#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */ + +/* + * Structure of the IP frame + */ +struct ip_header { + uint8_t version_ihl; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; + /*The options start here. */ +}; +#ifndef IP_PROTO_TCP +#define IP_PROTO_TCP 0x6 /* TCP protocol */ +#endif +#ifndef IP_PROTO_UDP +#define IP_PROTO_UDP 17 +#endif + +/* + * IGMP protocol structures + */ + +/* IGMP record type */ +#define IGMP_QUERY_TYPE 0x11 +#define IGMPV1_REPORT_TYPE 0x12 +#define IGMPV2_REPORT_TYPE 0x16 +#define IGMPV2_LEAVE_TYPE 0x17 +#define IGMPV3_REPORT_TYPE 0x22 + +/* Is packet type is either leave or report */ +#define IS_IGMP_REPORT_LEAVE_PACKET(type) ( \ + (IGMPV1_REPORT_TYPE == type) \ + || (IGMPV2_REPORT_TYPE == type) \ + || (IGMPV2_LEAVE_TYPE == type) \ + || (IGMPV3_REPORT_TYPE == type) \ + ) +/* + * Header in on cable format + */ + +struct igmp_header { + uint8_t type; + uint8_t code; /* For newer IGMP */ + uint16_t csum; + uint32_t group; +}; + +/* V3 group record types [grec_type] */ +#define IGMPV3_MODE_IS_INCLUDE 1 +#define IGMPV3_MODE_IS_EXCLUDE 2 +#define IGMPV3_CHANGE_TO_INCLUDE 3 +#define IGMPV3_CHANGE_TO_EXCLUDE 4 +#define IGMPV3_ALLOW_NEW_SOURCES 5 +#define IGMPV3_BLOCK_OLD_SOURCES 6 + +/* Group record format + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Record Type | Aux Data Len | Number of Sources (N) | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Multicast Address | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Address [1] | + ||+- -+ + | Source Address [2] | + ||+- -+ + . . . + . . . + . . . + ||+- -+ + | Source Address [N] | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Auxiliary Data . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct igmp_v3_grec { + uint8_t grec_type; + uint8_t grec_auxwords; + uint16_t grec_nsrcs; + uint32_t grec_mca; +}; + +/* IGMPv3 report format + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type = 0x22 | Reserved | Checksum | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Reserved | Number of Group Records (M) | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [1] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [2] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | . | + . . . + | . | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [M] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct igmp_v3_report { + uint8_t type; + uint8_t resv1; + uint16_t csum; + uint16_t resv2; + uint16_t ngrec; +}; + +/* Calculate the group record length*/ +#define IGMPV3_GRP_REC_LEN(x) (8 + (4 * x->grec_nsrcs) + (4 * x->grec_auxwords)) + +#endif /* _NET_IF_ETHERSUBR_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_packet.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_packet.h new file mode 100644 index 0000000000000000000000000000000000000000..07ac3a746a6567e85948edf933e7e411d454f950 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_packet.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 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. + */ + +#if !defined(__CDS_PKT_H) +#define __CDS_PKT_H + +/**========================================================================= + + \file cds_packet.h + + \brief Connectivity driver services (CDS) network Packet APIs + + Network Protocol packet/buffer support interfaces + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#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 + * @ cds Packet + */ +QDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet); + +/** + * cds_pkt_get_packet_length Returns the packet length + * @ cds Packet + */ +QDF_STATUS cds_pkt_get_packet_length(cds_pkt_t *pPacket, + uint16_t *pPacketSize); + +/* + * TODO: Remove later + * All the below difinitions are not + * required for Host Driver 2.0 + * once corresponding references are removed + * from HDD and other layers + * below code will be removed + */ +/* The size of AMSDU frame per spec can be a max of 3839 bytes + in BD/PDUs that means 30 (one BD = 128 bytes) + we must add the size of the 802.11 header to that */ +#define CDS_PKT_SIZE_BUFFER ((30 * 128) + 32) + +/* cds Packet Types */ +typedef enum { + /* cds Packet is used to transmit 802.11 Management frames. */ + CDS_PKT_TYPE_TX_802_11_MGMT, + + /* cds Packet is used to transmit 802.11 Data frames. */ + CDS_PKT_TYPE_TX_802_11_DATA, + + /* cds Packet is used to transmit 802.3 Data frames. */ + CDS_PKT_TYPE_TX_802_3_DATA, + + /* cds Packet contains Received data of an unknown frame type */ + CDS_PKT_TYPE_RX_RAW, + + /* Invalid sentinel value */ + CDS_PKT_TYPE_MAXIMUM +} CDS_PKT_TYPE; + +/* user IDs. These IDs are needed on the cds_pkt_get/set_user_data_ptr() + to identify the user area in the cds Packet. */ +typedef enum { + CDS_PKT_USER_DATA_ID_TL = 0, + CDS_PKT_USER_DATA_ID_BAL, + CDS_PKT_USER_DATA_ID_WMA, + CDS_PKT_USER_DATA_ID_HDD, + CDS_PKT_USER_DATA_ID_BSL, + + CDS_PKT_USER_DATA_ID_MAX +} CDS_PKT_USER_DATA_ID; + +#ifdef MEMORY_DEBUG +#define cds_packet_alloc(s, d, p) \ + cds_packet_alloc_debug(s, d, p, __FILE__, __LINE__) + +QDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + uint8_t *file_name, uint32_t line_num); +#else +QDF_STATUS cds_packet_alloc(uint16_t size, void **data, void **ppPacket); +#endif + +void cds_packet_free(void *pPacket); + +typedef QDF_STATUS (*cds_pkt_get_packet_callback)(cds_pkt_t *pPacket, + void *userData); + +#endif /* !defined( __CDS_PKT_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_queue.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..0487edb355da56503cc00ce12d5702dfc9feb5f4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_queue.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013-2015 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_QUEUE_H +#define _CDS_QUEUE_H + +#include /* include BSD queue */ + +#endif /* end of _CDS_QUEUE_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_reg_service.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_reg_service.h new file mode 100644 index 0000000000000000000000000000000000000000..0888d5820621e345559ec30532516563b6b4bbb1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_reg_service.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#if !defined __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 CDS_SBS_SEPARATION_THRESHOLD 100 +#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 + * @chan: channel number + * @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, uint32_t chan, + 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/drivers/staging/qcacld-3.0/core/cds/inc/cds_regdomain.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_regdomain.h new file mode 100644 index 0000000000000000000000000000000000000000..50d91f65d5a08f9bd999ec3a647d430a24e21c18 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_regdomain.h @@ -0,0 +1,522 @@ +/* + * 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. + */ + +/* + * 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 + +#define MIN_TX_PWR_CAP 8 +#define MAX_TX_PWR_CAP 30 + +#define CTRY_DEFAULT 0 +#define CTRY_FLAG 0x8000 +#define WORLD_ROAMING_FLAG 0x4000 +#define WORLD_ROAMING_MASK 0x00F0 +#define WORLD_ROAMING_PREFIX 0x0060 + +enum country_code { + CTRY_AFGHANISTAN = 4, + CTRY_ALBANIA = 8, + CTRY_ALGERIA = 12, + CTRY_AMERICAN_SAMOA = 16, + CTRY_ANGUILLA = 660, + CTRY_ARGENTINA = 32, + CTRY_ARGENTINA_AP = 5003, + CTRY_ARMENIA = 51, + CTRY_ARUBA = 533, + CTRY_AUSTRALIA = 36, + CTRY_AUSTRALIA_AP = 5000, + CTRY_AUSTRIA = 40, + CTRY_AZERBAIJAN = 31, + CTRY_BAHAMAS = 44, + CTRY_BAHRAIN = 48, + CTRY_BANGLADESH = 50, + CTRY_BARBADOS = 52, + CTRY_BELARUS = 112, + CTRY_BELGIUM = 56, + CTRY_BELIZE = 84, + CTRY_BERMUDA = 60, + CTRY_BHUTAN = 64, + CTRY_BOLIVIA = 68, + CTRY_BOSNIA_HERZ = 70, + CTRY_BRAZIL = 76, + CTRY_BRUNEI_DARUSSALAM = 96, + CTRY_BULGARIA = 100, + CTRY_BURKINA_FASO = 854, + CTRY_CAMBODIA = 116, + CTRY_CANADA = 124, + CTRY_CANADA_AP = 5001, + CTRY_CAYMAN_ISLANDS = 136, + CTRY_CENTRAL_AFRICA_REPUBLIC = 140, + CTRY_CHAD = 148, + CTRY_CHILE = 152, + CTRY_CHINA = 156, + CTRY_CHRISTMAS_ISLAND = 162, + CTRY_COLOMBIA = 170, + CTRY_COSTA_RICA = 188, + CTRY_COTE_DIVOIRE = 384, + CTRY_CROATIA = 191, + CTRY_CYPRUS = 196, + CTRY_CZECH = 203, + CTRY_DENMARK = 208, + CTRY_DOMINICA = 212, + CTRY_DOMINICAN_REPUBLIC = 214, + CTRY_ECUADOR = 218, + CTRY_EGYPT = 818, + CTRY_EL_SALVADOR = 222, + CTRY_ESTONIA = 233, + CTRY_ETHIOPIA = 231, + CTRY_FINLAND = 246, + CTRY_FRANCE = 250, + CTRY_FRENCH_GUIANA = 254, + CTRY_FRENCH_POLYNESIA = 258, + CTRY_GEORGIA = 268, + CTRY_GERMANY = 276, + CTRY_GHANA = 288, + CTRY_GIBRALTAR = 292, + CTRY_GREECE = 300, + CTRY_GREENLAND = 304, + CTRY_GRENADA = 308, + CTRY_GUADELOUPE = 312, + CTRY_GUAM = 316, + CTRY_GUATEMALA = 320, + CTRY_GUYANA = 328, + CTRY_HAITI = 332, + CTRY_HONDURAS = 340, + CTRY_HONG_KONG = 344, + CTRY_HUNGARY = 348, + CTRY_ICELAND = 352, + CTRY_INDIA = 356, + CTRY_INDONESIA = 360, + CTRY_IRAQ = 368, + CTRY_IRELAND = 372, + CTRY_ISRAEL = 376, + CTRY_ITALY = 380, + CTRY_JAMAICA = 388, + CTRY_JORDAN = 400, + CTRY_KAZAKHSTAN = 398, + CTRY_KENYA = 404, + CTRY_KOREA_ROC = 410, + CTRY_KOREA_ROC_AP = 412, + CTRY_KUWAIT = 414, + CTRY_LATVIA = 428, + CTRY_LEBANON = 422, + CTRY_LESOTHO = 426, + CTRY_LIBYA = 434, + CTRY_LIECHTENSTEIN = 438, + CTRY_LITHUANIA = 440, + CTRY_LUXEMBOURG = 442, + CTRY_MACAU = 446, + CTRY_MACEDONIA = 807, + CTRY_MALAWI = 454, + CTRY_MALAYSIA = 458, + CTRY_MALDIVES = 462, + CTRY_MALTA = 470, + CTRY_MARSHALL_ISLANDS = 584, + CTRY_MARTINIQUE = 474, + CTRY_MAURITANIA = 478, + CTRY_MAURITIUS = 480, + CTRY_MAYOTTE = 175, + CTRY_MEXICO = 484, + CTRY_MICRONESIA = 583, + CTRY_MOLDOVA = 498, + CTRY_MONACO = 492, + CTRY_MONGOLIA = 496, + CTRY_MONTENEGRO = 499, + CTRY_MOROCCO = 504, + CTRY_NAMIBIA = 516, + CTRY_NEPAL = 524, + CTRY_NETHERLANDS = 528, + CTRY_NETHERLANDS_ANTILLES = 530, + CTRY_NEW_ZEALAND = 554, + CTRY_NIGERIA = 566, + CTRY_NORTHERN_MARIANA_ISLANDS = 580, + CTRY_NICARAGUA = 558, + CTRY_NORWAY = 578, + CTRY_OMAN = 512, + CTRY_PAKISTAN = 586, + CTRY_PALAU = 585, + CTRY_PANAMA = 591, + CTRY_PAPUA_NEW_GUINEA = 598, + CTRY_PARAGUAY = 600, + CTRY_PERU = 604, + CTRY_PHILIPPINES = 608, + CTRY_POLAND = 616, + CTRY_PORTUGAL = 620, + CTRY_PUERTO_RICO = 630, + CTRY_QATAR = 634, + CTRY_REUNION = 638, + CTRY_ROMANIA = 642, + CTRY_RUSSIA = 643, + CTRY_RWANDA = 646, + CTRY_SAINT_BARTHELEMY = 652, + CTRY_SAINT_KITTS_AND_NEVIS = 659, + CTRY_SAINT_LUCIA = 662, + CTRY_SAINT_MARTIN = 663, + CTRY_SAINT_PIERRE_AND_MIQUELON = 666, + CTRY_SAINT_VINCENT_AND_THE_GRENADIENS = 670, + CTRY_SAMOA = 882, + CTRY_SAUDI_ARABIA = 682, + CTRY_SENEGAL = 686, + CTRY_SERBIA = 688, + CTRY_SINGAPORE = 702, + CTRY_SLOVAKIA = 703, + CTRY_SLOVENIA = 705, + CTRY_SOUTH_AFRICA = 710, + CTRY_SPAIN = 724, + CTRY_SURINAME = 740, + CTRY_SRI_LANKA = 144, + CTRY_SWEDEN = 752, + CTRY_SWITZERLAND = 756, + CTRY_TAIWAN = 158, + CTRY_TANZANIA = 834, + CTRY_THAILAND = 764, + CTRY_TOGO = 768, + CTRY_TRINIDAD_Y_TOBAGO = 780, + CTRY_TUNISIA = 788, + CTRY_TURKEY = 792, + CTRY_TURKS_AND_CAICOS = 796, + CTRY_UGANDA = 800, + CTRY_UKRAINE = 804, + CTRY_UAE = 784, + CTRY_UNITED_KINGDOM = 826, + CTRY_UNITED_STATES = 840, + CTRY_UNITED_STATES_AP = 841, + CTRY_UNITED_STATES_AP2 = 843, + CTRY_UNITED_STATES_PS = 842, + CTRY_URUGUAY = 858, + CTRY_UZBEKISTAN = 860, + CTRY_VANUATU = 548, + CTRY_VENEZUELA = 862, + CTRY_VIET_NAM = 704, + CTRY_VIRGIN_ISLANDS = 850, + CTRY_WALLIS_AND_FUTUNA = 876, + CTRY_YEMEN = 887, + CTRY_ZIMBABWE = 716, + CTRY_JAPAN9 = 4009, + CTRY_JAPAN15 = 4015, + CTRY_JAPAN48 = 4048, + CTRY_JAPAN55 = 4055, + CTRY_JAPAN60 = 4060, + CTRY_XA = 4100, +}; + +enum reg_domain { + NO_ENUMRD = 0x00, + NULL1_WORLD = 0x03, + NULL1_ETSIB = 0x07, + NULL1_ETSIC = 0x08, + + FCC1_FCCA = 0x10, + FCC1_WORLD = 0x11, + FCC2_FCCA = 0x20, + FCC2_WORLD = 0x21, + FCC2_ETSIC = 0x22, + FCC3_FCCA = 0x3A, + FCC3_WORLD = 0x3B, + FCC3_ETSIC = 0x3F, + FCC4_FCCA = 0x12, + FCC5_FCCA = 0x13, + FCC6_FCCA = 0x14, + FCC7_FCCA = 0x15, + FCC8_FCCA = 0x16, + FCC6_WORLD = 0x23, + FCC9_FCCA = 0x17, + FCC10_FCCA = 0x18, + FCC11_WORLD = 0x19, + FCC13_WORLD = 0xE4, + FCC14_FCCB = 0xE6, + + ETSI1_WORLD = 0x37, + ETSI3_ETSIA = 0x32, + ETSI2_WORLD = 0x35, + ETSI3_WORLD = 0x36, + ETSI4_WORLD = 0x30, + ETSI4_ETSIC = 0x38, + ETSI5_WORLD = 0x39, + ETSI6_WORLD = 0x34, + ETSI_RESERVED = 0x33, + FRANCE_RES = 0x31, + ETSI7_WORLD = 0x3C, + ETSI8_WORLD = 0x3D, + ETSI9_WORLD = 0x3E, + ETSI10_WORLD = 0x24, + ETSI11_WORLD = 0x26, + + APL4_WORLD = 0x42, + APL3_FCCA = 0x50, + APL_RESERVED = 0x44, + APL2_WORLD = 0x45, + APL2_FCCA = 0x4D, + APL2_APLC = 0x46, + APL3_WORLD = 0x47, + APL2_APLD = 0x49, + APL1_WORLD = 0x52, + APL1_FCCA = 0x53, + APL1_APLA = 0x54, + APL1_ETSIC = 0x55, + APL2_ETSIC = 0x56, + APL5_WORLD = 0x58, + APL6_WORLD = 0x5B, + APL7_FCCA = 0x5C, + APL8_WORLD = 0x5D, + APL9_WORLD = 0x5E, + APL10_WORLD = 0x5F, + APL11_FCCA = 0x4F, + APL12_WORLD = 0x51, + APL13_WORLD = 0x5A, + APL14_WORLD = 0x57, + APL15_WORLD = 0x59, + APL16_WORLD = 0x70, + APL17_ETSID = 0xE0, + APL20_WORLD = 0xE5, + APL23_WORLD = 0xE3, + + WOR0_WORLD = 0x60, + WOR1_WORLD = 0x61, + WOR2_WORLD = 0x62, + WOR3_WORLD = 0x63, + WOR4_FCCA = 0x64, + WOR5_ETSIC = 0x65, + WOR01_WORLD = 0x66, + WOR02_WORLD = 0x67, + EU1_WORLD = 0x68, + WOR9_WORLD = 0x69, + WORA_WORLD = 0x6A, + WORB_WORLD = 0x6B, + WORC_WORLD = 0x6C, + + MKK3_MKKB = 0x80, + MKK3_MKKA2 = 0x81, + MKK3_MKKC = 0x82, + MKK4_MKKB = 0x83, + MKK4_MKKA2 = 0x84, + MKK4_MKKC = 0x85, + MKK5_MKKA = 0x99, + MKK5_FCCA = 0x9A, + MKK5_MKKB = 0x86, + MKK5_MKKA2 = 0x87, + MKK5_MKKC = 0x88, + MKK3_MKKA = 0xF0, + MKK3_MKKA1 = 0xF1, + MKK3_FCCA = 0xF2, + MKK4_MKKA = 0xF3, + MKK4_MKKA1 = 0xF4, + MKK4_FCCA = 0xF5, + MKK9_MKKA = 0xF6, + MKK9_FCCA = 0xFC, + MKK9_MKKA1 = 0xFD, + MKK9_MKKC = 0xFE, + MKK9_MKKA2 = 0xFF, + MKK10_MKKA = 0xF7, + MKK10_FCCA = 0xD0, + MKK10_MKKA1 = 0xD1, + MKK10_MKKC = 0xD2, + MKK10_MKKA2 = 0xD3, + MKK11_MKKA = 0xD4, + MKK11_FCCA = 0xD5, + MKK11_MKKA1 = 0xD6, + MKK11_MKKC = 0xD7, + MKK11_MKKA2 = 0xD8, + MKK16_MKKC = 0xDF, + + FCC1 = 0x0110, + FCC2 = 0x0120, + FCC3 = 0x0160, + FCC4 = 0x0165, + FCC5 = 0x0510, + FCC6 = 0x0610, + FCC7 = 0x0710, + FCC8 = 0x0810, + FCC9 = 0x0910, + FCC10 = 0x0B10, + FCC11 = 0x0B20, + FCC13 = 0x0B60, + FCC14 = 0x0B70, + + ETSI1 = 0x0130, + ETSI2 = 0x0230, + ETSI3 = 0x0330, + ETSI4 = 0x0430, + ETSI5 = 0x0530, + ETSI6 = 0x0630, + ETSI8 = 0x0830, + ETSI9 = 0x0930, + ETSI10 = 0x0D30, + ETSI11 = 0x0E30, + + APL1 = 0x0150, + APL2 = 0x0250, + APL3 = 0x0350, + APL4 = 0x0450, + APL5 = 0x0550, + APL6 = 0x0650, + APL7 = 0x0750, + APL8 = 0x0850, + APL9 = 0x0950, + APL10 = 0x1050, + APL11 = 0x1150, + APL12 = 0x1160, + APL13 = 0x1170, + APL14 = 0x1180, + APL15 = 0x1190, + APL16 = 0x1200, + APL17 = 0x1210, + APL23 = 0x1280, + APL20 = 0x1250, + + NULL1 = 0x0198, + MKK3 = 0x0340, + MKK5 = 0x0540, + MKK11 = 0x1140, + MKK16 = 0x1640, + + WORLD = 0x0199, + FCCA = 0x0A10, + FCCB = 0x0B90, + MKKA = 0x0A40, + MKKC = 0x0A50, + ETSIC = 0x0C30, + +}; + +/** + * enum ctl_val: CTL value + * @FCC: FCC + * @MKK: MKK + * @ETSI: ETSI + * @NO_CTL: no CTL + */ +enum ctl_val { + FCC = 0x10, + MKK = 0x40, + ETSI = 0x30, + NO_CTL = 0xff +}; + +/** + * 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/drivers/staging/qcacld-3.0/core/cds/inc/cds_sched.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_sched.h new file mode 100644 index 0000000000000000000000000000000000000000..3d498a7230aa87291055167a7e9ec815a6e9fa5c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_sched.h @@ -0,0 +1,530 @@ +/* + * 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. + */ + +#if !defined(__CDS_SCHED_H) +#define __CDS_SCHED_H + +/**========================================================================= + + \file cds_sched.h + + \brief Connectivity driver services scheduler + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include +#include "qdf_lock.h" +#include "qdf_mc_timer.h" +#include "cds_config.h" +#include "qdf_cpuhp.h" + +#define TX_POST_EVENT 0x001 +#define TX_SUSPEND_EVENT 0x002 +#define MC_POST_EVENT 0x001 +#define MC_SUSPEND_EVENT 0x002 +#define RX_POST_EVENT 0x001 +#define RX_SUSPEND_EVENT 0x002 +#define TX_SHUTDOWN_EVENT 0x010 +#define MC_SHUTDOWN_EVENT 0x010 +#define RX_SHUTDOWN_EVENT 0x010 +#define WD_POST_EVENT 0x001 +#define WD_SHUTDOWN_EVENT 0x002 +#define WD_CHIP_RESET_EVENT 0x004 +#define WD_WLAN_SHUTDOWN_EVENT 0x008 +#define WD_WLAN_REINIT_EVENT 0x010 + +#ifdef QCA_CONFIG_SMP +/* +** Maximum number of cds messages to be allocated for +** OL Rx thread. +*/ +#define CDS_MAX_OL_RX_PKT 4000 +#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 tread +** ** pointer to the events that gracefully shutdown the MC and Tx threads +** +*/ +typedef struct _cds_sched_context { +#ifdef QCA_CONFIG_SMP + 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; + + /* Rx queue length */ + unsigned int ol_rx_queue_len; + + /* 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; +#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; +}; + +/* forward-declare hdd_context_s as it is used ina function type */ +struct hdd_context_s; +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; + unsigned long fw_state; + + qdf_event_t wma_complete_event; + + /* 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; + + struct cdp_pdev *pdev_txrx_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[TX_WMM_AC_NUM]; + qdf_work_t cds_recovery_work; + qdf_workqueue_t *cds_recovery_wq; + enum qdf_hang_reason recovery_reason; +}; + +/*--------------------------------------------------------------------------- + Function declarations and documenation + ---------------------------------------------------------------------------*/ +#ifdef QCA_CONFIG_SMP +int cds_sched_handle_cpu_hot_plug(void); +int cds_sched_handle_throughput_req(bool high_tput_required); + +/** + * 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); + +/*--------------------------------------------------------------------------- + \brief cds_drop_rxpkt_by_staid() - API to drop pending Rx packets for a sta + The \a cds_drop_rxpkt_by_staid() drops queued packets for a station, to drop + all the pending packets the caller has to send WLAN_MAX_STA_COUNT as staId. + \param pSchedContext - pointer to the global CDS Sched Context + \param staId - Station Id + + \return Nothing + \sa cds_drop_rxpkt_by_staid() + -------------------------------------------------------------------------*/ +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId); + +/*--------------------------------------------------------------------------- + \brief cds_indicate_rxpkt() - API to Indicate rx data packet + The \a cds_indicate_rxpkt() enqueues the rx packet onto ol_rx_thread_queue + and notifies cds_ol_rx_thread(). + \param Arg - pointer to the global CDS Sched Context + \param pkt - Vos data message buffer + + \return Nothing + \sa cds_indicate_rxpkt() + -------------------------------------------------------------------------*/ +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); + +/*--------------------------------------------------------------------------- + \brief cds_alloc_ol_rx_pkt() - API to return next available cds message + The \a cds_alloc_ol_rx_pkt() returns next available cds message buffer + used for Rx Data processing. + \param pSchedContext - pointer to the global CDS Sched Context + + \return pointer to cds message buffer + \sa cds_alloc_ol_rx_pkt() + -------------------------------------------------------------------------*/ +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext); + +/*--------------------------------------------------------------------------- + \brief cds_free_ol_rx_pkt() - API to release cds message to the freeq + The \a cds_free_ol_rx_pkt() returns the cds message used for Rx data + to the free queue. + \param pSchedContext - pointer to the global CDS Sched Context + \param pkt - Vos message buffer to be returned to free queue. + + \return Nothing + \sa cds_free_ol_rx_pkt() + -------------------------------------------------------------------------*/ +void cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt); +/*--------------------------------------------------------------------------- + \brief cds_free_ol_rx_pkt_freeq() - Free cdss buffer free queue + The \a cds_free_ol_rx_pkt_freeq() does mem free of the buffers + available in free cds buffer queue which is used for Data rx processing + from Tlshim. + \param pSchedContext - pointer to the global CDS Sched Context + + \return Nothing + \sa cds_free_ol_rx_pkt_freeq() + -------------------------------------------------------------------------*/ +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext); +#else +/** + * 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 + */ +static inline +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId) +{ +} + +/** + * cds_indicate_rxpkt() - API to Indicate rx data packet + * @pSchedContext: pointer to CDS Sched Context + * @pkt: CDS OL RX pkt pointer containing to RX data message buffer + * + * Return: none + */ +static inline +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 + */ +static inline +QDF_STATUS cds_close_rx_thread(void) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * cds_alloc_ol_rx_pkt() - API to return next available cds message + * @pSchedContext: pointer to CDS Sched Context + * + * Return: none + */ +static inline +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext) +{ + return NULL; +} + +/** + * cds_free_ol_rx_pkt() - API to release cds message to the freeq + * @pSchedContext: pointer to CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue + * + * Return: none + */ +static inline +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 CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue + * + * Return: none + */ +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; +} + +#endif + +/*--------------------------------------------------------------------------- + + \brief cds_sched_open() - initialize the CDS Scheduler + + The \a cds_sched_open() 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. + + - The Tx thread is created and ready to receive and dispatch messages + + \param p_cds_context - pointer to the global QDF Context + + \param p_cds_sched_context - pointer to a previously allocated buffer big + enough to hold a scheduler context. + + \return QDF_STATUS_SUCCESS - Scheduler was successfully initialized and + is ready to be used. + + QDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable to initialize the scheduler + + QDF_STATUS_E_NOMEM - insufficient memory exists to initialize + the scheduler + + QDF_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open + function + + QDF_STATUS_E_FAILURE - Failure to initialize the scheduler/ + + \sa cds_sched_open() + + -------------------------------------------------------------------------*/ +QDF_STATUS cds_sched_open(void *p_cds_context, + p_cds_sched_context pSchedCxt, uint32_t SchedCtxSize); + +/*--------------------------------------------------------------------------- + + \brief cds_sched_close() - Close the CDS Scheduler + + The \a cds_sched_closes() function 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_SUCCESS - Scheduler was successfully initialized and + is ready to be used. + + QDF_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open + function + + QDF_STATUS_E_FAILURE - Failure to initialize the scheduler/ + + \sa cds_sched_close() + + ---------------------------------------------------------------------------*/ +QDF_STATUS cds_sched_close(void); + +p_cds_sched_context get_cds_sched_ctxt(void); + +void qdf_timer_module_init(void); +void qdf_timer_module_deinit(void); +void cds_ssr_protect_init(void); +void cds_ssr_protect(const char *caller_func); +void cds_ssr_unprotect(const char *caller_func); +bool cds_wait_for_external_threads_completion(const char *caller_func); +void cds_print_external_threads(void); +int cds_get_gfp_flags(void); + +/** + * cds_return_external_threads_count() - return active external thread calls + * + * Return: total number of active extrenal threads in driver + */ +int cds_return_external_threads_count(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: CDS 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 /* #if !defined __CDS_SCHED_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_utils.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..93de1d5fb77783ce4aab457072d582446a0c1599 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_utils.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 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. + */ + +#if !defined(__CDS_UTILS_H) +#define __CDS_UTILS_H + +/**========================================================================= + + \file cds_utils.h + + \brief Connectivity driver services (CDS) utility APIs + + Various utility functions + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "ani_global.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define CDS_DIGEST_SHA1_SIZE (20) +#define CDS_DIGEST_MD5_SIZE (16) + +#define CDS_24_GHZ_BASE_FREQ (2407) +#define CDS_5_GHZ_BASE_FREQ (5000) +#define CDS_24_GHZ_CHANNEL_6 (6) +#define CDS_24_GHZ_CHANNEL_1 (1) +#define CDS_5_GHZ_CHANNEL_36 (36) +#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_enter() cds_debug("enter") +#define cds_exit() cds_debug("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 documenation + ------------------------------------------------------------------------*/ + +QDF_STATUS cds_crypto_init(uint32_t *phCryptProv); + +QDF_STATUS cds_crypto_deinit(uint32_t hCryptProv); + +/** + * cds_rand_get_bytes + + * FUNCTION: + * Returns cryptographically secure pseudo-random bytes. + * + * + * @param pbBuf - the caller allocated location where the bytes should be copied + * @param numBytes the number of bytes that should be generated and + * copied + * + * @return QDF_STATUS_SUCCSS if the operation succeeds + */ +QDF_STATUS cds_rand_get_bytes(uint32_t handle, uint8_t *pbBuf, + uint32_t numBytes); + +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); + +/** + * cds_upper_to_lower: API to convert upper case string into lower case + * @txt: input text + * @length: length of input string + * + * Return: None + */ +void cds_upper_to_lower(uint8_t *txt, uint32_t length); +#ifdef WLAN_FEATURE_11W +bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn, + uint8_t *frm, uint8_t *efrm); +bool cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id, + uint8_t *frm, uint8_t *efrm, uint16_t frmLen); +uint8_t cds_get_mmie_size(void); +/** + * cds_is_gmac_mmie_valid: Validates GMAC MIC + * @igtk: integrity group temporal key + * @ipn: IGTK packet number + * @frm: IEEE 802.11 frame + * @efrm: End of frame + * @key_length: Length of IGTK + * + * Return: True if MIC validation is successful, false otherwise + */ +bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, + uint8_t *efrm, uint16_t key_length); + +/** + * 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); + +#endif /* WLAN_FEATURE_11W */ +QDF_STATUS sme_send_flush_logs_cmd_to_fw(tpAniSirGlobal pMac); +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 /* #if !defined __CDS_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c new file mode 100644 index 0000000000000000000000000000000000000000..93dc3284edc5467294c1d339c084619ca8e4d878 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c @@ -0,0 +1,2898 @@ +/* + * 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: 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 +#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 "target_type.h" +#include "wlan_ocb_ucfg_api.h" +#include "wlan_ipa_ucfg_api.h" + +#ifdef ENABLE_SMMU_S1_TRANSLATION +#include "pld_common.h" +#include +#include +#endif +/* 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; + +static struct ol_if_ops dp_ol_if_ops = { + .peer_set_default_routing = wma_peer_set_default_routing, + .peer_rx_reorder_queue_setup = wma_peer_rx_reorder_queue_setup, + .peer_rx_reorder_queue_remove = wma_peer_rx_reorder_queue_remove, + .is_hw_dbs_2x2_capable = policy_mgr_is_hw_dbs_2x2_capable, + .lro_hash_config = wma_lro_config_cmd, + .rx_mic_error = wma_rx_mic_error_ind + /* TODO: Add any other control path calls required to OL_IF/WMA layer */ +}; + +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 (NULL == 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); + } +} + +/** cds_get_datapath_handles - Initialize pdev, vdev and soc + * @soc - soc handle + * @vdev - virtual handle + * @pdev - physical handle + */ +uint8_t cds_get_datapath_handles(void **soc, struct cdp_pdev **pdev, + struct cdp_vdev **vdev, uint8_t sessionId) +{ + + (*soc) = cds_get_context(QDF_MODULE_ID_SOC); + + if (!(*soc)) { + cds_err("soc handle is invalid"); + return -EINVAL; + } + + (*pdev) = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!(*pdev)) { + cds_err("pdev handle is invalid"); + return -EINVAL; + } + + (*vdev) = cdp_get_vdev_from_vdev_id((*soc), (*pdev), + sessionId); + + if (!(*vdev)) { + cds_err("vdev handle is invalid"); + return -EINVAL; + } + return 0; +} + + +QDF_STATUS cds_init(void) +{ + QDF_STATUS ret; + + ret = qdf_debugfs_init(); + if (ret != QDF_STATUS_SUCCESS) + cds_err("Failed to init debugfs"); + + qdf_lock_stats_init(); + qdf_mem_init(); + qdf_mc_timer_manager_init(); + qdf_event_list_init(); + qdf_cpuhp_init(); + qdf_register_self_recovery_callback(__cds_trigger_recovery); + qdf_register_fw_down_callback(cds_is_fw_down); + qdf_register_ssr_protect_callbacks(cds_ssr_protect, + cds_ssr_unprotect); + + gp_cds_context = &g_cds_context; + + gp_cds_context->qdf_ctx = &g_qdf_ctx; + qdf_mem_zero(&g_qdf_ctx, sizeof(g_qdf_ctx)); + + qdf_trace_spin_lock_init(); + qdf_trace_init(); + qdf_register_recovering_state_query_callback(cds_is_driver_recovering); + + qdf_register_debugcb_init(); + + cds_ssr_protect_init(); + + ret = cds_recovery_work_init(); + if (ret != QDF_STATUS_SUCCESS) { + cds_err("Failed to init recovery work"); + goto deinit; + } + + return QDF_STATUS_SUCCESS; +deinit: + qdf_cpuhp_deinit(); + qdf_event_list_destroy(); + qdf_mc_timer_manager_exit(); + qdf_mem_exit(); + qdf_lock_stats_deinit(); + qdf_debugfs_exit(); + gp_cds_context->qdf_ctx = NULL; + gp_cds_context = NULL; + qdf_mem_zero(&g_cds_context, sizeof(g_cds_context)); + return ret; +} + +/** + * cds_deinit() - Deinitialize CDS + * + * This function frees the CDS resources + */ +void cds_deinit(void) +{ + if (gp_cds_context == NULL) + return; + qdf_register_recovering_state_query_callback(NULL); + cds_recovery_work_deinit(); + qdf_cpuhp_deinit(); + qdf_mc_timer_manager_exit(); + qdf_mem_exit(); + qdf_lock_stats_deinit(); + qdf_debugfs_exit(); + qdf_event_list_destroy(); + + gp_cds_context->qdf_ctx = NULL; + gp_cds_context = NULL; + + qdf_mem_zero(&g_cds_context, sizeof(g_cds_context)); + return; +} + +#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 + * @mac_params: mac params + * + * 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 (NULL == olcfg) + return; + + if (NULL == cds_cfg) + return; + + for (i = 0; i < OL_TX_NUM_WMM_AC; 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 cds_config_info *cds_cfg, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{ + cdp_cfg->tx_flow_stop_queue_th = cds_cfg->tx_flow_stop_queue_th; + cdp_cfg->tx_flow_start_queue_offset = + cds_cfg->tx_flow_start_queue_offset; +} +#else +static inline void +cds_cdp_set_flow_control_params(struct cds_config_info *cds_cfg, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{} +#endif + +/** + * cds_cdp_cfg_attach() - attach data path config module + * @cds_cfg: generic platform level config instance + * + * Return: none + */ +static void cds_cdp_cfg_attach(struct cds_config_info *cds_cfg) +{ + struct txrx_pdev_cfg_param_t cdp_cfg = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + cdp_cfg.is_full_reorder_offload = cds_cfg->reorder_offload; + cdp_cfg.is_uc_offload_enabled = cds_cfg->uc_offload_enabled; + cdp_cfg.uc_tx_buffer_count = cds_cfg->uc_txbuf_count; + cdp_cfg.uc_tx_buffer_size = cds_cfg->uc_txbuf_size; + cdp_cfg.uc_rx_indication_ring_count = cds_cfg->uc_rxind_ringcount; + cdp_cfg.uc_tx_partition_base = cds_cfg->uc_tx_partition_base; + cdp_cfg.enable_rxthread = cds_cfg->enable_rxthread; + cdp_cfg.ip_tcp_udp_checksum_offload = + cds_cfg->ip_tcp_udp_checksum_offload; + cdp_cfg.ce_classify_enabled = cds_cfg->ce_classify_enabled; + + cds_cfg_update_ac_specs_params(&cdp_cfg, cds_cfg); + gp_cds_context->cfg_ctx = cdp_cfg_attach(soc, gp_cds_context->qdf_ctx, + (void *)(&cdp_cfg)); + if (!gp_cds_context->cfg_ctx) { + WMA_LOGP("%s: failed to init cfg handle", __func__); + return; + } + + /* Configure Receive flow steering */ + cdp_cfg_set_flow_steering(soc, gp_cds_context->cfg_ctx, + cds_cfg->flow_steering_enabled); + + cds_cdp_set_flow_control_params(cds_cfg, &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, + (uint8_t) cds_cfg->ap_disable_intrabss_fwd); + + /* + * 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 + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static void +cds_set_ac_specs_params(struct cds_config_info *cds_cfg) +{ + int i; + struct cds_context *cds_ctx; + + if (NULL == cds_cfg) + return; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + for (i = 0; i < OL_TX_NUM_WMM_AC; i++) { + cds_cfg->ac_specs[i] = cds_ctx->ac_specs[i]; + } +} + +/** + * 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. + * + * 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; + 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) { + cds_alert("Trying to open CDS without a PreOpen"); + return QDF_STATUS_E_FAILURE; + } + + /* Initialize the timer module */ + qdf_timer_module_init(); + + /* Initialize bug reporting structure */ + cds_init_log_completion(); + + status = qdf_event_create(&gp_cds_context->wma_complete_event); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("Unable to init wma_complete_event"); + return status; + } + + hdd_ctx = gp_cds_context->hdd_context; + if (!hdd_ctx || !hdd_ctx->config) { + cds_err("Hdd Context is Null"); + + status = QDF_STATUS_E_FAILURE; + goto err_wma_complete_event; + } + + status = dispatcher_enable(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to enable dispatcher; status:%d", status); + goto err_wma_complete_event; + } + + /* 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) { + cds_alert("scn is null!"); + + 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->config, 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 = + pmo_ucfg_psoc_target_suspend_acknowledge; + htcInfo.target_initial_wakeup_cb = pmo_ucfg_psoc_handle_initial_wake_up; + htcInfo.target_psoc = (void *)psoc; + 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; + } + pmo_ucfg_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; + } + + /*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) + hdd_ctx->config->maxNumberOfPeers = cds_cfg->max_station; + + HTCHandle = cds_get_context(QDF_MODULE_ID_HTC); + gp_cds_context->cfg_ctx = NULL; + if (!HTCHandle) { + cds_alert("HTCHandle is null!"); + + 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", hdd_ctx->target_type, + TARGET_TYPE_QCA8074, TARGET_TYPE_QCA6290); + + if (TARGET_TYPE_QCA6290 == hdd_ctx->target_type) + gp_cds_context->dp_soc = cdp_soc_attach(LITHIUM_DP, + gp_cds_context->hif_context, psoc, + gp_cds_context->htc_ctx, gp_cds_context->qdf_ctx, + &dp_ol_if_ops); + else + gp_cds_context->dp_soc = cdp_soc_attach(MOB_DRV_LEGACY_DP, + gp_cds_context->hif_context, psoc, + gp_cds_context->htc_ctx, gp_cds_context->qdf_ctx, + &dp_ol_if_ops); + + 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); + pmo_ucfg_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_cdp_cfg_attach(cds_cfg); + + 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; + } + + 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: + cdp_soc_detach(gp_cds_context->dp_soc); + gp_cds_context->dp_soc = NULL; + + ucfg_ocb_update_dp_handle(psoc, NULL); + pmo_ucfg_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; + pmo_ucfg_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"); + +err_wma_complete_event: + qdf_event_destroy(&gp_cds_context->wma_complete_event); + + return status; +} /* cds_open() */ + +QDF_STATUS cds_dp_open(struct wlan_objmgr_psoc *psoc) +{ + if (cdp_txrx_intr_attach(gp_cds_context->dp_soc) + != QDF_STATUS_SUCCESS) { + cds_alert("Failed to attach interrupts"); + goto close; + } + + cds_set_context(QDF_MODULE_ID_TXRX, + cdp_pdev_attach(cds_get_context(QDF_MODULE_ID_SOC), + gp_cds_context->cfg_ctx, + gp_cds_context->htc_ctx, + gp_cds_context->qdf_ctx, 0)); + if (!gp_cds_context->pdev_txrx_ctx) { + /* Critical Error ... Cannot proceed further */ + cds_alert("Failed to open TXRX"); + QDF_ASSERT(0); + goto intr_close; + } + + pmo_ucfg_psoc_set_txrx_handle(psoc, gp_cds_context->pdev_txrx_ctx); + ucfg_ocb_set_txrx_handle(psoc, gp_cds_context->pdev_txrx_ctx); + + cds_debug("CDS successfully Opened"); + + return 0; + +intr_close: + cdp_txrx_intr_detach(gp_cds_context->dp_soc); +close: + return QDF_STATUS_E_FAILURE; +} + +/** + * 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) { + cds_err("hif context is null"); + return QDF_STATUS_E_INVAL; + } + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) { + cds_err("soc context is null"); + 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, gp_cds_context->pdev_txrx_ctx, + scn); + + /* Reset wma wait event */ + qdf_event_reset(&gp_cds_context->wma_complete_event); + + /*call WMA pre start */ + status = wma_pre_start(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to WMA prestart"); + return QDF_STATUS_E_FAILURE; + } + + /* Need to update time out of complete */ + status = qdf_wait_for_event_completion( + &gp_cds_context->wma_complete_event, + CDS_WMA_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to wait for WMA complete; status:%u", status); + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); + goto exit_with_status; + } + + status = htc_start(gp_cds_context->htc_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to Start HTC"); + goto exit_with_status; + } + + 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, gp_cds_context->pdev_txrx_ctx); + if (errno) { + cds_err("Failed to attach pdev"); + status = qdf_status_from_os_return(errno); + goto stop_wmi; + } + + return QDF_STATUS_SUCCESS; + +stop_wmi: + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + cds_err("%s: Failed to get hif_handle!", __func__); + + wma_wmi_stop(); + + if (hif_ctx) { + cds_err("%s: Disable the isr & reset the soc!", __func__); + hif_disable_isr(hif_ctx); + hif_reset_soc(hif_ctx); + } + htc_stop(gp_cds_context->htc_ctx); + +exit_with_status: + return status; +} + +QDF_STATUS cds_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS qdf_status; + struct mac_start_params mac_params; + int errno; + + /* 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; + } + + errno = cdp_soc_attach_target(cds_get_context(QDF_MODULE_ID_SOC)); + if (errno) { + cds_err("Failed to attach soc target; errno:%d", errno); + goto err_sme_stop; + } + + errno = cdp_pdev_attach_target(cds_get_context(QDF_MODULE_ID_SOC), + cds_get_context(QDF_MODULE_ID_TXRX)); + if (errno) { + cds_err("Failed to attach pdev target; errno:%d", errno); + goto err_soc_target_detach; + } + + 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_event_reset(&gp_cds_context->wma_complete_event); + 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)); + wma_setneedshutdown(); + } else { + qdf_status = + qdf_wait_for_event_completion( + &gp_cds_context->wma_complete_event, + CDS_WMA_TIMEOUT); + if (qdf_status != QDF_STATUS_SUCCESS) { + if (qdf_status == QDF_STATUS_E_TIMEOUT) { + cds_alert("Timeout occurred before WMA_stop complete"); + } else { + cds_alert("WMA_stop reporting other error"); + } + QDF_ASSERT(0); + wma_setneedshutdown(); + } + } + + 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)); + wma_setneedshutdown(); + } + + handle = cds_get_context(QDF_MODULE_ID_PE); + if (!handle) { + cds_err("Invalid PE context return!"); + return QDF_STATUS_E_INVAL; + } + + umac_stop(); + + return qdf_status; +} + +#ifdef HIF_USB +static inline void cds_suspend_target(tp_wma_handle wma_handle) +{ + QDF_STATUS status; + /* Suspend the target and disable interrupt */ + status = pmo_ucfg_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 = pmo_ucfg_psoc_suspend_target(wma_handle->psoc, 1); + if (status) + cds_err("Failed to suspend target, status = %d", status); +} +#endif /* HIF_USB */ + +/** + * 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 cdp_pdev *txrx_pdev; + struct scheduler_ctx *sched_ctx; + QDF_STATUS qdf_status; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + cds_err("Failed to get wma_handle!"); + return QDF_STATUS_E_INVAL; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + cds_err("Failed to get hif_handle!"); + return QDF_STATUS_E_INVAL; + } + + txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + cds_err("Failed to get txrx pdev!"); + return QDF_STATUS_E_INVAL; + } + + /* flush any unprocessed scheduler messages */ + sched_ctx = scheduler_get_context(); + if (sched_ctx) + scheduler_queues_flush(sched_ctx); + + /* + * 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_info("send deinit sequence to firmware"); + if (!(cds_is_driver_recovering() || cds_is_driver_in_bad_state())) + 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), + (struct cdp_pdev *)txrx_pdev, 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_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"); + + qdf_status = dispatcher_disable(); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + if (QDF_IS_STATUS_ERROR(qdf_status)) + cds_err("Failed to disable dispatcher; status:%d", qdf_status); + + dispatcher_psoc_close(psoc); + + 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); + pmo_ucfg_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; + + cdp_soc_detach(gp_cds_context->dp_soc); + pmo_ucfg_psoc_update_dp_handle(psoc, NULL); + wlan_psoc_set_dp_handle(psoc, NULL); + + cds_shutdown_notifier_purge(); + + if (true == wma_needshutdown()) { + cds_err("Failed to shutdown wma"); + } else { + 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)); + } + + qdf_status = qdf_event_destroy(&gp_cds_context->wma_complete_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("failed to destroy wma_complete_event"); + 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) +{ + void *ctx; + + cdp_txrx_intr_detach(gp_cds_context->dp_soc); + + ctx = cds_get_context(QDF_MODULE_ID_TXRX); + cdp_pdev_detach(cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_pdev *)ctx, 1); + cds_set_context(QDF_MODULE_ID_TXRX, NULL); + pmo_ucfg_psoc_set_txrx_handle(psoc, NULL); + + return QDF_STATUS_SUCCESS; +} + +/** + * 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 + */ +void *cds_get_context(QDF_MODULE_ID module_id) +{ + void *context = NULL; + + if (gp_cds_context == NULL) { + cds_err("cds context pointer is null"); + 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_TXRX: + { + context = (void *)gp_cds_context->pdev_txrx_ctx; + 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 %i does not have its context maintained by CDS", + module_id); + QDF_ASSERT(0); + return NULL; + } + } + + if (!context) + cds_err("Module ID %i context is Null", module_id); + + 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 == NULL) { + /* + * 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 == NULL) { + 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 == NULL) { + 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 == NULL) { + cds_err("global cds context is NULL: %x", state); + + return; + } + + gp_cds_context->driver_state &= ~state; +} + +enum cds_fw_state cds_get_fw_state(void) +{ + if (gp_cds_context == NULL) { + cds_err("global cds context is NULL"); + + return CDS_FW_STATE_UNINITIALIZED; + } + + return gp_cds_context->fw_state; +} + +void cds_set_fw_state(enum cds_fw_state state) +{ + if (gp_cds_context == NULL) { + cds_err("global cds context is NULL: %d", state); + + return; + } + + qdf_atomic_set_bit(state, &gp_cds_context->fw_state); +} + +void cds_clear_fw_state(enum cds_fw_state state) +{ + if (gp_cds_context == NULL) { + cds_err("global cds context is NULL: %d", state); + + return; + } + + qdf_atomic_clear_bit(state, &gp_cds_context->fw_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 + * @param 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_TXRX: + p_cds_context->pdev_txrx_ctx = 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_TXRX: + cds_mod_context = (void **)&gp_cds_context->pdev_txrx_ctx; + 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_wma_complete_cback() - wma complete callback + * + * Return: none + */ +void cds_wma_complete_cback(void) +{ + if (!gp_cds_context) { + cds_err("invalid gp_cds_context"); + return; + } + + if (qdf_event_set(&gp_cds_context->wma_complete_event) != + QDF_STATUS_SUCCESS) { + cds_err("qdf_event_set failed"); + return; + } +} /* cds_wma_complete_cback() */ + +/** + * cds_get_vdev_types() - get vdev type + * @mode: mode + * @type: type + * @sub_type: sub_type + * + * Return: WMI vdev type + */ +QDF_STATUS cds_get_vdev_types(enum QDF_OPMODE mode, uint32_t *type, + uint32_t *sub_type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + *type = 0; + *sub_type = 0; + + switch (mode) { + case QDF_STA_MODE: + *type = WMI_VDEV_TYPE_STA; + break; + case QDF_SAP_MODE: + *type = WMI_VDEV_TYPE_AP; + break; + case QDF_P2P_DEVICE_MODE: + *type = WMI_VDEV_TYPE_AP; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE; + break; + case QDF_P2P_CLIENT_MODE: + *type = WMI_VDEV_TYPE_STA; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT; + break; + case QDF_P2P_GO_MODE: + *type = WMI_VDEV_TYPE_AP; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO; + break; + case QDF_OCB_MODE: + *type = WMI_VDEV_TYPE_OCB; + break; + case QDF_IBSS_MODE: + *type = WMI_VDEV_TYPE_IBSS; + break; + case QDF_MONITOR_MODE: + *type = WMI_VDEV_TYPE_MONITOR; + break; + case QDF_NDI_MODE: + *type = WMI_VDEV_TYPE_NDI; + break; + default: + cds_err("Invalid device mode %d", mode); + status = QDF_STATUS_E_INVAL; + break; + } + return status; +} + +/** + * 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 ((NULL == hdd_ctx) || (NULL == hdd_ctx->config)) { + cds_alert("Hdd Context is Null"); + return false; + } + return hdd_ctx->config->enablePacketLog; +} +#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) { + cds_err("wma is null"); + 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; + + /* 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; + } + + /* if *wlan* recovery is disabled, crash here for debugging */ + if (!cds_is_self_recovery_enabled()) { + QDF_DEBUG_PANIC("WLAN recovery is not enabled (via %s:%d)", + func, line); + return; + } + + /* ignore recovery if we are unloading; it would be a waste anyway */ + if (cds_is_driver_unloading()) { + cds_info("WLAN is unloading; ignore recovery"); + return; + } + + qdf = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf) { + cds_err("Qdf context is null"); + 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_set_recovery_in_progress(true); + cds_force_assert_target(qdf); + + 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; + + if (in_atomic()) { + __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); + return; + } + + cds_trigger_recovery_handler(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_get_monotonic_boottime() - Get kernel boot time. + * + * Return: Time in microseconds + */ + +uint64_t cds_get_monotonic_boottime(void) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +} + +/** + * 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 Invald"); + return; + } + p_cds_context->is_wakelock_log_enabled = value; +} + +/** + * cds_is_wakelock_enabled() - Check if logging of wakelock is enabled/disabled + * @value: Boolean value + * + * 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 Invald"); + 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_levelvalue: Log level specificed + * + * 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 Invald"); + 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 Invald"); + 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 trigerred 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 trigerred 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 +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 ((NULL == hdd_ctx) || (NULL == 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 ((NULL == hdd_ctx) || (NULL == 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) +{ + 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 trigerred 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) +{ + uint32_t ret; + 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, 500, 0); + + if (WLAN_LOG_INDICATOR_HOST_ONLY == indicator) { + cds_wlan_flush_host_logs_for_fatal(); + return QDF_STATUS_SUCCESS; + } + + ret = sme_send_flush_logs_cmd_to_fw(p_cds_context->mac_context); + if (0 != ret) { + 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) +{ + 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) { + cds_err("Invalid CDS Context"); + 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) { + cds_err("Invalid CDS Context"); + 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) { + cds_err("Invalid CDS Context"); + 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) { + cds_err("%s: cds context is invalid", __func__); + 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) { + cds_err("%s: cds context is invalid", __func__); + 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) { + cds_err("%s: cds context is invalid", __func__); + 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) { + cds_err("%s: cds context is invalid", __func__); + 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) { + cds_err("cds context is invalid"); + 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 + +uint32_t cds_get_connectivity_stats_pkt_bitmap(void *context) +{ + struct hdd_adapter *adapter = NULL; + + if (!context) + return 0; + + adapter = (struct hdd_adapter *)context; + if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + cds_err("Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); + return 0; + } + return adapter->pkt_type_bitmap; +} + +/** + * cds_get_arp_stats_gw_ip() - get arp stats track IP + * + * Return: ARP stats IP to track + */ +uint32_t cds_get_arp_stats_gw_ip(void *context) +{ + struct hdd_adapter *adapter = NULL; + + if (!context) + return 0; + + adapter = (struct hdd_adapter *)context; + + if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + cds_err("Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); + return 0; + } + + return adapter->track_arp_ip; +} + +/** + * cds_incr_arp_stats_tx_tgt_delivered() - increment ARP stats + * + * Return: none + */ +void cds_incr_arp_stats_tx_tgt_delivered(void) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter = NULL; + + hdd_ctx = gp_cds_context->hdd_context; + if (!hdd_ctx) { + cds_err("Hdd Context is Null"); + return; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (QDF_STA_MODE == adapter->device_mode) + break; + } + + if (adapter) + adapter->hdd_stats.hdd_arp_stats.tx_host_fw_sent++; +} + +/** + * cds_incr_arp_stats_tx_tgt_acked() - increment ARP stats + * + * Return: none + */ +void cds_incr_arp_stats_tx_tgt_acked(void) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter = NULL; + + hdd_ctx = gp_cds_context->hdd_context; + if (!hdd_ctx) { + cds_err("Hdd Context is Null"); + return; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (QDF_STA_MODE == adapter->device_mode) + break; + } + + if (adapter) + adapter->hdd_stats.hdd_arp_stats.tx_ack_cnt++; +} + +#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 = iommu_domain_get_attr(domain, + 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 = iommu_domain_get_attr(mapping->domain, + 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; + osdev->iommu_mapping = NULL; + 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/drivers/staging/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h b/drivers/staging/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h new file mode 100644 index 0000000000000000000000000000000000000000..72566a7cf30d2ae30c14d71b8ac76273834106ae --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h @@ -0,0 +1,578 @@ +/* + * 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 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, +}; + +/** + * enum ieee80211_opmode - operating mode + * @IEEE80211_M_IBSS - IBSS (adhoc) station + * @IEEE80211_M_HOSTAP - Software Access Point + * @IEEE80211_OPMODE_MAX = Highest numbered opmode in the list + * @IEEE80211_M_ANY - Any of the above; used by NDIS 6.x + * +*/ +enum ieee80211_opmode { + IEEE80211_M_IBSS = 0, + IEEE80211_M_HOSTAP = 6, + + /* Do not add after this line */ + IEEE80211_OPMODE_MAX = IEEE80211_M_HOSTAP, + + IEEE80211_M_ANY = 0xFF, +}; + +/* + * 802.11n + */ +#define IEEE80211_CWM_EXTCH_BUSY_THRESHOLD 30 + +enum ieee80211_cwm_mode { + IEEE80211_CWM_MODE20, + IEEE80211_CWM_MODE2040, + IEEE80211_CWM_MODE40, + IEEE80211_CWM_MODEMAX +}; + +enum ieee80211_cwm_extprotspacing { + IEEE80211_CWM_EXTPROTSPACING20, + IEEE80211_CWM_EXTPROTSPACING25, + IEEE80211_CWM_EXTPROTSPACINGMAX +}; + +enum ieee80211_cwm_width { + IEEE80211_CWM_WIDTH20, + IEEE80211_CWM_WIDTH40, + IEEE80211_CWM_WIDTH80, + IEEE80211_CWM_WIDTHINVALID = 0xff /* user invalid value */ +}; + +enum ieee80211_cwm_extprotmode { + IEEE80211_CWM_EXTPROTNONE, /* no protection */ + IEEE80211_CWM_EXTPROTCTSONLY, /* CTS to self */ + IEEE80211_CWM_EXTPROTRTSCTS, /* RTS-CTS */ + IEEE80211_CWM_EXTPROTMAX +}; + +enum ieee80211_fixed_rate_mode { + IEEE80211_FIXED_RATE_NONE = 0, + IEEE80211_FIXED_RATE_MCS = 1, /* HT rates */ + IEEE80211_FIXED_RATE_LEGACY = 2, /* legacy rates */ + IEEE80211_FIXED_RATE_VHT = 3 /* VHT rates */ +}; + +/* Holds the fixed rate information for each VAP */ +struct ieee80211_fixed_rate { + enum ieee80211_fixed_rate_mode mode; + uint32_t series; + uint32_t retries; +}; + +/* + * 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 */ +}; + +/* + * Roaming mode is effectively who controls the operation + * of the 802.11 state machine when operating as a station. + * State transitions are controlled either by the driver + * (typically when management frames are processed by the + * hardware/firmware), the host (auto/normal operation of + * the 802.11 layer), or explicitly through ioctl requests + * when applications like wpa_supplicant want control. + */ +enum ieee80211_roamingmode { + IEEE80211_ROAMING_DEVICE = 0, /* driver/hardware control */ + IEEE80211_ROAMING_AUTO = 1, /* 802.11 layer control */ + IEEE80211_ROAMING_MANUAL = 2, /* application control */ +}; + +/* + * Scanning mode controls station scanning work; this is + * used only when roaming mode permits the host to select + * the bss to join/channel to use. + */ +enum ieee80211_scanmode { + IEEE80211_SCAN_DEVICE = 0, /* driver/hardware control */ + IEEE80211_SCAN_BEST = 1, /* 802.11 layer selects best */ + IEEE80211_SCAN_FIRST = 2, /* take first suitable candidate */ +}; + +#define IEEE80211_NWID_LEN 32 +#define IEEE80211_CHAN_MAX 255 +#define IEEE80211_CHAN_BYTES 32 /* howmany(IEEE80211_CHAN_MAX, NBBY) */ +#define IEEE80211_CHAN_ANY (-1) /* token for ``any channel'' */ +#define IEEE80211_CHAN_ANYC \ + ((struct ieee80211_channel *) IEEE80211_CHAN_ANY) + +#define IEEE80211_CHAN_DEFAULT 11 +#define IEEE80211_CHAN_DEFAULT_11A 52 +#define IEEE80211_CHAN_ADHOC_DEFAULT1 10 +#define IEEE80211_CHAN_ADHOC_DEFAULT2 11 + +#define IEEE80211_RADAR_11HCOUNT 5 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11A 36 /* Move to channel 36 for mute test */ +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT20 36 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT40U 36 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT40D 40 /* Move to channel 40 for HT40D mute test */ +#define IEEE80211_RADAR_DETECT_DEFAULT_DELAY 60000 /* STA ignore AP beacons during this period in millisecond */ + +#define IEEE80211_2GCSA_TBTTCOUNT 3 + +/* 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 */ +/* HT 40 Intolerant mark bit for ACS use */ +#define IEEE80211_CHAN_HT40INTOLMARK 0x01000000 +/* 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_RADAR_FOUND 0x01 +#define IEEE80211_CHAN_DFS 0x0002 /* DFS required on channel */ +#define IEEE80211_CHAN_DFS_CLEAR 0x0008 /* if channel has been checked for DFS */ +#define IEEE80211_CHAN_11D_EXCLUDED 0x0010 /* excluded in 11D */ +#define IEEE80211_CHAN_CSA_RECEIVED 0x0020 /* Channel Switch Announcement received on this channel */ +#define IEEE80211_CHAN_DISALLOW_ADHOC 0x0040 /* ad-hoc is not allowed */ +#define IEEE80211_CHAN_DISALLOW_HOSTAP 0x0080 /* Station only channel */ + +/* + * Useful combinations of channel characteristics. + */ +#define IEEE80211_CHAN_FHSS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) +#define IEEE80211_CHAN_A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_B \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) +#define IEEE80211_CHAN_PUREG \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) +#define IEEE80211_CHAN_108A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) +#define IEEE80211_CHAN_108G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) +#define IEEE80211_CHAN_ST \ + (IEEE80211_CHAN_108A | IEEE80211_CHAN_STURBO) + +#define IEEE80211_IS_CHAN_11AC_2G(_c) \ + (IEEE80211_IS_CHAN_2GHZ((_c)) && IEEE80211_IS_CHAN_VHT((_c))) +#define IEEE80211_CHAN_11AC_VHT20_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT20) +#define IEEE80211_CHAN_11AC_VHT40_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS) +#define IEEE80211_CHAN_11AC_VHT80_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT80) + +#define IEEE80211_IS_CHAN_11AC_VHT20_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT20_2G) == IEEE80211_CHAN_11AC_VHT20_2G) +#define IEEE80211_IS_CHAN_11AC_VHT40_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40_2G) != 0) +#define IEEE80211_IS_CHAN_11AC_VHT80_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80_2G) == IEEE80211_CHAN_11AC_VHT80_2G) + +#define IEEE80211_CHAN_11NG_HT20 \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT20) +#define IEEE80211_CHAN_11NA_HT20 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT20) +#define IEEE80211_CHAN_11NG_HT40PLUS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_CHAN_11NG_HT40MINUS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_CHAN_11NA_HT40PLUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_CHAN_11NA_HT40MINUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT40MINUS) + +#define IEEE80211_CHAN_ALL \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_GFSK | \ + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | \ + IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS | \ + IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS | IEEE80211_CHAN_VHT80 | \ + IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER) +#define IEEE80211_CHAN_ALLTURBO \ + (IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO) + +#define IEEE80211_IS_CHAN_FHSS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS) +#define IEEE80211_IS_CHAN_A(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) +#define IEEE80211_IS_CHAN_B(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) +#define IEEE80211_IS_CHAN_PUREG(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) +#define IEEE80211_IS_CHAN_G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) +#define IEEE80211_IS_CHAN_ANYG(_c) \ + (IEEE80211_IS_CHAN_PUREG(_c) || IEEE80211_IS_CHAN_G(_c)) +#define IEEE80211_IS_CHAN_ST(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) +#define IEEE80211_IS_CHAN_108A(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) +#define IEEE80211_IS_CHAN_108G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) + +#define IEEE80211_IS_CHAN_2GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0) +#define IEEE80211_IS_CHAN_5GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0) +#define IEEE80211_IS_CHAN_OFDM(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_OFDM) != 0) +#define IEEE80211_IS_CHAN_CCK(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0) +#define IEEE80211_IS_CHAN_GFSK(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0) +#define IEEE80211_IS_CHAN_TURBO(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_TURBO) != 0) +#define IEEE80211_IS_CHAN_WEATHER_RADAR(_c) \ + ((((_c)->ic_freq >= 5600) && ((_c)->ic_freq <= 5650)) \ + || (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) && (5580 == (_c)->ic_freq))) +#define IEEE80211_IS_CHAN_STURBO(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_STURBO) != 0) +#define IEEE80211_IS_CHAN_DTURBO(_c) \ + (((_c)->ic_flags & \ + (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)) == IEEE80211_CHAN_TURBO) +#define IEEE80211_IS_CHAN_HALF(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0) +#define IEEE80211_IS_CHAN_QUARTER(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_QUARTER) != 0) +#define IEEE80211_IS_CHAN_PASSIVE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE) != 0) + +#define IEEE80211_IS_CHAN_DFS(_c) \ + (((_c)->ic_flagext & (IEEE80211_CHAN_DFS|IEEE80211_CHAN_DFS_CLEAR)) == IEEE80211_CHAN_DFS) +#define IEEE80211_IS_CHAN_DFSFLAG(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DFS) == IEEE80211_CHAN_DFS) +#define IEEE80211_IS_CHAN_DISALLOW_ADHOC(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DISALLOW_ADHOC) != 0) +#define IEEE80211_IS_CHAN_11D_EXCLUDED(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_11D_EXCLUDED) != 0) +#define IEEE80211_IS_CHAN_CSA(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_CSA_RECEIVED) != 0) +#define IEEE80211_IS_CHAN_ODD(_c) \ + (((_c)->ic_freq == 5170) || ((_c)->ic_freq == 5190) || \ + ((_c)->ic_freq == 5210) || ((_c)->ic_freq == 5230)) +#define IEEE80211_IS_CHAN_DISALLOW_HOSTAP(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DISALLOW_HOSTAP) != 0) + +#define IEEE80211_IS_CHAN_11NG_HT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT20) == IEEE80211_CHAN_11NG_HT20) +#define IEEE80211_IS_CHAN_11NA_HT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT20) == IEEE80211_CHAN_11NA_HT20) +#define IEEE80211_IS_CHAN_11NG_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT40PLUS) == IEEE80211_CHAN_11NG_HT40PLUS) +#define IEEE80211_IS_CHAN_11NG_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT40MINUS) == IEEE80211_CHAN_11NG_HT40MINUS) +#define IEEE80211_IS_CHAN_11NA_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT40PLUS) == IEEE80211_CHAN_11NA_HT40PLUS) +#define IEEE80211_IS_CHAN_11NA_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT40MINUS) == IEEE80211_CHAN_11NA_HT40MINUS) + +#define IEEE80211_IS_CHAN_11N(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS)) != 0) +#define IEEE80211_IS_CHAN_11N_HT20(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT20)) != 0) +#define IEEE80211_IS_CHAN_11N_HT40(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS)) != 0) +#define IEEE80211_IS_CHAN_11NG(_c) \ + (IEEE80211_IS_CHAN_2GHZ((_c)) && IEEE80211_IS_CHAN_11N((_c))) +#define IEEE80211_IS_CHAN_11NA(_c) \ + (IEEE80211_IS_CHAN_5GHZ((_c)) && IEEE80211_IS_CHAN_11N((_c))) +#define IEEE80211_IS_CHAN_11N_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) != 0) +#define IEEE80211_IS_CHAN_11N_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) != 0) + +#define IEEE80211_IS_CHAN_HT20_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT20) == IEEE80211_CHAN_HT20) +#define IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) == IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) == IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_IS_CHAN_HT40_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(_c) || IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(_c)) +#define IEEE80211_IS_CHAN_HT_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_HT20_CAPABLE(_c) || IEEE80211_IS_CHAN_HT40_CAPABLE(_c)) +#define IEEE80211_IS_CHAN_11N_CTL_CAPABLE(_c) IEEE80211_IS_CHAN_HT20_CAPABLE(_c) +#define IEEE80211_IS_CHAN_11N_CTL_U_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) == IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_IS_CHAN_11N_CTL_L_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) == IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_IS_CHAN_11N_CTL_40_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_11N_CTL_U_CAPABLE((_c)) || IEEE80211_IS_CHAN_11N_CTL_L_CAPABLE((_c))) + +#define IEEE80211_IS_CHAN_VHT(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_VHT20 | \ + IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS | IEEE80211_CHAN_VHT80)) != 0) +#define IEEE80211_IS_CHAN_11AC(_c) \ + (IEEE80211_IS_CHAN_5GHZ((_c)) && IEEE80211_IS_CHAN_VHT((_c))) +#define IEEE80211_CHAN_11AC_VHT20 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT20) +#define IEEE80211_CHAN_11AC_VHT40 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS) +#define IEEE80211_CHAN_11AC_VHT40PLUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40PLUS) +#define IEEE80211_CHAN_11AC_VHT40MINUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40MINUS) +#define IEEE80211_CHAN_11AC_VHT80 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT80) +#define IEEE80211_IS_CHAN_11AC_VHT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT20) == IEEE80211_CHAN_11AC_VHT20) + +#define IEEE80211_IS_CHAN_11AC_VHT40(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS)) != 0) +#define IEEE80211_IS_CHAN_11AC_VHT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40PLUS) == IEEE80211_CHAN_11AC_VHT40PLUS) +#define IEEE80211_IS_CHAN_11AC_VHT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40MINUS) == IEEE80211_CHAN_11AC_VHT40MINUS) +#define IEEE80211_IS_CHAN_11AC_VHT80(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80) == IEEE80211_CHAN_11AC_VHT80) + +#define IEEE80211_IS_CHAN_RADAR(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_RADAR_DFS) == IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_SET_RADAR(_c) \ + ((_c)->ic_flags |= IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_CLR_RADAR(_c) \ + ((_c)->ic_flags &= ~IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_SET_DISALLOW_ADHOC(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DISALLOW_ADHOC) +#define IEEE80211_CHAN_SET_DISALLOW_HOSTAP(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DISALLOW_HOSTAP) +#define IEEE80211_CHAN_SET_DFS(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DFS) +#define IEEE80211_CHAN_SET_DFS_CLEAR(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DFS_CLEAR) +#define IEEE80211_CHAN_EXCLUDE_11D(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_11D_EXCLUDED) + +/* channel encoding for FH phy */ +#define IEEE80211_FH_CHANMOD 80 +#define IEEE80211_FH_CHAN(set, pat) (((set) - 1) * IEEE80211_FH_CHANMOD + (pat)) +#define IEEE80211_FH_CHANSET(chan) ((chan) / IEEE80211_FH_CHANMOD + 1) +#define IEEE80211_FH_CHANPAT(chan) ((chan) % IEEE80211_FH_CHANMOD) + +/* + * 802.11 rate set. + */ +#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ +#define IEEE80211_RATE_MAXSIZE 36 /* max rates we'll handle */ +#define IEEE80211_HT_RATE_SIZE 128 +#define IEEE80211_RATE_SINGLE_STREAM_MCS_MAX 7 /* MCS7 */ + +#define IEEE80211_RATE_MCS 0x8000 +#define IEEE80211_RATE_MCS_VAL 0x7FFF + +#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val & (0xff << (idx * 8))) >> (idx * 8))) + +/* + * RSSI range + */ +#define IEEE80211_RSSI_MAX -10 /* in db */ +#define IEEE80211_RSSI_MIN -200 + +/* + * 11n A-MPDU & A-MSDU limits + */ +#define IEEE80211_AMPDU_LIMIT_MIN (1 * 1024) +#define IEEE80211_AMPDU_LIMIT_MAX (64 * 1024 - 1) +#define IEEE80211_AMPDU_LIMIT_DEFAULT IEEE80211_AMPDU_LIMIT_MAX +#define IEEE80211_AMPDU_SUBFRAME_MIN 2 +#define IEEE80211_AMPDU_SUBFRAME_MAX 64 +#define IEEE80211_AMPDU_SUBFRAME_DEFAULT 32 +#define IEEE80211_AMSDU_LIMIT_MAX 4096 +#define IEEE80211_RIFS_AGGR_DIV 10 +#define IEEE80211_MAX_AMPDU_MIN 0 +#define IEEE80211_MAX_AMPDU_MAX 3 + +/* + * 11ac A-MPDU limits + */ +#define IEEE80211_VHT_MAX_AMPDU_MIN 0 +#define IEEE80211_VHT_MAX_AMPDU_MAX 7 + +struct ieee80211_rateset { + uint8_t rs_nrates; + uint8_t rs_rates[IEEE80211_RATE_MAXSIZE]; +}; + +struct ieee80211_beacon_info { + uint8_t essid[IEEE80211_NWID_LEN + 1]; + uint8_t esslen; + uint8_t rssi_ctl_0; + uint8_t rssi_ctl_1; + uint8_t rssi_ctl_2; + int numchains; +}; + +#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ + +struct ieee80211_ibss_peer_list { + uint8_t bssid[IEEE80211_ADDR_LEN]; +}; + +struct ieee80211_roam { + int8_t rssi11a; /* rssi thresh for 11a bss */ + int8_t rssi11b; /* for 11g sta in 11b bss */ + int8_t rssi11bOnly; /* for 11b sta */ + uint8_t pad1; + uint8_t rate11a; /* rate thresh for 11a bss */ + uint8_t rate11b; /* for 11g sta in 11b bss */ + uint8_t rate11bOnly; /* for 11b sta */ + uint8_t pad2; +}; + +#define IEEE80211_TID_SIZE 17 /* total number of TIDs */ +#define IEEE80211_NON_QOS_SEQ 16 /* index for non-QoS (including management) sequence number space */ +#define IEEE80211_SEQ_MASK 0xfff /* sequence generator mask */ +#define MIN_SW_SEQ 0x100 /* minimum sequence for SW generate packect */ + +/* crypto related defines*/ +#define IEEE80211_KEYBUF_SIZE 16 +#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx+rx keys */ + +enum ieee80211_clist_cmd { + CLIST_UPDATE, + CLIST_DFS_UPDATE, + CLIST_NEW_COUNTRY, + CLIST_NOL_UPDATE +}; + +enum ieee80211_nawds_param { + IEEE80211_NAWDS_PARAM_NUM = 0, + IEEE80211_NAWDS_PARAM_MODE, + IEEE80211_NAWDS_PARAM_DEFCAPS, + IEEE80211_NAWDS_PARAM_OVERRIDE, +}; + +struct ieee80211_mib_cycle_cnts { + uint32_t tx_frame_count; + uint32_t rx_frame_count; + uint32_t rx_clear_count; + uint32_t cycle_count; + uint8_t is_rx_active; + uint8_t is_tx_active; +}; + +struct ieee80211_chanutil_info { + uint32_t rx_clear_count; + uint32_t cycle_count; + uint8_t value; + uint32_t beacon_count; + uint8_t beacon_intervals; +}; + +#endif /* CDS_COMMON__IEEE80211_I_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_packet.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_packet.c new file mode 100644 index 0000000000000000000000000000000000000000..ad5f29104ccf13486d42d04f963205f0ef7a613f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_packet.c @@ -0,0 +1,160 @@ +/* + * 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. + */ + +/**========================================================================= + + \file cds_packet.c + + \brief Connectivity driver services (CDS) network Packet APIs + + Network Protocol packet/buffer support interfaces + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include "qdf_nbuf.h" +#include "qdf_mem.h" +#include "cds_utils.h" + +#define TX_PKT_MIN_HEADROOM (64) + +/* Protocol specific packet tracking feature */ +#define CDS_PKT_TRAC_ETH_TYPE_OFFSET (12) +#define CDS_PKT_TRAC_IP_OFFSET (14) +#define CDS_PKT_TRAC_IP_HEADER_SIZE (20) +#define CDS_PKT_TRAC_DHCP_SRV_PORT (67) +#define CDS_PKT_TRAC_DHCP_CLI_PORT (68) +#define CDS_PKT_TRAC_EAPOL_ETH_TYPE (0x888E) + +/** + * cds_pkt_return_packet Free the cds Packet + * @ cds Packet + */ +QDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet) +{ + /* Validate the input parameter pointer */ + if (unlikely(packet == NULL)) { + 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; +} + +/**-------------------------------------------------------------------------- + + \brief cds_pkt_get_packet_length() - Get packet length for a cds Packet + + This API returns the total length of the data in a cds Packet. + + \param pPacket - the cds Packet to get the packet length from. + + \param pPacketSize - location to return the total size of the data contained + in the cds Packet. + \return + + \sa + + ---------------------------------------------------------------------------*/ +QDF_STATUS +cds_pkt_get_packet_length(cds_pkt_t *pPacket, uint16_t *pPacketSize) +{ + /* Validate the parameter pointers */ + if (unlikely((pPacket == NULL) || (pPacketSize == NULL)) || + (pPacket->pkt_buf == NULL)) { + 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 +/*--------------------------------------------------------------------------- +* @brief cds_packet_alloc_debug() - + Allocate a network buffer for TX + ---------------------------------------------------------------------------*/ +QDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + uint8_t *file_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, + file_name, line_num); + + if (nbuf != NULL) { + 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 +/*--------------------------------------------------------------------------- +* @brief cds_packet_alloc() - + Allocate a network buffer for TX + ---------------------------------------------------------------------------*/ +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 != NULL) { + 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 +/*--------------------------------------------------------------------------- +* @brief cds_packet_free() - + Free input network buffer + ---------------------------------------------------------------------------*/ +void cds_packet_free(void *pPacket) +{ + qdf_nbuf_free((qdf_nbuf_t) pPacket); +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_reg_service.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_reg_service.c new file mode 100644 index 0000000000000000000000000000000000000000..c658fdc9fffe8bcb5bee05f1ed3a8a33c4df2fa1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_reg_service.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 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. + */ + +/*============================================================================ + 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 "wlan_reg_services_api.h" +#include "cds_reg_service.h" +#include "cds_ieee80211_common_i.h" +#include "cds_config.h" +#include "cds_utils.h" + +uint32_t cds_get_vendor_reg_flags(struct wlan_objmgr_pdev *pdev, + uint32_t chan, 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; + int sec_channel; + + state = wlan_reg_get_channel_state(pdev, chan); + 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(chan)) { + 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; + + switch (bandwidth) { + case CH_WIDTH_80P80MHZ: + if (wlan_reg_get_5g_bonded_channel_state(pdev, chan, + bandwidth) != CHANNEL_STATE_INVALID) { + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT80_80; + } + bandwidth = CH_WIDTH_160MHZ; + /* FALLTHROUGH */ + case CH_WIDTH_160MHZ: + if (wlan_reg_get_5g_bonded_channel_state(pdev, chan, + bandwidth) != CHANNEL_STATE_INVALID) { + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT160; + } + bandwidth = CH_WIDTH_80MHZ; + /* FALLTHROUGH */ + case CH_WIDTH_80MHZ: + if (wlan_reg_get_5g_bonded_channel_state(pdev, chan, + bandwidth) != 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(pdev, chan, 0, &ch_params); + + if (ch_params.sec_ch_offset == LOW_PRIMARY_CH) + sec_channel = chan + 4; + else if (ch_params.sec_ch_offset == HIGH_PRIMARY_CH) + sec_channel = chan - 4; + else + sec_channel = 0; + + if (wlan_reg_get_bonded_channel_state(pdev, chan, bandwidth, + sec_channel) != + 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(pdev, chan, bandwidth, + 0) != 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(pdev, chan, bandwidth, + 0) != 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/drivers/staging/qcacld-3.0/core/cds/src/cds_regdomain.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_regdomain.c new file mode 100644 index 0000000000000000000000000000000000000000..f8f55d2a4c8caaa3d2e66a6ebcbd69454b3e0f8b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_regdomain.c @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2011,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. + */ + +/* + * 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, FCC}, + {FCC2, FCC}, + {FCC3, FCC}, + {FCC4, FCC}, + {FCC5, FCC}, + {FCC6, FCC}, + {FCC7, FCC}, + {FCC8, FCC}, + {FCC9, FCC}, + {FCC10, FCC}, + {FCC11, FCC}, + {FCC13, FCC}, + {FCC14, FCC}, + {ETSI1, ETSI}, + {ETSI2, ETSI}, + {ETSI3, ETSI}, + {ETSI4, ETSI}, + {ETSI5, ETSI}, + {ETSI6, ETSI}, + {ETSI8, ETSI}, + {ETSI9, ETSI}, + {ETSI10, ETSI}, + {ETSI11, ETSI}, + {APL1, ETSI}, + {APL2, ETSI}, + {APL3, ETSI}, + {APL4, ETSI}, + {APL5, ETSI}, + {APL6, ETSI}, + {APL7, ETSI}, + {APL8, ETSI}, + {APL9, ETSI}, + {APL10, ETSI}, + {APL11, ETSI}, + {APL12, ETSI}, + {APL13, ETSI}, + {APL14, FCC}, + {APL15, FCC}, + {APL16, FCC}, + {APL17, FCC}, + {APL20, ETSI}, + {APL23, ETSI}, + {NULL1, NO_CTL}, + {MKK3, MKK}, + {MKK5, MKK}, + {MKK11, MKK}, + {WORLD, ETSI}, + {FCCA, FCC}, + {MKKA, MKK}, + {MKKC, MKK}, + {ETSIC, ETSI}, + {WOR0_WORLD, NO_CTL}, + {WOR1_WORLD, NO_CTL}, + {WOR2_WORLD, NO_CTL}, + {WOR3_WORLD, NO_CTL}, + {WOR4_FCCA, NO_CTL}, + {WOR5_ETSIC, NO_CTL}, + {WOR01_WORLD, NO_CTL}, + {WOR02_WORLD, NO_CTL}, + {EU1_WORLD, NO_CTL}, + {WOR9_WORLD, NO_CTL}, + {WORA_WORLD, NO_CTL}, + {WORB_WORLD, NO_CTL}, + {WORC_WORLD, NO_CTL}, +}; + + +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 proceeed"); + 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) { + cds_err("unable to get WMA handle"); + 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/drivers/staging/qcacld-3.0/core/cds/src/cds_sched.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_sched.c new file mode 100644 index 0000000000000000000000000000000000000000..62fca2ef8173c9cbda4f53a82d749e017f622511 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_sched.c @@ -0,0 +1,1142 @@ +/* + * 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. + */ + +/** + * File: cds_sched.c + * + * DOC: CDS Scheduler Implementation + */ + + /* Include Files */ +#include +#include +#include +#include +#include +#include +#include +#include "cds_sched.h" +#include +#include "wma_types.h" +#include +#include +#include +#ifdef RX_PERFORMANCE +#include +#endif +/* Preprocessor Definitions and Constants */ +#define CDS_SCHED_THREAD_HEART_BEAT INFINITE +/* Milli seconds to delay SSR thread when an Entry point is Active */ +#define SSR_WAIT_SLEEP_TIME 200 +/* MAX iteration count to wait for Entry point to exit before + * we proceed with SSR in WD Thread + */ +#define MAX_SSR_WAIT_ITERATIONS 100 +#define MAX_SSR_PROTECT_LOG (16) + +static atomic_t ssr_protect_entry_count; + +/** + * struct ssr_protect - sub system restart(ssr) protection tracking table + * @func: Function which needs ssr protection + * @free: Flag to tell whether entry is free in table or not + * @pid: Process id which needs ssr protection + */ +struct ssr_protect { + const char *func; + bool free; + uint32_t pid; +}; + +static spinlock_t ssr_protect_lock; +static struct ssr_protect ssr_protect_log[MAX_SSR_PROTECT_LOG]; + +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 QCA_CONFIG_SMP +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(struct task_struct *task, unsigned long cpu) +{ + return set_cpus_allowed_ptr(task, cpumask_of(cpu)); +} + + +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; +} + +#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 perf 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; + struct cpumask new_mask; + unsigned long cpus; + + cds_debug("num possible cpu %d", num_possible_cpus()); + + 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)) + cpumask_set_cpu(cpus, &new_mask); + } else if (topology_physical_package_id(cpus) == + CDS_CPU_CLUSTER_TYPE_PERF) { + cpumask_set_cpu(cpus, &new_mask); + } + + core_affine_count++; + } + } else { + /* Attach to all cores, let scheduler decide */ + 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)) { + cpumask_copy(&pSchedContext->rx_thread_cpu_mask, &new_mask); + set_cpus_allowed_ptr(pSchedContext->ol_rx_thread, &new_mask); + } + + return 0; +err: + return 1; +} + +/** + * 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) +{ + 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; +} + +/** + * cds_sched_handle_throughput_req - cpu throughput requirement handler + * @high_tput_required: high throughput is required or not + * + * high or low throughput indication ahndler + * 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) +{ + 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_module_stop_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(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) +{ + cds_ssr_protect(__func__); + __cds_cpu_hotplug_notify(cpu, cpu_up); + cds_ssr_unprotect(__func__); +} + +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 /* QCA_CONFIG_SMP */ + +/** + * 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_debug("Opening the CDS Scheduler"); + /* Sanity checks */ + if ((p_cds_context == NULL) || (pSchedContext == NULL)) { + 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 QCA_CONFIG_SMP + 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; +#endif + gp_cds_sched_context = pSchedContext; + +#ifdef QCA_CONFIG_SMP + 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 QCA_CONFIG_SMP +OL_RX_THREAD_START_FAILURE: +#endif + +#ifdef QCA_CONFIG_SMP + 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 QCA_CONFIG_SMP +/** + * 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) +{ + 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; +} + +/** + * cds_free_ol_rx_pkt() - api to release cds message to the freeq + * This api returns the cds message used for Rx data to the free queue + * @pSchedContext: Pointer to the global CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue. + * + * Return: none + */ +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); +} + +/** + * 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) +{ + 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; +} + +/** + * cds_indicate_rxpkt() - indicate rx data packet + * @Arg: 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) +{ + 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); +} + +/** + * 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_debug("invoked"); + + if (!gp_cds_sched_context) { + cds_err("gp_cds_sched_context == NULL"); + 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 */ + +/** + * 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) +{ + struct list_head local_list; + struct cds_ol_rx_pkt *pkt, *tmp; + qdf_nbuf_t buf, next_buf; + + 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); + } +} + +/** + * 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); + 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); + } + 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; + + set_user_nice(current, -1); +#ifdef MSM_PLATFORM + set_wake_up_idle(true); +#endif + + 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_info("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"); + complete_and_exit(&pSchedContext->ol_rx_shutdown, 0); + + return 0; +} +#endif + +/** + * 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) +{ + cds_debug("invoked"); + + if (gp_cds_sched_context == NULL) { + cds_err("gp_cds_sched_context == NULL"); + return QDF_STATUS_E_FAILURE; + } + + cds_close_rx_thread(); + gp_cds_sched_context = NULL; + return QDF_STATUS_SUCCESS; +} /* cds_sched_close() */ + +/** + * get_cds_sched_ctxt() - get cds scheduler context + * + * Return: none + */ +p_cds_sched_context get_cds_sched_ctxt(void) +{ + /* Make sure that Vos Scheduler context has been initialized */ + if (gp_cds_sched_context == NULL) + cds_err("gp_cds_sched_context == NULL"); + + return gp_cds_sched_context; +} + +/** + * cds_ssr_protect_init() - initialize ssr protection debug functionality + * + * Return: + * void + */ +void cds_ssr_protect_init(void) +{ + int i = 0; + + spin_lock_init(&ssr_protect_lock); + + while (i < MAX_SSR_PROTECT_LOG) { + ssr_protect_log[i].func = NULL; + ssr_protect_log[i].free = true; + ssr_protect_log[i].pid = 0; + i++; + } + + INIT_LIST_HEAD(&shutdown_notifier_head); +} + +/** + * cds_print_external_threads() - print external threads stuck in driver + * + * Return: + * void + */ +void cds_print_external_threads(void) +{ + int i = 0; + unsigned long irq_flags; + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (!ssr_protect_log[i].free) { + cds_err("PID %d is executing %s", + ssr_protect_log[i].pid, + ssr_protect_log[i].func); + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); +} + +/** + * cds_ssr_protect() - start ssr protection + * @caller_func: name of calling function. + * + * This function is called to keep track of active driver entry points + * + * Return: none + */ +void cds_ssr_protect(const char *caller_func) +{ + int count; + int i = 0; + bool status = false; + unsigned long irq_flags; + + count = atomic_inc_return(&ssr_protect_entry_count); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (ssr_protect_log[i].free) { + ssr_protect_log[i].func = caller_func; + ssr_protect_log[i].free = false; + ssr_protect_log[i].pid = current->pid; + status = true; + break; + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + /* + * Dump the protect log at intervals if count is consistently growing. + * Long running functions should tend to dominate the protect log, so + * hopefully, dumping at multiples of log size will prevent spamming the + * logs while telling us which calls are taking a long time to finish. + */ + if (count >= MAX_SSR_PROTECT_LOG && count % MAX_SSR_PROTECT_LOG == 0) { + cds_err("Protect Log overflow; Dumping contents:"); + cds_print_external_threads(); + } + + if (!status) + cds_err("%s can not be protected; PID:%d, entry_count:%d", + caller_func, current->pid, count); +} + +/** + * cds_ssr_unprotect() - stop ssr protection + * @caller_func: name of calling function. + * + * Return: none + */ +void cds_ssr_unprotect(const char *caller_func) +{ + int count; + int i = 0; + bool status = false; + unsigned long irq_flags; + + count = atomic_dec_return(&ssr_protect_entry_count); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (!ssr_protect_log[i].free) { + if ((ssr_protect_log[i].pid == current->pid) && + !strcmp(ssr_protect_log[i].func, caller_func)) { + ssr_protect_log[i].func = NULL; + ssr_protect_log[i].free = true; + ssr_protect_log[i].pid = 0; + status = true; + break; + } + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + if (!status) + cds_err("%s was not protected; PID:%d, entry_count:%d", + caller_func, current->pid, count); +} + +/** + * 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. + * + * This is intended for early notification of remove() or shutdown() only so + * that lower layers can take care of stuffs like external waiting thread. + * + * Return: CDS status + */ +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 == NULL) + 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; +} + +/** + * 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) +{ + 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); +} + +/** + * 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) +{ + 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); +} + +/** + * cds_wait_for_external_threads_completion() - wait for external threads + * completion before proceeding further + * @caller_func: name of calling function. + * + * Return: true if there is no active entry points in driver + * false if there is at least one active entry in driver + */ +bool cds_wait_for_external_threads_completion(const char *caller_func) +{ + int count = MAX_SSR_WAIT_ITERATIONS; + int r; + + while (count) { + + r = atomic_read(&ssr_protect_entry_count); + + if (!r) + break; + + if (--count) { + cds_err("Waiting for %d active entry points to exit", + r); + msleep(SSR_WAIT_SLEEP_TIME); + if (count & 0x1) { + cds_err("in middle of waiting for active entry points:"); + cds_print_external_threads(); + } + } + } + + /* at least one external thread is executing */ + if (!count) { + cds_err("Timed-out waiting for active entry points:"); + cds_print_external_threads(); + return false; + } + + cds_info("Allowing SSR/Driver unload for %s", caller_func); + + return true; +} + +int cds_return_external_threads_count(void) +{ + return atomic_read(&ssr_protect_entry_count); +} + +/** + * cds_get_gfp_flags(): get GFP flags + * + * Based on the scheduled context, return GFP flags + * Return: gfp flags + */ +int cds_get_gfp_flags(void) +{ + int flags = GFP_KERNEL; + + if (in_interrupt() || in_atomic() || irqs_disabled()) + flags = GFP_ATOMIC; + + return flags; +} + +void cds_resume_rx_thread(void) +{ + p_cds_sched_context cds_sched_context = NULL; + + cds_sched_context = get_cds_sched_ctxt(); + if (NULL == cds_sched_context) { + cds_err("cds_sched_context is NULL"); + return; + } + + complete(&cds_sched_context->ol_resume_rx_event); +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_utils.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..2de74afa8aaa6514fe829a08df674319f09ffc30 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_utils.c @@ -0,0 +1,742 @@ +/* + * Copyright (c) 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. + */ + +/*============================================================================ + 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 "cds_crypto.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cds_ieee80211_common.h" +#include + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define AAD_LEN 20 +#define IV_SIZE_AES_128 16 +#define CMAC_IPN_LEN 6 +#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ +#define GMAC_NONCE_LEN 12 + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Function Definitions and Documentation + * -------------------------------------------------------------------------*/ +#ifdef WLAN_FEATURE_11W +static inline void xor_128(const u8 *a, const u8 *b, u8 *out) +{ + u8 i; + + for (i = 0; i < AES_BLOCK_SIZE; i++) + out[i] = a[i] ^ b[i]; +} + +static inline void leftshift_onebit(const u8 *input, u8 *output) +{ + int i, overflow = 0; + + for (i = (AES_BLOCK_SIZE - 1); i >= 0; i--) { + output[i] = input[i] << 1; + output[i] |= overflow; + overflow = (input[i] & 0x80) ? 1 : 0; + } + return; +} + +static void generate_subkey(struct crypto_cipher *tfm, u8 *k1, u8 *k2) +{ + u8 l[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; + u8 const_rb[AES_BLOCK_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 + }; + u8 const_zero[AES_BLOCK_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + crypto_cipher_encrypt_one(tfm, l, const_zero); + + if ((l[0] & 0x80) == 0) { /* If MSB(l) = 0, then k1 = l << 1 */ + leftshift_onebit(l, k1); + } else { /* Else k1 = ( l << 1 ) (+) Rb */ + leftshift_onebit(l, tmp); + xor_128(tmp, const_rb, k1); + } + + if ((k1[0] & 0x80) == 0) { + leftshift_onebit(k1, k2); + } else { + leftshift_onebit(k1, tmp); + xor_128(tmp, const_rb, k2); + } +} + +static inline void padding(u8 *lastb, u8 *pad, u16 length) +{ + u8 j; + + /* original last block */ + for (j = 0; j < AES_BLOCK_SIZE; j++) { + if (j < length) + pad[j] = lastb[j]; + else if (j == length) + pad[j] = 0x80; + else + pad[j] = 0x00; + } +} + +static void cds_cmac_calc_mic(struct crypto_cipher *tfm, + u8 *m, u16 length, u8 *mac) +{ + u8 x[AES_BLOCK_SIZE], y[AES_BLOCK_SIZE]; + u8 m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE]; + u8 k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128]; + int cmpBlk; + int i, nBlocks = (length + 15) / AES_BLOCK_SIZE; + + generate_subkey(tfm, k1, k2); + + if (nBlocks == 0) { + nBlocks = 1; + cmpBlk = 0; + } else { + cmpBlk = ((length % AES_BLOCK_SIZE) == 0) ? 1 : 0; + } + + if (cmpBlk) { /* Last block is complete block */ + xor_128(&m[AES_BLOCK_SIZE * (nBlocks - 1)], k1, m_last); + } else { /* Last block is not complete block */ + padding(&m[AES_BLOCK_SIZE * (nBlocks - 1)], padded, + length % AES_BLOCK_SIZE); + xor_128(padded, k2, m_last); + } + + for (i = 0; i < AES_BLOCK_SIZE; i++) + x[i] = 0; + + for (i = 0; i < (nBlocks - 1); i++) { + xor_128(x, &m[AES_BLOCK_SIZE * i], y); /* y = Mi (+) x */ + crypto_cipher_encrypt_one(tfm, x, y); /* x = AES-128(KEY, y) */ + } + + xor_128(x, m_last, y); + crypto_cipher_encrypt_one(tfm, x, y); + + memcpy(mac, x, CMAC_TLEN); +} +#endif + +/*-------------------------------------------------------------------------- + + \brief cds_crypto_init() - Initializes Crypto module + + The cds_crypto_init() function initializes Crypto module. + + \param phCryptProv - pointer to the Crypt handle + + \return QDF_STATUS_SUCCESS - Successfully generated random memory. + + QDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + QDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***QDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ +QDF_STATUS cds_crypto_init(uint32_t *phCryptProv) +{ + QDF_STATUS uResult = QDF_STATUS_E_FAILURE; + + /* This implementation doesn't require a crypto context */ + *phCryptProv = 0; + uResult = QDF_STATUS_SUCCESS; + return uResult; +} + +QDF_STATUS cds_crypto_deinit(uint32_t hCryptProv) +{ + QDF_STATUS uResult = QDF_STATUS_E_FAILURE; + + /* CryptReleaseContext succeeded */ + uResult = QDF_STATUS_SUCCESS; + + return uResult; +} + +/*-------------------------------------------------------------------------- + + \brief cds_rand_get_bytes() - Generates random byte + + The cds_rand_get_bytes() function generate random bytes. + + Buffer should be allocated before calling cds_rand_get_bytes(). + + Attempting to initialize an already initialized lock results in + a failure. + + \param lock - pointer to the opaque lock object to initialize + + \return QDF_STATUS_SUCCESS - Successfully generated random memory. + + QDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + QDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***QDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ +QDF_STATUS +cds_rand_get_bytes(uint32_t cryptHandle, uint8_t *pbBuf, uint32_t numBytes) +{ + QDF_STATUS uResult = QDF_STATUS_E_FAILURE; + + /* check for invalid pointer */ + if (NULL == pbBuf) { + uResult = QDF_STATUS_E_FAULT; + return uResult; + } + + get_random_bytes(pbBuf, numBytes); + /* "Random sequence generated." */ + uResult = QDF_STATUS_SUCCESS; + return uResult; +} + +#ifdef WLAN_FEATURE_11W +uint8_t cds_get_mmie_size(void) +{ + return sizeof(struct ieee80211_mmie); +} + +/*-------------------------------------------------------------------------- + + \brief cds_increase_seq() - Increase the IPN aka Sequence number by one unit + + The cds_increase_seq() function increases the IPN by one unit. + + \param ipn - pointer to the IPN aka Sequence number [6 bytes] + + --------------------------------------------------------------------------*/ +static void cds_increase_seq(uint8_t *ipn) +{ + uint64_t value = 0; + + if (ipn) { + value = (0xffffffffffff) & (*((uint64_t *) ipn)); + value = value + 1; + qdf_mem_copy(ipn, &value, IEEE80211_MMIE_IPNLEN); + } +} + +/*-------------------------------------------------------------------------- + + \brief cds_attach_mmie() - attches the complete MMIE at the end of frame + + The cds_attach_mmie() calculates the entire MMIE and attaches at the end + of Broadcast/Multicast robust management frames. + + \param igtk - pointer group key which will be used to calculate + the 8 byte MIC. + \param ipn - pointer ipn, it is also known as sequence number + \param key_id - key identication number + \param frm - pointer to the start of the frame. + \param efrm - pointer to the end of the frame. + \param frmLen - size of the entire frame. + + \return - this function will return true on success and false on + failure. + + --------------------------------------------------------------------------*/ + +bool +cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id, + uint8_t *frm, uint8_t *efrm, uint16_t frmLen) +{ + struct ieee80211_mmie *mmie; + struct ieee80211_frame *wh; + uint8_t aad[AAD_LEN], mic[CMAC_TLEN], *input = NULL; + uint8_t previous_ipn[IEEE80211_MMIE_IPNLEN] = { 0 }; + uint16_t nBytes = 0; + int ret = 0; + struct crypto_cipher *tfm; + + /* This is how received frame look like + * + * <------------frmLen----------------------------> + * + * +---------------+----------------------+-------+ + * | 802.11 HEADER | Management framebody | MMIE | + * +---------------+----------------------+-------+ + * ^ + * | + * efrm + * This is how MMIE from above frame look like + * + * + * <------------ 18 Bytes-----------------------------> + * +--------+---------+---------+-----------+---------+ + * |Element | Length | Key id | IPN | MIC | + * | id | | | | | + * +--------+---------+---------+-----------+---------+ + * Octet 1 1 2 6 8 + * + */ + + /* Check if frame is invalid length */ + if (((efrm - frm) != frmLen) || (frmLen < sizeof(*wh))) { + cds_err("Invalid frame length"); + return false; + } + mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie)); + + /* Copy Element id */ + mmie->element_id = IEEE80211_ELEMID_MMIE; + + /* Copy Length */ + mmie->length = sizeof(*mmie) - 2; + + /* Copy Key id */ + mmie->key_id = key_id; + + /* + * In case of error, revert back to original IPN + * to do that copy the original IPN into previous_ipn + */ + qdf_mem_copy(&previous_ipn[0], ipn, IEEE80211_MMIE_IPNLEN); + cds_increase_seq(ipn); + qdf_mem_copy(mmie->sequence_number, ipn, IEEE80211_MMIE_IPNLEN); + + /* + * Calculate MIC and then copy + */ + tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + tfm = NULL; + cds_err("crypto_alloc_cipher failed (%d)", ret); + goto err_tfm; + } + + ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128); + if (ret) { + cds_err("crypto_cipher_setkey failed (%d)", ret); + goto err_tfm; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + /* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ + nBytes = AAD_LEN + (frmLen - sizeof(struct ieee80211_frame)); + input = (uint8_t *) qdf_mem_malloc(nBytes); + if (NULL == input) { + cds_err("Memory allocation failed"); + ret = QDF_STATUS_E_NOMEM; + goto err_tfm; + } + + /* + * Copy the AAD, Management frame body, and + * MMIE with 8 bit MIC zeroed out + */ + qdf_mem_copy(input, aad, AAD_LEN); + /* Copy Management Frame Body and MMIE without MIC */ + qdf_mem_copy(input + AAD_LEN, + (uint8_t *) (efrm - + (frmLen - sizeof(struct ieee80211_frame))), + nBytes - AAD_LEN - CMAC_TLEN); + + cds_cmac_calc_mic(tfm, input, nBytes, mic); + qdf_mem_free(input); + + cds_debug("CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X", + mic[0], mic[1], mic[2], mic[3], + mic[4], mic[5], mic[6], mic[7]); + qdf_mem_copy(mmie->mic, mic, IEEE80211_MMIE_MICLEN); + +err_tfm: + if (ret) { + qdf_mem_copy(ipn, previous_ipn, IEEE80211_MMIE_IPNLEN); + } + + if (tfm) + cds_crypto_free_cipher(tfm); + return !ret ? true : false; +} + +bool +cds_is_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, uint8_t *efrm) +{ + struct ieee80211_mmie *mmie; + struct ieee80211_frame *wh; + uint8_t *rx_ipn, aad[AAD_LEN], mic[CMAC_TLEN], *input; + uint16_t nBytes = 0; + int ret = 0; + struct crypto_cipher *tfm; + + /* Check if frame is invalid length */ + if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) { + cds_err("Invalid frame length"); + return false; + } + + mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie)); + + /* Check Element ID */ + if ((mmie->element_id != IEEE80211_ELEMID_MMIE) || + (mmie->length != (sizeof(*mmie) - 2))) { + cds_err("IE is not Mgmt MIC IE or Invalid length"); + /* IE is not Mgmt MIC IE or invalid length */ + return false; + } + + /* Validate IPN */ + rx_ipn = mmie->sequence_number; + if (OS_MEMCMP(rx_ipn, ipn, CMAC_IPN_LEN) <= 0) { + /* Replay error */ + cds_err("Replay error mmie ipn %02X %02X %02X %02X %02X %02X" + " drvr ipn %02X %02X %02X %02X %02X %02X", + rx_ipn[0], rx_ipn[1], rx_ipn[2], rx_ipn[3], rx_ipn[4], + rx_ipn[5], ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], + ipn[5]); + return false; + } + tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + tfm = NULL; + cds_err("crypto_alloc_cipher failed (%d)", ret); + goto err_tfm; + } + + ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128); + if (ret) { + cds_err("crypto_cipher_setkey failed (%d)", ret); + goto err_tfm; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + /* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ + nBytes = AAD_LEN + (efrm - (uint8_t *) (wh + 1)); + input = (uint8_t *) qdf_mem_malloc(nBytes); + if (NULL == input) { + cds_err("Memory allocation failed"); + ret = QDF_STATUS_E_NOMEM; + goto err_tfm; + } + + /* Copy the AAD, MMIE with 8 bit MIC zeroed out */ + qdf_mem_copy(input, aad, AAD_LEN); + qdf_mem_copy(input + AAD_LEN, (uint8_t *) (wh + 1), + nBytes - AAD_LEN - CMAC_TLEN); + + cds_cmac_calc_mic(tfm, input, nBytes, mic); + qdf_mem_free(input); + + cds_err("CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X", + mic[0], mic[1], mic[2], mic[3], + mic[4], mic[5], mic[6], mic[7]); + + if (OS_MEMCMP(mic, mmie->mic, CMAC_TLEN) != 0) { + /* MMIE MIC mismatch */ + cds_err("BC/MC MGMT frame MMIE MIC check Failed" + " rmic %02X %02X %02X %02X %02X %02X %02X %02X" + " cmic %02X %02X %02X %02X %02X %02X %02X %02X", + mmie->mic[0], mmie->mic[1], mmie->mic[2], + mmie->mic[3], mmie->mic[4], mmie->mic[5], + mmie->mic[6], mmie->mic[7], mic[0], mic[1], mic[2], + mic[3], mic[4], mic[5], mic[6], mic[7]); + return false; + } + + /* Update IPN */ + qdf_mem_copy(ipn, rx_ipn, CMAC_IPN_LEN); + +err_tfm: + if (tfm) + cds_crypto_free_cipher(tfm); + + return !ret ? true : false; +} + +#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 + +/** + * ipn_swap: Swaps ipn + * @d: destination pointer + * @s: source pointer + * + * Return: None + */ +static inline void ipn_swap(u8 *d, const u8 *s) +{ + *d++ = s[5]; + *d++ = s[4]; + *d++ = s[3]; + *d++ = s[2]; + *d++ = s[1]; + *d = s[0]; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, + uint8_t *efrm, uint16_t key_length) +{ + struct ieee80211_mmie_16 *mmie; + struct ieee80211_frame *wh; + uint8_t rx_ipn[6], aad[AAD_LEN]; + uint8_t mic[IEEE80211_MMIE_GMAC_MICLEN] = {0}; + uint16_t data_len; + uint8_t gmac_nonce[GMAC_NONCE_LEN]; + uint8_t iv[AES_BLOCK_SIZE] = {0}; + int ret; + + /* Check if frame is invalid length */ + if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) { + cds_err("Invalid frame length"); + return false; + } + + mmie = (struct ieee80211_mmie_16 *)(efrm - sizeof(*mmie)); + + /* Check Element ID */ + if ((mmie->element_id != IEEE80211_ELEMID_MMIE) || + (mmie->length != (sizeof(*mmie) - 2))) { + cds_err("IE is not Mgmt MIC IE or Invalid length"); + /* IE is not Mgmt MIC IE or invalid length */ + return false; + } + + /* Validate IPN */ + ipn_swap(rx_ipn, mmie->sequence_number); + if (qdf_mem_cmp(rx_ipn, ipn, IEEE80211_MMIE_IPNLEN) <= 0) { + /* Replay error */ + cds_debug("Replay error mmie ipn %02X %02X %02X %02X %02X %02X" + " drvr ipn %02X %02X %02X %02X %02X %02X", + rx_ipn[0], rx_ipn[1], rx_ipn[2], rx_ipn[3], rx_ipn[4], + rx_ipn[5], ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], + ipn[5]); + return false; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate AAD: FC(masked) || A1 || A2 || A3 */ + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + data_len = efrm - (uint8_t *) (wh + 1) - IEEE80211_MMIE_GMAC_MICLEN; + + /* IV */ + qdf_mem_copy(gmac_nonce, wh->i_addr2, IEEE80211_ADDR_LEN); + qdf_mem_copy(gmac_nonce + IEEE80211_ADDR_LEN, rx_ipn, + IEEE80211_MMIE_IPNLEN); + qdf_mem_copy(iv, gmac_nonce, GMAC_NONCE_LEN); + iv[AES_BLOCK_SIZE - 1] = 0x01; + + ret = qdf_crypto_aes_gmac(igtk, key_length, iv, aad, + (uint8_t *) (wh + 1), data_len, mic); + if (ret) { + cds_err("qdf_crypto_aes_gmac failed %d", ret); + return false; + } + + if (qdf_mem_cmp(mic, mmie->mic, IEEE80211_MMIE_GMAC_MICLEN) != 0) { + /* MMIE MIC mismatch */ + cds_debug("BC/MC MGMT frame MMIE MIC check Failed" + " rmic %02X %02X %02X %02X %02X %02X %02X %02X" + " %02X %02X %02X %02X %02X %02X %02X %02X", + mmie->mic[0], mmie->mic[1], mmie->mic[2], + mmie->mic[3], mmie->mic[4], mmie->mic[5], + mmie->mic[6], mmie->mic[7], mmie->mic[8], + mmie->mic[9], mmie->mic[10], mmie->mic[11], + mmie->mic[12], mmie->mic[13], mmie->mic[14], + mmie->mic[15]); + return false; + } + + /* Update IPN */ + qdf_mem_copy(ipn, rx_ipn, IEEE80211_MMIE_IPNLEN); + + return true; +} +#else +bool cds_is_gmac_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, + uint8_t *efrm, uint16_t key_length) +{ + return false; +} +#endif + +#endif /* WLAN_FEATURE_11W */ + +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; +} + +void cds_upper_to_lower(uint8_t *txt, uint32_t length) +{ + int i; + + for (i = 0; i < length; i++) { + if (txt[i] >= 'A' && txt[i] <= 'Z') + txt[i] = txt[i] + 32; + } +} + +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; + } + + 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/drivers/staging/qcacld-3.0/core/cds/src/i_cds_packet.h b/drivers/staging/qcacld-3.0/core/cds/src/i_cds_packet.h new file mode 100644 index 0000000000000000000000000000000000000000..24f900fcf9ef718dcf4f152ac71288b46e081bca --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/i_cds_packet.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 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. + */ + +#if !defined(__I_CDS_PACKET_H) +#define __I_CDS_PACKET_H + +/**========================================================================= + + \file i_cds_packet.h + + \brief Connectivity driver services network packet APIs + + Network Protocol packet/buffer internal include file + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_types.h" +/** + * Rx Packet Struct + * Buffer for the packet received from WMA has pointers to 802.11 + * frame fields and additional information based on the type of frame. + * @channel: Channel number + * @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: Bit set to 1 if packet received during scanning + * @scan_src: Source of scan + * @dpuFeedback: DPU feedback for frame + * @sessionId: PE session + * @tsf_delta: Delta between tsf in frame and local value of tsf + * @rssi_raw: rssi based on actual noise floor in hardware. + */ +typedef struct { + uint8_t channel; + 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:1; + uint8_t scan_src; + uint8_t dpuFeedback; + uint8_t sessionId; + uint32_t tsf_delta; + uint32_t rssi_raw; +} 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/drivers/staging/qcacld-3.0/core/cds/src/queue.h b/drivers/staging/qcacld-3.0/core/cds/src/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..73200429eaf77516184b1179a3533efede432dca --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/queue.h @@ -0,0 +1,571 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $ + */ + +#if !defined(__NetBSD__) +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char *lastfile; + int lastline; + char *prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)NULL; } while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) do {(x) = (void *)0; } while (0) +#endif /* QUEUE_MACRO_DEBUG */ + +#ifdef ATHR_RNWF +/* NDIS contains a defn for SLIST_ENTRY and SINGLE_LIST_ENTRY */ +#endif + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ + struct name { \ + struct type *slh_first; /* first element */ \ + } + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SING_LIST_ENTRY(type) \ + struct { \ + struct type *sle_next; /* next element */ \ + } + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ + struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ + } + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ + struct { \ + struct type *stqe_next; /* next element */ \ + } + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((curelm), field); \ + } \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if (STAILQ_NEXT(elm, field)) { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define ATH_LIST_HEAD(name, type) \ + struct name { \ + struct type *lh_first; /* first element */ \ + } + +#ifndef LIST_HEAD +#define LIST_HEAD ATH_LIST_HEAD +#endif + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ + struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ + } + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define HEADNAME +#define COPY_HEADNAME(head) + +#define TAILQ_HEAD(name, type) \ + struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + HEADNAME \ + TRACEBUF \ + } + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ + struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ + } + +/* + * Tail queue functions. + */ + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + COPY_HEADNAME(head); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +static __inline void insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !(__GNUC__ || __INTEL_COMPILER) */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ || __INTEL_COMPILER */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ +#else /* !__NetBSD__ */ +#include_next +#endif /* __NetBSD__ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt.c new file mode 100644 index 0000000000000000000000000000000000000000..cf33c26aaf250cde9086a1a597f6f13456f49e5f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt.c @@ -0,0 +1,971 @@ +/* + * 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. + */ + +/** + * @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 + +#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 == NULL) + pkt = qdf_mem_malloc(sizeof(*pkt)); + + if (!pkt) { + qdf_print("%s: HTC packet allocation failed\n", __func__); + 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("%s: HTC packet is NULL\n", __func__); + 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. + */ +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; +} +#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); + 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->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 negtive 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)); + } 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(NULL == hif_ctx)) { + QDF_ASSERT(NULL != 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; + + /* 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, + pdev->rx_ring.fill_cnt, + 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/drivers/staging/qcacld-3.0/core/dp/htt/htt_fw_stats.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_fw_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..f403434b2aa8d0b5274a9514744591787bb4f2b3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_fw_stats.c @@ -0,0 +1,1334 @@ +/* + * 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. + */ + +/** + * @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 + +#define ROUND_UP_TO_4(val) (((val) + 3) & ~0x3) + + +#ifdef WLAN_DEBUG +static char *bw_str_arr[] = {"20MHz", "40MHz", "80MHz", "160MHz"}; +#endif + +/* + * 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) +{ +#ifdef WLAN_DEBUG + struct wlan_dbg_tx_stats *tx = &wlan_pdev_stats->tx; + struct wlan_dbg_rx_stats *rx = &wlan_pdev_stats->rx; +#endif + + qdf_nofl_info("WAL Pdev stats:"); + qdf_nofl_info("\n### Tx ###"); + + /* Num HTT cookies queued to dispatch list */ + qdf_nofl_info("comp_queued :\t%d", tx->comp_queued); + /* Num HTT cookies dispatched */ + qdf_nofl_info("comp_delivered :\t%d", tx->comp_delivered); + /* Num MSDU queued to WAL */ + qdf_nofl_info("msdu_enqued :\t%d", tx->msdu_enqued); + /* Num MPDU queued to WAL */ + qdf_nofl_info("mpdu_enqued :\t%d", tx->mpdu_enqued); + /* Num MSDUs dropped by WMM limit */ + qdf_nofl_info("wmm_drop :\t%d", tx->wmm_drop); + /* Num Local frames queued */ + qdf_nofl_info("local_enqued :\t%d", tx->local_enqued); + /* Num Local frames done */ + qdf_nofl_info("local_freed :\t%d", tx->local_freed); + /* Num queued to HW */ + qdf_nofl_info("hw_queued :\t%d", tx->hw_queued); + /* Num PPDU reaped from HW */ + qdf_nofl_info("hw_reaped :\t%d", tx->hw_reaped); + /* Num underruns */ + qdf_nofl_info("mac underrun :\t%d", tx->underrun); + /* Num underruns */ + qdf_nofl_info("phy underrun :\t%d", tx->phy_underrun); + /* Num PPDUs cleaned up in TX abort */ + qdf_nofl_info("tx_abort :\t%d", tx->tx_abort); + /* Num MPDUs requed by SW */ + qdf_nofl_info("mpdus_requed :\t%d", tx->mpdus_requed); + /* Excessive retries */ + qdf_nofl_info("excess retries :\t%d", tx->tx_ko); + /* last data rate */ + qdf_nofl_info("last rc :\t%d", tx->data_rc); + /* scheduler self triggers */ + qdf_nofl_info("sched self trig :\t%d", tx->self_triggers); + /* SW retry failures */ + qdf_nofl_info("ampdu retry failed:\t%d", tx->sw_retry_failure); + /* ilegal phy rate errirs */ + qdf_nofl_info("illegal rate errs :\t%d", tx->illgl_rate_phy_err); + /* pdev continuous excessive retries */ + qdf_nofl_info("pdev cont xretry :\t%d", tx->pdev_cont_xretry); + /* pdev continuous excessive retries */ + qdf_nofl_info("pdev tx timeout :\t%d", tx->pdev_tx_timeout); + /* pdev resets */ + qdf_nofl_info("pdev resets :\t%d", tx->pdev_resets); + /* PPDU > txop duration */ + qdf_nofl_info("ppdu txop ovf :\t%d", tx->txop_ovf); + + qdf_nofl_info("\n### Rx ###\n"); + /* Cnts any change in ring routing mid-ppdu */ + qdf_nofl_info("ppdu_route_change :\t%d", rx->mid_ppdu_route_change); + /* Total number of statuses processed */ + qdf_nofl_info("status_rcvd :\t%d", rx->status_rcvd); + /* Extra frags on rings 0-3 */ + qdf_nofl_info("r0_frags :\t%d", rx->r0_frags); + qdf_nofl_info("r1_frags :\t%d", rx->r1_frags); + qdf_nofl_info("r2_frags :\t%d", rx->r2_frags); + qdf_nofl_info("r3_frags :\t%d", rx->r3_frags); + /* MSDUs / MPDUs delivered to HTT */ + qdf_nofl_info("htt_msdus :\t%d", rx->htt_msdus); + qdf_nofl_info("htt_mpdus :\t%d", rx->htt_mpdus); + /* MSDUs / MPDUs delivered to local stack */ + qdf_nofl_info("loc_msdus :\t%d", rx->loc_msdus); + qdf_nofl_info("loc_mpdus :\t%d", rx->loc_mpdus); + /* AMSDUs that have more MSDUs than the status ring size */ + qdf_nofl_info("oversize_amsdu :\t%d", rx->oversize_amsdu); + /* Number of PHY errors */ + qdf_nofl_info("phy_errs :\t%d", rx->phy_errs); + /* Number of PHY errors dropped */ + qdf_nofl_info("phy_errs dropped :\t%d", rx->phy_err_drop); + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + qdf_nofl_info("mpdu_errs :\t%d", rx->mpdu_errs); + +} + +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_nofl_info("Target doesn't support stats type %d", type); + return; + } else if (status == HTT_DBG_STATS_STATUS_ERROR) { + qdf_nofl_info("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_nofl_info("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/drivers/staging/qcacld-3.0/core/dp/htt/htt_h2t.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_h2t.c new file mode 100644 index 0000000000000000000000000000000000000000..0464e3e5ef7c3a5686a93c2d0ec02d3c60eae203 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_h2t.c @@ -0,0 +1,1506 @@ +/* + * 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. + */ + +/** + * @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 + +#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); \ +} 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); +} + +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 != NULL) { + send_complete_part2(htt_pkt->pdev_ctxt, htc_pkt->Status, netbuf, + htt_pkt->msdu_id); + } + + if (pdev->cfg.is_high_latency && !pdev->cfg.default_tx_comp_req) { + int32_t credit_delta; + + 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); + } + + /* 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, + 1); /* tag - not relevant here */ + + 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); +#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, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + 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 doesnot 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 != NULL) { + 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, + 1); /* tag - not relevant here */ + + 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, + "Doesnot 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 + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + 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, + "Doesnot 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 + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + 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); + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + 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 + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + 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; + + 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; + /* TX COMP RING BASE LO */ + 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; + /* TX COMP RING BASE HI, NONE */ + + 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_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr); + msg_word++; + *msg_word = 0; + + 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; + + 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; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_SET(*msg_word, + 0); + + 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; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_SET(*msg_word, + 0); + + 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; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_SET(*msg_word, + 0); + + 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; + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_SET(*msg_word, + 0); + + 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; + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_SET(*msg_word, + 0); + + 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; + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_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, + 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/drivers/staging/qcacld-3.0/core/dp/htt/htt_internal.h b/drivers/staging/qcacld-3.0/core/dp/htt/htt_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..972946430d928c42a93f80c4594348ecde945b85 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_internal.h @@ -0,0 +1,1044 @@ +/* + * 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. + */ + +#ifndef _HTT_INTERNAL__H_ +#define _HTT_INTERNAL__H_ + +#include /* A_STATUS */ +#include /* qdf_nbuf_t */ +#include /* qdf_assert */ +#include /* HTC_PACKET */ + +#include + +#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 +#define NBUF_MAP_ID(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.dev.priv_cb_m.map_index) + +#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 : virual 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 recived + * @recvd : 0x48545452584D5367 ('HTTRXMSG') + */ +#define HTT_RX_RING_BUFF_DBG_LIST (2 * 1024) +struct rx_buf_debug { + qdf_dma_addr_t paddr; + qdf_nbuf_t nbuf; + void *nbuf_data; + uint64_t posted; /* timetamp */ + 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_print + ("----------------------RX DESC LRO----------------------\n"); + qdf_print("msdu_end.lro_eligible:0x%x\n", + rx_desc->msdu_end.lro_eligible); + qdf_print("msdu_start.tcp_only_ack:0x%x\n", + rx_desc->msdu_start.tcp_only_ack); + qdf_print("msdu_end.tcp_udp_chksum:0x%x\n", + rx_desc->msdu_end.tcp_udp_chksum); + qdf_print("msdu_end.tcp_seq_number:0x%x\n", + rx_desc->msdu_end.tcp_seq_number); + qdf_print("msdu_end.tcp_ack_number:0x%x\n", + rx_desc->msdu_end.tcp_ack_number); + qdf_print("msdu_start.tcp_proto:0x%x\n", + rx_desc->msdu_start.tcp_proto); + qdf_print("msdu_start.ipv6_proto:0x%x\n", + rx_desc->msdu_start.ipv6_proto); + qdf_print("msdu_start.ipv4_proto:0x%x\n", + rx_desc->msdu_start.ipv4_proto); + qdf_print("msdu_start.l3_offset:0x%x\n", + rx_desc->msdu_start.l3_offset); + qdf_print("msdu_start.l4_offset:0x%x\n", + rx_desc->msdu_start.l4_offset); + qdf_print("msdu_start.flow_id_toeplitz:0x%x\n", + rx_desc->msdu_start.flow_id_toeplitz); + qdf_print + ("---------------------------------------------------------\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_print + ("----------------------RX DESC----------------------------\n"); + qdf_print("attention: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->attention)); + qdf_print("frag_info: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->frag_info)); + qdf_print("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_print("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_print("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_print("mpdu_end: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->mpdu_end)); + qdf_print("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_print("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_print + ("---------------------------------------------------------\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 + +#define HTT_MAC_ADDR_LEN 6 + +/* + * 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) + +#define HTT_TX_DESC_PADDR(_pdev, _tx_desc_vaddr) \ + ((_pdev)->tx_descs.pool_paddr + (uint32_t) \ + ((char *)(_tx_desc_vaddr) - \ + (char *)((_pdev)->tx_descs.pool_vaddr))) + +#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); + +#if defined(HELIUMPLUS) +QDF_STATUS +htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev); +#endif /* defined(HELIUMPLUS) */ + +extern QDF_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev); + +extern QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_ll(struct htt_pdev_t *pdev); + +extern QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_hl(struct htt_pdev_t *pdev); + +extern 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 CONFIG_HL_SUPPORT +static inline int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr, + qdf_nbuf_t netbuf) +{ + return 0; +} +#else +int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr, + qdf_nbuf_t netbuf); +#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 != NULL) && + (pdev->rx_buff_list != NULL)) { + buf = pdev->rx_buff_list; + for (i = 0; i < HTT_RX_RING_BUFF_DBG_LIST; i++) { + if (buf[i].posted != 0) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "[%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_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "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_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "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()); + NBUF_MAP_ID(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 = NBUF_MAP_ID(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 CONFIG_HL_SUPPORT + +#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 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("%s: paddr not marked correctly: 0x%pK!\n", + __func__, (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 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); + pdev->rx_ring.fill_cnt--; + paddr = htt_paddr_trim_to_37(paddr); + return htt_rx_hash_list_lookup(pdev, paddr); +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +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); +#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; +} +#endif +#endif + +#endif /* _HTT_INTERNAL__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_monitor_rx.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_monitor_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..25607641d7759fddfdb3d9b7be196bbd076aa237 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_monitor_rx.c @@ -0,0 +1,1085 @@ +/* + * 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. + */ + +#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 /* ieee80211_rx_status */ +#include +#include +#include "ol_txrx_types.h" +#ifdef DEBUG_DMA_DONE +#include +#include +#endif +#include + +#define HTT_FCS_LEN (4) + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +enum { + HW_RX_DECAP_FORMAT_RAW = 0, + HW_RX_DECAP_FORMAT_NWIFI, + HW_RX_DECAP_FORMAT_8023, + HW_RX_DECAP_FORMAT_ETH2, +}; + +/** + * 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("%s: netbuf pop failed!\n", __func__); + 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 = 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("%s: netbuf pop failed!\n", __func__); + 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 = 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); + rx_status->ht_flags = ht_flags; + rx_status->vht_flags = vht_flags; + rx_status->rtap_flags |= ((preamble == SHORT_PREAMBLE) ? BIT(1) : 0); + if (bw == 0) + rx_status->vht_flag_values2 = 0; + else if (bw == 1) + rx_status->vht_flag_values2 = 1; + else if (bw == 2) + rx_status->vht_flag_values2 = 4; +} + +/** + * 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; +} + +/** + * htt_rx_mon_get_rx_status() - Update information about the rx status, + * which is used later for radiotap updation. + * @rx_desc: Pointer to struct htt_host_rx_desc_base + * @rx_status: Return variable updated with rx_status + * + * Return: None + */ +static 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) +{ + uint16_t channel_flags = 0; + 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); + channel_flags |= rx_desc->ppdu_start.l_sig_rate_select ? + IEEE80211_CHAN_CCK : IEEE80211_CHAN_OFDM; + channel_flags |= + (cds_chan_to_band(ch_info->ch_num) == CDS_BAND_2GHZ ? + IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ); + + rx_status->chan_flags = channel_flags; + rx_status->ant_signal_db = rx_desc->ppdu_start.rssi_comb; +} + +/** + * 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; + struct mon_rx_status rx_status = {0}; + 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("%s: netbuf pop failed!\n", __func__); + *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("%s: netbuf pop failed!\n", + __func__); + 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. + */ + htt_rx_mon_get_rx_status(pdev, rx_desc, &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(&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 = 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("%s: failed to handle amsdu packet\n", + __func__); + 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("%s: netbuf pop failed!\n", + __func__); + *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(QCA6290_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] & 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 + * accomodating 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 diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_rx.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..6e048acb238b17bea2e703dc53630e2139de5010 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_rx.c @@ -0,0 +1,3281 @@ +/* + * 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. + */ + +/** + * @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 /* ieee80211_rx_status */ +#include +#include +#include "ol_txrx_types.h" +#ifdef DEBUG_DMA_DONE +#include +#include +#endif +#include + +/* AR9888v1 WORKAROUND for EV#112367 */ +/* FIX THIS - remove this WAR when the bug is fixed */ +#define PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR + +/*--- setup / tear-down functions -------------------------------------------*/ + +#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_AVG_FRM_BYTES +#define HTT_RX_AVG_FRM_BYTES 1000 +#endif + +#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 + +/*--- RX In Order Definitions ------------------------------------------------*/ + +/* 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 + +#ifndef CONFIG_HL_SUPPORT +/** + * 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__); + } +} + +/* 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 (NULL == pdev->rx_ring.hash_table) + return; + + if (qdf_mem_smmu_s1_enabled(pdev->osdev) && pdev->is_ipa_uc_enabled && + pdev->rx_ring.smmu_map) + ipa_smmu = true; + + qdf_spin_lock_bh(&(pdev->rx_ring.rx_hash_lock)); + 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) { + qdf_update_mem_map_table(pdev->osdev, + &mem_map_table, + QDF_NBUF_CB_PADDR( + hash_entry->netbuf), + HTT_RX_BUF_SIZE); + + 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)); +} +#endif + +/* + * 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)]; +} + +/** + * 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; +} + +#ifdef CONFIG_HL_SUPPORT +static uint16_t +htt_rx_mpdu_desc_seq_num_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (pdev->rx_desc_size_hl) { + 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)(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); + } +} +#endif + +/** + * 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); +} + +#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 + +#ifndef CONFIG_HL_SUPPORT +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); +} + +#endif /* CONFIG_HL_SUPPORT*/ + +/** + * 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() - retrun 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}; + bool ipa_smmu = false; + + idx = *(pdev->rx_ring.alloc_idx.vaddr); + + if (qdf_mem_smmu_s1_enabled(pdev->osdev) && pdev->is_ipa_uc_enabled && + pdev->rx_ring.smmu_map) + ipa_smmu = true; + + 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; + } + + if (ipa_smmu) { + qdf_update_mem_map_table(pdev->osdev, &mem_map_table, + paddr, HTT_RX_BUF_SIZE); + cds_smmu_map_unmap(true, 1, &mem_map_table); + } + + pdev->rx_ring.buf.paddrs_ring[idx] = paddr_marked; + 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; +} + +#ifndef CONFIG_HL_SUPPORT +static int htt_rx_ring_size(struct htt_pdev_t *pdev) +{ + int size; + + /* + * 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); + 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)); +} +#endif + +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; +} + +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; +} + +#ifndef CONFIG_HL_SUPPORT + +void htt_rx_detach(struct htt_pdev_t *pdev) +{ + bool ipa_smmu = false; + qdf_timer_stop(&pdev->rx_ring.refill_retry_timer); + qdf_timer_free(&pdev->rx_ring.refill_retry_timer); + htt_rx_dbg_rxbuf_deinit(pdev); + + if (qdf_mem_smmu_s1_enabled(pdev->osdev) && pdev->is_ipa_uc_enabled && + pdev->rx_ring.smmu_map) + ipa_smmu = true; + + 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)) { + if (ipa_smmu) { + qdf_update_mem_map_table(pdev->osdev, + &mem_map_table, + QDF_NBUF_CB_PADDR( + pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx]), + HTT_RX_BUF_SIZE); + cds_smmu_map_unmap(false, 1, + &mem_map_table); + } +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, + pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx], + QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, + pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx], + QDF_DMA_FROM_DEVICE); +#endif + qdf_nbuf_free(pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx]); + 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)); +} +#endif + +/** + * 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; +} + +/*--- 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). + */ +/* FIX THIS: APPLIES TO LL ONLY */ + +#ifndef CONFIG_HL_SUPPORT +/** + * 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) +{ + 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); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +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); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +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); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +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; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +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; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +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; +} +#endif + +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; +} + +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; + pdev->rx_ring.fill_cnt--; + return msdu; +} + +/* + * FIX ME: this function applies only to LL rx descs. + * An equivalent for HL rx descs is needed. + */ +#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 +} + +#if defined(CONFIG_HL_SUPPORT) + +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); +} +#endif + +#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) +{ +} + +#if defined(CONFIG_HL_SUPPORT) + +static inline +void htt_set_checksum_result_hl(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ +} +#endif + +#endif + +#ifdef DEBUG_DMA_DONE +#define MAX_DONE_BIT_CHECK_ITER 5 +#endif + +#ifndef CONFIG_HL_SUPPORT +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(HTT_T2H_MSG_TYPE_RX_FRAG_IND == msg_type)) { + 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 + (HTT_T2H_MSG_TYPE_RX_FRAG_IND == msg_type)) + 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; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +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 0; +} + +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; +} +#endif + +static inline int +htt_rx_offload_msdu_cnt_ll( + htt_pdev_handle pdev) +{ + return htt_rx_ring_elems(pdev); +} + +#ifndef CONFIG_HL_SUPPORT +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(NULL == buf)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + 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(NULL == buf)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + 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; +} +#endif + +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); +} + +#ifndef CONFIG_HL_SUPPORT +/* 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) + +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; + enum rx_pkt_fate status = RX_PKT_FATE_SUCCESS; + qdf_dma_addr_t paddr; + qdf_mem_info_t mem_map_table = {0}; + int ret = 1; + bool ipa_smmu = false; + + 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); + + if (qdf_mem_smmu_s1_enabled(pdev->osdev) && pdev->is_ipa_uc_enabled && + pdev->rx_ring.smmu_map) + ipa_smmu = true; + + 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(NULL == msdu)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + *tail_msdu = NULL; + pdev->rx_ring.pop_fail_cnt++; + ret = 0; + goto end; + } + + while (msdu_count > 0) { + if (ipa_smmu) { + qdf_update_mem_map_table(pdev->osdev, &mem_map_table, + QDF_NBUF_CB_PADDR(msdu), + HTT_RX_BUF_SIZE); + 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("%s: netbuf pop failed!\n", + __func__); + *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); + + /* + * 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 = RX_PKT_FATE_FW_DROP_INVALID; + 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(NULL == next)) { + qdf_print("%s: netbuf pop failed!\n", + __func__); + *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; + } + } + + /* Update checksum result */ + htt_set_checksum_result_ll(pdev, msdu, rx_desc); + + /* 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(NULL == next)) { + qdf_print("%s: netbuf pop failed!\n", + __func__); + *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); + } + } + +end: + return ret; +} +#endif + +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); + +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); + +#ifndef CONFIG_HL_SUPPORT +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); +} +#endif + +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); + +#ifndef CONFIG_HL_SUPPORT +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); +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * 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; +} + +#endif + +#ifndef CONFIG_HL_SUPPORT +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_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; +} +#endif + +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. + */ +} + +#if defined(CONFIG_HL_SUPPORT) + +/** + * htt_rx_fill_ring_count() - replenish rx msdu buffer + * @pdev: Handle (pointer) to HTT pdev. + * + * This funciton will replenish the rx buffer to the max number + * that can be kept in the ring + * + * Return: None + */ +static inline void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ +} +#else + +static void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ + int num_to_fill; + + num_to_fill = pdev->rx_ring.fill_level - pdev->rx_ring.fill_cnt; + htt_rx_ring_fill_n(pdev, num_to_fill /* okay if <= 0 */); +} +#endif + +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); +} + +#define RX_RING_REFILL_DEBT_MAX 128 +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; +} + +#ifndef CONFIG_HL_SUPPORT +#define AR600P_ASSEMBLE_HW_RATECODE(_rate, _nss, _pream) \ + (((_pream) << 6) | ((_nss) << 4) | (_rate)) + +enum AR600P_HW_RATECODE_PREAM_TYPE { + AR600P_HW_RATECODE_PREAM_OFDM, + AR600P_HW_RATECODE_PREAM_CCK, + AR600P_HW_RATECODE_PREAM_HT, + AR600P_HW_RATECODE_PREAM_VHT, +}; + +/*--- RX In Order Hash Code --------------------------------------------------*/ + +/* 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(NULL == 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(NULL == 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: %s: paddr 0x%x netbuf %pK bucket %d\n", + __func__, paddr, netbuf, (int)i)); + + 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; +} +#endif + +#ifndef CONFIG_HL_SUPPORT +/* + * 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; + } + } + + RX_HASH_LOG(qdf_print("rx hash: %s: paddr 0x%x, netbuf %pK, bucket %d\n", + __func__, 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 == NULL) { + qdf_print("rx hash: %s: no entry found for %pK!\n", + __func__, (void *)paddr); + if (cds_is_self_recovery_enabled()) + cds_trigger_recovery(QDF_RX_HASH_NO_ENTRY_FOUND); + else + HTT_ASSERT_ALWAYS(0); + } + + 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 (NULL == pdev->rx_ring.hash_table) { + qdf_print("rx hash table allocation failed!\n"); + 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 (NULL == 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; +} +#endif + +/*--- RX In Order Hash Code --------------------------------------------------*/ + +/* move the function to the end of file + * to omit ll/hl pre-declaration + */ + +#if defined(CONFIG_HL_SUPPORT) + +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 */ +} + +#else + +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); + + pdev->rx_ring.fill_cnt = 0; + 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, + "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 */ +} +#endif + +#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(qdf_dma_addr_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 */ + +#ifndef REMOVE_PKT_LOG +/** + * 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("%s: %s, %s", + __func__, + "htt pdev is NULL", + "rx packet status callback register unsuccessful\n"); + 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("%s: %s, %s", + __func__, + "htt pdev is NULL", + "rx packet status callback deregister unsuccessful\n"); + return; + } + pdev->rx_pkt_dump_cb = NULL; +} + +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}; + 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); + if (hash_entry->netbuf) { + qdf_update_mem_map_table(pdev->osdev, + &mem_map_table, + QDF_NBUF_CB_PADDR( + hash_entry->netbuf), + HTT_RX_BUF_SIZE); + ret = cds_smmu_map_unmap(map, 1, + &mem_map_table); + if (ret) { + qdf_spin_unlock_bh( + &pdev->rx_ring.rx_hash_lock); + return QDF_STATUS_E_FAILURE; + } + } + list_iter = list_iter->next; + } + } + 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 (NULL == 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); + pdev->rx_ring.smmu_map = map; + status = htt_rx_hash_smmu_map(map, pdev); + qdf_spin_unlock_bh(&pdev->rx_ring.refill_lock); + + return status; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS +void htt_rx_enable_ppdu_end(int *enable_ppdu_end) +{ + *enable_ppdu_end = 1; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_t2h.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_t2h.c new file mode 100644 index 0000000000000000000000000000000000000000..91a97bd6fd04ae57619a9251faf2a4fef5bc3f0e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_t2h.c @@ -0,0 +1,1645 @@ +/* + * 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. + */ + +/** + * @file 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 /* htt_tx_status */ + +#include /* HTT_TX_SCHED, etc. */ +#include +#include +#include +#include +#include +#include "pktlog_ac.h" +#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) { + qdf_print("OPCODE message buffer alloc fail"); + 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), + (struct cdp_pdev *)pdev->txrx_pdev, + op_msg_buffer); +} +#else +static void htt_ipa_op_response(struct htt_pdev_t *pdev, uint32_t *msg_word) +{ +} +#endif + +#define MAX_TARGET_TX_CREDIT 204800 + +/* 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: + { + 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("%s: invalid packet len, %u\n", + __func__, + 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: + { + qdf_print("HTT_T2H_MSG_TYPE_RX_ADDBA not supported "); + break; + } + case HTT_T2H_MSG_TYPE_RX_DELBA: + { + qdf_print("HTT_T2H_MSG_TYPE_RX_DELBA not supported "); + break; + } + case HTT_T2H_MSG_TYPE_PEER_MAP: + { + uint8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN]; + 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); + + 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("%s: invalid nbuff len \n", __func__); + WARN_ON(1); + break; + } + + /*len is reduced by sizeof(*msg_word)*/ + pktlog_process_fw_msg(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_print("%s: invalid credit update,old_credit=%d," + "htt_credit_delta=%d\n", + __func__, + old_credit, + htt_credit_delta); + break; + } + + 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); + } + + htt_tx_group_credit_process(pdev, msg_word); + 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_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_error_info err_info; + struct ol_txrx_vdev_t *vdev; + struct ol_txrx_peer_t *peer; + 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("%s: invalid peer id %d\n", + __func__, peer_id); + qdf_assert(0); + break; + } + vdev = peer->vdev; + err_info.u.mic_err.vdev_id = vdev->vdev_id; + err_info.u.mic_err.key_id = + HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_GET + (*(msg_word + 1)); + qdf_mem_copy(err_info.u.mic_err.da, + (uint8_t *)(msg_word + 2), + OL_TXRX_MAC_ADDR_LEN); + qdf_mem_copy(err_info.u.mic_err.sa, + (uint8_t *)(msg_word + 4), + OL_TXRX_MAC_ADDR_LEN); + qdf_mem_copy(&err_info.u.mic_err.pn, + (uint8_t *)(msg_word + 6), 6); + qdf_mem_copy(err_info.u.mic_err.ta, + peer->mac_addr.raw, OL_TXRX_MAC_ADDR_LEN); + + wma_indicate_err(OL_RX_ERR_TKIP_MIC, &err_info); + break; + } + default: + { + qdf_print("%s: unhandled error type %d\n", + __func__, + HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(*msg_word)); + break; + } + } + } + + 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 succes 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) { + 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_print("%s: invalid credit update,old_credit=%d," + "num_msdus=%d\n", + __func__, + 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("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not "); + qdf_print("supported when full reorder offload is "); + qdf_print("disabled in the configuration.\n"); + break; + } + + if (qdf_unlikely(pdev->cfg.is_high_latency)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND "); + qdf_print("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 defined(HELIUMPLUS_DEBUG) + qdf_print("%s %d: peerid %d tid %d offloadind %d fragind %d\n", + __func__, __LINE__, 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_CB_PADDR(_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), \ + PCI_DMA_FROMDEVICE); \ + } 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; + + 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_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/drivers/staging/qcacld-3.0/core/dp/htt/htt_tx.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_tx.c new file mode 100644 index 0000000000000000000000000000000000000000..28ffb4823a2beecdc6db0d74edc4edaa1c3cafba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_tx.c @@ -0,0 +1,1939 @@ +/* + * 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. + */ + +/** + * @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 + +/* 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 +#define IPA_UC_TX_BUF_PADDR_HI_OFFSET 32 +#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_HI_UPDATE(frag_filed_ptr) \ +do { \ + frag_filed_ptr++; \ + /* frags_desc_ptr.hi */ \ + *frag_filed_ptr = 0; \ +} while (0) +#else +#define HTT_TX_DESC_FRAG_FIELD_HI_UPDATE(frag_filed_ptr) {} +#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; + + 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]; + *fptr = (uint32_t)(dma_page->page_p_addr + + offset * pdev->frag_descs.size); + HTT_TX_DESC_FRAG_FIELD_HI_UPDATE(fptr); +} + +/** + * 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) || + (NULL == 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) || + (NULL == 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\n", + 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 decriptor 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 decriptor 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) || + (NULL == 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\n", + 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 != NULL) { + 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("*** %s currently only applies for HL systems\n", __func__); + 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); +} + +#else /*ATH_11AC_TXCOMPACT */ + +#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 +/** + * 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; + unsigned int tx_buffer_count_pwr2; + qdf_dma_addr_t buffer_paddr; + uint32_t *header_ptr; + qdf_dma_addr_t *ring_vaddr; + uint16_t idx; + qdf_mem_info_t *mem_map_table = NULL, *mem_info = NULL; + qdf_shared_mem_t *shared_tx_buffer; + + ring_vaddr = (qdf_dma_addr_t *)pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr; + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + mem_map_table = qdf_mem_map_table_alloc(uc_tx_buf_cnt); + if (!mem_map_table) { + qdf_print("%s: Failed to allocate memory for mem map table\n", + __func__); + return 0; + } + mem_info = mem_map_table; + } + + /* 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\n", + tx_buffer_count); + goto pwr2; + } + + 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++; + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + *mem_info = pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[ + tx_buffer_count]->mem_info; + mem_info++; + } + } + +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; + } + } + } + + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + cds_smmu_map_unmap(true, tx_buffer_count_pwr2, + mem_map_table); + qdf_mem_free(mem_map_table); + } + + return tx_buffer_count_pwr2; +} + +/** + * 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; + qdf_mem_info_t *mem_map_table = NULL, *mem_info = NULL; + uint32_t num_unmapped = 0; + + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + mem_map_table = qdf_mem_map_table_alloc( + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); + if (!mem_map_table) { + qdf_print("%s: Failed to allocate memory for mem map table\n", + __func__); + return; + } + mem_info = mem_map_table; + } + + 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]) { + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + *mem_info = pdev->ipa_uc_tx_rsc. + tx_buf_pool_strg[idx]->mem_info; + mem_info++; + num_unmapped++; + } + 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; + } + } + + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + if (num_unmapped) + cds_smmu_map_unmap(false, num_unmapped, mem_map_table); + qdf_mem_free(mem_map_table); + } +} +#else +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_mem_info_t *mem_map_table = NULL, *mem_info = NULL; + qdf_shared_mem_t *shared_tx_buffer; + + ring_vaddr = pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr; + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + mem_map_table = qdf_mem_map_table_alloc(uc_tx_buf_cnt); + if (!mem_map_table) { + qdf_print("%s: Failed to allocate memory for mem map table\n", + __func__); + return 0; + } + mem_info = mem_map_table; + } + + /* 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("%s: TX BUF alloc fail, loop index: %d", + __func__, 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++; + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + *mem_info = pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[ + tx_buffer_count]->mem_info; + mem_info++; + } + } + +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; + } + } + } + + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + cds_smmu_map_unmap(true, tx_buffer_count_pwr2, + mem_map_table); + qdf_mem_free(mem_map_table); + } + + return tx_buffer_count_pwr2; +} + +static void htt_tx_buf_pool_free(struct htt_pdev_t *pdev) +{ + uint16_t idx; + qdf_mem_info_t *mem_map_table = NULL, *mem_info = NULL; + uint32_t num_unmapped = 0; + + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + mem_map_table = qdf_mem_map_table_alloc( + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); + if (!mem_map_table) { + qdf_print("%s: Failed to allocate memory for mem map table\n", + __func__); + return; + } + mem_info = mem_map_table; + } + + 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]) { + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + *mem_info = pdev->ipa_uc_tx_rsc. + tx_buf_pool_strg[idx]->mem_info; + mem_info++; + num_unmapped++; + } + 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; + } + } + + if (qdf_mem_smmu_s1_enabled(pdev->osdev)) { + if (num_unmapped) + cds_smmu_map_unmap(false, num_unmapped, mem_map_table); + qdf_mem_free(mem_map_table); + } +} +#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("%s: Unable to allocate memory for IPA tx ce idx\n", + __func__); + return -ENOBUFS; + } + + /* Allocate TX COMP Ring */ + tx_comp_ring_size = 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("%s: TX COMP ring alloc fail", __func__); + return_code = -ENOBUFS; + goto free_tx_ce_idx; + } + + /* 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) { + qdf_print("%s: TX BUF POOL vaddr storage alloc fail", __func__); + 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); + + + 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\n", + __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\n", + __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\n", + __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 + */ +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; +} + +/** + * 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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf_ctx is NULL", __func__); + 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_STATUS status; + + if (qdf_unlikely(!qdf_ctx)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf_ctx is NULL", __func__); + 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\n", + __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) { + 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_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 << QDF_CE_TX_CLASSIFY_BIT_S; + data_attr |= ce_pkt_type << QDF_CE_TX_PKT_TYPE_BIT_S; + data_attr |= pkt_offset << QDF_CE_TX_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/drivers/staging/qcacld-3.0/core/dp/htt/htt_types.h b/drivers/staging/qcacld-3.0/core/dp/htt/htt_types.h new file mode 100644 index 0000000000000000000000000000000000000000..2f1d49ab603f9ec83457927272d06e17f2dd4540 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_types.h @@ -0,0 +1,459 @@ +/* + * 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. + */ + +#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 wont 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_tx_mgmt_desc_buf { + qdf_nbuf_t msg_buf; + A_BOOL is_inuse; + qdf_nbuf_t mgmt_frm; +}; + +struct htt_tx_mgmt_desc_ctxt { + struct htt_tx_mgmt_desc_buf *pool; + A_UINT32 pending_cnt; +}; + +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; + + uint32_t tx_comp_idx_paddr; + qdf_shared_mem_t **tx_buf_pool_strg; + uint32_t alloc_tx_buf_cnt; +}; + +/** + * 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; + } 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 */ + int fill_cnt; /* # of rx buffers (full+empty) in the ring */ + 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 htt_tx_mgmt_desc_ctxt tx_mgmt_desc_ctxt; + 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/drivers/staging/qcacld-3.0/core/dp/htt/rx_desc.h b/drivers/staging/qcacld-3.0/core/dp/htt/rx_desc.h new file mode 100644 index 0000000000000000000000000000000000000000..cd31a86a86df829215f61a6c570e81cd97c9c1c9 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_cfg.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..3bd27bc0828650b8f5bb6a00a20c385eb255a176 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_cfg.h @@ -0,0 +1,739 @@ +/* + * 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 _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 + +/** + * @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[4]; + 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 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; + + struct ol_tx_sched_wrr_ac_specs_t ac_specs[TX_WMM_AC_NUM]; + + /* Flag to indicate whether new htt format is supported */ + bool new_htt_format_enabled; +}; + +#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_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 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; +} + +/** + * 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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_ctrl_addba_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_ctrl_addba_api.h new file mode 100644 index 0000000000000000000000000000000000000000..dabafdb802c1f077c64e35714efb86abe79ddb71 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_ctrl_addba_api.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013-2015 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_CTRL_ADDBA_API_H_ +#define _OL_CTRL_ADDBA_API_H_ +#define ol_ctrl_addba_attach(a, b, c, d, e) 0 +#define ol_ctrl_addba_detach(a) 0 +#define ol_ctrl_addba_init(a, b, c, d, e) 0 +#define ol_ctrl_addba_cleanup(a) 0 +#define ol_ctrl_addba_request_setup(a, b, c, d, e, f) 0 +#define ol_ctrl_addba_response_setup(a, b, c, d, e, f) 0 +#define ol_ctrl_addba_request_process(a, b, c, d, e) 0 +#define ol_ctrl_addba_response_process(a, b, c, d) 0 +#define ol_ctrl_addba_clear(a) 0 +#define ol_ctrl_delba_process(a, b, c) 0 +#define ol_ctrl_addba_get_status(a, b) 0 +#define ol_ctrl_addba_set_response(a, b, c) 0 +#define ol_ctrl_addba_clear_response(a) 0 +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_defines.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..3e73310b62a8d13db32043b33cc805389b10576f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_defines.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-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. + */ + +/* + * Offload specific Opaque Data types. + */ +#ifndef _DEV_OL_DEFINES_H +#define _DEV_OL_DEFINES_H + + /** + * 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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..afb04d2bb2f8e82c756f9c4130f5896d4ccce231 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h @@ -0,0 +1,417 @@ +/* + * 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. + */ + +/** + * @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 +/* TID */ +#define OL_HTT_TID_NON_QOS_UNICAST 16 +#define OL_HTT_TID_NON_QOS_MCAST_BCAST 18 + +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); + +#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); +#ifdef REMOVE_PKT_LOG +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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..03bce9614b8d0b916709d92a40447e49a4250040 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h @@ -0,0 +1,921 @@ +/* + * 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. + */ + +/** + * @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 /* uint16_t, etc. */ +#include /* qdf_nbuf_t */ +#include /* bool */ + +#include /* HTT_RX_IND_MPDU_STATUS */ +#include /* htt_pdev_handle */ + +#include /* ieee80211_rx_status */ +#include + +/*================ constants and types used in the rx API ===================*/ + +#define HTT_RSSI_INVALID 0x7fff + +/** + * 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 + * paramaters 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); + +/** + * @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 + */ +int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num); + +/** + * @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_staus - 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(QCA6290_HEADERS_DEF) && defined(FEATURE_MONITOR_MODE_SUPPORT) +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 + +/** + * @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); + +/** + * 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); + +/** + * @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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..99dcece58881b3e61cf141ddfe75f0daf6d5042b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h @@ -0,0 +1,844 @@ +/* + * 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. + */ + +/** + * @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_BYTES 0 +#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 + * paramaters 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 dicards 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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_params.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_params.h new file mode 100644 index 0000000000000000000000000000000000000000..08b066a1ceb0c15812df97d7e9930fc1ac38ea1f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_params.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2013-2015, 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. + */ + +/* + * Definitions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_OL_PARAMS_H +#define _DEV_OL_PARAMS_H +#include "ol_txrx_stats.h" +#include "wlan_defs.h" /* for wlan statst definitions */ +/* + * Enumeration of PDEV Configuration parameter + */ + +enum ol_ath_param_t { + OL_ATH_PARAM_TXCHAINMASK = 0, + OL_ATH_PARAM_RXCHAINMASK, + OL_ATH_PARAM_TXCHAINMASKLEGACY, + OL_ATH_PARAM_RXCHAINMASKLEGACY, + OL_ATH_PARAM_CHAINMASK_SEL, + OL_ATH_PARAM_AMPDU, + OL_ATH_PARAM_AMPDU_LIMIT, + OL_ATH_PARAM_AMPDU_SUBFRAMES, + OL_ATH_PARAM_LDPC, + OL_ATH_PARAM_NON_AGG_SW_RETRY_TH, + OL_ATH_PARAM_AGG_SW_RETRY_TH, + OL_ATH_PARAM_STA_KICKOUT_TH, + OL_ATH_PARAM_WLAN_PROF_ENABLE, + OL_ATH_PARAM_LTR_ENABLE, + OL_ATH_PARAM_LTR_AC_LATENCY_BE, + OL_ATH_PARAM_LTR_AC_LATENCY_BK, + OL_ATH_PARAM_LTR_AC_LATENCY_VI, + OL_ATH_PARAM_LTR_AC_LATENCY_VO, + OL_ATH_PARAM_LTR_AC_LATENCY_TIMEOUT, + OL_ATH_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + OL_ATH_PARAM_LTR_SLEEP_OVERRIDE, + OL_ATH_PARAM_LTR_RX_OVERRIDE, + OL_ATH_PARAM_L1SS_ENABLE, + OL_ATH_PARAM_DSLEEP_ENABLE, + OL_ATH_PARAM_PCIELP_TXBUF_FLUSH, + OL_ATH_PARAM_PCIELP_TXBUF_WATERMARK, + OL_ATH_PARAM_PCIELP_TXBUF_TMO_EN, + OL_ATH_PARAM_PCIELP_TXBUF_TMO_VALUE, + OL_ATH_PARAM_BCN_BURST, + OL_ATH_PARAM_ARP_AC_OVERRIDE, + OL_ATH_PARAM_TXPOWER_LIMIT2G, + OL_ATH_PARAM_TXPOWER_LIMIT5G, + OL_ATH_PARAM_TXPOWER_SCALE, + OL_ATH_PARAM_DCS, + OL_ATH_PARAM_ANI_ENABLE, + OL_ATH_PARAM_ANI_POLL_PERIOD, + OL_ATH_PARAM_ANI_LISTEN_PERIOD, + OL_ATH_PARAM_ANI_OFDM_LEVEL, + OL_ATH_PARAM_ANI_CCK_LEVEL, + OL_ATH_PARAM_PROXYSTA, + OL_ATH_PARAM_DYN_TX_CHAINMASK, + OL_ATH_PARAM_VOW_EXT_STATS, + OL_ATH_PARAM_PWR_GATING_ENABLE, + OL_ATH_PARAM_CHATTER, +}; + +/* + * Enumeration of PDEV Configuration parameter + */ + +enum ol_hal_param_t { + OL_HAL_CONFIG_DMA_BEACON_RESPONSE_TIME = 0 +}; + +/* + * structure to hold all stats information + * for offload device interface + */ +struct ol_stats { + int txrx_stats_level; + struct ol_txrx_stats txrx_stats; + struct wlan_dbg_stats stats; +}; +#endif /* _DEV_OL_PARAMS_H */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..67adf2cd77d3ec3a6aa9cb7ab047e29bd43af2a2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2011-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. + */ + +/** + * @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_ + +/** + * @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 +}; + +typedef void (*tp_ol_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb); +void ol_deregister_packetdump_callback(void); + +#ifdef WLAN_FEATURE_TSF_PLUS +typedef int (*tp_ol_timestamp_cb)(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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h new file mode 100644 index 0000000000000000000000000000000000000000..ab7519f17a4f63275fb5b5642a11f1398bf652bc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h @@ -0,0 +1,586 @@ +/* + * 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. + */ + +/** + * @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 pdev - txrx_pdev handle + * @return 0 for success or error code + */ +int +ol_txrx_pdev_post_attach(struct cdp_pdev *pdev); + +/** + * @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 informaiton changed in node. + * @details + * Only a single prarameter can be changed for each call to this func. + * + * @param peer - pointer to the node's object + * @param param - new param to be upated 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); + +/** + * @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_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) +{ +} + +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 /* CONFIG_HL_SUPPORT */ + +/** + * @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_LEGACY_TX_FLOW_CONTROL) || \ + 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_LEGACY_TX_FLOW_CONTROL) || \ + 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 data_vdev - 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_vdev *data_vdev, + 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); + +/** + * @brief set the safemode of the device + * @details + * This flag is used to bypass the encrypt and decrypt processes when send and + * receive packets. It works like open AUTH mode, HW will treate all packets + * as non-encrypt frames because no key installed. For rx fragmented frames, + * it bypasses all the rx defragmentaion. + * + * @param vdev - the data virtual device object + * @param val - the safemode state + * @return - void + */ +void ol_txrx_set_safemode(ol_txrx_vdev_handle vdev, uint32_t val); + +/** + * @brief configure the drop unencrypted frame flag + * @details + * Rx related. When set this flag, all the unencrypted frames + * received over a secure connection will be discarded + * + * @param vdev - the data virtual device object + * @param val - flag + * @return - void + */ +void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val); + +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 evaluted 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) + +/** + * @brief Configure the bad peer tx limit setting. + * @details + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_set_setting( + struct cdp_pdev *pdev, + int enable, + int period, + int txq_limit); + +/** + * @brief Configure the bad peer tx threshold limit + * @details + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_update_threshold( + struct cdp_pdev *pdev, + int level, + int tput_thresh, + int tx_limit); + +#else + +static inline void +ol_txrx_bad_peer_txctl_set_setting( + struct cdp_pdev *pdev, + int enable, + int period, + int txq_limit) +{ +} + +static inline void +ol_txrx_bad_peer_txctl_update_threshold( + struct cdp_pdev *pdev, + 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(void *); +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) +{ +} +static inline void ol_tx_dump_flow_pool_info(void *ctx) +{ +} +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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h new file mode 100644 index 0000000000000000000000000000000000000000..438b4060715e127871abd2eaeff44460cca9ab9a --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b8ab61497c55b9676837521cecae05c026ab5bbe --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h @@ -0,0 +1,690 @@ +/* + * 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. + */ + +/** + * @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)); + +} +#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); +} +#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, + + /* 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); + +#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) +{ +} +#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. + */ +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); + +/** + * @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. + * Hight letency 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); + +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? + */ +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); + +#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 + +#endif /* _OL_TXRX_HTT_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h new file mode 100644 index 0000000000000000000000000000000000000000..203f27743e9ca1603f9a30a337f901257e43ae8e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h @@ -0,0 +1,79 @@ +/* + * 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. + */ + +/** + * @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(void *data_vdev, 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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..4c2a073e02099ca9691f2206d0b9453c6c35cc25 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h @@ -0,0 +1,180 @@ +/* + * 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. + */ + +/** + * @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; + + /* 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 recevied 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/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..ab82d5e00dc272b53215e928fe4bdc43340f2f93 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/txrx/ipv6_defs.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ipv6_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..ffdd6568afa2138404ca6bc7c2e5514300fbe00d --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_cfg.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_cfg.c new file mode 100644 index 0000000000000000000000000000000000000000..940fbe7b7be628c01e8b2b5b6242a3e419ef464b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_cfg.c @@ -0,0 +1,539 @@ +/* + * 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. + */ + +#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 + +/** + * 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; + cfg_ctx->tx_free_at_download = 0; +} +#else + +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 + +#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 + +/* 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) { + printk(KERN_ERR "cfg ctx allocation failed\n"); + return NULL; + } + + ol_pdev_cfg_param_update(cfg_ctx); + + /* temporarily disabled PN check for Riva/Pronto */ + cfg_ctx->rx_pn_check = 1; + 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->ce_classify_enabled = cfg_param->ce_classify_enabled; + + ol_tx_set_flow_control_parameters((struct cdp_cfg *)cfg_ctx, cfg_param); + + for (i = 0; i < OL_TX_NUM_WMM_AC; 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; +} + +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_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 >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_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 >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_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 >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_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 >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_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 >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_AC_VO) + return cfg->ac_specs[ac].discard_weight; + + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b31f1268c77bf07b873f661db08bbcc0d3f1db89 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011-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_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 /* uint8_t */ +#include /* qdf_nbuf_t */ + +#include /* ol_txrx_pdev_handle */ +#include /* OL_TXRX_MAC_ADDR_LEN */ +#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_addba_req(pdev, peer_mac_addr, tid) ol_addba_req_reject +#define ol_ctrl_rx_addba_complete(pdev, peer_mac_addr, tid, failed) /* no-op */ + +#endif /* _OL_CTRL_TXRX_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..ca40d9ca1c74d6874de2a8786a49806a9cc4e906 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..4cccf084022c2042f2072c90ab4bf0775e9fb899 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.c @@ -0,0 +1,1879 @@ +/* + * 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. + */ + +#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 +#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 + +#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; +static 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, (struct cdp_pdev *)pdev, + &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, (struct cdp_pdev *)pdev, + &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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err("%s pdev is NULL\n", __func__); + 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 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[IEEE80211_ADDR_LEN]; + 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 == NULL || !IEEE80211_IS_DATA(wh)) + return; + + /* ignore frames for non-existent bssids */ + qdf_mem_copy(a1, wh->i_addr1, IEEE80211_ADDR_LEN); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_mem_cmp(a1, vdev->mac_addr.raw, IEEE80211_ADDR_LEN)) + break; + } + if (!vdev) + return; + + msg.wh = wh; + msg.msdu = msdu; + msg.vdev_id = vdev->vdev_id; + wdi_event_handler(WDI_EVENT_RX_PEER_INVALID, (struct cdp_pdev *)pdev, + &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); + OL_RX_REORDER_TRACE_ADD(pdev, tid, + reorder_idx, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_mpdu_desc), + 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); + } + } +} /* process_reorder */ + +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, i; + 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) { + 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); + } + } + + 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("%s: invalid tid, %u\n", + __func__, 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 != NULL && peer != NULL) { + 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_err(pdev->ctrl_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); +} + +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 (%02x:%02x:%02x:%02x:%02x:%02x): %s key of type %d\n", + peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + 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; + } + } +} + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + +#include + +static void transcap_nwifi_to_8023(qdf_nbuf_t msdu) +{ + struct ieee80211_frame *wh; + uint32_t hdrsize; + struct llc *llchdr; + struct ether_header *eth_hdr; + uint16_t ether_type = 0; + uint8_t a1[IEEE80211_ADDR_LEN]; + uint8_t a2[IEEE80211_ADDR_LEN]; + uint8_t a3[IEEE80211_ADDR_LEN]; + uint8_t fc1; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(msdu); + qdf_mem_copy(a1, wh->i_addr1, IEEE80211_ADDR_LEN); + qdf_mem_copy(a2, wh->i_addr2, IEEE80211_ADDR_LEN); + qdf_mem_copy(a3, wh->i_addr3, IEEE80211_ADDR_LEN); + fc1 = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + /* Native Wifi header is 80211 non-QoS header */ + hdrsize = sizeof(struct ieee80211_frame); + + llchdr = (struct llc *)(((uint8_t *) qdf_nbuf_data(msdu)) + hdrsize); + ether_type = llchdr->llc_un.type_snap.ether_type; + + /* + * Now move the data pointer to the beginning of the mac header : + * new-header = old-hdr + (wifhdrsize + llchdrsize - ethhdrsize) + */ + qdf_nbuf_pull_head(msdu, + (hdrsize + sizeof(struct llc) - + sizeof(struct ether_header))); + eth_hdr = (struct ether_header *)(qdf_nbuf_data(msdu)); + switch (fc1) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(eth_hdr->ether_dhost, a1, IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->ether_shost, a2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(eth_hdr->ether_dhost, a3, IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->ether_shost, a2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(eth_hdr->ether_dhost, a1, IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->ether_shost, a3, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + break; + } + eth_hdr->ether_type = ether_type; +} +#endif + +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. + */ +} + +/** + * @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 = ETHERNET_ADDR_LEN * 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); + } + } +} + +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("%s: invalid msdu_cnt=%u\n", + __func__, + 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_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_err(vdev->pdev->ctrl_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); + } +} + +/** + * @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 = ETHERNET_ADDR_LEN * 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; +} + +#ifdef WLAN_FEATURE_TSF_PLUS +#ifdef CONFIG_HL_SUPPORT +static inline 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); +} +#else +static inline 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); +} +#endif +#else +static inline void ol_rx_timestamp(struct cdp_cfg *cfg_pdev, + void *rx_desc, qdf_nbuf_t msdu) +{ +} +#endif + +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 (%02x:%02x:%02x:%02x:%02x:%02x) len %d\n", + msdu, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + 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 == NULL && 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) { + 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) { + struct ether_header 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)); + } + } + 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); + } + msdu = next; + } + /* sanity check - are there any frames left to give to the OS shim? */ + if (!deliver_list_head) + return; + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + if (pdev->host_80211_enable) + for (msdu = deliver_list_head; msdu; msdu = qdf_nbuf_next(msdu)) + transcap_nwifi_to_8023(msdu); +#endif + + 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); +} + +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; + } +} + +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; + 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; + struct htt_host_rx_desc_base *rx_desc; + qdf_nbuf_t loop_msdu; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("%s: invalid tid, %u\n", __FUNCTION__, 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("%s: Invalid pdev passed!\n", __func__); + qdf_assert_always(pdev); + return; + } + +#if defined(HELIUMPLUS_DEBUG) + qdf_print("%s %d: rx_ind_msg 0x%pK peer_id %d tid %d is_offload %d\n", + __func__, __LINE__, 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("%s: Pop status is 0, returning here", __func__); + 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); + + /* 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( + "%s: Couldn't find peer from ID 0x%x\n", + __func__, 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*/ + loop_msdu = head_msdu; + while (loop_msdu) { + qdf_nbuf_t msdu = head_msdu; + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, loop_msdu); + ol_rx_timestamp(pdev->ctrl_pdev, rx_desc, msdu); + loop_msdu = qdf_nbuf_next(loop_msdu); + } + + peer->rx_opt_proc(vdev, peer, tid, head_msdu); +} + +#ifndef REMOVE_PKT_LOG +/** + * 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) +{ + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer = NULL; + tp_ol_packetdump_cb packetdump_cb; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err("%s: pdev is NULL", __func__); + return; + } + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + ol_txrx_dbg("%s: peer with peer id %d is NULL", __func__, + peer_id); + return; + } + + packetdump_cb = pdev->ol_rx_packetdump_cb; + if (packetdump_cb) + packetdump_cb(msdu, status, peer->vdev->vdev_id, RX_DATA_PKT); +} +#endif + +/* 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); +} + +#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); + 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 = ETHERNET_ADDR_LEN * 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 diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.h new file mode 100644 index 0000000000000000000000000000000000000000..bcc6bab80382aef91030c5800d0091b31c782ffa --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.h @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#ifndef _OL_RX__H_ +#define _OL_RX__H_ + +#include /* qdf_nbuf_t */ +#include /* htt_pdev_handle */ +#include /* ol_txrx_vdev_t */ + +void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t head_msdu); + +void +ol_rx_discard(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t head_msdu); + +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 + + +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); + +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); + +#endif /* _OL_RX__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c new file mode 100644 index 0000000000000000000000000000000000000000..2e0f81d44bd9279ba152815abe91d54a2a1a6104 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c @@ -0,0 +1,1278 @@ +/* + * 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. + */ + +/*- + * 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 */ + +#define DEFRAG_IEEE80211_ADDR_EQ(a1, a2) \ + (!qdf_mem_cmp(a1, a2, IEEE80211_ADDR_LEN)) + +#define DEFRAG_IEEE80211_ADDR_COPY(dst, src) \ + qdf_mem_copy(dst, src, IEEE80211_ADDR_LEN) + +#define DEFRAG_IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | 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, +}; + +#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 desciptor 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 == NULL) || (rx_desc_old_position == NULL)) { + ol_txrx_err("ind_old_position,rx_desc_old_position is NULL\n"); + 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; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("%s: invalid tid, %u\n", __FUNCTION__, 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); + 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); + 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; + + 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; + + 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("\n ol_rx_reorder_store:%s mismatch\n", + (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 != NULL) { + + 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 != NULL) { + ol_txrx_alert("waitlist->tqe_prv = NULL\n"); + 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("%s: invalid tid, %u\n", __FUNCTION__, 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 */); + } +} + +/* + * 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; + + 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); + if (!ol_rx_pn_check_base(vdev, peer, tid, cur)) { + /* 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("ol_rx_defrag: PN Check failed\n"); + 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; + /* 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("\n ol_rx_defrag: TKIP decap failed\n"); + 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("\n ol_rx_defrag: CCMP demic failed\n"); + 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("\n ol_rx_defrag: CCMP decap failed\n"); + 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("\n ol_rx_defrag: wep decap failed\n"); + 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)) { + htt_rx_desc_frame_free(htt_pdev, msdu); + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, peer->mac_addr.raw, tid, 0, + OL_RX_DEFRAG_ERR, msdu, NULL, 0); + ol_txrx_err("\n ol_rx_defrag: TKIP demic failed\n"); + 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); + + 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 + IEEE80211_ADDR_LEN, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_TODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_FROMDS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr3); + break; + case IEEE80211_FC1_DIR_DSTODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr4); + break; + } + /* + * Bit 7 is 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] & 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 == NULL) + 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 += IEEE80211_ADDR_LEN; + + 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, + IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr3, + IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr3, IEEE80211_ADDR_LEN); + 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] &= ~IEEE80211_FC0_SUBTYPE_QOS; + + ol_rx_defrag_push_rx_desc(nbuf, rx_desc_old_position, + ind_old_position, rx_desc_len); + + } +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h new file mode 100644 index 0000000000000000000000000000000000000000..66b672d62edbd9d495decb59c02d441a4671f759 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2011-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_DEFRAG_H_ +#define _OL_RX_DEFRAG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFRAG_IEEE80211_ADDR_LEN 6 +#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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c new file mode 100644 index 0000000000000000000000000000000000000000..114da4e81066fdb28caa23c0e9afe9a11084b2d3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c @@ -0,0 +1,277 @@ +/* + * 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. + */ + +/* 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[IEEE80211_ADDR_LEN]; + 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, + IEEE80211_ADDR_LEN)) { + ol_txrx_dbg("Exit: %s | Unnecessary to adjust mac header\n", + __func__); + } 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; + /* + * 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; + } + + /* + * 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. + * @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(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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h new file mode 100644 index 0000000000000000000000000000000000000000..9fc63e7ff5bfd3b219a624d6644fd4bfc3d2326d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef _OL_RX_FWD_H_ +#define _OL_RX_FWD_H_ + +#include /* qdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +qdf_nbuf_t +ol_rx_fwd_mcast_check_sta(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, void *rx_desc, int is_wlan_mcast); + +qdf_nbuf_t +ol_rx_fwd_mcast_check_ap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, void *rx_desc, int is_wlan_mcast); + +/** + * @brief Check if rx frames should be transmitted over WLAN. + * @details + * 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. + * + * @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 the rx->tx + * forwarding check on + */ +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); + +A_STATUS +ol_get_intra_bss_fwd_pkts_count( + uint8_t vdev_id, + uint64_t *fwd_tx_packets, + uint64_t *fwd_rx_packets); + +#endif /* _OL_RX_FWD_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.c new file mode 100644 index 0000000000000000000000000000000000000000..dd09c3f50c71f3bd8b72afef165a2af8aa781a48 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2011, 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. + */ + +#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) +{ + int rc = ((new_pn->pn24 & 0xffffff) <= (old_pn->pn24 & 0xffffff)); + return rc; +} + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode) +{ + int rc = ((new_pn->pn48 & 0xffffffffffffULL) <= + (old_pn->pn48 & 0xffffffffffffULL)); + return rc; +} + +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) +{ + int pn_is_replay = 0; + + 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) +{ + 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); + } 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 " + "(%02x:%02x:%02x:%02x:%02x:%02x) %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, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + (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)); + } else { + ol_txrx_dbg( + "PN check failed - TID %d, peer %pK " + "(%02x:%02x:%02x:%02x:%02x:%02x) %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, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + (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)); + } +#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); + 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); + 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); + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.h new file mode 100644 index 0000000000000000000000000000000000000000..8e0c007b091d7e578fc13108bff70bb6dbf78c6d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#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); + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode); + +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); + +/** + * @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) + * @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); + +#endif /* _OL_RX_PN_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c new file mode 100644 index 0000000000000000000000000000000000000000..6335a9ef34f7710931032caa63d19483844b4d1c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c @@ -0,0 +1,825 @@ +/* + * 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. + */ + +/*=== 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 ===*/ + +/*---*/ + +/*=== global variables ===*/ + +/*---*/ + +/*=== 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 arive 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); + + /* 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)); + 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 == NULL) { + 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)); + 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("%s: invalid tid, %u\n", __FUNCTION__, 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_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("%s: invalid tid, %u\n", __FUNCTION__, 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("%s: invalid tid, %u\n", __FUNCTION__, 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 " + "(%02x:%02x:%02x:%02x:%02x:%02x)\n" + " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5], pn.pn128[1], + pn.pn128[0], + pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_desc)); + } else { + ol_txrx_dbg( + "Tgt PN check failed - TID %d, peer %pK " + "(%02x:%02x:%02x:%02x:%02x:%02x)\n" + " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5], pn.pn128[1], + pn.pn128[0], + pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_desc)); + } + 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 == NULL) { + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h new file mode 100644 index 0000000000000000000000000000000000000000..fa64010616751242299d9347613b01b7121bd9c0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c new file mode 100644 index 0000000000000000000000000000000000000000..487b140b25553eebbf66e5a86d105f77c0396304 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h new file mode 100644 index 0000000000000000000000000000000000000000..9f095015eb22d4b79b22f4e517fef218f1036611 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.c new file mode 100644 index 0000000000000000000000000000000000000000..0615aaab5eab4ad43a534223edf070d500e5616f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.c @@ -0,0 +1,1662 @@ +/* + * 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. + */ + +/* 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 + +/* + * 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; +} + +#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)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s:vdev is null", __func__); + return; + } else { + pdev = vdev->pdev; + if (qdf_unlikely(!pdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s:pdev is null", __func__); + return; + } + } + + if (is_tso_seg_mapping_done) { + /* + * 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. + */ + struct qdf_tso_num_seg_elem_t *tso_num_desc = + msdu_info->tso_info.tso_num_seg_list; + + if (qdf_unlikely(tso_num_desc == NULL)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d TSO common info is NULL!", + __func__, __LINE__); + 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 alocated TSO segements 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; +} +#endif + +/** + * ol_tx_data() - send data frame + * @vdev: virtual device handle + * @skb: skb + * + * Return: skb/NULL for success + */ +qdf_nbuf_t ol_tx_data(void *data_vdev, qdf_nbuf_t skb) +{ + struct ol_txrx_pdev_t *pdev; + qdf_nbuf_t ret; + ol_txrx_vdev_handle vdev = data_vdev; + + 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("%s: Failed to tx", __func__); + return ret; + } + + return NULL; +} + +#ifdef IPA_OFFLOAD +qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_vdev *vdev, qdf_nbuf_t skb) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + qdf_nbuf_t ret; + + if (qdf_unlikely(!pdev)) { + qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__); + + ol_txrx_err("%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); + + /* + * 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("%s: Failed to tx", __func__); + return ret; + } + + return NULL; +} +#endif + +#if defined(FEATURE_TSO) +/** + * 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; +} +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_MARGIN 400 +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS 5 +static void ol_tx_vdev_ll_pause_queue_send_base(struct ol_txrx_vdev_t *vdev) +{ + int max_to_accept; + + 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 (NULL == 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 == NULL) + 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 || + vdev->pdev->tx_throttle.current_throttle_phase == + THROTTLE_PHASE_ON) { + /* + * 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 (NULL == pdev) + return; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) + return; + + /* ensure that we send no more than tx_threshold frames at once */ + max_to_send = pdev->tx_throttle.tx_threshold; + + /* 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 (NULL == 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 (NULL == 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); + + vdev = NULL; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.txq.depth) { + qdf_timer_stop(&pdev->tx_throttle.tx_timer); + qdf_timer_start( + &pdev->tx_throttle.tx_timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + return; + } + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } +} + +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 && + pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) + return; + ol_tx_vdev_ll_pause_queue_send_base(vdev); +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +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; +} + +static 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 */ +} + +#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 + +/* tx filtering is handled within the target FW */ +#define TX_FILTER_CHECK(tx_msdu_info) 0 /* don't filter */ + +/** + * 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 + */ +#define OCB_HEADER_VERSION 1 +static bool parse_ocb_tx_header(qdf_nbuf_t msdu, + struct ocb_tx_ctrl_hdr_t *tx_ctrl) +{ + struct ether_header *eth_hdr_p; + struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr; + + /* Check if TX control header is present */ + eth_hdr_p = (struct ether_header *)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(struct ether_header)); + + /* 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; +} + + +#if defined(CONFIG_HL_SUPPORT) && defined(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 decriptor + */ +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("Provided tx descriptor from reserve pool for DHCP/EAPOL\n"); + } + } + 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 + +#if defined(CONFIG_HL_SUPPORT) + +/** + * 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 decriptor + */ +static inline +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 + */ +static inline +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 specifiy 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; +} + +#else + +static inline +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; +} + +static inline +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; +} +#endif + +/** + * 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 + * + * 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) +{ + 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);*/ + + 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; + 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; + + /* 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 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; + } + ol_tx_sched(pdev); + return NULL; /* all MSDUs were accepted */ +} + +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; + + return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, tx_comp_req); +} + +static 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; + + 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); +} + +qdf_nbuf_t +ol_tx_non_std(struct cdp_vdev *pvdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + if (vdev->pdev->cfg.is_high_latency) + return ol_tx_non_std_hl(vdev, tx_spec, msdu_list); + else + return ol_tx_non_std_ll(vdev, tx_spec, msdu_list); +} + +void +ol_txrx_data_tx_cb_set(struct cdp_vdev *pvdev, + ol_txrx_data_tx_cb callback, void *ctxt) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + pdev->tx_data_callback.func = callback; + pdev->tx_data_callback.ctxt = ctxt; +} + +void +ol_txrx_mgmt_tx_cb_set(struct cdp_pdev *ppdev, uint8_t type, + ol_txrx_mgmt_tx_cb download_cb, + ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + 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; +} + +#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; + + qdf_print("OL TX Descriptor 0x%pK msdu_id %d\n", + tx_desc, tx_desc->id); + qdf_print("HTT TX Descriptor vaddr: 0x%pK paddr: %pad", + tx_desc->htt_tx_desc, &tx_desc->htt_tx_desc_paddr); + qdf_print("%s %d: Fragment Descriptor 0x%pK (paddr=%pad)", + __func__, __LINE__, 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 */ + +int +ol_txrx_mgmt_send_ext(struct cdp_vdev *pvdev, + qdf_nbuf_t tx_mgmt_frm, + uint8_t type, uint8_t use_6mbps, uint16_t chanfreq) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_desc_t *tx_desc; + struct ol_txrx_msdu_info_t tx_msdu_info; + int result = 0; + + 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 */ +} + +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; +} + +#if defined(FEATURE_TSO) +/** + * 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 intialised + * + * 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("%s: ERROR: Pool size passed is 0", + __func__); + 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("%s: ERROR: c_element NULL for seg %d", + __func__, 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("%s: ERROR: c_element NULL for seg %d", + __func__, 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 == NULL && + 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 intialised + * + * 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("%s: ERROR: Pool size passed is 0", + __func__); + 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("%s: ERROR: c_element NULL for num of seg %d", + __func__, 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("%s: ERROR: c_element NULL for num of seg %d", + __func__, 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 == NULL && + 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 */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.h new file mode 100644 index 0000000000000000000000000000000000000000..d3c191f87db4f32a4198caf08a9b12082aa699d2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.h @@ -0,0 +1,238 @@ +/* + * 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. + */ + +/** + * @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 + +#ifdef IPA_OFFLOAD +/** + * ol_tx_send_ipa_data_frame() - send IPA data frame + * @vdev: vdev + * @skb: skb + * + * Return: skb/ NULL is for success + */ +qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_vdev *vdev, qdf_nbuf_t skb); +#endif + +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); + +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 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_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 + * @data_vdev: which vdev should transmit the tx data frames + * @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 + */ +qdf_nbuf_t +ol_tx_non_std(struct cdp_vdev *pvdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); + +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. + * @ppdev: the data physical device object + * @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. + */ +void +ol_txrx_mgmt_tx_cb_set(struct cdp_pdev *ppdev, 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 + * @pvdev: virtual device transmitting the frame + * @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_vdev *pvdev, + 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 + +#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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.c new file mode 100644 index 0000000000000000000000000000000000000000..c25f9c865fe6ab127c223c60194e86c19f174911 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.c @@ -0,0 +1,891 @@ +/* + * 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. + */ + +#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. + */ + +#if defined(CONFIG_HL_SUPPORT) + +#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] & 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 + ETHERNET_ADDR_LEN * 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 + ETHERNET_ADDR_LEN * 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] & 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(CONFIG_HL_SUPPORT) && 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 *peer_id) +{ + struct ol_txrx_peer_t *peer = NULL; + + if (vdev->hlTdlsFlag) { + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, + vdev->hl_tdls_ap_mac_addr.raw, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + + if (peer && (peer->peer_ids[0] == HTT_INVALID_PEER_ID)) { + ol_txrx_peer_release_ref(peer, + PEER_DEBUG_ID_OL_INTERNAL); + peer = NULL; + } else { + if (peer) + *peer_id = peer->local_id; + } + } + if (!peer) + peer = ol_txrx_assoc_peer_find(vdev); + + 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 *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 %s\n", __func__); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if (unlikely(NULL == 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 (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast DA tx data frame w/o association\n", + vdev, + 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]); + 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 (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast/mcast, but no self-peer found\n", + vdev, + 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]); + 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, &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. + */ + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: vdev %pK (%02x:%02x:%02x:%02x:%02x:%02x) trying to send unicast tx data frame to an unknown peer\n", + vdev, + 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]); + return NULL; /* error */ + } + TX_SCHED_DEBUG_PRINT("Peer found\n"); + 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( + "%s: remove the peer for invalid peer_id %pK\n", + __func__, 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( + "%s: remove the peer reference %pK\n", + __func__, 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 %s\n", __func__); + 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 %s\n", __func__); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if (unlikely(NULL == 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, OL_TXRX_MAC_ADDR_LEN); + 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 %s\n", __func__); + 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 +#endif /* defined(CONFIG_HL_SUPPORT) */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.h new file mode 100644 index 0000000000000000000000000000000000000000..b88f329476cd6425df37fbd32899b64f0f82378b --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.c new file mode 100644 index 0000000000000000000000000000000000000000..462e7b5b3c4b80c6a18454defdd04a0e0bda27b6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.c @@ -0,0 +1,1156 @@ +/* + * 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. + */ + +#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( + "%s Potential tx_desc corruption pkt_type:0x%x pdev:0x%pK", + __func__, 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("%s Timestamp:0x%x\n", + __func__, 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 CONFIG_PER_VDEV_TX_DESC_POOL + +/** + * 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!!\n"); + 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; +} + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) && defined(CONFIG_HL_SUPPORT) + +/** + * 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 == NULL)) { + 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 == NULL)) { + 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("%s %d pool is INVALID State!!\n", + __func__, __LINE__); + return; + } + break; + case FLOW_POOL_ACTIVE_UNPAUSED: + break; + default: + qdf_print("%s %d pool is INACTIVE State!!\n", + __func__, __LINE__); + 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_print("%s:%d: htt_fdesc=%pK frag=%d frag_vaddr=0x%pK frag_paddr=0x%llx len=%zu\n", + __func__, __LINE__, 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) && + !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("%s %d: Frag Descriptor Reset [%d] to 0x%x\n", + __func__, __LINE__, 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 */ + + /* This is to decrement skb->users count for TSO segment */ + if (tx_desc->pkt_type == OL_TX_FRM_TSO) + qdf_nbuf_tx_free(tx_desc->netbuf, had_error); + 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 != NULL) { + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.h new file mode 100644 index 0000000000000000000000000000000000000000..dc1bebfab889d08a7303b8c7bbd319944158ce29 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.h @@ -0,0 +1,481 @@ +/* + * 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. + */ + +/** + * @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 /* 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); + if (!pdev->tx_desc.free_list_bitmap) + qdf_print("%s: malloc failed", __func__); +} + +/** + * 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("%s: msdu_id %d > pool_size %d", + __func__, 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 !!\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); + } +} + +/** + * 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("%s: msdu_id %d > pool_size %d", + __func__, 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_ll_fastpath.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_ll_fastpath.c new file mode 100644 index 0000000000000000000000000000000000000000..db4611433bc1213ca64a47a0415298970c53d070 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_ll_fastpath.c @@ -0,0 +1,601 @@ +/* + * 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. + */ + +/* 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) +#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\n"); + QDF_BUG(0); + } + return msdu_list; +} + +/** + * 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 + * + * Return: None + */ +static inline void ol_tx_trace_pkt(qdf_nbuf_t skb, uint16_t msdu_id, + uint8_t vdev_id) +{ + 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)); + + qdf_dp_trace_log_pkt(vdev_id, skb, QDF_TX, QDF_TRACE_DEFAULT_PDEV_ID); + + qdf_dp_trace_set_track(skb, QDF_TX); + DPTRACE(qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_TX_PACKET_RECORD, + msdu_id, QDF_TX)); +} + +/** + * 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 + * inforamtion. + * + * @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_print("%s:%d: htt_fdesc=%pK frag=%d frag_paddr=0x%0llx len=%zu", + __func__, __LINE__, 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\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 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; + + /* + * 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); + + ol_tx_trace_pkt(msdu, tx_desc->id, + vdev->vdev_id); + /* + * 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; + } 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); + } + + /* + * 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)); + /* + * 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_ll_legacy.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_ll_legacy.c new file mode 100644 index 0000000000000000000000000000000000000000..5f905a04f19e1d46f0cbb664eade6bc171af4d0b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_ll_legacy.c @@ -0,0 +1,195 @@ +/* + * 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. + */ + +/* 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; + + /* + * 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; + + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..487582d8543f9d35a3dc18df9ba741a7095e77a3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.c @@ -0,0 +1,2358 @@ +/* + * 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. + */ + +#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; + + /* 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( + "%s: Delete Peer %pK\n", __func__, 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 + num = pdev->tx_queue.rsrc_threshold_hi - + pdev->tx_queue.rsrc_threshold_lo; + + TX_SCHED_DEBUG_PRINT("+%s : %u\n,", __func__, + 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("-%s\n", __func__); + + 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 CONFIG_PER_VDEV_TX_DESC_POOL + +/** + * 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 desciptor ptr + * + * Return: Success if available tx descriptors are too few + */ +static 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; + + vdev = tx_desc->vdev; + return qdf_atomic_read(&vdev->tx_desc_count) > + ((ol_tx_desc_pool_size_hl(pdev->ctrl_pdev) >> 1) + - TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED); +} +#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 + +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 %s\n", __func__); + + /* + * 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_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 %s\n", __func__); +} + +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 %s\n", __func__); + + 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; + /* 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 %s\n", __func__); + + *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 %s\n", __func__); + 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); + + 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 %s\n", __func__); +} + + +/*--- 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); + } + } +} +#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 %s\n", __func__); + 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 %s\n", __func__); +} + +void +ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev) +{ +#if defined(QCA_SUPPORT_TX_THROTTLE) + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (pdev->tx_throttle.is_paused == true) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = true; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); +#endif + ol_txrx_pdev_pause(pdev, 0); +} + +void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev) +{ +#if defined(QCA_SUPPORT_TX_THROTTLE) + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (pdev->tx_throttle.is_paused == false) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = false; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); +#endif + ol_txrx_pdev_unpause(pdev, 0); +} + +void +ol_txrx_vdev_pause(struct cdp_vdev *pvdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev = vdev->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 %s\n", __func__); + + + /* 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) { + 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 %s\n", __func__); +} + + +void ol_txrx_vdev_unpause(struct cdp_vdev *pvdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev = vdev->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 %s\n", __func__); + + + + /* 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) { + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void ol_txrx_vdev_flush(struct cdp_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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 maxinum peer num %d\n", + 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\n", + 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\n", + 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 %s\n", __func__); + 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 %s\n", __func__); +} + +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 %s\n", __func__); + 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 %s\n", __func__); +} + +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\n", + 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(NULL == pdev)) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL pdev handler\n"); + return; + } + + if (unlikely(NULL == txq)) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL txq\n"); + 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\n", + txq->peer->peer_ids[0], frames); + } else if (txq->peer) { + TX_SCHED_DEBUG_PRINT("Download peer_id %d, num_frames %d\n", + 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_pdev *ppdev, + int enable, int period, int txq_limit) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + 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_pdev *ppdev, + int level, int tput_thresh, + int tx_limit) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + /* 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( + "%s peer_id %d peer = 0x%x tx limit %d\n", + __func__, 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\n", + 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 (NULL == pdev) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL pdev handler\n"); + return; + } + + if (NULL == peer_link_status) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Error:NULL link report message. peer num %d\n", + 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\n"); + return; + } + + /* Check peer_num is reasonable */ + if (peer_num > MAX_NO_PEERS_IN_LIMIT) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "%s: Bad peer_num %d\n", __func__, peer_num); + return; + } + + TX_SCHED_DEBUG_PRINT_ALWAYS("%s: peer_num %d\n", __func__, 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("%s: peer id %d tput %d phy %d\n", + __func__, peer_id, peer_tput, peer_phy); + + /* Sanity check for the PHY mode value */ + if (peer_phy > TXRX_IEEE11_AC) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "%s: PHY value is illegal: %d, and the peer_id %d\n", + __func__, 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( + "%s: Check if peer_id %d exit limit\n", + __func__, 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( + "%s: Remove peer_id %d from limit list\n", + __func__, 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 != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Q: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + 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 != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "DQ: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + 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 != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "F: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + 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. + */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Current target credit: %d", + qdf_atomic_read(&pdev->target_tx_credit)); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Tx queue log:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + ": 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(QCA_LL_LEGACY_TX_FLOW_CONTROL) + +/** + * ol_txrx_vdev_pause- Suspend all tx data for the specified virtual device + * + * @data_vdev - the virtual device being paused + * @reason - the reason for which vdev queue is getting paused + * + * 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_vdev *pvdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + /* TO DO: log the queue pause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + 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 %s\n", __func__); +} + +/** + * ol_txrx_vdev_unpause - Resume tx for the specified virtual device + * + * @data_vdev - the virtual device being unpaused + * @reason - the reason for which vdev queue is getting unpaused + * + * 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_vdev *pvdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + /* TO DO: log the queue unpause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + 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((unsigned long) vdev); + } else { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + } else { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +/** + * ol_txrx_vdev_flush - Drop all tx data for the specified virtual device + * + * @data_vdev - the virtual device being flushed + * + * 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_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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) && + !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); +} +#endif /* defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) */ + +#if (!defined(QCA_LL_LEGACY_TX_FLOW_CONTROL)) && (!defined(CONFIG_HL_SUPPORT)) +void ol_txrx_vdev_flush(struct cdp_vdev *data_vdev) +{ +} +#endif + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +#ifndef CONFIG_ICNSS + +/** + * ol_txrx_map_to_netif_reason_type() - map to netif_reason_type + * @reason: 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( + "%s: reason not supported %d\n", + __func__, reason); + return WLAN_REASON_TYPE_MAX; + } +} + +/** + * ol_txrx_vdev_pause() - pause vdev network queues + * @vdev: vdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_vdev_pause(struct cdp_vdev *pvdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + enum netif_reason_type netif_reason; + + if (qdf_unlikely((!pdev) || (!pdev->pause_cb))) { + ol_txrx_err("%s: invalid pdev\n", __func__); + 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 + * @vdev: vdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_vdev_unpause(struct cdp_vdev *pvdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + enum netif_reason_type netif_reason; + + if (qdf_unlikely((!pdev) || (!pdev->pause_cb))) { + ol_txrx_err( + "%s: invalid pdev\n", __func__); + 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); + +} +#endif /* ifndef CONFIG_ICNSS */ +#endif /* ifdef QCA_LL_TX_FLOW_CONTROL_V2 */ + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || 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), + (struct cdp_vdev *)vdev, reason); + } + +} + +/** + * 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), + (struct cdp_vdev *)vdev, reason); + } + +} +#endif + +/*--- LL tx throttle queue code --------------------------------------------*/ +#if defined(QCA_SUPPORT_TX_THROTTLE) +#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\n"); + ol_txrx_throttle_pause(pdev); + ol_txrx_thermal_pause(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\n", ms); + qdf_timer_start(&pdev->tx_throttle. + phase_timer, ms); + } + } else { + /* Traffic can go */ + ol_txrx_dbg( + "throttle phase --> ON\n"); + 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\n", + 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) +{ + /* Reset the phase */ + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + + /* Start with the new time */ + *ms = pdev->tx_throttle. + throttle_time_ms[level][THROTTLE_PHASE_OFF]; + + qdf_timer_stop(&pdev->tx_throttle.phase_timer); +} +#endif + +void ol_tx_throttle_set_level(struct cdp_pdev *ppdev, int level) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int ms = 0; + + if (level >= THROTTLE_LEVEL_MAX) { + ol_txrx_dbg( + "%s invalid throttle level set %d, ignoring\n", + __func__, level); + return; + } + + ol_txrx_info("Setting throttle level %d\n", level); + + /* Set the current throttle level */ + pdev->tx_throttle.current_throttle_level = (enum throttle_level) level; + + ol_tx_set_throttle_phase_time(pdev, level, &ms); + + if (level != THROTTLE_LEVEL_0) + qdf_timer_start(&pdev->tx_throttle.phase_timer, ms); +} + +void ol_tx_throttle_init_period(struct cdp_pdev *ppdev, int period, + uint8_t *dutycycle_level) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int i; + + /* Set the current throttle level */ + pdev->tx_throttle.throttle_period_ms = period; + + ol_txrx_dbg("level OFF ON\n"); + 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\n", 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((struct cdp_pdev *)pdev, + 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; +} +#endif /* QCA_SUPPORT_TX_THROTTLE */ + +#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; +} + +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; +} + +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) +{ +#ifdef HIF_SDIO + return OL_TX_MAX_TXQ_GROUPS; +#else + return 0; +#endif +} +#endif /* FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL */ + +/*--- End of LL tx throttle queue code ---------------------------------------*/ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..4ccc6e70c6794c24e3c91191f5623db032f75f96 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.h @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2012-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_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) */ + +void ol_txrx_vdev_flush(struct cdp_vdev *pvdev); + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + (defined(QCA_LL_TX_FLOW_CONTROL_V2) && !defined(CONFIG_ICNSS)) || \ + defined(CONFIG_HL_SUPPORT) +void ol_txrx_vdev_pause(struct cdp_vdev *pvdev, uint32_t reason); +void ol_txrx_vdev_unpause(struct cdp_vdev *pvdev, uint32_t reason); +#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_pdev *ppdev, int level); +void ol_tx_throttle_init_period(struct cdp_pdev *ppdev, 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) {} +#endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +static inline bool +ol_tx_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq) +{ + return txq == pdev->tx_sched.last_used_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_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev, + 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 + +#endif /* _OL_TX_QUEUE__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.c new file mode 100644 index 0000000000000000000000000000000000000000..2a2c43aebe639ddfb962b7928dc717c2952c1a51 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.c @@ -0,0 +1,1599 @@ +/* + * 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. + */ + +#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; + +#define OL_A_MAX(_x, _y) ((_x) > (_y) ? (_x) : (_y)) + +#define OL_A_MIN(_x, _y) ((_x) < (_y) ? (_x) : (_y)) + + /*--- 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 %s\n", __func__); + + 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 = OL_A_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 %s\n", __func__); + 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 == NULL) + 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_pdev *data_pdev, + 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; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Scheduler Stats:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "====category(CRR,CRT,WSW): Queued Discard Dequeued frms wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%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; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Scheduler State Snapshot:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "====category(CRR,CRT,WSW): IS_Active Pend_Frames Pend_bytes wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%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; + pdev->tx_sched.last_used_txq = NULL; +} + +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; + 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; + + /* + * 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 cateogry (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); + + if (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; + /* + * this tx queue will download some frames, + * so update last_used_txq + */ + pdev->tx_sched.last_used_txq = txq; + + 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); + used_credits = 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); + } else { + if (ol_tx_is_txq_last_serviced_queue(pdev, txq)) { + /* + * The scheduler has looked at all the active + * tx queues but none were able to download any + * of their tx frames. + * Nothing is changed, so if none were able + * to download before, + * they wont be able to download now. + * Return that no credit has been used, which + * will cause the scheduler to stop. + */ + TAILQ_INSERT_HEAD(&category->state.head, txq, + list_elem); + return 0; + } + TAILQ_INSERT_TAIL(&category->state.head, txq, + list_elem); + if (!pdev->tx_sched.last_used_txq) + pdev->tx_sched.last_used_txq = txq; + } + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + } else { + used_credits = 0; + /* TODO: find its reason */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ol_tx_sched_select_batch_wrr_adv: error, no TXQ can be popped."); + } + 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 (NULL == 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 == NULL) + 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_pdev *pdev, + struct ol_tx_wmm_param_t wmm_param) +{ + struct ol_txrx_pdev_t *data_pdev = (struct ol_txrx_pdev_t *)pdev; + 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[OL_TX_NUM_WMM_AC], default_edca[OL_TX_NUM_WMM_AC]; + + 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[OL_TX_WMM_AC_VO].aifs + + wmm_param.ac[OL_TX_WMM_AC_VO].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_VI] = + wmm_param.ac[OL_TX_WMM_AC_VI].aifs + + wmm_param.ac[OL_TX_WMM_AC_VI].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BK] = + wmm_param.ac[OL_TX_WMM_AC_BK].aifs + + wmm_param.ac[OL_TX_WMM_AC_BK].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BE] = + wmm_param.ac[OL_TX_WMM_AC_BE].aifs + + wmm_param.ac[OL_TX_WMM_AC_BE].cwmin; + + for (i = 0; i < OL_TX_NUM_WMM_AC; 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 (NULL == 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("%s Tx Drop : %d\n", __func__, 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) (NULL == 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 %s\n", __func__); + while (sctx->frms) { + tx_desc = TAILQ_FIRST(&sctx->head); + if (tx_desc == NULL) { + /* 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 (NULL == 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 %s\n", __func__); +} + + 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 %s\n", __func__); + 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); + */ + 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); + 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 + 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 %s\n", __func__); +} + +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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.h new file mode 100644 index 0000000000000000000000000000000000000000..75b554e0846fb16b2b19b59968d73492cfadd928 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2012-2013, 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_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_pdev *data_pdev, + 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); +} +#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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.c new file mode 100644 index 0000000000000000000000000000000000000000..46558e14661fda3f7c77519d87d0d4fb65eac7c7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.c @@ -0,0 +1,1689 @@ +/* + * 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. + */ + +#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 /* 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 + +#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(QCA_LL_LEGACY_TX_FLOW_CONTROL) +void ol_txrx_flow_control_cb(struct cdp_vdev *pvdev, bool tx_resume) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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); + + return; +} + +/** + * 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 + */ +static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + + 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((struct cdp_vdev *)vdev, + true); + } else { + qdf_spin_unlock(&pdev->tx_mutex); + } + } + } +} +#elif defined(CONFIG_HL_SUPPORT) && defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_atomic_read(&vdev->os_q_paused) && + (vdev->tx_fl_hwm != 0)) { + qdf_spin_lock(&pdev->tx_mutex); + if (((ol_tx_desc_pool_size_hl( + vdev->pdev->ctrl_pdev) >> 1) + - TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED) + - qdf_atomic_read(&vdev->tx_desc_count) + > vdev->tx_fl_hwm) { + qdf_atomic_set(&vdev->os_q_paused, 0); + qdf_spin_unlock(&pdev->tx_mutex); + vdev->osif_flow_control_cb(vdev, true); + } else { + qdf_spin_unlock(&pdev->tx_mutex); + } + } + } +} +#else + +static inline void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +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)); + 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 void +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; + + 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 */); + } 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); + } + } +} + +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; + + tx_desc = ol_tx_desc_find(pdev, msdu_id); + qdf_assert(tx_desc); + + ol_tx_download_done_base(pdev, status, msdu, msdu_id); + + 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 */ + +#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 orginal 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 orginal 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_TSF_PLUS +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, + qdf_nbuf_t netbuf, u_int64_t ts) +{ + if (!netbuf) + return; + + if (pdev->ol_tx_timestamp_cb) + pdev->ol_tx_timestamp_cb(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, + qdf_nbuf_t netbuf, u_int64_t ts) +{ +} +#endif + +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 + * + * Return: none + */ +static void ol_tx_notify_completion(struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf) +{ + void *osif_dev; + ol_txrx_completion_fp tx_compl_cbk = NULL; + + 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 (tx_compl_cbk) + tx_compl_cbk(netbuf, osif_dev); +} + +/** + * 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 = cds_get_connectivity_stats_pkt_bitmap(osif_dev); + + 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); + } +} + +/** + * ol_tx_update_arp_stats() - update ARP packet TX stats + * @tx_desc: tx desc + * @netbuf: buffer + * @status: htt status + * + * + * Return: none + */ +static void ol_tx_update_arp_stats(struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + enum htt_tx_status status) +{ + uint32_t tgt_ip; + + qdf_assert(tx_desc); + + ol_tx_flow_pool_lock(tx_desc); + if (!tx_desc->vdev) { + ol_tx_flow_pool_unlock(tx_desc); + return; + } + + tgt_ip = cds_get_arp_stats_gw_ip(tx_desc->vdev->osif_dev); + ol_tx_flow_pool_unlock(tx_desc); + + if (tgt_ip == qdf_nbuf_get_arp_tgt_ip(netbuf)) { + if (status != htt_tx_status_download_fail) + cds_incr_arp_stats_tx_tgt_delivered(); + if (status == htt_tx_status_ok) + cds_incr_arp_stats_tx_tgt_acked(); + } +} + +/** + * 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; + tp_ol_packetdump_cb packetdump_cb; + 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; + 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; + + TAILQ_INIT(&tx_descs); + + ol_tx_delay_compute(pdev, status, desc_ids, num_msdus); + if (status == htt_tx_status_ok) { + 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); + } + + 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, netbuf, tx_tsf64); + } else if (txtstamp_list) + ol_tx_timestamp(pdev, netbuf, + (u_int64_t)txtstamp_list->timestamp[i] + ); + + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); + + if (QDF_NBUF_CB_GET_PACKET_TYPE(netbuf) == + QDF_NBUF_CB_PACKET_TYPE_ARP) { + if (qdf_nbuf_data_is_arp_req(netbuf)) + ol_tx_update_arp_stats(tx_desc, netbuf, + status); + } + + /* check tx completion notification */ + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(netbuf)) + ol_tx_notify_completion(tx_desc, netbuf); + + /* track connectivity stats */ + ol_tx_update_connectivity_stats(tx_desc, netbuf, + status); + ol_tx_update_ack_count(tx_desc, status); + + if (tx_desc->pkt_type != OL_TX_FRM_TSO) { + packetdump_cb = pdev->ol_tx_packetdump_cb; + if (packetdump_cb) + packetdump_cb(netbuf, status, + tx_desc->vdev_id, TX_DATA_PKT); + } + + 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)); + htc_pm_runtime_put(pdev->htt_pdev->htc_pdev); + 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("%s: Invalid desc id", __func__); + 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); +} + +#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, old_credit, mem_vdevs; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Group credit stats:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " 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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "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) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%4d: %5d: %6d %6d %8x", + curr_index, j, + curr_credit, + (curr_credit - old_credit), + mem_vdevs); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%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; + tp_ol_packetdump_cb packetdump_cb; + + tx_desc = ol_tx_desc_find_check(pdev, tx_desc_id); + if (tx_desc == NULL) { + ol_txrx_err( + "%s: invalid desc_id(%u), ignore it.\n", + __func__, + 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)); + + packetdump_cb = pdev->ol_tx_packetdump_cb; + if (packetdump_cb) + packetdump_cb(netbuf, status, + tx_desc->vdev->vdev_id, 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 +/** + * @brief updates the compute interval period for TSM stats. + * @details + * @param interval - interval for stats computation + */ +void ol_tx_set_compute_interval(struct cdp_pdev *ppdev, uint32_t interval) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + pdev->tx_delay.avg_period_ticks = qdf_system_msecs_to_ticks(interval); +} + +/** + * @brief Return the uplink (transmitted) packet count and loss count. + * @details + * 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() + * + * @param category - access category of interest + * @param out_packet_count - number of packets transmitted + * @param out_packet_loss_count - number of packets lost + */ +void +ol_tx_packet_count(struct cdp_pdev *ppdev, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + *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_pdev *ppdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int index; + uint32_t avg_delay_ticks; + struct ol_tx_delay_data *data; + + qdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + 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_pdev *ppdev, + uint16_t *report_bin_values, int category) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int index, i, j; + struct ol_tx_delay_data *data; + + qdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + 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 (NULL == 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; + } +} +#endif + +static int ol_tx_delay_category(struct ol_txrx_pdev_t *pdev, uint16_t msdu_id) +{ +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID + 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 + 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 */ + +/** + * ol_register_packetdump_callback() - registers + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler. + * + * @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 + * + */ +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err( + "%s: pdev is NULL", __func__); + 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 + * + * This function is used to deregidter tx data pkt., + * tx mgmt. pkt and rx data pkt. dump callback + * + * Return: None + * + */ +void ol_deregister_packetdump_callback(void) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err( + "%s: pdev is NULL", __func__); + return; + } + + pdev->ol_tx_packetdump_cb = NULL; + pdev->ol_rx_packetdump_cb = NULL; +} + +#ifdef WLAN_FEATURE_TSF_PLUS +void ol_register_timestamp_callback(tp_ol_timestamp_cb ol_tx_timestamp_cb) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err("%s: pdev is NULL", __func__); + return; + } + pdev->ol_tx_timestamp_cb = ol_tx_timestamp_cb; +} + +void ol_deregister_timestamp_callback(void) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err("%s: pdev is NULL", __func__); + return; + } + pdev->ol_tx_timestamp_cb = NULL; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.h new file mode 100644 index 0000000000000000000000000000000000000000..673c2fc5348619aa0dd825fc5595d23d502bf8e4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.h @@ -0,0 +1,152 @@ +/* + * 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. + */ + +/** + * @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 + * @ppdev: physical device instance + * @interval: interval for stats computation + * + * Return: NONE + */ +void ol_tx_set_compute_interval(struct cdp_pdev *ppdev, uint32_t interval); + +/** + * ol_tx_packet_count() - Return the uplink (transmitted) packet counts + * @ppdev: physical device instance + * @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_pdev *ppdev, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category); + +/** + * ol_tx_delay() - get tx packet delay + * @ppdev: physical device instance + * @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_pdev *ppdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category); + +/** + * ol_tx_delay_hist() - get tx packet delay histogram + * @ppdev: physical device instance + * @report_bin_values: bin + * @category: packet category + * + * Return: NONE + */ +void +ol_tx_delay_hist(struct cdp_pdev *ppdev, + uint16_t *report_bin_values, int category); +#endif /* QCA_COMPUTE_TX_DELAY */ + +/** + * ol_txrx_flow_control_cb() - call osif flow control callback + * @vdev: vdev handle + * @tx_resume: tx resume flag + * + * Return: none + */ +void ol_txrx_flow_control_cb(struct cdp_vdev *vdev, bool tx_resume); + +#endif /* _OL_TX_SEND__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c new file mode 100644 index 0000000000000000000000000000000000000000..c82766c007b350a5be968ca9eadb6f40c7602693 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c @@ -0,0 +1,6799 @@ +/* + * 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. + */ + +/*=== 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 /* 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 "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 "wlan_qct_sys.h" + +#include +#include +#include "wlan_roam_debug.h" + +#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, +}; + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +ol_txrx_peer_handle +ol_txrx_peer_find_by_local_id(struct cdp_pdev *pdev, + uint8_t 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 */ +QDF_STATUS ol_txrx_peer_state_update(struct cdp_pdev *pdev, + uint8_t *peer_mac, + enum ol_txrx_peer_state state); +static void ol_vdev_rx_set_intrabss_fwd(struct cdp_vdev *vdev, + bool val); +int ol_txrx_get_tx_pending(struct cdp_pdev *pdev_handle); +extern void +ol_txrx_set_wmm_param(struct cdp_pdev *data_pdev, + struct ol_tx_wmm_param_t wmm_param); + +extern void ol_txrx_get_pn_info(void *ppeer, uint8_t **last_pn_valid, + uint64_t **last_pn, uint32_t **rmf_pn_replays); + +/* thresh for peer's cached buf queue beyond which the elements are dropped */ +#define OL_TXRX_CACHED_BUFQ_THRESH 128 + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * ol_txrx_copy_mac_addr_raw() - copy raw mac addr + * @vdev: the data virtual device + * @bss_addr: bss address + * + * Return: None + */ +static void +ol_txrx_copy_mac_addr_raw(struct cdp_vdev *pvdev, uint8_t *bss_addr) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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, + IEEE80211_ADDR_LEN)) + qdf_mem_copy(vdev->hl_tdls_ap_mac_addr.raw, + vdev->last_real_peer->mac_addr.raw, + OL_TXRX_MAC_ADDR_LEN); + qdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); +} + +/** + * ol_txrx_add_last_real_peer() - add last peer + * @pdev: the data physical device + * @vdev: virtual device + * @peer_id: peer id + * + * Return: None + */ +static void +ol_txrx_add_last_real_peer(struct cdp_pdev *ppdev, + struct cdp_vdev *pvdev, uint8_t *peer_id) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + ol_txrx_peer_handle peer; + + peer = ol_txrx_find_peer_by_addr( + (struct cdp_pdev *)pdev, + vdev->hl_tdls_ap_mac_addr.raw, + peer_id); + + 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_spin_unlock_bh(&pdev->last_real_peer_mutex); +} + +/** + * is_vdev_restore_last_peer() - check for vdev last peer + * @peer: peer object + * + * Return: true if last peer is not null + */ +static bool +is_vdev_restore_last_peer(void *ppeer) +{ + struct ol_txrx_peer_t *peer = ppeer; + struct ol_txrx_vdev_t *vdev; + + vdev = peer->vdev; + return vdev->last_real_peer && (vdev->last_real_peer == peer); +} + +/** + * ol_txrx_update_last_real_peer() - check for vdev last peer + * @pdev: the data physical device + * @peer: peer device + * @peer_id: peer id + * @restore_last_peer: restore last peer flag + * + * Return: None + */ +static void +ol_txrx_update_last_real_peer(struct cdp_pdev *ppdev, void *ppeer, + uint8_t *peer_id, bool restore_last_peer) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + struct ol_txrx_peer_t *peer = ppeer; + struct ol_txrx_vdev_t *vdev; + + if (!restore_last_peer) + return; + + vdev = peer->vdev; + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, + vdev->hl_tdls_ap_mac_addr.raw, peer_id); + + 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_spin_unlock_bh(&pdev->last_real_peer_mutex); +} +#endif + +/** + * ol_tx_mark_first_wakeup_packet() - set flag to indicate that + * fw is compatible for marking first packet after wow wakeup + * @value: 1 for enabled/ 0 for disabled + * + * Return: None + */ +static void ol_tx_mark_first_wakeup_packet(uint8_t value) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err( + "%s: pdev is NULL\n", __func__); + return; + } + + htt_mark_first_wakeup_packet(pdev->htt_pdev, value); +} + +u_int16_t +ol_tx_desc_pool_size_hl(struct cdp_cfg *ctrl_pdev) +{ + u_int16_t desc_pool_size; + u_int16_t steady_state_tx_lifetime_ms; + u_int16_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; +} + +/*=== function definitions ===*/ + +/** + * 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + 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, uint8_t *peer_id) +{ + 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; + *peer_id = peer->local_id; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + return peer; +} + +static QDF_STATUS ol_txrx_get_vdevid(void *ppeer, uint8_t *vdev_id) +{ + struct ol_txrx_peer_t *peer = ppeer; + + 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; + return QDF_STATUS_SUCCESS; +} + +static struct cdp_vdev *ol_txrx_get_vdev_by_sta_id(struct cdp_pdev *ppdev, + uint8_t sta_id) +{ + struct ol_txrx_pdev_t *pdev = (struct 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 sta_id [%d]", sta_id); + return NULL; + } + + peer = ol_txrx_peer_get_ref_by_local_id((struct cdp_pdev *)pdev, sta_id, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "PEER [%d] not found", sta_id); + return NULL; + } + + vdev = peer->vdev; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + + return (struct cdp_vdev *)vdev; +} + +/** + * 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 + * @peer_id: pointer to fill in the value of peer->local_id for caller + * + * 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, + uint8_t *peer_id) +{ + 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; + *peer_id = peer->local_id; + 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 + * @peer_id: pointer to fill in the value of peer->local_id for caller + * + * 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, + u8 *peer_id, + 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; + *peer_id = peer->local_id; + return peer; +} + +static uint16_t ol_txrx_local_peer_id(void *ppeer) +{ + ol_txrx_peer_handle peer = ppeer; + + return peer->local_id; +} + +/** + * @brief Find a txrx peer handle from a peer's local ID + * @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. + * + * @param pdev - the data physical device object + * @param local_peer_id - the ID txrx assigned locally to the peer in question + * @return handle to the txrx peer object + */ +ol_txrx_peer_handle +ol_txrx_peer_find_by_local_id(struct cdp_pdev *ppdev, + uint8_t local_peer_id) +{ + struct ol_txrx_peer_t *peer; + 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->local_peer_ids.lock); + peer = pdev->local_peer_ids.map[local_peer_id]; + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); + 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 + +#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("%s: invalid group_id=%u, ignore update.\n", + __func__, + 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; + + + /* + * membership (vdev id mask and ac mask) is not matching + * TODO: ignoring ac mask for now + */ + 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_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, NULL); + } else { + /* Set Group Pointer (vdev and peer) */ + ol_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, group); + } + } + } + /* Update membership */ + group->membership = membership; +credit_update: + /* Update Credit */ + ol_txrx_update_group_credit(group, credit, absolute); + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); +} +#endif + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_set_desc_global_pool_size() - set global pool size + * @num_msdu_desc: total number of descriptors + * + * Return: none + */ +static void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + 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\n", + pdev->num_msdu_desc); +} + +/** + * ol_tx_get_desc_global_pool_size() - get global pool size + * @pdev: pdev handle + * + * Return: global pool size + */ +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return pdev->num_msdu_desc; +} + +/** + * 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) +{ + 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; +} + +#else +/** + * ol_tx_get_desc_global_pool_size() - get global pool size + * @pdev: pdev handle + * + * Return: global pool size + */ +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); +} + +/** + * 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; +} + +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * ol_txrx_rsrc_threshold_lo() - set threshold low - when to start tx desc + * margin replenishment + * @desc_pool_size: tx desc pool size + * + * Return: threshold low + */ +static inline uint16_t +ol_txrx_rsrc_threshold_lo(int desc_pool_size) +{ + int threshold_low; + + /* + * 5% margin of unallocated desc is too much for per + * vdev mechanism. + * Define the value separately. + */ + threshold_low = TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED; + + return threshold_low; +} + +/** + * ol_txrx_rsrc_threshold_hi() - set threshold high - where to stop + * during tx desc margin replenishment + * @desc_pool_size: tx desc pool size + * + * Return: threshold high + */ +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 7.5% margin + */ + threshold_high = ((15 * desc_pool_size)/100)/2; + + return threshold_high; +} +#else + +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 = (5 * 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 = (15 * desc_pool_size)/100; + + return threshold_high; +} +#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 + */ +static 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 + */ +static inline void +ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->txq_log_spinlock); +} + +#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) +{ +} + + +#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 + */ +static inline 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 + */ +static inline void +ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->grp_stat_spinlock); +} +#else + +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_hl_tdls_flag_reset() - reset tdls flag for vdev + * @vdev: the virtual device object + * @flag: flag + * + * Return: None + */ +void +ol_txrx_hl_tdls_flag_reset(struct cdp_vdev *pvdev, bool flag) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + vdev->hlTdlsFlag = flag; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_txrx_vdev_txqs_init() - initialise vdev tx queues + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev) +{ + u_int8_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 + */ +static 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 + */ +static 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 + */ +static 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); + } +} +#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(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) +static void ol_txrx_tso_stats_init(ol_txrx_pdev_handle pdev) +{ + qdf_spinlock_create(&pdev->stats.pub.tx.tso.tso_stats_lock); +} + +static void ol_txrx_tso_stats_deinit(ol_txrx_pdev_handle pdev) +{ + qdf_spinlock_destroy(&pdev->stats.pub.tx.tso.tso_stats_lock); +} + +static void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) +{ + int msdu_idx; + int seg_idx; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "TSO Statistics:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "TSO pkts %lld, bytes %lld\n", + pdev->stats.pub.tx.tso.tso_pkts.pkts, + pdev->stats.pub.tx.tso.tso_pkts.bytes); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "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); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "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; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "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++) { +#ifdef WLAN_DEBUG + struct qdf_tso_seg_t tso_seg = + TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx); +#endif + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "seg idx: %d", seg_idx); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "tso_enable: %d", + tso_seg.tso_flags.tso_enable); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "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); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "tcp_seq_num: 0x%x ip_id: %d", + tso_seg.tso_flags.tcp_seq_num, + tso_seg.tso_flags.ip_id); + } + } +} + +static 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 +} + +#else + +static void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO is not supported\n"); +} + +static void ol_txrx_tso_stats_init(ol_txrx_pdev_handle pdev) +{ + /* + * keeping the body empty and not keeping an error print as print will + * will show up everytime during driver load if TSO is not enabled. + */ +} + +static void ol_txrx_tso_stats_deinit(ol_txrx_pdev_handle pdev) +{ + /* + * keeping the body empty and not keeping an error print as print will + * will show up everytime during driver unload if TSO is not enabled. + */ +} + +static void ol_txrx_tso_stats_clear(ol_txrx_pdev_handle pdev) +{ + /* + * keeping the body empty and not keeping an error print as print will + * will show up everytime during driver unload if TSO is not enabled. + */ +} +#endif /* defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) */ + +#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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf_mem_malloc failure", + __func__); + 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 + * @ctrl_pdev: cfg pdev + * @htc_pdev: HTC pdev + * @osdev: os dev + * + * Return: txrx pdev handle + * NULL for failure + */ +static struct cdp_pdev * +ol_txrx_pdev_attach(ol_txrx_soc_handle soc, struct cdp_cfg *ctrl_pdev, + HTC_HANDLE htc_pdev, qdf_device_t osdev, uint8_t pdev_id) +{ + struct ol_txrx_pdev_t *pdev; + int i, tid; + + pdev = qdf_mem_malloc(sizeof(*pdev)); + if (!pdev) + goto fail0; + + /* init LL/HL cfg here */ + pdev->cfg.is_high_latency = ol_cfg_is_high_latency(ctrl_pdev); + pdev->cfg.default_tx_comp_req = !ol_cfg_tx_free_at_download(ctrl_pdev); + + /* store provided params */ + pdev->ctrl_pdev = ctrl_pdev; + pdev->osdev = osdev; + + 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->req_list); + pdev->req_list_depth = 0; + qdf_spinlock_create(&pdev->req_list_spinlock); + + /* do initial set up of the peer ID -> peer object lookup map */ + if (ol_txrx_peer_find_attach(pdev)) + 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); + + if (ol_cfg_is_high_latency(ctrl_pdev)) { + qdf_spinlock_create(&pdev->tx_queue_spinlock); + pdev->tx_sched.scheduler = ol_tx_sched_attach(pdev); + if (pdev->tx_sched.scheduler == NULL) + goto fail2; + } + ol_txrx_pdev_txq_log_init(pdev); + ol_txrx_pdev_grp_stats_init(pdev); + + pdev->htt_pdev = + htt_pdev_alloc(pdev, ctrl_pdev, htc_pdev, osdev); + if (!pdev->htt_pdev) + 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; + + ol_txrx_debugfs_init(pdev); + + return (struct cdp_pdev *)pdev; + +fail3: + ol_txrx_peer_find_detach(pdev); + +fail2: + if (ol_cfg_is_high_latency(ctrl_pdev)) + qdf_spinlock_destroy(&pdev->tx_queue_spinlock); + +fail1: + ol_txrx_tso_stats_deinit(pdev); + ol_txrx_fw_stats_desc_pool_deinit(pdev); + qdf_mem_free(pdev); + +fail0: + return NULL; +} + +#if !defined(REMOVE_PKT_LOG) && !defined(QVIT) +/** + * htt_pkt_log_init() - API to initialize packet log + * @handle: pdev handle + * @scn: HIF context + * + * Return: void + */ +void htt_pkt_log_init(struct cdp_pdev *ppdev, void *scn) +{ + struct ol_txrx_pdev_t *handle = (struct ol_txrx_pdev_t *)ppdev; + + if (handle->pkt_log_init) + return; + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + pktlog_sethandle(&handle->pl_dev, scn); + pktlog_set_callback_regtype(PKTLOG_DEFAULT_CALLBACK_REGISTRATION); + if (pktlogmod_init(scn)) + qdf_print("%s: pktlogmod_init failed", __func__); + else + handle->pkt_log_init = true; + } +} + +/** + * 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 (cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam()) && + handle->pkt_log_init) { + pktlogmod_exit(handle); + handle->pkt_log_init = false; + } +} + +#else +void htt_pkt_log_init(struct cdp_pdev *pdev_handle, void *ol_sc) { } +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 + * @pdev: txrx pdev + * + * Return: 0 for success + */ +int +ol_txrx_pdev_post_attach(struct cdp_pdev *ppdev) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + 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); + + 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) { + 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 outselves. + * HL - wait for a HTT target credit initialization + * during htt_attach. + */ + if (pdev->cfg.is_high_latency) { + 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); + } else { + qdf_atomic_add(ol_cfg_target_tx_credit(pdev->ctrl_pdev), + &pdev->target_tx_credit); + desc_pool_size = ol_tx_get_desc_global_pool_size(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) || + (NULL == 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( + "%s first tx_desc:0x%pK Last tx desc:0x%pK\n", __func__, + (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->tx_mutex); + 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; + } + +#ifdef PERE_IP_HDR_ALIGNMENT_WAR + pdev->host_80211_enable = ol_scn_host_80211_enable_get(pdev->ctrl_pdev); +#endif + + /* + * 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_tkip].cmp = + pdev->rx_pn[htt_sec_type_tkip_nomic].cmp = + pdev->rx_pn[htt_sec_type_aes_ccmp].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\n", 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->tx_mutex); + 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 + * + * @pdev - the physical device being initialized + * + * 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_pdev *ppdev) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + 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. + */ + if (qdf_atomic_read(&tx_desc->ref_cnt)) { + 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 + * @pdev - the data physical device object 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_pdev *ppdev, int force) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + /* 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\n", + pdev); + ol_txrx_peer_find_hash_erase(pdev); + } + + /* to get flow pool status before freeing descs */ + ol_tx_dump_flow_pool_info((void *)pdev); + 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->tx_mutex); + 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); + + /* + * 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 +} + +/** + * ol_txrx_pdev_detach() - delete the data SW state + * @ppdev - the data physical device object 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 + * 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: None + */ +static void ol_txrx_pdev_detach(struct cdp_pdev *ppdev, int force) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + struct ol_txrx_stats_req_internal *req, *temp_req; +#ifdef WLAN_DEBUG + int i = 0; +#endif + + /*checking to ensure txrx pdev structure is not NULL */ + if (!pdev) { + ol_txrx_err( + "NULL pdev passed to %s\n", __func__); + return; + } + + htt_pktlogmod_exit(pdev); + + 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\n", + 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)\n", + 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); + + 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); + + qdf_mem_free(pdev); +} + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * ol_txrx_vdev_tx_desc_cnt_init() - initialise tx descriptor count for vdev + * @vdev: the virtual device object + * + * Return: None + */ +static inline void +ol_txrx_vdev_tx_desc_cnt_init(struct ol_txrx_vdev_t *vdev) +{ + qdf_atomic_init(&vdev->tx_desc_count); +} +#else + +static inline void +ol_txrx_vdev_tx_desc_cnt_init(struct ol_txrx_vdev_t *vdev) +{ +} +#endif + +/** + * ol_txrx_vdev_attach - Allocate and initialize the data object + * for a new virtual device. + * + * @data_pdev - the physical device the virtual device belongs to + * @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 + * + * Return: success: handle to new data vdev object, failure: NULL + */ +static struct cdp_vdev * +ol_txrx_vdev_attach(struct cdp_pdev *ppdev, + uint8_t *vdev_mac_addr, + uint8_t vdev_id, enum wlan_op_mode op_mode) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + struct ol_txrx_vdev_t *vdev; + QDF_STATUS qdf_status; + + /* preconditions */ + TXRX_ASSERT2(pdev); + TXRX_ASSERT2(vdev_mac_addr); + + vdev = qdf_mem_malloc(sizeof(*vdev)); + if (!vdev) + return NULL; /* failure */ + + /* store provided params */ + vdev->pdev = pdev; + vdev->vdev_id = vdev_id; + vdev->opmode = op_mode; + + 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_tx_desc_cnt_init(vdev); + + qdf_mem_copy(&vdev->mac_addr.raw[0], vdev_mac_addr, + OL_TXRX_MAC_ADDR_LEN); + + TAILQ_INIT(&vdev->peer_list); + vdev->last_real_peer = NULL; + + ol_txrx_hl_tdls_flag_reset((struct cdp_vdev *)vdev, false); + +#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; + + /* 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); + /* add this vdev into the pdev's list */ + TAILQ_INSERT_TAIL(&pdev->vdev_list, vdev, vdev_list_elem); + + ol_txrx_dbg( + "Created vdev %pK (%02x:%02x:%02x:%02x:%02x:%02x)\n", + vdev, + 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]); + + /* + * 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 (struct cdp_vdev *)vdev; +} + +/** + *ol_txrx_vdev_register - Link a vdev's data object with the + * matching OS shim vdev object. + * + * @txrx_vdev: the virtual device's data object + * @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 void ol_txrx_vdev_register(struct cdp_vdev *pvdev, + void *osif_vdev, + struct ol_txrx_ops *txrx_ops) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + if (qdf_unlikely(!vdev) || qdf_unlikely(!txrx_ops)) { + qdf_print("%s: vdev/txrx_ops is NULL!\n", __func__); + qdf_assert(0); + return; + } + + 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; + txrx_ops->tx.tx = ol_tx_data; +} + +#ifdef currently_unused +/** + * ol_txrx_set_curchan - Setup the current operating channel of + * the device + * @pdev - the data physical device object + * @chan_mhz - the channel frequency (mhz) packets on + * + * Mainly used when populating monitor mode status that requires + * the current operating channel + * + */ +void ol_txrx_set_curchan(ol_txrx_pdev_handle pdev, uint32_t chan_mhz) +{ +} +#endif + +void ol_txrx_set_safemode(ol_txrx_vdev_handle vdev, uint32_t val) +{ + vdev->safemode = val; +} + +/** + * 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; +} + +void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val) +{ + vdev->drop_unenc = val; +} + +#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. + * @data_vdev: data object for the virtual device in question + * @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 void +ol_txrx_vdev_detach(struct cdp_vdev *pvdev, + ol_txrx_vdev_delete_cb callback, void *context) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev; + + /* preconditions */ + TXRX_ASSERT2(vdev); + pdev = vdev->pdev; + + /* prevent anyone from restarting the ll_pause timer again */ + qdf_atomic_set(&vdev->delete.detaching, 1); + + 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_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( + "%s: not deleting vdev object %pK (%02x:%02x:%02x:%02x:%02x:%02x) until deletion finishes for all its peers\n", + __func__, vdev, + 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]); + /* 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_spin_unlock_bh(&pdev->peer_ref_mutex); + qdf_event_destroy(&vdev->wait_delete_comp); + + ol_txrx_dbg( + "%s: deleting vdev obj %pK (%02x:%02x:%02x:%02x:%02x:%02x)\n", + __func__, vdev, + 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]); + + 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); +} + +/** + * 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) +{ + uint8_t sta_id; + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) + return; + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + peer = ol_txrx_peer_find_by_local_id((struct cdp_pdev *)pdev, + sta_id); + if (!peer) + continue; + 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. + * @data_pdev: data physical device object that will indirectly + * own the data_peer object + * @data_vdev - data virtual device object that will directly + * own the data_peer object + * @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: handle to new data peer object, or NULL if the attach + * fails + */ +static void * +ol_txrx_peer_attach(struct cdp_vdev *pvdev, uint8_t *peer_mac_addr) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + 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 (%02x:%02x:%02x:%02x:%02x:%02x) already exists.\n", + vdev->vdev_id, + peer_mac_addr[0], peer_mac_addr[1], + peer_mac_addr[2], peer_mac_addr[3], + peer_mac_addr[4], peer_mac_addr[5]); + 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 NULL; + } + } + 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 (%02x:%02x:%02x:%02x:%02x:%02x) old peer exists.\n", + vdev->vdev_id, + vdev->last_peer_mac_addr.raw[0], + vdev->last_peer_mac_addr.raw[1], + vdev->last_peer_mac_addr.raw[2], + vdev->last_peer_mac_addr.raw[3], + vdev->last_peer_mac_addr.raw[4], + vdev->last_peer_mac_addr.raw[5]); + 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 NULL; + } + } + } + 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\n", + 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 NULL; + } + } + + peer = qdf_mem_malloc(sizeof(*peer)); + if (!peer) + return NULL; /* failure */ + + /* store provided params */ + peer->vdev = vdev; + qdf_mem_copy(&peer->mac_addr.raw[0], peer_mac_addr, + OL_TXRX_MAC_ADDR_LEN); + + 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); + + 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 (%02x:%02x:%02x:%02x:%02x:%02x)\n", + vdev, peer, qdf_atomic_read(&peer->ref_cnt), + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + /* + * For every peer MAp message search and set if bss_peer + */ + if (qdf_mem_cmp(peer->mac_addr.raw, vdev->mac_addr.raw, + OL_TXRX_MAC_ADDR_LEN)) + 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((struct cdp_pdev *)pdev, 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((struct cdp_vdev *)vdev, true); + } + + ol_txrx_local_peer_id_alloc(pdev, peer); + + return (void *)peer; +} + +#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; +} + +#ifdef WLAN_FEATURE_11W +/** + * ol_txrx_get_pn_info() - Returns pn info from peer + * @peer: handle to peer + * @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 + */ +void +ol_txrx_get_pn_info(void *ppeer, uint8_t **last_pn_valid, + uint64_t **last_pn, uint32_t **rmf_pn_replays) +{ + ol_txrx_peer_handle peer = ppeer; + *last_pn_valid = &peer->last_rmf_pn_valid; + *last_pn = &peer->last_rmf_pn; + *rmf_pn_replays = &peer->rmf_pn_replays; +} +#else +void +ol_txrx_get_pn_info(void *ppeer, uint8_t **last_pn_valid, + uint64_t **last_pn, uint32_t **rmf_pn_replays) +{ +} +#endif + +/** + * ol_txrx_get_opmode() - Return operation mode of vdev + * @vdev: vdev handle + * + * Return: operation mode. + */ +static int ol_txrx_get_opmode(struct cdp_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + return vdev->opmode; +} + +/** + * ol_txrx_get_peer_state() - Return peer state of peer + * @peer: peer handle + * + * Return: return peer state + */ +static int ol_txrx_get_peer_state(void *ppeer) +{ + ol_txrx_peer_handle peer = ppeer; + + return peer->state; +} + +/** + * ol_txrx_get_vdev_for_peer() - Return vdev from peer handle + * @peer: peer handle + * + * Return: vdev handle from peer + */ +static struct cdp_vdev *ol_txrx_get_vdev_for_peer(void *ppeer) +{ + ol_txrx_peer_handle peer = ppeer; + + return (struct cdp_vdev *)peer->vdev; +} + +/** + * ol_txrx_get_vdev_mac_addr() - Return mac addr of vdev + * @vdev: vdev handle + * + * Return: vdev mac address + */ +static uint8_t * +ol_txrx_get_vdev_mac_addr(struct cdp_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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 + * @vdev: vdev handle + * + * Return: Handle to control pdev + */ +static struct cdp_cfg * +ol_txrx_get_ctrl_pdev_from_vdev(struct cdp_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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 + * @vdev: vdev handle + * @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_vdev *pvdev, + int16_t peer_num_delta) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + int16_t new_peer_num; + + 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 + * @vdev: vdev handle + * @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_vdev *pvdev, + uint16_t timer_value_sec) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + uint16_t old_timer_value = vdev->ibss_peer_heart_beat_timer; + + vdev->ibss_peer_heart_beat_timer = timer_value_sec; + + return old_timer_value; +} +#endif + +/** + * ol_txrx_remove_peers_for_vdev() - remove all vdev peers with lock held + * @vdev: vdev handle + * @callback: callback function to remove the peer. + * @callback_context: handle for callback function + * @remove_last_peer: Does it required to last peer. + * + * Return: NONE + */ +static void +ol_txrx_remove_peers_for_vdev(struct cdp_vdev *pvdev, + ol_txrx_vdev_peer_remove_cb callback, + void *callback_context, bool remove_last_peer) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + ol_txrx_peer_handle peer, temp; + int self_removed = 0; + /* remove all remote peers for vdev */ + qdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + + temp = NULL; + TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, + peer_list_elem) { + if (qdf_atomic_read(&peer->delete_in_progress)) + continue; + if (temp) { + qdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + callback(callback_context, temp->mac_addr.raw, + vdev->vdev_id, temp); + qdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + } + /* self peer is deleted last */ + if (peer == TAILQ_FIRST(&vdev->peer_list)) { + self_removed = 1; + break; + } + temp = peer; + } + + qdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + + if (self_removed) + ol_txrx_info("%s: self peer removed by caller ", + __func__); + + if (remove_last_peer) { + /* remove IBSS bss peer last */ + peer = TAILQ_FIRST(&vdev->peer_list); + callback(callback_context, (uint8_t *) &vdev->mac_addr, + vdev->vdev_id, peer); + } +} + +/** + * ol_txrx_remove_peers_for_vdev_no_lock() - remove vdev peers with no lock. + * @vdev: vdev handle + * @callback: callback function to remove the peer. + * @callback_context: handle for callback function + * + * Return: NONE + */ +static void +ol_txrx_remove_peers_for_vdev_no_lock(struct cdp_vdev *pvdev, + ol_txrx_vdev_peer_remove_cb callback, + void *callback_context) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + ol_txrx_peer_handle peer = NULL; + ol_txrx_peer_handle tmp_peer = NULL; + + TAILQ_FOREACH_SAFE(peer, &vdev->peer_list, peer_list_elem, tmp_peer) { + ol_txrx_info_high( + "%s: peer found for vdev id %d. deleting the peer", + __func__, vdev->vdev_id); + callback(callback_context, (uint8_t *)&vdev->mac_addr, + vdev->vdev_id, peer); + } +} + +/** + * ol_txrx_set_ocb_chan_info() - set OCB channel info to vdev. + * @vdev: vdev handle + * @ocb_set_chan: OCB channel information to be set in vdev. + * + * Return: NONE + */ +static void ol_txrx_set_ocb_chan_info(struct cdp_vdev *pvdev, + struct ol_txrx_ocb_set_chan ocb_set_chan) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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 + * @vdev: vdev handle + * + * Return: handle to struct ol_txrx_ocb_chan_info + */ +static struct ol_txrx_ocb_chan_info * +ol_txrx_get_ocb_chan_info(struct cdp_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + return vdev->ocb_channel_info; +} + +/** + * @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 data_peer - 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_pdev *ppdev, + uint8_t *peer_mac, + enum ol_txrx_peer_state state) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + 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 (NULL == peer) { + ol_txrx_err( + "%s: peer is null for peer_mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, + 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( + "%s: no state change, returns directly\n", + __func__); +#endif + peer_ref_cnt = ol_txrx_peer_release_ref + (peer, + PEER_DEBUG_ID_OL_INTERNAL); + return QDF_STATUS_SUCCESS; + } + + ol_txrx_dbg("%s: change from %d to %d\n", + __func__, 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( + "%s: pause peer and unpause mgmt/non-qos\n", + __func__); + 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("%s: peer is null", + __func__); + 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 != NULL) + 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( + "%s, delete reorder arr, tid:%d\n", + __func__, 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_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 = false; + int access_list = 0; + uint32_t err_code = 0; + + /* preconditions */ + TXRX_ASSERT2(peer); + + vdev = peer->vdev; + if (NULL == vdev) { + ol_txrx_err("The vdev is not present anymore\n"); + return -EINVAL; + } + + pdev = vdev->pdev; + if (NULL == pdev) { + ol_txrx_err("The pdev is not present anymore\n"); + 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\n"); + 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; + /* 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; + /* + * 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( + "%s: deleting vdev object %pK (%02x:%02x:%02x:%02x:%02x:%02x) - its last peer is done", + __func__, vdev, + 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]); + /* all peers are gone, go ahead and delete it */ + qdf_mem_free(vdev); + if (vdev_delete_cb) + vdev_delete_cb(vdev_delete_context); + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + } + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + } + + ol_txrx_info_high("[%d][%d]: Deleting peer %pK ref_cnt -> %d %s", + debug_id, + qdf_atomic_read(&peer->access_list[debug_id]), + peer, 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; + + 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 + * @sta_id: sta id + * + * Return: QDF Status + */ +static QDF_STATUS ol_txrx_clear_peer(struct cdp_pdev *ppdev, uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + QDF_STATUS status; + + if (!pdev) { + ol_txrx_err("Unable to find pdev!"); + return QDF_STATUS_E_FAILURE; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + ol_txrx_err("Invalid sta id %d", sta_id); + return QDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_get_ref_by_local_id(ppdev, sta_id, + 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_STR, + QDF_MAC_ADDR_ARRAY(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 (%02x:%02x:%02x:%02x:%02x:%02x)", + peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + if (cds_is_self_recovery_enabled()) { + if (!cds_is_driver_recovering() && !cds_is_fw_down()) + cds_trigger_recovery(QDF_PEER_UNMAP_TIMEDOUT); + else + ol_txrx_err("Recovery is in progress, ignore!"); + } else { + QDF_BUG(0); + } +} + + +/** + * ol_txrx_peer_detach() - Delete a peer's data object. + * @peer - the object to detach + * @bitmap - bitmap indicating special handling of request. + * + * 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: None + */ +static void ol_txrx_peer_detach(void *ppeer, uint32_t bitmap) +{ + ol_txrx_peer_handle peer = ppeer; + struct ol_txrx_vdev_t *vdev = peer->vdev; + + /* 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 (%02x:%02x:%02x:%02x:%02x:%02x)", + __func__, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + + 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. + */ + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_PEER_ATTACH); +} + +/** + * ol_txrx_peer_detach_force_delete() - Detach and delete a peer's data object + * @ppeer - the object to detach + * + * 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(void *ppeer) +{ + ol_txrx_peer_handle peer = ppeer; + ol_txrx_pdev_handle pdev = peer->vdev->pdev; + + ol_txrx_info_high("%s peer %pK, peer->ref_cnt %d", + __func__, peer, qdf_atomic_read(&peer->ref_cnt)); + + /* Clear the peer_id_to_obj map entries */ + ol_txrx_peer_remove_obj_map_entries(pdev, peer); + ol_txrx_peer_detach(peer, 1 << CDP_PEER_DELETE_NO_SPECIAL); +} + +/** + * ol_txrx_peer_detach_sync() - peer detach sync callback + * @ppeer - the peer object + * @peer_unmap_sync - peer unmap sync cb. + * @bitmap - bitmap indicating special handling of request. + * + * Return: None + */ +static void ol_txrx_peer_detach_sync(void *ppeer, + ol_txrx_peer_unmap_sync_cb peer_unmap_sync, + uint32_t bitmap) +{ + ol_txrx_peer_handle peer = ppeer; + ol_txrx_pdev_handle pdev = peer->vdev->pdev; + + ol_txrx_info_high("%s peer %pK, peer->ref_cnt %d", __func__, + peer, qdf_atomic_read(&peer->ref_cnt)); + + if (!pdev->peer_unmap_sync_cb) + pdev->peer_unmap_sync_cb = peer_unmap_sync; + + ol_txrx_peer_detach(peer, bitmap); +} + +/** + * ol_txrx_peer_unmap_sync_cb_set() - set peer unmap sync callback + * @ppdev - TXRX pdev context + * @peer_unmap_sync - peer unmap sync callback + * + * Return: None + */ +static void ol_txrx_peer_unmap_sync_cb_set( + struct cdp_pdev *ppdev, + ol_txrx_peer_unmap_sync_cb peer_unmap_sync) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + if (!pdev->peer_unmap_sync_cb) + pdev->peer_unmap_sync_cb = peer_unmap_sync; +} + +/** + * 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_pdev_t *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (txrx_pdev == NULL) { + ol_txrx_err( + "%s: txrx context is null", __func__); + 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( + "%s: tx frames are pending", __func__); + 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 + * @txrx_pdev: TXRX pdev context + * + * 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_pdev *ppdev) +{ + struct ol_txrx_pdev_t *txrx_pdev = (struct ol_txrx_pdev_t *)ppdev; + + if (ol_txrx_get_tx_pending((struct cdp_pdev *)txrx_pdev)) + return QDF_STATUS_E_BUSY; + else + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_runtime_resume() - ensure TXRX is ready to runtime resume + * @txrx_pdev: TXRX pdev context + * + * This is a dummy function for symmetry. + * + * Return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS ol_txrx_runtime_resume(struct cdp_pdev *ppdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ol_txrx_bus_suspend() - bus suspend + * @ppdev: TXRX pdev context + * + * Ensure that ol_txrx is ready for bus suspend + * + * Return: QDF_STATUS + */ +static QDF_STATUS ol_txrx_bus_suspend(struct cdp_pdev *ppdev) +{ + return ol_txrx_wait_for_pending_tx(SUSPEND_DRAIN_WAIT); +} + +/** + * ol_txrx_bus_resume() - bus resume + * @ppdev: TXRX pdev context + * + * Dummy function for symetry + * + * Return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS ol_txrx_bus_resume(struct cdp_pdev *ppdev) +{ + 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 + */ +int 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 tha 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("%s: pdev is NULL", __func__); + 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) { + ol_txrx_err("%s: failed to allocate desc pool", __func__); + 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("%s: pdev is NULL", __func__); + return; + } + if (!qdf_atomic_read(&pdev->ol_txrx_fw_stats_desc_pool.initialized)) { + ol_txrx_err("%s: Pool is not initialized", __func__); + return; + } + if (!pdev->ol_txrx_fw_stats_desc_pool.pool) { + ol_txrx_err("%s: Pool is not allocated", __func__); + 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("%s: Pool deinitialized", __func__); + 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("%s: desc_id %d allocated", + __func__, desc->desc_id); + else + ol_txrx_err("%s: fw stats descriptors are exhausted", __func__); + + 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("%s: Desc ID %u Pool deinitialized", + __func__, 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; +} + +static A_STATUS +ol_txrx_fw_stats_get(struct cdp_vdev *pvdev, struct ol_txrx_stats_req *req, + bool per_vdev, bool response_expected) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_pdev_t *pdev = vdev->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 (!pdev || + req->stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || + req->stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { + return A_ERROR; + } + + /* + * 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_ERROR; + } + + /* 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("%s: Cookie is not valid", __func__); + return; + } + req = ol_txrx_fw_stats_desc_get_req(pdev, (uint8_t)cookie); + if (!req) { + ol_txrx_err("%s: Request not retrieved for cookie %u", __func__, + (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\n", 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 */ + + 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) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "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) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "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) +{ +#ifdef WLAN_DEBUG + 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.others.pkts; +#endif + + if (level == QDF_STATS_VERBOSITY_LEVEL_LOW) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "STATS |%u %u|TX: %lld tso %lld ok %lld drops(%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, + 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; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "TX PATH Statistics:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "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.no_ack.bytes); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "successfully delivered: %lld (%lld B), download fail: %lld (%lld B), target discard: %lld (%lld B), no ack: %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.others.pkts, + pdev->stats.pub.tx.dropped.others.bytes); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "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); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "RX PATH Statistics:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%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); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " 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); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "Rx 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 */ + +static void ol_vdev_rx_set_intrabss_fwd(struct cdp_vdev *pvdev, bool val) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + if (NULL == vdev) + return; + + vdev->disable_intrabss_fwd = val; +} + +/** + * ol_txrx_update_mac_id() - update mac_id for vdev + * @vdev_id: vdev id + * @mac_id: mac id + * + * Return: none + */ +static void ol_txrx_update_mac_id(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 (NULL == 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 + * @vdev_id: vdev_id + * + * Return: tx ack count + */ +static uint32_t ol_txrx_get_tx_ack_stats(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; +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +/** + * ol_txrx_get_vdev_from_sta_id() - get vdev from sta_id + * @sta_id: sta_id + * + * Return: vdev handle + * NULL if not found. + */ +static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer = NULL; + ol_txrx_pdev_handle pdev = NULL; + + if (sta_id >= WLAN_MAX_STA_COUNT) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid sta id passed"); + return NULL; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "PDEV not found for sta_id [%d]", sta_id); + return NULL; + } + + peer = ol_txrx_peer_find_by_local_id((struct cdp_pdev *)pdev, sta_id); + + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "PEER [%d] not found", sta_id); + return NULL; + } + + return peer->vdev; +} + +/** + * ol_txrx_register_tx_flow_control() - register tx flow control callback + * @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 + */ +static int ol_txrx_register_tx_flow_control(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 (NULL == 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; +} + +/** + * ol_txrx_de_register_tx_flow_control_cb() - deregister tx flow control + * callback + * @vdev_id: vdev_id + * + * Return: 0 for success or error code + */ +static int ol_txrx_deregister_tx_flow_control_cb(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 (NULL == 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 + * @sta_id: sta id + * @low_watermark: low watermark + * @high_watermark_offset: high watermark offset value + * + * Return: true/false + */ +static bool +ol_txrx_get_tx_resource(uint8_t sta_id, + unsigned int low_watermark, + unsigned int high_watermark_offset) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_sta_id(sta_id); + + if (NULL == vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid sta_id %d", __func__, sta_id); + /* 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; +} + +/** + * ol_txrx_ll_set_tx_pause_q_depth() - set pause queue depth + * @vdev_id: vdev id + * @pause_q_depth: pause queue depth + * + * Return: 0 for success or error code + */ +static int +ol_txrx_ll_set_tx_pause_q_depth(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 (NULL == 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; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * ol_txrx_display_stats() - Display OL TXRX display stats + * @value: Module id for which stats needs to be displayed + * + * Return: status + */ +static QDF_STATUS +ol_txrx_display_stats(void *soc, uint16_t value, + enum qdf_stats_verbosity_level verb_level) +{ + ol_txrx_pdev_handle pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + 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: + ol_tx_dump_flow_pool_info((void *)pdev); + 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 + * @value: Module id for which stats needs to be cleared + * + * Return: None + */ +static void ol_txrx_clear_stats(uint16_t value) +{ + ol_txrx_pdev_handle pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL", __func__); + return; + } + + 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; + } + +} + +/** + * 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) +{ + int num_dropped = 0; + qdf_nbuf_t buf, next_buf; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + 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("%s:Dropped frames %u", __func__, 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) { + ol_txrx_err( + "Failed to allocate buf to cache the rx frames"); + 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) +{ + /* + * 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; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + 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 QCA_CONFIG_SMP + /* + * 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 /* QCA_CONFIG_SMP */ + ol_rx_data_handler(pdev, rx_buf_list, peer->local_id); +#endif /* QCA_CONFIG_SMP */ + } + + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + union ol_txrx_peer_update_param_t param; + struct privacy_exemption privacy_filter; + + if (!pdev) { + ol_txrx_err("Pdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (sta_desc->sta_id >= WLAN_MAX_STA_COUNT) { + ol_txrx_err("Invalid sta id :%d", + sta_desc->sta_id); + return QDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_by_local_id((struct cdp_pdev *)pdev, + sta_desc->sta_id); + 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 + * @peer_id: Pointer to the peer ID + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +static QDF_STATUS ol_txrx_register_ocb_peer(uint8_t *mac_addr, + uint8_t *peer_id) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + ol_txrx_err("%s: Unable to find pdev!", + __func__); + return QDF_STATUS_E_FAILURE; + } + + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, + mac_addr, peer_id); + if (!peer) { + ol_txrx_err("%s: Unable to find OCB peer!", + __func__); + return QDF_STATUS_E_FAILURE; + } + + ol_txrx_set_ocb_peer(pdev, peer); + + /* Set peer state to connected */ + ol_txrx_peer_state_update((struct cdp_pdev *)pdev, 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 == NULL) + 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 == NULL) || (peer == NULL)) { + 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 + * @pause_cb: pause callback + * + * Return: QDF status + */ +static QDF_STATUS ol_txrx_register_pause_cb(struct cdp_soc_t *soc, + tx_pause_callback pause_cb) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + 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) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (qdf_unlikely(!pdev)) { + ol_txrx_err("Invalid 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; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (qdf_unlikely(!sched_ctx)) + return; + + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (pdev == NULL) { + ol_txrx_err("pdev NULL!"); + TXRX_ASSERT2(0); + goto out; + } + if (pdev->offld_flush_cb != NULL) { + 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 == NULL)) { + ol_txrx_err("hif_device NULL!"); + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (pdev == NULL) { + ol_txrx_err("pdev NULL!"); + return; + } + hif_device = cds_get_context(QDF_MODULE_ID_HIF); + + if (qdf_unlikely(hif_device == NULL)) { + ol_txrx_err("hif_device NULL!"); + 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 + * @data_stall_detect_callback: data stall callback function + * + * + * Return: QDF_STATUS Enumeration + */ +static QDF_STATUS ol_register_data_stall_detect_cb( + data_stall_detect_cb data_stall_detect_callback) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (pdev == NULL) { + ol_txrx_err("%s: pdev NULL!", __func__); + 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 + * @data_stall_detect_callback: data stall callback function + * + * + * Return: QDF_STATUS Enumeration + */ +static QDF_STATUS ol_deregister_data_stall_detect_cb( + data_stall_detect_cb data_stall_detect_callback) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (pdev == NULL) { + ol_txrx_err("%s: pdev NULL!", __func__); + 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( + 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 scheduler_msg msg = {0}; + QDF_STATUS status; + struct data_stall_event_info *data_stall_info; + ol_txrx_pdev_handle pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL.", __func__); + return; + } + data_stall_info = qdf_mem_malloc(sizeof(*data_stall_info)); + if (!data_stall_info) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: data_stall_info is NULL.", __func__); + return; + } + 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); + + sys_build_message_header(SYS_MSG_ID_DATA_STALL_MSG, &msg); + /* Save callback and data */ + msg.callback = pdev->data_stall_detect_callback; + msg.bodyptr = data_stall_info; + msg.bodyval = 0; + + status = scheduler_post_message(QDF_MODULE_ID_TXRX, + QDF_MODULE_ID_HDD, + QDF_MODULE_ID_SYS, &msg); + + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post data stall msg to SYS", __func__); + qdf_mem_free(data_stall_info); + } +} + +void +ol_txrx_dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len) +{ + qdf_print("%s: Pkt: VA 0x%pK PA 0x%llx len %d\n", __func__, + 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); +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +bool +ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *vdev) +{ + struct ol_tx_flow_pool_t *pool; + bool enough_desc_flag; + + if (!vdev) + return false; + + pool = 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; +} +#else +bool ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *vdev) +{ + return true; +} +#endif + +/** + * 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_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + ol_txrx_vdev_handle vdev = NULL; + + if (qdf_unlikely(!pdev)) + return NULL; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) + break; + } + + return (struct cdp_vdev *)vdev; +} + +/** + * ol_txrx_set_wisa_mode() - set wisa mode + * @vdev: vdev handle + * @enable: enable flag + * + * Return: QDF STATUS + */ +static QDF_STATUS ol_txrx_set_wisa_mode(struct cdp_vdev *pvdev, bool enable) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + 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 int ol_txrx_soc_attach_target(ol_txrx_soc_handle soc) +{ + /* MCL legacy OL do nothing here */ + return 0; +} + +/** + * ol_txrx_soc_detach() - detach soc target + * @soc: soc handle + * + * MCL legacy OL do nothing here + * + * Return: noe + */ +static void ol_txrx_soc_detach(void *soc) +{ + qdf_mem_free(soc); +} + +/** + * ol_txrx_pkt_log_con_service() - connect packet log service + * @ppdev: physical device handle + * @scn: device context + * + * Return: noe + */ +#ifdef REMOVE_PKT_LOG +static void ol_txrx_pkt_log_con_service(struct cdp_pdev *ppdev, void *scn) +{ +} +#else +static void ol_txrx_pkt_log_con_service(struct cdp_pdev *ppdev, void *scn) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + htt_pkt_log_init((struct cdp_pdev *)pdev, scn); + pktlog_htc_attach(); +} +#endif + +/* OL wrapper functions for CDP abstraction */ +/** + * ol_txrx_wrapper_flush_rx_frames() - flush rx frames on the queue + * @peer: peer handle + * @drop: rx packets drop or deliver + * + * Return: none + */ +static void ol_txrx_wrapper_flush_rx_frames(void *peer, bool drop) +{ + ol_txrx_flush_rx_frames((ol_txrx_peer_handle)peer, drop); +} + +/** + * ol_txrx_wrapper_get_vdev_from_vdev_id() - get vdev instance from vdev id + * @ppdev: pdev handle + * @vdev_id: interface id + * + * Return: virtual interface instance + */ +static +struct cdp_vdev *ol_txrx_wrapper_get_vdev_from_vdev_id(struct cdp_pdev *ppdev, + uint8_t vdev_id) +{ + return ol_txrx_get_vdev_from_vdev_id(vdev_id); +} + +/** + * 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_pdev *pdev, + struct ol_txrx_desc_type *sta_desc) +{ + return ol_txrx_register_peer(sta_desc); +} + +/** + * ol_txrx_wrapper_peer_find_by_local_id() - Find a txrx peer handle + * @pdev - the data physical device object + * @local_peer_id - the ID txrx assigned locally to the peer in question + * + * 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. + * + * @return handle to the txrx peer object + */ +static void * +ol_txrx_wrapper_peer_find_by_local_id(struct cdp_pdev *pdev, + uint8_t local_peer_id) +{ + return (void *)ol_txrx_peer_find_by_local_id( + pdev, local_peer_id); +} + +/** + * 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 + * @data_peer - 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_pdev *pdev, + uint8_t *peer_mac, enum ol_txrx_peer_state state) +{ + return ol_txrx_peer_state_update(pdev, + peer_mac, state); +} + +/** + * ol_txrx_wrapper_find_peer_by_addr() - find peer instance by address + * @pdev: pdev handle + * @peer_addr: peer address want to find + * @peer_id: peer id + * + * Return: peer instance pointer + */ +static void *ol_txrx_wrapper_find_peer_by_addr(struct cdp_pdev *pdev, + uint8_t *peer_addr, uint8_t *peer_id) +{ + return ol_txrx_find_peer_by_addr(pdev, + peer_addr, peer_id); +} + +/** + * ol_txrx_wrapper_peer_get_ref_by_addr() - get peer reference by address + * @pdev: pdev handle + * @peer_addr: peer address we want to find + * @peer_id: peer id + * @debug_id: peer debug id for tracking + * + * Return: peer instance pointer + */ +static void * +ol_txrx_wrapper_peer_get_ref_by_addr(struct cdp_pdev *pdev, + u8 *peer_addr, uint8_t *peer_id, + enum peer_debug_id_type debug_id) +{ + return ol_txrx_peer_get_ref_by_addr((ol_txrx_pdev_handle)pdev, + peer_addr, peer_id, debug_id); +} + +/** + * ol_txrx_wrapper_peer_release_ref() - release peer reference + * @peer: peer handle + * @debug_id: peer debug id for tracking + * + * Release peer ref acquired by peer get ref api + * + * Return: void + */ +static void ol_txrx_wrapper_peer_release_ref(void *peer, + enum peer_debug_id_type debug_id) +{ + ol_txrx_peer_release_ref(peer, debug_id); +} + +/** + * 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); +} + +#ifdef WDI_EVENT_ENABLE +void *ol_get_pldev(struct cdp_pdev *txrx_pdev) +{ + struct ol_txrx_pdev_t *pdev = + (struct ol_txrx_pdev_t *)txrx_pdev; + if (pdev != NULL) + return pdev->pl_dev; + + return NULL; +} +#endif + +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_vdev_from_vdev_id = ol_txrx_wrapper_get_vdev_from_vdev_id, + .txrx_get_ctrl_pdev_from_vdev = ol_txrx_get_ctrl_pdev_from_vdev, + .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, + .txrx_get_tx_pending = ol_txrx_get_tx_pending, + .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, + /* TODO: Add other functions */ +}; + +static struct cdp_misc_ops ol_ops_misc = { +#ifdef QCA_IBSS_SUPPORT + .set_ibss_vdev_heart_beat_timer = + ol_txrx_set_ibss_vdev_heart_beat_timer, +#endif +#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 +}; + +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, +#endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ +}; + +static struct cdp_lflowctl_ops ol_ops_l_flowctl = { +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + .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 +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +}; + +#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 +}; +#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 +}; + +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 +}; + +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, + .peer_get_ref_by_addr = ol_txrx_wrapper_peer_get_ref_by_addr, + .peer_release_ref = ol_txrx_wrapper_peer_release_ref, + .find_peer_by_addr = ol_txrx_wrapper_find_peer_by_addr, + .find_peer_by_addr_and_vdev = ol_txrx_find_peer_by_addr_and_vdev, + .local_peer_id = ol_txrx_local_peer_id, + .peer_find_by_local_id = ol_txrx_wrapper_peer_find_by_local_id, + .peer_state_update = ol_txrx_wrapper_peer_state_update, + .get_vdevid = ol_txrx_get_vdevid, + .get_vdev_by_sta_id = ol_txrx_get_vdev_by_sta_id, + .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, + .get_vdev_for_peer = ol_txrx_get_vdev_for_peer, +#ifdef QCA_IBSS_SUPPORT + .update_ibss_add_peer_num_of_vdev = + ol_txrx_update_ibss_add_peer_num_of_vdev, +#endif + .remove_peers_for_vdev = ol_txrx_remove_peers_for_vdev, + .remove_peers_for_vdev_no_lock = ol_txrx_remove_peers_for_vdev_no_lock, +#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, +#endif /* CONFIG_HL_SUPPORT */ + .peer_detach_force_delete = ol_txrx_peer_detach_force_delete, +}; + +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, +}; + +/* 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, + .ocb_ops = &ol_ops_ocb, + .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 +}; + +/* + * Local prototype added to temporarily address warning caused by + * -Wmissing-prototypes. A more correct solution, namely to expose + * a prototype in an appropriate header file, will come later. + */ +struct cdp_soc_t *ol_txrx_soc_attach(void *scn_handle, + struct ol_if_ops *dp_ol_if_ops); +struct cdp_soc_t *ol_txrx_soc_attach(void *scn_handle, + struct ol_if_ops *dp_ol_if_ops) +{ + struct cdp_soc_t *soc = qdf_mem_malloc(sizeof(struct cdp_soc_t)); + + if (!soc) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: OL SOC memory allocation failed\n", __func__); + return NULL; + } + + soc->ops = &ol_txrx_ops; + return soc; +} + +bool ol_txrx_get_new_htt_msg_format(struct ol_txrx_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + return false; + } + return pdev->new_htt_msg_format; +} + +void ol_txrx_set_new_htt_msg_format(uint8_t val) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + return; + } + pdev->new_htt_msg_format = val; +} + +bool ol_txrx_get_peer_unmap_conf_support(void) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + return false; + } + return pdev->enable_peer_unmap_conf_support; +} + +void ol_txrx_set_peer_unmap_conf_support(bool val) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + return false; + } + return pdev->enable_tx_compl_tsf64; +} + +void ol_txrx_set_tx_compl_tsf64(bool val) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.h new file mode 100644 index 0000000000000000000000000000000000000000..b0b18236734648a1893924659e12c6ec49c4c20b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.h @@ -0,0 +1,207 @@ +/* + * 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 _OL_TXRX__H_ +#define _OL_TXRX__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include "cds_sched.h" +#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 + +#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, + u8 *peer_id, + 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_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 CONFIG_PER_VDEV_TX_DESC_POOL +#define TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK 400 +#define TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED 100 +#endif + +#ifdef CONFIG_TX_DESC_HI_PRIO_RESERVE +#define TXRX_HL_TX_DESC_HI_PRIO_RESERVED 20 +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +void +ol_txrx_hl_tdls_flag_reset(struct cdp_vdev *vdev, bool flag); +#else + +static inline void +ol_txrx_hl_tdls_flag_reset(struct cdp_vdev *vdev, bool flag) +{ +} +#endif + +#ifdef WDI_EVENT_ENABLE +void *ol_get_pldev(struct cdp_pdev *txrx_pdev); +#else +static inline +void *ol_get_pldev(struct cdp_pdev *txrx_pdev) +{ + return NULL; +} +#endif +/* + * @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_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 *vdev); + +struct cdp_vdev *ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id); + +void *ol_txrx_find_peer_by_addr(struct cdp_pdev *pdev, + uint8_t *peer_addr, + uint8_t *peer_id); + +void htt_pkt_log_init(struct cdp_pdev *pdev_handle, void *scn); +void peer_unmap_timer_handler(void *data); + +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); + +/** + * 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); +#endif /* _OL_TXRX__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c new file mode 100644 index 0000000000000000000000000000000000000000..1abb37faa0935ddf0a9f0a2244e59f1d192bae13 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2012-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_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] |= 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, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, &vdev->mac_addr.raw, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + 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, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + /* need to check the bssid behaviour for IBSS vdev */ + qdf_mem_copy(wh->i_addr3, &vdev->mac_addr.raw, + IEEE80211_ADDR_LEN); + 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, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr, + IEEE80211_ADDR_LEN); + 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] |= 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 >= IEEE8023_MAX_LEN) { + 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 != NULL); + 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 != NULL) { + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr4, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + 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] &= ~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 == NULL) { + /* + * 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, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + ETHERNET_ADDR_LEN); + break; + } + } + if (llc_hdr == NULL) { + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h new file mode 100644 index 0000000000000000000000000000000000000000..360717e7a1dd9e95edfca6f78cb4b284d2eed14e --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_event.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_event.c new file mode 100644 index 0000000000000000000000000000000000000000..e09ad1dd42a4d0d4d0f3698b5ab67ba1b22866d5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_event.c @@ -0,0 +1,233 @@ +/* + * 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. + */ + +#include "ol_txrx_types.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, + struct cdp_pdev *ppdev, void *data) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + struct ol_txrx_pdev_t *txrx_pdev = + (struct ol_txrx_pdev_t *)ppdev; + + /* + * Input validation + */ + if (!event) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid WDI event in %s\n", __func__); + return; + } + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid pdev in WDI event handler\n"); + 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_pdev *ppdev, + void *pevent_cb_sub, uint32_t event) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + struct ol_txrx_pdev_t *txrx_pdev = + (struct ol_txrx_pdev_t *)ppdev; + wdi_event_subscribe *event_cb_sub = + (wdi_event_subscribe *)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_pdev *ppdev, + void *pevent_cb_sub, uint32_t event) +{ + uint32_t event_index = event - WDI_EVENT_BASE; + + struct ol_txrx_pdev_t *txrx_pdev = + (struct ol_txrx_pdev_t *)ppdev; + + wdi_event_subscribe *event_cb_sub = + (wdi_event_subscribe *)pevent_cb_sub; + + /* 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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Insufficient memory for the WDI event lists\n"); + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c new file mode 100644 index 0000000000000000000000000000000000000000..d72ed8eb8259968c650292a120e556d93bd5d333 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c @@ -0,0 +1,1154 @@ +/* + * Copyright (c) 2015-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. + */ + +/* 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\n"); +} + +/** + * 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 + +/** + * 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; + + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) + ol_tx_deregister_global_mgmt_pool(pdev); + + 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!!!\n", i++); + + if (i == 1) + ol_tx_dump_flow_pool_info((void *)pdev); + + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + 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( + "%s: pool is NULL\n", __func__); + QDF_ASSERT(0); + return -ENOMEM; + } + if (!pdev) { + ol_txrx_err( + "%s: pdev is NULL\n", __func__); + 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( + "%s: invalid pool created %d\n", + __func__, 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pool) { + ol_txrx_err("flow pool is NULL"); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + 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 + */ +#ifdef WLAN_DEBUG +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"; + } +} +#endif + +/** + * ol_tx_dump_flow_pool_info() - dump global_pool and flow_pool info + * @ctx: cdp_soc context, required only in lithium_dp flow control. + * Remove void * while cleaning up cds_get_context. + * + * Return: none + */ +void ol_tx_dump_flow_pool_info(void *ctx) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool = NULL, *pool_prev = NULL; + struct ol_tx_flow_pool_t tmp_pool; + + + if (!pdev) { + ol_txrx_err("ERROR: pdev NULL"); + QDF_ASSERT(0); /* traceback */ + return; + } + + ol_txrx_log(QDF_TRACE_LEVEL_INFO_LOW, + "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); + + ol_txrx_log(QDF_TRACE_LEVEL_INFO_LOW, + "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); + + ol_txrx_log(QDF_TRACE_LEVEL_INFO_LOW, + "flow_pool_id %d ::", tmp_pool.flow_pool_id); + ol_txrx_log(QDF_TRACE_LEVEL_INFO_LOW, + "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); + ol_txrx_log(QDF_TRACE_LEVEL_INFO_LOW, + "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); + ol_txrx_log(QDF_TRACE_LEVEL_INFO_LOW, + "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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + ol_txrx_err("%s: pdev is null\n", + __func__); + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *dst_pool = NULL; + uint16_t desc_count = src_pool->avail_desc; + uint16_t desc_move_count = 0; + + if (!pdev) { + ol_txrx_err( + "%s: pdev is NULL\n", __func__); + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + 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 (!pdev) { + ol_txrx_err( + "%s: pdev is NULL\n", __func__); + 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) { + ol_txrx_err( + "%s: malloc failed\n", __func__); + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if ((!pdev) || (!pool) || (pool->status != FLOW_POOL_INVALID)) { + ol_txrx_err( + "%s: Invalid pool/pdev\n", __func__); + return -EINVAL; + } + + /* direclty 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( + "%s: invalid pool deleted %d\n", + __func__, 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool = NULL; + bool is_found = false; + + 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( + "%s: invalid vdev_id %d\n", + __func__, 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_err( + "%s: invalid vdev_id %d\n", + __func__, 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + uint8_t pool_create = 0; + enum htt_flow_type type = flow_type; + + ol_txrx_dbg( + "%s: flow_id %d flow_type %d flow_pool_id %d flow_pool_size %d\n", + __func__, flow_id, flow_type, flow_pool_id, flow_pool_size); + + if (qdf_unlikely(!pdev)) { + ol_txrx_err( + "%s: pdev is NULL", __func__); + 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 == NULL) { + ol_txrx_err( + "%s: creation of flow_pool %d size %d failed\n", + __func__, 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( + "%s: flow type %d not supported !!!\n", + __func__, 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + enum htt_flow_type type = flow_type; + + ol_txrx_dbg( + "%s: flow_id %d flow_type %d flow_pool_id %d\n", + __func__, flow_id, flow_type, flow_pool_id); + + if (qdf_unlikely(!pdev)) { + ol_txrx_err( + "%s: pdev is NULL", __func__); + return; + } + pdev->pool_stats.pool_unmap_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + ol_txrx_info( + "%s: flow_pool not available flow_pool_id %d\n", + __func__, type); + return; + } + + switch (type) { + + case FLOW_TYPE_VDEV: + ol_tx_flow_pool_vdev_unmap(pool, flow_id); + break; + default: + ol_txrx_info( + "%s: flow type %d not supported !!!\n", + __func__, 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + 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 (!pdev) { + ol_txrx_err( + "%s: pdev is NULL\n", __func__); + 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; + + /* destribute 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; + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + uint32_t stop_threshold = + ol_cfg_get_tx_flow_stop_queue_th(pdev->ctrl_pdev); + uint32_t 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + 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; + + 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_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + + ol_txrx_dbg("%s: flow_pool_id %d flow_pool_size %d\n", + __func__, flow_pool_id, flow_pool_size); + + if (qdf_unlikely(!pdev)) { + ol_txrx_err( + "%s: pdev is NULL", __func__); + return; + } + pdev->pool_stats.pool_resize_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + ol_txrx_err("%s: resize for flow_pool %d size %d failed\n", + __func__, 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 diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..04e514a0094c0b65ec9d293ebeb01bb5c39ee1ce --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2011-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_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 /* va_list */ +#include /* qdf_vprint */ + +#define ol_txrx_log(level, args...) \ + QDF_TRACE(QDF_MODULE_ID_TXRX, level, ## args) +#define ol_txrx_logfl(level, format, args...) \ + ol_txrx_log(level, FL(format), ## args) + +#define ol_txrx_alert(format, args...) \ + ol_txrx_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define ol_txrx_err(format, args...) \ + ol_txrx_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define ol_txrx_warn(format, args...) \ + ol_txrx_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define ol_txrx_info(format, args...) \ + ol_txrx_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define ol_txrx_info_high(format, args...) \ + ol_txrx_logfl(QDF_TRACE_LEVEL_INFO_HIGH, format, ## args) +#define ol_txrx_dbg(format, args...) \ + ol_txrx_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +/* + * define PN check failure message print rate + * as 1 second + */ +#define TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS 1000 + +#else +#define ol_txrx_log(level, args...) +#define ol_txrx_logfl(level, format, args...) +#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...) +#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))) { + 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_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_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 += IEEE80211_ADDR_LEN; + 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 != NULL && peer != NULL) { \ + 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(IEEE80211_IS_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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.c new file mode 100644 index 0000000000000000000000000000000000000000..1dd725b60b3b402632ec0e69ca2e3ffe52d2ddd8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.c @@ -0,0 +1,1650 @@ +/* + * 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. + */ + +/*=== 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 /* 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 + +/** + * ol_txrx_ipa_uc_get_resource() - Client request resource information + * @pdev: handle to the HTT instance + * + * 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_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!osdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf device is null!", __func__); + return QDF_STATUS_E_NOENT; + } + + 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; +} + +/** + * ol_txrx_ipa_uc_set_doorbell_paddr() - Client set IPA UC doorbell register + * @pdev: handle to the HTT instance + * + * 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_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + int ret; + + 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; +} + +/** + * ol_txrx_ipa_uc_set_active() - Client notify IPA UC data path active or not + * @pdev: handle to the HTT instance + * @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_pdev *ppdev, bool uc_active, + bool is_tx) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + int ret; + + 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; +} + +/** + * ol_txrx_ipa_uc_op_response() - Handle OP command response from firmware + * @pdev: handle to the device instance + * @op_msg: op response message from firmware + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_op_response(struct cdp_pdev *ppdev, uint8_t *op_msg) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + + 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; +} + +/** + * ol_txrx_ipa_uc_register_op_cb() - Register OP handler function + * @pdev: handle to the device instance + * @op_cb: handler function pointer + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_register_op_cb(struct cdp_pdev *ppdev, + ipa_uc_op_cb_type op_cb, void *usr_ctxt) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + + pdev->ipa_uc_op_cb = op_cb; + pdev->usr_ctxt = usr_ctxt; + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_get_stat() - Get firmware wdi status + * @pdev: handle to the HTT instance + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_get_stat(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + int ret; + + 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; +} + +/** + * ol_txrx_ipa_enable_autonomy() - Enable autonomy RX path + * @pdev: handle to the device instance + * + * Set all RX packet route to IPA + * Return: none + */ +QDF_STATUS ol_txrx_ipa_enable_autonomy(struct cdp_pdev *ppdev) +{ + /* TBD */ + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_disable_autonomy() - Disable autonomy RX path + * @pdev: handle to the device instance + * + * Disable RX packet route to host + * Return: none + */ +QDF_STATUS ol_txrx_ipa_disable_autonomy(struct cdp_pdev *ppdev) +{ + /* TBD */ + return QDF_STATUS_SUCCESS; +} + +#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) +{ + /* Setup MCC sys pipe */ + QDF_IPA_WDI_CONN_IN_PARAMS_NUM_SYS_PIPE_NEEDED(pipe_in) = + OL_TXRX_IPA_MAX_IFACE; + for (int 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 +/** + * 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) +{ + QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(tx_smmu) = + IPA_CLIENT_WLAN1_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; +} + +/** + * 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) +{ + QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) = + IPA_CLIENT_WLAN1_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_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; + 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) +{ +} + +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) +{ +} +#endif + +/** + * 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) +{ + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!osdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf device is null!", __func__); + 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; + 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) +{ + 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; + 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; + QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(rx) = 0; +} + +/** + * ol_txrx_ipa_setup() - Setup and connect IPA pipes + * @pdev: handle to the device instance + * @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 + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *ppdev, 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) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + 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; + 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 (!osdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf device is null!", __func__); + return QDF_STATUS_E_NOENT; + } + + 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); + else + ol_txrx_ipa_wdi_tx_params(ipa_res, tx); + + + /* 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); + else + ol_txrx_ipa_wdi_rx_params(ipa_res, rx); + + 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); + 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; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_cleanup() - Disconnect IPA pipes + * @tx_pipe_handle: Tx pipe handle + * @rx_pipe_handle: Rx pipe handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup(uint32_t tx_pipe_handle, uint32_t rx_pipe_handle) +{ + int ret; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disconnect IPA pipe", __func__); + ret = qdf_ipa_wdi_disconn_pipes(); + 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_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, %pM", + __func__, ifname, 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 falied: 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) +{ + int ret; + + /* unregister the interface with IPA */ + ret = qdf_ipa_wdi_dereg_intf(ifname); + 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; +} + +/** + * ol_txrx_ipa_uc_enable_pipes() - Enable and resume traffic on Tx/Rx pipes + * @pdev: handle to the device instance + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + QDF_STATUS status; + int ret; + + 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(); + 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((struct cdp_pdev *)pdev, true, true); + ol_txrx_ipa_uc_set_active((struct cdp_pdev *)pdev, true, false); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_uc_disable_pipes() – Suspend traffic and disable Tx/Rx pipes + * @pdev: handle to the device instance + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + int ret; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disable IPA pipes", __func__); + ret = qdf_ipa_wdi_disable_pipes(); + 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_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(&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); + + 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_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, + cds_get_context(QDF_MODULE_ID_QDF_DEVICE)); +} + +/** + * ol_txrx_ipa_setup() - Setup and connect IPA pipes + * @pdev: handle to the device instance + * @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_pdev *ppdev, 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) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + 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; + + 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 + * @tx_pipe_handle: Tx pipe handle + * @rx_pipe_handle: Rx pipe handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup(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 == NULL) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_hdr allocation failed"); + 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, %pM", ifname, 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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: ipa_hdr allocation failed", ifname); + 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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "tx_prop allocation failed"); + 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) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "rx_prop allocation failed"); + 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; +} + +/** + * ol_txrx_ipa_uc_enable_pipes() - Enable and resume traffic on Tx/Rx pipes + * @pdev: handle to the device instance + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + int result; + QDF_STATUS status; + + 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((struct cdp_pdev *)pdev, 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((struct cdp_pdev *)pdev, 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; +} + +/** + * ol_txrx_ipa_uc_disable_pipes() – Suspend traffic and disable Tx/Rx pipes + * @pdev: handle to the device instance + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_pdev *ppdev) +{ + ol_txrx_pdev_handle pdev = (ol_txrx_pdev_handle)ppdev; + struct ol_txrx_ipa_resources *ipa_res = &pdev->ipa_resource; + int result; + + 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_pdev *ppdev, + uint8_t reset_stats) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int result; + + 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_pdev *ppdev, + uint64_t quota_bytes) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + int result; + + 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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.h new file mode 100644 index 0000000000000000000000000000000000000000..cadf1a05c5ff8861fd0a9fa23bf6f3fe04cdcf2d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.h @@ -0,0 +1,156 @@ +/* + * 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. + */ + +#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 3 + +#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 */ + +QDF_STATUS ol_txrx_ipa_uc_get_resource(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_uc_set_doorbell_paddr(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_uc_set_active(struct cdp_pdev *pdev, bool uc_active, + bool is_tx); +QDF_STATUS ol_txrx_ipa_uc_op_response(struct cdp_pdev *pdev, uint8_t *op_msg); +QDF_STATUS ol_txrx_ipa_uc_register_op_cb(struct cdp_pdev *pdev, + ipa_uc_op_cb_type op_cb, void *usr_ctxt); +QDF_STATUS ol_txrx_ipa_uc_get_stat(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_enable_autonomy(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_disable_autonomy(struct cdp_pdev *pdev); +#ifdef CONFIG_IPA_WDI_UNIFIED_API +QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *pdev, 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); +#else /* CONFIG_IPA_WDI_UNIFIED_API */ +QDF_STATUS ol_txrx_ipa_setup(struct cdp_pdev *pdev, 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); +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ +QDF_STATUS ol_txrx_ipa_cleanup(uint32_t tx_pipe_handle, + uint32_t rx_pipe_handle); +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_STATUS ol_txrx_ipa_cleanup_iface(char *ifname, bool is_ipv6_enabled); +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_pdev *pdev); +QDF_STATUS ol_txrx_ipa_set_perf_level(int client, + uint32_t max_supported_bw_mbps); +#ifdef FEATURE_METERING +QDF_STATUS ol_txrx_ipa_uc_get_share_stats(struct cdp_pdev *pdev, + uint8_t reset_stats); +QDF_STATUS ol_txrx_ipa_uc_set_quota(struct cdp_pdev *pdev, + uint64_t quota_bytes); +#endif +#endif +#endif /* _OL_TXRX_IPA_H_*/ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c new file mode 100644 index 0000000000000000000000000000000000000000..c92064a7343e794750ef80b642f9739d22f87d93 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c @@ -0,0 +1,852 @@ +/* + * 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. + */ + +/*=== 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 /* 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, OL_TXRX_MAC_ADDR_LEN); + 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, OL_TXRX_MAC_ADDR_LEN); + 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); + } + } + } +} + +/*=== 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( + "%s: peer not found or peer ID is %d invalid", + __func__, 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; + + if (peer_id == HTT_INVALID_PEER) { + ol_txrx_err( + "%s: invalid peer ID %d\n", __func__, 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 */ + qdf_atomic_dec(&pdev->peer_id_to_obj_map[peer_id]. + del_peer_id_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( + "%s: peer already deleted, peer_id %d del_peer_id_ref_cnt %d", + __func__, peer_id, ref_cnt); + return; + } + peer = pdev->peer_id_to_obj_map[peer_id].peer; + + if (peer == NULL) { + /* + * 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( + "%s: peer not found for peer_id %d", + __func__, 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 == NULL) { + /* 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; + peer->peer_ids[i] = HTT_INVALID_PEER; + } + 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 (%02x:%02x:%02x:%02x:%02x:%02x)\n", + indent + 4, " ", i, peer, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + } + } + } +} + +#endif /* if TXRX_DEBUG_LEVEL */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h new file mode 100644 index 0000000000000000000000000000000000000000..a3d6c37a44645f413cdb7cb14088aef0c77a2c29 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2011, 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. + */ + +/** + * @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 + * caling 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 != NULL); */ + /* + * 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); + +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/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_types.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_types.h new file mode 100644 index 0000000000000000000000000000000000000000..456a5de00169ae5e66fe7d8c5b05eca054dac387 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_types.h @@ -0,0 +1,1381 @@ +/* + * 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. + */ + +/** + * @file ol_txrx_types.h + * @brief 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 /* 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 /* ol_pktlog_dev_handle */ +#include +#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 + +/* + * 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) + +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[OL_TXRX_MAC_ADDR_LEN]; + 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; +}; + +#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[OL_TXRX_MAC_ADDR_LEN]; +}; + +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; +}; +#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; + 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; +}; + +/* + * 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 { + /* 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; + } 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 */ + + 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; + + 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; + + 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 */ + tp_ol_packetdump_cb ol_tx_packetdump_cb; + tp_ol_packetdump_cb ol_rx_packetdump_cb; + +#ifdef WLAN_FEATURE_TSF_PLUS + 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; + + 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); + 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 */ + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + bool host_80211_enable; +#endif + + /* + * 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; + struct ol_tx_frms_queue_t *last_used_txq; + } 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; + } 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]; +#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; +}; + +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; + 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; + + 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; + +#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; + +#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(CONFIG_PER_VDEV_TX_DESC_POOL) + qdf_atomic_t tx_desc_count; +#endif + + 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; +}; + +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; + + qdf_atomic_t 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; + + /* + * 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; + +#ifdef WLAN_FEATURE_11W + /* PN counter for Robust Management Frames */ + uint64_t last_rmf_pn; + uint32_t rmf_pn_replays; + uint8_t last_rmf_pn_valid; +#endif + + /* 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; +}; + +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/drivers/staging/qcacld-3.0/core/dp/txrx/txrx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/txrx.h new file mode 100644 index 0000000000000000000000000000000000000000..10a3f6a008ef412b5644d050c89d0f73b0a88478 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/txrx.h @@ -0,0 +1,187 @@ +/* + * 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 TXRX_H +#define TXRX_H + +#include "cds_api.h" +#include "qdf_nbuf.h" +#include "csr_api.h" +#include "sap_api.h" +#include "ol_txrx_osif_api.h" + +/* 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 +}; + +struct txrx_rx_metainfo { + u8 up; + u16 dest_staid; +}; + +enum bt_frame_type { + /* BT-AMP packet of type data */ + TXRX_BT_AMP_TYPE_DATA = 0x0001, + + /* BT-AMP packet of type activity report */ + TXRX_BT_AMP_TYPE_AR = 0x0002, + + /* BT-AMP packet of type security frame */ + TXRX_BT_AMP_TYPE_SEC = 0x0003, + + /* BT-AMP packet of type Link Supervision request frame */ + TXRX_BT_AMP_TYPE_LS_REQ = 0x0004, + + /* BT-AMP packet of type Link Supervision reply frame */ + TXRX_BT_AMP_TYPE_LS_REP = 0x0005, + + /* Invalid Frame */ + TXRX_BAP_INVALID_FRAME +}; + +enum wlan_ts_direction { + /* uplink */ + WLAN_TX_DIR = 0, + + /* downlink */ + WLAN_RX_DIR = 1, + + /*bidirectional */ + WLAN_BI_DIR = 2, +}; + +enum wlan_sta_state { + /* Transition in this state made upon creation */ + WLAN_STA_INIT = 0, + + /* + * Transition happens after Assoc success if second level authentication + * is needed + */ + WLAN_STA_CONNECTED, + + /* + * Transition happens when second level auth is successful and keys are + * properly installed + */ + WLAN_STA_AUTHENTICATED, + + /* Transition happens when connectivity is lost */ + WLAN_STA_DISCONNECTED, + + WLAN_STA_MAX_STATE +}; + +struct wlan_txrx_stats { + /* Define various txrx stats here */ +}; + +struct ol_txrx_vdev_t; + +QDF_STATUS wlan_register_mgmt_client(void *pdev_txrx, + QDF_STATUS (*rx_mgmt)(void *g_cdsctx, + void *buf)); + +/* If RSSI realm is changed, send notification to Clients, SME, HDD */ +typedef QDF_STATUS (*wlan_txrx_rssi_cross_thresh)(void *adapter, u8 rssi, + void *usr_ctx, + int8_t avg_rssi); + +/* Rx callback registered with txrx */ +typedef int (*wlan_txrx_cb_type)(void *g_cdsctx, qdf_nbuf_t buf, u8 sta_id, + struct txrx_rx_metainfo *rx_meta_info); + +static inline int wlan_txrx_get_rssi(void *g_cdsctx, u8 sta_id, int8_t *rssi) +{ + return 0; +} + +static inline int wlan_txrx_enable_uapsd_ac(void *g_cdsctx, u8 sta_id, + enum txrx_wmm_ac ac, u8 tid, u8 up, + u32 srv_int, u32 suspend_int, + enum wlan_ts_direction ts_dir) +{ + return 0; +} + +static inline int wlan_txrx_disable_uapsd_ac(void *g_cdsctx, u8 sta_id, + enum txrx_wmm_ac ac) +{ + return 0; +} + +static inline int wlan_change_sta_state(void *g_cdsctx, u8 sta_id, + enum wlan_sta_state state) +{ + return 0; +} + +static inline int wlan_deregister_mgmt_client(void *g_cdsctx) +{ + return 0; +} + +static inline void wlan_assoc_failed(u8 staid) +{ +} + +static inline int wlan_get_ap_stats(void *g_cdsctx, tSap_SoftapStats *buf, + bool reset) +{ + return 0; +} + +static inline int wlan_get_txrx_stats(void *g_cdsctx, + struct wlan_txrx_stats *stats, u8 sta_id) +{ + return 0; +} + +static inline int wlan_txrx_update_rssi_bmps(void *g_cdsctx, u8 sta_id, + int8_t rssi) +{ + return 0; +} + +static inline int wlan_txrx_deregister_rssi_indcb(void *g_cdsctx, + int8_t rssi_val, + u8 trigger_event, + wlan_txrx_rssi_cross_thresh + cb, int mod_id) +{ + return 0; +} + +static inline int wlan_txrx_register_rssi_indcb(void *g_cdsctx, + int8_t rssi_val, + u8 trigger_event, + wlan_txrx_rssi_cross_thresh cb, + int mod_id, void *usr_ctx) +{ + return 0; +} + +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event.h b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event.h new file mode 100644 index 0000000000000000000000000000000000000000..6c97260bbcde087e07a85d01561a034076bea54a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event.h @@ -0,0 +1,93 @@ +/* + * 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 _WDI_EVENT_H_ +#define _WDI_EVENT_H_ + +#include "athdefs.h" +#include "qdf_nbuf.h" +#define WDI_EVENT_BASE 0x100 /* Event starting number */ + +#define WDI_NO_VAL (-1) +enum WDI_EVENT { + WDI_EVENT_TX_STATUS = WDI_EVENT_BASE, + WDI_EVENT_RX_DESC, + WDI_EVENT_RX_DESC_REMOTE, + WDI_EVENT_RATE_FIND, + WDI_EVENT_RATE_UPDATE, + WDI_EVENT_SW_EVENT, + WDI_EVENT_RX_PEER_INVALID, + /* From WIN definations */ + WDI_EVENT_LITE_RX, + WDI_EVENT_LITE_T2H, + /* End of new event items */ + + WDI_EVENT_LAST +}; + +struct wdi_event_rx_peer_invalid_msg { + qdf_nbuf_t msdu; + struct ieee80211_frame *wh; + uint8_t vdev_id; +}; + +#define WDI_NUM_EVENTS (WDI_EVENT_LAST - WDI_EVENT_BASE) + +#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/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event_api.h b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event_api.h new file mode 100644 index 0000000000000000000000000000000000000000..3997d076dd0b00dcd266080311adc45882e72a85 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event_api.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#ifndef _WDI_EVENT_API_H_ +#define _WDI_EVENT_API_H_ + +#include "wdi_event.h" +#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 pdev - the event physical device, that maintains the event lists + * @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_pdev *ppdev, + void *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 pdev - the event physical device with the list of event subscribers + * @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_pdev *ppdev, + void *event_cb_sub, + uint32_t event); + + +void wdi_event_handler(enum WDI_EVENT event, + struct cdp_pdev *txrx_pdev, 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, + struct cdp_pdev *txrx_pdev, 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_pdev *ppdev, void *event_cb_sub, + uint32_t event) +{ + return 0; +} + +static inline int wdi_event_unsub(struct cdp_pdev *ppdev, + void *event_cb_sub, + uint32_t event) +{ + return 0; +} +#endif /* WDI_EVENT_ENABLE */ + +#endif /* _WDI_EVENT_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h b/drivers/staging/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..753d8999036a39fe4b36628c9f3880f18dec6e3a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h @@ -0,0 +1,241 @@ +/* + * 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 _QC_SAP_IOCTL_H_ +#define _QC_SAP_IOCTL_H_ + +/* + * QCSAP ioctls. + */ + +#define QCSAP_ADDR_LEN 6 + +typedef uint8_t qcmacaddr[QCSAP_ADDR_LEN]; + +/* + * Channel List Info + */ + +struct channel_list_info { + uint8_t num_channels; + uint8_t channels[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +}; + +#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 +#define QCSAP_IOCTL_CLR_STATS (SIOCIWFIRSTPRIV + 14) + +#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_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_INI_CFG (SIOCIWFIRSTPRIV + 26) +#define QCSAP_IOCTL_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) +#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 MAX_VAR_ARGS 7 +#define QCSAP_IOCTL_PRIV_GET_RSSI (SIOCIWFIRSTPRIV + 29) +#define QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED (SIOCIWFIRSTPRIV + 31) + +#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) + +/* + * + * 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, + QCASAP_PARAM_DCM, + QCASAP_PARAM_RANGE_EXT, + QCSAP_SET_DEFAULT_AMPDU, + QCSAP_ENABLE_RTS_BURSTING, + QCASAP_SET_HE_BSS_COLOR, +}; + +int iw_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +#endif /* __linux__ */ + +#endif /*_QC_SAP_IOCTL_H_*/ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_apf.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_apf.h new file mode 100644 index 0000000000000000000000000000000000000000..eeee39294123176a4ebf8bf4b2051870a5332de2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_apf.h @@ -0,0 +1,104 @@ +/* + * 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. + */ + +/* + * 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" + +#define APF_CONTEXT_MAGIC 0x4575354 + +#define MAX_APF_MEMORY_LEN 4096 + +/* APF commands wait times in msec */ +#define WLAN_WAIT_TIME_APF_GET_CAPS 1000 +#define WLAN_WAIT_TIME_APF_READ_MEM 10000 + +/** + * 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 + * @apf_get_offload: struct for get offload + * + * 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 */ + +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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h new file mode 100644 index 0000000000000000000000000000000000000000..7072a1586e3a26e987ae0f7445e28f37a8867add --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h @@ -0,0 +1,459 @@ +/* + * 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. + */ + +#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 + +/* Preprocessor Definitions and Constants */ +#ifdef FEATURE_WLAN_TDLS +#define HDD_MAX_NUM_TDLS_STA 8 +#define HDD_MAX_NUM_TDLS_STA_P_UAPSD_OFFCHAN 1 +#define TDLS_STA_INDEX_VALID(staId) \ + (((staId) >= 0) && ((staId) < 0xFF)) +#else +#define HDD_MAX_NUM_TDLS_STA 0 + +#endif +/* Timeout (in ms) for Link to Up before Registering Station */ +#define ASSOC_LINKUP_TIMEOUT 60 + +/* Timeout in ms for peer info request commpletion */ +#define IBSS_PEER_INFO_REQ_TIMOEUT 1000 + +#define INVALID_PEER_IDX -1 + +/** + * enum eConnectionState - connection state values at HDD + * @eConnectionState_NotConnected: Not associated in Infra or participating in + * in an IBSS / Ad-hoc network + * @eConnectionState_Connecting: While connection in progress + * @eConnectionState_Associated: Associated in an Infrastructure network + * @eConnectionState_IbssDisconnected: Participating in an IBSS network though + * disconnected (no partner stations in the IBSS) + * @eConnectionState_IbssConnected: Participating in an IBSS network with + * partner stations also present + * @eConnectionState_Disconnecting: Disconnecting in an Infrastructure network. + * @eConnectionState_NdiDisconnected: NDI in disconnected state - no peers + * @eConnectionState_NdiConnected: NDI in connected state - at least one peer + */ +typedef enum { + eConnectionState_NotConnected, + eConnectionState_Connecting, + eConnectionState_Associated, + eConnectionState_IbssDisconnected, + eConnectionState_IbssConnected, + eConnectionState_Disconnecting, + 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 + * @hs20_present: hs20 element present or not + * @ht_op_present: ht operation present or not + * @vht_op_present: vht operation present or not + */ +struct hdd_conn_flag { + uint8_t ht_present:1; + uint8_t vht_present:1; + uint8_t hs20_present:1; + uint8_t ht_op_present:1; + uint8_t vht_op_present:1; + uint8_t reserved:3; +}; + +/*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 + * @connState: connection state of the NIC + * @bssId: BSSID + * @SSID: SSID Info + * @staId: Station ID + * @peerMacAddress:Peer Mac Address of the IBSS Stations + * @authType: Auth Type + * @ucEncryptionType: Unicast Encryption Type + * @mcEncryptionType: Multicast Encryption Type + * @Keys: Keys + * @operationChannel: Operation Channel + * @uIsAuthenticated: Remembers authenticated state + * @dot11Mode: dot11Mode + * @proxyARPService: 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 + * @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 + * @hs20vendor_ie: holds passpoint/hs20 info + * @conn_flag: flag conn info params is present or not + * @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 + */ +struct hdd_connection_info { + eConnectionState connState; + struct qdf_mac_addr bssId; + tCsrSSIDInfo SSID; + uint8_t staId[MAX_PEERS]; + struct qdf_mac_addr peerMacAddress[MAX_PEERS]; + eCsrAuthType authType; + eCsrEncryptionType ucEncryptionType; + eCsrEncryptionType mcEncryptionType; + tCsrKeys Keys; + uint8_t operationChannel; + uint8_t uIsAuthenticated; + uint32_t dot11Mode; + uint8_t proxyARPService; + bool ptk_installed; + bool gtk_installed; + uint8_t nss; + uint32_t rate_flags; + uint32_t 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; + uint32_t roam_count; + int8_t signal; + int32_t assoc_status_code; + uint32_t cca; + tCsrSSIDInfo last_ssid; + eCsrAuthType last_auth_type; + char auth_time[HDD_TIME_STRING_LEN]; + char connect_time[HDD_TIME_STRING_LEN]; + enum phy_ch_width ch_width; +}; + +/* Forward declarations */ +struct hdd_adapter; +struct hdd_station_ctx; +struct hdd_context; + +/** + * hdd_is_connecting() - Function to check connection progress + * @hdd_sta_ctx: pointer to global HDD Station context + * + * Return: true if connecting, false otherwise + */ +bool hdd_is_connecting(struct hdd_station_ctx *hdd_sta_ctx); + +/* + * hdd_is_fils_connection: API to determine if connection is FILS + * @adapter: hdd adapter + * + * Return: true if fils connection else false + */ +bool hdd_is_fils_connection(struct hdd_adapter *adapter); + +/** + * hdd_conn_is_connected() - Function to check connection status + * @sta_ctx: pointer to global HDD Station context + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_conn_is_connected(struct hdd_station_ctx *sta_ctx); + +/** + * hdd_adapter_is_connected_sta() - check if @adapter is a connected station + * @adapter: the adapter to check + * + * Return: true if @adapter is a connected station + */ +bool hdd_adapter_is_connected_sta(struct hdd_adapter *adapter); + +/** + * hdd_conn_get_connected_band() - get current connection radio band + * @sta_ctx: pointer to global HDD Station context + * + * 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 hdd_station_ctx *sta_ctx); + +/** + * hdd_get_sta_connection_in_progress() - get STA for which connection + * is in progress + * @hdd_ctx: hdd context + * + * Return: hdd adpater for which connection is in progress + */ +struct hdd_adapter *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_sme_roam_callback() - hdd sme roam callback + * @pContext: pointer to adapter context + * @roam_info: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_sme_roam_callback(void *pContext, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult); + +/** + * hdd_set_genie_to_csr() - set genie to csr + * @adapter: pointer to adapter + * @RSNAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_genie_to_csr(struct hdd_adapter *adapter, + eCsrAuthType *RSNAuthType); + +/** + * hdd_set_csr_auth_type() - set csr auth type + * @adapter: pointer to adapter + * @RSNAuthType: auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_csr_auth_type(struct hdd_adapter *adapter, + eCsrAuthType RSNAuthType); + +#ifdef FEATURE_WLAN_TDLS +/** + * hdd_roam_register_tdlssta() - register new TDLS station + * @adapter: pointer to adapter + * @peerMac: pointer to peer MAC address + * @staId: station identifier + * @qos: Quality of service + * + * Construct the staDesc 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, uint16_t staId, + uint8_t qos); +#endif + +QDF_STATUS hdd_roam_deregister_tdlssta(struct hdd_adapter *adapter, + uint8_t staId); + +/** + * hdd_perform_roam_set_key_complete() - perform set key complete + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_perform_roam_set_key_complete(struct hdd_adapter *adapter); + +#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 */ + +QDF_STATUS hdd_change_peer_state(struct hdd_adapter *adapter, + uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +bool hdd_is_roam_sync_in_progress(struct csr_roam_info *roaminfo); +#else +static inline bool hdd_is_roam_sync_in_progress(struct csr_roam_info *roaminfo) +{ + return false; +} +#endif + +QDF_STATUS hdd_update_dp_vdev_flags(void *cbk_data, + uint8_t sta_id, + uint32_t vdev_param, + bool is_link_up); + +QDF_STATUS hdd_roam_register_sta(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint8_t sta_id, + struct qdf_mac_addr *peer_mac_addr, + struct bss_description *bss_desc); + +bool hdd_save_peer(struct hdd_station_ctx *sta_ctx, uint8_t sta_id, + struct qdf_mac_addr *peer_mac_addr); +void hdd_delete_peer(struct hdd_station_ctx *sta_ctx, uint8_t sta_id); +QDF_STATUS hdd_roam_deregister_sta(struct hdd_adapter *adapter, uint8_t sta_id); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter, + const tSirMacAddr bssid, int channel); +/** + * hdd_save_gtk_params() - Save GTK offload params + * @adapter: HDD adapter + * @csr_roam_info: CSR roam info + * @is_reassoc: boolean to indicate roaming + * + * Return: None + */ +void hdd_save_gtk_params(struct hdd_adapter *adapter, + struct csr_roam_info *csr_roam_info, bool is_reassoc); +#else +static inline QDF_STATUS +hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter, + const tSirMacAddr bssid, int channel) +{ + return QDF_STATUS_SUCCESS; +} +static inline void hdd_save_gtk_params(struct hdd_adapter *adapter, + struct csr_roam_info *csr_roam_info, + bool is_reassoc) +{ +} +#endif + +/** + * 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_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 + * @adapter: The HDD adapter being initialized + * + * This function initializes the roam profile that is embedded within + * the adapter. + * + * Return: void + */ +void hdd_roam_profile_init(struct hdd_adapter *adapter); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..c4de89870d58ffe2a62dde6958ae85edc7751384 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h @@ -0,0 +1,17331 @@ +/* + * 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. + */ + +#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 "osapi_linux.h" +#include +#include "wlan_pmo_hw_filter_public_struct.h" +#include "wlan_action_oui_public_struct.h" +#include "wlan_hdd_green_ap_cfg.h" + +struct hdd_context; + +#define FW_MODULE_LOG_LEVEL_STRING_LENGTH (512) +#define TX_SCHED_WRR_PARAM_STRING_LENGTH (50) +#define TX_SCHED_WRR_PARAMS_NUM (5) +#define CFG_ENABLE_RX_THREAD (1 << 0) +#define CFG_ENABLE_RPS (1 << 1) +#define CFG_ENABLE_NAPI (1 << 2) +#define CFG_ENABLE_DYNAMIC_RPS (1 << 3) + +#ifdef DHCP_SERVER_OFFLOAD +#define IPADDR_NUM_ENTRIES (4) +#define IPADDR_STRING_LENGTH (16) +#endif + +#define CFG_DBS_SCAN_PARAM_LENGTH (42) + +/* Number of items that can be configured */ +#define MAX_CFG_INI_ITEMS 1024 + +#define MAX_PRB_REQ_VENDOR_OUI_INI_LEN 160 +#define VENDOR_SPECIFIC_IE_BITMAP 0x20000000 + +#define CFG_CONCURRENT_IFACE_MAX_LEN 16 + +/* Defines for all of the things we read from the configuration (registry). */ +/* + * + * gEnableConnectedScan - Will enable or disable scan in connected state + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable the scanning in + * Connected state + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_CONNECTED_SCAN_NAME "gEnableConnectedScan" +#define CFG_ENABLE_CONNECTED_SCAN_MIN (0) +#define CFG_ENABLE_CONNECTED_SCAN_MAX (1) +#define CFG_ENABLE_CONNECTED_SCAN_DEFAULT (1) + +#ifdef WLAN_NUD_TRACKING +/* + * + * gEnableNUDTracking - Will enable or disable NUD tracking within driver + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable NUD tracking within driver + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_NUD_TRACKING_NAME "gEnableNUDTracking" +#define CFG_ENABLE_NUD_TRACKING_MIN (0) +#define CFG_ENABLE_NUD_TRACKING_MAX (1) +#define CFG_ENABLE_NUD_TRACKING_DEFAULT (1) +#endif + +/* + * + * RTSThreshold - Will provide RTSThreshold + * @Min: 0 + * @Max: 1048576 + * @Default: 2347 + * + * This ini is used to set default RTSThreshold + * If minimum value 0 is selectd then it will use always RTS + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RTS_THRESHOLD_NAME "RTSThreshold" +#define CFG_RTS_THRESHOLD_MIN WNI_CFG_RTS_THRESHOLD_STAMIN /* min is 0, meaning always use RTS. */ +#define CFG_RTS_THRESHOLD_MAX WNI_CFG_RTS_THRESHOLD_STAMAX /* max is the max frame size */ +#define CFG_RTS_THRESHOLD_DEFAULT WNI_CFG_RTS_THRESHOLD_STADEF + +/* + * + * 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_NAME "gFragmentationThreshold" +#define CFG_FRAG_THRESHOLD_MIN WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN +#define CFG_FRAG_THRESHOLD_MAX WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX +#define CFG_FRAG_THRESHOLD_DEFAULT WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF + +#define CFG_OPERATING_CHANNEL_NAME "gOperatingChannel" +#define CFG_OPERATING_CHANNEL_MIN (0) +#define CFG_OPERATING_CHANNEL_MAX (14) +#define CFG_OPERATING_CHANNEL_DEFAULT (1) + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_SHORT_SLOT_TIME_ENABLED_NAME "gShortSlotTimeEnabled" +#define CFG_SHORT_SLOT_TIME_ENABLED_MIN WNI_CFG_SHORT_SLOT_TIME_STAMIN +#define CFG_SHORT_SLOT_TIME_ENABLED_MAX WNI_CFG_SHORT_SLOT_TIME_STAMAX +#define CFG_SHORT_SLOT_TIME_ENABLED_DEFAULT WNI_CFG_SHORT_SLOT_TIME_STADEF + +#define CFG_11D_SUPPORT_ENABLED_NAME "g11dSupportEnabled" +#define CFG_11D_SUPPORT_ENABLED_MIN WNI_CFG_11D_ENABLED_STAMIN +#define CFG_11D_SUPPORT_ENABLED_MAX WNI_CFG_11D_ENABLED_STAMAX +#define CFG_11D_SUPPORT_ENABLED_DEFAULT WNI_CFG_11D_ENABLED_STADEF /* Default is ON */ + +/* + * + * 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_NAME "enable_11d_in_world_mode" + #define CFG_ENABLE_11D_IN_WORLD_MODE_MIN (0) + #define CFG_ENABLE_11D_IN_WORLD_MODE_MAX (1) + #define CFG_ENABLE_11D_IN_WORLD_MODE_DEFAULT (0) + +#define CFG_11H_SUPPORT_ENABLED_NAME "g11hSupportEnabled" +#define CFG_11H_SUPPORT_ENABLED_MIN (0) +#define CFG_11H_SUPPORT_ENABLED_MAX (1) +#define CFG_11H_SUPPORT_ENABLED_DEFAULT (1) /* Default is ON */ + +/* COUNTRY Code Priority */ +#define CFG_COUNTRY_CODE_PRIORITY_NAME "gCountryCodePriority" +#define CFG_COUNTRY_CODE_PRIORITY_MIN (0) +#define CFG_COUNTRY_CODE_PRIORITY_MAX (1) +#define CFG_COUNTRY_CODE_PRIORITY_DEFAULT (0) + +#define CFG_HEARTBEAT_THRESH_24_NAME "gHeartbeat24" +#define CFG_HEARTBEAT_THRESH_24_MIN WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN +#define CFG_HEARTBEAT_THRESH_24_MAX WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX +#define CFG_HEARTBEAT_THRESH_24_DEFAULT WNI_CFG_HEART_BEAT_THRESHOLD_STADEF + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_MAX_RX_AMPDU_FACTOR_NAME "gMaxRxAmpduFactor" +#define CFG_MAX_RX_AMPDU_FACTOR_MIN WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN +#define CFG_MAX_RX_AMPDU_FACTOR_MAX WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX +#define CFG_MAX_RX_AMPDU_FACTOR_DEFAULT WNI_CFG_MAX_RX_AMPDU_FACTOR_STADEF + +/* Configuration option for HT MPDU density (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_HT_MPDU_DENSITY_NAME "ght_mpdu_density" +#define CFG_HT_MPDU_DENSITY_MIN WNI_CFG_MPDU_DENSITY_STAMIN +#define CFG_HT_MPDU_DENSITY_MAX WNI_CFG_MPDU_DENSITY_STAMAX +#define CFG_HT_MPDU_DENSITY_DEFAULT WNI_CFG_MPDU_DENSITY_STADEF + +#define CFG_REG_CHANGE_DEF_COUNTRY_NAME "gRegulatoryChangeCountry" +#define CFG_REG_CHANGE_DEF_COUNTRY_DEFAULT (0) +#define CFG_REG_CHANGE_DEF_COUNTRY_MIN (0) +#define CFG_REG_CHANGE_DEF_COUNTRY_MAX (1) + +#define CFG_ADVERTISE_CONCURRENT_OPERATION_NAME "gAdvertiseConcurrentOperation" +#define CFG_ADVERTISE_CONCURRENT_OPERATION_DEFAULT (1) +#define CFG_ADVERTISE_CONCURRENT_OPERATION_MIN (0) +#define CFG_ADVERTISE_CONCURRENT_OPERATION_MAX (1) + +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, +}; + +/* + * + * gChannelBondingMode24GHz - Configures Channel Bonding in 24 GHz + * @Min: 0 + * @Max: 10 + * @Default: 1 + * + * This ini is used to set default channel bonding mode 24GHZ + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_CHANNEL_BONDING_MODE_24GHZ_NAME "gChannelBondingMode24GHz" +#define CFG_CHANNEL_BONDING_MODE_MIN WNI_CFG_CHANNEL_BONDING_MODE_STAMIN +#define CFG_CHANNEL_BONDING_MODE_MAX WNI_CFG_CHANNEL_BONDING_MODE_STAMAX +#define CFG_CHANNEL_BONDING_MODE_DEFAULT WNI_CFG_CHANNEL_BONDING_MODE_STADEF + +/* + * + * override_ht20_40_24g - use channel Bonding in 24 GHz from supplicant + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to use channel Bonding in 24 GHz from supplicant if + * gChannelBondingMode24GHz is set + * + * Related: gChannelBondingMode24GHz + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_OVERRIDE_HT40_20_24GHZ_NAME "override_ht20_40_24g" +#define CFG_OVERRIDE_HT40_20_24GHZ_MIN 0 +#define CFG_OVERRIDE_HT40_20_24GHZ_MAX 1 +#define CFG_OVERRIDE_HT40_20_24GHZ_DEFAULT 0 + +/* + * + * gChannelBondingMode5GHz - Configures Channel Bonding in 5 GHz + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to set default channel bonding mode 5GHZ + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_CHANNEL_BONDING_MODE_5GHZ_NAME "gChannelBondingMode5GHz" +#define CFG_CHANNEL_BONDING_MODE_MIN WNI_CFG_CHANNEL_BONDING_MODE_STAMIN +#define CFG_CHANNEL_BONDING_MODE_MAX WNI_CFG_CHANNEL_BONDING_MODE_STAMAX +#define CFG_CHANNEL_BONDING_MODE_DEFAULT WNI_CFG_CHANNEL_BONDING_MODE_STADEF + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_SHORT_GI_20MHZ_NAME "gShortGI20Mhz" +#define CFG_SHORT_GI_20MHZ_MIN WNI_CFG_SHORT_GI_20MHZ_STAMIN +#define CFG_SHORT_GI_20MHZ_MAX WNI_CFG_SHORT_GI_20MHZ_STAMAX +#define CFG_SHORT_GI_20MHZ_DEFAULT WNI_CFG_SHORT_GI_20MHZ_STADEF + +/* + * + * gScanResultAgeCount - Set scan result age count + * @Min: 1 + * @Max: 100 + * @Default: 1 + * + * This ini parameter is the number of times a scan + * doesn't find it before it is removed from results. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_RESULT_AGE_COUNT_NAME "gScanResultAgeCount" +#define CFG_SCAN_RESULT_AGE_COUNT_MIN (1) +#define CFG_SCAN_RESULT_AGE_COUNT_MAX (100) +#define CFG_SCAN_RESULT_AGE_COUNT_DEFAULT (1) + +/* + * + * gNeighborScanTimerPeriod - Set neighbor scan timer period + * @Min: 3 + * @Max: 300 + * @Default: 200 + * + * This ini is used to set the timer period in secs after + * which neighbor scan is trigerred. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_NAME "gNeighborScanTimerPeriod" +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN (3) +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX (300) +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT (100) + +/* + * + * gRoamRestTimeMin - Set min neighbor scan timer period + * @Min: 3 + * @Max: 300 + * @Default: 200 + * + * 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_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_NAME "gRoamRestTimeMin" +#define CFG_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_MIN (3) +#define CFG_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_MAX (300) +#define CFG_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_DEFAULT (50) + +/* + * + * 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_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_NAME "gOpportunisticThresholdDiff" +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MIN (0) +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MAX (127) +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT (0) + +/* + * + * 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_NEIGHBOR_SCAN_CHAN_LIST_NAME "gNeighborScanChannelList" +#define CFG_NEIGHBOR_SCAN_CHAN_LIST_DEFAULT "" + +/* + * + * 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_NEIGHBOR_SCAN_MIN_CHAN_TIME_NAME "gNeighborScanChannelMinTime" +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN (10) +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX (40) +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT (20) + +/* + * + * gNeighborScanChannelMaxTime - 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_NEIGHBOR_SCAN_MAX_CHAN_TIME_NAME "gNeighborScanChannelMaxTime" +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN (3) +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX (300) +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT (40) + +/* + * + * 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_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_NAME "gNeighborScanRefreshPeriod" +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN (1000) +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX (60000) +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT (20000) + +/* + * + * 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_EMPTY_SCAN_REFRESH_PERIOD_NAME "gEmptyScanRefreshPeriod" +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN (0) +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX (60000) +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT (0) + +/* + * + * gEnableDFSChnlScan - Enable DFS channel scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable DFS channel + * scan + */ +#define CFG_ENABLE_DFS_CHNL_SCAN_NAME "gEnableDFSChnlScan" +#define CFG_ENABLE_DFS_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_CHNL_SCAN_DEFAULT (1) + +/* + * + * honour_nl_scan_policy_flags - Whether to honour NL80211 scan policy flags + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This parameter will decide whether to honour scan flags such as + * NL80211_SCAN_FLAG_HIGH_ACCURACY , NL80211_SCAN_FLAG_LOW_SPAN, + * NL80211_SCAN_FLAG_LOW_POWER. + * Acceptable values for this: + * 0: Config is disabled + * 1: Config is enabled + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + * + */ +#define CFG_HONOUR_NL_SCAN_POLICY_FLAGS "honour_nl_scan_policy_flags" +#define CFG_HONOUR_NL_SCAN_POLICY_FLAGS_MIN (0) +#define CFG_HONOUR_NL_SCAN_POLICY_FLAGS_MAX (1) +#define CFG_HONOUR_NL_SCAN_POLICY_FLAGS_DEFAULT (1) + +/* + * + * wake_lock_in_user_scan - use wake lock during user scan + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to define if wake lock is held used during user scan req + * + * Related: Scan + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_WAKE_LOCK_IN_SCAN "wake_lock_in_user_scan" +#define CFG_ENABLE_WAKE_LOCK_IN_SCAN_MIN (0) +#define CFG_ENABLE_WAKE_LOCK_IN_SCAN_MAX (1) +#define CFG_ENABLE_WAKE_LOCK_IN_SCAN_DEFAULT (0) + + + +/* + * + * 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_NAME "pmkidModes" +#define CFG_PMKID_MODES_MIN (0x0) +#define CFG_PMKID_MODES_MAX (0x3) +#define CFG_PMKID_MODES_DEFAULT (0x3) +#define CFG_PMKID_MODES_OKC (0x1) +#define CFG_PMKID_MODES_PMKSA_CACHING (0x2) + +/* + * + * gEnableDFSPnoChnlScan - enable dfs channels in PNO scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable dfs channels in PNO scan request, + * enabling this ini enables driver to include dfs channels in its + * PNO scan request + * Related: NA + * + * Supported Feature: DFS, PNO + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_NAME "gEnableDFSPnoChnlScan" +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_DEFAULT (1) + +/* + * + * gEnableFirstScan2GOnly - Enable first scan 2G only + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to scan 2G channels only in first scan. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_NAME "gEnableFirstScan2GOnly" +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_MIN (0) +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_MAX (1) +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_DEFAULT (0) + +/* + * + * gScanAgingTime - Set scan aging time + * @Min: 0 + * @Max: 200 + * @Default: 30 + * + * This ini is used to set scan aging timeout value + * in secs. For example after 30 secs the bss results + * greater than 30secs age will be flushed. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_AGING_PARAM_NAME "gScanAgingTime" +#define CFG_SCAN_AGING_PARAM_MIN (0) +#define CFG_SCAN_AGING_PARAM_MAX (200) +#ifdef QCA_WIFI_NAPIER_EMULATION +#define CFG_SCAN_AGING_PARAM_DEFAULT (90) +#else +#define CFG_SCAN_AGING_PARAM_DEFAULT (30) +#endif + +#ifdef FEATURE_WLAN_SCAN_PNO +/* + * + * gPNOScanSupport - Enable or Disable PNO scan + * @Min: 1 + * @Max: 0 + * @Default: 1 + * + * This ini is used to Enable or Disable PNO scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PNO_SCAN_SUPPORT "gPNOScanSupport" +#define CFG_PNO_SCAN_SUPPORT_ENABLE (1) +#define CFG_PNO_SCAN_SUPPORT_DISABLE (0) +#define CFG_PNO_SCAN_SUPPORT_DEFAULT (1) + +/* + * + * gPNOScanTimerRepeatValue - Set PNO scan timer repeat value + * @Min: 30 + * @Max: 0 + * @Default: 0xffffffff + * + * This ini is used by firmware to set fast scan max cycles + * equal to gPNOScanTimerRepeatValue. Taking power consumption + * into account firmware after gPNOScanTimerRepeatValue times + * fast_scan_period switches to slow_scan_period. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE "gPNOScanTimerRepeatValue" +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_DEFAULT (30) +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MIN (0) +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MAX (0xffffffff) + +/* + * + * gPNOSlowScanMultiplier - Set PNO slow scan multiplier + * @Min: 6 + * @Max: 0 + * @Default: 30 + * + * This ini is used by firmware to set slow scan period + * as gPNOSlowScanMultiplier times fast_scan_period. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PNO_SLOW_SCAN_MULTIPLIER "gPNOSlowScanMultiplier" +#define CFG_PNO_SLOW_SCAN_MULTIPLIER_DEFAULT (6) +#define CFG_PNO_SLOW_SCAN_MULTIPLIER_MIN (0) +#define CFG_PNO_SLOW_SCAN_MULTIPLIER_MAX (30) +#endif + +/* + * + * max_scan_count - Set maximum number of scans + * @Min: 1 + * @Max: 8 + * @Default: 4 + * + * This ini is used to set the maximum number of + * scans that host can queue at firmware. + * Rome firmware support 8 scan queue size and 4 + * are reserved for internal scan requests like + * roaming. So host can send 4 scan requests. + * In iHelium, there is no constraint in number of + * scan queue size at firmware but the current use + * cases needs support of maximum of 4 scan request + * from host. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_MAX_SCAN_COUNT_NAME "max_scan_count" +#define CFG_MAX_SCAN_COUNT_MIN (1) +#define CFG_MAX_SCAN_COUNT_MAX (8) +#define CFG_MAX_SCAN_COUNT_DEFAULT (4) + +/* + * + * drop_bcn_on_chan_mismatch - drop the beacon for chan mismatch + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to decide drop the beacon or not if channel received + * in metadata doesn't match the one in beacon. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DROP_BCN_ON_CHANNEL_MISMATCH "drop_bcn_on_chan_mismatch" +#define CFG_DROP_BCN_ON_CHANNEL_MISMATCH_MIN (0) +#define CFG_DROP_BCN_ON_CHANNEL_MISMATCH_MAX (1) +#define CFG_DROP_BCN_ON_CHANNEL_MISMATCH_DEFAULT (1) + +/* + * + * gPassiveMaxChannelTime - Set max channel time for passive scan + * @Min: 0 + * @Max: 10000 + * @Default: 110 + * + * This ini is used to set maximum channel time in secs spent in + * passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PASSIVE_MAX_CHANNEL_TIME_NAME "gPassiveMaxChannelTime" +#define CFG_PASSIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_MAX (10000) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_DEFAULT (110) + +/* + * + * gPassiveMinChannelTime - Set min channel time for passive scan + * @Min: 0 + * @Max: 10000 + * @Default: 60 + * + * This ini is used to set minimum channel time in secs spent in + * passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PASSIVE_MIN_CHANNEL_TIME_NAME "gPassiveMinChannelTime" +#define CFG_PASSIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_MAX (10000) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_DEFAULT (60) + +/* + * + * gActiveMaxChannelTime - Set max channel time for active scan + * @Min: 0 + * @Max: 10000 + * @Default: 40 + * + * This ini is used to set maximum channel time in secs spent in + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ACTIVE_MAX_CHANNEL_TIME_NAME "gActiveMaxChannelTime" +#define CFG_ACTIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_MAX (10000) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_DEFAULT (40) + +/* + * + * active_max_channel_time_2g - Set max time for active 2G channel scan + * @Min: 0 + * @Max: 10000 + * @Default: 80 + * + * This ini is used to set maximum time in msecs spent in active 2G channel scan + * if it's not zero, in case of zero, CFG_ACTIVE_MAX_CHANNEL_TIME is used for 2G + * channels also. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ACTIVE_MAX_2G_CHANNEL_TIME_NAME "active_max_channel_time_2g" +#define CFG_ACTIVE_MAX_2G_CHANNEL_TIME_MIN (0) +#define CFG_ACTIVE_MAX_2G_CHANNEL_TIME_MAX (10000) +#define CFG_ACTIVE_MAX_2G_CHANNEL_TIME_DEFAULT (80) + + +/* + * + * gActiveMinChannelTime - Set min channel time for active scan + * @Min: 0 + * @Max: 10000 + * @Default: 20 + * + * This ini is used to set minimum channel time in secs spent in + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ACTIVE_MIN_CHANNEL_TIME_NAME "gActiveMinChannelTime" +#define CFG_ACTIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_MAX (10000) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_DEFAULT (20) + +/* + * + * gScanNumProbes - Set the number of probes on each channel for active scan + * @Min: 0 + * @Max: 20 + * @Default: 0 + * + * This ini is used to set number of probes on each channel for + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_NUM_PROBES_NAME "gScanNumProbes" +#define CFG_SCAN_NUM_PROBES_MIN (0) +#define CFG_SCAN_NUM_PROBES_MAX (20) +#define CFG_SCAN_NUM_PROBES_DEFAULT (0) + +/* + * + * gScanProbeRepeatTime - Set the probe repeat time on each channel for active scan + * @Min: 0 + * @Max: 30 + * @Default: 0 + * + * This ini is used to set probe repeat time on each channel for + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_PROBE_REPEAT_TIME_NAME "gScanProbeRepeatTime" +#define CFG_SCAN_PROBE_REPEAT_TIME_MIN (0) +#define CFG_SCAN_PROBE_REPEAT_TIME_MAX (30) +#define CFG_SCAN_PROBE_REPEAT_TIME_DEFAULT (0) + +#ifdef FEATURE_WLAN_EXTSCAN +/* + * + * gExtScanEnable - Enable external scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to control enabling of external scan + * feature. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_ALLOWED_NAME "gExtScanEnable" +#define CFG_EXTSCAN_ALLOWED_MIN (0) +#define CFG_EXTSCAN_ALLOWED_MAX (1) +#define CFG_EXTSCAN_ALLOWED_DEF (1) + +/* + * + * gExtScanPassiveMaxChannelTime - Set max channel time for external + * passive scan + * @Min: 0 + * @Max: 500 + * @Default: 110 + * + * This ini is used to set maximum channel time in secs spent in + * external passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_NAME "gExtScanPassiveMaxChannelTime" +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MAX (500) +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_DEFAULT (110) + +/* + * + * gExtScanPassiveMinChannelTime - Set min channel time for external + * passive scan + * @Min: 0 + * @Max: 500 + * @Default: 60 + * + * This ini is used to set minimum channel time in secs spent in + * external passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_NAME "gExtScanPassiveMinChannelTime" +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MAX (500) +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_DEFAULT (60) + +/* + * + * gExtScanActiveMaxChannelTime - Set min channel time for external + * active scan + * @Min: 0 + * @Max: 110 + * @Default: 40 + * + * This ini is used to set maximum channel time in secs spent in + * external active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_NAME "gExtScanActiveMaxChannelTime" +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MAX (110) +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_DEFAULT (40) + +/* + * + * gExtScanActiveMinChannelTime - Set min channel time for external + * active scan + * @Min: 0 + * @Max: 110 + * @Default: 20 + * + * This ini is used to set minimum channel time in secs spent in + * external active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_NAME "gExtScanActiveMinChannelTime" +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MAX (110) +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_DEFAULT (20) +#endif + +/* + * + * gChPredictionFullScanMs - Set periodic timer for channel + * prediction + * @Min: 3000 + * @Max: 0x7fffffff + * @Default: 60000 + * + * This ini is used to set the periodic timer upon which + * a full scan needs to be triggered when PNO channel + * prediction feature is enabled. This parameter is intended + * to tweak the internal algortihm for experiments. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + * + */ +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME "gChPredictionFullScanMs" +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MIN (30000) +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MAX (0x7fffffff) +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_DEFAULT (60000) + +/* + * + * 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_EARLY_STOP_SCAN_ENABLE "gEnableEarlyStopScan" +#define CFG_EARLY_STOP_SCAN_ENABLE_MIN (0) +#define CFG_EARLY_STOP_SCAN_ENABLE_MAX (1) +#define CFG_EARLY_STOP_SCAN_ENABLE_DEFAULT (0) + +/* + * + * 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_EARLY_STOP_SCAN_MIN_THRESHOLD "gEarlyStopScanMinThreshold" +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MIN (-80) +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MAX (-70) +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_DEFAULT (-73) + +/* + * + * 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_EARLY_STOP_SCAN_MAX_THRESHOLD "gEarlyStopScanMaxThreshold" +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MIN (-60) +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MAX (-40) +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_DEFAULT (-43) + +/* + * + * gFirstScanBucketThreshold - Set first scan bucket + * threshold + * @Min: -50 + * @Max: -30 + * @Default: -30 + * + * This ini will configure the first scan bucket + * threshold to the mentioned value and all the AP's which + * have RSSI under this threshold will fall under this + * bucket. This configuration item used to tweak and + * test the input for internal algorithm. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + * + */ +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_NAME "gFirstScanBucketThreshold" +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_MIN (-50) +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_MAX (-30) +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_DEFAULT (-30) + +/* + * + * obss_active_dwelltime - Set obss active dwelltime + * @Min: 5 + * @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_NAME "obss_active_dwelltime" +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MIN (5) +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MAX (1000) +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_DEFAULT (10) + +/* + * + * obss_passive_dwelltime - Set obss passive dwelltime + * @Min: 10 + * @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_NAME "obss_passive_dwelltime" +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MIN (10) +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MAX (1000) +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_DEFAULT (20) + +/* + * + * 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. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_NAME "obss_width_trigger_interval" +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MIN (10) +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MAX (900) +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_DEFAULT (200) + +/* + * + * gbug_report_for_scan_results - Enable bug report + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to create bug report in + * case of nil scan results. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_CREATE_BUG_REPORT_FOR_SCAN "gbug_report_for_scan_results" +#define CFG_CREATE_BUG_REPORT_FOR_SCAN_DISABLE (0) +#define CFG_CREATE_BUG_REPORT_FOR_SCAN_ENABLE (1) +#define CFG_CREATE_BUG_REPORT_FOR_SCAN_DEFAULT (0) + +/* + * + * hostscan_adaptive_dwell_mode - Enable adaptive dwell mode + * during host scan with conneciton + * @Min: 0 + * @Max: 4 + * @Default: 2 + * + * This ini will set the algo used in dwell time optimization + * during host scan with connection. + * 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: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME "hostscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_DEFAULT (2) + +/* + * + * hostscan_adaptive_dwell_mode_no_conn - Enable adaptive dwell mode + * during host scan without connection + * @Min: 0 + * @Max: 4 + * @Default: 4 + * + * This ini will set the algo used in dwell time optimization + * during host scan without connection. + * 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: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_NAME "hostscan_adaptive_dwell_mode_no_conn" +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_MIN (0) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_MAX (4) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_DEFAULT (4) + +/* + * + * extscan_adaptive_dwell_mode - Enable adaptive dwell mode + * during ext scan + * @Min: 0 + * @Max: 4 + * @Default: 1 + * + * This ini will set the algo used in dwell time optimization + * during ext 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: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME "extscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_DEFAULT (1) + +/* + * + * pnoscan_adaptive_dwell_mode - Enable adaptive dwell mode + * during pno scan + * @Min: 0 + * @Max: 4 + * @Default: 1 + * + * This ini will set the algo used in dwell time optimization + * during pno 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: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME "pnoscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_DEFAULT (1) + +/* + * + * adaptive_dwell_mode_enabled - Enable adaptive dwell mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This parameter 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_NAME "adaptive_dwell_mode_enabled" +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_MIN (0) +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_MAX (1) +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_DEFAULT (1) + +/* + * + * global_adapt_dwelltime_mode - Set default adaptive mode + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This parameter 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_NAME "global_adapt_dwelltime_mode" +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MIN (0) +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MAX (4) +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_DEFAULT (0) + +/* + * + * gRssiCatGap - Set Rssi CatGap + * @Min: 5 + * @Max: 100 + * @Default: 5 + * + * This ini is used to set default RssiCatGap + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RSSI_CATEGORY_GAP_NAME "gRssiCatGap" +#define CFG_RSSI_CATEGORY_GAP_MIN (5) +#define CFG_RSSI_CATEGORY_GAP_MAX (100) +#define CFG_RSSI_CATEGORY_GAP_DEFAULT (5) + +/* + * + * 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_ROAM_PREFER_5GHZ "gRoamPrefer5GHz" +#define CFG_ROAM_PREFER_5GHZ_MIN (0) +#define CFG_ROAM_PREFER_5GHZ_MAX (1) +#define CFG_ROAM_PREFER_5GHZ_DEFAULT (1) + +/* + * + * 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_ROAM_INTRA_BAND "gRoamIntraBand" +#define CFG_ROAM_INTRA_BAND_MIN (0) +#define CFG_ROAM_INTRA_BAND_MAX (1) +#define CFG_ROAM_INTRA_BAND_DEFAULT (0) + +/* + * + * FastRoamEnabled - Enable fast roaming + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to inform FW to enable fast roaming + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_FEATURE_ENABLED_NAME "FastRoamEnabled" +#define CFG_LFR_FEATURE_ENABLED_MIN (0) +#define CFG_LFR_FEATURE_ENABLED_MAX (1) +#define CFG_LFR_FEATURE_ENABLED_DEFAULT (0) + +/* + * + * 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_FAST_TRANSITION_ENABLED_NAME "FastTransitionEnabled" +#define CFG_FAST_TRANSITION_ENABLED_NAME_MIN (0) +#define CFG_FAST_TRANSITION_ENABLED_NAME_MAX (1) +#define CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT (1) + +/* + * + * RoamRssiDiff - Enable roam based on rssi + * @Min: 0 + * @Max: 30 + * @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_ROAM_RSSI_DIFF_NAME "RoamRssiDiff" +#define CFG_ROAM_RSSI_DIFF_MIN (0) +#define CFG_ROAM_RSSI_DIFF_MAX (30) +#define CFG_ROAM_RSSI_DIFF_DEFAULT (5) + +/* + * + * 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_ROAM_RSSI_ABS_THRESHOLD_NAME "rssi_abs_thresh" +#define CFG_ROAM_RSSI_ABS_THRESHOLD_MIN (-96) +#define CFG_ROAM_RSSI_ABS_THRESHOLD_MAX (0) +#define CFG_ROAM_RSSI_ABS_THRESHOLD_DEFAULT (0) + +/* + * + * 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_ROAM_SCAN_N_PROBES "gRoamScanNProbes" +#define CFG_ROAM_SCAN_N_PROBES_MIN (1) +#define CFG_ROAM_SCAN_N_PROBES_MAX (10) +#define CFG_ROAM_SCAN_N_PROBES_DEFAULT (2) + +/* + * + * gRoamScanHomeAwayTime - 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_ROAM_SCAN_HOME_AWAY_TIME "gRoamScanHomeAwayTime" +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN (0) +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX (300) +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT (0) + +/* + * + * 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_ROAM_SCAN_OFFLOAD_ENABLED "gRoamScanOffloadEnabled" +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_MIN (0) +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX (1) +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT (1) + +/* + * + * gRoamRescanRssiDiff - 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_ROAM_RESCAN_RSSI_DIFF_NAME "gRoamRescanRssiDiff" +#define CFG_ROAM_RESCAN_RSSI_DIFF_MIN (0) +#define CFG_ROAM_RESCAN_RSSI_DIFF_MAX (100) +#define CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT (5) + +/* + * + * gDroppedPktDisconnectTh - Sets dropped packet threshold in firmware + * @Min: 0 + * @Max: 512 + * @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_TH_NAME "gDroppedPktDisconnectTh" +#define CFG_DROPPED_PKT_DISCONNECT_TH_MIN (0) +#define CFG_DROPPED_PKT_DISCONNECT_TH_MAX (65535) +#define CFG_DROPPED_PKT_DISCONNECT_TH_DEFAULT (512) + +/* + * + * 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_NAME "gForce1x1Exception" +#define CFG_FORCE_1X1_MIN (0) +#define CFG_FORCE_1X1_MAX (2) +#define CFG_FORCE_1X1_DEFAULT (2) + +/* + * + * 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_NAME "g11bNumTxChains" +#define CFG_11B_NUM_TX_CHAIN_MIN (0) +#define CFG_11B_NUM_TX_CHAIN_MAX (2) +#define CFG_11B_NUM_TX_CHAIN_DEFAULT (0) + +/* + * + * 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_NAME "g11agNumTxChains" +#define CFG_11AG_NUM_TX_CHAIN_MIN (0) +#define CFG_11AG_NUM_TX_CHAIN_MAX (2) +#define CFG_11AG_NUM_TX_CHAIN_DEFAULT (0) + +/* + * + * 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_ENABLE_FAST_ROAM_IN_CONCURRENCY "gEnableFastRoamInConcurrency" +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MIN (0) +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MAX (1) +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_DEFAULT (1) + +/* + * + * 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_STRICT_5GHZ_PREF_BY_MARGIN "gSelect5GHzMargin" +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_MIN (0) +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_MAX (60) +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_DEFAULT (0) + +#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_ROAMING_OFFLOAD_NAME "gRoamOffloadEnabled" +#define CFG_ROAMING_OFFLOAD_MIN (0) +#define CFG_ROAMING_OFFLOAD_MAX (1) +#define CFG_ROAMING_OFFLOAD_DEFAULT (1) +#endif + +/* + * + * 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_ROAM_SCAN_HI_RSSI_MAXCOUNT_NAME "gRoamScanHiRssiMaxCount" +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MIN (0) +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MAX (10) +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_DEFAULT (3) + +/* + * + * gRoamScanHiRssiDelta - Sets RSSI Delta for scan trigger + * @Min: 0 + * @Max: 16 + * @Default: 10 + * + * 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_ROAM_SCAN_HI_RSSI_DELTA_NAME "gRoamScanHiRssiDelta" +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_MIN (0) +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_MAX (16) +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_DEFAULT (10) + +/* + * + * 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_ROAM_SCAN_HI_RSSI_DELAY_NAME "gRoamScanHiRssiDelay" +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_MIN (5000) +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_MAX (0x7fffffff) +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_DEFAULT (15000) + +/* + * + * 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_ROAM_SCAN_HI_RSSI_UB_NAME "gRoamScanHiRssiUpperBound" +#define CFG_ROAM_SCAN_HI_RSSI_UB_MIN (-66) +#define CFG_ROAM_SCAN_HI_RSSI_UB_MAX (0) +#define CFG_ROAM_SCAN_HI_RSSI_UB_DEFAULT (-30) + +#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_ENABLE_LFR_SUBNET_DETECTION "gLFRSubnetDetectionEnable" +#define CFG_ENABLE_LFR_SUBNET_MIN (0) +#define CFG_ENABLE_LFR_SUBNET_MAX (1) +#define CFG_ENABLE_LFR_SUBNET_DEFAULT (1) +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/* + * + * 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 enviournment. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET "groam_dense_rssi_thresh_offset" +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MIN (0) +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MAX (20) +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET_DEFAULT (10) + +/* + * + * 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_ROAM_FT_OPEN_ENABLE_NAME "enable_ftopen" +#define CFG_ROAM_FT_OPEN_ENABLE_MIN (0) +#define CFG_ROAM_FT_OPEN_ENABLE_MAX (1) +#define CFG_ROAM_FT_OPEN_ENABLE_DEFAULT (1) + +/* + * + * 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_ROAM_DENSE_MIN_APS "groam_dense_min_aps" +#define CFG_ROAM_DENSE_MIN_APS_MIN (1) +#define CFG_ROAM_DENSE_MIN_APS_MAX (5) +#define CFG_ROAM_DENSE_MIN_APS_DEFAULT (3) + +/* + * + * 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_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_NAME "roam_bg_scan_bad_rssi_thresh" +#define CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_MIN (-96) +#define CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_MAX (0) +#define CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_DEFAULT (-76) + +/* + * + * roam_bg_scan_client_bitmap - Bitmap used to identify the scan clients + * @Min: 0 + * @Max: 0x3FF + * @Default: 0x + * + * 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_ROAM_BG_SCAN_CLIENT_BITMAP_NAME "roam_bg_scan_client_bitmap" +#define CFG_ROAM_BG_SCAN_CLIENT_BITMAP_MIN (0) +#define CFG_ROAM_BG_SCAN_CLIENT_BITMAP_MAX (0x7FF) +#define CFG_ROAM_BG_SCAN_CLIENT_BITMAP_DEFAULT (0x424) + +/* + * + * 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_MIN_DELAY_BTW_ROAM_SCAN_NAME "min_delay_btw_roam_scans" +#define CFG_MIN_DELAY_BTW_ROAM_SCAN_MIN (0) +#define CFG_MIN_DELAY_BTW_ROAM_SCAN_MAX (60) +#define CFG_MIN_DELAY_BTW_ROAM_SCAN_DEFAULT (10) + +/* + * + * 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_MAX - 13 + * + * For Ex: 0xDA (PER, LOW_RSSI, HIGH_RSSI, MAWC, DENSE) + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_NAME "roam_trigger_reason_bitmask" +#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MIN (0) +#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MAX (0xFFFFFFFF) +#define CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_DEFAULT (0x10DA) + +/* + * + * 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_NAME "roaming_scan_policy" +#define CFG_ROAM_SCAN_SCAN_POLICY_MIN (0) +#define CFG_ROAM_SCAN_SCAN_POLICY_MAX (1) +#define CFG_ROAM_SCAN_SCAN_POLICY_DEFAULT (0) + +/* + * + * 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_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_NAME "roam_bad_rssi_thresh_offset_2g" +#define CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_MIN (0) +#define CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_MAX (86) +#define CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_DEFAULT (40) + +/* + * + * 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_ROAM_HO_DELAY_FOR_RX_NAME "ho_delay_for_rx" +#define CFG_ROAM_HO_DELAY_FOR_RX_MIN (0) +#define CFG_ROAM_HO_DELAY_FOR_RX_MAX (200) +#define CFG_ROAM_HO_DELAY_FOR_RX_DEFAULT (0) + +/* + * + * 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_ROAM_FORCE_RSSI_TRIGGER_NAME "roam_force_rssi_trigger" +#define CFG_ROAM_FORCE_RSSI_TRIGGER_MIN (0) +#define CFG_ROAM_FORCE_RSSI_TRIGGER_MAX (1) +#define CFG_ROAM_FORCE_RSSI_TRIGGER_DEFAULT (1) + +/* + * + * roamscan_adaptive_dwell_mode - Sets dwell time adaptive mode + * @Min: 0 + * @Max: 4 + * @Default: 1 + * + * 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_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME "roamscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_DEFAULT (1) + +/* + * Timer waiting for interface up from the upper layer. If + * this timer expires all the cds modules shall be closed. + * Time Units: ms + */ +#define CFG_INTERFACE_CHANGE_WAIT_NAME "gInterfaceChangeWait" +#define CFG_INTERFACE_CHANGE_WAIT_MIN (10) +#define CFG_INTERFACE_CHANGE_WAIT_MAX (500000) +#define CFG_INTERFACE_CHANGE_WAIT_DEFAULT (10000) + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_SHORT_PREAMBLE_NAME "gShortPreamble" +#define CFG_SHORT_PREAMBLE_MIN WNI_CFG_SHORT_PREAMBLE_STAMIN +#define CFG_SHORT_PREAMBLE_MAX WNI_CFG_SHORT_PREAMBLE_STAMAX +#define CFG_SHORT_PREAMBLE_DEFAULT WNI_CFG_SHORT_PREAMBLE_STADEF + +/* + * + * gIbssBssid - Default IBSS BSSID if BSSID is not provided by supplicant + * @Min: "000000000000" + * @Max: "ffffffffffff" + * @Default: "000AF5040506" + * + * This ini is used to set Default IBSS BSSID if BSSID + * is not provided by supplicant and Coalesing is disabled + * + * Related: Only applicable if gCoalesingInIBSS is 0 + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_BSSID_NAME "gIbssBssid" +#define CFG_IBSS_BSSID_MIN "000000000000" +#define CFG_IBSS_BSSID_MAX "ffffffffffff" +#define CFG_IBSS_BSSID_DEFAULT "000AF5040506" + +/* + * + * gAdHocChannel5G - Default 5Ghz IBSS channel if channel is not + * provided by supplicant. + * @Min: 36 + * @Max: 165 + * @Default: 44 + * + * This ini is used to set default 5Ghz IBSS channel + * if channel is not provided by supplicant and band is 5Ghz + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_NAME "gAdHocChannel5G" +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_MIN (36) +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_MAX (165) +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_DEFAULT (44) + +/* + * + * gAdHocChannel24G - Default 2.4Ghz IBSS channel if channel is not + * provided by supplicant. + * @Min: 1 + * @Max: 14 + * @Default: 6 + * + * This ini is used to set default 2.4Ghz IBSS channel + * if channel is not provided by supplicant and band is 2.4Ghz + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_NAME "gAdHocChannel24G" +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_MIN (1) +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_MAX (14) +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_DEFAULT (6) + +/* + * + * gCoalesingInIBSS - If IBSS coalesing is enabled. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set IBSS coalesing + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_COALESING_IN_IBSS_NAME "gCoalesingInIBSS" +#define CFG_COALESING_IN_IBSS_MIN (0) +#define CFG_COALESING_IN_IBSS_MAX (1) +#define CFG_COALESING_IN_IBSS_DEFAULT (0) /* disabled */ + +/* + * + * gIbssATIMWinSize - Set IBSS ATIM window size + * @Min: 0 + * @Max: 50 + * @Default: 0 + * + * This ini is used to set IBSS ATIM window size + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_ATIM_WIN_SIZE_NAME "gIbssATIMWinSize" +#define CFG_IBSS_ATIM_WIN_SIZE_MIN (0) +#define CFG_IBSS_ATIM_WIN_SIZE_MAX (50) +#define CFG_IBSS_ATIM_WIN_SIZE_DEFAULT (0) + + +/* + * + * gIbssIsPowerSaveAllowed - Indicates if IBSS Power Save is + * supported or not + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to Indicates if IBSS Power Save is + * supported or not. When not allowed,IBSS station has + * to stay awake all the time and should never set PM=1 + * in its transmitted frames. + * + * Related: valid only when gIbssATIMWinSize is non-zero + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_NAME "gIbssIsPowerSaveAllowed" +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_MIN (0) +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_MAX (1) +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_DEFAULT (1) + +/* + * + * gIbssIsPowerCollapseAllowed - Indicates if IBSS Power Collapse + * is allowed + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to indicates if IBSS Power Collapse + * is allowed + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_NAME "gIbssIsPowerCollapseAllowed" +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MIN (0) +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MAX (1) +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_DEFAULT (1) + +/* + * + * gIbssAwakeOnTxRx - Indicates whether IBSS station + * can exit power save mode and enter power active + * state whenever there is a TX/RX activity. + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to ndicates whether IBSS station + * can exit power save mode and enter power active + * state whenever there is a TX/RX activity. + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_AWAKE_ON_TX_RX_NAME "gIbssAwakeOnTxRx" +#define CFG_IBSS_AWAKE_ON_TX_RX_MIN (0) +#define CFG_IBSS_AWAKE_ON_TX_RX_MAX (1) +#define CFG_IBSS_AWAKE_ON_TX_RX_DEFAULT (0) + +/* + * + * gIbssInactivityTime - Indicates the data + * inactivity time in number of beacon intervals + * after which IBSS station re-inters power save + * + * @Min: 1 + * @Max: 10 + * @Default: 1 + * + * In IBSS mode if Awake on TX/RX activity is enabled + * Ibss Inactivity parameter indicates the data + * inactivity time in number of beacon intervals + * after which IBSS station re-inters power save + * by sending Null frame with PM=1 + * + * Related: Aplicable if gIbssAwakeOnTxRx is enabled + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_INACTIVITY_TIME_NAME "gIbssInactivityTime" +#define CFG_IBSS_INACTIVITY_TIME_MIN (1) +#define CFG_IBSS_INACTIVITY_TIME_MAX (10) +#define CFG_IBSS_INACTIVITY_TIME_DEFAULT (1) + +/* + * + * gIbssTxSpEndInactivityTime - Indicates the time after + * which TX Service Period is terminated by + * sending a Qos Null frame with EOSP. + * + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * In IBSS mode Tx Service Period Inactivity + * time in msecs indicates the time after + * which TX Service Period is terminated by + * sending a Qos Null frame with EOSP. + * If value is 0, TX SP is terminated with the + * last buffered packet itself instead of waiting + * for the inactivity. + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_TXSP_END_INACTIVITY_NAME "gIbssTxSpEndInactivityTime" +#define CFG_IBSS_TXSP_END_INACTIVITY_MIN (0) +#define CFG_IBSS_TXSP_END_INACTIVITY_MAX (100) +#define CFG_IBSS_TXSP_END_INACTIVITY_DEFAULT (0) + +/* + * + * gIbssPsWarmupTime - PS-supporting device + * does not enter protocol sleep state during first + * gIbssPsWarmupTime seconds. + * + * @Min: 0 + * @Max: 65535 + * @Default: 0 + * + * When IBSS network is initialized, PS-supporting device + * does not enter protocol sleep state during first + * gIbssPsWarmupTime seconds. + * + * Related: valid if gIbssIsPowerSaveAllowed is set + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_PS_WARMUP_TIME_NAME "gIbssPsWarmupTime" +#define CFG_IBSS_PS_WARMUP_TIME_MIN (0) +/* Allow unsigned Int Max for now */ +#define CFG_IBSS_PS_WARMUP_TIME_MAX (65535) +#define CFG_IBSS_PS_WARMUP_TIME_DEFAULT (0) + +/* + * + * gIbssPs1RxChainInAtim - IBSS Power Save Enable/Disable 1 RX + * chain usage during the ATIM window + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * IBSS Power Save Enable/Disable 1 RX + * chain usage during the ATIM window + * + * Related: Depend on gIbssIsPowerSaveAllowed + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_NAME "gIbssPs1RxChainInAtim" +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MIN (0) +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MAX (1) +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_DEFAULT (0) + +/* + * + * wlm_latency_enable - WLM latency Enable + * + * @min: 0 + * @max: 1 + * @default: 1 + * + * 0 - disable + * 1 - enable + * + * + */ +#define CFG_LATENCY_ENABLE_NAME "wlm_latency_enable" +#define CFG_LATENCY_ENABLE_MIN (0) +#define CFG_LATENCY_ENABLE_MAX (1) +#define CFG_LATENCY_ENABLE_DEFAULT (1) + +/* + * + * wlm_latency_level - WLM latency level + * Define 4 latency level to gain latency + * + * @min: 0 + * @max: 3 + * @defalut: 0 + * + * 0 - normal + * 1 - moderate + * 2 - low + * 3 - ultralow + * + * + */ +#define CFG_LATENCY_LEVEL_NAME "wlm_latency_level" +#define CFG_LATENCY_LEVEL_MIN (0) +#define CFG_LATENCY_LEVEL_MAX (3) +#define CFG_LATENCY_LEVEL_DEFAULT (0) + +/* + * + * wlm_latency_flags_normal - WLM flags setting for normal level + * + * @min: 0x0 + * @max: 0xffffffff + * @defalut: 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 useage + * + * + */ +#define CFG_LATENCY_FLAGS_NORMAL_NAME "wlm_latency_flags_normal" +#define CFG_LATENCY_FLAGS_NORMAL_MIN (0x0) +#define CFG_LATENCY_FLAGS_NORMAL_MAX (0xffffffff) +#define CFG_LATENCY_FLAGS_NORMAL_DEFAULT (0x0) + +/* + * + * wlm_latency_flags_moderate - WLM flags setting for moderate level + * + * @min: 0x0 + * @max: 0xffffffff + * @defalut: 0x8 + * + * |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 useage + * + * + */ +#define CFG_LATENCY_FLAGS_MODERATE_NAME "wlm_latency_flags_moderate" +#define CFG_LATENCY_FLAGS_MODERATE_MIN (0x0) +#define CFG_LATENCY_FLAGS_MODERATE_MAX (0xffffffff) +#define CFG_LATENCY_FLAGS_MODERATE_DEFAULT (0x8) + +/* + * + * wlm_latency_flags_low - WLM flags setting for low level + * + * @min: 0x0 + * @max: 0xffffffff + * @defalut: 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 useage + * + * + */ +#define CFG_LATENCY_FLAGS_LOW_NAME "wlm_latency_flags_low" +#define CFG_LATENCY_FLAGS_LOW_MIN (0x0) +#define CFG_LATENCY_FLAGS_LOW_MAX (0xffffffff) +#define CFG_LATENCY_FLAGS_LOW_DEFAULT (0xa) + +/* + * + * wlm_latency_flags_ultralow - WLM flags setting for ultralow level + * + * @min: 0x0 + * @max: 0xffffffff + * @defalut: 0xc83 + * + * |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 useage + * + * + */ +#define CFG_LATENCY_FLAGS_ULTRALOW_NAME "wlm_latency_flags_ultralow" +#define CFG_LATENCY_FLAGS_ULTRALOW_MIN (0x0) +#define CFG_LATENCY_FLAGS_ULTRALOW_MAX (0xffffffff) +#define CFG_LATENCY_FLAGS_ULTRALOW_DEFAULT (0xc83) + +#define CFG_INTF0_MAC_ADDR_NAME "Intf0MacAddress" +#define CFG_INTF0_MAC_ADDR_MIN "000000000000" +#define CFG_INTF0_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF0_MAC_ADDR_DEFAULT "000AF58989FF" + +#define CFG_INTF1_MAC_ADDR_NAME "Intf1MacAddress" +#define CFG_INTF1_MAC_ADDR_MIN "000000000000" +#define CFG_INTF1_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF1_MAC_ADDR_DEFAULT "000AF58989FE" + +#define CFG_INTF2_MAC_ADDR_NAME "Intf2MacAddress" +#define CFG_INTF2_MAC_ADDR_MIN "000000000000" +#define CFG_INTF2_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF2_MAC_ADDR_DEFAULT "000AF58989FD" + +#define CFG_INTF3_MAC_ADDR_NAME "Intf3MacAddress" +#define CFG_INTF3_MAC_ADDR_MIN "000000000000" +#define CFG_INTF3_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF3_MAC_ADDR_DEFAULT "000AF58989FC" + +/* + * + * gDot11Mode - SAP phy mode + * @Min: 0 + * @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_DOT11_MODE_NAME "gDot11Mode" +#define CFG_DOT11_MODE_MIN eHDD_DOT11_MODE_AUTO +#define CFG_DOT11_MODE_DEFAULT eHDD_DOT11_MODE_11ax +#define CFG_DOT11_MODE_MAX eHDD_DOT11_MODE_11ax + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_AP_QOS_UAPSD_MODE_NAME "gEnableApUapsd" +#define CFG_AP_QOS_UAPSD_MODE_MIN (0) +#define CFG_AP_QOS_UAPSD_MODE_MAX (1) +#define CFG_AP_QOS_UAPSD_MODE_DEFAULT (1) + +/* + * + * 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_NAME "gEnableApRandomBssid" +#define CFG_AP_ENABLE_RANDOM_BSSID_MIN (0) +#define CFG_AP_ENABLE_RANDOM_BSSID_MAX (1) +#define CFG_AP_ENABLE_RANDOM_BSSID_DEFAULT (0) + +/* + * + * 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_NAME "gEnableApProt" +#define CFG_AP_ENABLE_PROTECTION_MODE_MIN (0) +#define CFG_AP_ENABLE_PROTECTION_MODE_MAX (1) +#define CFG_AP_ENABLE_PROTECTION_MODE_DEFAULT (1) + +/* + * + * 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_NAME "gApProtection" +#define CFG_AP_PROTECTION_MODE_MIN (0x0) +#define CFG_AP_PROTECTION_MODE_MAX (0xFFFF) +#define CFG_AP_PROTECTION_MODE_DEFAULT (0xBFFF) + +/* + * + * 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_MODE_NAME "gEnableApOBSSProt" +#define CFG_AP_OBSS_PROTECTION_MODE_MIN (0) +#define CFG_AP_OBSS_PROTECTION_MODE_MAX (1) +#define CFG_AP_OBSS_PROTECTION_MODE_DEFAULT (0) + +/* + * + * gDisableIntraBssFwd - Disable intrs BSS Rx packets + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disbale to forward Intra-BSS Rx packets when + * ap_isolate=1 in hostapd.conf + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_STA_SECURITY_SEPERATION_NAME "gDisableIntraBssFwd" +#define CFG_AP_STA_SECURITY_SEPERATION_MIN (0) +#define CFG_AP_STA_SECURITY_SEPERATION_MAX (1) +#define CFG_AP_STA_SECURITY_SEPERATION_DEFAULT (0) + +/* + * + * gApKeepAlivePeriod - AP keep alive period + * @Min: 1 + * @Max: 65535 + * @Default: 20 + * + * This ini is used to set keep alive period of AP + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_KEEP_ALIVE_PERIOD_NAME "gApKeepAlivePeriod" +#define CFG_AP_KEEP_ALIVE_PERIOD_MIN WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN +#define CFG_AP_KEEP_ALIVE_PERIOD_MAX WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX +#define CFG_AP_KEEP_ALIVE_PERIOD_DEFAULT WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF + +/* + * + * 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_PERIOD_NAME "gApLinkMonitorPeriod" +#define CFG_AP_LINK_MONITOR_PERIOD_MIN (3) +#define CFG_AP_LINK_MONITOR_PERIOD_MAX (50) +#define CFG_AP_LINK_MONITOR_PERIOD_DEFAULT (10) + +/* + * + * gBeaconInterval - Beacon interval for SoftAP + * @Min: 0 + * @Max: 65535 + * @Default: 100 + * + * This ini is used to set beacon interval for SoftAP + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_BEACON_INTERVAL_NAME "gBeaconInterval" +#define CFG_BEACON_INTERVAL_MIN WNI_CFG_BEACON_INTERVAL_STAMIN +#define CFG_BEACON_INTERVAL_MAX WNI_CFG_BEACON_INTERVAL_STAMAX +#define CFG_BEACON_INTERVAL_DEFAULT WNI_CFG_BEACON_INTERVAL_STADEF + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define CFG_WLAN_AUTO_SHUTDOWN "gWlanAutoShutdown" +#define CFG_WLAN_AUTO_SHUTDOWN_MIN (0) +#define CFG_WLAN_AUTO_SHUTDOWN_MAX (86400) /* Max 1 day timeout */ +#define CFG_WLAN_AUTO_SHUTDOWN_DEFAULT (0) +#endif + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/* + * + * gWlanMccToSccSwitchMode - Control SAP channel. + * @Min: 0 + * @Max: 5 + * @Default: 0 + * + * This ini is used to override SAP channel. + * If gWlanMccToSccSwitchMode = 0: disabled. + * If gWlanMccToSccSwitchMode = 1: Enable switch. + * If gWlainMccToSccSwitchMode = 2: Force switch with SAP restart. + * If gWlainMccToSccSwitchMode = 3: Force switch without SAP restart. + * If gWlainMccToSccSwitchMode = 4: Switch using + * fav channel(s)without SAP restart. + * If gWlainMccToSccSwitchMode = 5: Force switch without SAP restart.MCC allowed + * in exceptional cases. + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE "gWlanMccToSccSwitchMode" +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MIN (QDF_MCC_TO_SCC_SWITCH_DISABLE) +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MAX \ + (QDF_MCC_TO_SCC_SWITCH_MAX - 1) +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_DEFAULT (QDF_MCC_TO_SCC_SWITCH_DISABLE) +#endif + +#define CFG_DISABLE_PACKET_FILTER "gDisablePacketFilter" +#define CFG_DISABLE_PACKET_FILTER_MIN (0) +#define CFG_DISABLE_PACKET_FILTER_MAX (1) +#define CFG_DISABLE_PACKET_FILTER_DEFAULT (1) + +#define CFG_ENABLE_LTE_COEX "gEnableLTECoex" +#define CFG_ENABLE_LTE_COEX_MIN (0) +#define CFG_ENABLE_LTE_COEX_MAX (1) +#define CFG_ENABLE_LTE_COEX_DEFAULT (0) + +#define CFG_GO_KEEP_ALIVE_PERIOD_NAME "gGoKeepAlivePeriod" +#define CFG_GO_KEEP_ALIVE_PERIOD_MIN WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN +#define CFG_GO_KEEP_ALIVE_PERIOD_MAX WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX +#define CFG_GO_KEEP_ALIVE_PERIOD_DEFAULT WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF + +/* gGoLinkMonitorPeriod is period where link is idle and where + * we send NULL frame + */ +#define CFG_GO_LINK_MONITOR_PERIOD_NAME "gGoLinkMonitorPeriod" +#define CFG_GO_LINK_MONITOR_PERIOD_MIN (3) +#define CFG_GO_LINK_MONITOR_PERIOD_MAX (50) +#define CFG_GO_LINK_MONITOR_PERIOD_DEFAULT (10) + +#define CFG_VCC_RSSI_TRIGGER_NAME "gVccRssiTrigger" +#define CFG_VCC_RSSI_TRIGGER_MIN (0) +#define CFG_VCC_RSSI_TRIGGER_MAX (80) +#define CFG_VCC_RSSI_TRIGGER_DEFAULT (80) + +#define CFG_VCC_UL_MAC_LOSS_THRESH_NAME "gVccUlMacLossThresh" +#define CFG_VCC_UL_MAC_LOSS_THRESH_MIN (0) +#define CFG_VCC_UL_MAC_LOSS_THRESH_MAX (9) +#define CFG_VCC_UL_MAC_LOSS_THRESH_DEFAULT (9) + +/* + * + * gPassiveMaxChannelTimeConc - Maximum passive scan time in milliseconds. + * @Min: 0 + * @Max: 10000 + * @Default: 110 + * + * This ini is used to set maximum passive scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_NAME "gPassiveMaxChannelTimeConc" +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN (0) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_DEFAULT (110) + +/* + * + * gPassiveMinChannelTimeConc - Minimum passive scan time in milliseconds. + * @Min: 0 + * @Max: 10000 + * @Default: 60 + * + * This ini is used to set minimum passive scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_NAME "gPassiveMinChannelTimeConc" +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN (0) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_DEFAULT (60) + +/* + * + * gActiveMaxChannelTimeConc - Maximum active scan time in milliseconds. + * @Min: 0 + * @Max: 10000 + * @Default: 40 + * + * This ini is used to set maximum active scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_NAME "gActiveMaxChannelTimeConc" +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN (0) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_DEFAULT (40) + +/* + * + * gActiveMinChannelTimeConc - Minimum active scan time in milliseconds.. + * @Min: 0 + * @Max: 10000 + * @Default: 20 + * + * This ini is used to set minimum active scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_NAME "gActiveMinChannelTimeConc" +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN (0) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_DEFAULT (20) + +/* + * + * gRestTimeConc - Rest time before moving to a new channel to scan. + * @Min: 0 + * @Max: 10000 + * @Default: 100 + * + * This ini is used to configure rest time. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_REST_TIME_CONC_NAME "gRestTimeConc" +#define CFG_REST_TIME_CONC_MIN (0) +#define CFG_REST_TIME_CONC_MAX (10000) +#define CFG_REST_TIME_CONC_DEFAULT (100) + +/* + * + * gMinRestTimeConc - Mininum time spent on home channel before moving to a + * new channel to scan. + * @Min: 0 + * @Max: 50 + * @Default: 50 + * + * This ini is used to configure minimum time spent on home channel before + * moving to a new channel to scan. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_MIN_REST_TIME_NAME "gMinRestTimeConc" +#define CFG_MIN_REST_TIME_MIN (0) +#define CFG_MIN_REST_TIME_MAX (50) +#define CFG_MIN_REST_TIME_DEFAULT (50) + +/* + * + * gIdleTimeConc - Data inactivity time in msec. + * @Min: 0 + * @Max: 25 + * @Default: 25 + * + * This ini is used to configure data inactivity time in msec on bss channel + * that will be used by scan engine in firmware. + * For example if this value is 25ms then firmware will check for data + * inactivity every 25ms till gRestTimeConc is reached. + * If inactive then scan engine will move from home channel to scan the next + * frequency. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_IDLE_TIME_NAME "gIdleTimeConc" +#define CFG_IDLE_TIME_MIN (0) +#define CFG_IDLE_TIME_MAX (25) +#define CFG_IDLE_TIME_DEFAULT (25) + +#define CFG_MAX_PS_POLL_NAME "gMaxPsPoll" +#define CFG_MAX_PS_POLL_MIN WNI_CFG_MAX_PS_POLL_STAMIN +#define CFG_MAX_PS_POLL_MAX WNI_CFG_MAX_PS_POLL_STAMAX +#define CFG_MAX_PS_POLL_DEFAULT WNI_CFG_MAX_PS_POLL_STADEF + +#define CFG_MAX_TX_POWER_NAME "gTxPowerCap" +#define CFG_MAX_TX_POWER_MIN WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN +#define CFG_MAX_TX_POWER_MAX WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX +/* Not to use CFG default because if no registry setting, this is ignored by SME. */ +#define CFG_MAX_TX_POWER_DEFAULT WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX + +/* This ini controls driver to honor/dishonor power constraint from AP */ +#define CFG_TX_POWER_CTRL_NAME "gAllowTPCfromAP" +#define CFG_TX_POWER_CTRL_DEFAULT (1) +#define CFG_TX_POWER_CTRL_MIN (0) +#define CFG_TX_POWER_CTRL_MAX (1) + +/* + * + * gMaxLIModulatedDTIM - Set MaxLIModulate Dtim + * @Min: 1 + * @Max: 10 + * @Default: 10 + * + * This ini is used to set default MaxLIModulatedDTIM + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_MAX_LI_MODULATED_DTIM_NAME "gMaxLIModulatedDTIM" +#define CFG_MAX_LI_MODULATED_DTIM_MIN (1) +#define CFG_MAX_LI_MODULATED_DTIM_MAX (10) +#define CFG_MAX_LI_MODULATED_DTIM_DEFAULT (10) + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_FW_MCC_RTS_CTS_PROT_NAME "gFWMccRtsCtsProtection" +#define CFG_FW_MCC_RTS_CTS_PROT_MIN (0) +#define CFG_FW_MCC_RTS_CTS_PROT_MAX (1) +#define CFG_FW_MCC_RTS_CTS_PROT_DEFAULT (0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_FW_MCC_BCAST_PROB_RESP_NAME "gFWMccBCastProbeResponse" +#define CFG_FW_MCC_BCAST_PROB_RESP_MIN (0) +#define CFG_FW_MCC_BCAST_PROB_RESP_MAX (1) +#define CFG_FW_MCC_BCAST_PROB_RESP_DEFAULT (0) + +/* + * + * gDataInactivityTimeout - Data activity timeout for non wow mode. + * @Min: 1 + * @Max: 255 + * @Default: 200 + * + * This ini is used to set data inactivity timeout in non wow mode. + * + * Supported Feature: inactivity timeout in non wow mode + * + * Usage: External + * + * + */ + +#define CFG_DATA_INACTIVITY_TIMEOUT_NAME "gDataInactivityTimeout" +#define CFG_DATA_INACTIVITY_TIMEOUT_MIN (1) +#define CFG_DATA_INACTIVITY_TIMEOUT_MAX (255) +#define CFG_DATA_INACTIVITY_TIMEOUT_DEFAULT (200) + +/* + * + * 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. + * + * Supported Feature: inactivity timeout in wow mode + * + * Usage: External + * + * + */ +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_NAME "g_wow_data_inactivity_timeout" +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_MIN (1) +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_MAX (255) +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_DEFAULT (50) + +/* + * + * gStaKeepAlivePeriod - Sends NULL frame to AP periodically in + * seconds to notify STA's existence + * @Min: 0 + * @Max: 65535 + * @Default: 30 + * + * This ini is used to send default NULL frame to AP + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_NAME "gStaKeepAlivePeriod" +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MIN (0) +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MAX (65535) +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_DEFAULT (60) + +/** + * enum station_keepalive_method - available keepalive methods for stations + * @HDD_STA_KEEPALIVE_NULL_DATA: null data packet + * @HDD_STA_KEEPALIVE_GRAT_ARP: gratuitous ARP packet + * @HDD_STA_KEEPALIVE_COUNT: number of method options available + */ +enum station_keepalive_method { + HDD_STA_KEEPALIVE_NULL_DATA, + HDD_STA_KEEPALIVE_GRAT_ARP, + /* keep at the end */ + HDD_STA_KEEPALIVE_COUNT +}; + +/* + * + * gStaKeepAliveMethod - Which keepalive method to use + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini determines which keepalive method to use for station interfaces + * 1) Use null data packets + * 2) Use gratuitous ARP packets + * + * Related: gStaKeepAlivePeriod, gApKeepAlivePeriod, gGoKeepAlivePeriod + * + * Supported Feature: STA, Keepalive + * + * Usage: Internal/External + * + * + */ +#define CFG_STA_KEEPALIVE_METHOD_NAME "gStaKeepAliveMethod" +#define CFG_STA_KEEPALIVE_METHOD_MIN (HDD_STA_KEEPALIVE_NULL_DATA) +#define CFG_STA_KEEPALIVE_METHOD_MAX (HDD_STA_KEEPALIVE_COUNT - 1) +#define CFG_STA_KEEPALIVE_METHOD_DEFAULT (HDD_STA_KEEPALIVE_GRAT_ARP) + +/* 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_MODE_NAME "WmmIsEnabled" +#define CFG_QOS_WMM_MODE_MIN (0) +#define CFG_QOS_WMM_MODE_MAX (2) /* HDD_WMM_NO_QOS */ +#define CFG_QOS_WMM_MODE_DEFAULT (0) /* HDD_WMM_AUTO */ + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_80211E_ENABLED_NAME "80211eIsEnabled" +#define CFG_QOS_WMM_80211E_ENABLED_MIN (0) +#define CFG_QOS_WMM_80211E_ENABLED_MAX (1) +#define CFG_QOS_WMM_80211E_ENABLED_DEFAULT (0) + +/* + * + * 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. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_UAPSD_MASK_NAME "UapsdMask" +#define CFG_QOS_WMM_UAPSD_MASK_MIN (0x00) +#define CFG_QOS_WMM_UAPSD_MASK_MAX (0xFF) +#define CFG_QOS_WMM_UAPSD_MASK_DEFAULT (0x00) + +/* + * + * ImplicitQosIsEnabled - Enableimplicit QOS + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable implicit QOS. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_NAME "ImplicitQosIsEnabled" +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_MIN (0) +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_MAX (1) +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_DEFAULT (0) + +/* + * + * InfraUapsdVoSrvIntv - Set Uapsd service interval for voice + * @Min: 0 + * @Max: 4294967295UL + * @Default: 20 + * + * This ini is used to set Uapsd service interval for voice. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_NAME "InfraUapsdVoSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_DEFAULT (20) + +/* + * + * InfraUapsdVoSuspIntv - Set Uapsd suspension interval for voice + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for voice. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_NAME "InfraUapsdVoSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_DEFAULT (2000) + +/* + * + * InfraUapsdViSrvIntv - Set Uapsd service interval for video + * @Min: 0 + * @Max: 4294967295UL + * @Default: 300 + * + * This ini is used to set Uapsd service interval for video. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_NAME "InfraUapsdViSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_DEFAULT (300) + +/* + * + * InfraUapsdViSuspIntv - Set Uapsd suspension interval for video + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for video + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_NAME "InfraUapsdViSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_DEFAULT (2000) + +/* + * + * InfraUapsdBeSrvIntv - Set Uapsd service interval for BE + * @Min: 0 + * @Max: 4294967295UL + * @Default: 300 + * + * This ini is used to set Uapsd service interval for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_NAME "InfraUapsdBeSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_DEFAULT (300) + +/* + * + * InfraUapsdBeSuspIntv - Set Uapsd suspension interval for BE + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_NAME "InfraUapsdBeSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_DEFAULT (2000) + +/* + * + * InfraUapsdBkSrvIntv - Set Uapsd service interval for BK + * @Min: 0 + * @Max: 4294967295UL + * @Default: 300 + * + * This ini is used to set Uapsd service interval for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_NAME "InfraUapsdBkSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_DEFAULT (300) + +/* + * + * InfraUapsdBkSuspIntv - Set Uapsd suspension interval for BK + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_NAME "InfraUapsdBkSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_DEFAULT (2000) + +/* 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 + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME "InfraDirAcVo" +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_NAME "InfraNomMsduSizeAcVo" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_DEFAULT (0x80D0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_NAME "InfraMeanDataRateAcVo" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_DEFAULT (0x14500) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_NAME "InfraMinPhyRateAcVo" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_DEFAULT (0x5B8D80) +/* + * + * 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: Internal/External + * + * + */ + #define CFG_QOS_WMM_INFRA_SBA_AC_VO_NAME "InfraSbaAcVo" + #define CFG_QOS_WMM_INFRA_SBA_AC_VO_MIN (0x2001) + #define CFG_QOS_WMM_INFRA_SBA_AC_VO_MAX (0xFFFF) + #define CFG_QOS_WMM_INFRA_SBA_AC_VO_DEFAULT (0x2001) + + /* default TSPEC parameters for AC_VI */ +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_NAME "InfraDirAcVi" +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_NAME "InfraNomMsduSizeAcVi" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_DEFAULT (0x85DC) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_NAME "InfraMeanDataRateAcVi" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_DEFAULT (0x57E40) + +/* + * + * iInfraMinPhyRateAcVi - 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_NAME "InfraMinPhyRateAcVi" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_DEFAULT (0x5B8D80) + +/* + * + * 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: Internal/External + * + * + */ + #define CFG_QOS_WMM_INFRA_SBA_AC_VI_NAME "InfraSbaAcVi" + #define CFG_QOS_WMM_INFRA_SBA_AC_VI_MIN (0x2001) + #define CFG_QOS_WMM_INFRA_SBA_AC_VI_MAX (0xFFFF) + #define CFG_QOS_WMM_INFRA_SBA_AC_VI_DEFAULT (0x2001) + + /* default TSPEC parameters for AC_BE*/ +/* + * + * InfraDirAcBe - Set TSPEC direction for BE + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_NAME "InfraDirAcBe" +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_NAME "InfraNomMsduSizeAcBe" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_DEFAULT (0x85DC) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_NAME "InfraMeanDataRateAcBe" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_DEFAULT (0x493E0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_NAME "InfraMinPhyRateAcBe" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_DEFAULT (0x5B8D80) + +/* + * + * 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: Internal/External + * + * + */ + #define CFG_QOS_WMM_INFRA_SBA_AC_BE_NAME "InfraSbaAcBe" + #define CFG_QOS_WMM_INFRA_SBA_AC_BE_MIN (0x2001) + #define CFG_QOS_WMM_INFRA_SBA_AC_BE_MAX (0xFFFF) + #define CFG_QOS_WMM_INFRA_SBA_AC_BE_DEFAULT (0x2001) + + /* default TSPEC parameters for AC_Bk*/ +/* + * + * InfraDirAcBk - Set TSPEC direction for BK + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_NAME "InfraDirAcBk" +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_NAME "InfraNomMsduSizeAcBk" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_DEFAULT (0x85DC) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_NAME "InfraMeanDataRateAcBk" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_DEFAULT (0x493E0) + +/* + * + * InfraMinPhyRateAcBke - 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: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_NAME "InfraMinPhyRateAcBk" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_DEFAULT (0x5B8D80) + +/* + * + * InfraSbaAcBk - Set surplus bandwidth allowance for BK + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ + #define CFG_QOS_WMM_INFRA_SBA_AC_BK_NAME "InfraSbaAcBk" + #define CFG_QOS_WMM_INFRA_SBA_AC_BK_MIN (0x2001) + #define CFG_QOS_WMM_INFRA_SBA_AC_BK_MAX (0xFFFF) + #define CFG_QOS_WMM_INFRA_SBA_AC_BK_DEFAULT (0x2001) + +/* + * + * burstSizeDefinition - Set TS burst size + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set TS burst size + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_BURST_SIZE_DEFN_NAME "burstSizeDefinition" +#define CFG_QOS_WMM_BURST_SIZE_DEFN_MIN (0) +#define CFG_QOS_WMM_BURST_SIZE_DEFN_MAX (1) +#define CFG_QOS_WMM_BURST_SIZE_DEFN_DEFAULT (0) + +/* + * + * tsInfoAckPolicy - Set TS ack policy + * @Min: 0x00 + * @Max: 0x01 + * @Default: 0x00 + * + * This ini is used to set TS ack policy + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_NAME "tsInfoAckPolicy" +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_MIN (0x00) +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_MAX (0x01) +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_DEFAULT (0x00) + +/* + * + * SingleTIDRC - Set replay counter for all TID's + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set replay counter for all TID's + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_SINGLE_TID_RC_NAME "SingleTIDRC" +#define CFG_SINGLE_TID_RC_MIN (0) /* Separate replay counter for all TID */ +#define CFG_SINGLE_TID_RC_MAX (1) /* Single replay counter for all TID */ +#define CFG_SINGLE_TID_RC_DEFAULT (1) + +/* + * + * gAddTSWhenACMIsOff - Set ACM value for AC + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set ACM value for AC + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_NAME "gAddTSWhenACMIsOff" +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MIN (0) +/* Send AddTs even when ACM is not set for the AC */ +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MAX (1) +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_DEFAULT (0) + +#ifdef FEATURE_WLAN_ESE +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_NAME "InfraInactivityInterval" +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MIN (0) +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_DEFAULT (0) /* disabled */ + +#define CFG_ESE_FEATURE_ENABLED_NAME "EseEnabled" +#define CFG_ESE_FEATURE_ENABLED_MIN (0) +#define CFG_ESE_FEATURE_ENABLED_MAX (1) +#define CFG_ESE_FEATURE_ENABLED_DEFAULT (0) /* disabled */ +#endif /* FEATURE_WLAN_ESE */ + +/* + * + * 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_NAME "MAWCEnabled" +#define CFG_LFR_MAWC_FEATURE_ENABLED_MIN (0) +#define CFG_LFR_MAWC_FEATURE_ENABLED_MAX (1) +#define CFG_LFR_MAWC_FEATURE_ENABLED_DEFAULT (0) + +/* + * + * 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_MAWC_ROAM_ENABLED_NAME "mawc_roam_enabled" +#define CFG_MAWC_ROAM_ENABLED_MIN (0) +#define CFG_MAWC_ROAM_ENABLED_MAX (1) +#define CFG_MAWC_ROAM_ENABLED_DEFAULT (0) + +/* + * + * 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_MAWC_ROAM_TRAFFIC_THRESHOLD_NAME "mawc_roam_traffic_threshold" +#define CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_MIN (0) +#define CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_MAX (0xFFFFFFFF) +#define CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_DEFAULT (300) + +/* + * + * 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_MAWC_ROAM_AP_RSSI_THRESHOLD_NAME "mawc_roam_ap_rssi_threshold" +#define CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_MIN (-120) +#define CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_MAX (0) +#define CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_DEFAULT (-66) + +/* + * + * 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_MAWC_ROAM_RSSI_HIGH_ADJUST_NAME "mawc_roam_rssi_high_adjust" +#define CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_MIN (3) +#define CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_MAX (5) +#define CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_DEFAULT (5) + +/* + * + * mawc_roam_rssi_high_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_MAWC_ROAM_RSSI_LOW_ADJUST_NAME "mawc_roam_rssi_low_adjust" +#define CFG_MAWC_ROAM_RSSI_LOW_ADJUST_MIN (3) +#define CFG_MAWC_ROAM_RSSI_LOW_ADJUST_MAX (5) +#define CFG_MAWC_ROAM_RSSI_LOW_ADJUST_DEFAULT (5) + +/*This parameter is used to set Wireless Extended Security Mode.*/ +#define CFG_ENABLE_WES_MODE_NAME "gWESModeEnabled" +#define CFG_ENABLE_WES_MODE_NAME_MIN (0) +#define CFG_ENABLE_WES_MODE_NAME_MAX (1) +#define CFG_ENABLE_WES_MODE_NAME_DEFAULT (0) + +#define CFG_TL_DELAYED_TRGR_FRM_INT_NAME "DelayedTriggerFrmInt" +#define CFG_TL_DELAYED_TRGR_FRM_INT_MIN 1 +#define CFG_TL_DELAYED_TRGR_FRM_INT_MAX (4294967295UL) +#define CFG_TL_DELAYED_TRGR_FRM_INT_DEFAULT 3000 + +/* + * + * gRrmEnable - Enable/Disable RRM + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to controls the capabilities (11 k) included + * in the capabilities field. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define CFG_RRM_ENABLE_NAME "gRrmEnable" +#define CFG_RRM_ENABLE_MIN (0) +#define CFG_RRM_ENABLE_MAX (1) +#define CFG_RRM_ENABLE_DEFAULT (0) + +/* + * + * 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_RANDOMIZATION_INTVL_NAME "gRrmRandnIntvl" +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_MIN (10) +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_MAX (100) +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_DEFAULT (100) + +/* + * + * rm_capability - Configure RM enabled capabilities IE + * @Default: 73,10,91,00,04 + * + * 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_NAME "rm_capability" +#define CFG_RM_CAPABILITY_DEFAULT "73,10,91,00,04" + +#define CFG_TELE_BCN_MAX_LI_NAME "telescopicBeaconMaxListenInterval" +#define CFG_TELE_BCN_MAX_LI_MIN (0) +#define CFG_TELE_BCN_MAX_LI_MAX (7) +#define CFG_TELE_BCN_MAX_LI_DEFAULT (5) + +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_NAME "gNeighborLookupThreshold" +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN (10) +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX (120) +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT (78) + +/* + * + * 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_5G_RSSI_THRESHOLD_OFFSET_NAME "lookup_threshold_5g_offset" +#define CFG_5G_RSSI_THRESHOLD_OFFSET_MIN (-120) +#define CFG_5G_RSSI_THRESHOLD_OFFSET_MAX (120) +#define CFG_5G_RSSI_THRESHOLD_OFFSET_DEFAULT (0) + +#define CFG_DELAY_BEFORE_VDEV_STOP_NAME "gDelayBeforeVdevStop" +#define CFG_DELAY_BEFORE_VDEV_STOP_MIN (2) +#define CFG_DELAY_BEFORE_VDEV_STOP_MAX (200) +#define CFG_DELAY_BEFORE_VDEV_STOP_DEFAULT (20) + +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_NAME "gMaxNeighborReqTries" +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MIN (1) +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MAX (4) +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_DEFAULT (3) + +#define CFG_ROAM_BMISS_FIRST_BCNT_NAME "gRoamBmissFirstBcnt" +#define CFG_ROAM_BMISS_FIRST_BCNT_MIN (5) +#define CFG_ROAM_BMISS_FIRST_BCNT_MAX (100) +#define CFG_ROAM_BMISS_FIRST_BCNT_DEFAULT (10) + +#define CFG_ROAM_BMISS_FINAL_BCNT_NAME "gRoamBmissFinalBcnt" +#define CFG_ROAM_BMISS_FINAL_BCNT_MIN (5) +#define CFG_ROAM_BMISS_FINAL_BCNT_MAX (100) +#define CFG_ROAM_BMISS_FINAL_BCNT_DEFAULT (20) + +#define CFG_ROAM_BEACON_RSSI_WEIGHT_NAME "gRoamBeaconRssiWeight" +#define CFG_ROAM_BEACON_RSSI_WEIGHT_MIN (0) +#define CFG_ROAM_BEACON_RSSI_WEIGHT_MAX (16) +#define CFG_ROAM_BEACON_RSSI_WEIGHT_DEFAULT (14) + +/* + * + * 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_NAME "gTelescopicBeaconWakeupEn" +#define CFG_TELE_BCN_WAKEUP_EN_MIN (0) +#define CFG_TELE_BCN_WAKEUP_EN_MAX (1) +#define CFG_TELE_BCN_WAKEUP_EN_DEFAULT (0) + +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_NAME "gApDataAvailPollInterval" +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_MIN (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMIN) +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_MAX (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMAX) +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_DEFAULT (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STADEF) + +#define CFG_ENABLE_HOST_ARPOFFLOAD_NAME "hostArpOffload" +#define CFG_ENABLE_HOST_ARPOFFLOAD_MIN (0) +#define CFG_ENABLE_HOST_ARPOFFLOAD_MAX (1) +#define CFG_ENABLE_HOST_ARPOFFLOAD_DEFAULT (1) + +#define CFG_ENABLE_HOST_SSDP_NAME "ssdp" +#define CFG_ENABLE_HOST_SSDP_MIN (0) +#define CFG_ENABLE_HOST_SSDP_MAX (1) +#define CFG_ENABLE_HOST_SSDP_DEFAULT (1) + +#define CFG_ENABLE_HOST_NSOFFLOAD_NAME "hostNSOffload" +#define CFG_ENABLE_HOST_NSOFFLOAD_MIN (0) +#define CFG_ENABLE_HOST_NSOFFLOAD_MAX (1) +#define CFG_ENABLE_HOST_NSOFFLOAD_DEFAULT (1) + +/* + * + * 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_HW_FILTER_MODE_BITMAP_NAME "gHwFilterMode" +#define CFG_HW_FILTER_MODE_BITMAP_MIN (0) +#define CFG_HW_FILTER_MODE_BITMAP_MAX (3) +#define CFG_HW_FILTER_MODE_BITMAP_DEFAULT (1) + +/* + * + * BandCapability - Preferred band (0: Both, 1: 2.4G only, 2: 5G only) + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set default band capability + * (0: Both, 1: 2.4G only, 2: 5G only) + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_BAND_CAPABILITY_NAME "BandCapability" +#define CFG_BAND_CAPABILITY_MIN (0) +#define CFG_BAND_CAPABILITY_MAX (2) +#define CFG_BAND_CAPABILITY_DEFAULT (0) + +#define CFG_ENABLE_BYPASS_11D_NAME "gEnableBypass11d" +#define CFG_ENABLE_BYPASS_11D_MIN (0) +#define CFG_ENABLE_BYPASS_11D_MAX (1) +#define CFG_ENABLE_BYPASS_11D_DEFAULT (1) + +/* + * + * 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 "gEnableDumpCollect" +#define CFG_ENABLE_RAMDUMP_COLLECTION_MIN (0) +#define CFG_ENABLE_RAMDUMP_COLLECTION_MAX (1) +#define CFG_ENABLE_RAMDUMP_COLLECTION_DEFAULT (1) + +enum hdd_link_speed_rpt_type { + eHDD_LINK_SPEED_REPORT_ACTUAL = 0, + eHDD_LINK_SPEED_REPORT_MAX = 1, + eHDD_LINK_SPEED_REPORT_MAX_SCALED = 2, +}; + +/* + * + * gVhtChannelWidth - Channel width capability for 11ac + * @Min: 0 + * @Max: 4 + * @Default: 3 + * + * 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 "gVhtChannelWidth" +#define CFG_VHT_CHANNEL_WIDTH_MIN (0) +#define CFG_VHT_CHANNEL_WIDTH_MAX (4) +#define CFG_VHT_CHANNEL_WIDTH_DEFAULT (2) + +/* + * + * gVhtRxMCS - VHT Rx MCS capability for 1x1 mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * 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: Internal/External + * + * + */ + +#define CFG_VHT_ENABLE_RX_MCS_8_9 "gVhtRxMCS" +#define CFG_VHT_ENABLE_RX_MCS_8_9_MIN (0) +#define CFG_VHT_ENABLE_RX_MCS_8_9_MAX (2) +#define CFG_VHT_ENABLE_RX_MCS_8_9_DEFAULT (0) + +/* + * + * gVhtTxMCS - VHT Tx MCS capability for 1x1 mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * 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: Internal/External + * + * + */ + +#define CFG_VHT_ENABLE_TX_MCS_8_9 "gVhtTxMCS" +#define CFG_VHT_ENABLE_TX_MCS_8_9_MIN (0) +#define CFG_VHT_ENABLE_TX_MCS_8_9_MAX (2) +#define CFG_VHT_ENABLE_TX_MCS_8_9_DEFAULT (0) + +/* + * + * gVhtRxMCS2x2 - VHT Rx MCS capability for 2x2 mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * 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 "gVhtRxMCS2x2" +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_MIN (0) +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_MAX (2) +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_DEFAULT (0) + +/* + * + * gVhtTxMCS2x2 - VHT Tx MCS capability for 2x2 mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * 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 "gVhtTxMCS2x2" +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_MIN (0) +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_MAX (2) +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_DEFAULT (0) + +/* + * + * 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 "enable_vht20_mcs9" +#define CFG_ENABLE_VHT20_MCS9_MIN (0) +#define CFG_ENABLE_VHT20_MCS9_MAX (1) +#define CFG_ENABLE_VHT20_MCS9_DEFAULT (1) + +/* + * + * gEnable2x2 - Enables/disables VHT Tx/Rx MCS values for 2x2 + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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 "gEnable2x2" +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_DEFAULT (0) + +/* + * + * 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 "enableBTChainSeparation" +#define CFG_ENABLE_BT_CHAIN_SEPARATION_MIN (0) +#define CFG_ENABLE_BT_CHAIN_SEPARATION_MAX (1) +#define CFG_ENABLE_BT_CHAIN_SEPARATION_DEFAULT (0) + +/* + * + * 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 "disable_high_ht_mcs_2x2" +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MIN (0) +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MAX (8) +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2_DEFAULT (0) + +/* + * + * gStaPrefer80MHzOver160MHz - set Sta perferance to connect in 80HZ/160HZ + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set Sta perferance 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 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ "gStaPrefer80MHzOver160MHz" +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ_MIN (0) +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ_MAX (1) +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ_DEFAULT (1) + +/* + * + * gEnableMuBformee - Enables/disables multi-user (MU) beam formee capability + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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 "gEnableMuBformee" +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_DEFAULT (0) + +#define CFG_VHT_ENABLE_PAID_FEATURE "gEnablePAID" +#define CFG_VHT_ENABLE_PAID_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_PAID_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_PAID_FEATURE_DEFAULT (0) + +#define CFG_VHT_ENABLE_GID_FEATURE "gEnableGID" +#define CFG_VHT_ENABLE_GID_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_GID_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_GID_FEATURE_DEFAULT (0) + +/* + * + * gSetTxChainmask1x1 - Sets Transmit chain mask. + * @Min: 1 + * @Max: 3 + * @Default: 0 + * + * 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 "gSetTxChainmask1x1" +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MIN (0) +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MAX (3) +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_DEFAULT (0) + +/* + * + * gSetRxChainmask1x1 - Sets Receive chain mask. + * @Min: 1 + * @Max: 3 + * @Default: 0 + * + * 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 "gSetRxChainmask1x1" +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MIN (0) +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MAX (3) +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_DEFAULT (0) + +/* + * + * gEnableAMPDUPS - Enable the AMPDUPS + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default AMPDUPS + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_AMPDUPS_FEATURE "gEnableAMPDUPS" +#define CFG_ENABLE_AMPDUPS_FEATURE_MIN (0) +#define CFG_ENABLE_AMPDUPS_FEATURE_MAX (1) +#define CFG_ENABLE_AMPDUPS_FEATURE_DEFAULT (0) + +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE "gEnableHtSMPS" +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_MIN (0) +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_MAX (1) +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_DEFAULT (0) + +#define CFG_HT_SMPS_CAP_FEATURE "gHtSMPS" +#define CFG_HT_SMPS_CAP_FEATURE_MIN (0) +#define CFG_HT_SMPS_CAP_FEATURE_MAX (3) +#define CFG_HT_SMPS_CAP_FEATURE_DEFAULT (3) + +/* + * + * 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 "gDisableDFSChSwitch" +#define CFG_DISABLE_DFS_CH_SWITCH_MIN (0) +#define CFG_DISABLE_DFS_CH_SWITCH_MAX (1) +#define CFG_DISABLE_DFS_CH_SWITCH_DEFAULT (0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_DFS_MASTER_CAPABILITY "gEnableDFSMasterCap" +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_MIN (0) +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_MAX (1) +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_DEFAULT (0) + +/* + * + * 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_PREFERRED_CHANNEL_LOCATION "gSapPreferredChanLocation" +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_MIN (0) +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_MAX (2) +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_DEFAULT (0) + +/* + * + * 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: NA. + * + * Supported Feature: DFS + * + * Usage: Internal/External + * + * + */ +#define CFG_DISABLE_DFS_JAPAN_W53 "gDisableDfsJapanW53" +#define CFG_DISABLE_DFS_JAPAN_W53_MIN (0) +#define CFG_DISABLE_DFS_JAPAN_W53_MAX (1) +#define CFG_DISABLE_DFS_JAPAN_W53_DEFAULT (0) + +/* + * + * gDisableDfsJapanW53 - Enable dfs phyerror filtering offload in FW + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME "dfsPhyerrFilterOffload" +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN (0) +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX (1) +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT (0) + +#define CFG_REPORT_MAX_LINK_SPEED "gReportMaxLinkSpeed" +#define CFG_REPORT_MAX_LINK_SPEED_MIN (eHDD_LINK_SPEED_REPORT_ACTUAL) +#define CFG_REPORT_MAX_LINK_SPEED_MAX (eHDD_LINK_SPEED_REPORT_MAX_SCALED) +#define CFG_REPORT_MAX_LINK_SPEED_DEFAULT (eHDD_LINK_SPEED_REPORT_ACTUAL) + +/* + * + * gLinkSpeedRssiHigh - Report the max possible speed with RSSI scaling + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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 "gLinkSpeedRssiHigh" +#define CFG_LINK_SPEED_RSSI_HIGH_MIN (-127) +#define CFG_LINK_SPEED_RSSI_HIGH_MAX (0) +#define CFG_LINK_SPEED_RSSI_HIGH_DEFAULT (-55) + +/* + * + * 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 "gLinkSpeedRssiMed" +#define CFG_LINK_SPEED_RSSI_MID_MIN (-127) +#define CFG_LINK_SPEED_RSSI_MID_MAX (0) +#define CFG_LINK_SPEED_RSSI_MID_DEFAULT (-65) + +/* + * + * 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 "gLinkSpeedRssiLow" +#define CFG_LINK_SPEED_RSSI_LOW_MIN (-127) +#define CFG_LINK_SPEED_RSSI_LOW_MAX (0) +#define CFG_LINK_SPEED_RSSI_LOW_DEFAULT (-80) + +/* + * + * 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. + * + * Supported Feature: P2P + * + * Usage: Internal/External + * + * + */ + +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_NAME "isP2pDeviceAddrAdministrated" +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MIN (0) +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MAX (1) +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_DEFAULT (1) + +/* + * + * gEnableSSR - Enable/Disable SSR + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable System Self Recovery at the times of + * System crash or fatal errors + * gEnableSSR = 0 Disabled + * gEnableSSR = 1 wlan shutdown and re-init happens + * + * Related: None + * + * Supported Feature: SSR + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SSR "gEnableSSR" +#define CFG_ENABLE_SSR_MIN (0) +#define CFG_ENABLE_SSR_MAX (1) +#define CFG_ENABLE_SSR_DEFAULT (1) + +/** + * + * gEnableDataStallDetection - Enable/Disable Data stall detection + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable data stall detection + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_DATA_STALL_DETECTION "gEnableDataStallDetection" +#define CFG_ENABLE_DATA_STALL_DETECTION_MIN (0) +#define CFG_ENABLE_DATA_STALL_DETECTION_MAX (1) +#define CFG_ENABLE_DATA_STALL_DETECTION_DEFAULT (1) + +/* + * + * gEnableOverLapCh - Enables Overlap Channel. If set, allow overlapping + * channels to be selected for the SoftAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set Overlap Channel + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_OVERLAP_CH "gEnableOverLapCh" +#define CFG_ENABLE_OVERLAP_CH_MIN (0) +#define CFG_ENABLE_OVERLAP_CH_MAX (1) +#define CFG_ENABLE_OVERLAP_CH_DEFAULT (0) + +/* + * + * 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 "gEnable5gEBT" +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_MIN (0) +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_MAX (1) +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_DEFAULT (1) + +#define CFG_ENABLE_MEMORY_DEEP_SLEEP "gEnableMemDeepSleep" +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_MIN (0) +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_MAX (1) +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_DEFAULT (1) + +/* + * + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_CCK_TX_FIR_OVERRIDE_NAME "gEnableCckTxFirOverride" +#define CFG_ENABLE_CCK_TX_FIR_OVERRIDE_MIN (0) +#define CFG_ENABLE_CCK_TX_FIR_OVERRIDE_MAX (1) +#define CFG_ENABLE_CCK_TX_FIR_OVERRIDE_DEFAULT (0) + +#ifndef REMOVE_PKT_LOG +#define CFG_ENABLE_PACKET_LOG "gEnablePacketLog" +#define CFG_ENABLE_PACKET_LOG_MIN (0) +#define CFG_ENABLE_PACKET_LOG_MAX (1) +#ifdef FEATURE_PKTLOG +#define CFG_ENABLE_PACKET_LOG_DEFAULT (1) +#else +#define CFG_ENABLE_PACKET_LOG_DEFAULT (0) +#endif +#endif + + +/* gFwDebugLogType takes values from enum dbglog_process_t, + * make default value as DBGLOG_PROCESS_NET_RAW to give the + * logs to net link since cnss_diag service is started at boot + * time by default. + */ +#define CFG_ENABLE_FW_LOG_TYPE "gFwDebugLogType" +#define CFG_ENABLE_FW_LOG_TYPE_MIN (0) +#define CFG_ENABLE_FW_LOG_TYPE_MAX (255) +#define CFG_ENABLE_FW_LOG_TYPE_DEFAULT (3) + +/* gFwDebugLogLevel takes values from enum DBGLOG_LOG_LVL, + * make default value as DBGLOG_WARN to enable error and + * warning logs by default. + */ +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL "gFwDebugLogLevel" +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MIN (0) +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MAX (255) +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_DEFAULT (3) + +/* For valid values of log levels check enum DBGLOG_LOG_LVL and + * for valid values of module ids check enum WLAN_MODULE_ID. + */ +#define CFG_ENABLE_FW_MODULE_LOG_LEVEL "gFwDebugModuleLoglevel" +#define CFG_ENABLE_FW_MODULE_LOG_DEFAULT "2,1,3,1,5,1,9,1,13,1,14,1,18,1,19,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,4,1" + +/* + * + * 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/External + * + * + */ + +#define CFG_ENABLE_CONCURRENT_STA "gEnableConcurrentSTA" +#define CFG_ENABLE_CONCURRENT_STA_DEFAULT "" + +/* + * + * 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 "gEnableRTSProfiles" +#define CFG_ENABLE_FW_RTS_PROFILE_MIN (0) +#define CFG_ENABLE_FW_RTS_PROFILE_MAX (66) +#define CFG_ENABLE_FW_RTS_PROFILE_DEFAULT (33) + + +/* + * QDF Trace Enable Control + * Notes: + * the MIN/MAX/DEFAULT values apply for all modules + * the DEFAULT value is outside the valid range. if the DEFAULT + * value is not overridden, then no change will be made to the + * "built in" default values compiled into the code + * values are a bitmap indicating which log levels are to enabled + * (must match order of qdf_trace_level enumerations) + * 00000001 FATAL + * 00000010 ERROR + * 00000100 WARN + * 00001000 INFO + * 00010000 INFO HIGH + * 00100000 INFO MED + * 01000000 INFO LOW + * 10000000 DEBUG + * + * hence a value of 0xFF would set all bits (enable all logs) + */ + +#define CFG_QDF_TRACE_ENABLE_WDI_NAME "qdf_trace_enable_wdi" +#define CFG_QDF_TRACE_ENABLE_HDD_NAME "qdf_trace_enable_hdd" +#define CFG_QDF_TRACE_ENABLE_SME_NAME "qdf_trace_enable_sme" +#define CFG_QDF_TRACE_ENABLE_PE_NAME "qdf_trace_enable_pe" +#define CFG_QDF_TRACE_ENABLE_PMC_NAME "qdf_trace_enable_pmc" +#define CFG_QDF_TRACE_ENABLE_WMA_NAME "qdf_trace_enable_wma" +#define CFG_QDF_TRACE_ENABLE_SYS_NAME "qdf_trace_enable_sys" +#define CFG_QDF_TRACE_ENABLE_QDF_NAME "qdf_trace_enable_qdf" +#define CFG_QDF_TRACE_ENABLE_SAP_NAME "qdf_trace_enable_sap" +#define CFG_QDF_TRACE_ENABLE_HDD_SAP_NAME "qdf_trace_enable_hdd_sap" +#define CFG_QDF_TRACE_ENABLE_BMI_NAME "qdf_trace_enable_bmi" +#define CFG_QDF_TRACE_ENABLE_CFG_NAME "qdf_trace_enable_cfg" +#define CFG_QDF_TRACE_ENABLE_EPPING "qdf_trace_enable_epping" +#define CFG_QDF_TRACE_ENABLE_QDF_DEVICES "qdf_trace_enable_qdf_devices" +#define CFG_QDF_TRACE_ENABLE_TXRX_NAME "qdf_trace_enable_txrx" +#define CFG_QDF_TRACE_ENABLE_DP_NAME "qdf_trace_enable_dp" +#define CFG_QDF_TRACE_ENABLE_HTC_NAME "qdf_trace_enable_htc" +#define CFG_QDF_TRACE_ENABLE_HIF_NAME "qdf_trace_enable_hif" +#define CFG_CDR_TRACE_ENABLE_HDD_SAP_DATA_NAME "qdf_trace_enable_hdd_sap_data" +#define CFG_QDF_TRACE_ENABLE_HDD_DATA_NAME "qdf_trace_enable_hdd_data" +#define CFG_QDF_TRACE_ENABLE_WIFI_POS "qdf_trace_enable_wifi_pos" +#define CFG_QDF_TRACE_ENABLE_NAN "qdf_trace_enable_nan" +#define CFG_QDF_TRACE_ENABLE_REGULATORY "qdf_trace_enable_regulatory" +#define CFG_QDF_TRACE_ENABLE_CP_STATS "qdf_trace_enable_cp_stats" + +#define CFG_QDF_TRACE_ENABLE_MIN (0) +#define CFG_QDF_TRACE_ENABLE_MAX (0xff) +#define CFG_QDF_TRACE_ENABLE_DEFAULT (0xffff) +/* disable debug logs for DP by default */ +#define CFG_QDF_TRACE_ENABLE_DP_DEFAULT (0x7f) + +#ifdef ENABLE_MTRACE_LOG +/* + * Enable MTRACE for all modules + */ +#define CFG_ENABLE_MTRACE "enable_mtrace" +#define CFG_ENABLE_MTRACE_MIN (0) +#define CFG_ENABLE_MTRACE_MAX (1) +#define CFG_ENABLE_MTRACE_DEFAULT (0) +#endif + +#define HDD_MCASTBCASTFILTER_FILTER_NONE 0x00 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST 0x01 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST 0x02 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST_BROADCAST 0x03 +#define HDD_MULTICAST_FILTER_LIST 0x04 +#define HDD_MULTICAST_FILTER_LIST_CLEAR 0x05 + +/* + * Enable Dynamic DTIM + * Options + * 0 -Disable DynamicDTIM + * 1 to 5 - SLM will switch to DTIM specified here when host suspends and + * switch DTIM1 when host resumes + */ +#define CFG_ENABLE_DYNAMIC_DTIM_NAME "gEnableDynamicDTIM" +#define CFG_ENABLE_DYNAMIC_DTIM_MIN (0) +#define CFG_ENABLE_DYNAMIC_DTIM_MAX (9) +#define CFG_ENABLE_DYNAMIC_DTIM_DEFAULT (0) + +/* + * + * 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 "gConfigVCmode" +#define CFG_VC_MODE_BITMAP_MIN (0x00000000) +#define CFG_VC_MODE_BITMAP_MAX (0x0fffffff) +#define CFG_VC_MODE_BITMAP_DEFAULT (0x00000005) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST "gEnableSAPManadatoryChanList" +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MIN (0) +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MAX (1) +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_DEFAULT (0) + +/* + * Skip DFS Channel in case of P2P Search + * Options + * 0 - Don't Skip DFS Channel in case of P2P Search + * 1 - Skip DFS Channel in case of P2P Search + */ +/* + * + * gSkipDfsChannelInP2pSearch - Skip DFS Channel in case of P2P Search + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to to disable(skip) dfs channel in p2p search. + * Related: NA. + * + * Supported Feature: DFS P2P + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_NAME "gSkipDfsChannelInP2pSearch" +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MIN (0) +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MAX (1) +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_DEFAULT (1) +/* + * + * gIgnoreDynamicDtimInP2pMode - Ignore Dynamic Dtim in case of P2P + * Options. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to decide if Dynamic Dtim needs to be consider or + * not in case of P2P. + * 0 - Consider Dynamic Dtim incase of P2P + * 1 - Ignore Dynamic Dtim incase of P2P + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ + +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_NAME "gIgnoreDynamicDtimInP2pMode" +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MIN (0) +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MAX (1) +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_DEFAULT (0) + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_SHORT_GI_40MHZ_NAME "gShortGI40Mhz" +#define CFG_SHORT_GI_40MHZ_MIN 0 +#define CFG_SHORT_GI_40MHZ_MAX 1 +#define CFG_SHORT_GI_40MHZ_DEFAULT 1 + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_MCC_ENABLED_NAME "gEnableMCCMode" +#define CFG_ENABLE_MCC_ENABLED_MIN (0) +#define CFG_ENABLE_MCC_ENABLED_MAX (1) +#define CFG_ENABLE_MCC_ENABLED_DEFAULT (1) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_ALLOW_MCC_GO_DIFF_BI_NAME "gAllowMCCGODiffBI" +#define CFG_ALLOW_MCC_GO_DIFF_BI_MIN (0) +#define CFG_ALLOW_MCC_GO_DIFF_BI_MAX (4) +#define CFG_ALLOW_MCC_GO_DIFF_BI_DEFAULT (4) + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) +/* + * Enable/Disable Bad Peer TX CTL feature + * Default: Enable + */ +#define CFG_BAD_PEER_TX_CTL_ENABLE_NAME "gBadPeerTxCtlEnable" +#define CFG_BAD_PEER_TX_CTL_ENABLE_MIN (0) +#define CFG_BAD_PEER_TX_CTL_ENABLE_MAX (1) +#define CFG_BAD_PEER_TX_CTL_ENABLE_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_PERIOD_NAME "gBadPeerTxCtlPeriod" +#define CFG_BAD_PEER_TX_CTL_PERIOD_MIN (10) +#define CFG_BAD_PEER_TX_CTL_PERIOD_MAX (10000) +#define CFG_BAD_PEER_TX_CTL_PERIOD_DEFAULT (50) + +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_NAME "gBadPeerTxCtlTxqLimit" +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_DEFAULT (100) + +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_NAME "gBadPeerTxCtlTgtBackoffTime" +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_DEFAULT (20) + +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_NAME "gBadPeerTxCtlTgtReportPeriod" +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_DEFAULT (500) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_NAME "gBadPeerTxCtlCondLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_NAME "gBadPeerTxCtlDeltaLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_MAX (11) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_NAME "gBadPeerTxCtlPctLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_NAME "gBadPeerTxCtlTputLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_MAX (11) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_NAME "gBadPeerTxCtlTxLimitLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_NAME "gBadPeerTxCtlCondLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_NAME "gBadPeerTxCtlDeltaLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_MAX (54) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlPctLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlTputLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_MAX (54) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlTxLimitLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_NAME "gBadPeerTxCtlCondLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_NAME "gBadPeerTxCtlDeltaLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_MAX (72) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_NAME "gBadPeerTxCtlPctLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_NAME "gBadPeerTxCtlTputLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_MAX (72) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_DEFAULT (15) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_NAME "gBadPeerTxCtlTxLimitLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_NAME "gBadPeerTxCtlCondLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_NAME "gBadPeerTxCtlDeltaLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_MAX (433) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlPctLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlTputLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_MAX (433) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_DEFAULT (15) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlTxLimitLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_DEFAULT (3) +#endif + + +/* + * Enable/Disable Thermal Mitigation feature + * Default: Enable + */ +#define CFG_THERMAL_MIGRATION_ENABLE_NAME "gThermalMitigationEnable" +#define CFG_THERMAL_MIGRATION_ENABLE_MIN (0) +#define CFG_THERMAL_MIGRATION_ENABLE_MAX (1) +#define CFG_THERMAL_MIGRATION_ENABLE_DEFAULT (0) + +#define CFG_THROTTLE_PERIOD_NAME "gThrottlePeriod" +#define CFG_THROTTLE_PERIOD_MIN (10) +#define CFG_THROTTLE_PERIOD_MAX (10000) +#define CFG_THROTTLE_PERIOD_DEFAULT (4000) + +/* + * Configure Throttle Period Different Level Duty Cycle in percentage + * When temperature measured is greater than threshold at particular level, + * then throtling level will get increased by one level and + * will reduce TX duty by the given percentage + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_NAME "gThrottleDutyCycleLevel0" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MAX (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_DEFAULT (0) + +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_NAME "gThrottleDutyCycleLevel1" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MAX (100) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_DEFAULT (50) + +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_NAME "gThrottleDutyCycleLevel2" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MAX (100) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_DEFAULT (75) + +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_NAME "gThrottleDutyCycleLevel3" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MAX (100) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_DEFAULT (94) + +#define CFG_THERMAL_TEMP_MIN_LEVEL0_NAME "gThermalTempMinLevel0" +#define CFG_THERMAL_TEMP_MIN_LEVEL0_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL0_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL0_DEFAULT (0) + +#define CFG_THERMAL_TEMP_MAX_LEVEL0_NAME "gThermalTempMaxLevel0" +#define CFG_THERMAL_TEMP_MAX_LEVEL0_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL0_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL0_DEFAULT (90) + +#define CFG_THERMAL_TEMP_MIN_LEVEL1_NAME "gThermalTempMinLevel1" +#define CFG_THERMAL_TEMP_MIN_LEVEL1_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL1_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL1_DEFAULT (70) + +#define CFG_THERMAL_TEMP_MAX_LEVEL1_NAME "gThermalTempMaxLevel1" +#define CFG_THERMAL_TEMP_MAX_LEVEL1_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL1_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL1_DEFAULT (110) + +#define CFG_THERMAL_TEMP_MIN_LEVEL2_NAME "gThermalTempMinLevel2" +#define CFG_THERMAL_TEMP_MIN_LEVEL2_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL2_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL2_DEFAULT (90) + +#define CFG_THERMAL_TEMP_MAX_LEVEL2_NAME "gThermalTempMaxLevel2" +#define CFG_THERMAL_TEMP_MAX_LEVEL2_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL2_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL2_DEFAULT (125) + +#define CFG_THERMAL_TEMP_MIN_LEVEL3_NAME "gThermalTempMinLevel3" +#define CFG_THERMAL_TEMP_MIN_LEVEL3_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL3_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL3_DEFAULT (110) + +#define CFG_THERMAL_TEMP_MAX_LEVEL3_NAME "gThermalTempMaxLevel3" +#define CFG_THERMAL_TEMP_MAX_LEVEL3_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL3_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL3_DEFAULT (0) + +/* + * Enable/Disable Modulated DTIM feature + * Default: Disable + */ +#define CFG_ENABLE_MODULATED_DTIM_NAME "gEnableModulatedDTIM" +#define CFG_ENABLE_MODULATED_DTIM_MIN (0) +#define CFG_ENABLE_MODULATED_DTIM_MAX (5) +#define CFG_ENABLE_MODULATED_DTIM_DEFAULT (0) + +/* + * + * gMCAddrListEnable - Enable/Disable Multicast MAC Address List feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default MAC Address + * Default: Enable + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_MC_ADDR_LIST_ENABLE_NAME "gMCAddrListEnable" +#define CFG_MC_ADDR_LIST_ENABLE_MIN (0) +#define CFG_MC_ADDR_LIST_ENABLE_MAX (1) +#define CFG_MC_ADDR_LIST_ENABLE_DEFAULT (1) + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_ENABLE_RX_STBC "gEnableRXSTBC" +#define CFG_ENABLE_RX_STBC_MIN (0) +#define CFG_ENABLE_RX_STBC_MAX (1) +#define CFG_ENABLE_RX_STBC_DEFAULT (1) + +/* + * + * gEnableTXSTBC - Enables/disables Tx STBC capability in STA mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Tx STBC capability + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_TX_STBC "gEnableTXSTBC" +#define CFG_ENABLE_TX_STBC_MIN (0) +#define CFG_ENABLE_TX_STBC_MAX (1) +#define CFG_ENABLE_TX_STBC_DEFAULT (0) + +/* + * + * 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 "gMaxHTMCSForTxData" +#define CFG_MAX_HT_MCS_FOR_TX_DATA_MIN (WNI_CFG_MAX_HT_MCS_TX_DATA_STAMIN) +#define CFG_MAX_HT_MCS_FOR_TX_DATA_MAX (WNI_CFG_MAX_HT_MCS_TX_DATA_STAMAX) +#define CFG_MAX_HT_MCS_FOR_TX_DATA_DEFAULT (WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF) + +/* + * + * 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: 0 + * + * This ini is used to enable/disable remote peer info query support + * + * Usage: External + * + * + */ +#define CFG_SAP_GET_PEER_INFO "gSapGetPeerInfo" +#define CFG_SAP_GET_PEER_INFO_MIN (0) +#define CFG_SAP_GET_PEER_INFO_MAX (1) +#define CFG_SAP_GET_PEER_INFO_DEFAULT (0) + +/* + * + * 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 "gDisableABGRateForTxData" +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MIN \ + (WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMIN) +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MAX \ + (WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMAX) +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA_DEFAULT \ + (WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF) + +/* + * + * gRateForTxMgmt - rate for tx mgmt frame + * @Min: 0x0 + * @Max: 0xFF + * @Default: 0xFF + * + * This ini is used to configure the rate for tx + * mgmt frame. Default 0xFF means disable. + * + * Usage: External + * + * + */ +#define CFG_RATE_FOR_TX_MGMT "gRateForTxMgmt" +#define CFG_RATE_FOR_TX_MGMT_MIN (WNI_CFG_RATE_FOR_TX_MGMT_STAMIN) +#define CFG_RATE_FOR_TX_MGMT_MAX (WNI_CFG_RATE_FOR_TX_MGMT_STAMAX) +#define CFG_RATE_FOR_TX_MGMT_DEFAULT (WNI_CFG_RATE_FOR_TX_MGMT_STADEF) + +/* + * + * gRateForTxMgmt2G - rate for tx mgmt frame on 2G + * @Min: 0x0 + * @Max: 0xFF + * @Default: 0xFF + * + * This ini is used to configure the rate for tx + * mgmt frame on 2G Band. Default 0xFF means disable. + * It has higher priority and will overwrite gRateForTxMgmt + * setting. + * + * Usage: External + * + * + */ +#define CFG_RATE_FOR_TX_MGMT_2G "gRateForTxMgmt2G" +#define CFG_RATE_FOR_TX_MGMT_2G_MIN (WNI_CFG_RATE_FOR_TX_MGMT_2G_STAMIN) +#define CFG_RATE_FOR_TX_MGMT_2G_MAX (WNI_CFG_RATE_FOR_TX_MGMT_2G_STAMAX) +#define CFG_RATE_FOR_TX_MGMT_2G_DEFAULT (WNI_CFG_RATE_FOR_TX_MGMT_2G_STADEF) + +/* + * + * gRateForTxMgmt5G - rate for tx mgmt frame on 5G + * @Min: 0x0 + * @Max: 0xFF + * @Default: 0xFF + * + * This ini is used to configure the rate for tx + * mgmt frame on 5G Band. Default 0xFF means disable. + * It has higher priority and will overwrite gRateForTxMgmt + * setting. + * + * Usage: External + * + * + */ +#define CFG_RATE_FOR_TX_MGMT_5G "gRateForTxMgmt5G" +#define CFG_RATE_FOR_TX_MGMT_5G_MIN (WNI_CFG_RATE_FOR_TX_MGMT_5G_STAMIN) +#define CFG_RATE_FOR_TX_MGMT_5G_MAX (WNI_CFG_RATE_FOR_TX_MGMT_5G_STAMAX) +#define CFG_RATE_FOR_TX_MGMT_5G_DEFAULT (WNI_CFG_RATE_FOR_TX_MGMT_5G_STADEF) + +/* + * + * 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 + * + * + */ +#define CFG_PREVENT_LINK_DOWN_NAME "gPreventLinkDown" +#define CFG_PREVENT_LINK_DOWN_MIN (0) +#define CFG_PREVENT_LINK_DOWN_MAX (1) +#if defined(QCA_WIFI_NAPIER_EMULATION) || defined(QCA_WIFI_QCA6290) +#define CFG_PREVENT_LINK_DOWN_DEFAULT (1) +#else +#define CFG_PREVENT_LINK_DOWN_DEFAULT (0) +#endif /* QCA_WIFI_NAPIER_EMULATION */ + +#ifdef FEATURE_WLAN_TDLS +/* + * + * gEnableTDLSSupport - Enable support for TDLS. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable TDLS support. + * + * Related: None. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_SUPPORT_ENABLE "gEnableTDLSSupport" +#define CFG_TDLS_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_SUPPORT_ENABLE_DEFAULT (0) + +/* + * + * gEnableTDLSImplicitTrigger - Enable Implicit TDLS. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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 "gEnableTDLSImplicitTrigger" +#define CFG_TDLS_IMPLICIT_TRIGGER_MIN (0) +#define CFG_TDLS_IMPLICIT_TRIGGER_MAX (1) +#define CFG_TDLS_IMPLICIT_TRIGGER_DEFAULT (0) + +/* + * + * 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 "gTDLSTxStatsPeriod" +#define CFG_TDLS_TX_STATS_PERIOD_MIN (1000) +#define CFG_TDLS_TX_STATS_PERIOD_MAX (4294967295UL) +#define CFG_TDLS_TX_STATS_PERIOD_DEFAULT (2000) + +/* + * + * 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 "gTDLSTxPacketThreshold" +#define CFG_TDLS_TX_PACKET_THRESHOLD_MIN (0) +#define CFG_TDLS_TX_PACKET_THRESHOLD_MAX (4294967295UL) +#define CFG_TDLS_TX_PACKET_THRESHOLD_DEFAULT (40) + +/* + * + * 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 "gTDLSMaxDiscoveryAttempt" +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN (1) +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX (100) +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_DEFAULT (5) + +/* + * + * 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 "gTDLSIdleTimeout" +#define CFG_TDLS_IDLE_TIMEOUT_MIN (500) +#define CFG_TDLS_IDLE_TIMEOUT_MAX (40000) +#define CFG_TDLS_IDLE_TIMEOUT_DEFAULT (5000) + + +/* + * + * 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 "gTDLSIdlePacketThreshold" +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN (0) +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX (40000) +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_DEFAULT (3) + +/* + * + * 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 "gTDLSRSSITriggerThreshold" +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN (-120) +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX (0) +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_DEFAULT (-75) + +/* + * + * 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 "gTDLSRSSITeardownThreshold" +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN (-120) +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX (0) +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_DEFAULT (-75) + +/* + * + * gTDLSRSSIDelta - Delta value for the peer RSSI that can trigger teardown. + * @Min: -30 + * @Max: 0 + * @Default: -20 + * + * This ini is used to . + * 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 "gTDLSRSSIDelta" +#define CFG_TDLS_RSSI_DELTA_MIN (-30) +#define CFG_TDLS_RSSI_DELTA_MAX (0) +#define CFG_TDLS_RSSI_DELTA_DEFAULT (-20) + +/* + * + * 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_NAME "gTDLSUapsdMask" +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_MIN (0) +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_MAX (0x0F) +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_DEFAULT (0x0F) + +/* + * + * 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_BUFFER_STA_SUPPORT_ENABLE "gEnableTDLSBufferSta" +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_DEFAULT (1) + +/* + * + * gTDLSPuapsdInactivityTime - Peer UAPSD Inactivity time. + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to configure peer uapsd inactivity time. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME "gTDLSPuapsdInactivityTime" +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_MIN (0) +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_MAX (10) +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_DEFAULT (0) + +/* + * + * 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_PUAPSD_RX_FRAME_THRESHOLD "gTDLSPuapsdRxFrameThreshold" +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MIN (10) +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MAX (20) +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_DEFAULT (10) + +/* + * + * 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 "gTDLSPuapsdPTIWindow" +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MIN (1) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MAX (5) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_DEFAULT (2) + +/* + * + * gTDLSPuapsdPTRTimeout - Peer Traffic Response timer duration in ms. + * @Min: 0 + * @Max: 10000 + * @Default: 5000 + * + * This ini is used to configure the peer traffic response timer duration + * in ms. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT "gTDLSPuapsdPTRTimeout" +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MIN (0) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MAX (10000) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_DEFAULT (5000) + +/* + * + * gTDLSExternalControl - Enable external TDLS control. + * @Min: 0 + * @Max: 1 + * @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. + * + * Related: gEnableTDLSSupport, gEnableTDLSImplicitTrigger. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_EXTERNAL_CONTROL "gTDLSExternalControl" +#define CFG_TDLS_EXTERNAL_CONTROL_MIN (0) +#define CFG_TDLS_EXTERNAL_CONTROL_MAX (1) +#define CFG_TDLS_EXTERNAL_CONTROL_DEFAULT (1) + +/* + * This INI item is used to control subsystem restart(SSR) test framework + * Set it's value to 1 to enable APPS trigerred SSR testing + */ +#define CFG_ENABLE_CRASH_INJECT "gEnableForceTargetAssert" +#define CFG_ENABLE_CRASH_INJECT_MIN (0) +#define CFG_ENABLE_CRASH_INJECT_MAX (1) +#define CFG_ENABLE_CRASH_INJECT_DEFAULT (0) + +/* + * + * gEnableTDLSOffChannel - Enables off-channel support for TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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_SUPPORT_ENABLE "gEnableTDLSOffChannel" +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_DEFAULT (0) + +/* + * + * 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 "gEnableTDLSWmmMode" +#define CFG_TDLS_WMM_MODE_ENABLE_MIN (0) +#define CFG_TDLS_WMM_MODE_ENABLE_MAX (1) +#define CFG_TDLS_WMM_MODE_ENABLE_DEFAULT (1) + +/* + * + * 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 "gTDLSPrefOffChanNum" +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN (1) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX (165) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT (36) + +/* + * + * gTDLSPrefOffChanBandwidth - Preferred TDLS channel bandwidth when + * off-channel support is enabled. + * @Min: 0x01 + * @Max: 0x0F + * @Default: 0x07 + * + * 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. + * + * Related: gEnableTDLSSupport, gEnableTDLSOffChannel. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW "gTDLSPrefOffChanBandwidth" +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MIN (0x01) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MAX (0x0F) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_DEFAULT (0x07) + +/* + * + * gEnableTDLSScan - Allow scan and maintain TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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 "gEnableTDLSScan" +#define CFG_TDLS_SCAN_ENABLE_MIN (0) +#define CFG_TDLS_SCAN_ENABLE_MAX (1) +#define CFG_TDLS_SCAN_ENABLE_DEFAULT (1) + +/* + * + * gTDLSPeerKickoutThreshold - TDLS peer kickout threshold to firmware. + * @Min: 10 + * @Max: 5000 + * @Default: 96 + * + * This ini is used to configure TDLS peer kickout 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 kickout + * notification to host driver + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD "gTDLSPeerKickoutThreshold" +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD_MIN (10) +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD_MAX (5000) +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD_DEFAULT (96) + +#endif + +/* + * + * 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 "gTDLSEnableDeferTime" +#define CFG_TDLS_ENABLE_DEFER_TIMER_MIN (500) +#define CFG_TDLS_ENABLE_DEFER_TIMER_MAX (6000) +#define CFG_TDLS_ENABLE_DEFER_TIMER_DEFAULT (2000) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_TX_LDPC_ENABLE_FEATURE "gTxLdpcEnable" +#define CFG_TX_LDPC_ENABLE_FEATURE_MIN (0) +#define CFG_TX_LDPC_ENABLE_FEATURE_MAX (3) +#define CFG_TX_LDPC_ENABLE_FEATURE_DEFAULT (3) + +/* + * + * gEnableRXLDPC - Config Param to enable Rx LDPC capability + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable Rx LDPC capability + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Concurrency/Standalone + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_RX_LDPC "gEnableRXLDPC" +#define CFG_ENABLE_RX_LDPC_MIN (0) +#define CFG_ENABLE_RX_LDPC_MAX (1) +#define CFG_ENABLE_RX_LDPC_DEFAULT (0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_NAME "gEnableMCCAdaptiveScheduler" +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MIN (0) +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MAX (1) +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_DEFAULT (1) + +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE "gTxBFEnable" +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MIN (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN) +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MAX (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX) +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_DEFAULT (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF) + +/* + * + * 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_NAME "enable_subfee_vendor_vhtie" +#define CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE_MIN (0) +#define CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE_MAX (1) +#define CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE_DEFAULT (1) + +/* + * Enable / Disable Tx beamformee in SAP mode + * Default: Disable + */ +#define CFG_VHT_ENABLE_TXBF_SAP_MODE "gEnableTxBFeeSAP" +#define CFG_VHT_ENABLE_TXBF_SAP_MODE_MIN (0) +#define CFG_VHT_ENABLE_TXBF_SAP_MODE_MAX (1) +#define CFG_VHT_ENABLE_TXBF_SAP_MODE_DEFAULT (0) + +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED "gTxBFCsnValue" +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MIN (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN) +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MAX (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX - 1) +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_DEFAULT (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF - 1) + +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ "gEnableTxBFin20MHz" +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_MIN (0) +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_MAX (1) +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_DEFAULT (0) + +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER "gEnableTxSUBeamformer" +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MIN (0) +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MAX (1) +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_DEFAULT (0) + +/* Enable debug for remain on channel issues */ +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_NAME "gDebugP2pRemainOnChannel" +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_DEFAULT (0) +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MIN (0) +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MAX (1) + +/* + * SAP ALLOW All Channels + */ +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_NAME "gSapAllowAllChannel" +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MIN (0) +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MAX (1) +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_DEFAULT (0) + +#define CFG_DISABLE_LDPC_WITH_TXBF_AP "gDisableLDPCWithTxbfAP" +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_MIN (0) +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_MAX (1) +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_DEFAULT (0) + +/* Parameter to control VHT support in 2.4 GHz band */ +#define CFG_ENABLE_VHT_FOR_24GHZ_NAME "gEnableVhtFor24GHzBand" +#define CFG_ENABLE_VHT_FOR_24GHZ_MIN (0) +#define CFG_ENABLE_VHT_FOR_24GHZ_MAX (1) +#define CFG_ENABLE_VHT_FOR_24GHZ_DEFAULT (0) + +/* + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_NAME "gEnableVendorVhtFor24GHzBand" +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MIN (0) +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MAX (1) +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_DEFAULT (1) + +/* + * + * gEnableSNRMonitoring - Enables SNR Monitoring + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default snr monitor + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_SNR_MONITORING_NAME "gEnableSNRMonitoring" +#define CFG_ENABLE_SNR_MONITORING_MIN (0) +#define CFG_ENABLE_SNR_MONITORING_MAX (1) +#define CFG_ENABLE_SNR_MONITORING_DEFAULT (0) + +/* + * + * gEnableIpTcpUdpChecksumOffload - It enables IP, TCP and UDP checksum + * offload in hardware + * @Min: 0 + * @Max: 1 + * @Default: DEF + * + * This ini is used to enable IP, TCP and UDP checksum offload in hardware + * and also advertise same to network stack + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD "gEnableIpTcpUdpChecksumOffload" +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DISABLE (0) +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE (1) +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DEFAULT (CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE) + +#ifdef WLAN_FEATURE_FASTPATH + +/* + * + * gEnableFastPath - Control to enable fastpath feature + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable fastpath feature + * + * Supported Feature: Wlan Fastpath Feature + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_FASTPATH "gEnableFastPath" +#define CFG_ENABLE_FASTPATH_MIN (0) +#define CFG_ENABLE_FASTPATH_MAX (1) +#define CFG_ENABLE_FASTPATH_DEFAULT (CFG_ENABLE_FASTPATH_MIN) +#endif /* WLAN_FEATURE_FASTPATH */ + +/* + * IPA Offload configuration - Each bit enables a feature + * bit0 - IPA Enable + * bit1 - IPA Pre filter enable + * bit2 - IPv6 enable + * bit3 - IPA Resource Manager (RM) enable + * bit4 - IPA Clock scaling enable + */ +#define CFG_IPA_OFFLOAD_CONFIG_NAME "gIPAConfig" +#define CFG_IPA_OFFLOAD_CONFIG_MIN (0) +#define CFG_IPA_OFFLOAD_CONFIG_MAX (0xFFFFFFFF) +#define CFG_IPA_OFFLOAD_CONFIG_DEFAULT (CFG_IPA_OFFLOAD_CONFIG_MIN) + +/* + * IPA DESC SIZE + */ +#define CFG_IPA_DESC_SIZE_NAME "gIPADescSize" +#define CFG_IPA_DESC_SIZE_MIN (800) +#define CFG_IPA_DESC_SIZE_MAX (8000) +#define CFG_IPA_DESC_SIZE_DEFAULT (800) + +#define CFG_IPA_HIGH_BANDWIDTH_MBPS "gIPAHighBandwidthMbps" +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_MIN (200) +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_MAX (1000) +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_DEFAULT (400) + +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS "gIPAMediumBandwidthMbps" +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MIN (100) +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MAX (400) +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_DEFAULT (200) + +#define CFG_IPA_LOW_BANDWIDTH_MBPS "gIPALowBandwidthMbps" +#define CFG_IPA_LOW_BANDWIDTH_MBPS_MIN (0) +#define CFG_IPA_LOW_BANDWIDTH_MBPS_MAX (100) +#define CFG_IPA_LOW_BANDWIDTH_MBPS_DEFAULT (100) + +/* + * Firmware uart print + */ +#define CFG_ENABLE_FW_UART_PRINT_NAME "gEnablefwprint" +#define CFG_ENABLE_FW_UART_PRINT_DISABLE (0) +#define CFG_ENABLE_FW_UART_PRINT_ENABLE (1) +#define CFG_ENABLE_FW_UART_PRINT_DEFAULT (CFG_ENABLE_FW_UART_PRINT_DISABLE) + +/* + * Firmware log + */ +#define CFG_ENABLE_FW_LOG_NAME "gEnablefwlog" +#define CFG_ENABLE_FW_LOG_DISABLE (0) +#define CFG_ENABLE_FW_LOG_WMI (1) +#define CFG_ENABLE_FW_LOG_DIAG (2) +#define CFG_ENABLE_FW_LOG_MIN (CFG_ENABLE_FW_LOG_DISABLE) +#define CFG_ENABLE_FW_LOG_MAX (CFG_ENABLE_FW_LOG_DIAG) +#define CFG_ENABLE_FW_LOG_DEFAULT (CFG_ENABLE_FW_LOG_WMI) + +/* Macro to handle maximum receive AMPDU size configuration */ +#define CFG_VHT_AMPDU_LEN_EXPONENT_NAME "gVhtAmpduLenExponent" +#define CFG_VHT_AMPDU_LEN_EXPONENT_MIN (0) +#define CFG_VHT_AMPDU_LEN_EXPONENT_MAX (7) +#define CFG_VHT_AMPDU_LEN_EXPONENT_DEFAULT (3) + +#define CFG_VHT_MPDU_LEN_NAME "gVhtMpduLen" +#define CFG_VHT_MPDU_LEN_MIN (0) +#define CFG_VHT_MPDU_LEN_MAX (2) +#define CFG_VHT_MPDU_LEN_DEFAULT (0) + +#define CFG_SAP_MAX_NO_PEERS "gSoftApMaxPeers" +#define CFG_SAP_MAX_NO_PEERS_MIN (1) +#define CFG_SAP_MAX_NO_PEERS_MAX (SIR_SAP_MAX_NUM_PEERS) +#define CFG_SAP_MAX_NO_PEERS_DEFAULT (SIR_SAP_MAX_NUM_PEERS) + +/* + * + * gEnableDebugLog - Enable/Disable the Connection related logs + * @Min: 0 + * @Max: 0xFF + * @Default: 0x0F + * + * This ini is used to enable/disable the connection related logs + * 0x1 - Enable mgmt pkt logs (excpet probe req/rsp, beacons). + * 0x2 - Enable EAPOL pkt logs. + * 0x4 - Enable DHCP pkt logs. + * 0x8 - Enable mgmt action frames logs. + * 0x0 - Disable all the above connection related logs. + * The default value of 0x0F will enable all the above logs + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE "gEnableDebugLog" +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MIN (0) +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MAX (0xFF) +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT (0x0F) + +/* SAR Thermal limit values for 2g and 5g */ + +#define CFG_SET_TXPOWER_LIMIT2G_NAME "TxPower2g" +#define CFG_SET_TXPOWER_LIMIT2G_MIN (0) +#define CFG_SET_TXPOWER_LIMIT2G_MAX (30) +#define CFG_SET_TXPOWER_LIMIT2G_DEFAULT (30) + +#define CFG_SET_TXPOWER_LIMIT5G_NAME "TxPower5g" +#define CFG_SET_TXPOWER_LIMIT5G_MIN (0) +#define CFG_SET_TXPOWER_LIMIT5G_MAX (30) +#define CFG_SET_TXPOWER_LIMIT5G_DEFAULT (30) + +#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_LL_TX_FLOW_LWM "TxFlowLowWaterMark" +#define CFG_LL_TX_FLOW_LWM_MIN (0) +#define CFG_LL_TX_FLOW_LWM_MAX (1000) +#define CFG_LL_TX_FLOW_LWM_DEFAULT (300) + +/* + * + * 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_LL_TX_FLOW_HWM_OFFSET "TxFlowHighWaterMarkOffset" +#define CFG_LL_TX_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_FLOW_HWM_OFFSET_MAX (300) +#define CFG_LL_TX_FLOW_HWM_OFFSET_DEFAULT (94) + +/* + * + * 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_LL_TX_FLOW_MAX_Q_DEPTH "TxFlowMaxQueueDepth" +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_DEFAULT (1500) + +/* + * + * 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_LL_TX_LBW_FLOW_LWM "TxLbwFlowLowWaterMark" +#define CFG_LL_TX_LBW_FLOW_LWM_MIN (0) +#define CFG_LL_TX_LBW_FLOW_LWM_MAX (1000) +#define CFG_LL_TX_LBW_FLOW_LWM_DEFAULT (450) + +/* + * + * 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_LL_TX_LBW_FLOW_HWM_OFFSET "TxLbwFlowHighWaterMarkOffset" +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MAX (300) +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_DEFAULT (50) + +/* + * + * 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_LL_TX_LBW_FLOW_MAX_Q_DEPTH "TxLbwFlowMaxQueueDepth" +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_DEFAULT (750) + +/* + * + * 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_LL_TX_HBW_FLOW_LWM "TxHbwFlowLowWaterMark" +#define CFG_LL_TX_HBW_FLOW_LWM_MIN (0) +#define CFG_LL_TX_HBW_FLOW_LWM_MAX (1000) +#define CFG_LL_TX_HBW_FLOW_LWM_DEFAULT (406) + +/* + * + * 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_LL_TX_HBW_FLOW_HWM_OFFSET "TxHbwFlowHighWaterMarkOffset" +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MAX (300) +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_DEFAULT (94) + +/* + * + * 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_LL_TX_HBW_FLOW_MAX_Q_DEPTH "TxHbwFlowMaxQueueDepth" +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_DEFAULT (1500) +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + +/* + * + * TxFlowStopQueueThreshold - Stop queue Threshold to pause + * Netif queues when it reaches + * @Min: 0 + * @Max: 50 + * @Default: 15 + * + * This ini specifies the threshold of data packets transmitted + * before pausing netif queues. + * + * Related: TxFlowStartQueueOffset + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH "TxFlowStopQueueThreshold" +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_DEFAULT (15) +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_MIN (0) +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_MAX (50) + +/* + * + * TxFlowStartQueueOffset - Start queue offset to unpause + * Netif queues + * @Min: 0 + * @Max: 30 + * @Default: 11 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxFlowStopQueueThreshold. + * + * Related: TxFlowStopQueueThreshold + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET "TxFlowStartQueueOffset" +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_DEFAULT (10) +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MIN (0) +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MAX (30) + + +#define CFG_SAP_MAX_OFFLOAD_PEERS "gMaxOffloadPeers" +#define CFG_SAP_MAX_OFFLOAD_PEERS_MIN (2) +#define CFG_SAP_MAX_OFFLOAD_PEERS_MAX (5) +#define CFG_SAP_MAX_OFFLOAD_PEERS_DEFAULT (2) + +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS "gMaxOffloadReorderBuffs" +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MIN (0) +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MAX (3) +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_DEFAULT (2) + +#ifdef FEATURE_WLAN_RA_FILTERING +#define CFG_RA_FILTER_ENABLE_NAME "gRAFilterEnable" +#define CFG_RA_FILTER_ENABLE_MIN (0) +#define CFG_RA_FILTER_ENABLE_MAX (1) +#define CFG_RA_FILTER_ENABLE_DEFAULT (1) + +#define CFG_RA_RATE_LIMIT_INTERVAL_NAME "gRArateLimitInterval" +#define CFG_RA_RATE_LIMIT_INTERVAL_MIN (60) +#define CFG_RA_RATE_LIMIT_INTERVAL_MAX (3600) +#define CFG_RA_RATE_LIMIT_INTERVAL_DEFAULT (60) /*60 SEC */ +#endif + +/* + * + * gIgnorePeerErpInfo - Used for ignore peer infrormation + * @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_NAME "gIgnorePeerErpInfo" +#define CFG_IGNORE_PEER_ERP_INFO_MIN (0) +#define CFG_IGNORE_PEER_ERP_INFO_MAX (1) +#define CFG_IGNORE_PEER_ERP_INFO_DEFAULT (0) + +/* + * + * gEnableMemoryDebug - Enables the memory debug + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable default memory debug + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#ifdef MEMORY_DEBUG +#define CFG_ENABLE_MEMORY_DEBUG_NAME "gEnableMemoryDebug" +#define CFG_ENABLE_MEMORY_DEBUG_MIN (0) +#define CFG_ENABLE_MEMORY_DEBUG_MAX (1) +#define CFG_ENABLE_MEMORY_DEBUG_DEFAULT (1) +#endif + +/* + * + * 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 + * + * This ini specifies the behavior of FW in case of + * CHIP_POWER_SAVE_FAIL_DETECTED event + * + * Usage: External + * + * + */ +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME "g_auto_detect_power_failure_mode" +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_DEFAULT (PMO_FW_TO_CRASH_ON_PWR_FAILURE) +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_MIN (PMO_FW_TO_CRASH_ON_PWR_FAILURE) +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_MAX \ + (PMO_AUTO_PWR_FAILURE_DETECT_DISABLE) +/* + * + * gMaxAmsduNum - Max number of MSDU's in aggregate + * @Min: 0 + * @Max: 3 + * @Default: 1 + * gMaxAmsduNum is the number of MSDU's transmitted in the 11n aggregate + * frame. Setting it to a value larger than 1 enables transmit aggregation. + * It is a PHY parameter that applies to all vdev's in firmware. + * + * Supported Feature: 11n aggregation + * + * Usage: Internal + * + * + */ +#define CFG_MAX_AMSDU_NUM_NAME "gMaxAmsduNum" +#define CFG_MAX_AMSDU_NUM_MIN (0) +#define CFG_MAX_AMSDU_NUM_MAX (3) +#define CFG_MAX_AMSDU_NUM_DEFAULT (1) + +/* + * + * gInitialDwellTime - Used to set initial dwell time + * @Min: 0 + * @Max: 0 + * @Default: 100 + * + * This ini is used to set default initial dwell time + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_INITIAL_DWELL_TIME_NAME "gInitialDwellTime" +#define CFG_INITIAL_DWELL_TIME_DEFAULT (0) +#define CFG_INITIAL_DWELL_TIME_MIN (0) +#define CFG_INITIAL_DWELL_TIME_MAX (100) + +/* + * + * gInitialScanNoDFSChnl - WLAN skips scanning the DFS channels + * @Min: 0 + * @Max: 0 + * @Default: 1 + * + * This ini is used to set for the first scan after driver + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_NAME "gInitialScanNoDFSChnl" +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_DEFAULT (0) +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_MIN (0) +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_MAX (1) + +/* + * + * gAllowDFSChannelRoam - Allow dfs channel in roam + * @Min: 0 + * @Max: 1 + * @Default: 2 + * + * This ini is used to set default dfs channel + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ROAMING_DFS_CHANNEL_NAME "gAllowDFSChannelRoam" +#define CFG_ROAMING_DFS_CHANNEL_DISABLED (0) +#define CFG_ROAMING_DFS_CHANNEL_ENABLED_NORMAL (1) +#define CFG_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE (2) +#define CFG_ROAMING_DFS_CHANNEL_MIN (CFG_ROAMING_DFS_CHANNEL_DISABLED) +#define CFG_ROAMING_DFS_CHANNEL_MAX (CFG_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE) +#define CFG_ROAMING_DFS_CHANNEL_DEFAULT (CFG_ROAMING_DFS_CHANNEL_DISABLED) + +#ifdef MSM_PLATFORM +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD "gBusBandwidthHighThreshold" +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_DEFAULT (2000) +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD "gBusBandwidthMediumThreshold" +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_DEFAULT (500) +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD "gBusBandwidthLowThreshold" +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_DEFAULT (150) +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL "gBusBandwidthComputeInterval" +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_DEFAULT (100) +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MIN (0) +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MAX (10000) + +/* + * + * gEnableTcpLimitOutput - Control to enable TCP limit output byte + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * 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_ENABLE_TCP_LIMIT_OUTPUT "gTcpLimitOutputEnable" +#define CFG_ENABLE_TCP_LIMIT_OUTPUT_DEFAULT (1) +#define CFG_ENABLE_TCP_LIMIT_OUTPUT_MIN (0) +#define CFG_ENABLE_TCP_LIMIT_OUTPUT_MAX (1) + +/* + * + * gTcpAdvWinScaleEnable - Control to enable TCP adv window scaling + * @Min: -0 + * @Max: 1 + * @Default: 1 + * + * 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_ENABLE_TCP_ADV_WIN_SCALE "gTcpAdvWinScaleEnable" +#define CFG_ENABLE_TCP_ADV_WIN_SCALE_DEFAULT (1) +#define CFG_ENABLE_TCP_ADV_WIN_SCALE_MIN (0) +#define CFG_ENABLE_TCP_ADV_WIN_SCALE_MAX (1) + +/* + * + * gTcpDelAckEnable - Control to enable Dynamic Configuration of Tcp Delayed Ack + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * 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_ENABLE_TCP_DELACK "gTcpDelAckEnable" +#define CFG_ENABLE_TCP_DELACK_DEFAULT (1) +#define CFG_ENABLE_TCP_DELACK_MIN (0) +#define CFG_ENABLE_TCP_DELACK_MAX (1) + +/* + * + * enable_tcp_param_update - Configure TCP param through Wi-Fi HAL + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to configure TCP param through Wi-Fi HAL + * + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_TCP_PARAM_UPDATE "enable_tcp_param_update" +#define CFG_ENABLE_TCP_PARAM_UPDATE_DEFAULT (0) +#define CFG_ENABLE_TCP_PARAM_UPDATE_MIN (0) +#define CFG_ENABLE_TCP_PARAM_UPDATE_MAX (1) + + +/* + * + * 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_TCP_DELACK_THRESHOLD_HIGH "gTcpDelAckThresholdHigh" +#define CFG_TCP_DELACK_THRESHOLD_HIGH_DEFAULT (500) +#define CFG_TCP_DELACK_THRESHOLD_HIGH_MIN (0) +#define CFG_TCP_DELACK_THRESHOLD_HIGH_MAX (16000) + +/* + * + * 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_TCP_DELACK_THRESHOLD_LOW "gTcpDelAckThresholdLow" +#define CFG_TCP_DELACK_THRESHOLD_LOW_DEFAULT (1000) +#define CFG_TCP_DELACK_THRESHOLD_LOW_MIN (0) +#define CFG_TCP_DELACK_THRESHOLD_LOW_MAX (10000) + +/* + * + * 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_TCP_DELACK_TIMER_COUNT "gTcpDelAckTimerCount" +#define CFG_TCP_DELACK_TIMER_COUNT_DEFAULT (30) +#define CFG_TCP_DELACK_TIMER_COUNT_MIN (1) +#define CFG_TCP_DELACK_TIMER_COUNT_MAX (1000) + + +/* + * + * 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_TCP_TX_HIGH_TPUT_THRESHOLD_NAME "gTcpTxHighTputThreshold" +#define CFG_TCP_TX_HIGH_TPUT_THRESHOLD_DEFAULT (500) +#define CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MIN (0) +#define CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MAX (16000) + +/* + * + * 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_NAME "periodic_stats_display_time" +#define CFG_PERIODIC_STATS_DISPLAY_TIME_DEFAULT (10) +#define CFG_PERIODIC_STATS_DISPLAY_TIME_MIN (0) +#define CFG_PERIODIC_STATS_DISPLAY_TIME_MAX (256) + +#endif /* MSM_PLATFORM */ + +#ifdef WLAN_FEATURE_11W +/* + * + * 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) + * + * Usage: Internal/External + * + * + */ +#define CFG_PMF_SA_QUERY_MAX_RETRIES_NAME "pmfSaQueryMaxRetries" +#define CFG_PMF_SA_QUERY_MAX_RETRIES_DEFAULT (5) +#define CFG_PMF_SA_QUERY_MAX_RETRIES_MIN (0) +#define CFG_PMF_SA_QUERY_MAX_RETRIES_MAX (20) + +/* + * + * pmfSaQueryRetryInterval - Control PMF SA query retry interval + * for SAP in ms + * @Min: 0 + * @Max: 2000 + * @Default: 200 + * + * This ini to set the PMF SA query retry interval for SAP in ms + * + * Related: None. + * + * Supported Feature: PMF(11W) + * + * Usage: Internal/External + * + * + */ +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_NAME "pmfSaQueryRetryInterval" +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_DEFAULT (200) +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_MIN (0) +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_MAX (2000) +#endif + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_MAX_CONCURRENT_CONNECTIONS_NAME "gMaxConcurrentActiveSessions" +#define CFG_MAX_CONCURRENT_CONNECTIONS_DEFAULT (3) +#define CFG_MAX_CONCURRENT_CONNECTIONS_MIN (1) +#define CFG_MAX_CONCURRENT_CONNECTIONS_MAX (4) + +/* + * + * gIgnoreCAC - Used to ignore CAC + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default CAC + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_IGNORE_CAC_NAME "gIgnoreCAC" +#define CFG_IGNORE_CAC_MIN (0) +#define CFG_IGNORE_CAC_MAX (1) +#define CFG_IGNORE_CAC_DEFAULT (0) + +#define CFG_DFS_RADAR_PRI_MULTIPLIER_NAME "gDFSradarMappingPriMultiplier" +#define CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT (4) +#define CFG_DFS_RADAR_PRI_MULTIPLIER_MIN (0) +#define CFG_DFS_RADAR_PRI_MULTIPLIER_MAX (10) + +/* + * + * gReorderOffloadSupported - Packet reordering offload to firmware + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Packet reordering + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_REORDER_OFFLOAD_SUPPORT_NAME "gReorderOffloadSupported" +#define CFG_REORDER_OFFLOAD_SUPPORT_MIN (0) +#define CFG_REORDER_OFFLOAD_SUPPORT_MAX (1) +#define CFG_REORDER_OFFLOAD_SUPPORT_DEFAULT (1) + +/* IpaUcTxBufCount should be power of 2 */ +#define CFG_IPA_UC_TX_BUF_COUNT_NAME "IpaUcTxBufCount" +#define CFG_IPA_UC_TX_BUF_COUNT_MIN (0) +#define CFG_IPA_UC_TX_BUF_COUNT_MAX (2048) +#define CFG_IPA_UC_TX_BUF_COUNT_DEFAULT (512) + +#define CFG_IPA_UC_TX_BUF_SIZE_NAME "IpaUcTxBufSize" +#define CFG_IPA_UC_TX_BUF_SIZE_MIN (0) +#define CFG_IPA_UC_TX_BUF_SIZE_MAX (4096) +#define CFG_IPA_UC_TX_BUF_SIZE_DEFAULT (2048) + +/* IpaUcRxIndRingCount should be power of 2 */ +#define CFG_IPA_UC_RX_IND_RING_COUNT_NAME "IpaUcRxIndRingCount" +#define CFG_IPA_UC_RX_IND_RING_COUNT_MIN (0) +#define CFG_IPA_UC_RX_IND_RING_COUNT_MAX (2048) +#define CFG_IPA_UC_RX_IND_RING_COUNT_DEFAULT (1024) + +#define CFG_IPA_UC_TX_PARTITION_BASE_NAME "IpaUcTxPartitionBase" +#define CFG_IPA_UC_TX_PARTITION_BASE_MIN (0) +#define CFG_IPA_UC_TX_PARTITION_BASE_MAX (9000) +#define CFG_IPA_UC_TX_PARTITION_BASE_DEFAULT (3000) + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +/* Enable WLAN Logging to app space */ +#define CFG_WLAN_LOGGING_SUPPORT_NAME "wlanLoggingEnable" +#define CFG_WLAN_LOGGING_SUPPORT_ENABLE (1) +#define CFG_WLAN_LOGGING_SUPPORT_DISABLE (0) +#define CFG_WLAN_LOGGING_SUPPORT_DEFAULT (1) + +/* Enable forwarding the driver logs to kmsg console */ +#define CFG_WLAN_LOGGING_CONSOLE_SUPPORT_NAME "wlanLoggingToConsole" +#define CFG_WLAN_LOGGING_CONSOLE_SUPPORT_ENABLE (1) +#define CFG_WLAN_LOGGING_CONSOLE_SUPPORT_DISABLE (0) +#define CFG_WLAN_LOGGING_CONSOLE_SUPPORT_DEFAULT (1) +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + +#ifdef WLAN_FEATURE_LPSS +#define CFG_ENABLE_LPASS_SUPPORT "gEnableLpassSupport" +#define CFG_ENABLE_LPASS_SUPPORT_DEFAULT (0) +#define CFG_ENABLE_LPASS_SUPPORT_MIN (0) +#define CFG_ENABLE_LPASS_SUPPORT_MAX (1) +#endif + +/* + * NaN feature support configuration + * gEnableNanSupport = 0 means NaN is not supported + * gEnableNanSupport = 1 means NaN is supported + */ +#ifdef WLAN_FEATURE_NAN +#define CFG_ENABLE_NAN_SUPPORT "gEnableNanSupport" +#define CFG_ENABLE_NAN_SUPPORT_DEFAULT (0) +#define CFG_ENABLE_NAN_SUPPORT_MIN (0) +#define CFG_ENABLE_NAN_SUPPORT_MAX (1) +#endif + +#define CFG_ENABLE_SELF_RECOVERY "gEnableSelfRecovery" +#define CFG_ENABLE_SELF_RECOVERY_MIN (0) +#define CFG_ENABLE_SELF_RECOVERY_MAX (1) +#define CFG_ENABLE_SELF_RECOVERY_DEFAULT (0) + +#define CFG_ENABLE_SAP_SUSPEND "gEnableSapSuspend" +#define CFG_ENABLE_SAP_SUSPEND_MIN (0) +#define CFG_ENABLE_SAP_SUSPEND_MAX (1) +#define CFG_ENABLE_SAP_SUSPEND_DEFAULT (1) + +/* + * + * 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: Internal/External + * + * + */ + +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_NAME "gEnableDeauthToDisassocMap" +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MIN (0) +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MAX (1) +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_DEFAULT (0) + +#ifdef DHCP_SERVER_OFFLOAD +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_NAME "gDHCPServerOffloadEnable" +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN (0) +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MAX (1) +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_DEFAULT (CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN) + +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_NAME "gDHCPMaxNumClients" +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MIN (1) +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX (8) +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_DEFAULT (CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX) + +#define CFG_DHCP_SERVER_IP_NAME "gDHCPServerIP" +#define CFG_DHCP_SERVER_IP_DEFAULT "" +#endif /* DHCP_SERVER_OFFLOAD */ + +/* + * + * gSendDeauthBeforeCon - It will send deauth before connection + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default DeauthBeforeCon + * 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 "gSendDeauthBeforeCon" +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MIN (0) +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX (1) +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_DEFAULT (0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME "gEnableCustomConcRule1" +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MIN (0) +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MAX (1) +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_DEFAULT (0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME "gEnableCustomConcRule2" +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MIN (0) +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MAX (1) +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_DEFAULT (0) + +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ "gEnableStaConnectionIn5Ghz" +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MIN (0) +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MAX (1) +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_DEFAULT (1) + +#define CFG_ENABLE_MAC_ADDR_SPOOFING "gEnableMacAddrSpoof" +#define CFG_ENABLE_MAC_ADDR_SPOOFING_MIN (0) +#define CFG_ENABLE_MAC_ADDR_SPOOFING_MAX (1) +#define CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT (1) + +/* + * + * gP2PListenDeferInterval - Defer Remain on channel for some duration + * @Min: 100 + * @Max: 200 + * @Default: 100 + * + * This ini is used to defer back to back RoC request when sta is + * connected. + * If back to back listen received when sta is connected then fw is + * not getting enough time to spend on home channel so it leading to + * heartbeat failure. + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ + +#define CFG_P2P_LISTEN_DEFER_INTERVAL_NAME "gP2PListenDeferInterval" +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MIN (100) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MAX (200) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_DEFAULT (100) + +/* + * + * 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_MIRACAST_MCC_REST_TIME_VAL "gStaMiracastMccRestTimeVal" +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MIN (100) +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MAX (500) +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_DEFAULT (400) + +/* + * + * sta_scan_burst_duration - Burst duration in case of split scan. + * @Min: 0 + * @Max: 180 + * @Default: 0 + * + * This ini is used to set burst duration of scan only when STA is active. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_STA_SCAN_BURST_DURATION_VAL "sta_scan_burst_duration" +#define CFG_STA_SCAN_BURST_DURATION_VAL_MIN (0) +#define CFG_STA_SCAN_BURST_DURATION_VAL_MAX (180) +#define CFG_STA_SCAN_BURST_DURATION_VAL_DEFAULT (0) + +/* + * + * p2p_scan_burst_duration - Burst duration in case of split scan for p2p scan. + * @Min: 0 + * @Max: 180 + * @Default: 0 + * + * This ini is used to set burst duration of scan for p2p scan requests. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_P2P_SCAN_BURST_DURATION_VAL "p2p_scan_burst_duration" +#define CFG_P2P_SCAN_BURST_DURATION_VAL_MIN (0) +#define CFG_P2P_SCAN_BURST_DURATION_VAL_MAX (180) +#define CFG_P2P_SCAN_BURST_DURATION_VAL_DEFAULT (0) + +/* + * + * go_scan_burst_duration - Burst duration in case of split scan when GO is + * active. + * @Min: 0 + * @Max: 180 + * @Default: 0 + * + * This ini is used to set burst duration of scan when GO is active. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_GO_SCAN_BURST_DURATION_VAL "go_scan_burst_duration" +#define CFG_GO_SCAN_BURST_DURATION_VAL_MIN (0) +#define CFG_GO_SCAN_BURST_DURATION_VAL_MAX (180) +#define CFG_GO_SCAN_BURST_DURATION_VAL_DEFAULT (0) + +/* + * + * ap_scan_burst_duration - Burst duration in case of split scan when ap + * is active. + * @Min: 0 + * @Max: 32 + * @Default: 0 + * + * This ini is used to set burst duration of scan when SAP is active. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_AP_SCAN_BURST_DURATION_VAL "ap_scan_burst_duration" +#define CFG_AP_SCAN_BURST_DURATION_VAL_MIN (0) +#define CFG_AP_SCAN_BURST_DURATION_VAL_MAX (32) +#define CFG_AP_SCAN_BURST_DURATION_VAL_DEFAULT (0) + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* + * + * 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_NAME "gSapChannelAvoidance" +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_MIN (0) +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_MAX (1) +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_DEFAULT (0) +#endif /* FEATURE_AP_MCC_CH_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_NAME "gSAP11ACOverride" +#define CFG_SAP_11AC_OVERRIDE_MIN (0) +#define CFG_SAP_11AC_OVERRIDE_MAX (1) +#define CFG_SAP_11AC_OVERRIDE_DEFAULT (0) + +/* + * + * 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_NAME "gGO11ACOverride" +#define CFG_GO_11AC_OVERRIDE_MIN (0) +#define CFG_GO_11AC_OVERRIDE_MAX (1) +#define CFG_GO_11AC_OVERRIDE_DEFAULT (1) + +#define CFG_SAP_DOT11MC "gSapDot11mc" +#define CFG_SAP_DOT11MC_MIN (0) +#define CFG_SAP_DOT11MC_MAX (1) +#define CFG_SAP_DOT11MC_DEFAULT (0) + +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR "gPreferNonDfsChanOnRadar" +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN (0) +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX (1) +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT (0) + +#define CFG_MULTICAST_HOST_FW_MSGS "gMulticastHostFwMsgs" +#define CFG_MULTICAST_HOST_FW_MSGS_MIN (0) +#define CFG_MULTICAST_HOST_FW_MSGS_MAX (1) +#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 + + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_CONC_SYSTEM_PREF "gSystemPref" +#define CFG_CONC_SYSTEM_PREF_MIN (0) +#define CFG_CONC_SYSTEM_PREF_MAX (2) +#define CFG_CONC_SYSTEM_PREF_DEFAULT (0) + +/* + * + * TSOEnable - Control to enable tso feature + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable TSO feature + * + * Supported Feature: TSO Feature + * + * Usage: Internal + * + * + */ +#define CFG_TSO_ENABLED_NAME "TSOEnable" +#define CFG_TSO_ENABLED_MIN (0) +#define CFG_TSO_ENABLED_MAX (1) +#define CFG_TSO_ENABLED_DEFAULT (0) + +/* + * + * LROEnable - Control to enable lro feature + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable LRO feature + * + * Supported Feature: LRO + * + * Usage: Internal + * + * + */ +#define CFG_LRO_ENABLED_NAME "LROEnable" +#define CFG_LRO_ENABLED_MIN (0) +#define CFG_LRO_ENABLED_MAX (1) +#define CFG_LRO_ENABLED_DEFAULT (0) + +/* + * + * GROEnable - Control to enable gro feature + * + * @Disable: 0 + * @Enable: 1 + * @Default: 0 + * + * This ini is used to enable GRO feature + * + * Supported Feature: GRO + * + * Usage: Internal + * + * + */ +#define CFG_GRO_ENABLED_NAME "GROEnable" +#define CFG_GRO_ENABLED_MIN (0) +#define CFG_GRO_ENABLED_MAX (1) +#define CFG_GRO_ENABLED_DEFAULT (0) + +/* + * 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 + */ +#define CFG_FLOW_STEERING_ENABLED_NAME "gEnableFlowSteering" +#define CFG_FLOW_STEERING_ENABLED_MIN (0) +#define CFG_FLOW_STEERING_ENABLED_MAX (1) +#define CFG_FLOW_STEERING_ENABLED_DEFAULT (0) + +/* + * 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_MAX_MSDUS_PER_RXIND_NAME "maxMSDUsPerRxInd" +#define CFG_MAX_MSDUS_PER_RXIND_MIN (4) +#define CFG_MAX_MSDUS_PER_RXIND_MAX (32) +#define CFG_MAX_MSDUS_PER_RXIND_DEFAULT (32) +/* + * In static display use case when APPS is in stand alone power save mode enable + * active offload mode which helps FW to filter out MC/BC data packets to avoid + * APPS wake up and save more power. + * + * By default enable active mode offload as it helps to save more power in + * static display usecase(APPS stand alone power collapse). + * + * If active mode offload(gActiveModeOffload=1) 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(gActiveModeOffload=0) then all applicable + * data offload/filtering is enabled during cfg80211 suspend and disabled + * during cfg80211 resume + * + * Active mode offload feature is bydefault enabled for all targets + */ + +#define CFG_ACTIVE_MODE_OFFLOAD "gActiveModeOffload" +#define CFG_ACTIVE_MODE_OFFLOAD_MIN (0) +#define CFG_ACTIVE_MODE_OFFLOAD_MAX (1) +#define CFG_ACTIVE_MODE_OFFLOAD_DEFAULT (1) + +/* + * 0: Disable APF packet filter + * 1: Enable APF packet filter + */ +#define CFG_APF_PACKET_FILTER_OFFLOAD "gBpfFilterEnable" +#define CFG_APF_PACKET_FILTER_OFFLOAD_MIN (0) +#define CFG_APF_PACKET_FILTER_OFFLOAD_MAX (1) +#define CFG_APF_PACKET_FILTER_OFFLOAD_DEFAULT (1) + +/* + * + * 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 "gCckChainMaskEnable" +#define CFG_TX_CHAIN_MASK_CCK_MIN (0) +#define CFG_TX_CHAIN_MASK_CCK_MAX (1) +#define CFG_TX_CHAIN_MASK_CCK_DEFAULT (0) +/* + * + * gTxChainMask1ss - Enables/disables tx chain Mask1ss + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * This ini is used to set default tx chain Mask1ss + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_TX_CHAIN_MASK_1SS "gTxChainMask1ss" +#define CFG_TX_CHAIN_MASK_1SS_MIN (0) +#define CFG_TX_CHAIN_MASK_1SS_MAX (3) +#define CFG_TX_CHAIN_MASK_1SS_DEFAULT (1) + +/* + * + * 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_NAME "gEnableSmartChainmask" +#define CFG_ENABLE_SMART_CHAINMASK_MIN (0) +#define CFG_ENABLE_SMART_CHAINMASK_MAX (1) +#define CFG_ENABLE_SMART_CHAINMASK_DEFAULT (0) + +/* + * + * 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_NAME "gEnableAlternativeChainmask" +#define CFG_ENABLE_COEX_ALT_CHAINMASK_MIN (0) +#define CFG_ENABLE_COEX_ALT_CHAINMASK_MAX (1) +#define CFG_ENABLE_COEX_ALT_CHAINMASK_DEFAULT (0) + +/* + * set the self gen power value from + * 0 to 0xffff + */ +#define CFG_SELF_GEN_FRM_PWR "gSelfGenFrmPwr" +#define CFG_SELF_GEN_FRM_PWR_MIN (0) +#define CFG_SELF_GEN_FRM_PWR_MAX (0xffff) +#define CFG_SELF_GEN_FRM_PWR_DEFAULT (0) + +/* + * + * gTxAggregationSize - Gives an option to configure Tx aggregation size + * in no of MPDUs + * @Min: 0 + * @Max: 64 + * @Default: 64 + * + * 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: Internal/External + * + * + */ + +#define CFG_TX_AGGREGATION_SIZE "gTxAggregationSize" +#define CFG_TX_AGGREGATION_SIZE_MIN (0) +#define CFG_TX_AGGREGATION_SIZE_MAX (64) +#define CFG_TX_AGGREGATION_SIZE_DEFAULT (64) + +/* + * + * gTxAggregationSizeBE - To configure Tx aggregation size for BE queue + * in no of MPDUs + * @Min: 0 + * @Max: 64 + * @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 "gTxAggregationSizeBE" +#define CFG_TX_AGGREGATION_SIZEBE_MIN (0) +#define CFG_TX_AGGREGATION_SIZEBE_MAX (64) +#define CFG_TX_AGGREGATION_SIZEBE_DEFAULT (0) + +/* + * + * gTxAggregationSizeBK - To configure Tx aggregation size for BK queue + * in no of MPDUs + * @Min: 0 + * @Max: 64 + * @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 "gTxAggregationSizeBK" +#define CFG_TX_AGGREGATION_SIZEBK_MIN (0) +#define CFG_TX_AGGREGATION_SIZEBK_MAX (64) +#define CFG_TX_AGGREGATION_SIZEBK_DEFAULT (0) + +/* + * + * gTxAggregationSizeVI - To configure Tx aggregation size for VI queue + * in no of MPDUs + * @Min: 0 + * @Max: 64 + * @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 "gTxAggregationSizeVI" +#define CFG_TX_AGGREGATION_SIZEVI_MIN (0) +#define CFG_TX_AGGREGATION_SIZEVI_MAX (64) +#define CFG_TX_AGGREGATION_SIZEVI_DEFAULT (0) + +/* + * + * gTxAggregationSizeVO - To configure Tx aggregation size for VO queue + * in no of MPDUs + * @Min: 0 + * @Max: 64 + * @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 "gTxAggregationSizeVO" +#define CFG_TX_AGGREGATION_SIZEVO_MIN (0) +#define CFG_TX_AGGREGATION_SIZEVO_MAX (64) +#define CFG_TX_AGGREGATION_SIZEVO_DEFAULT (0) + +/* + * + * gRxAggregationSize - Gives an option to configure Rx aggregation size + * in no of MPDUs + * @Min: 1 + * @Max: 64 + * @Default: 64 + * + * 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: Internal/External + * + * + */ + +#define CFG_RX_AGGREGATION_SIZE "gRxAggregationSize" +#define CFG_RX_AGGREGATION_SIZE_MIN (1) +#define CFG_RX_AGGREGATION_SIZE_MAX (64) +#define CFG_RX_AGGREGATION_SIZE_DEFAULT (64) + +/* + * + * 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 "gTxAggSwRetryBE" +#define CFG_TX_AGGR_SW_RETRY_BE_MIN (0) +#define CFG_TX_AGGR_SW_RETRY_BE_MAX (64) +#define CFG_TX_AGGR_SW_RETRY_BE_DEFAULT (0) + +/* + * + * 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 "gTxAggSwRetryBK" +#define CFG_TX_AGGR_SW_RETRY_BK_MIN (0) +#define CFG_TX_AGGR_SW_RETRY_BK_MAX (64) +#define CFG_TX_AGGR_SW_RETRY_BK_DEFAULT (0) + +/* + * + * 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 "gTxAggSwRetryVI" +#define CFG_TX_AGGR_SW_RETRY_VI_MIN (0) +#define CFG_TX_AGGR_SW_RETRY_VI_MAX (64) +#define CFG_TX_AGGR_SW_RETRY_VI_DEFAULT (0) + +/* + * + * 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 "gTxAggSwRetryVO" +#define CFG_TX_AGGR_SW_RETRY_VO_MIN (0) +#define CFG_TX_AGGR_SW_RETRY_VO_MAX (64) +#define CFG_TX_AGGR_SW_RETRY_VO_DEFAULT (0) + +/* + * + * gTxAggSwRetry - Configure Tx aggregation sw retry + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * 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 "gTxAggSwRetry" +#define CFG_TX_AGGR_SW_RETRY_MIN (0) +#define CFG_TX_AGGR_SW_RETRY_MAX (64) +#define CFG_TX_AGGR_SW_RETRY_DEFAULT (0) + +/* + * + * 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 "gTxNonAggSwRetryBE" +#define CFG_TX_NON_AGGR_SW_RETRY_BE_MIN (0) +#define CFG_TX_NON_AGGR_SW_RETRY_BE_MAX (64) +#define CFG_TX_NON_AGGR_SW_RETRY_BE_DEFAULT (0) + +/* + * + * 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 "gTxNonAggSwRetryBK" +#define CFG_TX_NON_AGGR_SW_RETRY_BK_MIN (0) +#define CFG_TX_NON_AGGR_SW_RETRY_BK_MAX (64) +#define CFG_TX_NON_AGGR_SW_RETRY_BK_DEFAULT (0) + +/* + * + * 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 "gTxNonAggSwRetryVI" +#define CFG_TX_NON_AGGR_SW_RETRY_VI_MIN (0) +#define CFG_TX_NON_AGGR_SW_RETRY_VI_MAX (64) +#define CFG_TX_NON_AGGR_SW_RETRY_VI_DEFAULT (0) + +/* + * + * 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 "gTxNonAggSwRetryVO" +#define CFG_TX_NON_AGGR_SW_RETRY_VO_MIN (0) +#define CFG_TX_NON_AGGR_SW_RETRY_VO_MAX (64) +#define CFG_TX_NON_AGGR_SW_RETRY_VO_DEFAULT (0) + +/* + * + * gTxNonAggSwRetry - Configure Tx non aggregation sw retry + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * 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 "gTxNonAggSwRetry" +#define CFG_TX_NON_AGGR_SW_RETRY_MIN (0) +#define CFG_TX_NON_AGGR_SW_RETRY_MAX (64) +#define CFG_TX_NON_AGGR_SW_RETRY_DEFAULT (0) + +/* + * fine timing measurement capability information + * + * <----- fine_time_meas_cap (in bits) -----> + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + *| 8-31 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + *| reserved | SAP | SAP |P2P-GO|P2P-GO|P2P-CLI|P2P-CLI| STA | STA | + *| |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 | + * +-----------------+-----------------+-----------+ + */ +#define CFG_FINE_TIME_MEAS_CAPABILITY "gfine_time_meas_cap" +#define CFG_FINE_TIME_MEAS_CAPABILITY_MIN (0x0000) +#define CFG_FINE_TIME_MEAS_CAPABILITY_MAX (0x00BD) +#define CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT (0x000D) + +/** + * enum dot11p_mode - The 802.11p mode of operation + * @WLAN_HDD_11P_DISABLED: 802.11p mode is disabled + * @WLAN_HDD_11P_STANDALONE: 802.11p-only operation + * @WLAN_HDD_11P_CONCURRENT: 802.11p and WLAN operate concurrently + */ +enum dot11p_mode { + WLAN_HDD_11P_DISABLED = 0, + WLAN_HDD_11P_STANDALONE, + WLAN_HDD_11P_CONCURRENT, +}; + +#define CFG_DOT11P_MODE_NAME "gDot11PMode" +#define CFG_DOT11P_MODE_DEFAULT (WLAN_HDD_11P_DISABLED) +#define CFG_DOT11P_MODE_MIN (WLAN_HDD_11P_DISABLED) +#define CFG_DOT11P_MODE_MAX (WLAN_HDD_11P_CONCURRENT) + +/* + * + * etsi13_srd_chan_in_master_mode - Enable/disable ETSI SRD channels in + * master mode PCL and ACS functionality + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * etsi13_srd_chan_in_master_mode is to enable/disable ETSI SRD channels in + * master mode PCL and ACS functionality + * + * Related: None + * + * Supported Feature: SAP/P2P-GO + * + * Usage: Internal/External + * + * + */ +#define CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE "etsi13_srd_chan_in_master_mode" +#define CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE_DEF (0) +#define CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE_MIN (0) +#define CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE_MAX (1) + +/* + * + * 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 "num_tx_chains_2g" +#define CFG_NUM_TX_CHAINS_2G_MIN 0x01249249 +#define CFG_NUM_TX_CHAINS_2G_MAX 0x02492492 +#define CFG_NUM_TX_CHAINS_2G_DEF 0x02492492 + +/* + * + * 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 "num_tx_chains_5g" +#define CFG_NUM_TX_CHAINS_5G_MIN 0x01249249 +#define CFG_NUM_TX_CHAINS_5G_MAX 0x02492492 +#define CFG_NUM_TX_CHAINS_5G_DEF 0x02492492 + +/* + * + * 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 "num_rx_chains_2g" +#define CFG_NUM_RX_CHAINS_2G_MIN 0x01249249 +#define CFG_NUM_RX_CHAINS_2G_MAX 0x02492492 +#define CFG_NUM_RX_CHAINS_2G_DEF 0x02492492 + +/* + * + * 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 "num_rx_chains_5g" +#define CFG_NUM_RX_CHAINS_5G_MIN 0x01249249 +#define CFG_NUM_RX_CHAINS_5G_MAX 0x02492492 +#define CFG_NUM_RX_CHAINS_5G_DEF 0x02492492 + +/* + * + * 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 "tx_nss_2g" +#define CFG_TX_NSS_2G_MIN 0x01249249 +#define CFG_TX_NSS_2G_MAX 0x02492492 +#define CFG_TX_NSS_2G_DEF 0x02492492 + +/* + * + * 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 "tx_nss_5g" +#define CFG_TX_NSS_5G_MIN 0x01249249 +#define CFG_TX_NSS_5G_MAX 0x02492492 +#define CFG_TX_NSS_5G_DEF 0x02492492 + +/* + * + * 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 "rx_nss_2g" +#define CFG_RX_NSS_2G_MIN 0x01249249 +#define CFG_RX_NSS_2G_MAX 0x02492492 +#define CFG_RX_NSS_2G_DEF 0x02492492 + +/* + * + * 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 "rx_nss_5g" +#define CFG_RX_NSS_5G_MIN 0x01249249 +#define CFG_RX_NSS_5G_MAX 0x02492492 +#define CFG_RX_NSS_5G_DEF 0x02492492 + +/* + * + * 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 "num_tx_chains_11b" +#define CFG_NUM_TX_CHAINS_11b_MIN 0x01249249 +#define CFG_NUM_TX_CHAINS_11b_MAX 0x02492492 +#define CFG_NUM_TX_CHAINS_11b_DEF 0x02492492 + +/* + * + * 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 "num_tx_chains_11g" +#define CFG_NUM_TX_CHAINS_11g_MIN 0x01249249 +#define CFG_NUM_TX_CHAINS_11g_MAX 0x02492492 +#define CFG_NUM_TX_CHAINS_11g_DEF 0x02492492 + +/* + * + * 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 "num_tx_chains_11a" +#define CFG_NUM_TX_CHAINS_11a_MIN 0x01249249 +#define CFG_NUM_TX_CHAINS_11a_MAX 0x02492492 +#define CFG_NUM_TX_CHAINS_11a_DEF 0x02492492 + +/* + * + * 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 "disable_tx_mrc_2g" +#define CFG_DISABLE_TX_MRC_2G_MIN 0 +#define CFG_DISABLE_TX_MRC_2G_MAX 1 +#define CFG_DISABLE_TX_MRC_2G_DEF 0 + +/* + * + * 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 "disable_rx_mrc_2g" +#define CFG_DISABLE_RX_MRC_2G_MIN 0 +#define CFG_DISABLE_RX_MRC_2G_MAX 1 +#define CFG_DISABLE_RX_MRC_2G_DEF 0 + +/* + * + * 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 "disable_tx_mrc_5g" +#define CFG_DISABLE_TX_MRC_5G_MIN 0 +#define CFG_DISABLE_TX_MRC_5G_MAX 1 +#define CFG_DISABLE_TX_MRC_5G_DEF 0 + +/* + * + * 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 "disable_rx_mrc_5g" +#define CFG_DISABLE_RX_MRC_5G_MIN 0 +#define CFG_DISABLE_RX_MRC_5G_MAX 1 +#define CFG_DISABLE_RX_MRC_5G_DEF 0 + +/* + * + * gEnable_go_cts2self_for_sta - Indicate firmware to stop NOA and + * start using cts2self + * @Min: 1 + * @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 "gEnable_go_cts2self_for_sta" +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA_DEFAULT (0) +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA_MIN (0) +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA_MAX (1) + +#define CFG_CE_CLASSIFY_ENABLE_NAME "gCEClassifyEnable" +#define CFG_CE_CLASSIFY_ENABLE_MIN (0) +#define CFG_CE_CLASSIFY_ENABLE_MAX (1) +#define CFG_CE_CLASSIFY_ENABLE_DEFAULT (1) + +/* + * + * + * gDualMacFeatureDisable - Disable Dual MAC feature. + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * 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: Internal/External + * + * + */ +#define CFG_DUAL_MAC_FEATURE_DISABLE "gDualMacFeatureDisable" +#define CFG_DUAL_MAC_FEATURE_DISABLE_MIN (0) +#define CFG_DUAL_MAC_FEATURE_DISABLE_MAX (6) +#define CFG_DUAL_MAC_FEATURE_DISABLE_DEFAULT (0) + +/* + * + * 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_NAME "gdbs_scan_selection" +#define CFG_DBS_SCAN_SELECTION_DEFAULT "" + +/* + * + * g_sta_sap_scc_on_dfs_chan - Allow STA+SAP SCC on DFS channel with master + * mode support disabled. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to allow STA+SAP SCC on DFS channel with master mode + * support disabled. + * 0 - Disallow STA+SAP SCC on DFS channel + * 1 - Allow STA+SAP SCC on DFS channel with master mode disabled + * + * Related: None. + * + * Supported Feature: Non-DBS, DBS + * + * Usage: Internal/External + * + * + */ +#define CFG_STA_SAP_SCC_ON_DFS_CHAN "g_sta_sap_scc_on_dfs_chan" +#define CFG_STA_SAP_SCC_ON_DFS_CHAN_MIN (0) +#define CFG_STA_SAP_SCC_ON_DFS_CHAN_MAX (1) +#define CFG_STA_SAP_SCC_ON_DFS_CHAN_DEFAULT (0) + +/* + * + * g_sta_sap_scc_on_lte_coex_chan - Allow STA+SAP SCC on LTE coex channel + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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: Internal/External + * + * + */ +#define CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN "g_sta_sap_scc_on_lte_coex_chan" +#define CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN_MIN (0) +#define CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN_MAX (1) +#define CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN_DEFAULT (0) + +/* + * gPNOChannelPrediction will allow user to enable/disable the + * PNO channel prediction feature. + * In current PNO implementation, scan is always done until all configured + * channels are scanned. If we can determine DUT is stationary based on + * scanning a subset of channels, we may cancel the remaining channels. + * Hence, we can save additional power consumption. + */ +#define CFG_PNO_CHANNEL_PREDICTION_NAME "gPNOChannelPrediction" +#define CFG_PNO_CHANNEL_PREDICTION_MIN (0) +#define CFG_PNO_CHANNEL_PREDICTION_MAX (1) +#define CFG_PNO_CHANNEL_PREDICTION_DEFAULT (0) +/* + * The top K number of channels are used for tanimoto distance + * calculation. These are the top channels on which the probability + * of finding the AP's is extremely high. This number is intended + * for tweaking the internal algorithm for experiments. This should + * not be changed externally. + */ +#define CFG_TOP_K_NUM_OF_CHANNELS_NAME "gTopKNumOfChannels" +#define CFG_TOP_K_NUM_OF_CHANNELS_MIN (1) +#define CFG_TOP_K_NUM_OF_CHANNELS_MAX (5) +#define CFG_TOP_K_NUM_OF_CHANNELS_DEFAULT (3) +/* + * This is the threshold value to determine that the STA is + * stationary. If the tanimoto distance is less than this + * value, then the device is considered to be stationary. + * This parameter is intended to tweak the internal algorithm + * for experiments. This should not be changed externally. + */ +#define CFG_STATIONARY_THRESHOLD_NAME "gStationaryThreshold" +#define CFG_STATIONARY_THRESHOLD_MIN (0) +#define CFG_STATIONARY_THRESHOLD_MAX (100) +#define CFG_STATIONARY_THRESHOLD_DEFAULT (10) + +/* Option to report rssi in cfg80211_inform_bss_frame() + * 0 = use rssi value based on noise floor = -96 dBm + * 1 = use rssi value based on actual noise floor in hardware + */ +#define CFG_INFORM_BSS_RSSI_RAW_NAME "gInformBssRssiRaw" +#define CFG_INFORM_BSS_RSSI_RAW_MIN (0) +#define CFG_INFORM_BSS_RSSI_RAW_MAX (1) +#define CFG_INFORM_BSS_RSSI_RAW_DEFAULT (1) + +/* GPIO pin to toggle when capture tsf */ +#define CFG_SET_TSF_GPIO_PIN_NAME "gtsf_gpio_pin" +#define CFG_SET_TSF_GPIO_PIN_MIN (0) +#define CFG_SET_TSF_GPIO_PIN_MAX (254) +#define TSF_GPIO_PIN_INVALID (255) +#define CFG_SET_TSF_GPIO_PIN_DEFAULT (TSF_GPIO_PIN_INVALID) + +#ifdef WLAN_FEATURE_TSF_PLUS +/* PTP options */ +#define CFG_SET_TSF_PTP_OPT_NAME "gtsf_ptp_options" +#define CFG_SET_TSF_PTP_OPT_MIN (0) +#define CFG_SET_TSF_PTP_OPT_MAX (0xff) +#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_OPT_DEFAULT (0xf) +#endif + +/* + * + * 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_ENABLE_TW_COEX_LEGACY_NAME "gThreeWayCoexConfigLegacyEnable" +#define CFG_ENABLE_TW_COEX_LEGACY_MIN (0) +#define CFG_ENABLE_TW_COEX_LEGACY_MAX (1) +#define CFG_ENABLE_TW_COEX_LEGACY_DEFAULT (0) + +/* + * Dense traffic threshold + * traffic threshold required for dense roam scan + * Measured in kbps + */ +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD "gtraffic_threshold" +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MIN (0) +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MAX (0xffffffff) +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_DEFAULT (400) + +/* + * + * 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/Internal + * + * + */ +#define CFG_USER_AUTO_CHANNEL_SELECTION "gvendor_acs_support" +#define CFG_USER_AUTO_CHANNEL_SELECTION_DISABLE (0) +#define CFG_USER_AUTO_CHANNEL_SELECTION_ENABLE (1) +#define CFG_USER_AUTO_CHANNEL_SELECTION_DEFAULT (0) + +/* + * + * 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 "gacs_support_for_dfs_lte_coex" +#define CFG_USER_ACS_DFS_LTE_DISABLE (0) +#define CFG_USER_ACS_DFS_LTE_ENABLE (1) +#define CFG_USER_ACS_DFS_LTE_DEFAULT (0) + +/* + * Enabling gignore_peer_ht_opmode will enable 11g + * protection only when there is a 11g AP in vicinity. + */ +#define CFG_IGNORE_PEER_HT_MODE_NAME "gignore_peer_ht_opmode" +#define CFG_IGNORE_PEER_HT_MODE_MIN (0) +#define CFG_IGNORE_PEER_HT_MODE_MAX (1) +#define CFG_IGNORE_PEER_HT_MODE_DEFAULT (0) + +#ifdef WLAN_FEATURE_NAN_DATAPATH +/* + * Enable NaN data path feature. NaN data path enables + * NaN supported devices to exchange data over traditional + * TCP/UDP network stack. + */ +#define CFG_ENABLE_NAN_DATAPATH_NAME "genable_nan_datapath" +#define CFG_ENABLE_NAN_DATAPATH_MIN (0) +#define CFG_ENABLE_NAN_DATAPATH_MAX (1) +#define CFG_ENABLE_NAN_DATAPATH_DEFAULT (0) + +/* + * NAN channel on which NAN data interface to start + */ +#define CFG_ENABLE_NAN_NDI_CHANNEL_NAME "gnan_datapath_ndi_channel" +#define CFG_ENABLE_NAN_NDI_CHANNEL_MIN (6) +#define CFG_ENABLE_NAN_NDI_CHANNEL_MAX (149) +#define CFG_ENABLE_NAN_NDI_CHANNEL_DEFAULT (6) +#endif + +/* + * Enable/Disable to initiate BUG report in case of fatal event + * Default: Enable + */ +#define CFG_ENABLE_FATAL_EVENT_TRIGGER "gEnableFatalEvent" +#define CFG_ENABLE_FATAL_EVENT_TRIGGER_MIN (0) +#define CFG_ENABLE_FATAL_EVENT_TRIGGER_MAX (1) +#define CFG_ENABLE_FATAL_EVENT_TRIGGER_DEFAULT (1) + +/* + * + * 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_ENABLE_EDCA_INI_NAME "gEnableEdcaParams" +#define CFG_ENABLE_EDCA_INI_MIN (0) +#define CFG_ENABLE_EDCA_INI_MAX (1) +#define CFG_ENABLE_EDCA_INI_DEFAULT (0) + +/* + * + * gEdcaVoCwmin - Set Cwmin value for EDCA_AC_VO + * @Min: 0 + * @Max: 0x15 + * @Default: 2 + * + * This ini is used to set default Cwmin value for EDCA_AC_VO + * Cwmin value for EDCA_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_VALUE_NAME "gEdcaVoCwmin" +#define CFG_EDCA_VO_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_VO_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_VO_CWMIN_VALUE_DEFAULT (2) + +/* + * + * gEdcaViCwmin - Set Cwmin value for EDCA_AC_VI + * @Min: 0x0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default value for EDCA_AC_VI + * Cwmin value for EDCA_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_VALUE_NAME "gEdcaViCwmin" +#define CFG_EDCA_VI_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_VI_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_VI_CWMIN_VALUE_DEFAULT (3) + +/* + * + * gEdcaBkCwmin - Set Cwmin value for EDCA_AC_BK + * @Min: 0x0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmin value for EDCA_AC_BK + * Cwmin value for EDCA_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_VALUE_NAME "gEdcaBkCwmin" +#define CFG_EDCA_BK_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_BK_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_BK_CWMIN_VALUE_DEFAULT (4) + +/* + * + * gEdcaBeCwmin - Set Cwmin value for EDCA_AC_BE + * @Min: 0x0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmin value for EDCA_AC_BE + * Cwmin value for EDCA_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_VALUE_NAME "gEdcaBeCwmin" +#define CFG_EDCA_BE_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_BE_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_BE_CWMIN_VALUE_DEFAULT (4) + +/* + * + * gEdcaVoCwmax - Set Cwmax value for EDCA_AC_VO + * @Min: 0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default Cwmax value for EDCA_AC_VO + * Cwmax value for EDCA_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_VALUE_NAME "gEdcaVoCwmax" +#define CFG_EDCA_VO_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_VO_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_VO_CWMAX_VALUE_DEFAULT (3) + +/* + * + * gEdcaViCwmax - Set Cwmax value for EDCA_AC_VI + * @Min: 0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmax value for EDCA_AC_VI + * Cwmax value for EDCA_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_VALUE_NAME "gEdcaViCwmax" +#define CFG_EDCA_VI_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_VI_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_VI_CWMAX_VALUE_DEFAULT (4) + +/* + * + * gEdcaBkCwmax - Set Cwmax value for EDCA_AC_BK + * @Min: 0 + * @Max: 15 + * @Default: 10 + * + * This ini is used to set default Cwmax value for EDCA_AC_BK + * Cwmax value for EDCA_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_VALUE_NAME "gEdcaBkCwmax" +#define CFG_EDCA_BK_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_BK_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_BK_CWMAX_VALUE_DEFAULT (10) + +/* + * + * gEdcaBeCwmax - Set Cwmax value for EDCA_AC_BE + * @Min: 0 + * @Max: 15 + * @Default: 10 + * + * This ini is used to set default Cwmax value for EDCA_AC_BE + * Cwmax value for EDCA_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_VALUE_NAME "gEdcaBeCwmax" +#define CFG_EDCA_BE_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_BE_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_BE_CWMAX_VALUE_DEFAULT (10) + +/* + * + * gEdcaVoAifs - Set Aifs value for EDCA_AC_VO + * @Min: 0 + * @Max: 15 + * @Default: 2 + * + * This ini is used to set default Aifs value for EDCA_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_VALUE_NAME "gEdcaVoAifs" +#define CFG_EDCA_VO_AIFS_VALUE_MIN (0) +#define CFG_EDCA_VO_AIFS_VALUE_MAX (15) +#define CFG_EDCA_VO_AIFS_VALUE_DEFAULT (2) + +/* + * + * gEdcaViAifs - Set Aifs value for EDCA_AC_VI + * @Min: 0 + * @Max: 15 + * @Default: 2 + * + * This ini is used to set default Aifs value for EDCA_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_VALUE_NAME "gEdcaViAifs" +#define CFG_EDCA_VI_AIFS_VALUE_MIN (0) +#define CFG_EDCA_VI_AIFS_VALUE_MAX (15) +#define CFG_EDCA_VI_AIFS_VALUE_DEFAULT (2) + +/* + * + * gEdcaBkAifs - Set Aifs value for EDCA_AC_BK + * @Min: 0 + * @Max: 15 + * @Default: 7 + * + * This ini is used to set default Aifs value for EDCA_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_VALUE_NAME "gEdcaBkAifs" +#define CFG_EDCA_BK_AIFS_VALUE_MIN (0) +#define CFG_EDCA_BK_AIFS_VALUE_MAX (15) +#define CFG_EDCA_BK_AIFS_VALUE_DEFAULT (7) + +/* + * + * gEdcaBeAifs - Set Aifs value for EDCA_AC_BE + * @Min: 0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default Aifs value for EDCA_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_VALUE_NAME "gEdcaBeAifs" +#define CFG_EDCA_BE_AIFS_VALUE_MIN (0) +#define CFG_EDCA_BE_AIFS_VALUE_MAX (15) +#define CFG_EDCA_BE_AIFS_VALUE_DEFAULT (3) + +/* + * + * 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_ENABLE_TX_SCHED_WRR_VO_NAME "gEnableTxSchedWrrVO" +#define CFG_ENABLE_TX_SCHED_WRR_VO_DEFAULT "" + +/* + * + * 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_ENABLE_TX_SCHED_WRR_VI_NAME "gEnableTxSchedWrrVI" +#define CFG_ENABLE_TX_SCHED_WRR_VI_DEFAULT "" + +/* + * + * 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_ENABLE_TX_SCHED_WRR_BE_NAME "gEnableTxSchedWrrBE" +#define CFG_ENABLE_TX_SCHED_WRR_BE_DEFAULT "" + +/* + * + * 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_ENABLE_TX_SCHED_WRR_BK_NAME "gEnableTxSchedWrrBK" +#define CFG_ENABLE_TX_SCHED_WRR_BK_DEFAULT "" + +#ifdef CONFIG_DP_TRACE +/* + * Enable/disable DPTRACE + * Enabling this might have performace impact. + */ +#define CFG_ENABLE_DP_TRACE "enable_dp_trace" +#define CFG_ENABLE_DP_TRACE_MIN (0) +#define CFG_ENABLE_DP_TRACE_MAX (1) +#define CFG_ENABLE_DP_TRACE_DEFAULT (1) + +/* 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 +/* + * 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 + */ +#define CFG_ENABLE_DP_TRACE_CONFIG "gDptraceConfig" +#define CFG_ENABLE_DP_TRACE_CONFIG_DEFAULT "1, 6, 2, 126" +#endif + +/* + * This parameter will set the weight to calculate the average low pass + * filter for channel congestion. + * Acceptable values for this: 0-100 (In %) + */ +#define CFG_ADAPT_DWELL_LPF_WEIGHT_NAME "adapt_dwell_lpf_weight" +#define CFG_ADAPT_DWELL_LPF_WEIGHT_MIN (0) +#define CFG_ADAPT_DWELL_LPF_WEIGHT_MAX (100) +#define CFG_ADAPT_DWELL_LPF_WEIGHT_DEFAULT (80) + +/* + * This parameter will set interval to monitor wifi activity + * in passive scan in msec. + * Acceptable values for this: 0-25 + */ +#define CFG_ADAPT_DWELL_PASMON_INTVAL_NAME "adapt_dwell_passive_mon_intval" +#define CFG_ADAPT_DWELL_PASMON_INTVAL_MIN (0) +#define CFG_ADAPT_DWELL_PASMON_INTVAL_MAX (25) +#define CFG_ADAPT_DWELL_PASMON_INTVAL_DEFAULT (10) + +/* + * This parameter will set % of wifi activity used in passive scan 0-100. + * Acceptable values for this: 0-100 (in %) + */ +#define CFG_ADAPT_DWELL_WIFI_THRESH_NAME "adapt_dwell_wifi_act_threshold" +#define CFG_ADAPT_DWELL_WIFI_THRESH_MIN (0) +#define CFG_ADAPT_DWELL_WIFI_THRESH_MAX (100) +#define CFG_ADAPT_DWELL_WIFI_THRESH_DEFAULT (10) + +/* + * + * 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_NAME "g_bug_on_reinit_failure" +#define CFG_BUG_ON_REINIT_FAILURE_MIN (0) +#define CFG_BUG_ON_REINIT_FAILURE_MAX (1) +#define CFG_BUG_ON_REINIT_FAILURE_DEFAULT (1) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_SUB_20_CHANNEL_WIDTH_NAME "gSub20ChannelWidth" +#define CFG_SUB_20_CHANNEL_WIDTH_MIN (WLAN_SUB_20_CH_WIDTH_NONE) +#define CFG_SUB_20_CHANNEL_WIDTH_MAX (WLAN_SUB_20_CH_WIDTH_10) +#define CFG_SUB_20_CHANNEL_WIDTH_DEFAULT (WLAN_SUB_20_CH_WIDTH_NONE) + +#define CFG_TGT_GTX_USR_CFG_NAME "tgt_gtx_usr_cfg" +#define CFG_TGT_GTX_USR_CFG_MIN (0) +#define CFG_TGT_GTX_USR_CFG_MAX (32) +#define CFG_TGT_GTX_USR_CFG_DEFAULT (32) + +#define CFG_SAP_INTERNAL_RESTART_NAME "gEnableSapInternalRestart" +#define CFG_SAP_INTERNAL_RESTART_MIN (0) +#define CFG_SAP_INTERNAL_RESTART_MAX (1) +#define CFG_SAP_INTERNAL_RESTART_DEFAULT (1) + +/* + * + * 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_NAME "restart_beaconing_on_chan_avoid_event" +#define CFG_RESTART_BEACONING_ON_CH_AVOID_MIN (CH_AVOID_RULE_DO_NOT_RESTART) +#define CFG_RESTART_BEACONING_ON_CH_AVOID_MAX (CH_AVOID_RULE_RESTART_24G_ONLY) +#define CFG_RESTART_BEACONING_ON_CH_AVOID_DEFAULT (CH_AVOID_RULE_RESTART) +/* + * 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. + * Default : Disable + */ +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_NAME "gSapMaxInactivityOverride" +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_MIN (0) +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_MAX (1) +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_DEFAULT (0) + +/* + * + * rx_mode - Control to decide rx mode + * + * @Min: 0 + * @Max: (CFG_ENABLE_RX_THREAD | CFG_ENABLE_RPS | CFG_ENABLE_NAPI | \ + * CFG_ENABLE_DYNAMIC_RPS) + * @Default: MDM_PLATFORM - 0 + * HELIUMPLUS - CFG_ENABLE_NAPI + * Other cases - (CFG_ENABLE_RX_THREAD | CFG_ENABLE_NAPI) + * + * This ini is used to decide mode for the rx path + * + * Supported Feature: NAPI + * + * Usage: Internal + * + * + */ +#define CFG_RX_MODE_NAME "rx_mode" +#define CFG_RX_MODE_MIN (0) +#define CFG_RX_MODE_MAX (CFG_ENABLE_RX_THREAD | CFG_ENABLE_RPS | \ + CFG_ENABLE_NAPI | CFG_ENABLE_DYNAMIC_RPS) +#ifdef MDM_PLATFORM +#define CFG_RX_MODE_DEFAULT (0) +#elif defined(HELIUMPLUS) +#define CFG_RX_MODE_DEFAULT CFG_ENABLE_NAPI +#else +#define CFG_RX_MODE_DEFAULT (CFG_ENABLE_RX_THREAD | CFG_ENABLE_NAPI) +#endif + +/* + * + * ce_service_max_yield_time - Control to set ce service max yield time (in us) + * + * @Min: 500 + * @Max: 10000 + * @Default: 10000 + * + * This ini is used to set ce service max yield time (in us) + * + * Supported Feature: NAPI + * + * Usage: Internal + * + * + */ +#define CFG_CE_SERVICE_MAX_YIELD_TIME_NAME "ce_service_max_yield_time" +#define CFG_CE_SERVICE_MAX_YIELD_TIME_MIN (500) +#define CFG_CE_SERVICE_MAX_YIELD_TIME_MAX (10000) +#define CFG_CE_SERVICE_MAX_YIELD_TIME_DEFAULT (10000) + +/* + * + * ce_service_max_rx_ind_flush - Control to set ce service max rx ind flush + * + * @Min: 1 + * @Max: 32 + * @Default: 1 + * + * This ini is used to set ce service max rx ind flush + * + * Supported Feature: NAPI + * + * Usage: Internal + * + * + */ +#define CFG_CE_SERVICE_MAX_RX_IND_FLUSH_NAME "ce_service_max_rx_ind_flush" +#define CFG_CE_SERVICE_MAX_RX_IND_FLUSH_MIN (1) +#define CFG_CE_SERVICE_MAX_RX_IND_FLUSH_MAX (32) +#define CFG_CE_SERVICE_MAX_RX_IND_FLUSH_DEFAULT (32) + +/* + * + * 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_NAPI_CE_CPU_MASK_NAME "NAPI_CPU_AFFINITY_MASK" +#define CFG_NAPI_CE_CPU_MASK_MIN (0) +#define CFG_NAPI_CE_CPU_MASK_MAX (0xFF) +#define CFG_NAPI_CE_CPU_MASK_DEFAULT (0) + +/* + * + * RX_THREAD_CPU_AFFINITY_MASK - CPU mask to affine Rx_thread + * + * @Min: 0 + * @Max: 0xFF + * @Default: 0 + * + * This ini is used to set Rx_thread CPU affinity + * + * Supported Feature: Rx_thread + * + * Usage: Internal + * + * + */ +#define CFG_RX_THREAD_CPU_MASK_NAME "RX_THREAD_CPU_AFFINITY_MASK" +#define CFG_RX_THREAD_CPU_MASK_MIN (0) +#define CFG_RX_THREAD_CPU_MASK_MAX (0xFF) +#ifdef RX_PERFORMANCE +#define CFG_RX_THREAD_CPU_MASK_DEFAULT (0xFE) +#else +#define CFG_RX_THREAD_CPU_MASK_DEFAULT (0) +#endif + +/* 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. + */ + +/* Name of the ini file entry to specify RPS map for different RX queus */ +#define CFG_RPS_RX_QUEUE_CPU_MAP_LIST_NAME "rpsRxQueueCpuMapList" + +/* 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. + */ +#define CFG_RPS_RX_QUEUE_CPU_MAP_LIST_DEFAULT "e" + +/* 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. + */ +#define CFG_RPS_RX_QUEUE_CPU_MAP_LIST_LEN 30 + +#ifdef WLAN_FEATURE_WOW_PULSE +/* + * Enable/Disable WOW PULSE feature + * Set the wakeup pulse which FW use to wake up HOST + * Default : Disable + */ +#define CFG_WOW_PULSE_SUPPORT_NAME "gwow_pulse_support" +#define CFG_WOW_PULSE_SUPPORT_MIN (0) +#define CFG_WOW_PULSE_SUPPORT_MAX (1) +#define CFG_WOW_PULSE_SUPPORT_DEFAULT (CFG_WOW_PULSE_SUPPORT_MIN) + +/* + * GPIO PIN for Pulse + * Which PIN to send the Pulse + */ +#define CFG_WOW_PULSE_PIN_NAME "gwow_pulse_pin" +#define CFG_WOW_PULSE_PIN_MIN (CFG_SET_TSF_GPIO_PIN_MIN) +#define CFG_WOW_PULSE_PIN_MAX (CFG_SET_TSF_GPIO_PIN_MAX) +#define CFG_WOW_PULSE_PIN_DEFAULT (35) + +/* + * Pulse interval low + * The interval of low level in the pulse + * The value which defined by customer should between 160 and 480 + */ +#define CFG_WOW_PULSE_INTERVAL_LOW_NAME "gwow_pulse_interval_low" +#define CFG_WOW_PULSE_INTERVAL_LOW_MIN (160) +#define CFG_WOW_PULSE_INTERVAL_LOW_MAX (480) +#define CFG_WOW_PULSE_INTERVAL_LOW_DEFAULT (180) + +/* + * Pulse interval high + * The interval of high level in the pulse + * The value which defined by customer should between 20 and 40 + */ +#define CFG_WOW_PULSE_INTERVAL_HIGH_NAME "gwow_pulse_interval_high" +#define CFG_WOW_PULSE_INTERVAL_HIGH_MIN (20) +#define CFG_WOW_PULSE_INTERVAL_HIGH_MAX (40) +#define CFG_WOW_PULSE_INTERVAL_HIGH_DEFAULT (20) +#endif + +/* + * Support to start sap in indoor channel + * Customer can config this item to enable/disable sap in indoor channel + * Default: Disable + */ +#define CFG_INDOOR_CHANNEL_SUPPORT_NAME "gindoor_channel_support" +#define CFG_INDOOR_CHANNEL_SUPPORT_MIN (0) +#define CFG_INDOOR_CHANNEL_SUPPORT_MAX (1) +#define CFG_INDOOR_CHANNEL_SUPPORT_DEFAULT (0) + +/* + * + * 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_NAME "g_mark_sap_indoor_as_disable" +#define CFG_MARK_INDOOR_AS_DISABLE_MIN (0) +#define CFG_MARK_INDOOR_AS_DISABLE_MAX (1) +#define CFG_MARK_INDOOR_AS_DISABLE_DEFAULT (0) + +/* + * Force softap to 11n, when gSapForce11NFor11AC is set to 1 from ini + * despite of hostapd.conf request for 11ac + */ +#define CFG_SAP_FORCE_11N_FOR_11AC_NAME "gSapForce11NFor11AC" +#define CFG_SAP_FORCE_11N_FOR_11AC_MIN (0) +#define CFG_SAP_FORCE_11N_FOR_11AC_MAX (1) +#define CFG_SAP_FORCE_11N_FOR_11AC_DEFAULT (0) + +#define CFG_GO_FORCE_11N_FOR_11AC_NAME "gGoForce11NFor11AC" +#define CFG_GO_FORCE_11N_FOR_11AC_MIN (0) +#define CFG_GO_FORCE_11N_FOR_11AC_MAX (1) +#define CFG_GO_FORCE_11N_FOR_11AC_DEFAULT (0) + +/* + * sap tx leakage threshold + * customer can set this value from 100 to 1000 which means + * sap tx leakage threshold is -10db to -100db + */ +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_NAME "gsap_tx_leakage_threshold" +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_MIN (100) +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_MAX (1000) +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_DEFAULT (310) + + +/* + * 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_FILTER_MULTICAST_REPLAY_NAME "enable_multicast_replay_filter" +#define CFG_FILTER_MULTICAST_REPLAY_MIN (0) +#define CFG_FILTER_MULTICAST_REPLAY_MAX (1) +#define CFG_FILTER_MULTICAST_REPLAY_DEFAULT (1) + +/* Optimize channel avoidance indication coming from firmware */ +#define CFG_OPTIMIZE_CA_EVENT_NAME "goptimize_chan_avoid_event" +#define CFG_OPTIMIZE_CA_EVENT_DISABLE (0) +#define CFG_OPTIMIZE_CA_EVENT_ENABLE (1) +#define CFG_OPTIMIZE_CA_EVENT_DEFAULT (0) + +/* + * + * 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: Internal/External + * + * + */ +#define CFG_CRASH_FW_TIMEOUT_NAME "fw_timeout_crash" +#define CFG_CRASH_FW_TIMEOUT_DISABLE (0) +#define CFG_CRASH_FW_TIMEOUT_ENABLE (1) +#define CFG_CRASH_FW_TIMEOUT_DEFAULT (1) + +/* + * + * 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_RX_WAKELOCK_TIMEOUT_NAME "rx_wakelock_timeout" +#define CFG_RX_WAKELOCK_TIMEOUT_DEFAULT (50) +#define CFG_RX_WAKELOCK_TIMEOUT_MIN (0) +#define CFG_RX_WAKELOCK_TIMEOUT_MAX (100) + +/* + * + * 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_ENABLE_5G_BAND_PREF_NAME "enable_5g_band_pref" +#define CFG_ENABLE_5G_BAND_PREF_MIN (0) +#define CFG_ENABLE_5G_BAND_PREF_MAX (1) +#define CFG_ENABLE_5G_BAND_PREF_DEFAULT (0) + +/* + * + * 5g_rssi_boost_threshold - A_band_boost_threshold above which 5 GHz 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_5G_RSSI_BOOST_THRESHOLD_NAME "5g_rssi_boost_threshold" +#define CFG_5G_RSSI_BOOST_THRESHOLD_MIN (-70) +#define CFG_5G_RSSI_BOOST_THRESHOLD_MAX (-55) +#define CFG_5G_RSSI_BOOST_THRESHOLD_DEFAULT (-60) + +/* + * + * 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_5G_RSSI_BOOST_FACTOR_NAME "5g_rssi_boost_factor" +#define CFG_5G_RSSI_BOOST_FACTOR_MIN (0) +#define CFG_5G_RSSI_BOOST_FACTOR_MAX (2) +#define CFG_5G_RSSI_BOOST_FACTOR_DEFAULT (1) + +/* + * + * 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_5G_MAX_RSSI_BOOST_NAME "5g_max_rssi_boost" +#define CFG_5G_MAX_RSSI_BOOST_MIN (0) +#define CFG_5G_MAX_RSSI_BOOST_MAX (20) +#define CFG_5G_MAX_RSSI_BOOST_DEFAULT (10) + +/* + * + * 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_5G_RSSI_PENALIZE_THRESHOLD_NAME "5g_rssi_penalize_threshold" +#define CFG_5G_RSSI_PENALIZE_THRESHOLD_MIN (-80) +#define CFG_5G_RSSI_PENALIZE_THRESHOLD_MAX (-65) +#define CFG_5G_RSSI_PENALIZE_THRESHOLD_DEFAULT (-70) + +/* + * + * 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_5G_RSSI_PENALIZE_FACTOR_NAME "5g_rssi_penalize_factor" +#define CFG_5G_RSSI_PENALIZE_FACTOR_MIN (0) +#define CFG_5G_RSSI_PENALIZE_FACTOR_MAX (2) +#define CFG_5G_RSSI_PENALIZE_FACTOR_DEFAULT (1) + +/* + * + * 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_5G_MAX_RSSI_PENALIZE_NAME "5g_max_rssi_penalize" +#define CFG_5G_MAX_RSSI_PENALIZE_MIN (0) +#define CFG_5G_MAX_RSSI_PENALIZE_MAX (20) +#define CFG_5G_MAX_RSSI_PENALIZE_DEFAULT (10) + +/* + * + * g_max_sched_scan_plan_int - pno sched max scan plan interval. + * @Min: 1 + * @Max: 7200 + * @Default: 3600 + * + * This ini is used to set max sched scan plan interval for pno scan + * (value in seconds). + * + * Related: gPNOScanSupport + * + * Supported Feature: PNO scan + * + * Usage: External + * + * + */ +#define CFG_MAX_SCHED_SCAN_PLAN_INT_NAME "g_max_sched_scan_plan_int" +#define CFG_MAX_SCHED_SCAN_PLAN_INT_MIN (1) +#define CFG_MAX_SCHED_SCAN_PLAN_INT_MAX (7200) +#define CFG_MAX_SCHED_SCAN_PLAN_INT_DEFAULT (3600) + +/* + * + * g_max_sched_scan_plan_iterations - pno sched max scan plan iterations. + * @Min: 1 + * @Max: 100 + * @Default: 10 + * + * This ini is used to set max sched scan plan iterations for pno scan + * (value in seconds). + * + * Related: gPNOScanSupport + * + * Supported Feature: PNO scan + * + * Usage: External + * + * + */ +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_NAME "g_max_sched_scan_plan_iterations" +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MIN (1) +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MAX (100) +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_DEFAULT (10) + +/** + * 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 superceeded + * 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_NAME "private_wext_control" +#define CFG_PRIVATE_WEXT_CONTROL_MIN (hdd_wext_disabled) +#define CFG_PRIVATE_WEXT_CONTROL_MAX (hdd_wext_enabled) +#define CFG_PRIVATE_WEXT_CONTROL_DEFAULT (hdd_wext_deprecated) + +/* + * + * 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_PER_ROAM_MONITOR_TIME "gper_roam_mon_time" +#define CFG_PER_ROAM_MONITOR_TIME_MIN (5) +#define CFG_PER_ROAM_MONITOR_TIME_MAX (25) +#define CFG_PER_ROAM_MONTIOR_TIME_DEFAULT (25) + +/* + * + * gPowerUsage - Preferred Power Usage + * @Min: Min + * @Max: Max + * @Default: Mod + * + * This ini is used to set the preferred power usage + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_POWER_USAGE_NAME "gPowerUsage" +#define CFG_POWER_USAGE_MIN "Min" +#define CFG_POWER_USAGE_MAX "Max" +#define CFG_POWER_USAGE_DEFAULT "Mod" + + +/* + * + * 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_PER_ROAM_MIN_CANDIDATE_RSSI "gper_min_rssi_threshold_for_roam" +#define CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MIN (0) +#define CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MAX (96) +#define CFG_PER_ROAM_MIN_CANDIDATE_RSSI_DEFAULT (83) + + +/* + * + * 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_NAME "gEnableImps" +#define CFG_ENABLE_IMPS_MIN (0) +#define CFG_ENABLE_IMPS_MAX (1) +#define CFG_ENABLE_IMPS_DEFAULT (1) + +/* + * + * 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_NAME "gEnableBmps" +#define CFG_ENABLE_PS_MIN (0) +#define CFG_ENABLE_PS_MAX (1) +#define CFG_ENABLE_PS_DEFAULT (1) + +/* + * + * 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_PS_ENABLE_TIMER_NAME "gAutoBmpsTimerValue" +#define CFG_AUTO_PS_ENABLE_TIMER_MIN (0) +#define CFG_AUTO_PS_ENABLE_TIMER_MAX (1000) +#define CFG_AUTO_PS_ENABLE_TIMER_DEFAULT (600) + +#ifdef WLAN_ICMP_DISABLE_PS +/* + * + * gIcmpDisablePsValue - Set ICMP packet disable power save value + * @Min: 0 + * @Max: 10000 + * @Default: 5000 + * + * This ini is used to set ICMP packet disable power save value in + * millisecond. + * + * Related: gEnableBmps + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ICMP_DISABLE_PS_NAME "gIcmpDisablePsValue" +#define CFG_ICMP_DISABLE_PS_MIN (0) +#define CFG_ICMP_DISABLE_PS_MAX (10000) +#define CFG_ICMP_DISABLE_PS_DEFAULT (5000) +#endif + +/* + * + * 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_NAME "gBmpsMinListenInterval" +#define CFG_BMPS_MINIMUM_LI_MIN (1) +#define CFG_BMPS_MINIMUM_LI_MAX (65535) +#define CFG_BMPS_MINIMUM_LI_DEFAULT (1) + +/* + * + * 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_NAME "gBmpsMaxListenInterval" +#define CFG_BMPS_MAXIMUM_LI_MIN (1) +#define CFG_BMPS_MAXIMUM_LI_MAX (65535) +#define CFG_BMPS_MAXIMUM_LI_DEFAULT (1) + +#ifdef FEATURE_RUNTIME_PM +/* + * + * gRuntimePM - enable runtime suspend + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable runtime_suspend + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_RUNTIME_PM "gRuntimePM" +#define CFG_ENABLE_RUNTIME_PM_MIN (0) +#define CFG_ENABLE_RUNTIME_PM_MAX (1) +#define CFG_ENABLE_RUNTIME_PM_DEFAULT (0) + +/* + * + * gRuntimePMDelay - Set runtime pm's inactivity timer + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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_RUNTIME_PM_DELAY_NAME "gRuntimePMDelay" +#define CFG_RUNTIME_PM_DELAY_MIN (100) +#define CFG_RUNTIME_PM_DELAY_MAX (10000) +#define CFG_RUNTIME_PM_DELAY_DEFAULT (500) +#endif + +/* + * + * gEnablePowerSaveOffload - Enable Power Save Offload + * @Min: 0 + * @Max: 5 + * @Default: 0 + * + * This ini is used to set Power Save Offload configuration: + * Current values of gEnablePowerSaveOffload: + * 0 -> Power save offload is disabled + * 1 -> Legacy Power save enabled + Deep sleep Disabled + * 2 -> QPower enabled + Deep sleep Disabled + * 3 -> Legacy Power save enabled + Deep sleep Enabled + * 4 -> QPower enabled + Deep sleep Enabled + * 5 -> Duty cycling QPower enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_POWERSAVE_OFFLOAD_NAME "gEnablePowerSaveOffload" +#define CFG_POWERSAVE_OFFLOAD_MIN (0) +#define CFG_POWERSAVE_OFFLOAD_MAX (PS_DUTY_CYCLING_QPOWER) +#define CFG_POWERSAVE_OFFLOAD_DEFAULT (CFG_POWERSAVE_OFFLOAD_MIN) + +/* + * + * 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 patter and pattern byte match on all interfaces. + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_WOW_STATUS_NAME "gEnableWoW" +#define CFG_WOW_ENABLE_MIN (0) +#define CFG_WOW_ENABLE_MAX (3) +#define CFG_WOW_STATUS_DEFAULT (3) + +#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_GO_TO_SUSPEND "gExtWoWgotoSuspend" +#define CFG_EXTWOW_GO_TO_SUSPEND_MIN (0) +#define CFG_EXTWOW_GO_TO_SUSPEND_MAX (1) +#define CFG_EXTWOW_GO_TO_SUSPEND_DEFAULT (1) + +/* + * + * 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 "gExtWowApp1WakeupPinNumber" +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MIN (0) +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MAX (255) +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_DEFAULT (12) + +/* + * + * 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 "gExtWowApp2WakeupPinNumber" +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MIN (0) +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MAX (255) +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_DEFAULT (16) + +/* + * + * 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 "gExtWoWApp2KAInitPingInterval" +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_DEFAULT (240) + +/* + * + * 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 "gExtWoWApp2KAMinPingInterval" +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_DEFAULT (240) + +/* + * + * 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 "gExtWoWApp2KAMaxPingInterval" +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_DEFAULT (1280) + +/* + * + * 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 "gExtWoWApp2KAIncPingInterval" +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_DEFAULT (4) + +/* + * + * gExtWoWApp2KAIncPingInterval - 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 "gExtWoWApp2TcpSrcPort" +#define CFG_EXTWOW_TCP_SRC_PORT_MIN (0) +#define CFG_EXTWOW_TCP_SRC_PORT_MAX (65535) +#define CFG_EXTWOW_TCP_SRC_PORT_DEFAULT (5000) + +/* + * + * 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 "gExtWoWApp2TcpDstPort" +#define CFG_EXTWOW_TCP_DST_PORT_MIN (0) +#define CFG_EXTWOW_TCP_DST_PORT_MAX (65535) +#define CFG_EXTWOW_TCP_DST_PORT_DEFAULT (5001) + +/* + * + * 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 "gExtWoWApp2TcpTxTimeout" +#define CFG_EXTWOW_TCP_TX_TIMEOUT_MIN (0) +#define CFG_EXTWOW_TCP_TX_TIMEOUT_MAX (0xffffffff) +#define CFG_EXTWOW_TCP_TX_TIMEOUT_DEFAULT (200) + +/* + * + * 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 + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_RX_TIMEOUT "gExtWoWApp2TcpRxTimeout" +#define CFG_EXTWOW_TCP_RX_TIMEOUT_MIN (0) +#define CFG_EXTWOW_TCP_RX_TIMEOUT_MAX (0xffffffff) +#define CFG_EXTWOW_TCP_RX_TIMEOUT_DEFAULT (200) +#endif + +/* + * + * gper_roam_enabled - To enabled/disable PER based roaming in FW + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * 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_PER_ROAM_ENABLE_NAME "gper_roam_enabled" +#define CFG_PER_ROAM_ENABLE_MIN (0) +#define CFG_PER_ROAM_ENABLE_MAX (3) +#define CFG_PER_ROAM_ENABLE_DEFAULT (3) + +/* + * + * 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_PER_ROAM_CONFIG_HIGH_RATE_TH_NAME "gper_roam_high_rate_th" +#define CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MIN (10) +#define CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MAX (0xffffffff) +#define CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_DEFAULT (400) + +/* + * + * 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_PER_ROAM_CONFIG_LOW_RATE_TH_NAME "gper_roam_low_rate_th" +#define CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MIN (10) +#define CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MAX (0xffffffff) +#define CFG_PER_ROAM_CONFIG_LOW_RATE_TH_DEFAULT (200) + +/* + * + * 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_PER_ROAM_CONFIG_RATE_TH_PERCENT_NAME "gper_roam_th_percent" +#define CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MIN (10) +#define CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MAX (100) +#define CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_DEFAULT (60) + +/* + * + * 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_PER_ROAM_REST_TIME_NAME "gper_roam_rest_time" +#define CFG_PER_ROAM_REST_TIME_MIN (10) +#define CFG_PER_ROAM_REST_TIME_MAX (3600) +#define CFG_PER_ROAM_REST_TIME_DEFAULT (300) + +/* + * + * 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_NAME "g_is_fils_enabled" +#define CFG_IS_FILS_ENABLED_DEFAULT (1) +#define CFG_IS_FILS_ENABLED_MIN (0) +#define CFG_IS_FILS_ENABLED_MAX (1) + +/* + * + * 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_NAME "g_enable_bcast_probe_rsp" +#define CFG_ENABLE_BCAST_PROBE_RESP_MIN (0) +#define CFG_ENABLE_BCAST_PROBE_RESP_MAX (1) +#define CFG_ENABLE_BCAST_PROBE_RESP_DEFAULT (1) + +/** + * arp_ac_category - ARP access category + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * Firmware by default categorizes ARP packets with VOICE TID. + * This ini shall be used to override the default configuration. + * Access category enums are referenced in ieee80211_common.h + * WME_AC_BE = 0 (Best effort) + * WME_AC_BK = 1 (Background) + * WME_AC_VI = 2 (Video) + * WME_AC_VO = 3 (Voice) + * + * Related: none + * + * Usage: Internal/External + * + * + */ +#define CFG_ARP_AC_CATEGORY "arp_ac_category" +#define CFG_ARP_AC_CATEGORY_MIN (0) +#define CFG_ARP_AC_CATEGORY_MAX (3) +#define CFG_ARP_AC_CATEGORY_DEFAULT (3) + +/* + * + * 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_NAME "gActiveUcBpfMode" +#define CFG_ACTIVE_UC_APF_MODE_MIN (ACTIVE_APF_DISABLED) +#define CFG_ACTIVE_UC_APF_MODE_MAX (ACTIVE_APF_MODE_COUNT - 1) +#define CFG_ACTIVE_UC_APF_MODE_DEFAULT (ACTIVE_APF_DISABLED) + +/* + * + * 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_NAME "gActiveMcBcBpfMode" +#define CFG_ACTIVE_MC_BC_APF_MODE_MIN (ACTIVE_APF_DISABLED) +#define CFG_ACTIVE_MC_BC_APF_MODE_MAX (ACTIVE_APF_ENABLED) +#define CFG_ACTIVE_MC_BC_APF_MODE_DEFAULT (ACTIVE_APF_DISABLED) + +/* + * + * acs_with_more_param- Enable acs calculation with more param. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable acs calculation with more param. + * + * Related: NA + * + * Supported Feature: ACS + * + * Usage: Internal/External + * + * + */ + +#define CFG_ACS_WITH_MORE_PARAM_NAME "acs_with_more_param" +#define CFG_ACS_WITH_MORE_PARAM_MIN (0) +#define CFG_ACS_WITH_MORE_PARAM_MAX (1) +#define CFG_ACS_WITH_MORE_PARAM_DEFAULT (0) + +/* + * + * AutoChannelSelectWeight - ACS channel weight + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 0x000000FF + * + * This ini is used to adjust weight of factors in + * acs algorithm. + * + * Supported Feature: ACS + * + * Usage: Internal/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 "AutoChannelSelectWeight" +#define CFG_AUTO_CHANNEL_SELECT_WEIGHT_MIN (0) +#define CFG_AUTO_CHANNEL_SELECT_WEIGHT_MAX (0xFFFFFFFF) +#define CFG_AUTO_CHANNEL_SELECT_WEIGHT_DEFAULT (0x000000FF) + +#ifdef WLAN_FEATURE_11AX +/* 11AX related INI configuration */ +/* + * + * he_dynamic_frag_support - configure dynamic fragmentation + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * This ini is used to configure dynamic fragmentation. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: Internal/External + * + * + */ + +#define CFG_HE_DYNAMIC_FRAGMENTATION_NAME "he_dynamic_frag_support" +#define CFG_HE_DYNAMIC_FRAGMENTATION_MIN (0) +#define CFG_HE_DYNAMIC_FRAGMENTATION_MAX (3) +#define CFG_HE_DYNAMIC_FRAGMENTATION_DEFAULT (0) + +/* + * + * enable_ul_mimo- Enable UL MIMO. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable UL MIMO. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_UL_MIMO_NAME "enable_ul_mimo" +#define CFG_ENABLE_UL_MIMO_MIN (0) +#define CFG_ENABLE_UL_MIMO_MAX (1) +#define CFG_ENABLE_UL_MIMO_DEFAULT (0) + +/* + * + * enable_ul_ofdma- Enable UL OFDMA. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable UL OFDMA. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_ENABLE_UL_OFDMA_NAME "enable_ul_ofdma" +#define CFG_ENABLE_UL_OFDMA_MIN (0) +#define CFG_ENABLE_UL_OFDMA_MAX (1) +#define CFG_ENABLE_UL_OFDMA_DEFAULT (0) + +/* + * + * 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_NAME "he_sta_obsspd" +#define CFG_HE_STA_OBSSPD_MIN (0) +#define CFG_HE_STA_OBSSPD_MAX (0xffffffff) +#define CFG_HE_STA_OBSSPD_DEFAULT (0x15b8c2ae) + +#endif /* WLAN_FEATURE_11AX */ +#ifdef WLAN_SUPPORT_TWT +/* + * + * 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_NAME "enable_twt" +#define CFG_ENABLE_TWT_MIN (0) +#define CFG_ENABLE_TWT_MAX (1) +#define CFG_ENABLE_TWT_DEFAULT (1) + +/* + * + * 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_NAME "twt_congestion_timeout" +#define CFG_TWT_CONGESTION_TIMEOUT_MIN (0) +#define CFG_TWT_CONGESTION_TIMEOUT_MAX (10000) +#define CFG_TWT_CONGESTION_TIMEOUT_DEFAULT (100) + +#endif /* WLAN_SUPPORT_TWT */ + +/* + * + * 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_NAME "gEnableANI" +#define CFG_ENABLE_ANI_MIN (0) +#define CFG_ENABLE_ANI_MAX (1) +#define CFG_ENABLE_ANI_DEFAULT (1) + +/* + * + * 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_NAME "g_qcn_ie_support" +#define CFG_QCN_IE_SUPPORT_MIN 0 +#define CFG_QCN_IE_SUPPORT_MAX 1 +#define CFG_QCN_IE_SUPPORT_DEFAULT 1 + +/* + * + * 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: N/A + * + * Usage: Internal + * + * + */ +#define CFG_TIMER_MULTIPLIER_NAME "gTimerMultiplier" +#define CFG_TIMER_MULTIPLIER_MIN (1) +#define CFG_TIMER_MULTIPLIER_MAX (0xFFFFFFFF) +#ifdef QCA_WIFI_NAPIER_EMULATION +#define CFG_TIMER_MULTIPLIER_DEFAULT (100) +#else +#define CFG_TIMER_MULTIPLIER_DEFAULT (1) +#endif + +/* Begin of probe request IE whitelisting feature ini params */ +/* + * + * g_enable_probereq_whitelist_ies - Enable IE white listing + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable probe request IE white 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_WHITELIST_NAME "g_enable_probereq_whitelist_ies" +#define CFG_PRB_REQ_IE_WHITELIST_MIN (0) +#define CFG_PRB_REQ_IE_WHITELIST_MAX (1) +#define CFG_PRB_REQ_IE_WHITELIST_DEFAULT (0) + +/* + * For IE white 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP0_NAME "g_probe_req_ie_bitmap_0" +#define CFG_PRB_REQ_IE_BIT_MAP0_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP0_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP0_DEFAULT (0x00000000) + +/* + * + * 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP1_NAME "g_probe_req_ie_bitmap_1" +#define CFG_PRB_REQ_IE_BIT_MAP1_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP1_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP1_DEFAULT (0x00000000) + +/* + * + * 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP2_NAME "g_probe_req_ie_bitmap_2" +#define CFG_PRB_REQ_IE_BIT_MAP2_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP2_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP2_DEFAULT (0x00000000) + +/* + * + * 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP3_NAME "g_probe_req_ie_bitmap_3" +#define CFG_PRB_REQ_IE_BIT_MAP3_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP3_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP3_DEFAULT (0x00000000) + +/* + * + * 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP4_NAME "g_probe_req_ie_bitmap_4" +#define CFG_PRB_REQ_IE_BIT_MAP4_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP4_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP4_DEFAULT (0x00000000) + +/* + * + * 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP5_NAME "g_probe_req_ie_bitmap_5" +#define CFG_PRB_REQ_IE_BIT_MAP5_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP5_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP5_DEFAULT (0x00000000) + +/* + * + * 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP6_NAME "g_probe_req_ie_bitmap_6" +#define CFG_PRB_REQ_IE_BIT_MAP6_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP6_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP6_DEFAULT (0x00000000) + +/* + * + * 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PRB_REQ_IE_BIT_MAP7_NAME "g_probe_req_ie_bitmap_7" +#define CFG_PRB_REQ_IE_BIT_MAP7_MIN (0x00000000) +#define CFG_PRB_REQ_IE_BIT_MAP7_MAX (0xFFFFFFFF) +#define CFG_PRB_REQ_IE_BIT_MAP7_DEFAULT (0x00000000) + +/* + * For vendor specific IE, Probe Req OUI types and sub types which are + * to be white 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 whitelisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_OUI_NAME "gProbeReqOUIs" +#define CFG_PROBE_REQ_OUI_DEFAULT "" +/* End of probe request IE whitelisting feature ini params */ + +/* + * + * g_sap_chanswitch_beacon_cnt - channel switch beacon count + * @Min: 1 + * @Max: 10 + * @Default: 10 + * + * This ini is used to configure channel switch beacon count + * + * Related: none + * + * Usage: External + * + * + */ +#define CFG_SAP_CH_SWITCH_BEACON_CNT "g_sap_chanswitch_beacon_cnt" +#define CFG_SAP_CH_SWITCH_BEACON_CNT_MIN (1) +#define CFG_SAP_CH_SWITCH_BEACON_CNT_MAX (10) +#define CFG_SAP_CH_SWITCH_BEACON_CNT_DEFAULT (10) + +/* + * + * g_sap_chanswitch_mode - channel switch mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to configure channel switch mode + * + * Related: none + * + * Usage: External + * + * + */ +#define CFG_SAP_CH_SWITCH_MODE "g_sap_chanswitch_mode" +#define CFG_SAP_CH_SWITCH_MODE_MIN (0) +#define CFG_SAP_CH_SWITCH_MODE_MAX (1) +#define CFG_SAP_CH_SWITCH_MODE_DEFAULT (1) + +/* + * + * 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 milli seconds + * + * Related: None + * + * Supported Feature: FILS + * + * Usage: External + * + * + */ +#define CFG_FILS_MAX_CHAN_GUARD_TIME_NAME "g_fils_max_chan_guard_time" +#define CFG_FILS_MAX_CHAN_GUARD_TIME_MIN (0) +#define CFG_FILS_MAX_CHAN_GUARD_TIME_MAX (10) +#define CFG_FILS_MAX_CHAN_GUARD_TIME_DEFAULT (0) + +/** + * 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 "gSetRTSForSIFSBursting" +#define CFG_SET_RTS_FOR_SIFS_BURSTING_MIN (0) +#define CFG_SET_RTS_FOR_SIFS_BURSTING_MAX (1) +#define CFG_SET_RTS_FOR_SIFS_BURSTING_DEFAULT (0) + +/** + * + * 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 "gMaxMPDUsInAMPDU" +#define CFG_MAX_MPDUS_IN_AMPDU_MIN (0) +#define CFG_MAX_MPDUS_IN_AMPDU_MAX (64) +#define CFG_MAX_MPDUS_IN_AMPDU_DEFAULT (0) + +/* + * + * gScanBackoffMultiplier - For NLO/PNO, multiply fast scan period by this every + * max cycles + * @Min: 0 + * @Max: 255 + * @Default: 0 + * + * For Network Listen Offload and Perfered Network Offload, multiply the fast + * scan period by this value after max cycles have occurred. Setting this to 0 + * disables the feature. + * + * @E.g. + * # Disable scan backoff multiplier + * gScanBackoffMultiplier=0 + * # Effectively the same + * gScanBackoffMultiplier=1 + * # Double the scan period after each max cycles have occurred + * gScanBackoffMultiplier=2 + * + * Related: NLO, PNO + * + * Usage: Internal/External + * + * + */ +#define CFG_SCAN_BACKOFF_MULTIPLIER_NAME "gScanBackoffMultiplier" +#define CFG_SCAN_BACKOFF_MULTIPLIER_MIN (0) +#define CFG_SCAN_BACKOFF_MULTIPLIER_MAX (255) +#define CFG_SCAN_BACKOFF_MULTIPLIER_DEFAULT (0) + +/* + * + * mawc_nlo_enabled - For NLO/PNO, enable MAWC based scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Enable/Disable the Motion Aided Wireless Connectivity + * based NLO using this parameter + * + * Related: NLO, PNO + * + * Usage: Internal/External + * + * + */ +#define CFG_MAWC_NLO_ENABLED_NAME "mawc_nlo_enabled" +#define CFG_MAWC_NLO_ENABLED_MIN (0) +#define CFG_MAWC_NLO_ENABLED_MAX (1) +#define CFG_MAWC_NLO_ENABLED_DEFAULT (1) + +/* + * + * mawc_nlo_exp_backoff_ratio - Exponential back off ratio + * @Min: 0 + * @Max: 300 + * @Default: 3 + * + * Configure the exponential back off ratio using this + * parameter for MAWC based NLO + * ratio of exponential backoff, next = current + current*ratio/100 + * + * Related: NLO, PNO + * + * Usage: Internal/External + * + * + */ +#define CFG_MAWC_NLO_EXP_BACKOFF_RATIO_NAME "mawc_nlo_exp_backoff_ratio" +#define CFG_MAWC_NLO_EXP_BACKOFF_RATIO_MIN (0) +#define CFG_MAWC_NLO_EXP_BACKOFF_RATIO_MAX (300) +#define CFG_MAWC_NLO_EXP_BACKOFF_RATIO_DEFAULT (3) + +/* + * + * mawc_nlo_init_scan_interval - Initial Scan Interval + * @Min: 1000 + * @Max: 0xFFFFFFFF + * @Default: 10000 + * + * Configure the initial scan interval using this + * parameter for MAWC based NLO (Units in Milliseconds) + * + * Related: NLO, PNO + * + * Usage: Internal/External + * + * + */ +#define CFG_MAWC_NLO_INIT_SCAN_INTERVAL_NAME "mawc_nlo_init_scan_interval" +#define CFG_MAWC_NLO_INIT_SCAN_INTERVAL_MIN (1000) +#define CFG_MAWC_NLO_INIT_SCAN_INTERVAL_MAX (0xFFFFFFFF) +#define CFG_MAWC_NLO_INIT_SCAN_INTERVAL_DEFAULT (10000) + +/* + * + * mawc_nlo_max_scan_interval - Maximum Scan Interval + * @Min: 1000 + * @Max: 0xFFFFFFFF + * @Default: 60000 + * + * Configure the maximum scan interval using this + * parameter for MAWC based NLO (Units in Milliseconds) + * + * Related: NLO, PNO + * + * Usage: Internal/External + * + * + */ +#define CFG_MAWC_NLO_MAX_SCAN_INTERVAL_NAME "mawc_nlo_max_scan_interval" +#define CFG_MAWC_NLO_MAX_SCAN_INTERVAL_MIN (1000) +#define CFG_MAWC_NLO_MAX_SCAN_INTERVAL_MAX (0xFFFFFFFF) +#define CFG_MAWC_NLO_MAX_SCAN_INTERVAL_DEFAULT (60000) + + +/* + * enum hdd_external_acs_policy - External ACS policy + * @HDD_EXTERNAL_ACS_PCL_PREFERRED -Preferable for ACS to select a + * channel with non-zero pcl weight. + * @HDD_EXTERNAL_ACS_PCL_MANDATORY -Mandatory for ACS to select a + * channel with non-zero pcl weight. + * + * enum hdd_external_acs_policy is used to select the ACS policy. + * + */ +enum hdd_external_acs_policy { + HDD_EXTERNAL_ACS_PCL_PREFERRED = 0, + HDD_EXTERNAL_ACS_PCL_MANDATORY = 1, +}; + +/* + * + * external_acs_policy - External ACS policy control + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Values are per enum hdd_external_acs_policy. + * + * This ini is used to control the external ACS policy. + * + * Related: None + * + * Supported Feature: ACS + * + * Usage: Internal/External + * + * + */ +#define CFG_EXTERNAL_ACS_POLICY "acs_policy" +#define CFG_EXTERNAL_ACS_POLICY_MIN (HDD_EXTERNAL_ACS_PCL_PREFERRED) +#define CFG_EXTERNAL_ACS_POLICY_MAX (HDD_EXTERNAL_ACS_PCL_MANDATORY) +#define CFG_EXTERNAL_ACS_POLICY_DEFAULT (HDD_EXTERNAL_ACS_PCL_PREFERRED) + +/* + * 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 "gSapMaxMCSForTxData" +#define CFG_SAP_MAX_MCS_FOR_TX_DATA_MIN (0) +#define CFG_SAP_MAX_MCS_FOR_TX_DATA_MAX (383) +#define CFG_SAP_MAX_MCS_FOR_TX_DATA_DEFAULT (0) + +/* + * + * gEnableTxOrphan- Enable/Disable orphaning of Tx packets + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable orphaning of Tx packets. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_TX_ORPHAN_ENABLE_NAME "gEnableTxOrphan" +#define CFG_TX_ORPHAN_ENABLE_DEFAULT (0) +#define CFG_TX_ORPHAN_ENABLE_MIN (0) +#define CFG_TX_ORPHAN_ENABLE_MAX (1) + +/* + * + * 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_NAME "gItoRepeatCount" +#define CFG_ITO_REPEAT_COUNT_MIN (0) +#define CFG_ITO_REPEAT_COUNT_MAX (5) +#define CFG_ITO_REPEAT_COUNT_DEFAULT (0) + +/* + * + * 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_NAME "oce_sta_enable" +#define CFG_OCE_ENABLE_STA_MIN (0) +#define CFG_OCE_ENABLE_STA_MAX (1) +#define CFG_OCE_ENABLE_STA_DEFAULT (1) + +/* + * + * 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_NAME "oce_sap_enable" +#define CFG_OCE_ENABLE_SAP_MIN (0) +#define CFG_OCE_ENABLE_SAP_MAX (1) +#define CFG_OCE_ENABLE_SAP_DEFAULT (1) + +/* + * + * 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_ROAM_DISALLOW_DURATION_NAME "groam_disallow_duration" +#define CFG_ROAM_DISALLOW_DURATION_MIN (0) +#define CFG_ROAM_DISALLOW_DURATION_MAX (3600) +#define CFG_ROAM_DISALLOW_DURATION_DEFAULT (30) + +/* + * + * 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_ROAM_RSSI_CHANNEL_PENALIZATION_NAME "grssi_channel_penalization" +#define CFG_ROAM_RSSI_CHANNEL_PENALIZATION_MIN (0) +#define CFG_ROAM_RSSI_CHANNEL_PENALIZATION_MAX (15) +#define CFG_ROAM_RSSI_CHANNEL_PENALIZATION_DEFAULT (5) + +/* + * + * 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_ROAM_NUM_DISALLOWED_APS_NAME "groam_num_disallowed_aps" +#define CFG_ROAM_NUM_DISALLOWED_APS_MIN (0) +#define CFG_ROAM_NUM_DISALLOWED_APS_MAX (8) +#define CFG_ROAM_NUM_DISALLOWED_APS_DEFAULT (3) + + +/* + * + * gEnableNDIMacRandomization - When enabled this will randomize NDI Mac + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * When enabled this will randomize NDI Mac + * + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_RANDOMIZE_NDI_MAC_NAME "gEnableNDIMacRandomization" +#define CFG_RANDOMIZE_NDI_MAC_MIN (0) +#define CFG_RANDOMIZE_NDI_MAC_MAX (1) +#define CFG_RANDOMIZE_NDI_MAC_DEFAULT (1) + +/* + * + * gEnableLPRx - Enable/Disable LPRx + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini Enables or disables the LPRx in FW + * + * Usage: External + * + * + */ + +#define CFG_LPRx_NAME "gEnableLPRx" +#define CFG_LPRx_MIN (0) +#define CFG_LPRx_MAX (1) +#define CFG_LPRx_DEFAULT (1) + +/* + * + * 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_NAME "gUpperBrssiThresh" +#define CFG_UPPER_BRSSI_THRESH_MIN (36) +#define CFG_UPPER_BRSSI_THRESH_MAX (66) +#define CFG_UPPER_BRSSI_THRESH_DEFAULT (46) + +/* + * + * gLowerrBrssiThresh - 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_NAME "gLowerBrssiThresh" +#define CFG_LOWER_BRSSI_THRESH_MIN (6) +#define CFG_LOWER_BRSSI_THRESH_MAX (36) +#define CFG_LOWER_BRSSI_THRESH_DEFAULT (26) + +/* + * + * 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_NAME "gDtim1ChRxEnable" +#define CFG_DTIM_1CHRX_ENABLE_MIN (0) +#define CFG_DTIM_1CHRX_ENABLE_MAX (1) +#define CFG_DTIM_1CHRX_ENABLE_DEFAULT (1) + +/* + * + * 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 + * + * + * + * Supported Feature: STA + * + * Usage: External + * + * + */ + +#define CFG_SCAN_11D_INTERVAL_NAME "scan_11d_interval" +#define CFG_SCAN_11D_INTERVAL_DEFAULT (3600000) +#define CFG_SCAN_11D_INTERVAL_MIN (1000) +#define CFG_SCAN_11D_INTERVAL_MAX (36000000) +/* + * + * is_bssid_hint_priority - Set priority for connection with bssid_hint + * BSSID. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to give priority to BSS for connection which comes + * as part of bssid_hint + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ + +#define CFG_IS_BSSID_HINT_PRIORITY_NAME "is_bssid_hint_priority" +#define CFG_IS_BSSID_HINT_PRIORITY_DEFAULT (0) +#define CFG_IS_BSSID_HINT_PRIORITY_MIN (0) +#define CFG_IS_BSSID_HINT_PRIORITY_MAX (1) + +/* + * + * rssi_weightage - RSSI Weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 20 + * + * This ini is used to increase/decrease RSSI weightage in best candidate + * selection. AP with better RSSI will get more weightage. + * + * Related: None + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_RSSI_WEIGHTAGE_NAME "rssi_weightage" +#define CFG_RSSI_WEIGHTAGE_DEFAULT (20) +#define CFG_RSSI_WEIGHTAGE_MIN (0) +#define CFG_RSSI_WEIGHTAGE_MAX (100) + +/* + * + * ht_caps_weightage - HT caps weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 2 + * + * This ini is used to increase/decrease HT caps weightage in best candidate + * selection. If AP supports HT caps, AP will get additional Weightage with + * this param. Weightage will be given only if dot11mode is HT capable. + * + * Related: None + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_HT_CAPABILITY_WEIGHTAGE_NAME "ht_caps_weightage" +#define CFG_HT_CAPABILITY_WEIGHTAGE_DEFAULT (2) +#define CFG_HT_CAPABILITY_WEIGHTAGE_MIN (0) +#define CFG_HT_CAPABILITY_WEIGHTAGE_MAX (100) + +/* + * + * vht_caps_weightage - VHT caps Weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 1 + * + * This ini is used to increase/decrease VHT caps weightage in best candidate + * selection. If AP supports VHT caps, AP will get additional weightage with + * this param. Weightage will be given only if dot11mode is VHT capable. + * + * Related: None + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_VHT_CAPABILITY_WEIGHTAGE_NAME "vht_caps_weightage" +#define CFG_VHT_CAPABILITY_WEIGHTAGE_DEFAULT (1) +#define CFG_VHT_CAPABILITY_WEIGHTAGE_MIN (0) +#define CFG_VHT_CAPABILITY_WEIGHTAGE_MAX (100) + +/* + * + * he_caps_weightage - HE caps Weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 1 + * + * This ini is used to increase/decrease HE caps weightage in best candidate + * selection. If AP supports HE caps, AP will get additional weightage with + * this param. Weightage will be given only if dot11mode is HE capable. + * + * Related: None + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_HE_CAPABILITY_WEIGHTAGE_NAME "he_caps_weightage" +#define CFG_HE_CAPABILITY_WEIGHTAGE_DEFAULT (2) +#define CFG_HE_CAPABILITY_WEIGHTAGE_MIN (0) +#define CFG_HE_CAPABILITY_WEIGHTAGE_MAX (100) + +/* + * + * chan_width_weightage - Channel Width Weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 17 + * + * This ini is used to increase/decrease Channel Width weightage in best + * candidate selection. AP with Higher channel width will get higher weightage + * + * Related: bandwidth_weight_per_index + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_CHAN_WIDTH_WEIGHTAGE_NAME "chan_width_weightage" +#define CFG_CHAN_WIDTH_WEIGHTAGE_DEFAULT (17) +#define CFG_CHAN_WIDTH_WEIGHTAGE_MIN (0) +#define CFG_CHAN_WIDTH_WEIGHTAGE_MAX (100) + +/* + * + * chan_band_weightage - Channel Band perferance to 5GHZ to + * calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 2 + * + * This ini is used to increase/decrease Channel Band Preference weightage + * in best candidate selection. 5GHZ AP get this additional boost compare to + * 2GHZ AP before rssi_pref_5g_rssi_thresh and 2.4Ghz get weightage after + * rssi_pref_5g_rssi_thresh. + * + * Related: rssi_pref_5g_rssi_thresh, band_weight_per_index + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + * 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 "gEnableFastPwrTransition" +#define CFG_PHY_REG_DEFAULT (0x0) +#define CFG_PHY_REG_MIN (0x0) +#define CFG_PHY_REG_MAX (0x2) + +/* + * + * sae_enabled - Enable/Disable SAE support in driver + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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_NAME "sae_enabled" +#define CFG_IS_SAE_ENABLED_DEFAULT (1) +#define CFG_IS_SAE_ENABLED_MIN (0) +#define CFG_IS_SAE_ENABLED_MAX (1) + +/* + * Type declarations + */ +#define CFG_CHAN_BAND_WEIGHTAGE_NAME "chan_band_weightage" +#define CFG_CHAN_BAND_WEIGHTAGE_DEFAULT (2) +#define CFG_CHAN_BAND_WEIGHTAGE_MIN (0) +#define CFG_CHAN_BAND_WEIGHTAGE_MAX (100) + +/* + * + * nss_weightage - NSS Weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 16 + * + * This ini is used to increase/decrease NSS weightage in best candidate + * selection. If there are two AP, one AP supports 2x2 and another one supports + * 1x1 and station supports 2X2, first A will get this additional weightage + * depending on self-capability. + * + * Related: nss_weight_per_index + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_NSS_WEIGHTAGE_NAME "nss_weightage" +#define CFG_NSS_WEIGHTAGE_DEFAULT (16) +#define CFG_NSS_WEIGHTAGE_MIN (0) +#define CFG_NSS_WEIGHTAGE_MAX (100) + +/* + * + * beamforming_cap_weightage - Beam Forming Weightage to + * calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 2 + * + * This ini is used to increase/decrease Beam forming Weightage if some AP + * support Beam forming or not. If AP supports Beam forming, that AP will get + * additional boost of this weightage. + * + * Related: None + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_BEAMFORMING_CAP_WEIGHTAGE_NAME "beamforming_cap_weightage" +#define CFG_BEAMFORMING_CAP_WEIGHTAGE_DEFAULT (2) +#define CFG_BEAMFORMING_CAP_WEIGHTAGE_MIN (0) +#define CFG_BEAMFORMING_CAP_WEIGHTAGE_MAX (100) + +/* + * + * pcl_weightage - PCL Weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 10 + * + * This ini is used to increase/decrease PCL weightage in best candidate + * selection. If some APs are in PCL list, those AP will get addition + * weightage. + * + * Related: None + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_PCL_WEIGHT_WEIGHTAGE_NAME "pcl_weightage" +#define CFG_PCL_WEIGHT_DEFAULT (10) +#define CFG_PCL_WEIGHT_MIN (0) +#define CFG_PCL_WEIGHT_MAX (100) + +/* + * + * channel_congestion_weightage - channel Congestion Weightage to + * calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 5 + * + * This ini is used to increase/decrease channel congestion weightage in + * candidate selection. Congestion is measured with the help of ESP/QBSS load. + * + * Related: num_esp_qbss_slots + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_CHANNEL_CONGESTION_WEIGHTAGE_NAME "channel_congestion_weightage" +#define CFG_CHANNEL_CONGESTION_WEIGHTAGE_DEFAULT (5) +#define CFG_CHANNEL_CONGESTION_WEIGHTAGE_MIN (0) +#define CFG_CHANNEL_CONGESTION_WEIGHTAGE_MAX (100) + +/* + * + * oce_wan_weightage - OCE WAN DL capacity Weightage to calculate best candidate + * @Min: 0 + * @Max: 100 + * @Default: 2 + * + * This ini is used to increase/decrease OCE WAN caps weightage in best + * candidate selection. If AP have OCE WAN information, give weightage depending + * on the downaload available capacity. + * + * Related: num_oce_wan_slots + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_OCE_WAN_WEIGHTAGE_NAME "oce_wan_weightage" +#define CFG_OCE_WAN_WEIGHTAGE_DEFAULT (2) +#define CFG_OCE_WAN_WEIGHTAGE_MIN (0) +#define CFG_OCE_WAN_WEIGHTAGE_MAX (100) + +/* + * + * best_rssi_threshold - Best Rssi for score calculation + * @Min: 0 + * @Max: 96 + * @Default: 55 + * + * This ini tells limit for best RSSI. RSSI better than this limit are + * considered as best RSSI. The best RSSI is given full rssi_weightage. + * + * Related: rssi_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_BEST_RSSI_THRESHOLD_NAME "best_rssi_threshold" +#define CFG_BEST_RSSI_THRESHOLD_DEFAULT (55) +#define CFG_BEST_RSSI_THRESHOLD_MIN (0) +#define CFG_BEST_RSSI_THRESHOLD_MAX (96) + +/* + * + * good_rssi_threshold - Good Rssi for score calculation + * @Min: 0 + * @Max: 96 + * @Default: 70 + * + * This ini tells limit for good RSSI. RSSI better than this limit and less + * than best_rssi_threshold is considered as good RSSI. + * + * Related: rssi_weightage, best_rssi_threshold + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_GOOD_RSSI_THRESHOLD_NAME "good_rssi_threshold" +#define CFG_GOOD_RSSI_THRESHOLD_DEFAULT (70) +#define CFG_GOOD_RSSI_THRESHOLD_MIN (0) +#define CFG_GOOD_RSSI_THRESHOLD_MAX (96) + +/* + * + * bad_rssi_threshold - Bad Rssi for score calculation + * @Min: 0 + * @Max: 96 + * @Default: 80 + * + * This ini tells limit for Bad RSSI. RSSI greater then bad_rssi_threshold + * is considered as bad RSSI. + * + * Related: rssi_weightage, good_rssi_threshold + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_BAD_RSSI_THRESHOLD_NAME "bad_rssi_threshold" +#define CFG_BAD_RSSI_THRESHOLD_DEFAULT (80) +#define CFG_BAD_RSSI_THRESHOLD_MIN (0) +#define CFG_BAD_RSSI_THRESHOLD_MAX (96) + +/* + * + * good_rssi_pcnt - Percent Score to Good RSSI out of total RSSI score. + * @Min: 0 + * @Max: 100 + * @Default: 80 + * + * This ini tells about how much percent should be given to good RSSI(RSSI + * between best_rssi_threshold and good_rssi_threshold) out of RSSI weightage. + * + * Related: rssi_weightage, best_rssi_threshold, good_rssi_threshold + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_GOOD_RSSI_PCNT_NAME "good_rssi_pcnt" +#define CFG_GOOD_RSSI_PCNT_DEFAULT (80) +#define CFG_GOOD_RSSI_PCNT_MIN (0) +#define CFG_GOOD_RSSI_PCNT_MAX (100) + +/* + * + * bad_rssi_pcnt - Percent Score to BAD RSSI out of total RSSI score. + * @Min: 0 + * @Max: 100 + * @Default: 25 + * + * This ini tells about how much percent should be given to bad RSSI (RSSI + * between good_rssi_threshold and bad_rssi_threshold) out of RSSI weightage. + * + * Related: rssi_weightage, good_rssi_threshold, bad_rssi_threshold + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_BAD_RSSI_PCNT_NAME "bad_rssi_pcnt" +#define CFG_BAD_RSSI_PCNT_DEFAULT (25) +#define CFG_BAD_RSSI_PCNT_MIN (0) +#define CFG_BAD_RSSI_PCNT_MAX (100) + +/* + * + * good_rssi_bucket_size - Bucket size between best and good RSSI to score. + * @Min: 1 + * @Max: 10 + * @Default: 5 + * + * This ini tells about bucket size for scoring between best and good RSSI. + * Below Best RSSI, 100% score will be given. Between best and good RSSI, RSSI + * is divided in buckets and score will be assigned bucket wise starting from + * good_rssi_pcnt. + * + * Related: rssi_weightage, good_rssi_pcnt + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_GOOD_RSSI_BUCKET_SIZE_NAME "good_rssi_bucket_size" +#define CFG_GOOD_RSSI_BUCKET_SIZE_DEFAULT (5) +#define CFG_GOOD_RSSI_BUCKET_SIZE_MIN (1) +#define CFG_GOOD_RSSI_BUCKET_SIZE_MAX (10) + +/* + * + * bad_rssi_bucket_size - Bucket size between good and bad RSSI to score. + * @Min: 1 + * @Max: 10 + * @Default: 5 + * + * This ini tells about bucket size for scoring between good and bad RSSI. + * Between good and bad RSSI, RSSI is divided in buckets and score will be + * assigned bucket wise starting from bad_rssi_pcnt. + * + * Related: rssi_weightage, bad_rssi_pcnt + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_BAD_RSSI_BUCKET_SIZE_NAME "bad_rssi_bucket_size" +#define CFG_BAD_RSSI_BUCKET_SIZE_DEFAULT (5) +#define CFG_BAD_RSSI_BUCKET_SIZE_MIN (1) +#define CFG_BAD_RSSI_BUCKET_SIZE_MAX (10) + +/* + * + * rssi_pref_5g_rssi_thresh - A RSSI threshold above which 5 GHz is not favored + * @Min: 0 + * @Max: 96 + * @Default: 76 + * + * 5G AP are given chan_band_weightage. This ini tells about RSSI threshold + * above which 5GHZ is not favored. + * + * Related: chan_band_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_RSSI_PERF_5G_THRESHOLD_NAME "rssi_pref_5g_rssi_thresh" +#define CFG_RSSI_PERF_5G_THRESHOLD_DEFAULT (76) +#define CFG_RSSI_PERF_5G_THRESHOLD_MIN (0) +#define CFG_RSSI_PERF_5G_THRESHOLD_MAX (96) + +/* + * + * bandwidth_weight_per_index - percentage as per bandwidth + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x6432190C + * + * This INI give percentage value of chan_width_weightage to be used as per + * peer bandwidth. Self BW is also considered while calculating score. Eg if + * self BW is 20 MHZ 10% will be given for all AP irrespective of the AP + * capability. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): 20 MHz - Def 12% + * 1 Index (BITS 8-15): 40 MHz - Def 25% + * 2 Index (BITS 16-23): 80 MHz - Def 50% + * 3 Index (BITS 24-31): 160 MHz - Def 100% + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: chan_width_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_BAND_WIDTH_WEIGHT_PER_INDEX_NAME "bandwidth_weight_per_index" +#define CFG_BAND_WIDTH_WEIGHT_PER_INDEX_DEFAULT (0x6432190C) +#define CFG_BAND_WIDTH_WEIGHT_PER_INDEX_MIN (0x00000000) +#define CFG_BAND_WIDTH_WEIGHT_PER_INDEX_MAX (0x64646464) + +/* + * + * nss_weight_per_index - percentage as per NSS + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x6432190C + * + * This INI give percentage value of nss_weightage to be used as per peer NSS. + * Self NSS capability is also considered. Eg if self NSS is 1x1 10% will be + * given for all AP irrespective of the AP capability. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): 1X1- Def 12% + * 1 Index (BITS 8-15): 2X2- Def 25% + * 2 Index (BITS 16-23): 3X3- Def 50% + * 3 Index (BITS 24-31): 4X4- Def 100% + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: nss_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_NSS_WEIGHT_PER_INDEX_NAME "nss_weight_per_index" +#define CFG_NSS_WEIGHT_PER_INDEX_DEFAULT (0x6432190C) +#define CFG_NSS_WEIGHT_PER_INDEX_MIN (0x00000000) +#define CFG_NSS_WEIGHT_PER_INDEX_MAX (0x64646464) + +/* + * + * band_weight_per_index - percentage as per band + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x0000644B + * + * This INI give percentage value of chan_band_weightage to be used as per band. + * If RSSI is greater than rssi_pref_5g_rssi_thresh preference is given for 5Ghz + * else, it's given for 2.4Ghz. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): 2.4GHz - Def 10% + * 1 Index (BITS 8-15): 5GHz - Def 20% + * 2 Index (BITS 16-23): Reserved + * 3 Index (BITS 24-31): Reserved + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: chan_band_weightage, rssi_pref_5g_rssi_thresh + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_BAND_WEIGHT_PER_INDEX_NAME "band_weight_per_index" +#define CFG_BAND_WEIGHT_PER_INDEX_DEFAULT (0x0000644B) +#define CFG_BAND_WEIGHT_PER_INDEX_MIN (0x00000000) +#define CFG_BAND_WEIGHT_PER_INDEX_MAX (0x64646464) + +/* + * + * num_esp_qbss_slots - number of slots in which the esp/qbss load will + * be divided + * + * @Min: 1 + * @Max: 15 + * @Default: 4 + * + * Number of slots in which the esp/qbss load will be divided. Max 15. index 0 + * is used for 'not_present. Num_slot will equally divide 100. e.g, if + * num_slot = 4 slot 1 = 0-25% load, slot 2 = 26-50% load, slot 3 = 51-75% load, + * slot 4 = 76-100% load. Remaining unused index can be 0. + * + * Usage: External + * + * + */ +#define CFG_ESP_QBSS_SLOTS_NAME "num_esp_qbss_slots" +#define CFG_ESP_QBSS_SLOTS_DEFAULT (4) +#define CFG_ESP_QBSS_SLOTS_MIN (1) +#define CFG_ESP_QBSS_SLOTS_MAX (15) + +/* + * + * esp_qbss_score_idx3_to_0 - percentage for esp/qbss load for slots 0-3 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x19326432 + * + * This INI give percentage value of channel_congestion_weightage to be used as + * index in which the load value falls. Index 0 is for percentage when ESP/QBSS + * is not present. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): when ESP/QBSS is not present + * 1 Index (BITS 8-15): SLOT_1 + * 2 Index (BITS 16-23): SLOT_2 + * 3 Index (BITS 24-31): SLOT_3 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: channel_congestion_weightage, num_esp_qbss_slots + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_ESP_QBSS_SCORE_IDX3_TO_0_NAME "esp_qbss_score_idx3_to_0" +#define CFG_ESP_QBSS_SCORE_IDX3_TO_0_DEFAULT (0x19326432) +#define CFG_ESP_QBSS_SCORE_IDX3_TO_0_MIN (0x00000000) +#define CFG_ESP_QBSS_SCORE_IDX3_TO_0_MAX (0x64646464) + +/* + * + * esp_qbss_score_idx7_to_4 - percentage for esp/qbss load for slots 4-7 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x0000000A + * + * This INI give percentage value of channel_congestion_weightage to be used as + * index in which the load value falls. Used only if num_esp_qbss_slots is + * greater than 3. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): SLOT_4 + * 1 Index (BITS 8-15): SLOT_5 + * 2 Index (BITS 16-23): SLOT_6 + * 3 Index (BITS 24-31): SLOT_7 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: channel_congestion_weightage, num_esp_qbss_slots + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_ESP_QBSS_SCORE_IDX7_TO_4_NAME "esp_qbss_score_idx7_to_4" +#define CFG_ESP_QBSS_SCORE_IDX7_TO_4_DEFAULT (0x0000000A) +#define CFG_ESP_QBSS_SCORE_IDX7_TO_4_MIN (0x00000000) +#define CFG_ESP_QBSS_SCORE_IDX7_TO_4_MAX (0x64646464) + + +/* + * + * esp_qbss_score_idx11_to_8 - percentage for esp/qbss load for slots 8-11 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x00000000 + * + * This INI give percentage value of channel_congestion_weightage to be used as + * index in which the load value falls. Used only if num_esp_qbss_slots is + * greater than 7. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): SLOT_8 + * 1 Index (BITS 8-15): SLOT_9 + * 2 Index (BITS 16-23): SLOT_10 + * 3 Index (BITS 24-31): SLOT_11 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: channel_congestion_weightage, num_esp_qbss_slots + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_ESP_QBSS_SCORE_IDX11_TO_8_NAME "esp_qbss_score_idx11_to_8" +#define CFG_ESP_QBSS_SCORE_IDX11_TO_8_DEFAULT (0x00000000) +#define CFG_ESP_QBSS_SCORE_IDX11_TO_8_MIN (0x00000000) +#define CFG_ESP_QBSS_SCORE_IDX11_TO_8_MAX (0x64646464) + + +/* + * + * esp_qbss_score_idx15_to_12 - percentage for esp/qbss load for slots 12-15 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x00000000 + * + * This INI give percentage value of channel_congestion_weightage to be used as + * index in which the load value falls. Used only if num_esp_qbss_slots is + * greater than 11. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): SLOT_12 + * 1 Index (BITS 8-15): SLOT_13 + * 2 Index (BITS 16-23): SLOT_14 + * 3 Index (BITS 24-31): SLOT_15 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: channel_congestion_weightage, num_esp_qbss_slots + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_ESP_QBSS_SCORE_IDX15_TO_12_NAME "esp_qbss_score_idx15_to_12" +#define CFG_ESP_QBSS_SCORE_IDX15_TO_12_DEFAULT (0x00000000) +#define CFG_ESP_QBSS_SCORE_IDX15_TO_12_MIN (0x00000000) +#define CFG_ESP_QBSS_SCORE_IDX15_TO_12_MAX (0x64646464) + +/* + * + * num_oce_wan_slots - number of slots in which the oce wan metrics will + * be divided + * + * @Min: 1 + * @Max: 15 + * @Default: 8 + * + * Number of slots in which the oce wan metrics will be divided. Max 15. index 0 + * is used for not_present. Num_slot will equally divide 100. e.g, if + * num_slot = 4 slot 1 = 0-3 DL CAP, slot 2 = 4-7 DL CAP, slot 3 = 8-11 DL CAP, + * slot 4 = 12-15 DL CAP. Remaining unused index can be 0. + * + * Related: oce_wan_weightage + * + * Usage: External + * + * + */ +#define CFG_OCE_WAN_SLOTS_NAME "num_oce_wan_slots" +#define CFG_OCE_WAN_SLOTS_DEFAULT (15) +#define CFG_OCE_WAN_SLOTS_MIN (1) +#define CFG_OCE_WAN_SLOTS_MAX (15) + +/* + * + * oce_wan_score_idx3_to_0 - percentage for OCE WAN metrics score for slots 0-3 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x00000032 + * + * This INI give percentage value of OCE WAN metrics DL CAP, to be used as + * index in which the DL CAP value falls. Index 0 is for percentage when + * OCE WAN metrics DL CAP is not present. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): when OCE WAN metrics DL CAP is not present + * 1 Index (BITS 8-15): SLOT_1 + * 2 Index (BITS 16-23): SLOT_2 + * 3 Index (BITS 24-31): SLOT_3 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: num_oce_wan_slots, oce_wan_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_OCE_WAN_SCORE_IDX3_TO_0_NAME "oce_wan_score_idx3_to_0" +#define CFG_OCE_WAN_SCORE_IDX3_TO_0_DEFAULT (0x00000032) +#define CFG_OCE_WAN_SCORE_IDX3_TO_0_MIN (0x00000000) +#define CFG_OCE_WAN_SCORE_IDX3_TO_0_MAX (0x64646464) + +/* + * + * oce_wan_score_idx7_to_4 - percentage for OCE WAN metrics score for slots 4-7 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x00000000 + * + * This INI give percentage value of OCE WAN metrics DL CAP, to be used as + * index in which the DL CAP value falls. Used only if num_oce_wan_slots is + * greater than 3. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): SLOT_4 + * 1 Index (BITS 8-15): SLOT_5 + * 2 Index (BITS 16-23): SLOT_6 + * 3 Index (BITS 24-31): SLOT_7 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: num_oce_wan_slots, oce_wan_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_OCE_WAN_SCORE_IDX7_TO_4_NAME "oce_wan_score_idx7_to_4" +#define CFG_OCE_WAN_SCORE_IDX7_TO_4_DEFAULT (0x00000000) +#define CFG_OCE_WAN_SCORE_IDX7_TO_4_MIN (0x00000000) +#define CFG_OCE_WAN_SCORE_IDX7_TO_4_MAX (0x64646464) + +/* + * + * oce_wan_score_idx11_to_8 - percentage for OCE WAN metrics score for slot 8-11 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x06030000 + * + * This INI give percentage value of OCE WAN metrics DL CAP, to be used as + * index in which the DL CAP value falls. Used only if num_oce_wan_slots is + * greater than 7. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): SLOT_8 + * 1 Index (BITS 8-15): SLOT_9 + * 2 Index (BITS 16-23): SLOT_10 + * 3 Index (BITS 24-31): SLOT_11 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: num_oce_wan_slots, oce_wan_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_OCE_WAN_SCORE_IDX11_TO_8_NAME "oce_wan_score_idx11_to_8" +#define CFG_OCE_WAN_SCORE_IDX11_TO_8_DEFAULT (0x06030000) +#define CFG_OCE_WAN_SCORE_IDX11_TO_8_MIN (0x00000000) +#define CFG_OCE_WAN_SCORE_IDX11_TO_8_MAX (0x64646464) + +/* + * + * oce_wan_score_idx15_to_12 - % for OCE WAN metrics score for slot 12-15 + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x6432190C + * + * This INI give percentage value of OCE WAN metrics DL CAP, to be used as + * index in which the DL CAP value falls. Used only if num_oce_wan_slots is + * greater than 11. + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): SLOT_12 + * 1 Index (BITS 8-15): SLOT_13 + * 2 Index (BITS 16-23): SLOT_14 + * 3 Index (BITS 24-31): SLOT_15 + * These percentage values are stored in HEX. For any index max value, can be 64 + * + * Related: num_oce_wan_slots, oce_wan_weightage + * + * Supported Feature: STA Candidate selection + * + * Usage: External + * + * + */ +#define CFG_OCE_WAN_SCORE_IDX15_TO_12_NAME "oce_wan_score_idx15_to_12" +#define CFG_OCE_WAN_SCORE_IDX15_TO_12_DEFAULT (0x6432190C) +#define CFG_OCE_WAN_SCORE_IDX15_TO_12_MIN (0x00000000) +#define CFG_OCE_WAN_SCORE_IDX15_TO_12_MAX (0x64646464) + +/* + * + * 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_NAME "enable_scoring_for_roam" +#define CFG_ENABLE_SCORING_FOR_ROAM_DEFAULT (1) +#define CFG_ENABLE_SCORING_FOR_ROAM_MIN (0) +#define CFG_ENABLE_SCORING_FOR_ROAM_MAX (1) + +/* + * + * force_rsne_override - force rsnie override from user + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable test mode to force rsne override used in + * security enhancement test cases to pass the RSNIE sent by user in + * assoc request. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: internal + * + * + */ +#define CFG_FORCE_RSNE_OVERRIDE_NAME "force_rsne_override" +#define CFG_FORCE_RSNE_OVERRIDE_MIN (0) +#define CFG_FORCE_RSNE_OVERRIDE_MAX (1) +#define CFG_FORCE_RSNE_OVERRIDE_DEFAULT (0) + +/* + * + * gChanSwitchHostapdRateEnabled - Enable/disable hostapd rate when doing SAP + * channel switch + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set supported rates calculated from hostapd.conf file + * or not when doing SAP channel switch. It must set it to 0 when cross-band + * channel switch happens such as from 2G to 5G or 5G to 2G. + * + * Related: When doing SAP channel switch, if gChanSwitchHostapdRateEnabled is + * set to 1, supported rates will be calculated from hostapd.conf file, + * if gChanSwitchHostapdRateEnabled is set to 0, supported rates will be + * calculated from driver default rates. + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_NAME \ + "gChanSwitchHostapdRateEnabled" +#define CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_MIN (0) +#define CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_MAX (1) +#define CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_DEFAULT (0) + +/* + * + * 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_NAME "g_mbo_candidate_rssi_thres" +#define CFG_CANDIDATE_RSSI_THRESHOLD_DEFAULT (-72) +#define CFG_CANDIDATE_RSSI_THRESHOLD_MIN (-120) +#define CFG_CANDIDATE_RSSI_THRESHOLD_MAX (0) + +/* + * + * 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_NAME "g_mbo_current_rssi_thres" +#define CFG_CURRENT_RSSI_THRESHOLD_DEFAULT (-65) +#define CFG_CURRENT_RSSI_THRESHOLD_MIN (-120) +#define CFG_CURRENT_RSSI_THRESHOLD_MAX (0) + +/* + * + * 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_NAME "g_mbo_current_rssi_mcc_thres" +#define CFG_MBO_CUR_RSSI_MCC_THRESHOLD_DEFAULT (-75) +#define CFG_MBO_CUR_RSSI_MCC_THRESHOLD_MIN (-120) +#define CFG_MBO_CUR_RSSI_MCC_THRESHOLD_MAX (0) + +/* + * + * 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_NAME "g_mbo_candidate_rssi_btc_thres" +#define CFG_MBO_CAND_RSSI_BTC_THRESHOLD_DEFAULT (-70) +#define CFG_MBO_CAND_RSSI_BTC_THRESHOLD_MIN (-120) +#define CFG_MBO_CAND_RSSI_BTC_THRESHOLD_MAX (0) + +/* + * + * g_enable_packet_filter_bitmap - Enable Packet filters before going into + * suspend mode + * @Min: 0 + * @Max: 63 + * @Default: 0 + * Below is the Detailed bit map of the Filters + * 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 Ciscoswitches 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 + * + * This ini support to enable above mentioned packet filters + * when target goes to suspend mode, clear those when resume + * + * Related: None + * + * Supported Feature: PACKET FILTERING + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_PACKET_FILTERS_NAME "g_enable_packet_filter_bitmap" +#define CFG_ENABLE_PACKET_FILTERS_DEFAULT (0) +#define CFG_ENABLE_PACKET_FILTERS_MIN (0) +#define CFG_ENABLE_PACKET_FILTERS_MAX (63) + + +/* + * + * 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 "gDfsBeaconTxEnhanced" +#define CFG_DFS_BEACON_TX_ENHANCED_MIN (0) +#define CFG_DFS_BEACON_TX_ENHANCED_MAX (1) +#define CFG_DFS_BEACON_TX_ENHANCED_DEFAULT (0) + +/* + * 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 "gReducedBeaconInterval" +#define CFG_REDUCED_BEACON_INTERVAL_MIN (0) +#define CFG_REDUCED_BEACON_INTERVAL_MAX (100) +#define CFG_REDUCED_BEACON_INTERVAL_DEFAULT (0) + +/* + * 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_NAME \ + "oce_enable_rssi_assoc_reject" +#define CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT_MIN (0) +#define CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT_MAX (1) +#define CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT_DEFAULT (1) + +/* + * + * oce_enable_probe_req_rate - Set probe request rate + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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_NAME "oce_enable_probe_req_rate" +#define CFG_OCE_PROBE_REQ_RATE_MIN (0) +#define CFG_OCE_PROBE_REQ_RATE_MAX (1) +#define CFG_OCE_PROBE_REQ_RATE_DEFAULT (1) + +/* + * + * 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_NAME "oce_enable_probe_resp_rate" +#define CFG_OCE_PROBE_RSP_RATE_MIN (0) +#define CFG_OCE_PROBE_RSP_RATE_MAX (1) +#define CFG_OCE_PROBE_RSP_RATE_DEFAULT (0) + +/* + * + * 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_NAME "oce_enable_beacon_rate" +#define CFG_OCE_BEACON_RATE_MIN (0) +#define CFG_OCE_BEACON_RATE_MAX (1) +#define CFG_OCE_BEACON_RATE_DEFAULT (0) + +/* + * + * oce_enable_probe_req_deferral - Enable/disable probe request deferral + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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_NAME "oce_enable_probe_req_deferral" +#define CFG_ENABLE_PROBE_REQ_DEFERRAL_MIN (0) +#define CFG_ENABLE_PROBE_REQ_DEFERRAL_MAX (1) +#define CFG_ENABLE_PROBE_REQ_DEFERRAL_DEFAULT (1) + +/* + * + * oce_enable_fils_discovery_sap - Enable/disable fils discovery in sap mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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_NAME "oce_enable_fils_discovery_sap" +#define CFG_ENABLE_FILS_DISCOVERY_SAP_MIN (0) +#define CFG_ENABLE_FILS_DISCOVERY_SAP_MAX (1) +#define CFG_ENABLE_FILS_DISCOVERY_SAP_DEFAULT (1) + +/* + * + * 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_NAME "enable_esp_for_roam" +#define CFG_ENABLE_ESP_FEATURE_MIN (0) +#define CFG_ENABLE_ESP_FEATURE_MAX (1) +#define CFG_ENABLE_ESP_FEATURE_DEFAULT (1) + +/* + * + * tx_chain_mask_2g - tx chain mask for 2g + * @Min: 0 + * @Max: 3 + * @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 + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_TX_CHAIN_MASK_2G_NAME "tx_chain_mask_2g" +#define CFG_TX_CHAIN_MASK_2G_MIN (0) +#define CFG_TX_CHAIN_MASK_2G_MAX (3) +#define CFG_TX_CHAIN_MASK_2G_DEFAULT (0) + + +/* + * + * tx_chain_mask_5g - tx chain mask for 5g + * @Min: 0 + * @Max: 3 + * @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 + * tx_chain_mask_5g=2 : for 5g tx use chain 1 + * tx_chain_mask_5g=3 : for 5g tx can use either chain + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_TX_CHAIN_MASK_5G_NAME "tx_chain_mask_5g" +#define CFG_TX_CHAIN_MASK_5G_MIN (0) +#define CFG_TX_CHAIN_MASK_5G_MAX (3) +#define CFG_TX_CHAIN_MASK_5G_DEFAULT (0) + + +/* + * + * rx_chain_mask_2g - rx chain mask for 2g + * @Min: 0 + * @Max: 3 + * @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 + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_RX_CHAIN_MASK_2G_NAME "rx_chain_mask_2g" +#define CFG_RX_CHAIN_MASK_2G_MIN (0) +#define CFG_RX_CHAIN_MASK_2G_MAX (3) +#define CFG_RX_CHAIN_MASK_2G_DEFAULT (0) + + +/* + * + * rx_chain_mask_5g - rx chain mask for 5g + * @Min: 0 + * @Max: 3 + * @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 + * rx_chain_mask_5g=2 : for 5g rx use chain 1 + * rx_chain_mask_5g=3 : for 5g rx can use either chain + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_RX_CHAIN_MASK_5G_NAME "rx_chain_mask_5g" +#define CFG_RX_CHAIN_MASK_5G_MIN (0) +#define CFG_RX_CHAIN_MASK_5G_MAX (3) +#define CFG_RX_CHAIN_MASK_5G_DEFAULT (0) + +/* + * + * btm_offload_config - Configure BTM + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * 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 + * 000 match if exact BSSIDs are found + * 001 match if at least one top priority BSSID only + * 010, 011, 100, 101, 110, 111 reserved + * + * BIT 6: Set this to 1 will send BTM query frame and 0 not sent. + * + * BIT 7-31: Reserved + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_BTM_ENABLE_NAME "btm_offload_config" +#define CFG_BTM_ENABLE_MIN (0x00000000) +#define CFG_BTM_ENABLE_MAX (0xffffffff) +#define CFG_BTM_ENABLE_DEFAULT (0x00000001) + +/* + * + * 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 "btm_solicited_timeout" +#define CFG_BTM_SOLICITED_TIMEOUT_MIN (1) +#define CFG_BTM_SOLICITED_TIMEOUT_MAX (10000) +#define CFG_BTM_SOLICITED_TIMEOUT_DEFAULT (100) + +/* + * + * 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 "btm_max_attempt_cnt" +#define CFG_BTM_MAX_ATTEMPT_CNT_MIN (0x00000001) +#define CFG_BTM_MAX_ATTEMPT_CNT_MAX (0xFFFFFFFF) +#define CFG_BTM_MAX_ATTEMPT_CNT_DEFAULT (0x00000003) + +/* + * + * sticky_time - Stick time after roaming to new AP by BTM + * @Min: 0 + * @Max: 0x0000FFFF + * @Default: 300 + * + * 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 "btm_sticky_time" +#define CFG_BTM_STICKY_TIME_MIN (0x00000000) +#define CFG_BTM_STICKY_TIME_MAX (0x0000FFFF) +#define CFG_BTM_STICKY_TIME_DEFAULT (300) + +/* + * + * gcmp_enabled - ini to enable/disable GCMP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 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_NAME "gcmp_enabled" +#define CFG_ENABLE_GCMP_MIN (0) +#define CFG_ENABLE_GCMP_MAX (1) +#define CFG_ENABLE_GCMP_DEFAULT (1) + +/* + * + * 11k_offload_enable_bitmask - Bitmask to enable 11k offload to FW + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set which of the 11k features is offloaded to FW + * Currently Neighbor Report Request is supported for offload and is enabled + * by default + * B0: Offload 11k neighbor report requests + * B1-B31: Reserved + * + * Related : None + * + * Usage: External + * + * + */ + +#define CFG_OFFLOAD_11K_ENABLE_BITMASK_NAME "11k_offload_enable_bitmask" +#define CFG_OFFLOAD_11K_ENABLE_BITMASK_MIN (0) +#define CFG_OFFLOAD_11K_ENABLE_BITMASK_MAX (1) +#define CFG_OFFLOAD_11K_ENABLE_BITMASK_DEFAULT (1) + +#define OFFLOAD_11K_BITMASK_NEIGHBOR_REPORT_REQUEST 0x1 +/* + * + * 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_NAME \ + "nr_offload_params_bitmask" +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_MIN (0) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_MAX (63) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_DEFAULT (63) + +/* + * + * 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_NAME \ + "nr_offload_time_offset" +#define CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_MIN (0) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_MAX (3600) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_DEFAULT (30) + +/* + * + * 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_NAME \ + "nr_offload_low_rssi_offset" +#define CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_MIN (4) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_MAX (10) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_DEFAULT (4) + +/* + * + * 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_NAME \ + "nr_offload_bmiss_count_trigger" +#define CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_MIN (1) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_MAX (5) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_DEFAULT (1) + +/* + * + * 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_NAME \ + "nr_offload_per_threshold_offset" +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_MIN (5) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_MAX (20) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_DEFAULT (5) + +/* + * + * 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_NAME \ + "nr_offload_cache_timeout" +#define CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_MIN (5) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_MAX (86400) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_DEFAULT (1200) + +/* + * + * 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_NAME \ + "nr_offload_max_req_cap" +#define CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_MIN (3) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_MAX (300) +#define CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_DEFAULT (3) + +/* + * + * 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 "wmi_wq_watchdog" +#define CFG_WMI_WQ_WATCHDOG_MIN (0) +#define CFG_WMI_WQ_WATCHDOG_MAX (30) /* 30s */ +#define CFG_WMI_WQ_WATCHDOG_DEFAULT (20) /* 20s */ + +/* + * + * gEnableDTIMSelectionDiversity - Enable/Disable chain + * selection optimization for one chain dtim + * @Min: 0 + * @Max: 30 + * @Default: 5 + * + * Usage: External + * + * + */ +#define CFG_DTIM_SELECTION_DIVERSITY_NAME "gEnableDTIMSelectionDiversity" +#define CFG_DTIM_SELECTION_DIVERSITY_MIN (0) +#define CFG_DTIM_SELECTION_DIVERSITY_MAX (30) +#define CFG_DTIM_SELECTION_DIVERSITY_DEFAULT (5) + +/* + * + * 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_CHANNEL_SELECT_LOGIC_CONC_NAME "channel_select_logic_conc" +#define CFG_CHANNEL_SELECT_LOGIC_CONC_MIN (0x00000000) +#define CFG_CHANNEL_SELECT_LOGIC_CONC_MAX (0xFFFFFFFF) +#define CFG_CHANNEL_SELECT_LOGIC_CONC_DEFAULT (0x00000003) + +/* + * + * gTxSchDelay - Enable/Disable Tx sch delay + * @Min: 0 + * @Max: 5 + * @Default: 0 + * + * Usage: Internal/External + * + * + */ + +#define CFG_TX_SCH_DELAY_NAME "gTxSchDelay" +#define CFG_TX_SCH_DELAY_MIN (0) +#define CFG_TX_SCH_DELAY_MAX (5) +#define CFG_TX_SCH_DELAY_DEFAULT (0) + +/* + * 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 atleast 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 comparision + * mac-addr EE-1A-59-FE-FD-AF is present and first 3 bytes and last byte of + * mac address should be considered for comparision + * 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 "gEnableActionOUI" +#define CFG_ENABLE_ACTION_OUI_MIN (0) +#define CFG_ENABLE_ACTION_OUI_MAX (1) +#define CFG_ENABLE_ACTION_OUI_DEFAULT (1) + +/* + * + * gActionOUIConnect1x1 - Used to specify action OUIs for 1x1 connection + * @Default: 000C43 00 25 42 001018 06 02FFF02C0000 BC 25 42 001018 06 02FF040C0000 BC 25 42 00037F 00 35 6C + * 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: 42 - NSS == 2 && Band == 2G + * 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_NAME "gActionOUIConnect1x1" +#define CFG_ACTION_OUI_CONNECT_1X1_DEFAULT "000C43 00 25 42 001018 06 02FFF02C0000 BC 25 42 001018 06 02FF040C0000 BC 25 42 00037F 00 35 6C 001018 06 02FF009C0000 BC 25 48" + +/* + * + * 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_NAME "gActionOUIITOExtension" +#define CFG_ACTION_OUI_ITO_EXTENSION_DEFAULT "00037F 06 01010000FF7F FC 01 000AEB 02 0100 C0 01 000B86 03 010408 E0 01" + +/* + * + * 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_NAME "gActionOUICCKM1X1" +#define CFG_ACTION_OUI_CCKM_1X1_DEFAULT "" + +/* + * + * 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_NAME "gActionOUIITOAlternate" + #define CFG_ACTION_OUI_ITO_ALTERNATE_DEFAULT "001018 06 0202001c0000 FC 01" + +/* + * + * 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_NAME "gActionOUISwitchTo11nMode" +#define CFG_ACTION_OUI_SWITCH_TO_11N_MODE_DEFAULT "00904C 05 0418BF0CB2 F8 21 40" + +/* + * + * 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_NAME "gActionOUIConnect1x1with1TxRxChain" +#define CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN_DEFAULT "001018 06 02FFF0040000 BC 21 40 001018 06 02FFF0050000 BC 21 40 001018 06 02FFF4050000 BC 21 40" + +/* + * + * 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_NAME "gActionOUIDisableAggressiveTX" +#define CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX_DEFAULT "FFFFFF 00 2A F85971000000 E0 50 FFFFFF 00 2A 14ABC5000000 E0 50" + +/* End of action oui inis */ + + +/* + * + * gEnableUnitTestFramework - Enable/Disable unit test framework + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Usage: Internal (only for dev and test team) + * + * + */ +#define CFG_ENABLE_UNIT_TEST_FRAMEWORK_NAME "gEnableUnitTestFramework" +#define CFG_ENABLE_UNIT_TEST_FRAMEWORK_MIN (0) +#define CFG_ENABLE_UNIT_TEST_FRAMEWORK_MAX (1) +#define CFG_ENABLE_UINT_TEST_FRAMEWORK_DEFAULT (0) + +/* + * + * enable_rtt_mac_randomization - Enable/Disable rtt mac randomization + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Usage: External + * + * + */ +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_NAME "enable_rtt_mac_randomization" +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_MIN (0) +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_MAX (1) +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION_DEFAULT (0) + +/* + * + * 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_NAME "gEnableSecondaryRate" +#define CFG_ENABLE_SECONDARY_RATE_MIN (0) +#define CFG_ENABLE_SECONDARY_RATE_MAX (0x3F) +#define CFG_ENABLE_SECONDARY_RATE_DEFAULT (0x17) + +#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_NAME "gMwsCoex4gQuickTdm" +#define CFG_MWS_COEX_4G_QUICK_FTDM_MIN (0x00000000) +#define CFG_MWS_COEX_4G_QUICK_FTDM_MAX (0xFFFFFFFF) +#define CFG_MWS_COEX_4G_QUICK_FTDM_DEFAULT (0x00000000) + +/* + * + * 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_NAME "gMwsCoex5gnrPwrLimit" +#define CFG_MWS_COEX_5G_NR_PWR_LIMIT_MIN (0x00000000) +#define CFG_MWS_COEX_5G_NR_PWR_LIMIT_MAX (0xFFFFFFFF) +#define CFG_MWS_COEX_5G_NR_PWR_LIMIT_DEFAULT (0x00000000) +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * + * 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_ROAM_PREAUTH_RETRY_COUNT_NAME "roam_preauth_retry_count" +#define CFG_ROAM_PREAUTH_RETRY_COUNT_MIN (1) +#define CFG_ROAM_PREAUTH_RETRY_COUNT_MAX (10) +#define CFG_ROAM_PREAUTH_RETRY_COUNT_DEFAULT (5) + +/* + * + * 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_ROAM_PREAUTH_NO_ACK_TIMEOUT_NAME "roam_preauth_no_ack_timeout" +#define CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_MIN (5) +#define CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_MAX (50) +#define CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_DEFAULT (5) +#endif +/* + * + * gSetBTCMode - Config BTC mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * 0 - TDD + * 1 - FDD + * 2 - Hybrid + * + * Usage: External + * + * + */ +#define CFG_SET_BTC_MODE_NAME "gSetBTCMode" +#define CFG_SET_BTC_MODE_MIN (0) +#define CFG_SET_BTC_MODE_MAX (2) +#define CFG_SET_BTC_MODE_DEFAULT (0) + +/* + * + * gSetAntennaIsolation - Set Antenna Isolation + * @Min: 0 + * @Max: 255 + * @Default: 25 + * + * Usage: External + * + * + */ +#define CFG_SET_ANTENNA_ISOLATION_NAME "gSetAntennaIsolation" +#define CFG_SET_ANTENNA_ISOLATION_MIN (0) +#define CFG_SET_ANTENNA_ISOLATION_MAX (255) +#define CFG_SET_ANTENNA_ISOLATION_DEFAULT (25) + +/* + * + * gSetMaxTxPowerForBTC - Set Max WLAN Tx power in COEX scenario + * @Min: 0 + * @Max: 100 + * @Default: 100 + * + * Usage: External + * + * + */ +#define CFG_SET_MAX_TX_POWER_FOR_BTC_NAME "gSetMaxTxPowerForBTC" +#define CFG_SET_MAX_TX_POWER_FOR_BTC_MIN (0) +#define CFG_SET_MAX_TX_POWER_FOR_BTC_MAX (100) +#define CFG_SET_MAX_TX_POWER_FOR_BTC_DEFAULT (100) + +/* + * + * gSetWlanLowRssiThreshold - Set WLAN low RSSI threshold for BTC mode switching + * @Min: -100 + * @Max: 0 + * @Default: -80 + * + * Usage: External + * + * + */ +#define CFG_SET_WLAN_LOW_RSSI_THRESHOLD_NAME "gSetWlanLowRssiThreshold" +#define CFG_SET_WLAN_LOW_RSSI_THRESHOLD_MIN (-100) +#define CFG_SET_WLAN_LOW_RSSI_THRESHOLD_MAX (0) +#define CFG_SET_WLAN_LOW_RSSI_THRESHOLD_DEFAULT (-80) + +/* + * + * gSetBtLowRssiThreshold - Set BT low RSSI threshold for BTC mode switching + * @Min: -100 + * @Max: 0 + * @Default: -80 + * + * Usage: External + * + * + */ +#define CFG_SET_BT_LOW_RSSI_THRESHOLD_NAME "gSetBtLowRssiThreshold" +#define CFG_SET_BT_LOW_RSSI_THRESHOLD_MIN (-100) +#define CFG_SET_BT_LOW_RSSI_THRESHOLD_MAX (0) +#define CFG_SET_BT_LOW_RSSI_THRESHOLD_DEFAULT (-80) + +/* + * + * gSetBtInterferenceLowLL - Set lower limit of low level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -25 + * + * Usage: External + * + * + */ +#define CFG_SET_BT_INTERFERENCE_LOW_LL_NAME "gSetBtInterferenceLowLL" +#define CFG_SET_BT_INTERFERENCE_LOW_LL_MIN (-100) +#define CFG_SET_BT_INTERFERENCE_LOW_LL_MAX (100) +#define CFG_SET_BT_INTERFERENCE_LOW_LL_DEFAULT (-25) + +/* + * + * gSetBtInterferenceLowUL - Set upper limit of low level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -21 + * + * Usage: External + * + * + */ +#define CFG_SET_BT_INTERFERENCE_LOW_UL_NAME "gSetBtInterferenceLowUL" +#define CFG_SET_BT_INTERFERENCE_LOW_UL_MIN (-100) +#define CFG_SET_BT_INTERFERENCE_LOW_UL_MAX (100) +#define CFG_SET_BT_INTERFERENCE_LOW_UL_DEFAULT (-21) + +/* + * + * gSetBtInterferenceMediumLL - Set lower limit of medium level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -20 + * + * Usage: External + * + * + */ +#define CFG_SET_BT_INTERFERENCE_MEDIUM_LL_NAME "gSetBtInterferenceMediumLL" +#define CFG_SET_BT_INTERFERENCE_MEDIUM_LL_MIN (-100) +#define CFG_SET_BT_INTERFERENCE_MEDIUM_LL_MAX (100) +#define CFG_SET_BT_INTERFERENCE_MEDIUM_LL_DEFAULT (-20) + +/* + * + * gSetBtInterferenceMediumUL - Set upper limit of medium level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -16 + * + * Usage: External + * + * + */ +#define CFG_SET_BT_INTERFERENCE_MEDIUM_UL_NAME "gSetBtInterferenceMediumUL" +#define CFG_SET_BT_INTERFERENCE_MEDIUM_UL_MIN (-100) +#define CFG_SET_BT_INTERFERENCE_MEDIUM_UL_MAX (100) +#define CFG_SET_BT_INTERFERENCE_MEDIUM_UL_DEFAULT (-16) + +/* + * + * gSetBtInterferenceHighLL - Set lower limit of high level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -15 + * + * Usage: External + * + * + */ +#define CFG_SET_BT_INTERFERENCE_HIGH_LL_NAME "gSetBtInterferenceHighLL" +#define CFG_SET_BT_INTERFERENCE_HIGH_LL_MIN (-100) +#define CFG_SET_BT_INTERFERENCE_HIGH_LL_MAX (100) +#define CFG_SET_BT_INTERFERENCE_HIGH_LL_DEFAULT (-15) + +/* + * + * gSetBtInterferenceHighUL - Set upper limit of high level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -11 + * + * Usage: External + * + * + */ +#define CFG_SET_BT_INTERFERENCE_HIGH_UL_NAME "gSetBtInterferenceHighUL" +#define CFG_SET_BT_INTERFERENCE_HIGH_UL_MIN (-100) +#define CFG_SET_BT_INTERFERENCE_HIGH_UL_MAX (100) +#define CFG_SET_BT_INTERFERENCE_HIGH_UL_DEFAULT (-11) + +#ifdef FEATURE_MPTA_HELPER +/* + * + * gMPTAHelperEnable - Config MPTA helper enable + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Usage: External + * + * + */ +#define CFG_SET_MPTA_HELPER_ENABLE_NAME "gMPTAHelperEnable" +#define CFG_SET_MPTA_HELPER_ENABLE_MIN (0) +#define CFG_SET_MPTA_HELPER_ENABLE_MAX (1) +#define CFG_SET_MPTA_HELPER_ENABLE_DEFAULT (0) +#endif + +/* + * + * 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_NAME "enable_mac_provision" +#define CFG_ENABLE_MAC_PROVISION_MIN (0) +#define CFG_ENABLE_MAC_PROVISION_MAX (1) +#define CFG_ENABLE_MAC_PROVISION_DEFAULT (0) + +/* + * + * 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_NAME "provisioned_intf_pool" +#define CFG_PROVISION_INTERFACE_POOL_MIN (0) +#define CFG_PROVISION_INTERFACE_POOL_MAX (0xffffffff) +#define CFG_PROVISION_INTERFACE_POOL_DEFAULT (0xffffffff) +/* + * + * 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_NAME "derived_intf_pool" +#define CFG_DERIVED_INTERFACE_POOL_MIN (0) +#define CFG_DERIVED_INTERFACE_POOL_MAX (0xffffffff) +#define CFG_DERIVED_INTERFACE_POOL_DEFAULT (0xffffffff) + +/* + * + * gEnablePeerUnmapConfSupport - Set PEER UNMAP confirmation support + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable peer unmap confirmation support + * in Host. Host sends this support to FW only if FW support is enabled. + * + * + * Supported Feature: STA/SAP/P2P + * + * Usage: External + * + * + */ +#define CFG_ENABLE_PEER_UNMAP_CONF_NAME "gEnablePeerUnmapConfSupport" +#define CFG_ENABLE_PEER_UNMAP_CONF_MIN (0) +#define CFG_ENABLE_PEER_UNMAP_CONF_MAX (1) +#define CFG_ENABLE_PEER_UNMAP_CONF_DEFAULT (0) + +/* + * + * roam_score_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 "roam_score_delta" + +#define CFG_ROAM_SCORE_DELTA_DEFAULT 0 +#define CFG_ROAM_SCORE_DELTA_MIN 0 +#define CFG_ROAM_SCORE_DELTA_MAX 100 + +/* + * + * 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 + * + * 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_TRIGGER_DELTA_BITMAP "roam_score_delta_bitmap" + +#define CFG_ROAM_TRIGGER_DELTA_BITMAP_DEFAULT 0xffffffff +#define CFG_ROAM_TRIGGER_DELTA_BITMAP_MIN 0 +#define CFG_ROAM_TRIGGER_DELTA_BITMAP_MAX 0xffffffff + +/* + * + * 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. + * Enabling this flag also will Set the bit 8 of btm_offload_config + * which will be sent to firmware + * + * Supported Feature: STA + * + * Usage: External + * + + */ +#define CFG_PREFER_BTM_QUERY "prefer_btm_query" + +#define CFG_PREFER_BTM_QUERY_DEFAULT 1 +#define CFG_PREFER_BTM_QUERY_MIN 0 +#define CFG_PREFER_BTM_QUERY_MAX 1 + +#define BTM_OFFLOAD_CONFIG_BIT_8 8 +#define BTM_OFFLOAD_CONFIG_BIT_7 7 + +/* + * + * prefer_roam_score_for_candidate_selection - choose to sort the candidates on + * roam score or prefered 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 preferred APs. + * Enabling this flag also will Set the bit 7 of btm_offload_config + * which will be sent to firmware + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_BTM_ABRIDGE "prefer_roam_score_for_candidate_selection" + +#define CFG_ENABLE_BTM_ABRIDGE_DEFAULT 1 +#define CFG_ENABLE_BTM_ABRIDGE_MIN 0 +#define CFG_ENABLE_BTM_ABRIDGE_MAX 1 + +/* + * + * 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: STA + * + * Usage: External + * + * + */ +#define CFG_BTM_VALIDITY_TIMER "roam_candidate_validity_timer" + +#define CFG_BTM_VALIDITY_TIMER_DEFAULT 0xffffffff +#define CFG_BTM_VALIDITY_TIMER_MIN 0 +#define CFG_BTM_VALIDITY_TIMER_MAX 0xffffffff + + /* + * + * 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 + * + * + */ +#define CFG_ENABLE_BEACON_RECEPTION_STATS_NAME "enable_beacon_reception_stats" +#define CFG_ENABLE_BEACON_RECEPTION_STATS_MIN 0 +#define CFG_ENABLE_BEACON_RECEPTION_STATS_MAX 1 +#define CFG_ENABLE_BEACON_RECEPTION_STATS_DEFAULT 0 + +/* + * + * 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: 0 + * + * 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: STA + * + * Usage: External + * + * + */ +#define CFG_BTM_DISASSOC_TIMER_THRESHOLD "btm_disassoc_timer_threshold" + +#define CFG_BTM_DISASSOC_TIMER_THRESHOLD_DEFAULT 0 +#define CFG_BTM_DISASSOC_TIMER_THRESHOLD_MIN 0 +#define CFG_BTM_DISASSOC_TIMER_THRESHOLD_MAX 0xffffffff + +/* + * + * 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 "enable_bss_load_roam_trigger" + +#define CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM_DEFAULT 0 +#define CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM_MIN 0 +#define CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM_MAX 1 + +/* + * + * bss_load_threshold - bss load above which the STA should trigger roaming + * @Min: 0 + * @Max: 100 + * @Default: 70 + * + * When the bss laod 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 "bss_load_threshold" + +#define CFG_BSS_LOAD_THRESHOLD_DEFAULT 70 +#define CFG_BSS_LOAD_THRESHOLD_MIN 0 +#define CFG_BSS_LOAD_THRESHOLD_MAX 100 + + /* + * + * 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 "bss_load_sample_time" + +#define CFG_BSS_LOAD_SAMPLE_TIME_DEFAULT 10000 +#define CFG_BSS_LOAD_SAMPLE_TIME_MIN 0 +#define CFG_BSS_LOAD_SAMPLE_TIME_MAX 0xffffffff + +/* + * gEnableRTTsupport + * @Min: 0 - Disabled + * @Max: 1 - Enabled + * @Default: 1 - Enabled + * + * The param is used to enable/disable support for RTT + */ +#define CFG_ENABLE_RTT_SUPPORT "gEnableRTTSupport" +#define CFG_ENABLE_RTT_SUPPORT_DEFAULT (1) +#define CFG_ENABLE_RTT_SUPPORT_MIN (0) +#define CFG_ENABLE_RTT_SUPPORT_MAX (1) + +/* + * Type declarations + */ + +struct hdd_config { + /* Bitmap to track what is explicitly configured */ + DECLARE_BITMAP(bExplicitCfg, MAX_CFG_INI_ITEMS); + + /* Config parameters */ +#ifdef WLAN_NUD_TRACKING + bool enable_nud_tracking; +#endif + bool enable_connected_scan; + uint32_t RTSThreshold; + uint32_t FragmentationThreshold; + uint8_t OperatingChannel; + bool ShortSlotTimeEnabled; + bool Is11dSupportEnabled; + bool Is11hSupportEnabled; + bool fSupplicantCountryCodeHasPriority; + uint32_t HeartbeatThresh24; + char PowerUsageControl[4]; + bool fIsImpsEnabled; + bool is_ps_enabled; + uint32_t auto_bmps_timer_val; + uint32_t icmp_disable_ps_val; + uint32_t nBmpsMaxListenInterval; + uint32_t nBmpsMinListenInterval; + enum hdd_dot11_mode dot11Mode; + uint32_t nChannelBondingMode24GHz; + bool override_ht20_40_24g; + uint32_t nChannelBondingMode5GHz; + uint32_t MaxRxAmpduFactor; + uint32_t ShortGI20MhzEnable; + uint32_t ScanResultAgeCount; + uint8_t nRssiCatGap; + bool fIsShortPreamble; + struct qdf_mac_addr IbssBssid; + uint32_t AdHocChannel5G; + uint32_t AdHocChannel24G; + + bool apUapsdEnabled; + bool apRandomBssidEnabled; + bool apProtEnabled; + uint16_t apProtection; + bool apOBSSProtEnabled; + bool apDisableIntraBssFwd; + uint8_t enableLTECoex; + uint32_t apKeepAlivePeriod; + uint32_t goKeepAlivePeriod; + enum station_keepalive_method sta_keepalive_method; + uint32_t apLinkMonitorPeriod; + uint32_t goLinkMonitorPeriod; + uint32_t nBeaconInterval; + uint8_t nTxPowerCap; /* In dBm */ + bool allow_tpc_from_ap; + uint8_t disablePacketFilter; + bool fRrmEnable; + uint16_t nRrmRandnIntvl; + /* length includes separator */ + char rm_capability[3 * DOT11F_IE_RRMENABLEDCAP_MAX_LEN]; + + /* Bitmap for operating voltage corner mode */ + uint32_t vc_mode_cfg_bitmap; + +#ifdef MWS_COEX + /* Bitmap for MWS-COEX 4G Quick FTDM */ + uint32_t mws_coex_4g_quick_tdm; + + /* Bitmap for MWS-COEX 5G-NR power limit */ + uint32_t mws_coex_5g_nr_pwr_limit; +#endif + + uint16_t nNeighborScanPeriod; + uint16_t neighbor_scan_min_period; + uint8_t nNeighborLookupRssiThreshold; + uint8_t delay_before_vdev_stop; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t neighborScanChanList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + uint16_t nMaxNeighborReqTries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; + + /* Additional Handoff params */ + uint16_t nVccRssiTrigger; + uint32_t nVccUlMacLossThreshold; + + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + uint32_t active_dwell_2g; /* in units of milliseconds */ + uint32_t scan_probe_repeat_time; + uint32_t scan_num_probes; + bool drop_bcn_on_chan_mismatch; + + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; + + uint32_t nPassiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /* In units of milliseconds */ + uint32_t min_rest_time_conc; + /* In units of milliseconds */ + uint32_t idle_time_conc; + + uint8_t nMaxPsPoll; + + uint8_t nRssiFilterPeriod; + uint8_t fMaxLIModulatedDTIM; + + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + uint8_t nDataInactivityTimeout; + uint8_t wow_data_inactivity_timeout; + + /* WMM QoS Configuration */ + enum hdd_wmm_user_mode WmmMode; + bool b80211eIsEnabled; + uint8_t UapsdMask; /* what ACs to setup U-APSD for at assoc */ + uint32_t InfraUapsdVoSrvIntv; + uint32_t InfraUapsdVoSuspIntv; + uint32_t InfraUapsdViSrvIntv; + uint32_t InfraUapsdViSuspIntv; + uint32_t InfraUapsdBeSrvIntv; + uint32_t InfraUapsdBeSuspIntv; + uint32_t InfraUapsdBkSrvIntv; + uint32_t InfraUapsdBkSuspIntv; + bool isFastRoamIniFeatureEnabled; + bool MAWCEnabled; + bool mawc_roam_enabled; + uint32_t mawc_roam_traffic_threshold; + int8_t mawc_roam_ap_rssi_threshold; + uint8_t mawc_roam_rssi_high_adjust; + uint8_t mawc_roam_rssi_low_adjust; +#ifdef FEATURE_WLAN_ESE + uint32_t InfraInactivityInterval; + bool isEseIniFeatureEnabled; +#endif + bool isFastTransitionEnabled; + uint8_t RoamRssiDiff; + int32_t rssi_abs_thresh; + bool isWESModeEnabled; + uint32_t pmkid_modes; + bool isRoamOffloadScanEnabled; + bool bImplicitQosEnabled; + + /* default TSPEC parameters for AC_VO */ + enum sme_qos_wmm_dir_type InfraDirAcVo; + uint16_t InfraNomMsduSizeAcVo; + uint32_t InfraMeanDataRateAcVo; + uint32_t InfraMinPhyRateAcVo; + uint16_t InfraSbaAcVo; + + /* default TSPEC parameters for AC_VI */ + enum sme_qos_wmm_dir_type InfraDirAcVi; + uint16_t InfraNomMsduSizeAcVi; + uint32_t InfraMeanDataRateAcVi; + uint32_t InfraMinPhyRateAcVi; + uint16_t InfraSbaAcVi; + + /* default TSPEC parameters for AC_BE */ + enum sme_qos_wmm_dir_type InfraDirAcBe; + uint16_t InfraNomMsduSizeAcBe; + uint32_t InfraMeanDataRateAcBe; + uint32_t InfraMinPhyRateAcBe; + uint16_t InfraSbaAcBe; + + /* default TSPEC parameters for AC_BK */ + enum sme_qos_wmm_dir_type InfraDirAcBk; + uint16_t InfraNomMsduSizeAcBk; + uint32_t InfraMeanDataRateAcBk; + uint32_t InfraMinPhyRateAcBk; + uint16_t InfraSbaAcBk; + + uint32_t DelayedTriggerFrmInt; + + char enableConcurrentSTA[CFG_CONCURRENT_IFACE_MAX_LEN]; + + /* Control for Replay counetr. value 1 means + * single replay counter for all TID + */ + bool bSingleTidRc; + bool fhostArpOffload; + enum pmo_hw_filter_mode hw_filter_mode_bitmap; + bool ssdp; + +#ifdef FEATURE_RUNTIME_PM + bool runtime_pm; + uint32_t runtime_pm_delay; +#endif + +#ifdef FEATURE_WLAN_RA_FILTERING + bool IsRArateLimitEnabled; + uint16_t RArateLimitInterval; +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + bool PnoOffload; +#endif + bool fhostNSOffload; + bool burstSizeDefinition; + uint8_t tsInfoAckPolicy; + + bool AddTSWhenACMIsOff; + + uint32_t infraStaKeepAlivePeriod; + uint8_t nBandCapability; + bool teleBcnWakeupEn; + +/* QDF Trace Control*/ + uint16_t qdf_trace_enable_wdi; + uint16_t qdf_trace_enable_hdd; + uint16_t qdf_trace_enable_sme; + uint16_t qdf_trace_enable_pe; + uint16_t qdf_trace_enable_pmc; + uint16_t qdf_trace_enable_wma; + uint16_t qdf_trace_enable_sys; + uint16_t qdf_trace_enable_qdf; + uint16_t qdf_trace_enable_sap; + uint16_t qdf_trace_enable_hdd_sap; + uint16_t qdf_trace_enable_bmi; + uint16_t qdf_trace_enable_cfg; + uint16_t qdf_trace_enable_txrx; + uint16_t qdf_trace_enable_dp; + uint16_t qdf_trace_enable_htc; + uint16_t qdf_trace_enable_hif; + uint16_t qdf_trace_enable_hdd_sap_data; + uint16_t qdf_trace_enable_hdd_data; + uint16_t qdf_trace_enable_epping; + uint16_t qdf_trace_enable_qdf_devices; + uint16_t qdf_trace_enable_wifi_pos; + uint16_t qdf_trace_enable_nan; + uint16_t qdf_trace_enable_regulatory; + uint16_t qdf_trace_enable_cp_stats; +#ifdef ENABLE_MTRACE_LOG + bool enable_mtrace; +#endif + uint16_t nTeleBcnMaxListenInterval; + uint8_t enableBypass11d; + uint8_t enableDFSChnlScan; + bool wake_lock_in_user_scan; + bool honour_nl_scan_policy_flags; + uint8_t enable_dfs_pno_chnl_scan; + uint8_t enableDynamicDTIM; + uint8_t ShortGI40MhzEnable; + enum hdd_link_speed_rpt_type reportMaxLinkSpeed; + int32_t linkSpeedRssiHigh; + int32_t linkSpeedRssiMid; + int32_t linkSpeedRssiLow; + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; + uint8_t enableMCC; + uint8_t allowMCCGODiffBI; + bool isP2pDeviceAddrAdministrated; + uint8_t thermalMitigationEnable; + uint32_t throttlePeriod; + uint32_t throttle_dutycycle_level0; + uint32_t throttle_dutycycle_level1; + uint32_t throttle_dutycycle_level2; + uint32_t throttle_dutycycle_level3; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + bool bad_peer_txctl_enable; + uint32_t bad_peer_txctl_prd; + uint32_t bad_peer_txctl_txq_lmt; + uint32_t bad_peer_tgt_backoff; + uint32_t bad_peer_tgt_report_prd; + uint32_t bad_peer_cond_ieee80211b; + uint32_t bad_peer_delta_ieee80211b; + uint32_t bad_peer_pct_ieee80211b; + uint32_t bad_peer_tput_ieee80211b; + uint32_t bad_peer_limit_ieee80211b; + uint32_t bad_peer_cond_ieee80211ag; + uint32_t bad_peer_delta_ieee80211ag; + uint32_t bad_peer_pct_ieee80211ag; + uint32_t bad_peer_tput_ieee80211ag; + uint32_t bad_peer_limit_ieee80211ag; + uint32_t bad_peer_cond_ieee80211n; + uint32_t bad_peer_delta_ieee80211n; + uint32_t bad_peer_pct_ieee80211n; + uint32_t bad_peer_tput_ieee80211n; + uint32_t bad_peer_limit_ieee80211n; + uint32_t bad_peer_cond_ieee80211ac; + uint32_t bad_peer_delta_ieee80211ac; + uint32_t bad_peer_pct_ieee80211ac; + uint32_t bad_peer_tput_ieee80211ac; + uint32_t bad_peer_limit_ieee80211ac; +#endif + uint8_t vhtChannelWidth; + uint8_t vhtRxMCS; + uint8_t vhtTxMCS; + bool enableTxBF; + bool enable_subfee_vendor_vhtie; + bool enable_txbf_sap_mode; + bool enable_vht20_mcs9; + uint8_t txBFCsnValue; + bool enable_su_tx_bformer; + uint8_t vhtRxMCS2x2; + uint8_t vhtTxMCS2x2; + uint8_t disable_high_ht_mcs_2x2; + bool enable2x2; + uint8_t txchainmask1x1; + uint8_t rxchainmask1x1; + bool enableMuBformee; + bool enableVhtpAid; + bool enableVhtGid; + bool enableTxBFin20MHz; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + uint8_t enableModulatedDTIM; + uint32_t fEnableMCAddrList; + bool enableFirstScan2GOnly; + bool skipDfsChnlInP2pSearch; + bool ignoreDynamicDtimInP2pMode; + bool enableRxSTBC; + bool enableTxSTBC; + uint8_t enable_tx_ldpc; + uint8_t enable_rx_ldpc; + bool enable5gEBT; + bool prevent_link_down; +#ifdef FEATURE_WLAN_TDLS + bool fEnableTDLSSupport; + bool fEnableTDLSImplicitTrigger; + uint32_t fTDLSTxStatsPeriod; + uint32_t fTDLSTxPacketThreshold; + uint32_t fTDLSMaxDiscoveryAttempt; + uint32_t tdls_idle_timeout; + uint32_t fTDLSIdlePacketThreshold; + int32_t fTDLSRSSITriggerThreshold; + int32_t fTDLSRSSITeardownThreshold; + int32_t fTDLSRSSIDelta; + uint32_t fTDLSUapsdMask; /* what ACs to setup U-APSD for TDLS */ + uint32_t fEnableTDLSBufferSta; + uint32_t fEnableTDLSSleepSta; + uint32_t fTDLSPuapsdInactivityTimer; + uint32_t fTDLSRxFrameThreshold; + uint32_t fTDLSPuapsdPTIWindow; + uint32_t fTDLSPuapsdPTRTimeout; + bool fTDLSExternalControl; + uint32_t fEnableTDLSOffChannel; + uint32_t fEnableTDLSWmmMode; + uint8_t fTDLSPrefOffChanNum; + uint8_t fTDLSPrefOffChanBandwidth; + uint8_t enable_tdls_scan; + uint32_t tdls_peer_kickout_threshold; +#endif + uint8_t scanAgingTimeout; + uint8_t disableLDPCWithTxbfAP; + uint8_t enableMCCAdaptiveScheduler; + bool sapAllowAllChannel; + bool enableSSR; + bool enable_data_stall_det; + bool enableVhtFor24GHzBand; + bool enable_sap_vendor_vht; + bool bFastRoamInConIniFeatureEnabled; + bool fEnableSNRMonitoring; + /*PNO related parameters */ +#ifdef FEATURE_WLAN_SCAN_PNO + bool configPNOScanSupport; + uint32_t configPNOScanTimerRepeatValue; + uint32_t pno_slow_scan_multiplier; +#endif + uint8_t max_amsdu_num; + uint8_t nSelect5GHzMargin; + uint8_t isCoalesingInIBSSAllowed; + + /* IBSS Power Save related parameters */ + uint32_t ibssATIMWinSize; + uint8_t isIbssPowerSaveAllowed; + uint8_t isIbssPowerCollapseAllowed; + uint8_t isIbssAwakeOnTxRx; + uint32_t ibssInactivityCount; + uint32_t ibssTxSpEndInactivityTime; + uint32_t ibssPsWarmupTime; + uint32_t ibssPs1RxChainInAtimEnable; + + bool enable_ip_tcp_udp_checksum_offload; + uint8_t enablePowersaveOffload; + bool enablefwprint; + uint8_t enable_fw_log; + uint8_t fVhtAmpduLenExponent; + uint32_t vhtMpduLen; + uint32_t IpaConfig; + bool IpaClkScalingEnable; + uint32_t IpaDescSize; + uint32_t IpaHighBandwidthMbps; + uint32_t IpaMediumBandwidthMbps; + uint32_t IpaLowBandwidthMbps; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint32_t WlanMccToSccSwitchMode; +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + uint32_t WlanAutoShutdown; +#endif + uint8_t wowEnable; + uint8_t maxNumberOfPeers; + uint8_t disableDFSChSwitch; + uint8_t enableDFSMasterCap; + uint16_t thermalTempMinLevel0; + uint16_t thermalTempMaxLevel0; + uint16_t thermalTempMinLevel1; + uint16_t thermalTempMaxLevel1; + uint16_t thermalTempMinLevel2; + uint16_t thermalTempMaxLevel2; + uint16_t thermalTempMinLevel3; + uint16_t thermalTempMaxLevel3; + uint32_t TxPower2g; + uint32_t TxPower5g; + uint32_t gEnableDebugLog; + bool fDfsPhyerrFilterOffload; + uint8_t gSapPreferredChanLocation; + uint8_t gDisableDfsJapanW53; + bool gEnableOverLapCh; + bool fRegChangeDefCountry; + bool acs_with_more_param; + uint32_t auto_channel_select_weight; + uint16_t max_ht_mcs_txdata; + bool sap_get_peer_info; + bool disable_abg_rate_txdata; + uint8_t rate_for_tx_mgmt; + uint8_t rate_for_tx_mgmt_2g; + uint8_t rate_for_tx_mgmt_5g; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + uint32_t TxFlowLowWaterMark; + uint32_t TxFlowHighWaterMarkOffset; + uint32_t TxFlowMaxQueueDepth; + uint32_t TxLbwFlowLowWaterMark; + uint32_t TxLbwFlowHighWaterMarkOffset; + uint32_t TxLbwFlowMaxQueueDepth; + uint32_t TxHbwFlowLowWaterMark; + uint32_t TxHbwFlowHighWaterMarkOffset; + uint32_t TxHbwFlowMaxQueueDepth; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + uint32_t TxFlowStopQueueThreshold; + uint32_t TxFlowStartQueueOffset; + uint8_t apMaxOffloadPeers; + uint8_t apMaxOffloadReorderBuffs; + bool advertiseConcurrentOperation; + bool enableMemDeepSleep; + bool enable_cck_tx_fir_override; + + uint8_t allowDFSChannelRoam; + + bool debugP2pRemainOnChannel; + +#ifndef REMOVE_PKT_LOG + bool enablePacketLog; +#endif + +#ifdef MSM_PLATFORM + uint32_t busBandwidthHighThreshold; + uint32_t busBandwidthMediumThreshold; + uint32_t busBandwidthLowThreshold; + uint32_t busBandwidthComputeInterval; + uint32_t enable_tcp_delack; + bool enable_tcp_limit_output; + uint32_t enable_tcp_adv_win_scale; + uint32_t tcpDelackThresholdHigh; + uint32_t tcpDelackThresholdLow; + uint32_t tcp_tx_high_tput_thres; + uint32_t tcp_delack_timer_count; + bool enable_tcp_param_update; + u8 periodic_stats_disp_time; +#endif /* MSM_PLATFORM */ + + /* FW debug log parameters */ + uint32_t enableFwLogType; + uint32_t enableFwLogLevel; + uint8_t enableFwModuleLogLevel[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + + /* RTS profile parameter */ + uint32_t rts_profile; + +#ifdef WLAN_FEATURE_11W + uint32_t pmfSaQueryMaxRetries; + uint32_t pmfSaQueryRetryInterval; +#endif + + uint8_t gMaxConcurrentActiveSessions; + + uint8_t ignoreCAC; + + /* Flag to indicate crash inject enabled or not */ + bool crash_inject_enabled; + + bool enable_sap_mandatory_chan_list; + + int32_t dfsRadarPriMultiplier; + uint8_t reorderOffloadSupport; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + + uint32_t IpaUcTxBufCount; + uint32_t IpaUcTxBufSize; + uint32_t IpaUcRxIndRingCount; + uint32_t IpaUcTxPartitionBase; +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + /* WLAN Logging */ + bool wlan_logging_enable; + bool wlan_logging_to_console; +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + +#ifdef WLAN_FEATURE_LPSS + bool enable_lpass_support; +#endif +#ifdef WLAN_FEATURE_NAN + bool enable_nan_support; +#endif + bool enableSelfRecovery; +#ifdef FEATURE_WLAN_FORCE_SAP_SCC + uint8_t SapSccChanAvoidance; +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + + bool enable_sap_suspend; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + uint8_t extWowGotoSuspend; + uint8_t extWowApp1WakeupPinNumber; + uint8_t extWowApp2WakeupPinNumber; + uint32_t extWowApp2KAInitPingInterval; + uint32_t extWowApp2KAMinPingInterval; + uint32_t extWowApp2KAMaxPingInterval; + uint32_t extWowApp2KAIncPingInterval; + uint16_t extWowApp2TcpSrcPort; + uint16_t extWowApp2TcpDstPort; + uint32_t extWowApp2TcpTxTimeout; + uint32_t extWowApp2TcpRxTimeout; +#endif + bool gEnableDeauthToDisassocMap; +#ifdef DHCP_SERVER_OFFLOAD + bool enableDHCPServerOffload; + uint32_t dhcpMaxNumClients; + uint8_t dhcpServerIP[IPADDR_STRING_LENGTH]; +#endif /* DHCP_SERVER_OFFLOAD */ + bool enable_mac_spoofing; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + uint16_t p2p_listen_defer_interval; + uint32_t sta_miracast_mcc_rest_time_val; + uint32_t sta_scan_burst_duration; + uint32_t p2p_scan_burst_duration; + uint32_t go_scan_burst_duration; + uint32_t ap_scan_burst_duration; + bool is_ramdump_enabled; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t sap_11ac_override; + uint8_t go_11ac_override; + uint8_t sap_dot11mc; + uint8_t prefer_non_dfs_on_radar; + bool ignore_peer_erp_info; + uint8_t multicast_host_fw_msgs; + uint8_t conc_system_pref; + bool send_deauth_before_con; + bool tso_enable; + bool lro_enable; + bool gro_enable; + bool flow_steering_enable; + uint8_t max_msdus_per_rxinorderind; + bool active_mode_offload; + bool apf_packet_filter_enable; + /* parameter for defer timer for enabling TDLS on p2p listen */ + uint16_t tdls_enable_defer_time; + uint32_t fine_time_meas_cap; + uint8_t max_scan_count; +#ifdef WLAN_FEATURE_FASTPATH + bool fastpath_enable; +#endif + uint8_t dot11p_mode; + bool etsi13_srd_chan_in_master_mode; + uint8_t rx_mode; + uint32_t ce_service_max_yield_time; + uint8_t ce_service_max_rx_ind_flush; + uint32_t napi_cpu_affinity_mask; + /* CPU affinity mask for rx_thread */ + uint32_t rx_thread_affinity_mask; + uint8_t cpu_map_list[CFG_RPS_RX_QUEUE_CPU_MAP_LIST_LEN]; +#ifdef FEATURE_WLAN_EXTSCAN + bool extscan_enabled; + uint32_t extscan_passive_max_chn_time; + uint32_t extscan_passive_min_chn_time; + uint32_t extscan_active_max_chn_time; + uint32_t extscan_active_min_chn_time; +#endif + bool ce_classify_enabled; + uint32_t dual_mac_feature_disable; + uint8_t dbs_scan_selection[CFG_DBS_SCAN_PARAM_LENGTH]; + uint32_t sta_sap_scc_on_dfs_chan; + uint32_t sta_sap_scc_on_lte_coex_chan; + bool tx_chain_mask_cck; + uint8_t tx_chain_mask_1ss; + bool smart_chainmask_enabled; + bool alternative_chainmask_enabled; + uint16_t self_gen_frm_pwr; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_channel_prediction; + uint8_t top_k_num_of_channels; + uint8_t stationary_thresh; + uint32_t channel_prediction_full_scan; +#endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + int8_t first_scan_bucket_threshold; + uint8_t ht_mpdu_density; +#ifdef FEATURE_LFR_SUBNET_DETECTION + bool enable_lfr_subnet_detection; +#endif + uint16_t obss_active_dwelltime; + uint16_t obss_passive_dwelltime; + uint16_t obss_width_trigger_interval; + uint8_t inform_bss_rssi_raw; +#ifdef WLAN_FEATURE_TSF + uint32_t tsf_gpio_pin; + +#ifdef WLAN_FEATURE_TSF_PLUS + uint8_t tsf_ptp_options; +#endif /* WLAN_FEATURE_TSF_PLUS */ +#endif + bool enable_three_way_coex_config_legacy; + uint32_t roam_dense_traffic_thresh; + uint32_t roam_dense_rssi_thresh_offset; + bool ignore_peer_ht_opmode; + uint32_t roam_dense_min_aps; + int8_t roam_bg_scan_bad_rssi_thresh; + uint8_t roam_bad_rssi_thresh_offset_2g; + uint32_t ho_delay_for_rx; + uint32_t min_delay_btw_roam_scans; + uint32_t roam_trigger_reason_bitmask; + bool roaming_scan_policy; + uint32_t roam_bg_scan_client_bitmap; + bool enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; + + /* Tuning TX sched parameters for VO (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_vo[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + /* Tuning TX sched parameters for VI (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_vi[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + /* Tuning TX sched parameters for BE (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_be[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + /* Tuning TX sched parameters for BK (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_bk[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + + bool enable_fatal_event; + bool apf_enabled; +#ifdef CONFIG_DP_TRACE + bool enable_dp_trace; + uint8_t dp_trace_config[DP_TRACE_CONFIG_STRING_LENGTH]; +#endif + bool adaptive_dwell_mode_enabled; + enum scan_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum scan_dwelltime_adaptive_mode scan_adaptive_dwell_mode_nc; + enum scan_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + enum scan_dwelltime_adaptive_mode extscan_adaptive_dwell_mode; + enum scan_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; + enum scan_dwelltime_adaptive_mode global_adapt_dwelltime_mode; + uint8_t adapt_dwell_lpf_weight; + uint8_t adapt_dwell_passive_mon_intval; + uint8_t adapt_dwell_wifi_act_threshold; + bool vendor_acs_support; + bool acs_support_for_dfs_ltecoex; + bool bug_report_for_no_scan_results; + bool bug_on_reinit_failure; +#ifdef WLAN_FEATURE_NAN_DATAPATH + bool enable_nan_datapath; + uint8_t nan_datapath_ndi_channel; +#endif + uint32_t iface_change_wait_time; + /* parameter to control GTX */ + uint32_t tgt_gtx_usr_cfg; + enum cfg_sub_20_channel_width enable_sub_20_channel_width; + bool indoor_channel_support; + /* control marking indoor channel passive to disable */ + bool force_ssc_disable_indoor_channel; + /* parameter to force sap into 11n */ + bool sap_force_11n_for_11ac; + bool go_force_11n_for_11ac; + uint16_t sap_tx_leakage_threshold; + bool multicast_replay_filter; + bool goptimize_chan_avoid_event; + bool enable_go_cts2self_for_sta; + 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 sta_prefer_80MHz_over_160MHz; + uint8_t sap_max_inactivity_override; + bool fw_timeout_crash; + /* beacon count before channel switch */ + uint8_t sap_chanswitch_beacon_cnt; + uint8_t sap_chanswitch_mode; + uint32_t rx_wakelock_timeout; + uint32_t max_sched_scan_plan_interval; + uint32_t max_sched_scan_plan_iterations; +#ifdef WLAN_FEATURE_WOW_PULSE + bool wow_pulse_support; + uint8_t wow_pulse_pin; + uint16_t wow_pulse_interval_high; + uint16_t wow_pulse_interval_low; +#endif + enum hdd_wext_control private_wext_control; + bool sap_internal_restart; + enum restart_beaconing_on_ch_avoid_rule + restart_beaconing_on_chan_avoid_event; + uint8_t is_per_roam_enabled; + uint32_t per_roam_high_rate_threshold; + uint32_t per_roam_low_rate_threshold; + uint32_t per_roam_th_percent; + uint32_t per_roam_rest_time; + uint32_t per_roam_mon_time; + uint32_t min_candidate_rssi; + enum active_apf_mode active_uc_apf_mode; + enum active_apf_mode active_mc_bc_apf_mode; + bool enable_bcast_probe_rsp; + uint8_t he_dynamic_frag_support; +#ifdef WLAN_FEATURE_11AX + bool enable_ul_mimo; + bool enable_ul_ofdma; + uint32_t he_sta_obsspd; +#endif +#ifdef WLAN_SUPPORT_TWT + bool enable_twt; + uint32_t twt_congestion_timeout; +#endif + uint32_t arp_ac_category; + bool ani_enabled; + bool qcn_ie_support; + bool tx_orphan_enable; + + bool probe_req_ie_whitelist; + /* probe request bit map ies */ + uint32_t probe_req_ie_bitmap_0; + uint32_t probe_req_ie_bitmap_1; + uint32_t probe_req_ie_bitmap_2; + uint32_t probe_req_ie_bitmap_3; + uint32_t probe_req_ie_bitmap_4; + uint32_t probe_req_ie_bitmap_5; + uint32_t probe_req_ie_bitmap_6; + uint32_t probe_req_ie_bitmap_7; + /* Probe Request multiple vendor OUIs */ + uint8_t probe_req_ouis[MAX_PRB_REQ_VENDOR_OUI_INI_LEN]; + uint32_t no_of_probe_req_ouis; + uint32_t probe_req_voui[MAX_PROBE_REQ_OUIS]; + + uint32_t timer_multiplier; + uint8_t fils_max_chan_guard_time; + uint8_t scan_backoff_multiplier; + bool mawc_nlo_enabled; + uint32_t mawc_nlo_exp_backoff_ratio; + uint32_t mawc_nlo_init_scan_interval; + uint32_t mawc_nlo_max_scan_interval; + enum hdd_external_acs_policy external_acs_policy; + /* threshold of packet drops at which FW initiates disconnect */ + uint16_t pkt_err_disconn_th; + enum force_1x1_type is_force_1x1_enable; + uint8_t enable_rts_sifsbursting; + uint8_t max_mpdus_inampdu; + uint16_t sap_max_mcs_txdata; + enum pmo_auto_pwr_detect_failure_mode auto_pwr_save_fail_mode; + uint16_t num_11b_tx_chains; + uint16_t num_11ag_tx_chains; + uint8_t ito_repeat_count; + /* LCA(Last connected AP) disallow configs */ + uint32_t disallow_duration; + uint32_t rssi_channel_penalization; + uint32_t num_disallowed_aps; + bool oce_sta_enabled; + bool oce_sap_enabled; + bool enable_11d_in_world_mode; + /* 5G preference parameters for boosting RSSI */ + bool enable_5g_band_pref; + int8_t rssi_boost_threshold_5g; + uint8_t rssi_boost_factor_5g; + uint8_t max_rssi_boost_5g; + /* 5G preference parameters for dropping RSSI*/ + int8_t rssi_penalize_threshold_5g; + uint8_t rssi_penalize_factor_5g; + uint8_t max_rssi_penalize_5g; + bool enable_lprx; + uint8_t upper_brssi_thresh; + uint8_t lower_brssi_thresh; + bool enable_dtim_1chrx; + int8_t rssi_thresh_offset_5g; + bool is_ndi_mac_randomized; + uint32_t scan_11d_interval; + bool chan_switch_hostapd_rate_enabled; + bool is_bssid_hint_priority; + 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; + uint32_t bandwidth_weight_per_index; + uint32_t nss_weight_per_index; + uint32_t band_weight_per_index; + 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; + uint8_t num_esp_qbss_slots; + uint32_t esp_qbss_score_slots3_to_0; + uint32_t esp_qbss_score_slots7_to_4; + uint32_t esp_qbss_score_slots11_to_8; + uint32_t esp_qbss_score_slots15_to_12; + uint8_t num_oce_wan_slots; + uint32_t oce_wan_score_slots3_to_0; + uint32_t oce_wan_score_slots7_to_4; + uint32_t oce_wan_score_slots11_to_8; + uint32_t oce_wan_score_slots15_to_12; + bool enable_scoring_for_roam; + bool force_rsne_override; + bool is_fils_enabled; + uint16_t wlm_latency_enable; + uint16_t wlm_latency_level; + uint32_t wlm_latency_flags_normal; + uint32_t wlm_latency_flags_moderate; + uint32_t wlm_latency_flags_low; + uint32_t wlm_latency_flags_ultralow; + /* mbo related thresholds */ + 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; + uint8_t packet_filters_bitmap; + uint8_t enable_phy_reg_retention; + uint8_t dfs_beacon_tx_enhanced; + uint16_t reduced_beacon_interval; + bool rssi_assoc_reject_enabled; + bool oce_probe_req_rate_enabled; + bool oce_probe_resp_rate_enabled; + bool oce_beacon_rate_enabled; + bool probe_req_deferral_enabled; + bool fils_discovery_sap_enabled; + bool esp_for_roam_enabled; + uint8_t tx_chain_mask_2g; + uint8_t rx_chain_mask_2g; + uint8_t tx_chain_mask_5g; + uint8_t rx_chain_mask_5g; + uint32_t btm_offload_config; +#ifdef WLAN_FEATURE_SAE + bool is_sae_enabled; +#endif + uint32_t btm_solicited_timeout; + uint32_t btm_max_attempt_cnt; + uint32_t btm_sticky_time; + bool gcmp_enabled; + bool is_11k_offload_supported; + uint32_t offload_11k_enable_bitmask; + uint32_t neighbor_report_offload_params_bitmask; + uint32_t neighbor_report_offload_time_offset; + uint32_t neighbor_report_offload_low_rssi_offset; + uint32_t neighbor_report_offload_bmiss_count_trigger; + uint32_t neighbor_report_offload_per_threshold_offset; + uint32_t neighbor_report_offload_cache_timeout; + uint32_t neighbor_report_offload_max_req_cap; + bool action_oui_enable; + uint8_t action_oui_str[ACTION_OUI_MAXIMUM_ID][ACTION_OUI_MAX_STR_LEN]; + uint16_t wmi_wq_watchdog_timeout; + bool enable_dtim_selection_diversity; + uint32_t channel_select_logic_conc; + bool enable_bt_chain_separation; + uint8_t enable_tx_sch_delay; + uint32_t enable_secondary_rate; + HDD_GREEN_AP_CFG_FIELDS + bool is_unit_test_framework_enabled; + bool enable_ftopen; + bool enable_rtt_mac_randomization; + bool roam_force_rssi_trigger; + uint8_t set_btc_mode; + uint8_t set_antenna_isolation; + uint8_t set_max_tx_power_for_btc; + int16_t set_wlan_low_rssi_threshold; + int16_t set_bt_low_rssi_threshold; + int16_t set_bt_interference_low_ll; + int16_t set_bt_interference_low_ul; + int16_t set_bt_interference_medium_ll; + int16_t set_bt_interference_medium_ul; + int16_t set_bt_interference_high_ll; + int16_t set_bt_interference_high_ul; +#ifdef FEATURE_MPTA_HELPER + bool set_mpta_helper_enable; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint32_t roam_preauth_retry_count; + uint32_t roam_preauth_no_ack_timeout; +#endif + uint32_t num_tx_chains_2g; + uint32_t num_tx_chains_5g; + uint32_t num_rx_chains_2g; + uint32_t num_rx_chains_5g; + uint32_t tx_nss_2g; + uint32_t tx_nss_5g; + uint32_t rx_nss_2g; + uint32_t rx_nss_5g; + uint32_t num_tx_chains_11b; + uint32_t num_tx_chains_11g; + uint32_t num_tx_chains_11a; + bool disable_tx_mrc_2g; + bool disable_rx_mrc_2g; + bool disable_tx_mrc_5g; + bool disable_rx_mrc_5g; + bool mac_provision; + uint32_t provisioned_intf_pool; + uint32_t derived_intf_pool; + bool enable_peer_unmap_conf_support; + uint8_t enable_rtt_support; + + uint32_t roam_score_delta; + uint32_t roam_score_delta_bitmap; + bool prefer_btm_query; + bool btm_abridge_config; + uint32_t btm_validity_timer; + uint32_t btm_disassoc_timer_threshold; + bool enable_bss_load_roam_trigger; + uint32_t bss_load_threshold; + uint32_t bss_load_sample_time; + + bool enable_beacon_reception_stats; +}; + +#define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) +#define VAR_SIZE(_Struct, _Var) (sizeof(((_Struct *)0)->_Var)) + +#define VAR_FLAGS_NONE (0) + +/* bit 0 is Required or Optional */ +#define VAR_FLAGS_REQUIRED (1 << 0) +#define VAR_FLAGS_OPTIONAL (0 << 0) + +/* + * bit 1 tells if range checking is required. + * If less than MIN, assume MIN. + * If greater than MAX, assume MAX. + */ +#define VAR_FLAGS_RANGE_CHECK (1 << 1) +#define VAR_FLAGS_RANGE_CHECK_ASSUME_MINMAX (VAR_FLAGS_RANGE_CHECK) + +/* + * bit 2 is range checking that assumes the DEFAULT value + * If less than MIN, assume DEFAULT, + * If greater than MAX, assume DEFAULT. + */ +#define VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT (1 << 2) + +/* + * Bit 3 indicates that the config item can be modified dynamicially + * on a running system + */ +#define VAR_FLAGS_DYNAMIC_CFG (1 << 3) + +enum wlan_parameter_type { + WLAN_PARAM_Integer, + WLAN_PARAM_SignedInteger, + WLAN_PARAM_HexInteger, + WLAN_PARAM_String, + WLAN_PARAM_MacAddr, +}; + +#define REG_VARIABLE(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default, _Min, _Max) \ + { \ + (_Name), \ + (_Type), \ + (_Flags), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (_Default), \ + (_Min), \ + (_Max), \ + NULL, \ + 0 \ + } + +#define REG_DYNAMIC_VARIABLE(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default, _Min, _Max, \ + _CBFunc, _CBParam) \ + { \ + (_Name), \ + (_Type), \ + (VAR_FLAGS_DYNAMIC_CFG | (_Flags)), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (_Default), \ + (_Min), \ + (_Max), \ + (_CBFunc), \ + (_CBParam) \ + } + +#define REG_VARIABLE_STRING(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default) \ + { \ + (_Name), \ + (_Type), \ + (_Flags), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (unsigned long)(_Default), \ + 0, \ + 0, \ + NULL, \ + 0 \ + } + +struct reg_table_entry { + char *RegName; /* variable name in the qcom_cfg.ini file */ + enum wlan_parameter_type RegType; /* variable type in hdd_config struct */ + unsigned long Flags; /* Specify optional parms and if RangeCheck is performed */ + unsigned short VarOffset; /* offset to field from the base address of the structure */ + unsigned short VarSize; /* size (in bytes) of the field */ + unsigned long VarDefault; /* default value to use */ + unsigned long VarMin; /* minimum value, for range checking */ + unsigned long VarMax; /* maximum value, for range checking */ + /* Dynamic modification notifier */ + void (*pfnDynamicnotify)(struct hdd_context *hdd_ctx, + unsigned long notifyId); + unsigned long notifyId; /* Dynamic modification identifier */ +}; + +/** + * hdd_to_csr_wmm_mode() - Utility function to convert HDD to CSR WMM mode + * + * @enum hdd_wmm_user_mode - hdd WMM user mode + * + * Return: CSR WMM mode + */ +eCsrRoamWmmUserModeType hdd_to_csr_wmm_mode(enum hdd_wmm_user_mode mode); + +/* Function declarations and documenation */ +QDF_STATUS hdd_parse_config_ini(struct hdd_context *hdd_ctx); + +/** + * hdd_validate_prb_req_ie_bitmap - validates user input for ie bit map + * @hdd_ctx: the pointer to hdd context + * + * This function checks whether user has entered valid probe request + * ie bitmap and also verifies vendor ouis if vendor specific ie is set + * + * Return: status of verification + * true - valid input + * false - invalid input + */ +bool hdd_validate_prb_req_ie_bitmap(struct hdd_context *hdd_ctx); + +/** + * hdd_parse_probe_req_ouis - form ouis from ini gProbeReqOUIs + * @hdd_ctx: the pointer to hdd context + * + * 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: status of parsing + * 0 - success + * negative value - failure + */ +int hdd_parse_probe_req_ouis(struct hdd_context *hdd_ctx); + +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); +QDF_STATUS hdd_cfg_get_global_config(struct hdd_context *hdd_ctx, char *pBuf, + int buflen); + +eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(enum hdd_dot11_mode dot11Mode); +QDF_STATUS hdd_execute_global_config_command(struct hdd_context *hdd_ctx, + char *command); + +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(struct hdd_context *hdd_ctx); + +QDF_STATUS hdd_update_nss(struct hdd_adapter *adapter, uint8_t nss); + +/** + * hdd_dfs_indicate_radar() - Block tx as radar found on the channel + * @hdd_ctxt: 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); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_conc_ut.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_conc_ut.h new file mode 100644 index 0000000000000000000000000000000000000000..c1cc042da67fb2ef6b7eced595caaaaf1902fe22 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_conc_ut.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 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 __WLAN_HDD_CONC_UT_H +#define __WLAN_HDD_CONC_UT_H + +/* Include files */ + +#include "wlan_hdd_main.h" +#include "wlan_policy_mgr_api.h" +#ifdef MPC_UT_FRAMEWORK +void clean_report(struct hdd_context *hdd_ctx); +void fill_report(struct hdd_context *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum policy_mgr_pcl_type pcl_type, char *reason, + uint8_t *pcl); +void print_report(struct hdd_context *hdd_ctx); +void wlan_hdd_one_connection_scenario(struct hdd_context *hdd_ctx); +void wlan_hdd_two_connections_scenario(struct hdd_context *hdd_ctx, + uint8_t first_chnl, enum policy_mgr_chain_mode first_chain_mask); +void wlan_hdd_three_connections_scenario(struct hdd_context *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum policy_mgr_chain_mode chain_mask, uint8_t use_same_mac); +#else +static inline +void clean_report(struct hdd_context *hdd_ctx) +{ +} + +static inline +void fill_report(struct hdd_context *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum policy_mgr_pcl_type pcl_type, char *reason, + uint8_t *pcl) +{ +} + +static inline +void print_report(struct hdd_context *hdd_ctx) +{ +} + +static inline +void wlan_hdd_one_connection_scenario(struct hdd_context *hdd_ctx) +{ +} + +static inline +void wlan_hdd_two_connections_scenario(struct hdd_context *hdd_ctx, + uint8_t first_chnl, enum policy_mgr_chain_mode first_chain_mask) +{ +} + +static inline +void wlan_hdd_three_connections_scenario(struct hdd_context *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum policy_mgr_chain_mode chain_mask, uint8_t use_same_mac) +{ +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_data_stall_detection.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_data_stall_detection.h new file mode 100644 index 0000000000000000000000000000000000000000..4104ba58cc735710144e4dc2d7d3c014d821bf2b --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h new file mode 100644 index 0000000000000000000000000000000000000000..daa4795e581fa9c875795f95d97b32f42cc47172 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h @@ -0,0 +1,155 @@ +/* + * 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. + */ + +#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_CONNECT_INFO: connect_info file id + * @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_CONNECT_INFO = 0, + HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO = 1, + HDD_DEBUFS_FILE_ID_OFFLOAD_INFO = 2, + + 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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_coex.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_coex.h new file mode 100644 index 0000000000000000000000000000000000000000..5a6bfed8829dde75ba9138a7de0128e8dcff7320 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_csr.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_csr.h new file mode 100644 index 0000000000000000000000000000000000000000..8d4b36b0e6008932c380baed6bd42fcbda059e30 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_csr.h @@ -0,0 +1,213 @@ +/* + * 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. + */ + +/** + * 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_CONNECT_INFO_BUF_SIZE (4 * 1024) +#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 + * @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_connect_info() - API to get connect info + * into user buffer + * @buf: output buffer to hold connect info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +ssize_t +wlan_hdd_debugfs_update_connect_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len); + +/** + * wlan_hdd_debugfs_update_filters_info() - API to get offload info + * into user buffer + * @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 + * @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 +/** + * wlan_hdd_debugfs_csr_init() - Create wifi diagnostic debugfs files + * @adapter: pointer to adapter for which debugfs files are to be created + * + * Return: None + */ +static inline 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 + */ +static inline 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 + */ +static inline ssize_t +wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len) +{ + return 0; +} + +/** + * wlan_hdd_debugfs_update_connect_info() - API to get connect info + * into user buffer + * @buf: output buffer to hold connect info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +static inline ssize_t +wlan_hdd_debugfs_update_connect_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len) +{ + return 0; +} + +/** + * wlan_hdd_debugfs_update_filters_info() - API to get offload info + * into user buffer + * @buf: output buffer to hold offload info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +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; +} + +/** + * wlan_hdd_debugfs_update_roam_stats() - API to get roam scan stats info + * into user buffer + * @buf: output buffer to hold roam scan stats info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_llstat.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_llstat.h new file mode 100644 index 0000000000000000000000000000000000000000..8b7b04eb2eace5f12e6a1c18de2257e2e6afb599 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_llstat.h @@ -0,0 +1,107 @@ +/* + * 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: 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 + +#define DEBUGFS_LLSTATS_BUF_SIZE 12288 +#define DEBUGFS_LLSTATS_REQID 4294967295UL +#define DEBUGFS_LLSTATS_REQMASK 0x7 + +#include + +#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_link_layer_process_iface_stats() - This function is called after + * @adapter: Pointer to device 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 hdd_adapter *adapter, + 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 hdd_adapter *adapter, + 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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h new file mode 100644 index 0000000000000000000000000000000000000000..d1cc09d82a050655d0a9e0a02a91b05eafb88c4f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 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 __WLAN_HDD_DRIVER_OPS_H__ +#define __WLAN_HDD_DRIVER_OPS_H__ + +#include "hif.h" + +struct hdd_context; + +/** + * 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 + * + * 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(void); + +/** + * 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); + +#endif /* __WLAN_HDD_DRIVER_OPS_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h new file mode 100644 index 0000000000000000000000000000000000000000..1c71e01d075f1f16ac0f3ca13980bad1c7abc488 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h new file mode 100644 index 0000000000000000000000000000000000000000..d72dd88170c308788f27ed73d421828df3aee6a9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#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, + struct ifreq *ifr); +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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_he.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_he.h new file mode 100644 index 0000000000000000000000000000000000000000..79f4e8ca046c047742fe378dabd9e17ed5da598a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_he.h @@ -0,0 +1,175 @@ +/* + * 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 : 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_RU_COUNT - to get RU count, + * @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, +}; + +/** + * hdd_update_tgt_he_cap() - Update HE related capabilities + * @hdd_ctx: HDD context + * @he_cap: Target HE 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_he_print_ini_config()- Print 11AX(HE) specific INI configuration + * @hdd_ctx: handle to hdd context + * + * Return: None + */ +void hdd_he_print_ini_config(struct hdd_context *hdd_ctx); + +/** + * 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); + +/** + * hdd_he_set_sme_config() - set HE related SME config param + * @sme_config: pointer to SME config + * @config: pointer to INI config + * + * Return: None + */ +void hdd_he_set_sme_config(tSmeConfigParams *sme_config, + struct hdd_config *config); + +/** + * 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); +#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 \ +}, + +#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 void hdd_he_print_ini_config(struct hdd_context *hdd_ctx) +{ +} + +static inline int hdd_update_he_cap_in_cfg(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline void hdd_he_set_sme_config(tSmeConfigParams *sme_config, + struct hdd_config *config) +{ +} + +/* dummy definition */ +#define FEATURE_11AX_VENDOR_COMMANDS + +#endif +#endif /* if !defined(WLAN_HDD_HE_H)*/ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h new file mode 100644 index 0000000000000000000000000000000000000000..b1a30dcd4f8290560e3806abc13cd76fe77c0a15 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h @@ -0,0 +1,59 @@ +/* + * 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_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[SIR_IPV4_ADDR_LEN]; + uint8_t hostIpv6Addr[SIR_MAC_IPV6_ADDR_LEN]; + } 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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h new file mode 100644 index 0000000000000000000000000000000000000000..1c1c90a0e853a318ca3e45ac06cb07af7ade6fec --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h new file mode 100644 index 0000000000000000000000000000000000000000..459449bcae5cc711f0dbfdd571749336fb3b1649 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h @@ -0,0 +1,79 @@ +/* + * 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 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_tx_flow_info() - To set TX flow info if IPA is + * enabled + * + * This routine is called to set TX flow info if IPA is enabled + * + * Return: None + */ +void hdd_ipa_set_tx_flow_info(void); + +/** + * 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); + +#else +static inline +void hdd_ipa_send_nbuf_to_network(qdf_nbuf_t skb, qdf_netdev_t dev) +{ +} + +static inline void hdd_ipa_set_tx_flow_info(void) +{ +} + +static inline void hdd_ipa_set_mcc_mode(bool mcc_mode) +{ +} + +#endif +#endif /* HDD_IPA_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_lro.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_lro.h new file mode 100644 index 0000000000000000000000000000000000000000..a9eef0b610165cdf517ee07466afd5852ea5d04e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_lro.h @@ -0,0 +1,76 @@ +/* + * 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 __WLAN_HDD_LRO_H__ +#define __WLAN_HDD_LRO_H__ +/** + * DOC: wlan_hdd_lro.h + * + * WLAN LRO interface module headers + */ + +struct hdd_context; + +#if defined(FEATURE_LRO) +/** + * hdd_lro_rx() - Handle Rx procesing via LRO + * @adapter: pointer to adapter context + * @skb: pointer to sk_buff + * + * Return: QDF_STATUS_SUCCESS if processed via LRO or non zero return code + */ +QDF_STATUS hdd_lro_rx(struct hdd_adapter *adapter, struct sk_buff *skb); + +void hdd_lro_display_stats(struct hdd_context *hdd_ctx); + +/** + * hdd_lro_set_reset() - vendor command for Disable/Enable LRO + * @hdd_ctx: hdd context + * @hdd_adapter_t: adapter + * @enable_flag: enable or disable LRO. + * + * Return: none + */ +QDF_STATUS hdd_lro_set_reset(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t enable_flag); + +#else +static inline int hdd_lro_init(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline QDF_STATUS hdd_lro_rx(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void hdd_lro_display_stats(struct hdd_context *hdd_ctx) +{ +} + +static inline QDF_STATUS hdd_lro_set_reset(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t enable_flag) +{ + return 0; +} +#endif /* FEATURE_LRO */ +#endif /* __WLAN_HDD_LRO_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h new file mode 100644 index 0000000000000000000000000000000000000000..d96b376b4ff76bb1e99296b0be713b8747a27fec --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h @@ -0,0 +1,3703 @@ +/* + * 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. + */ + +#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 "sir_mac_prot_def.h" +#include "csr_api.h" +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#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 +#include "cdp_txrx_flow_ctrl_legacy.h" +#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_nud_tracking.h" +#include "wlan_hdd_twt.h" +#include "wma_sar_public_structs.h" + +/* + * Preprocessor definitions and constants + */ + +#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 */ + +/** Number of Tx Queues */ +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +#define NUM_TX_QUEUES 5 +#else +#define NUM_TX_QUEUES 4 +#endif + +/* + * 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 + +/** Length of the TX queue for the netdev */ +#define HDD_NETDEV_TX_QUEUE_LEN (3000) + +/** Hdd Tx Time out value */ +#ifdef LIBRA_LINUX_PC +#define HDD_TX_TIMEOUT (8000) +#else +#define HDD_TX_TIMEOUT msecs_to_jiffies(5000) +#endif + +#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 + +/** + * enum hdd_adapter_flags - event bitmap flags registered net device + * @NET_DEVICE_REGISTERED: Adapter is registered with the kernel + * @SME_SESSION_OPENED: Firmware vdev has been created + * @INIT_TX_RX_SUCCESS: Adapter datapath is initialized + * @WMM_INIT_DONE: Adapter is initialized + * @SOFTAP_BSS_STARTED: Software Access Point (SAP) is running + * @DEVICE_IFACE_OPENED: Adapter has been "opened" via the kernel + * @ACS_PENDING: Auto Channel Selection (ACS) is pending + * @SOFTAP_INIT_DONE: Software Access Point (SAP) is initialized + * @VENDOR_ACS_RESPONSE_PENDING: Waiting for event for vendor acs + * @DOWN_DURING_SSR: Mark interface is down during SSR + */ +enum hdd_adapter_flags { + NET_DEVICE_REGISTERED, + SME_SESSION_OPENED, + INIT_TX_RX_SUCCESS, + WMM_INIT_DONE, + SOFTAP_BSS_STARTED, + DEVICE_IFACE_OPENED, + ACS_PENDING, + SOFTAP_INIT_DONE, + VENDOR_ACS_RESPONSE_PENDING, + DOWN_DURING_SSR, +}; + +/** + * enum hdd_driver_flags - HDD global event bitmap flags + * @ACS_IN_PROGRESS: Auto Channel Selection (ACS) in progress + */ +enum hdd_driver_flags { + ACS_IN_PROGRESS, +}; + +/** Maximum time(ms)to wait for disconnect to complete **/ +/* This value should be larger than the timeout used by WMA to wait for + * stop vdev response from FW + */ +#ifdef QCA_WIFI_3_0_EMU +#define WLAN_WAIT_TIME_DISCONNECT 7000 +#else +#define WLAN_WAIT_TIME_DISCONNECT 7000 +#endif +#define WLAN_WAIT_DISCONNECT_ALREADY_IN_PROGRESS 1000 +#define WLAN_WAIT_TIME_STOP_ROAM 4000 +#define WLAN_WAIT_TIME_STATS 800 +#define WLAN_WAIT_TIME_POWER 800 +#define WLAN_WAIT_TIME_COUNTRY 1000 +#define WLAN_WAIT_TIME_LINK_STATUS 800 +#define WLAN_WAIT_TIME_POWER_STATS 800 + +#define WLAN_WAIT_TIME_ABORTSCAN 2000 + +/** 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 + +/** 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_TDLS_MGMT 11000 + +/* Scan Req Timeout */ +#define WLAN_WAIT_TIME_SCAN_REQ 100 + +#define WLAN_WAIT_TIME_ANTENNA_MODE_REQ 3000 +#define WLAN_WAIT_TIME_SET_DUAL_MAC_CFG 1500 + +#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 MAX_CFG_STRING_LEN 255 + +/* Maximum time(ms) to wait for external acs response */ +#define WLAN_VENDOR_ACS_WAIT_TIME 1000 + +#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +/** Mac Address string **/ +#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#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) + +/** Maximum Length of WPA/RSN IE */ +#define MAX_WPA_RSN_IE_LEN 255 + +#define WPS_OUI_TYPE "\x00\x50\xf2\x04" +#define WPS_OUI_TYPE_SIZE 4 + +#define SS_OUI_TYPE "\x00\x16\x32" +#define SS_OUI_TYPE_SIZE 3 + +#define P2P_OUI_TYPE "\x50\x6f\x9a\x09" +#define P2P_OUI_TYPE_SIZE 4 + +#define HS20_OUI_TYPE "\x50\x6f\x9a\x10" +#define HS20_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 wlan_hdd_get_p2p_ie_ptr(ie, ie_len) \ + wlan_get_vendor_ie_ptr_from_oui(P2P_OUI_TYPE, P2P_OUI_TYPE_SIZE, \ + ie, ie_len) + +#ifdef WLAN_FEATURE_WFD +#define wlan_hdd_get_wfd_ie_ptr(ie, ie_len) \ + wlan_get_vendor_ie_ptr_from_oui(WFD_OUI_TYPE, WFD_OUI_TYPE_SIZE, \ + ie, ie_len) +#endif + +#define wlan_hdd_get_mbo_ie_ptr(ie, ie_len) \ + wlan_get_vendor_ie_ptr_from_oui(MBO_OUI_TYPE, MBO_OUI_TYPE_SIZE, \ + ie, ie_len) + +#define WLAN_CHIP_VERSION "WCNSS" + +#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_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() hdd_debug("enter") +#define hdd_enter_dev(dev) hdd_debug("enter(%s)", (dev)->name) +#define hdd_exit() hdd_debug("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 4 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET 24 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET 24 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET 30 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET 0 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET 1 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_OFFSET 2 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_TYPE_OFFSET 5 +#define WLAN_HDD_VENDOR_SPECIFIC_ACTION 0x09 +#define WLAN_HDD_WFA_OUI 0x506F9A +#define WLAN_HDD_WFA_P2P_OUI_TYPE 0x09 +#define WLAN_HDD_P2P_SOCIAL_CHANNELS 3 +#define WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN 1 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET 6 + +#define WLAN_HDD_IS_SOCIAL_CHANNEL(center_freq) \ + (((center_freq) == 2412) || ((center_freq) == 2437) || \ + ((center_freq) == 2462)) + +#define WLAN_HDD_CHANNEL_IN_UNII_1_BAND(center_freq) \ + (((center_freq) == 5180) || ((center_freq) == 5200) \ + || ((center_freq) == 5220) || ((center_freq) == 5240)) + +#ifdef WLAN_FEATURE_11W +#define WLAN_HDD_SA_QUERY_ACTION_FRAME 8 +#endif + +#define WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP 14 +#define WLAN_HDD_TDLS_ACTION_FRAME 12 + +#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 + +#if defined(CONFIG_HL_SUPPORT) +#define HDD_MOD_EXIT_SSR_MAX_RETRIES 200 +#else +#define HDD_MOD_EXIT_SSR_MAX_RETRIES 75 +#endif + +#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 */ + +#define HDD_ENABLE_SIFS_BURST_DEFAULT (1) +/* 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" + +/* session ID invalid */ +#define HDD_SESSION_ID_INVALID 0xFF + +#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 + +/* + * Generic asynchronous request/response support + * + * Many of the APIs supported by HDD require a call to SME to + * perform an action or to retrieve some data. In most cases SME + * performs the operation asynchronously, and will execute a provided + * callback function when the request has completed. In order to + * synchronize this the HDD API allocates a context which is then + * passed to SME, and which is then, in turn, passed back to the + * callback function when the operation completes. The callback + * function then sets a completion variable inside the context which + * the HDD API is waiting on. In an ideal world the HDD API would + * wait forever (or at least for a long time) for the response to be + * received and for the completion variable to be set. However in + * most cases these HDD APIs are being invoked in the context of a + * user space thread which has invoked either a cfg80211 API or a + * wireless extensions ioctl and which has taken the kernel rtnl_lock. + * Since this lock is used to synchronize many of the kernel tasks, we + * do not want to hold it for a long time. In addition we do not want + * to block user space threads (such as the wpa supplicant's main + * thread) for an extended time. Therefore we only block for a short + * time waiting for the response before we timeout. This means that + * it is possible for the HDD API to timeout, and for the callback to + * be invoked afterwards. In order for the callback function to + * determine if the HDD API is still waiting, a magic value is also + * stored in the shared context. Only if the context has a valid + * magic will the callback routine do any work. In order to further + * synchronize these activities a spinlock is used so that if any HDD + * API timeout coincides with its callback, the operations of the two + * threads will be serialized. + */ + +extern spinlock_t hdd_context_lock; +extern struct mutex hdd_init_deinit_lock; + +/* 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) + +/** + * enum hdd_auth_key_mgmt - auth key mgmt protocols + * @HDD_AUTH_KEY_MGMT_802_1X: 802.1x + * @HDD_AUTH_KEY_MGMT_PSK: PSK + * @HDD_AUTH_KEY_MGMT_CCKM: CCKM + */ +enum hdd_auth_key_mgmt { + HDD_AUTH_KEY_MGMT_802_1X = BIT(0), + HDD_AUTH_KEY_MGMT_PSK = BIT(1), + HDD_AUTH_KEY_MGMT_CCKM = BIT(2) +}; + +/** + * struct hdd_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 + * @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 hdd_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; + uint64_t qtime; +}; + +struct hdd_tx_rx_stats { + /* start_xmit stats */ + __u32 tx_called; + __u32 tx_dropped; + __u32 tx_orphaned; + __u32 tx_classified_ac[NUM_TX_QUEUES]; + __u32 tx_dropped_ac[NUM_TX_QUEUES]; + + /* rx stats */ + __u32 rx_packets[NUM_CPUS]; + __u32 rx_dropped[NUM_CPUS]; + __u32 rx_delivered[NUM_CPUS]; + __u32 rx_refused[NUM_CPUS]; + qdf_atomic_t rx_usolict_arp_n_mcast_drp; + + /* 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 jiffies_last_txtimeout; +}; + +#ifdef WLAN_FEATURE_11W +/** + * 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; +}; +#endif + +/** + * struct hdd_arp_stats_s - 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 hdd_arp_stats_s { + 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 hdd_dns_stats_s - 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 hdd_dns_stats_s { + 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 hdd_tcp_stats_s - 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 + * @tx_tcp_syn_ack_cnt: no of tcp syn acked by FW + * @tx_tcp_syn_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 hdd_tcp_stats_s { + 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 hdd_icmpv4_stats_s - 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 hdd_icmpv4_stats_s { + 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 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; +}; + +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_arp_stats_s hdd_arp_stats; + struct hdd_dns_stats_s hdd_dns_stats; + struct hdd_tcp_stats_s hdd_tcp_stats; + struct hdd_icmpv4_stats_s hdd_icmpv4_stats; + struct hdd_peer_stats peer_stats; +#ifdef WLAN_FEATURE_11W + struct hdd_pmf_stats hdd_pmf_stats; +#endif +}; + +/** + * 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 + * @defer_key_complete: Should key complete be deferred? + * + */ +struct hdd_roaming_info { + tSirMacAddr bssid; + tSirMacAddr peer_mac; + uint32_t roam_id; + eRoamCmdStatus roam_status; + bool defer_key_complete; + +}; + +#ifdef FEATURE_WLAN_WAPI +/* Define WAPI macros for Length, BKID count etc*/ +#define MAC_ADDR_LEN 6 +#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 WLAN_EID_WAPI 68 +#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 action_pkt_buffer { + uint8_t *frame_ptr; + uint32_t frame_length; + uint16_t freq; +}; + +/** + * struct hdd_scan_req - Scan Request entry + * @node : List entry element + * @adapter: Adapter address + * @scan_request: scan request holder + * @scan_id: scan identifier used across host layers which is generated at WMI + * @cookie: scan request identifier sent to userspace + * @source: scan request originator (NL/Vendor scan) + * @timestamp: scan request timestamp + * + * Scan request linked list element + */ +struct hdd_scan_req { + qdf_list_node_t node; + struct hdd_adapter *adapter; + struct cfg80211_scan_request *scan_request; + uint32_t scan_id; + uint8_t source; + uint32_t timestamp; + qdf_timer_t hdd_scan_inactivity_timer; + uint32_t scan_req_flags; +}; + +/** + * struct hdd_mon_set_ch_info - Holds monitor mode channel switch params + * @channel: Channel number. + * @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 { + uint8_t channel; + uint8_t cb_mode; + uint32_t channel_width; + eCsrPhyMode phy_mode; +}; + +/** + * struct hdd_station_ctx -- STA-specific information + * @roam_profile: current roaming profile + * @security_ie: WPA or RSN IE used by the @roam_profile + * @assoc_additional_ie: association additional IE used by the @roam_profile + * @wpa_versions: bitmap of supported WPA versions + * @auth_key_mgmt: bitmap of supported auth key mgmt protocols + * @requested_bssid: Specific BSSID to which to connect + * @conn_info: current connection information + * @roam_info: current roaming information + * @ft_carrier_on: is carrier on + * @ibss_sta_generation: current ibss generation. Incremented whenever + * ibss New peer joins and departs the network + * @ibss_enc_key_installed: is the ibss wep/wpa-none encryptions key + * installed? + * @ibss_enc_key: current ibss wep/wpa-none encryption key (if + * @ibss_enc_key_installed is %true) + * @ibss_peer_info: information about the ibss peer + * @hdd_reassoc_scenario: is station in the middle of reassociation? + * @sta_debug_state: STA context debug variable + * @broadcast_staid: STA ID assigned for broadcast frames + * @ch_info: monitor mode channel information + * @ndp_ctx: NAN data path context + * @ap_supports_immediate_power_save: Does the current AP allow our STA + * to immediately go into power save? + */ +struct hdd_station_ctx { + struct csr_roam_profile roam_profile; + uint8_t security_ie[MAX_WPA_RSN_IE_LEN]; + tSirAddie assoc_additional_ie; + enum nl80211_wpa_versions wpa_versions; + enum hdd_auth_key_mgmt auth_key_mgmt; + struct qdf_mac_addr requested_bssid; + struct hdd_connection_info conn_info; + struct hdd_connection_info cache_conn_info; + struct hdd_roaming_info roam_info; + int ft_carrier_on; + int ibss_sta_generation; + bool ibss_enc_key_installed; + tCsrRoamSetKey ibss_enc_key; + tSirPeerInfoRspParams ibss_peer_info; + bool hdd_reassoc_scenario; + int sta_debug_state; + uint8_t broadcast_staid; + struct hdd_mon_set_ch_info ch_info; + bool ap_supports_immediate_power_save; +}; + +/** + * 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_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_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; + uint8_t rate_flags; +}; + +/** + * 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 + * @rx_retries: cumulative retry counts + * @tx_failed: number of failed transmissions + * @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; + int8_t rssi; + struct hdd_rate_info tx_rate; + struct hdd_rate_info rx_rate; +}; + +/** + * struct 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 +}; + +/** + * struct 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 +}; + +/** + * struct hdd_station_info - Per station structure kept in HDD for + * multiple station support for SoftAP + * @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 + * @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 + * @max_phy_rate: Calcuated maximum phy rate based on mode, nss, mcs etc. + * @tx_packets: Packets send to current station + * @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 + * @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 + * @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 of the station + * @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 + * @capability: Capability information of current station + * @support_mode: Max supported mode of a station currently + * connected to sap + */ +struct hdd_station_info { + bool in_use; + uint8_t sta_id; + eStationType sta_type; + struct qdf_mac_addr sta_mac; + 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 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; + 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 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; +}; + +/** + * 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_channel: 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 + * @txrx_stats: TX RX statistics from firmware + * @acs_in_progress: In progress acs flag for an adapter + */ +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; + tCsrRoamSetKey group_key; + tCsrRoamSetKey wep_key[CSR_MAX_NUM_KEY]; + uint8_t wep_def_key_idx; + struct sap_context *sap_context; + tsap_config_t sap_config; + uint8_t operating_channel; + struct hdd_beacon_data *beacon; + qdf_mc_timer_t vendor_acs_timer; + bool vendor_acs_timer_initialized; + enum bss_stop_reason bss_stop_reason; + struct hdd_fw_txrx_stats txrx_stats; + qdf_atomic_t acs_in_progress; +}; + +/** + * 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 + +#ifdef WLAN_FEATURE_PACKET_FILTERING +struct hdd_multicast_addr_list { + uint8_t mc_cnt; + uint8_t addr[WLAN_HDD_MAX_MC_ADDR_LIST][ETH_ALEN]; +}; +#endif + +#define WLAN_HDD_MAX_HISTORY_ENTRY 10 + +/** + * struct hdd_netif_queue_stats - netif queue operation statistics + * @pause_count - pause counter + * @unpause_count - unpause counter + */ +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 + */ +struct hdd_netif_queue_history { + qdf_time_t time; + uint16_t netif_action; + uint16_t netif_reason; + uint32_t pause_map; +}; + +/** + * struct hdd_chan_change_params - channel related information + * @chan: operating channel + * @chan_params: channel parameters + */ +struct hdd_chan_change_params { + uint8_t chan; + 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 + * + * Runtime PM control for underlying activities + */ +struct hdd_runtime_pm_context { + qdf_runtime_lock_t dfs; + qdf_runtime_lock_t connect; +}; + +/** + * struct hdd_connect_pm_context - Runtime PM connect context per adapter + * @connect: Runtime Connect Context + * + * Structure to hold runtime pm connect context for each adapter. + */ +struct hdd_connect_pm_context { + qdf_runtime_lock_t connect; +}; + +/* + * 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; + +/** + * struct hdd_adapter - hdd vdev/net_device context + * @vdev: object manager vdev context + * @vdev_lock: lock to protect vdev context access + * @event_flags: a bitmap of hdd_adapter_flags + */ +struct hdd_adapter { + /* 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 + */ + uint32_t magic; + + /* list node for membership in the adapter list */ + qdf_list_node_t node; + + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + qdf_spinlock_t vdev_lock; + + void *txrx_vdev; + + /** Handle to the network device */ + struct net_device *dev; + + enum QDF_OPMODE device_mode; + + /** IPv4 notifier callback for handling ARP offload on change in IP */ + 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; + + /** ops checks if Opportunistic Power Save is Enable or Not + * ctw stores ctWindow value once we receive Opps command from + * wpa_supplicant then using ctWindow value we need to Enable + * Opportunistic Power Save + */ + uint8_t ops; + uint32_t ctw; + + /** Current MAC Address for the adapter */ + struct qdf_mac_addr mac_addr; + +#ifdef WLAN_NUD_TRACKING + struct hdd_nud_tracking_info nud_tracking; +#endif + bool disconnection_in_progress; + qdf_mutex_t disconnection_status_lock; + unsigned long event_flags; + + /**Device TX/RX statistics*/ + struct net_device_stats stats; + /** HDD statistics*/ + struct hdd_stats hdd_stats; + + /* estimated link speed */ + uint32_t estimated_linkspeed; + + uint8_t session_id; + + /* QDF event for session close */ + qdf_event_t qdf_session_close_event; + + /* QDF event for session open */ + qdf_event_t qdf_session_open_event; + + /* TODO: move these to sta ctx. These may not be used in AP */ + /** completion variable for disconnect callback */ + struct completion disconnect_comp_var; + + struct completion roaming_comp_var; + + /* completion variable for Linkup Event */ + struct completion linkup_event_var; + + /* completion variable for cancel remain on channel Event */ + struct completion cancel_rem_on_chan_var; + + /* completion variable for off channel remain on channel Event */ + struct completion offchannel_tx_event; + /* Completion variable for action frame */ + struct completion tx_action_cnf_event; + /* Completion variable for remain on channel ready */ + struct completion rem_on_chan_ready_event; + + struct completion sta_authorized_event; + + struct completion ibss_peer_info_comp; + + /* Track whether the linkup handling is needed */ + bool is_link_up_service_needed; + + /* WMM Status */ + struct hdd_wmm_status hdd_wmm_status; + + /** Multiple station supports */ + /** Per-station structure */ + spinlock_t sta_info_lock; /* To protect access to station Info */ + struct hdd_station_info sta_info[WLAN_MAX_STA_COUNT]; + struct hdd_station_info cache_sta_info[WLAN_MAX_STA_COUNT]; + + +#ifdef FEATURE_WLAN_WAPI + struct hdd_wapi_info wapi_info; +#endif + + int8_t rssi; + int32_t rssi_on_disconnect; +#ifdef WLAN_FEATURE_LPSS + bool rssi_send; +#endif + + uint8_t snr; + + struct work_struct sap_stop_bss_work; + + union { + struct hdd_station_ctx station; + struct hdd_ap_ctx ap; + } session; + + qdf_atomic_t ch_switch_in_progress; + +#ifdef WLAN_FEATURE_TSF + /* tsf value received from firmware */ + 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 WLAN_FEATURE_TSF_PLUS + /* spin lock for read/write timestamps */ + qdf_spinlock_t host_target_sync_lock; + qdf_mc_timer_t host_target_sync_timer; + uint64_t cur_host_time; + uint64_t last_host_time; + uint64_t last_target_time; + /* to store the count of continuous invalid tstamp-pair */ + int continuous_error_count; + /* to indicate whether tsf_sync has been initialized */ + qdf_atomic_t tsf_sync_ready_flag; +#endif /* WLAN_FEATURE_TSF_PLUS */ +#endif + +#ifdef WLAN_FEATURE_PACKET_FILTERING + struct hdd_multicast_addr_list mc_addr_list; +#endif + uint8_t addr_filter_pattern; + + bool survey_idx; + + struct hdd_scan_info scan_info; + + /* Flag to ensure PSB is configured through framework */ + uint8_t psb_changed; + /* UAPSD psb value configured through framework */ + uint8_t configured_psb; +#ifdef IPA_OFFLOAD + void *ipa_context; +#endif + /* Use delayed work for Sec AP ACS as Pri AP Startup need to complete + * since CSR (PMAC Struct) Config is same for both AP + */ + struct delayed_work acs_pending_work; + + struct work_struct scan_block_work; + qdf_list_t blocked_scan_request_q; + qdf_mutex_t blocked_scan_request_q_lock; +#ifdef MSM_PLATFORM + unsigned long prev_rx_packets; + unsigned long prev_tx_packets; + uint64_t prev_fwd_tx_packets; + uint64_t prev_fwd_rx_packets; + int connection; +#endif +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + qdf_mc_timer_t tx_flow_control_timer; + bool tx_flow_timer_initialized; + unsigned int tx_flow_low_watermark; + unsigned int tx_flow_high_watermark_offset; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + bool offloads_configured; + + /* DSCP to UP QoS Mapping */ + enum sme_qos_wmmuptype dscp_to_up_map[WLAN_HDD_MAX_DSCP + 1]; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + bool is_link_layer_stats_set; +#endif + uint8_t link_status; + + /* variable for temperature in Celsius */ + int temperature; + +#ifdef WLAN_FEATURE_DSRC + /* MAC addresses used for OCB interfaces */ + struct qdf_mac_addr ocb_mac_address[QDF_MAX_CONCURRENCY_PERSONA]; + int ocb_mac_addr_count; +#endif + + /* BITMAP indicating pause reason */ + uint32_t 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]; + ol_txrx_tx_fp tx_fn; + /* debugfs entry */ + struct dentry *debugfs_phy; + /* + * The pre cac channel is saved here and will be used when the SAP's + * channel needs to be moved from the existing 2.4GHz channel. + */ + uint8_t pre_cac_chan; + + /* + * Indicate if HO fails during disconnect so that + * disconnect is not initiated by HDD as its already + * initiated by CSR + */ + bool roam_ho_fail; + struct lfr_firmware_status lfr_fw_status; + bool con_status; + bool dad; + uint8_t active_ac; + 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; + uint32_t mon_chan; + uint32_t mon_bandwidth; + + /* rcpi information */ + 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 */ +}; + +#define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station) +#define WLAN_HDD_GET_AP_CTX_PTR(adapter) (&(adapter)->session.ap) +#define WLAN_HDD_GET_CTX(adapter) ((adapter)->hdd_ctx) +#define WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter) \ + (&(adapter)->session.ap.hostapd_state) +#define WLAN_HDD_GET_SAP_CTX_PTR(adapter) ((adapter)->session.ap.sap_context) + +#ifdef WLAN_FEATURE_NAN_DATAPATH +#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_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_channel: pre defined channel to avoid ACS. + */ +struct acs_dfs_policy { + enum dfs_mode acs_dfs_mode; + uint8_t acs_channel; +}; + +/** + * 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 +}; + +/** + * suspend_resume_stats - Collection of 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]; +}; + +/** + * 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 +}; + +/** + * tos - Type of service requested by the application + * TOS_BK: Back ground traffic + * TOS_BE: Best effort traffic + * TOS_VI: Video traffic + * TOS_VO: Voice traffic + */ +enum tos { + TOS_BK = 0, + TOS_BE = 1, + TOS_VI = 2, + TOS_VO = 3, +}; + +#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_AC 4 +#define HDD_MAX_OFF_CHAN_ENTRIES 2 + +#define HDD_AC_BIT_INDX 0 +#define HDD_DWELL_TIME_INDX 1 + +/** + * 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 + * @channel_num: channel number + * @reg_status: Current regulatory status of the channel + * Enable + * Disable + * DFS + * Invalid + * @wiphy_status: Current wiphy status + */ +struct hdd_cache_channel_info { + uint32_t channel_num; + 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: Dynamicaly 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; +}; + +/** + * 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; +}; + +/** + * struct hdd_context - hdd shared driver and psoc/device context + * @psoc: object manager psoc context + * @pdev: object manager pdev context + * @g_event_flags: a bitmap of hdd_driver_flags + * @dynamic_nss_chains_support: Per vdev dynamic nss chains update capability + * @sar_cmd_params: SAR command params to be configured to the FW + */ +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; /* List of adapters */ + + struct hdd_adapter *sta_to_adapter[HDD_MAX_ADAPTERS]; + + /** Pointer for firmware image data */ + const struct firmware *fw; + + /** Pointer for configuration data */ + const struct firmware *cfg; + + /** Pointer to the parent device */ + struct device *parent_dev; + + /** Config values read from qcom_cfg.ini file */ + struct hdd_config *config; + + /* Completion variable to indicate Mc Thread Suspended */ + struct completion mc_sus_event_var; + + bool is_scheduler_suspended; + +#ifdef QCA_CONFIG_SMP + bool is_ol_rx_thread_suspended; +#endif + + bool hdd_wlan_suspended; + bool suspended; + /* flag to start pktlog after SSR/PDR if previously enabled */ + bool is_pktlog_enabled; + + /* Lock to avoid race condition during start/stop bss */ + struct mutex sap_lock; + +#ifdef FEATURE_OEM_DATA_SUPPORT + /* OEM App registered or not */ + bool oem_app_registered; + + /* OEM App Process ID */ + int32_t oem_pid; +#endif + + /** Concurrency Parameters*/ + 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]; + + /** P2P Device MAC Address for the adapter */ + struct qdf_mac_addr p2p_device_address; + + qdf_wake_lock_t rx_wake_lock; + qdf_wake_lock_t sap_wake_lock; + + void *hdd_ipa; + + /* Flag keeps track of wiphy suspend/resume */ + bool is_wiphy_suspended; + +#ifdef MSM_PLATFORM + /* DDR bus bandwidth compute timer + */ + qdf_timer_t bus_bw_timer; + bool bus_bw_timer_running; + qdf_spinlock_t bus_bw_timer_lock; + struct work_struct bus_bw_work; + int cur_vote_level; + spinlock_t bus_bw_lock; + int cur_rx_level; + uint64_t prev_no_rx_offload_pkts; + uint64_t prev_rx_offload_pkts; + int cur_tx_level; + uint64_t prev_tx; +#endif + + struct completion ready_to_suspend; + /* defining the solution type */ + uint32_t target_type; + + qdf_atomic_t con_mode_flag; + /* defining the firmware version */ + uint32_t target_fw_version; + uint32_t target_fw_vers_ext; + struct hdd_fw_ver_info fw_version_info; + + /* defining the chip/rom version */ + uint32_t target_hw_version; + /* defining the chip/rom revision */ + uint32_t target_hw_revision; + /* chip/rom name */ + char *target_hw_name; + 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 */ + + uint8_t max_intf_count; + uint8_t current_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 + + struct work_struct sap_start_work; + bool is_sap_restart_required; + bool is_sta_connection_pending; + qdf_spinlock_t sap_update_info_lock; + qdf_spinlock_t sta_update_info_lock; + + uint8_t dev_dfs_cac_status; + + bool bt_coex_mode_set; + struct fw_log_info fw_log_settings; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + qdf_mc_timer_t skip_acs_scan_timer; + uint8_t skip_acs_scan_status; + uint8_t *last_acs_channel_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 + + /* Time since boot up to extscan start (in micro seconds) */ + uint64_t ext_scan_start_since_boot; + unsigned long g_event_flags; + 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; + + /* number of rf chains supported by target */ + uint32_t num_rf_chains; + /* Is htTxSTBC supported by target */ + 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; + + uint16_t hdd_txrx_hist_idx; + struct hdd_tx_rx_histogram *hdd_txrx_hist; + + /* + * place to store FTM capab of target. This allows changing of FTM capab + * at runtime and intersecting it with target capab before updating. + */ + uint32_t fine_time_meas_cap_target; + uint32_t rx_high_ind_cnt; + /* For Rx thread non GRO/LRO packet accounting */ + uint64_t no_rx_offload_pkt_cnt; + /* Current number of TX X RX chains being used */ + enum antenna_mode current_antenna_mode; + + /* the radio index assigned by cnss_logger */ + int radio_index; + qdf_work_t sap_pre_cac_work; + bool hbw_requested; + uint32_t last_nil_scan_bug_report_timestamp; + enum RX_OFFLOAD ol_enable; +#ifdef WLAN_FEATURE_NAN_DATAPATH + bool nan_datapath_enabled; +#endif + /* Present state of driver cds modules */ + enum driver_modules_status driver_status; + qdf_delayed_work_t psoc_idle_timeout_work; + /* Interface change lock */ + struct mutex iface_change_lock; + bool rps; + bool dynamic_rps; + bool enable_rxthread; + bool napi_enable; + bool stop_modules_in_progress; + bool start_modules_in_progress; + 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; + bool roaming_in_progress; + struct scan_chan_info *chan_info; + struct mutex chan_info_lock; + /* bit map to set/reset TDLS by different sources */ + 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_session_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 + /* indicate whether tsf has been initialized */ + qdf_atomic_t tsf_ready_flag; + /* indicate whether it's now capturing tsf(updating tstamp-pair) */ + qdf_atomic_t cap_tsf_flag; + /* the context that is capturing tsf */ + struct hdd_adapter *cap_tsf_context; +#endif + uint8_t bt_a2dp_active:1; + uint8_t bt_vo_active:1; + enum band_info curr_band; + bool imps_enabled; + int user_configured_pkt_filter_rules; + bool is_fils_roaming_supported; + QDF_STATUS (*receive_offload_cb)(struct hdd_adapter *, + struct sk_buff *); + qdf_atomic_t vendor_disable_lro_flag; + qdf_atomic_t disable_lro_in_concurrency; + qdf_atomic_t disable_lro_in_low_tput; + bool en_tcp_delack_no_lro; + bool force_rsne_override; + qdf_wake_lock_t monitor_mode_wakelock; + bool lte_coex_ant_share; + 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; +#endif +#ifdef DISABLE_CHANNEL_LIST + struct hdd_cache_channels *original_channels; + qdf_mutex_t cache_channel_lock; +#endif + enum sar_version sar_version; +#ifdef FEATURE_WLAN_APF + bool apf_supported; + uint32_t apf_version; + bool apf_enabled_v2; +#endif + struct hdd_dynamic_mac dynamic_mac_list[QDF_MAX_CONCURRENCY_PERSONA]; + bool dynamic_nss_chains_support; + /* Completion variable to indicate that all pdev cmds are flushed */ + struct completion pdev_cmd_flushed_var; + + 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 wlan_mlme_chain_cfg fw_chain_cfg; + struct sar_limit_cmd_params *sar_cmd_params; +}; + +/** + * struct hdd_vendor_acs_chan_params - vendor acs channel parameters + * @channel_count: channel count + * @channel_list: pointer to channel list + * @pcl_count: pcl list count + * @vendor_pcl_list: pointer to pcl list + * @vendor_weight_list: pointer to pcl weight list + */ +struct hdd_vendor_acs_chan_params { + uint32_t channel_count; + uint8_t *channel_list; + uint32_t pcl_count; + uint8_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_ch: primary channel + * @ht_sec_ch: secondary channel + * @vht_seg0_center_ch: segment0 for vht + * @vht_seg1_center_ch: vht segment 1 + * @chan_width: channel width + */ +struct hdd_vendor_chan_info { + uint8_t band; + uint8_t pri_ch; + uint8_t ht_sec_ch; + uint8_t vht_seg0_center_ch; + uint8_t vht_seg1_center_ch; + 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; +}; + +/* + * @eHDD_DRV_OP_PROBE: Refers to .probe operation + * @eHDD_DRV_OP_REMOVE: Refers to .remove operation + * @eHDD_DRV_OP_SHUTDOWN: Refers to .shutdown operation + * @eHDD_DRV_OP_REINIT: Refers to .reinit operation + * @eHDD_DRV_OP_IFF_UP: Refers to IFF_UP operation + */ +enum { + eHDD_DRV_OP_PROBE = 0, + eHDD_DRV_OP_REMOVE, + eHDD_DRV_OP_SHUTDOWN, + eHDD_DRV_OP_REINIT, + eHDD_DRV_OP_IFF_UP +}; + +/* + * Function declarations and documentation + */ + +int hdd_validate_channel_and_bandwidth(struct hdd_adapter *adapter, + uint32_t chan_number, + enum phy_ch_width chan_bw); + +const char *hdd_device_mode_to_string(uint8_t device_mode); + +QDF_STATUS hdd_get_front_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter); + +QDF_STATUS hdd_get_next_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *current_adapter, + struct hdd_adapter **out_adapter); + +QDF_STATUS hdd_remove_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +QDF_STATUS hdd_remove_front_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter); + +QDF_STATUS hdd_add_adapter_back(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +QDF_STATUS hdd_add_adapter_front(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * hdd_for_each_adapter - adapter iterator macro + * @hdd_ctx: the global HDD context + * @adapter: an hdd_adapter pointer to use as a cursor + */ +#define hdd_for_each_adapter(hdd_ctx, adapter) \ + for (hdd_get_front_adapter(hdd_ctx, &adapter); \ + adapter; \ + hdd_get_next_adapter(hdd_ctx, adapter, &adapter)) + +struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, + uint8_t session_type, + const char *name, tSirMacAddr macAddr, + unsigned char name_assign_type, + bool rtnl_held); +QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held); +QDF_STATUS 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); +struct hdd_adapter *hdd_get_adapter_by_vdev(struct hdd_context *hdd_ctx, + uint32_t vdev_id); +struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx, + tSirMacAddr macAddr); + +/* + * 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); + +int hdd_vdev_create(struct hdd_adapter *adapter, + csr_roam_complete_cb callback, void *ctx); +int hdd_vdev_destroy(struct hdd_adapter *adapter); +int hdd_vdev_ready(struct hdd_adapter *adapter); + +QDF_STATUS hdd_init_station_mode(struct hdd_adapter *adapter); +struct hdd_adapter *hdd_get_adapter(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode); +/* + * hdd_get_device_mode() - Get device mode + * @session_id: Session id + * + * Return: Device mode + */ +enum QDF_OPMODE hdd_get_device_mode(uint32_t session_id); +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); + +enum hdd_adapter_stop_flag_t { + HDD_IN_CAC_WORK_TH_CONTEXT = 0x00000001, +}; + +QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + enum hdd_adapter_stop_flag_t flag); + +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); +uint8_t hdd_get_operating_channel(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); +void crda_regulatory_entry_default(uint8_t *countryCode, int domain_id); +void wlan_hdd_reset_prob_rspies(struct hdd_adapter *adapter); +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); + +void wlan_hdd_cfg80211_update_wiphy_caps(struct wiphy *wiphy); +QDF_STATUS hdd_set_ibss_power_save_params(struct hdd_adapter *adapter); + +/** + * 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_session_id() - ensure the given session Id is valid + * @session_id: the session Id to validate + * + * Return: Errno + */ +#define wlan_hdd_validate_session_id(session_id) \ + __wlan_hdd_validate_session_id(session_id, __func__) + +int __wlan_hdd_validate_session_id(uint8_t session_id, const char *func); + +bool hdd_is_valid_mac_address(const uint8_t *pMacAddr); +QDF_STATUS hdd_issta_p2p_clientconnected(struct hdd_context *hdd_ctx); +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); +#ifdef MSM_PLATFORM +/** + * hdd_bus_bw_compute_timer_start() - start the bandwidth timer + * @hdd_ctx: the global hdd context + * + * Return: None + */ +void hdd_bus_bw_compute_timer_start(struct hdd_context *hdd_ctx); + +/** + * hdd_bus_bw_compute_timer_try_start() - try to start the bandwidth timer + * @hdd_ctx: the global hdd context + * + * This function ensures there is at least one adapter in the associated state + * before starting the bandwidth timer. + * + * Return: None + */ +void hdd_bus_bw_compute_timer_try_start(struct hdd_context *hdd_ctx); + +/** + * hdd_bus_bw_compute_timer_stop() - stop the bandwidth timer + * @hdd_ctx: the global hdd context + * + * Return: None + */ +void hdd_bus_bw_compute_timer_stop(struct hdd_context *hdd_ctx); + +/** + * hdd_bus_bw_compute_timer_try_stop() - try to stop the bandwidth timer + * @hdd_ctx: the global hdd context + * + * This function ensures there are no adapters in the associated state before + * stopping the bandwidth timer. + * + * Return: None + */ +void hdd_bus_bw_compute_timer_try_stop(struct hdd_context *hdd_ctx); + +/** + * hdd_bus_bandwidth_init() - Initialize bus bandwidth data structures. + * @hdd_ctx: HDD context + * + * Initialize bus bandwidth related data structures like spinlock and timer. + * + * Return: None. + */ +int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx); + +/** + * hdd_bus_bandwidth_deinit() - De-initialize bus bandwidth data structures. + * @hdd_ctx: HDD context + * + * De-initialize bus bandwidth related data structures like timer. + * + * Return: None. + */ +void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx); + +#define GET_CUR_RX_LVL(config) ((config)->cur_rx_level) +#define GET_BW_COMPUTE_INTV(config) ((config)->busBandwidthComputeInterval) + +#else + +static inline +void hdd_bus_bw_compute_timer_start(struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_bus_bw_compute_timer_try_start(struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_bus_bw_compute_timer_stop(struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_bus_bw_compute_timer_try_stop(struct hdd_context *hdd_ctx) +{ +} + +static inline +int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline +void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx) +{ +} + +#define GET_CUR_RX_LVL(config) 0 +#define GET_BW_COMPUTE_INTV(config) 0 + +#endif + +int hdd_qdf_trace_enable(QDF_MODULE_ID module_id, uint32_t bitmask); + +int hdd_init(void); +void hdd_deinit(void); + +int hdd_wlan_startup(struct device *dev); +void __hdd_wlan_exit(void); +int hdd_wlan_notify_modem_power_state(int state); +#ifdef QCA_HT_2040_COEX +/** + * hdd_wlan_set_ht2040_mode() - notify FW with HT20/HT40 mode + * @adapter: pointer to adapter + * @sta_id: station id + * @sta_mac: station MAC address + * @channel_type: channel type + * + * This function notifies FW with HT20/HT40 mode + * + * Return: 0 if successful, error number otherwise + */ +int hdd_wlan_set_ht2040_mode(struct hdd_adapter *adapter, uint16_t sta_id, + struct qdf_mac_addr sta_mac, int channel_type); +#endif + +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); +#endif + +/** + * hdd_fill_nss_chain_params() - Fill nss chains ini params + * @hdd_ctx: hdd context + * @vdev_ini_cfg: structure to be filled + * @device_mode: device mode for which the inis are to be filled + * + * This function fills nss chains ini params for the respective device mode. + * + * Return: none + */ +void hdd_fill_nss_chain_params(struct hdd_context *hdd_ctx, + struct mlme_nss_chains *vdev_ini_cfg, + uint8_t device_mode); + +/** + * hdd_is_vdev_in_conn_state() - Check whether the vdev is in + * connected/started state. + * @adapter: hdd adapter of the vdev + * + * 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 hdd_adapter *adapter); + +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); + +int wlan_hdd_scan_abort(struct hdd_adapter *adapter); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline bool roaming_offload_enabled(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->config->isRoamOffloadEnabled; +} +#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) +{ + return hdd_ctx->config->isFastRoamIniFeatureEnabled; +} +#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 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 + +/** + * 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 + * @adapter: pointer to SAP adapter struct + * + * 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 hdd_adapter *adapter); + +/** + * 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 + * @adapter: AP 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: None + */ +void hdd_switch_sap_channel(struct hdd_adapter *adapter, uint8_t channel, + bool forced); + +#if defined(FEATURE_WLAN_CH_AVOID) +void 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 +void hdd_unsafe_channel_restart_sap(struct hdd_context *hdd_ctx) +{ +} + +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); + +/** + * wlan_hdd_disable_roaming() - disable roaming on all STAs except the input one + * @cur_adapter: Current HDD adapter passed from caller + * + * This function loops through all adapters and disables roaming on each STA + * mode adapter except the current adapter passed from the caller + * + * Return: None + */ +void wlan_hdd_disable_roaming(struct hdd_adapter *cur_adapter); + +/** + * wlan_hdd_enable_roaming() - enable roaming on all STAs except the input one + * @cur_adapter: Current HDD adapter passed from caller + * + * This function loops through all adapters and enables roaming on each STA + * mode adapter except the current adapter passed from the caller + * + * Return: None + */ +void wlan_hdd_enable_roaming(struct hdd_adapter *cur_adapter); + +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); + +QDF_STATUS +wlan_hdd_check_custom_con_channel_rules(struct hdd_adapter *sta_adapter, + struct hdd_adapter *ap_adapter, + struct csr_roam_profile *roam_profile, + tScanResultHandle *scan_cache, + bool *concurrent_chnl_same); + +void wlan_hdd_stop_sap(struct hdd_adapter *ap_adapter); +void wlan_hdd_start_sap(struct hdd_adapter *ap_adapter, bool reinit); + +#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_sap_pre_cac_failure(void *data); +void hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx); + +void wlan_hdd_txrx_pause_cb(uint8_t vdev_id, + enum netif_action_type action, enum netif_reason_type reason); + +int hdd_wlan_dump_stats(struct hdd_adapter *adapter, int value); +void wlan_hdd_deinit_tx_rx_histogram(struct hdd_context *hdd_ctx); +void wlan_hdd_display_tx_rx_histogram(struct hdd_context *hdd_ctx); +void wlan_hdd_clear_tx_rx_histogram(struct hdd_context *hdd_ctx); +void +wlan_hdd_display_netif_queue_history(struct hdd_context *hdd_ctx, + enum qdf_stats_verbosity_level verb_lvl); +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); + +struct hdd_adapter * +hdd_get_adapter_by_sme_session_id(struct hdd_context *hdd_ctx, + uint32_t sme_session_id); + +/** + * 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); +enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width); + +/** + * 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); + +QDF_STATUS hdd_chan_change_notify(struct hdd_adapter *adapter, + struct net_device *dev, + struct hdd_chan_change_params chan_change, + bool legacy_phymode); +int wlan_hdd_set_channel(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + enum nl80211_channel_type channel_type); +int wlan_hdd_cfg80211_start_bss(struct hdd_adapter *adapter, + 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 */ + +#ifdef FEATURE_TSO +/** + * 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) +{ + if (hdd_ctx->config->tso_enable && + hdd_ctx->config->enable_ip_tcp_udp_checksum_offload) { + /* + * We want to enable TSO only if IP/UDP/TCP TX checksum flag is + * enabled. + */ + hdd_debug("TSO Enabled"); + wlan_dev->features |= + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG; + } +} +#else +static inline void hdd_set_tso_flags(struct hdd_context *hdd_ctx, + struct net_device *wlan_dev){} +#endif /* FEATURE_TSO */ + +void hdd_get_ibss_peer_info_cb(void *pUserData, + tSirPeerInfoRspParams *pPeerInfo); + +#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) +{ + hdd_ctx->radio_index = nl_srv_init(hdd_ctx->wiphy); + + /* 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) +{ + return nl_srv_init(hdd_ctx->wiphy); +} +#endif +QDF_STATUS hdd_sme_open_session_callback(uint8_t session_id, + QDF_STATUS qdf_status); +QDF_STATUS hdd_sme_close_session_callback(uint8_t session_id); + +int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid, + uint8_t channel, const handoff_src src); +int hdd_register_cb(struct hdd_context *hdd_ctx); +void hdd_deregister_cb(struct hdd_context *hdd_ctx); +int hdd_start_station_adapter(struct hdd_adapter *adapter); +int hdd_start_ap_adapter(struct hdd_adapter *adapter); +int hdd_configure_cds(struct hdd_context *hdd_ctx); +int hdd_set_fw_params(struct hdd_adapter *adapter); +int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit); +int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode); +int hdd_start_adapter(struct hdd_adapter *adapter); +void hdd_populate_random_mac_addr(struct hdd_context *hdd_ctx, uint32_t num); +/** + * hdd_is_interface_up()- Checkfor interface up before ssr + * @hdd_ctx: HDD context + * + * check if there are any wlan interfaces before SSR accordingly start + * the interface. + * + * Return: 0 if interface was opened else false + */ +bool hdd_is_interface_up(struct hdd_adapter *adapter); +/** + * hdd_get_bss_entry() - Get the bss entry matching the chan, bssid and ssid + * @wiphy: wiphy + * @channel: channel of the BSS to find + * @bssid: bssid of the BSS to find + * @ssid: ssid of the BSS to find + * @ssid_len: ssid len of of the BSS to find + * + * The API is a wrapper to get bss from kernel matching the chan, + * bssid and ssid + * + * Return: bss structure if found else NULL + */ +struct cfg80211_bss *hdd_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len); + +void hdd_connect_result(struct net_device *dev, const u8 *bssid, + struct csr_roam_info *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason); + +#ifdef WLAN_FEATURE_FASTPATH +void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + void *context); +#else +static inline void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + 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); +void hdd_unsafe_channel_restart_sap(struct hdd_context *hdd_ctx); +/** + * 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 + * + * 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); + +int hdd_enable_disable_ca_event(struct hdd_context *hddctx, + uint8_t set_value); +void wlan_hdd_undo_acs(struct hdd_adapter *adapter); + +#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 + * @adapter: The adapter being queried + * + * 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 hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + return &sta_ctx->roam_profile; +} + +/** + * hdd_security_ie() - Get adapter's security IE + * @adapter: The adapter being queried + * + * Given an adapter this function returns a pointer to its security IE + * buffer. Note that this buffer is maintained outside the roam + * profile but, when in use, is referenced by a pointer within the + * 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 security IE buffer + */ +static inline +uint8_t *hdd_security_ie(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + return sta_ctx->security_ie; +} + +/** + * hdd_assoc_additional_ie() - Get adapter's assoc additional IE + * @adapter: The adapter being queried + * + * Given an adapter this function returns a pointer to its assoc + * additional IE buffer. Note that this buffer is maintained outside + * the roam profile but, when in use, is referenced by a pointer + * within the roam profile. + * + * NOTE WELL: Caller is responsible for ensuring this interface is only + * invoked for STA-type interfaces + * + * Return: pointer to the adapter's assoc additional IE buffer + */ +static inline +tSirAddie *hdd_assoc_additional_ie(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + return &sta_ctx->assoc_additional_ie; +} + +/** + * 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); +void hdd_set_roaming_in_progress(bool value); +bool hdd_is_connection_in_progress(uint8_t *session_id, + enum scan_reject_states *reason); +void hdd_restart_sap(struct hdd_adapter *ap_adapter); +void hdd_check_and_restart_sap_with_non_dfs_acs(void); +bool hdd_set_connection_in_progress(bool value); + +/** + * wlan_hdd_sap_get_valid_channellist() - Get SAPs valid channel list + * @ap_adapter: adapter + * @channel_count: valid channel count + * @channel_list: valid channel 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 + */ +int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter, + uint32_t *channel_count, + uint8_t *channel_list, + enum band_info band); +/** + * 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); +void wlan_hdd_start_sap(struct hdd_adapter *ap_adapter, bool reinit); + +/** + * 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 + * @sessionId: SME session id, i.e. vdev_id + * @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 sessionId, + tSirSmeChanInfo *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, sessionId, + NULL, dev_mode); + return; + } + + ch_info.chan_id = chan_info->chan_id; + 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, sessionId, + &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 sessionId, + tSirSmeChanInfo *chan_info, + enum QDF_OPMODE dev_mode) +{ + hdd_send_peer_status_ind_to_oem_app(peer_mac, peer_status, + peer_timing_meas_cap, sessionId, chan_info, dev_mode); +} +#endif /* WIFI_POS_CONVERGENCE */ + +/** + * wlan_hdd_send_p2p_quota()- Send P2P Quota value to FW + * @adapter: Adapter data + * @sval: P2P quota value + * + * Send P2P quota value to FW + * + * Return: 0 success else failure + */ +int wlan_hdd_send_p2p_quota(struct hdd_adapter *adapter, int sval); + +/** + * wlan_hdd_send_p2p_quota()- 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_adapter_from_vdev()- Get adapter from vdev id + * and PSOC object data + * @psoc: Psoc object data + * @vdev_id: vdev id + * + * Get adapter from vdev id and PSOC object data + * + * Return: adapter pointer + */ +struct hdd_adapter *wlan_hdd_get_adapter_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_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_whitelist_attr() - Copy probe req ie whitelist attrs from cfg + * @ie_whitelist: output parameter + * @cfg: pointer to hdd config + * + * Return: None + */ +void hdd_update_ie_whitelist_attr(struct probe_req_whitelist_attr *ie_whitelist, + struct hdd_config *cfg); + +/** + * hdd_get_rssi_snr_by_bssid() - gets the rssi and snr by bssid from scan cache + * @adapter: adapter 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(struct hdd_adapter *adapter, 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 defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) +/** + * hdd_clear_fils_connection_info: API to clear fils info from roam profile and + * free allocated memory + * @adapter: pointer to hdd adapter + * + * Return: None + */ +void hdd_clear_fils_connection_info(struct hdd_adapter *adapter); + +/** + * hdd_update_hlp_info() - Update HLP packet received in FILS (re)assoc rsp + * @dev: net device + * @roam_fils_params: Fils join rsp params + * + * This API is used to send the received HLP packet in Assoc rsp(FILS AKM) + * to the network layer. + * + * Return: None + */ +void hdd_update_hlp_info(struct net_device *dev, + struct csr_roam_info *roam_info); +#else +static inline void hdd_clear_fils_connection_info(struct hdd_adapter *adapter) +{ } +static inline void hdd_update_hlp_info(struct net_device *dev, + struct csr_roam_info *roam_info) +{} +#endif + +#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_dp_trace_init() - initialize DP Trace by calling the QDF API + * @config: hdd config + * + * Return: NONE + */ +#ifdef CONFIG_DP_TRACE +void hdd_dp_trace_init(struct hdd_config *config); +#else +static inline +void hdd_dp_trace_init(struct hdd_config *config) {} +#endif + +void hdd_set_rx_mode_rps(bool enable); + +/** + * hdd_set_limit_off_chan_for_tos() - set limit off-chan command parameters + * @adapter: pointer adapter context + * @tos: type of service + * @status: status of the traffic (active/inactive) + * + * This function updates the limit off-channel command parameters to WMA + * + * Return: 0 on success or non zero value on failure + */ +int hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, enum tos tos, + bool is_tos_active); + +/** + * hdd_drv_ops_inactivity_handler() - Timeout handler for driver ops + * inactivity timer + * @context: pointer to context + * + * Return: None + */ +void hdd_drv_ops_inactivity_handler(void *context); + +/** + * hdd_start_driver_ops_timer() - Starts driver ops inactivity timer + * @drv_op: Enum indicating driver op + * + * Return: none + */ +void hdd_start_driver_ops_timer(int drv_op); + +/** + * hdd_stop_driver_ops_timer() - Stops driver ops inactivity timer + * + * Return: none + */ +void hdd_stop_driver_ops_timer(void); + +/** + * hdd_pld_ipa_uc_shutdown_pipes() - Disconnect IPA WDI pipes during PDR + * + * Return: None + */ +void hdd_pld_ipa_uc_shutdown_pipes(void); + +/** + * hdd_limit_max_per_index_score() -check if per index score doesn't exceed 100% + * (0x64). If it exceed make it 100% + * + * @per_index_score: per_index_score as input + * + * Return: per_index_score within the max limit + */ +uint32_t hdd_limit_max_per_index_score(uint32_t per_index_score); +/** + * 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_enable() - Trigger psoc enable for CLD Components + * + * Return: None + */ +void hdd_component_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * hdd_component_psoc_disable() - Trigger psoc disable for CLD Components + * + * Return: None + */ +void hdd_component_psoc_disable(struct wlan_objmgr_psoc *psoc); + +#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 */ +/** + * hdd_set_disconnect_status() - set adapter disconnection status + * @hdd_adapter: Pointer to hdd adapter + * @disconnecting: Disconnect status to set + * + * Return: None + */ +void hdd_set_disconnect_status(struct hdd_adapter *adapter, bool disconnecting); + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * wlan_hdd_set_mon_chan() - Set capture channel on the monitor mode interface. + * @adapter: Handle to adapter + * @chan: Monitor mode channel + * @bandwidth: Capture channel bandwidth + * + * Return: 0 on success else error code. + */ +int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, uint32_t chan, + uint32_t bandwidth); +#else +static inline +int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, uint32_t chan, + uint32_t bandwidth) +{ + return 0; +} +#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_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_get_nud_stats_cb() - callback api to update the stats received from FW + * @data: pointer to hdd context. + * @rsp: pointer to data received from FW. + * @context: callback context + * + * This is called when wlan driver received response event for + * get arp stats to firmware. + * + * Return: None + */ +void hdd_get_nud_stats_cb(void *data, struct rsp_stats *rsp, void *context); + +/** + * 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 MSM_PLATFORM +/** + * wlan_hdd_send_tcp_param_update_event() - Send vendor event to update + * TCP parameter through Wi-Fi HAL + * @hdd_ctx: Pointer to HDD context + * @data: Parameters to update + * @dir: Direction(tx/rx) to update + * + * Return: None + */ +void wlan_hdd_send_tcp_param_update_event(struct hdd_context *hdd_ctx, + void *data, + uint8_t dir); + +/** + * wlan_hdd_update_tcp_rx_param() - update TCP param in RX dir + * @hdd_ctx: Pointer to HDD context + * @data: Parameters to update + * + * Return: None + */ +void wlan_hdd_update_tcp_rx_param(struct hdd_context *hdd_ctx, void *data); + +/** + * wlan_hdd_update_tcp_tx_param() - update TCP param in TX dir + * @hdd_ctx: Pointer to HDD context + * @data: Parameters to update + * + * Return: None + */ +void wlan_hdd_update_tcp_tx_param(struct hdd_context *hdd_ctx, void *data); +#else +static inline +void wlan_hdd_update_tcp_rx_param(struct hdd_context *hdd_ctx, void *data) +{ +} + +static inline +void wlan_hdd_update_tcp_tx_param(struct hdd_context *hdd_ctx, void *data) +{ +} + +static inline +void wlan_hdd_send_tcp_param_update_event(struct hdd_context *hdd_ctx, + void *data, + uint8_t dir) +{ +} + +#endif /* MSM_PLATFORM */ + +/** + * 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_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); + +/** + * hdd_psoc_idle_shutdown - perform idle shutdown after interface inactivity + * timeout + * @dev: platform device structure + * + * Return: 0 for success errorno for failure + */ +int hdd_psoc_idle_shutdown(struct device *dev); + +/** + * hdd_psoc_idle_restart - perform idle restart after idle shutdown + * @dev: platform device structure + * + * Return: 0 for success non-zero error code for failure + */ +int hdd_psoc_idle_restart(struct device *dev); + +/** + * 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); +#endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h new file mode 100644 index 0000000000000000000000000000000000000000..609e07bb7a0d62a841671c13b27d61b0f0506298 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h @@ -0,0 +1,39 @@ +/* + * 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 WLAN_HDD_MISC_H +#define WLAN_HDD_MISC_H +/* + * If MULTI_IF_NAME is defined, then prepend MULTI_IF_NAME to the filename + * to prevent name conflicts when loading multiple instances of the driver. + */ +#ifdef MULTI_IF_NAME +#define PREFIX MULTI_IF_NAME "/" +#else +#define PREFIX "" +#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 */ + +#endif /* WLAN_HDD_MISC_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_mpta_helper.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_mpta_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..e911feb3a74b7a198dab286af0e0a49d4530a3f5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_mpta_helper.h @@ -0,0 +1,82 @@ +/* + * 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_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_hdd_cfg.h" + +#ifdef FEATURE_MPTA_HELPER +#include + +/** + * wlan_hdd_mpta_helper_enable() - enable/disable mpta helper + * according to cfg from INI + * @config: pointer of BTC config items + * + * Return: 0 on success; error number otherwise. + * + */ +int +wlan_hdd_mpta_helper_enable(struct hdd_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); + +#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 \ +}, + +#else /* FEATURE_MPTA_HELPER */ +#define FEATURE_MPTA_HELPER_COMMANDS + +static inline int +wlan_hdd_mpta_helper_enable(struct hdd_config *config) +{ + return 0; +} + +#endif /* FEATURE_MPTA_HELPER */ + +#endif /* __WLAN_HDD_MPTA_HELPER_H */ + diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h new file mode 100644 index 0000000000000000000000000000000000000000..93ec1153fecfa1d74a139e28af1d359e308b6dd8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 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. + */ + +#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; + +int wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * 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 + */ +static inline bool wlan_hdd_nan_is_supported(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->config->enable_nan_support && + sme_is_feature_supported_by_fw(NAN); +} + +/** + * hdd_nan_populate_cds_config() - Populate NAN cds configuration + * @cds_cfg: CDS Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_nan_populate_cds_config(struct cds_config_info *cds_cfg, + struct hdd_context *hdd_ctx) +{ + cds_cfg->is_nan_enabled = hdd_ctx->config->enable_nan_support; +} + +/** + * hdd_nan_populate_pmo_config() - Populate NAN pmo configuration + * @pmo_cfg: PMO Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_nan_populate_pmo_config(struct pmo_psoc_cfg *pmo_cfg, + struct hdd_context *hdd_ctx) +{ + pmo_cfg->nan_enable = hdd_ctx->config->enable_nan_support; +} + +/** + * wlan_hdd_cfg80211_nan_callback() - cfg80211 NAN event handler + * @hdd_handle: opaque handle to the global HDD context + * @msg: NAN event message + * + * This is a callback function and it gets called when we need to report + * a nan event to userspace. The wlan host driver simply encapsulates the + * event into a netlink payload and then forwards it to userspace via a + * cfg80211 vendor event. + * + * Return: nothing + */ +void wlan_hdd_cfg80211_nan_callback(hdd_handle_t hdd_handle, tSirNanEvent *msg); +#else +static inline bool wlan_hdd_nan_is_supported(struct hdd_context *hdd_ctx) +{ + return false; +} +static inline void hdd_nan_populate_cds_config(struct cds_config_info *cds_cfg, + struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_nan_populate_pmo_config(struct pmo_psoc_cfg *pmo_cfg, + struct hdd_context *hdd_ctx) +{ +} + +static inline +void wlan_hdd_cfg80211_nan_callback(hdd_handle_t hdd_handle, tSirNanEvent *msg) +{ +} +#endif /* WLAN_FEATURE_NAN */ +#endif /* __WLAN_HDD_NAN_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..9e008218a3dcb96160a4ed286ad545f6c283abc0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h @@ -0,0 +1,101 @@ +/* + * 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 __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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h new file mode 100644 index 0000000000000000000000000000000000000000..c8cd09d56d16f9e78e4b1b11ae7e375922ae1bb0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h @@ -0,0 +1,222 @@ +/* + * 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: wlan_hdd_oemdata.h + * + * Internal includes for the oem data + */ + +#ifndef __WLAN_HDD_OEM_DATA_H__ +#define __WLAN_HDD_OEM_DATA_H__ + +struct hdd_context; + +#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 + +/** + * typedef eOemErrorCode - 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 + * @chan_id: channel id + * @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 chan_id; + 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; +}; + +/** + * enum oem_capability_mask - mask field for userspace client capabilities + * @OEM_CAP_RM_FTMRR: FTM range report mask bit + * @OEM_CAP_RM_LCI: LCI capability mask bit + */ +enum oem_capability_mask { + OEM_CAP_RM_FTMRR = (1 << (0)), + OEM_CAP_RM_LCI = (1 << (1)), +}; + +/** + * struct oem_get_capability_rsp - capabilities set by userspace and target. + * @target_cap: target capabilities + * @client_capabilities: capabilities set by userspace via set request + */ +struct oem_get_capability_rsp { + struct oem_data_cap target_cap; + struct sme_oem_capability cap; +}; + +void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac, + uint8_t peerStatus, + uint8_t peerTimingMeasCap, + uint8_t sessionId, + struct sSirSmeChanInfo *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); +void hdd_update_channel_bw_info(struct hdd_context *hdd_ctx, + uint16_t chan, + 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, + uint16_t chan, + void *hdd_chan_info) {} +#endif /* FEATURE_OEM_DATA_SUPPORT */ +#endif /* __WLAN_HDD_OEM_DATA_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h new file mode 100644 index 0000000000000000000000000000000000000000..876ff193101ea36f22f1a4952bc03e78630f1e17 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h @@ -0,0 +1,209 @@ +/* + * 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 __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 WLAN_HDD_80211_PEER_ADDR_OFFSET (WLAN_HDD_80211_FRM_DA_OFFSET + \ + MAC_ADDR_LEN) + +#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 ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; +}; + +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); + +void __hdd_indicate_mgmt_frame(struct hdd_adapter *adapter, + uint32_t nFrameLength, uint8_t *pbFrames, + uint8_t frameType, uint32_t rxChan, int8_t rxRssi); + +int wlan_hdd_check_remain_on_channel(struct hdd_adapter *adapter); +void wlan_hdd_cancel_existing_remain_on_channel(struct hdd_adapter *adapter); + +#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 + +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); + + +void wlan_hdd_cleanup_remain_on_channel_ctx(struct hdd_adapter *adapter); + +void wlan_hdd_roc_request_dequeue(struct work_struct *work); + +/** + * 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_listen_offload_start() - hdd set listen offload start + * @adapter: adapter context + * @params: listen offload parameters + * + * This function sets listen offload start parameters. + * + * Return: 0 - success + * others - failure + */ +int wlan_hdd_listen_offload_start(struct hdd_adapter *adapter, + struct sir_p2p_lo_start *params); + +/** + * wlan_hdd_listen_offload_stop() - hdd set listen offload stop + * @adapter: adapter context + * + * This function sets listen offload stop parameters. + * + * Return: 0 - success + * others - failure + */ +int wlan_hdd_listen_offload_stop(struct hdd_adapter *adapter); + +/** + * 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 + * @adapter: Pointer to HDD adapter + * + * This function cleans up action frame. + * + * Return: None + */ +void wlan_hdd_cleanup_actionframe(struct hdd_adapter *adapter); +#endif /* __P2P_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h new file mode 100644 index 0000000000000000000000000000000000000000..af0f10218a797f3c4ad80489927a67bff9c61115 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#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" +/** + * hdd_enable_default_pkt_filters() - Enable default packet filters based + * on, filters bit map provided in INI, when target goes to suspend mode + * @adapter: Adapter context for which default filters to be configure + * + * Return: zero if success, non-zero otherwise + */ +int hdd_enable_default_pkt_filters(struct hdd_adapter *pAadapter); + +/** + * hdd_disable_default_pkt_filters() - Disable default packet filters based + * on, filters bit map provided in INI, when target resumes + * @adapter: Adapter context for which default filters to be cleared + * + * Return: zero if success, non-zero otherwise + */ +int hdd_disable_default_pkt_filters(struct hdd_adapter *adapter); + +/** + * wlan_hdd_set_filter() - Set packet filter + * @hdd_ctx: Global HDD context + * @request: Packet filter request struct + * @sessionId: Target session 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 sessionId); +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h new file mode 100644 index 0000000000000000000000000000000000000000..8d2bbfc92ebb0953462c8ed66f689ebb17932d9c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h @@ -0,0 +1,180 @@ +/* + * 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. + */ + +#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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h new file mode 100644 index 0000000000000000000000000000000000000000..fc8f4847c3007c06c7270706e2c22c1252bd6145 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2012, 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. + */ + +#ifndef __WLAN_HDD_POWER_H +#define __WLAN_HDD_POWER_H + +/** + * DOC: wlan_hdd_power.h + * + * HDD Power Management API + */ + +#include "wlan_hdd_main.h" + +#ifdef WLAN_FEATURE_PACKET_FILTERING + +#define HDD_MAX_CMP_PER_PACKET_FILTER 5 + +#define HDD_WAKELOCK_TIMEOUT_CONNECT 1000 +#define HDD_WAKELOCK_TIMEOUT_RESUME 1000 +/* + * 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 + +/** + * 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_INVALID: 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_fffset: 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 + +/** + * 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_enable_arp_offload() - API to enable ARP offload + * @adapter: Adapter context for which ARP offload is to be configured + * @trigger: trigger reason for request + * + * Return: None + */ +void hdd_enable_arp_offload(struct hdd_adapter *adapter, + 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 + * @trigger: trigger reason for request + * + * Return: None + */ +void hdd_disable_arp_offload(struct hdd_adapter *adapter, + 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_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); + +/** + * hdd_enable_ns_offload() - enable NS offload + * @adapter: pointer to the adapter + * + * Return: nothing + */ +void hdd_enable_ns_offload(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger); + +/** + * hdd_disable_ns_offload() - disable NS offload + * @adapter: pointer to the adapter + * + * Return: nothing + */ +void hdd_disable_ns_offload(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger); + +/** + * 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); + +/** + * 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_qpower_config() - set qpower config to firmware + * @hddctx: HDD context + * @adapter: HDD adapter + * @qpower: new qpower config value + * + * Return: 0 on success; Errno on failure + */ +int hdd_set_qpower_config(struct hdd_context *hddctx, + struct hdd_adapter *adapter, + uint8_t qpower); + +#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 + * @adapter: adapter upon which the request was received + * @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 hdd_adapter *adapter, + 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 durring 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 */ +#endif /* __WLAN_HDD_POWER_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h new file mode 100644 index 0000000000000000000000000000000000000000..87493f5e48a21feeedd76bcff55f7e72c5351313 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 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. + */ + +#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 +#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR +#endif + +int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy); +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_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_set_band() - helper function for setting the regulatory band + * @hdd_ctx: the HDD context to set the band for + * @ui_band: the UI band to configure + * + * Return: zero for success, non-zero error code for failure + */ +int hdd_reg_set_band(struct net_device *dev, u8 ui_band); + +/** + * 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 + * @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); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h new file mode 100644 index 0000000000000000000000000000000000000000..17e0ad5e204d4b27ae4fc75c4d8f52e30eb0efe8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h @@ -0,0 +1,257 @@ +/* + * 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(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 + +/** + * 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 + * + * 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 + */ +void hdd_softap_tx_timeout(struct net_device *dev); + +/** + * hdd_softap_init_tx_rx() - Initialize Tx/Rx module + * @adapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_init_tx_rx(struct hdd_adapter *adapter); + +/** + * hdd_softap_deinit_tx_rx() - Deinitialize Tx/Rx module + * @adapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_deinit_tx_rx(struct hdd_adapter *adapter); + +/** + * hdd_softap_init_tx_rx_sta() - Initialize Tx/Rx for a softap station + * @adapter: pointer to adapter context + * @sta_id: Station ID to initialize + * @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, + uint8_t sta_id, + struct qdf_mac_addr *sta_mac); + +/** + * hdd_softap_deinit_tx_rx_sta() - Deinitialize Tx/Rx for a softap station + * @adapter: pointer to adapter context + * @sta_id: Station ID to deinitialize + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_deinit_tx_rx_sta(struct hdd_adapter *adapter, + uint8_t sta_id); + +/** + * hdd_softap_rx_packet_cbk() - Receive packet handler + * @context: pointer to HDD context + * @rx_buf: pointer to rx qdf_nbuf chain + * + * Receive callback registered with the Data Path. The Data Path will + * call this to notify the HDD 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 hdd_softap_rx_packet_cbk(void *context, qdf_nbuf_t rx_buf); + +/** + * hdd_softap_deregister_sta() - Deregister a STA with the Data Path + * @adapter: pointer to adapter context + * @sta_id: Station ID to deregister + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_deregister_sta(struct hdd_adapter *adapter, + uint8_t sta_id); + +/** + * hdd_softap_register_sta() - Register a SoftAP STA + * @adapter: pointer to adapter context + * @auth_required: is additional authentication required? + * @privacy_required: should 802.11 privacy bit be set? + * @sta_id: station ID assigned to this station + * @sta_mac: station MAC address + * @wmm_enabled: is WMM enabled for this STA? + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter, + bool auth_required, + bool privacy_required, + uint8_t sta_id, + struct qdf_mac_addr *sta_mac, + bool wmm_enabled); + +/** + * hdd_softap_register_bc_sta() - Register the SoftAP broadcast STA + * @adapter: pointer to adapter context + * @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 hdd_adapter *adapter, + 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); + +/** + * hdd_softap_get_sta_id() - Find station ID from MAC address + * @adapter: pointer to adapter context + * @sta_mac: MAC address of the destination + * @sta_id: Station ID associated with the MAC address + * + * Return: QDF_STATUS_SUCCESS if a match was found, in which case + * @sta_id is populated, QDF_STATUS_E_FAILURE if a match is + * not found + */ +QDF_STATUS hdd_softap_get_sta_id(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac, + uint8_t *sta_id); + +#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_post_dhcp_ind() - Send DHCP START/STOP indication to FW + * @adapter: pointer to hdd adapter + * @sta_id: peer station ID + * @type: WMA message type + * + * Return: error number + */ +int hdd_post_dhcp_ind(struct hdd_adapter *adapter, + uint8_t sta_id, uint16_t type); + +/** + * hdd_inspect_dhcp_packet() - Inspect DHCP packet + * @adapter: pointer to hdd adapter + * @sta_id: peer station ID + * @skb: pointer to OS packet (sk_buff) + * @dir: direction + * + * Return: error number + */ +int hdd_inspect_dhcp_packet(struct hdd_adapter *adapter, + uint8_t sta_id, + struct sk_buff *skb, + enum qdf_proto_dir dir); + +#endif /* end #if !defined(WLAN_HDD_SOFTAP_TX_RX_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_spectralscan.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_spectralscan.h new file mode 100644 index 0000000000000000000000000000000000000000..be1b55f423aa249d16674778b4a4f5bb8ed5e39c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_spectralscan.h @@ -0,0 +1,222 @@ +/* + * 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 : 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; +}; + +#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 \ +}, \ +{ \ + .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 \ +}, \ +{ \ + .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_scam_get_config \ +}, \ +{ \ + .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 \ +}, \ +{ \ + .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 \ +}, \ +{ \ + .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 \ +}, + +/** + * 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_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_scam_get_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * 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_get_diag_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * 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_get_cap_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * 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_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +#else +#define FEATURE_SPECTRAL_SCAN_VENDOR_COMMANDS +#endif + +#if defined(CNSS_GENL) && defined(WLAN_CONV_SPECTRAL_ENABLE) +/** + * spectral_scan_activate_service() - Activate spectral scan message handler + * + * This function registers a handler to receive netlink message from + * the spectral scan application process. + * + * Return: None + */ +void spectral_scan_activate_service(void); + +/** + * 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); +#else +static inline void spectral_scan_activate_service(void) +{ +} + +static inline void spectral_scan_deactivate_service(void) +{ +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs.h new file mode 100644 index 0000000000000000000000000000000000000000..843352d63fd8799457a1ff71588cbddb7c609a5f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs.h @@ -0,0 +1,120 @@ +/* + * 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. + */ +#ifndef _WLAN_HDD_SYSFS_H_ +#define _WLAN_HDD_SYSFS_H_ + +#ifdef WLAN_SYSFS +/** + * hdd_sysfs_create_driver_root_obj() - create driver root kobject + * + * Return: none + */ +void hdd_sysfs_create_driver_root_obj(void); + +/** + * hdd_sysfs_destroy_driver_root_obj() - destroy driver root kobject + * + * Return: none + */ +void hdd_sysfs_destroy_driver_root_obj(void); + +/** + * hdd_sysfs_create_version_interface() - create version interface + * @psoc: PSOC ptr + * + * Return: none + */ +void hdd_sysfs_create_version_interface(struct wlan_objmgr_psoc *psoc); + +/** + * hdd_sysfs_destroy_version_interface() - destroy version interface + * + * Return: none + */ +void hdd_sysfs_destroy_version_interface(void); +/** + * hdd_sysfs_create_powerstats_interface() - create power_stats interface + * + * Return: none + */ +void hdd_sysfs_create_powerstats_interface(void); +/** + * hdd_sysfs_destroy_powerstats_interface() - destroy power_stats interface + * + * Return: none + */ +void hdd_sysfs_destroy_powerstats_interface(void); +#else +static inline +void hdd_sysfs_create_driver_root_obj(void) +{ +} + +static inline +void hdd_sysfs_destroy_driver_root_obj(void) +{ +} + +static inline +void hdd_sysfs_create_version_interface(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void hdd_sysfs_destroy_version_interface(void) +{ +} + +static inline +void hdd_sysfs_create_powerstats_interface(void) +{ +} + +static inline +void hdd_sysfs_destroy_powerstats_interface(void) +{ +} +#endif + +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +/** + * hdd_sysfs_create_adapter_root_obj() - create adapter sysfs entries + * @adapter: HDD adapter + * + * Return: none + */ +void hdd_sysfs_create_adapter_root_obj(struct hdd_adapter *adapter); +/** + * hdd_sysfs_destroy_adapter_root_obj() - Destroy adapter sysfs entries + * @adapter: HDD adapter + * + * Return: none + */ +void hdd_sysfs_destroy_adapter_root_obj(struct hdd_adapter *adapter); +#else +static inline +void hdd_sysfs_create_adapter_root_obj(struct hdd_adapter *adapter) +{ +} + +static inline +void hdd_sysfs_destroy_adapter_root_obj(struct hdd_adapter *adapter) +{ +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h new file mode 100644 index 0000000000000000000000000000000000000000..0339213df54e17a1d500cd7fc9eca95bbeb2b34c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h @@ -0,0 +1,296 @@ +/* + * 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 __HDD_TDLS_H +#define __HDD_TDLS_H +/** + * DOC: wlan_hdd_tdls.h + * WLAN Host Device Driver TDLS include file + */ + +struct hdd_context; + +/** + * enum tdls_concerned_external_events - External events that affect TDLS + * @P2P_ROC_START: P2P remain on channel starts + * @P2P_ROC_END: P2P remain on channel ends + */ +enum tdls_concerned_external_events { + P2P_ROC_START, + P2P_ROC_END, +}; + +#ifdef FEATURE_WLAN_TDLS + +/* 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 */ +/** + * struct hdd_tdls_config_params - tdls config params + * + * @tdls: tdls + * @tx_period_t: tx period + * @tx_packet_n: tx packets number + * @discovery_tries_n: discovery tries + * @idle_timeout_t: idle traffic time out value + * @idle_packet_n: idle packet number + * @rssi_trigger_threshold: rssi trigger threshold + * @rssi_teardown_threshold: rssi tear down threshold + * @rssi_delta: rssi delta + */ +struct hdd_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; +}; + +typedef int (*cfg80211_exttdls_callback)(const uint8_t *mac, + uint32_t opclass, + uint32_t channel, + uint32_t state, + int32_t reason, void *ctx); + +/** + * struct tdlsInfo_t - 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 + */ +typedef struct { + 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; +} tdlsInfo_t; + +int wlan_hdd_tdls_set_params(struct net_device *dev, + struct hdd_tdls_config_params *config); + +int wlan_hdd_tdls_get_all_peers(struct hdd_adapter *adapter, char *buf, + int buflen); + +int wlan_hdd_tdls_extctrl_deconfig_peer(struct hdd_adapter *adapter, + const uint8_t *peer); +int wlan_hdd_tdls_extctrl_config_peer(struct hdd_adapter *adapter, + const uint8_t *peer, + cfg80211_exttdls_callback callback, + uint32_t chan, + uint32_t max_latency, + uint32_t op_class, + uint32_t min_bandwidth); + +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); + +#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_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 +#if (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)) +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 +#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_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); +int wlan_hdd_tdls_antenna_switch(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + 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, uint16_t sta_id, + uint8_t qos); + +QDF_STATUS hdd_tdls_deregister_peer(void *userdata, uint32_t vdev_id, + uint8_t sta_id); + +#else + +static inline int wlan_hdd_tdls_antenna_switch(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + 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 void +hdd_tdls_notify_p2p_roc(struct hdd_context *hdd_ctx, + enum tdls_concerned_external_events event) +{ +} + +static inline +QDF_STATUS hdd_tdls_register_peer(void *userdata, uint32_t vdev_id, + const uint8_t *mac, uint16_t sta_id, + uint8_t qos); +{ +} + +static inline +QDF_STATUS hdd_tdls_deregister_peer(void *userdata, uint32_t vdev_id, + uint8_t sta_id) +{ +} +#endif /* End of FEATURE_WLAN_TDLS */ +#endif /* __HDD_TDLS_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..41d12a3216054386772351d22cd53ec627bffd1d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 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. + */ + +#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_JOIN_IBSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_LEAVE_IBSS) \ + 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/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h new file mode 100644 index 0000000000000000000000000000000000000000..0a5e689a797a678ed30ecefc9a861654871ee83d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h @@ -0,0 +1,342 @@ +/* + * Copyright (c) 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. + */ + +#if !defined WLAN_HDD_TSF_H +#define WLAN_HDD_TSF_H +#include "wlan_hdd_cfg.h" +#include "wlan_hdd_main.h" + +/** + * 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 +}; + +#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 + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to uplayer. + * + * Return: Describe the execute result of this routine + */ +int hdd_indicate_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len); + +/** + * 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); + +#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, uint32_t *buf, + int len) +{ + 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; +} + +#endif + +#if defined(WLAN_FEATURE_TSF_PLUS) && defined(WLAN_FEATURE_TSF) +/** + * hdd_tsf_is_ptp_enabled() - check ini configuration + * @hdd: pointer to hdd context + * + * This function checks tsf configuration for ptp + * + * Return: true on enable, false on disable + */ +bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd); +/** + * 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_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_tsf_notify_wlan_state_change() - + * notify tsf module of wlan connection state + * @old_state: old wlan state + * @new_state: new wlan state + * + * This function check the old and new connection state, determine whether + * to start or stop tsf sync + * + * Return: nothing + */ +void hdd_tsf_notify_wlan_state_change(struct hdd_adapter *adapter, + eConnectionState old_state, + eConnectionState new_state); + +/** + * hdd_tx_timestamp() - time stamp TX netbuf + * + * @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 + */ +int hdd_tx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time); + +/** + * 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); +/** + * 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); +#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_tsf_notify_wlan_state_change(struct hdd_adapter *adapter, + eConnectionState old_state, + eConnectionState new_state) + +{ +} + +static inline +int hdd_tx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time) +{ + return -ENOTSUPP; +} + +static inline +int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time) +{ + return -ENOTSUPP; +} + +static inline +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 + */ +static inline +bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd) +{ + return FALSE; +} +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_twt.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_twt.h new file mode 100644 index 0000000000000000000000000000000000000000..98d67b4a1b9d05b3643d5641445ae572c77eba32 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_twt.h @@ -0,0 +1,165 @@ +/* + * 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 : 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" + +struct hdd_context; +struct wma_tgt_cfg; +struct wmi_twt_enable_complete_event_param; + +#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, +}; + +/** + * hdd_twt_print_ini_config() - Print TWT INI config items + * @hdd_ctx: HDD Context + * + * Return: None + */ +void hdd_twt_print_ini_config(struct hdd_context *hdd_ctx); + +/** + * 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_enable_cmd() - Send TWT enable command to target + * @hdd_ctx: HDD Context + * + * Return: None + */ +void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx); + +/** + * hdd_twt_enable_comp_cb() - TWT enable complete event callback + * @hdd_ctx: pointer to global HDD Context + * @twt_event: TWT event data received from the target + * + * Return: None + */ +void hdd_twt_enable_comp_cb(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params); + +/** + * hdd_twt_disable_comp_cb() - TWT disable complete event callback + * @hdd_ctx: pointer to global HDD Context + * + * Return: None + */ +void hdd_twt_disable_comp_cb(void *hdd_ctx); + +/** + * 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); + +#else +static inline void hdd_twt_print_ini_config(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} + +static inline void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_twt_enable_comp_cb(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params) +{ +} + +static inline void hdd_twt_disable_comp_cb(void *hdd_ctx) +{ +} + +static inline void wlan_hdd_twt_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx) +{ +} + +#endif +#endif /* if !defined(WLAN_HDD_TWT_H)*/ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h new file mode 100644 index 0000000000000000000000000000000000000000..719c3051c0d4ef2556c48f925afe73378e7b044c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h @@ -0,0 +1,279 @@ +/* + * 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. + */ + +#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" + +struct hdd_context; + +#define HDD_ETHERTYPE_802_1_X 0x888E +#define HDD_ETHERTYPE_802_1_X_FRAME_OFFSET 12 +#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 + +netdev_tx_t hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +void hdd_tx_timeout(struct net_device *dev); + +QDF_STATUS hdd_init_tx_rx(struct hdd_adapter *adapter); +QDF_STATUS hdd_deinit_tx_rx(struct hdd_adapter *adapter); +QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf); + +/** + * hdd_rx_ol_init() - Initialize Rx mode(LRO or GRO) method + * @hdd_ctx: pointer to HDD Station Context + * + * Return: 0 on success and non zero on failure. + */ +int hdd_rx_ol_init(struct hdd_context *hdd_ctx); + +/** + * hdd_disable_rx_ol_in_concurrency() - Disable Rx offload due to concurrency + * @disable: true/false to disable/enable the Rx offload + * + * Return: none + */ +void hdd_disable_rx_ol_in_concurrency(bool disable); + +/** + * hdd_disable_rx_ol_for_low_tput() - Disable Rx offload in low TPUT scenario + * @hdd_ctx: hdd context + * @disable: true/false to disable/enable the Rx offload + * + * Return: none + */ +void hdd_disable_rx_ol_for_low_tput(struct hdd_context *hdd_ctx, bool disable); + +QDF_STATUS hdd_get_peer_sta_id(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *peer_mac_addr, + uint8_t *sta_id); +/** + * hdd_reset_all_adapters_connectivity_stats() - reset connectivity stats + * @hdd_ctx: pointer to HDD Station Context + * + * Return: None + */ +void hdd_reset_all_adapters_connectivity_stats(struct hdd_context *hdd_ctx); + +/** + * hdd_tx_rx_collect_connectivity_stats_info() - collect connectivity stats + * @skb: pointer to skb data + * @adapter: pointer to vdev apdapter + * @action: action done on pkt. + * @pkt_type: data pkt type + * + * Return: None + */ +void hdd_tx_rx_collect_connectivity_stats_info(struct sk_buff *skb, + void *adapter, enum connectivity_stats_pkt_status action, + uint8_t *pkt_type); + +/** + * hdd_tx_queue_cb() - Disable/Enable the Transmit Queues + * @context: HDD context + * @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(void *context, 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); +void hdd_tx_resume_timer_expired_handler(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 flowControl, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause); +void hdd_deregister_tx_flow_control(struct hdd_adapter *adapter); +void hdd_get_tx_resource(struct hdd_adapter *adapter, + uint8_t STAId, uint16_t timer_value); + +#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_tx_resume_timer_expired_handler(void *adapter_context) +{ +} +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 flowControl, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause) +{ +} +static inline void hdd_deregister_tx_flow_control(struct hdd_adapter *adapter) +{ +} +static inline void hdd_get_tx_resource(struct hdd_adapter *adapter, + uint8_t STAId, uint16_t timer_value) +{ +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +int hdd_get_peer_idx(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *addr); + +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 + +void hdd_send_rps_ind(struct hdd_adapter *adapter); +void hdd_send_rps_disable_ind(struct hdd_adapter *adapter); +void wlan_hdd_classify_pkt(struct sk_buff *skb); + +#ifdef MSM_PLATFORM +void hdd_reset_tcp_delack(struct hdd_context *hdd_ctx); +bool hdd_is_current_high_throughput(struct hdd_context *hdd_ctx); +#define HDD_MSM_CFG(msm_cfg) msm_cfg +#else +static inline void hdd_reset_tcp_delack(struct hdd_context *hdd_ctx) {} +static inline bool hdd_is_current_high_throughput(struct hdd_context *hdd_ctx) +{ + return false; +} +#define HDD_MSM_CFG(msm_cfg) 0 +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_event_eapol_log(struct sk_buff *skb, enum qdf_proto_dir dir); +#else +static inline +void hdd_event_eapol_log(struct sk_buff *skb, enum qdf_proto_dir dir) +{} +#endif + +/* + * 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 + +static inline void +hdd_skb_fill_gso_size(struct net_device *dev, struct sk_buff *skb) +{ + if (skb_cloned(skb) && skb_is_nonlinear(skb) && + skb_shinfo(skb)->gso_size == 0 && + ip_hdr(skb)->protocol == IPPROTO_TCP) { + skb_shinfo(skb)->gso_size = dev->mtu - + ((skb_transport_header(skb) - skb_network_header(skb)) + + tcp_hdrlen(skb)); + } +} + +/** + * hdd_txrx_get_tx_ack_count() - get tx acked count + * @adapter: Pointer to adapter + * + * Return: tx acked count + */ +uint32_t hdd_txrx_get_tx_ack_count(struct hdd_adapter *adapter); + +#ifdef CONFIG_HL_SUPPORT +static inline QDF_STATUS +hdd_skb_nontso_linearize(struct sk_buff *skb) +{ + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +hdd_skb_nontso_linearize(struct sk_buff *skb) +{ + if (qdf_nbuf_is_nonlinear(skb) && qdf_nbuf_is_tso(skb) == false) { + if (qdf_unlikely(skb_linearize(skb))) + return QDF_STATUS_E_NOMEM; + } + return QDF_STATUS_SUCCESS; +} +#endif + +#endif /* end #if !defined(WLAN_HDD_TX_RX_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h new file mode 100644 index 0000000000000000000000000000000000000000..12376c9d61d69eabd431e4586dbf2355a1b210a4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h @@ -0,0 +1,302 @@ +/* + * 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 __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 exchnage 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 exchnage 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; + +/** TS Info Ack Policy */ +enum hdd_wlan_wmm_ts_info_ack_policy { + HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK = 0, + HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK = 1, +}; + +/** Enable 11d */ +#define ENABLE_11D 1 + +/** Disable 11d */ +#define DISABLE_11D 0 + +/* + * refer wpa.h in wpa supplicant code for REASON_MICHAEL_MIC_FAILURE + * + * supplicant sets REASON_MICHAEL_MIC_FAILURE as the reason code when it + * sends the MLME deauth IOCTL for TKIP counter measures + */ +#define HDD_REASON_MICHAEL_MIC_FAILURE 14 + +#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 + +/** + * hdd_unregister_wext() - unregister wext context + * @dev: net device handle + * + * Unregisters wext interface context for a given net device + * + * Returns: None + */ +void hdd_unregister_wext(struct net_device *dev); + +/** + * 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); + +void hdd_wlan_get_stats(struct hdd_adapter *adapter, 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); + +int hdd_get_ldpc(struct hdd_adapter *adapter, int *value); +int hdd_set_ldpc(struct hdd_adapter *adapter, int value); +int hdd_get_tx_stbc(struct hdd_adapter *adapter, int *value); +int hdd_set_tx_stbc(struct hdd_adapter *adapter, int value); +int hdd_get_rx_stbc(struct hdd_adapter *adapter, int *value); +int hdd_set_rx_stbc(struct hdd_adapter *adapter, int value); + +/** + * 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); + +int wlan_hdd_update_phymode(struct net_device *net, mac_handle_t mac_handle, + int new_phymode, struct hdd_context *phddctx); + +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); + +/** + * 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: result of the command + */ +#ifdef CONFIG_WLAN_DEBUG_CRASH_INJECT +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 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 + +#endif /* __WEXT_IW_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h new file mode 100644 index 0000000000000000000000000000000000000000..6a5b0b7b6945277677f36c598f54a6941978cc9c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2011-2012,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. + */ + +#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 + +/*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. + */ +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 confgured 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: identifer which uniquely identifies this context to userspace + * @qosFlowID: identifier which uniquely identifies this flow to SME + * @adapter: adapter upon which this flow was configured + * @acType: access category for this flow + * @lastStatus: the status of the last operation performed on this flow by SME + * @wmmAcSetupImplicitQos: 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 + */ +struct hdd_wmm_qos_context { + struct list_head node; + uint32_t handle; + uint32_t qosFlowId; + struct hdd_adapter *adapter; + sme_ac_enum_type acType; + hdd_wlan_wmm_status_e lastStatus; + struct work_struct wmmAcSetupImplicitQos; + uint32_t magic; + bool is_inactivity_timer_running; +}; + +/** + * struct hdd_wmm_ac_status - WMM related per-AC state & status info + * @wmmAcAccessRequired - does the AP require access to this AC? + * @wmmAcAccessNeeded - does the worker thread need to acquire access to + * this AC? + * @wmmAcAccessPending - is implicit QoS negotiation currently taking place? + * @wmmAcAccessFailed - has implicit QoS negotiation already failed? + * @wmmAcAccessGranted - has implicit QoS negotiation already succeeded? + * @wmmAcAccessAllowed - is access to this AC allowed, either because we + * are not doing WMM, we are not doing implicit QoS, implict QoS has + * completed, or explicit QoS has completed? + * @wmmAcTspecValid - is the wmmAcTspecInfo valid? + * @wmmAcUapsdInfoValid - are the wmmAcUapsd* fields valid? + * @wmmAcTspecInfo - current (possibly aggregate) Tspec for this AC + * @wmmAcIsUapsdEnabled - is UAPSD enabled on this AC? + * @wmmAcUapsdServiceInterval - service interval for this AC + * @wmmAcUapsdSuspensionInterval - suspension interval for this AC + * @wmmAcUapsdDirection - direction for this AC + * @wmmInactivityTime - inactivity time for this AC + * @wmmPrevTrafficCnt - TX counter used for inactivity detection + * @wmmInactivityTimer - timer used for inactivity detection + */ +struct hdd_wmm_ac_status { + bool wmmAcAccessRequired; + bool wmmAcAccessNeeded; + bool wmmAcAccessPending; + bool wmmAcAccessFailed; + bool wmmAcAccessGranted; + bool wmmAcAccessAllowed; + bool wmmAcTspecValid; + bool wmmAcUapsdInfoValid; + struct sme_qos_wmmtspecinfo wmmAcTspecInfo; + bool wmmAcIsUapsdEnabled; + uint32_t wmmAcUapsdServiceInterval; + uint32_t wmmAcUapsdSuspensionInterval; + enum sme_qos_wmm_dir_type wmmAcUapsdDirection; + +#ifdef FEATURE_WLAN_ESE + uint32_t wmmInactivityTime; + uint32_t wmmPrevTrafficCnt; + qdf_mc_timer_t wmmInactivityTimer; +#endif +}; + +/** + * struct hdd_wmm_status - WMM status maintained per-adapter + * @wmmContextList - list of WMM contexts active on the adapter + * @wmmLock - mutex used for exclusive access to this adapter's WMM status + * @wmmACStatus - per-AC WMM status + * @wmmQap - is this connected to a QoS-enabled AP? + * @wmmQosConnection - is this a QoS connection? + */ +struct hdd_wmm_status { + struct list_head wmmContextList; + struct mutex wmmLock; + struct hdd_wmm_ac_status wmmAcStatus[WLAN_MAX_AC]; + bool wmmQap; + bool wmmQosConnection; +}; + +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[]; + +#define WLAN_HDD_MAX_DSCP 0x3f + +/** + * 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_wmm_init() - initialize the WMM DSCP configuation + * @adapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuation 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_init(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 configuation 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_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). + * + * 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(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_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 + * @acType: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter, + sme_ac_enum_type acType); + +/** + * hdd_wmm_acquire_access() - Function which will attempt to acquire + * admittance for a WMM AC + * + * @adapter: [in] pointer to adapter context + * @acType: [in] WMM AC type of OS packet + * @pGranted: [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 acType, bool *pGranted); + +/** + * hdd_wmm_assoc() - Function which will handle the housekeeping + * required by WMM when association takes place + * + * @adapter: [in] pointer to adapter context + * @roam_info: [in] pointer to roam information + * @eBssType: [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + eCsrRoamBssType eBssType); + +/** + * 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 + * @eBssType : [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + eCsrRoamBssType eBssType); + +/** + * hdd_wmm_get_uapsd_mask() - Function which will calculate the + * initial value of the UAPSD mask based upon the device configuration + * + * @adapter : [in] pointer to adapter context + * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_get_uapsd_mask(struct hdd_adapter *adapter, + uint8_t *pUapsdMask); + +/** + * 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 + * @pTspec : [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 *pTspec); + +/** + * 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); +#endif /* #ifndef _WLAN_HDD_WMM_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h new file mode 100644 index 0000000000000000000000000000000000000000..1a6c35cf398cca2a6da59415e3e85e9303dc511b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h @@ -0,0 +1,155 @@ +/* + * 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. + */ + +#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 patern 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_apf.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_apf.c new file mode 100644 index 0000000000000000000000000000000000000000..74a509d179dbf537261bc7624bb107a2dac4ce70 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_apf.c @@ -0,0 +1,715 @@ +/* + * 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: wlan_hdd_apf.c + * + * Android Packet Filter support and implementation + */ + +#include "wlan_hdd_apf.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 + +static 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_context: 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 = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("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; + } + + cfg80211_vendor_cmd_reply(skb); + hdd_exit(); + return 0; + +nla_put_failure: + kfree_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; + + hdd_enter(); + + if (!hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + 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.total_length = nla_get_u32(tb[APF_PACKET_SIZE]); + + if (!apf_set_offload.total_length) { + hdd_debug("APF reset packet filter received"); + 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) { + hdd_err("qdf_mem_malloc failed for apf offload program"); + ret = -ENOMEM; + goto fail; + } + + apf_set_offload.current_length = prog_len; + nla_memcpy(apf_set_offload.program, tb[APF_PROGRAM], prog_len); + apf_set_offload.session_id = adapter->session_id; + + hdd_debug("APF set instructions"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + apf_set_offload.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 APF SET/RESET to SME, session_id: %d APF Version: %d filter ID: %d total_length: %d current_length: %d current 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; + + hdd_enter(); + + status = sme_set_apf_enable_disable(hdd_adapter_get_mac_handle(adapter), + adapter->session_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; + + hdd_exit(); + 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; + + hdd_enter(); + + + write_mem_params.vdev_id = adapter->session_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 == NULL) { + hdd_err("failed to alloc mem for apf write mem operation"); + 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; + } + + if (write_mem_params.buf) + qdf_mem_free(write_mem_params.buf); + + hdd_exit(); + return ret; +} + +/** + * hdd_apf_read_memory_callback - HDD Callback for the APF read memory + * operation + * @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_adapter *adapter; + struct hdd_apf_context *context; + uint8_t *buf_ptr; + uint32_t pkt_offset; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx) || !evt) { + hdd_err("HDD context is invalid or event buf(%pK) is null", + evt); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, evt->vdev_id); + if (hdd_validate_adapter(adapter)) + return; + context = &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; + + hdd_enter(); + + if (context->apf_enabled) { + hdd_err("Cannot get/set while interpreter is enabled"); + return -EINVAL; + } + + read_mem_params.vdev_id = adapter->session_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]); + + /* 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 == NULL) { + hdd_err("alloc failed for cumulative event buffer"); + 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(hdd_adapter_get_mac_handle(adapter), + &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 = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("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"); + kfree_skb(skb); + ret = -EINVAL; + goto fail; + } + + cfg80211_vendor_cmd_reply(skb); +fail: + if (context->buf) { + qdf_mem_free(context->buf); + context->buf = NULL; + } + + hdd_exit(); + 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(); + + 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 (!hdd_ctx->apf_supported) { + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_apf_offload(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c new file mode 100644 index 0000000000000000000000000000000000000000..0dcc7d5a3d4b4e70ebb5c2cb7945bbeffb4e8460 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c @@ -0,0 +1,5699 @@ +/* + * 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: 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 +#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_scan.h" + +#include "wlan_hdd_nud_tracking.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 }; + +#ifdef WLAN_FEATURE_11W +/* 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 }; +#endif + +/* 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}; + +/* 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 +uint8_t ccp_rsn_oui_80[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x08}; +uint8_t ccp_rsn_oui_90[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x09}; +#endif + +/* Offset where the EID-Len-IE, start. */ +#define FT_ASSOC_RSP_IES_OFFSET 6 /* Capability(2) + AID(2) + Status Code(2) */ +#define FT_ASSOC_REQ_IES_OFFSET 4 /* Capability(2) + LI(2) */ + +#define BEACON_FRAME_IES_OFFSET 12 +#define HDD_PEER_AUTHORIZE_WAIT 10 + +/** + * beacon_filter_table - table of IEs used for beacon filtering + */ +static const int beacon_filter_table[] = { + SIR_MAC_DS_PARAM_SET_EID, + SIR_MAC_ERP_INFO_EID, + SIR_MAC_EDCA_PARAM_SET_EID, + SIR_MAC_QOS_CAPABILITY_EID, + SIR_MAC_HT_INFO_EID, + SIR_MAC_VHT_OPMODE_EID, + SIR_MAC_VHT_OPERATION_EID, +#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. + */ + SIR_MAC_EID_VENDOR, +#endif +}; + +#if defined(WLAN_FEATURE_SAE) && \ + defined(CFG80211_EXTERNAL_AUTH_SUPPORT) +/** + * wlan_hdd_sae_callback() - Sends SAE info to supplicant + * @adapter: pointer adapter context + * @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 hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + 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}; + + 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 = 0x00; + params.key_mgmt_suite |= 0x0F << 8; + params.key_mgmt_suite |= 0xAC << 16; + params.key_mgmt_suite |= 0x8 << 24; + + params.action = NL80211_EXTERNAL_AUTH_START; + qdf_mem_copy(params.bssid, sae_info->peer_mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + 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 hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ } +#endif + +/** + * hdd_conn_set_authenticated() - set authentication state + * @adapter: pointer to the adapter + * @auth_state: authentication state + * + * This function updates the global HDD station context + * authentication state. + * + * Return: none + */ +static void +hdd_conn_set_authenticated(struct hdd_adapter *adapter, uint8_t auth_state) +{ + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + char *auth_time; + uint32_t time_buffer_size; + + /* save the new connection state */ + hdd_debug("Authenticated state Changed from oldState:%d to State:%d", + sta_ctx->conn_info.uIsAuthenticated, auth_state); + sta_ctx->conn_info.uIsAuthenticated = auth_state; + + 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); + +} + +/** + * 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) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + char *connect_time; + uint32_t time_buffer_size; + + /* save the new connection state */ + hdd_debug("Changed conn state from old:%d to new:%d for dev %s", + hdd_sta_ctx->conn_info.connState, conn_state, + adapter->dev->name); + + hdd_tsf_notify_wlan_state_change(adapter, + hdd_sta_ctx->conn_info.connState, + conn_state); + hdd_sta_ctx->conn_info.connState = conn_state; + + connect_time = hdd_sta_ctx->conn_info.connect_time; + time_buffer_size = sizeof(hdd_sta_ctx->conn_info.connect_time); + if (conn_state == eConnectionState_Associated) + qdf_get_time_of_the_day_in_hr_min_sec_usec(connect_time, + time_buffer_size); + else + qdf_mem_zero(connect_time, time_buffer_size); + +} + +/** + * hdd_conn_get_connection_state() - get connection state + * @adapter: pointer to the adapter + * @pConnState: pointer to connection state + * + * This function updates the global HDD station context connection state. + * + * Return: true if (Infra Associated or IBSS Connected) + * and sets output parameter pConnState; + * false otherwise + */ +static inline bool +hdd_conn_get_connection_state(struct hdd_station_ctx *sta_ctx, + eConnectionState *out_state) +{ + eConnectionState state = sta_ctx->conn_info.connState; + + if (out_state) + *out_state = state; + + switch (state) { + case eConnectionState_Associated: + case eConnectionState_IbssConnected: + case eConnectionState_IbssDisconnected: + case eConnectionState_NdiConnected: + return true; + default: + return false; + } +} + +bool hdd_is_connecting(struct hdd_station_ctx *hdd_sta_ctx) +{ + return hdd_sta_ctx->conn_info.connState == + eConnectionState_Connecting; +} + +bool hdd_conn_is_connected(struct hdd_station_ctx *sta_ctx) +{ + return hdd_conn_get_connection_state(sta_ctx, NULL); +} + +bool hdd_adapter_is_connected_sta(struct hdd_adapter *adapter) +{ + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_NDI_MODE: + return hdd_conn_is_connected(&adapter->session.station); + default: + return false; + } +} + +enum band_info hdd_conn_get_connected_band(struct hdd_station_ctx *sta_ctx) +{ + uint8_t staChannel = 0; + + if (eConnectionState_Associated == sta_ctx->conn_info.connState) + staChannel = sta_ctx->conn_info.operationChannel; + + if (staChannel > 0 && staChannel < 14) + return BAND_2G; + else if (staChannel >= 36 && staChannel <= 184) + 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 + * @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 hdd_station_ctx *sta_ctx, + eCsrEncryptionType *pConnectedCipherAlgo) +{ + bool connected = false; + + connected = hdd_conn_get_connection_state(sta_ctx, NULL); + + if (pConnectedCipherAlgo) + *pConnectedCipherAlgo = sta_ctx->conn_info.ucEncryptionType; + + return connected; +} + +struct hdd_adapter *hdd_get_sta_connection_in_progress( + struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_station_ctx *hdd_sta_ctx; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return NULL; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode) || + (QDF_P2P_DEVICE_MODE == adapter->device_mode)) { + if (eConnectionState_Connecting == + hdd_sta_ctx->conn_info.connState) { + hdd_debug("vdev_id %d: Connection is in progress", + adapter->session_id); + return adapter; + } else if ((eConnectionState_Associated == + hdd_sta_ctx->conn_info.connState) && + sme_is_sta_key_exchange_in_progress( + hdd_ctx->mac_handle, + adapter->session_id)) { + hdd_debug("vdev_id %d: Key exchange is in progress", + adapter->session_id); + return adapter; + } + } + } + return NULL; +} + +void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *sta_adapter; + QDF_STATUS status; + + sta_adapter = hdd_get_sta_connection_in_progress(hdd_ctx); + if (sta_adapter) { + hdd_debug("Disconnecting STA on vdev: %d", + sta_adapter->session_id); + status = wlan_hdd_disconnect(sta_adapter, + eCSR_DISCONNECT_REASON_DEAUTH); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("wlan_hdd_disconnect failed, status: %d", + status); + } + } +} + +/** + * hdd_remove_beacon_filter() - remove beacon filter + * @adapter: Pointer to the hdd adapter + * + * Return: 0 on success and errno on failure + */ +static 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->session_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_remove_beacon_filter() failed"); + return -EFAULT; + } + + return 0; +} + +/** + * hdd_add_beacon_filter() - add beacon filter + * @adapter: Pointer to the hdd adapter + * + * Return: 0 on success and errno on failure + */ +static 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 int *)ie_map); + + status = sme_add_beacon_filter(hdd_ctx->mac_handle, + adapter->session_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 + +/** + * hdd_copy_ht_operation()- copy HT operation element from roam info to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_copy_ht_operation(struct hdd_station_ctx *hdd_sta_ctx, + struct csr_roam_info *roam_info) +{ + tDot11fIEHTInfo *roam_ht_ops = &roam_info->ht_operation; + 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 = roam_ht_ops->primaryChannel; + + /* HT_PARAMS */ + temp_ht_ops = roam_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 (roam_ht_ops->recommendedTxWidthSet) + hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; + if (roam_ht_ops->rifsMode) + hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_RIFS_MODE; + if (roam_ht_ops->controlledAccessOnly) + hdd_ht_ops->ht_param |= HT_PARAM_CONTROLLED_ACCESS_ONLY; + temp_ht_ops = roam_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 = roam_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 (roam_ht_ops->nonGFDevicesPresent) + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT; + if (roam_ht_ops->transmitBurstLimit) + hdd_ht_ops->operation_mode |= + HT_OP_MODE_TX_BURST_LIMIT; + if (roam_ht_ops->obssNonHTStaPresent) + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; + + /* stbc_param */ + temp_ht_ops = roam_ht_ops->basicSTBCMCS & + HT_STBC_PARAM_MCS; + if (temp_ht_ops) + hdd_ht_ops->stbc_param |= temp_ht_ops; + if (roam_ht_ops->dualCTSProtection) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT; + if (roam_ht_ops->secondaryBeacon) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_STBC_BEACON; + if (roam_ht_ops->lsigTXOPProtectionFullSupport) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT; + if (roam_ht_ops->pcoActive) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_PCO_ACTIVE; + if (roam_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] = + roam_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->chanCenterFreqSeg1; + ieee_ops->center_freq_seg1_idx = roam_ops->chanCenterFreqSeg2; +} +#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->chanCenterFreqSeg1; + ieee_ops->center_freq_seg2_idx = roam_ops->chanCenterFreqSeg2; +} +#endif /* KERNEL_VERSION(4, 12, 0) */ + +/** + * hdd_copy_vht_operation()- copy VHT operations element from roam info to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_copy_vht_operation(struct hdd_station_ctx *hdd_sta_ctx, + struct csr_roam_info *roam_info) +{ + tDot11fIEVHTOperation *roam_vht_ops = &roam_info->vht_operation; + 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 = roam_vht_ops->chanWidth; + hdd_copy_vht_center_freq(hdd_vht_ops, roam_vht_ops); + hdd_vht_ops->basic_mcs_set = roam_vht_ops->basicMCSSet; +} + + +/** + * hdd_save_bss_info() - save connection info in hdd sta ctx + * @adapter: Pointer to adapter + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_save_bss_info(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_sta_ctx->conn_info.freq = cds_chan_to_freq( + hdd_sta_ctx->conn_info.operationChannel); + if (roam_info->vht_caps.present) { + hdd_sta_ctx->conn_info.conn_flag.vht_present = true; + hdd_copy_vht_caps(&hdd_sta_ctx->conn_info.vht_caps, + &roam_info->vht_caps); + } else { + hdd_sta_ctx->conn_info.conn_flag.vht_present = false; + } + if (roam_info->ht_caps.present) { + hdd_sta_ctx->conn_info.conn_flag.ht_present = true; + hdd_copy_ht_caps(&hdd_sta_ctx->conn_info.ht_caps, + &roam_info->ht_caps); + } else { + hdd_sta_ctx->conn_info.conn_flag.ht_present = false; + } + if (roam_info->reassoc) + hdd_sta_ctx->conn_info.roam_count++; + if (roam_info->hs20vendor_ie.present) { + hdd_sta_ctx->conn_info.conn_flag.hs20_present = true; + qdf_mem_copy(&hdd_sta_ctx->conn_info.hs20vendor_ie, + &roam_info->hs20vendor_ie, + sizeof(roam_info->hs20vendor_ie)); + } else { + hdd_sta_ctx->conn_info.conn_flag.hs20_present = false; + } + if (roam_info->ht_operation.present) { + hdd_sta_ctx->conn_info.conn_flag.ht_op_present = true; + hdd_copy_ht_operation(hdd_sta_ctx, roam_info); + } else { + hdd_sta_ctx->conn_info.conn_flag.ht_op_present = false; + } + if (roam_info->vht_operation.present) { + hdd_sta_ctx->conn_info.conn_flag.vht_op_present = true; + hdd_copy_vht_operation(hdd_sta_ctx, roam_info); + } else { + hdd_sta_ctx->conn_info.conn_flag.vht_op_present = false; + } + /* 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_conn_save_connect_info() - save current connection information + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @eBssType: bss type + * + * Return: none + */ +static void +hdd_conn_save_connect_info(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + eCsrRoamBssType eBssType) +{ + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + eCsrEncryptionType encryptType = eCSR_ENCRYPT_TYPE_NONE; + + QDF_ASSERT(roam_info); + + if (roam_info) { + /* Save the BSSID for the connection */ + if (eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) { + QDF_ASSERT(roam_info->pBssDesc); + qdf_copy_macaddr(&sta_ctx->conn_info.bssId, + &roam_info->bssid); + + /* + * Save the Station ID for this station from + * the 'Roam Info'. For IBSS mode, staId is + * assigned in NEW_PEER_IND. For reassoc, + * the staID doesn't change and it may be invalid + * in this structure so no change here. + */ + if (!roam_info->fReassocReq) { + sta_ctx->conn_info.staId[0] = + roam_info->staId; + } + } else if (eCSR_BSS_TYPE_IBSS == eBssType) { + qdf_copy_macaddr(&sta_ctx->conn_info.bssId, + &roam_info->bssid); + } else { + /* + * can't happen. We need a valid IBSS or Infra setting + * in the BSSDescription or we can't function. + */ + QDF_ASSERT(0); + } + + /* notify WMM */ + hdd_wmm_connect(adapter, roam_info, eBssType); + + if (!roam_info->u.pConnectedProfile) { + QDF_ASSERT(roam_info->u.pConnectedProfile); + } else { + /* Get Multicast Encryption Type */ + encryptType = + roam_info->u.pConnectedProfile->mcEncryptionType; + sta_ctx->conn_info.mcEncryptionType = encryptType; + /* Get Unicast Encryption Type */ + encryptType = + roam_info->u.pConnectedProfile->EncryptionType; + sta_ctx->conn_info.ucEncryptionType = encryptType; + + sta_ctx->conn_info.authType = + roam_info->u.pConnectedProfile->AuthType; + sta_ctx->conn_info.last_auth_type = + sta_ctx->conn_info.authType; + + sta_ctx->conn_info.operationChannel = + roam_info->u.pConnectedProfile->operationChannel; + + /* Save the ssid for the connection */ + qdf_mem_copy(&sta_ctx->conn_info.SSID.SSID, + &roam_info->u.pConnectedProfile->SSID, + sizeof(tSirMacSSid)); + qdf_mem_copy(&sta_ctx->conn_info.last_ssid.SSID, + &roam_info->u.pConnectedProfile->SSID, + sizeof(tSirMacSSid)); + + /* Save dot11mode in which STA associated to AP */ + sta_ctx->conn_info.dot11Mode = + roam_info->u.pConnectedProfile->dot11Mode; + + sta_ctx->conn_info.proxyARPService = + roam_info->u.pConnectedProfile->proxyARPService; + + sta_ctx->conn_info.nss = roam_info->chan_info.nss; + + sta_ctx->conn_info.rate_flags = + roam_info->chan_info.rate_flags; + + sta_ctx->conn_info.ch_width = + roam_info->chan_info.ch_width; + } + hdd_save_bss_info(adapter, roam_info); + } +} + +/** + * hdd_send_ft_assoc_response() - send fast transition assoc response + * @dev: pointer to net device + * @adapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Send the 11R key information to the supplicant. Only then can the supplicant + * generate the PMK-R1. (BTW, the ESE supplicant also needs the Assoc Resp IEs + * for the same purpose.) + * + * Mainly the Assoc Rsp IEs are passed here. For the IMDA this contains the + * R1KHID, R0KHID and the MDID. For FT, this consists of the Reassoc Rsp FTIEs. + * This is the Assoc Response. + * + * Return: none + */ +static void +hdd_send_ft_assoc_response(struct net_device *dev, + struct hdd_adapter *adapter, + struct csr_roam_info *pCsrRoamInfo) +{ + union iwreq_data wrqu; + char *buff; + unsigned int len = 0; + u8 *pFTAssocRsp = NULL; + + if (pCsrRoamInfo->nAssocRspLength == 0) { + hdd_debug("assoc rsp length is 0"); + return; + } + + pFTAssocRsp = + (u8 *) (pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength + + pCsrRoamInfo->nAssocReqLength); + if (pFTAssocRsp == NULL) { + hdd_debug("AssocReq or AssocRsp is NULL"); + return; + } + /* pFTAssocRsp needs to point to the IEs */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hdd_debug("AssocRsp is now at %02x%02x", + (unsigned int)pFTAssocRsp[0], + (unsigned int)pFTAssocRsp[1]); + + /* We need to send the IEs to the supplicant. */ + buff = qdf_mem_malloc(IW_GENERIC_IE_MAX); + if (buff == NULL) { + hdd_err("unable to allocate memory"); + return; + } + /* Send the Assoc Resp, the supplicant needs this for initial Auth. */ + len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET; + wrqu.data.length = len; + memcpy(buff, pFTAssocRsp, len); + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, buff); + + qdf_mem_free(buff); +} + +/** + * hdd_send_ft_event() - send fast transition event + * @adapter: pointer to adapter + * + * Send the FTIEs, RIC IEs during FT. This is eventually used to send the + * FT events to the supplicant. At the reception of Auth2 we send the RIC + * followed by the auth response IEs to the supplicant. + * Once both are received in the supplicant, an FT event is generated + * to the supplicant. + * + * Return: none + */ +static void hdd_send_ft_event(struct hdd_adapter *adapter) +{ + uint16_t auth_resp_len = 0; + uint32_t ric_ies_length = 0; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + mac_handle_t mac_handle; + +#if defined(KERNEL_SUPPORT_11R_CFG80211) + struct cfg80211_ft_event_params ftEvent; + uint8_t ftIe[DOT11F_IE_FTINFO_MAX_LEN]; + uint8_t ricIe[DOT11F_IE_RICDESCRIPTOR_MAX_LEN]; + struct net_device *dev = adapter->dev; +#else + char *buff; + union iwreq_data wrqu; + uint16_t str_len; +#endif + + mac_handle = hdd_ctx->mac_handle; +#if defined(KERNEL_SUPPORT_11R_CFG80211) + qdf_mem_zero(ftIe, DOT11F_IE_FTINFO_MAX_LEN); + qdf_mem_zero(ricIe, DOT11F_IE_RICDESCRIPTOR_MAX_LEN); + + sme_get_rici_es(mac_handle, adapter->session_id, (u8 *) ricIe, + DOT11F_IE_RICDESCRIPTOR_MAX_LEN, &ric_ies_length); + if (ric_ies_length == 0) + hdd_warn("Do not send RIC IEs as length is 0"); + + ftEvent.ric_ies = ricIe; + ftEvent.ric_ies_len = ric_ies_length; + hdd_debug("RIC IEs is of length %d", (int)ric_ies_length); + + sme_get_ft_pre_auth_response(mac_handle, adapter->session_id, + (u8 *) ftIe, DOT11F_IE_FTINFO_MAX_LEN, + &auth_resp_len); + + if (auth_resp_len == 0) { + hdd_debug("AuthRsp FTIES is of length 0"); + return; + } + + sme_set_ft_pre_auth_state(mac_handle, adapter->session_id, true); + + ftEvent.target_ap = ftIe; + + ftEvent.ies = (u8 *) (ftIe + QDF_MAC_ADDR_SIZE); + ftEvent.ies_len = auth_resp_len - QDF_MAC_ADDR_SIZE; + + hdd_debug("ftEvent.ies_len %zu", ftEvent.ies_len); + hdd_debug("ftEvent.ric_ies_len %zu", ftEvent.ric_ies_len); + hdd_debug("ftEvent.target_ap %2x-%2x-%2x-%2x-%2x-%2x", + ftEvent.target_ap[0], ftEvent.target_ap[1], + ftEvent.target_ap[2], ftEvent.target_ap[3], ftEvent.target_ap[4], + ftEvent.target_ap[5]); + + (void)cfg80211_ft_event(dev, &ftEvent); + +#else + /* We need to send the IEs to the supplicant */ + buff = qdf_mem_malloc(IW_CUSTOM_MAX); + if (buff == NULL) { + hdd_err("unable to allocate memory"); + return; + } + + /* Sme needs to send the RIC IEs first */ + str_len = strlcpy(buff, "RIC=", IW_CUSTOM_MAX); + sme_get_rici_es(mac_handle, adapter->session_id, + (u8 *) &(buff[str_len]), (IW_CUSTOM_MAX - str_len), + &ric_ies_length); + if (ric_ies_length == 0) { + hdd_warn("Do not send RIC IEs as length is 0"); + } else { + wrqu.data.length = str_len + ric_ies_length; + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buff); + } + + /* Sme needs to provide the Auth Resp */ + qdf_mem_zero(buff, IW_CUSTOM_MAX); + str_len = strlcpy(buff, "AUTH=", IW_CUSTOM_MAX); + sme_get_ft_pre_auth_response(mac_handle, adapter->session_id, + (u8 *) &buff[str_len], + (IW_CUSTOM_MAX - str_len), &auth_resp_len); + + if (auth_resp_len == 0) { + qdf_mem_free(buff); + hdd_debug("AuthRsp FTIES is of length 0"); + return; + } + + wrqu.data.length = str_len + auth_resp_len; + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buff); + + qdf_mem_free(buff); +#endif +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_send_new_ap_channel_info() - send new ap channel info + * @dev: pointer to net device + * @adapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Send the ESE required "new AP Channel info" to the supplicant. + * (This keeps the supplicant "up to date" on the current channel.) + * + * The current (new AP) channel information is passed in. + * + * Return: none + */ +static void +hdd_send_new_ap_channel_info(struct net_device *dev, + struct hdd_adapter *adapter, + struct csr_roam_info *pCsrRoamInfo) +{ + union iwreq_data wrqu; + struct bss_description *descriptor = pCsrRoamInfo->pBssDesc; + + if (descriptor == NULL) { + hdd_err("bss descriptor is null"); + return; + } + /* + * Send the Channel event, the supplicant needs this to generate + * the Adjacent AP report. + */ + hdd_debug("Sending up an SIOCGIWFREQ, channelId: %d", + descriptor->channelId); + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.freq.m = descriptor->channelId; + wrqu.freq.e = 0; + wrqu.freq.i = 0; + wireless_send_event(adapter->dev, SIOCGIWFREQ, &wrqu, NULL); +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_send_update_beacon_ies_event() - send update beacons ie event + * @adapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void +hdd_send_update_beacon_ies_event(struct hdd_adapter *adapter, + struct csr_roam_info *pCsrRoamInfo) +{ + union iwreq_data wrqu; + u8 *beacon_ies; + u8 currentLen = 0; + char *buff; + int totalIeLen = 0, currentOffset = 0, strLen; + + memset(&wrqu, '\0', sizeof(wrqu)); + + if (0 == pCsrRoamInfo->nBeaconLength) { + hdd_debug("beacon frame length is 0"); + return; + } + beacon_ies = (u8 *) (pCsrRoamInfo->pbFrames + BEACON_FRAME_IES_OFFSET); + if (beacon_ies == NULL) { + hdd_warn("Beacon IEs is NULL"); + return; + } + /* beacon_ies needs to point to the IEs */ + hdd_debug("Beacon IEs is now at %02x%02x", + (unsigned int)beacon_ies[0], + (unsigned int)beacon_ies[1]); + hdd_debug("Beacon IEs length = %d", + pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET); + + /* We need to send the IEs to the supplicant. */ + buff = qdf_mem_malloc(IW_CUSTOM_MAX); + if (buff == NULL) { + hdd_err("unable to allocate memory"); + return; + } + + strLen = strlcpy(buff, "BEACONIEs=", IW_CUSTOM_MAX); + currentLen = strLen + 1; + + totalIeLen = pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET; + do { + /* + * If the beacon size exceeds max CUSTOM event size, break it + * into chunks of CUSTOM event max size and send it to + * supplicant. Changes are done in supplicant to handle this. + */ + qdf_mem_zero(&buff[strLen + 1], IW_CUSTOM_MAX - (strLen + 1)); + currentLen = + QDF_MIN(totalIeLen, IW_CUSTOM_MAX - (strLen + 1) - 1); + qdf_mem_copy(&buff[strLen + 1], beacon_ies + currentOffset, + currentLen); + currentOffset += currentLen; + totalIeLen -= currentLen; + wrqu.data.length = strLen + 1 + currentLen; + if (totalIeLen) + buff[strLen] = 1; /* more chunks pending */ + else + buff[strLen] = 0; /* last chunk */ + + hdd_debug("Beacon IEs length to supplicant = %d", + currentLen); + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buff); + } while (totalIeLen > 0); + + qdf_mem_free(buff); +} + +/** + * hdd_send_association_event() - send association event + * @dev: pointer to net device + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void hdd_send_association_event(struct net_device *dev, + struct csr_roam_info *pCsrRoamInfo) +{ + int ret; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + union iwreq_data wrqu; + int we_event; + char *msg; + struct qdf_mac_addr peerMacAddr; + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + we_event = SIOCGIWAP; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (NULL != pCsrRoamInfo) + if (pCsrRoamInfo->roamSynchInProgress) { + /* change logging before release */ + hdd_debug("LFR3:hdd_send_association_event"); + /* Update tdls module about the disconnection event */ + hdd_notify_sta_disconnect(adapter->session_id, + true, false, + adapter->vdev); + } +#endif + if (eConnectionState_Associated == sta_ctx->conn_info.connState) { + tSirSmeChanInfo chan_info = {0}; + + if (!pCsrRoamInfo || !pCsrRoamInfo->pBssDesc) { + hdd_warn("STA in associated state but pCsrRoamInfo is null"); + return; + } + + if (!hdd_is_roam_sync_in_progress(pCsrRoamInfo)) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + adapter->device_mode, adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, + adapter->device_mode, true); + } + memcpy(wrqu.ap_addr.sa_data, pCsrRoamInfo->pBssDesc->bssId, + sizeof(pCsrRoamInfo->pBssDesc->bssId)); + + ucfg_p2p_status_connect(adapter->vdev); + + hdd_info("wlan: " MAC_ADDRESS_STR " connected to " + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(adapter->mac_addr.bytes), + MAC_ADDR_ARRAY(wrqu.ap_addr.sa_data)); + hdd_send_update_beacon_ies_event(adapter, pCsrRoamInfo); + + /* + * Send IWEVASSOCRESPIE Event if WLAN_FEATURE_CIQ_METRICS + * is Enabled Or Send IWEVASSOCRESPIE Event if + * fFTEnable is true. + * Send FT Keys to the supplicant when FT is enabled + */ + if ((roam_profile->AuthType.authType[0] == + eCSR_AUTH_TYPE_FT_RSN_PSK) + || (roam_profile->AuthType.authType[0] == + eCSR_AUTH_TYPE_FT_RSN) +#ifdef FEATURE_WLAN_ESE + || (roam_profile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_RSN) + || (roam_profile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_WPA) +#endif + ) { + hdd_send_ft_assoc_response(dev, adapter, pCsrRoamInfo); + } + qdf_copy_macaddr(&peerMacAddr, + &sta_ctx->conn_info.bssId); + chan_info.chan_id = pCsrRoamInfo->chan_info.chan_id; + chan_info.mhz = pCsrRoamInfo->chan_info.mhz; + chan_info.info = pCsrRoamInfo->chan_info.info; + chan_info.band_center_freq1 = + pCsrRoamInfo->chan_info.band_center_freq1; + chan_info.band_center_freq2 = + pCsrRoamInfo->chan_info.band_center_freq2; + chan_info.reg_info_1 = + pCsrRoamInfo->chan_info.reg_info_1; + chan_info.reg_info_2 = + pCsrRoamInfo->chan_info.reg_info_2; + + ret = hdd_objmgr_set_peer_mlme_state(adapter->vdev, + WLAN_ASSOC_STATE); + if (ret) + hdd_err("Peer object %pM fail to set associated state", + peerMacAddr.bytes); + + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_app(&peerMacAddr, + ePeerConnected, + pCsrRoamInfo->timingMeasCap, + adapter->session_id, &chan_info, + adapter->device_mode); + /* Update tdls module about connection event */ + hdd_notify_sta_connect(adapter->session_id, + pCsrRoamInfo->tdls_chan_swit_prohibited, + pCsrRoamInfo->tdls_prohibited, + adapter->vdev); + +#ifdef MSM_PLATFORM + /* start timer in sta/p2p_cli */ + spin_lock_bh(&hdd_ctx->bus_bw_lock); + adapter->prev_tx_packets = adapter->stats.tx_packets; + adapter->prev_rx_packets = adapter->stats.rx_packets; + cdp_get_intra_bss_fwd_pkts_count( + cds_get_context(QDF_MODULE_ID_SOC), adapter->session_id, + &adapter->prev_fwd_tx_packets, + &adapter->prev_fwd_rx_packets); + spin_unlock_bh(&hdd_ctx->bus_bw_lock); + hdd_bus_bw_compute_timer_start(hdd_ctx); +#endif + } else if (eConnectionState_IbssConnected == /* IBss Associated */ + sta_ctx->conn_info.connState) { + policy_mgr_update_connection_info(hdd_ctx->psoc, + adapter->session_id); + memcpy(wrqu.ap_addr.sa_data, sta_ctx->conn_info.bssId.bytes, + ETH_ALEN); + hdd_debug("wlan: new IBSS peer connection to BSSID " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(sta_ctx->conn_info.bssId.bytes)); + } else { /* Not Associated */ + hdd_info("wlan: disconnected"); + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(hdd_ctx, true); +#endif + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + qdf_copy_macaddr(&peerMacAddr, + &sta_ctx->conn_info.bssId); + + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_app(&peerMacAddr, + ePeerDisconnected, 0, + adapter->session_id, + NULL, + adapter->device_mode); + } + + hdd_lpass_notify_disconnect(adapter); + /* Update tdls module about the disconnection event */ + hdd_notify_sta_disconnect(adapter->session_id, + false, + false, + adapter->vdev); + +#ifdef MSM_PLATFORM + /* stop timer in sta/p2p_cli */ + spin_lock_bh(&hdd_ctx->bus_bw_lock); + adapter->prev_tx_packets = 0; + adapter->prev_rx_packets = 0; + adapter->prev_fwd_tx_packets = 0; + adapter->prev_fwd_rx_packets = 0; + spin_unlock_bh(&hdd_ctx->bus_bw_lock); + hdd_bus_bw_compute_timer_try_stop(hdd_ctx); +#endif + } + hdd_ipa_set_tx_flow_info(); + + msg = NULL; + /* During the WLAN uninitialization,supplicant is stopped before the + * driver so not sending the status of the connection to supplicant + */ + if (cds_is_load_or_unload_in_progress()) { + wireless_send_event(dev, we_event, &wrqu, msg); +#ifdef FEATURE_WLAN_ESE + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) { + if ((roam_profile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_RSN) || + (roam_profile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_WPA)) + hdd_send_new_ap_channel_info(dev, adapter, + pCsrRoamInfo); + } +#endif + } +} + +/** + * hdd_conn_remove_connect_info() - remove connection info + * @sta_ctx: pointer to global HDD station context + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void hdd_conn_remove_connect_info(struct hdd_station_ctx *sta_ctx) +{ + /* Remove staId, bssId and peerMacAddress */ + sta_ctx->conn_info.staId[0] = HDD_WLAN_INVALID_STA_ID; + qdf_mem_zero(&sta_ctx->conn_info.bssId, QDF_MAC_ADDR_SIZE); + qdf_mem_zero(&sta_ctx->conn_info.peerMacAddress[0], + QDF_MAC_ADDR_SIZE); + + /* Clear all security settings */ + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + sta_ctx->conn_info.mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + sta_ctx->conn_info.ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + + qdf_mem_zero(&sta_ctx->conn_info.Keys, sizeof(tCsrKeys)); + qdf_mem_zero(&sta_ctx->ibss_enc_key, sizeof(tCsrRoamSetKey)); + + sta_ctx->conn_info.proxyARPService = 0; + + qdf_mem_zero(&sta_ctx->conn_info.SSID, sizeof(tCsrSSIDInfo)); +} + +/** + * hdd_clear_roam_profile_ie() - Clear Roam Profile IEs + * @adapter: adapter who's IEs are to be cleared + * + * Return: None + */ +static void hdd_clear_roam_profile_ie(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + struct csr_roam_profile *roam_profile; + + hdd_enter(); + + /* clear WPA/RSN/WSC IE information in the profile */ + roam_profile = hdd_roam_profile(adapter); + + roam_profile->nWPAReqIELength = 0; + roam_profile->pWPAReqIE = NULL; + roam_profile->nRSNReqIELength = 0; + roam_profile->pRSNReqIE = NULL; + +#ifdef FEATURE_WLAN_WAPI + roam_profile->nWAPIReqIELength = 0; + roam_profile->pWAPIReqIE = NULL; +#endif + + roam_profile->bWPSAssociation = false; + roam_profile->bOSENAssociation = false; + roam_profile->pAddIEScan = NULL; + roam_profile->nAddIEScanLength = 0; + roam_profile->pAddIEAssoc = NULL; + roam_profile->nAddIEAssocLength = 0; + + roam_profile->EncryptionType.numEntries = 1; + roam_profile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + roam_profile->mcEncryptionType.numEntries = 1; + roam_profile->mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + roam_profile->AuthType.numEntries = 1; + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + + qdf_mem_zero(roam_profile->bssid_hint.bytes, QDF_MAC_ADDR_SIZE); + +#ifdef WLAN_FEATURE_11W + roam_profile->MFPEnabled = false; + roam_profile->MFPRequired = 0; + roam_profile->MFPCapable = 0; +#endif + + qdf_mem_zero(roam_profile->Keys.KeyLength, CSR_MAX_NUM_KEY); + qdf_mem_zero(roam_profile->Keys.KeyMaterial, + sizeof(roam_profile->Keys.KeyMaterial)); +#ifdef FEATURE_WLAN_WAPI + adapter->wapi_info.wapi_auth_mode = WAPI_AUTH_MODE_OPEN; + adapter->wapi_info.wapi_mode = false; +#endif + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + sta_ctx->auth_key_mgmt = 0; + qdf_zero_macaddr(&sta_ctx->requested_bssid); + hdd_clear_fils_connection_info(adapter); + hdd_exit(); +} + +/** + * hdd_roam_deregister_sta() - deregister station + * @adapter: pointer to adapter + * @staId: station identifier + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_deregister_sta(struct hdd_adapter *adapter, uint8_t staid) +{ + QDF_STATUS qdf_status; + + qdf_status = cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_pdev *)cds_get_context(QDF_MODULE_ID_TXRX), + staid); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("cdp_clear_peer() failed for staid %d. Status(%d) [0x%08X]", + staid, qdf_status, qdf_status); + } + + return qdf_status; +} + +/** + * hdd_print_bss_info() - print bss info + * @hdd_sta_ctx: pointer to hdd station context + * + * Return: None + */ +static void hdd_print_bss_info(struct hdd_station_ctx *hdd_sta_ctx) +{ + uint32_t *cap_info; + + hdd_debug("WIFI DATA LOGGER"); + hdd_debug("channel: %d", + hdd_sta_ctx->conn_info.freq); + hdd_debug("dot11mode: %d", + hdd_sta_ctx->conn_info.dot11Mode); + hdd_debug("AKM: %d", + hdd_sta_ctx->conn_info.last_auth_type); + hdd_debug("ssid: %.*s", + hdd_sta_ctx->conn_info.last_ssid.SSID.length, + hdd_sta_ctx->conn_info.last_ssid.SSID.ssId); + hdd_debug("roam count: %d", + hdd_sta_ctx->conn_info.roam_count); + hdd_debug("ant_info: %d", + hdd_sta_ctx->conn_info.txrate.nss); + hdd_debug("datarate legacy %d", + hdd_sta_ctx->conn_info.txrate.legacy); + hdd_debug("datarate mcs: %d", + hdd_sta_ctx->conn_info.txrate.mcs); + if (hdd_sta_ctx->conn_info.conn_flag.ht_present) { + cap_info = (uint32_t *)&hdd_sta_ctx->conn_info.ht_caps; + hdd_debug("ht caps: %x", *cap_info); + } + if (hdd_sta_ctx->conn_info.conn_flag.vht_present) { + cap_info = (uint32_t *)&hdd_sta_ctx->conn_info.vht_caps; + hdd_debug("vht caps: %x", *cap_info); + } + if (hdd_sta_ctx->conn_info.conn_flag.hs20_present) + hdd_debug("hs20 info: %x", + hdd_sta_ctx->conn_info.hs20vendor_ie.release_num); + hdd_debug("signal: %d", + hdd_sta_ctx->conn_info.signal); + hdd_debug("noise: %d", + hdd_sta_ctx->conn_info.noise); +} + +/** + * hdd_dis_connect_handler() - disconnect event handler + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @roamId: roam identifier + * @roamStatus: roam status + * @roamResult: roam result + * + * This function handles disconnect event: + * 1. Disable transmit queues; + * 2. Clean up internal connection states and data structures; + * 3. Send disconnect indication to supplicant. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS hdd_dis_connect_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS vstatus; + struct net_device *dev = adapter->dev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + uint8_t sta_id; + bool sendDisconInd = true; + mac_handle_t mac_handle; + + if (dev == NULL) { + hdd_err("net_dev is released return"); + return QDF_STATUS_E_FAILURE; + } + /* notify apps that we can't pass traffic anymore */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + if (ucfg_ipa_is_enabled() && + (sta_ctx->conn_info.staId[0] != HDD_WLAN_INVALID_STA_ID)) + ucfg_ipa_wlan_evt(hdd_ctx->pdev, adapter->dev, + adapter->device_mode, + sta_ctx->conn_info.staId[0], + adapter->session_id, + WLAN_IPA_STA_DISCONNECT, + sta_ctx->conn_info.bssId.bytes); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(hdd_ctx, true); +#endif + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + adapter->session_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); + + /* HDD has initiated disconnect, do not send disconnect indication + * to kernel. Sending disconnected event to kernel for userspace + * initiated disconnect will be handled by disconnect handler call + * to cfg80211_disconnected. + */ + if ((eConnectionState_Disconnecting == + sta_ctx->conn_info.connState) || + (eConnectionState_NotConnected == + sta_ctx->conn_info.connState) || + (eConnectionState_Connecting == + sta_ctx->conn_info.connState)) { + hdd_debug("HDD has initiated a disconnect, no need to send disconnect indication to kernel"); + sendDisconInd = false; + } else { + INIT_COMPLETION(adapter->disconnect_comp_var); + hdd_conn_set_connection_state(adapter, + eConnectionState_Disconnecting); + } + + hdd_clear_roam_profile_ie(adapter); + hdd_wmm_init(adapter); + hdd_debug("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + + /* indicate 'disconnect' status to wpa_supplicant... */ + hdd_send_association_event(dev, roam_info); + /* indicate disconnected event to nl80211 */ + if (roamStatus != eCSR_ROAM_IBSS_LEAVE) { + /* + * Only send indication to kernel if not initiated + * by kernel + */ + if (sendDisconInd) { + /* + * To avoid wpa_supplicant sending "HANGED" CMD + * to ICS UI. + */ + if (eCSR_ROAM_LOSTLINK == roamStatus) { + if (roam_info->reasonCode == + eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON) + pr_info("wlan: disconnected due to poor signal, rssi is %d dB\n", + roam_info->rxRssi); + wlan_hdd_cfg80211_indicate_disconnect( + dev, false, + roam_info->reasonCode); + } else { + wlan_hdd_cfg80211_indicate_disconnect( + dev, false, + WLAN_REASON_UNSPECIFIED + ); + } + + hdd_debug("sent disconnected event to nl80211, reason code %d", + (eCSR_ROAM_LOSTLINK == roamStatus) ? + roam_info->reasonCode : + WLAN_REASON_UNSPECIFIED); + } + + /* update P2P connection status */ + ucfg_p2p_status_disconnect(adapter->vdev); + } + + hdd_wmm_adapter_clear(adapter); + mac_handle = hdd_ctx->mac_handle; + sme_ft_reset(mac_handle, adapter->session_id); + sme_reset_key(mac_handle, adapter->session_id); + if (hdd_remove_beacon_filter(adapter) != 0) + hdd_err("hdd_remove_beacon_filter() failed"); + + if (eCSR_ROAM_IBSS_LEAVE == roamStatus) { + uint8_t i; + + sta_id = sta_ctx->broadcast_staid; + vstatus = hdd_roam_deregister_sta(adapter, sta_id); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_err("hdd_roam_deregister_sta() failed for staID %d Status: %d [0x%x]", + sta_id, status, status); + status = QDF_STATUS_E_FAILURE; + } + if (sta_id < HDD_MAX_ADAPTERS) + hdd_ctx->sta_to_adapter[sta_id] = NULL; + else + hdd_debug("invalid sta id %d", sta_id); + /* Clear all the peer sta register with TL. */ + for (i = 0; i < MAX_PEERS; i++) { + if (HDD_WLAN_INVALID_STA_ID == + sta_ctx->conn_info.staId[i]) + continue; + sta_id = sta_ctx->conn_info.staId[i]; + hdd_debug("Deregister StaID %d", sta_id); + vstatus = hdd_roam_deregister_sta(adapter, sta_id); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_err("hdd_roam_deregister_sta() failed to for staID %d Status: %d [0x%x]", + sta_id, status, status); + status = QDF_STATUS_E_FAILURE; + } + /* set the staid and peer mac as 0, all other + * reset are done in hdd_connRemoveConnectInfo. + */ + sta_ctx->conn_info.staId[i] = + HDD_WLAN_INVALID_STA_ID; + qdf_mem_zero(&sta_ctx->conn_info.peerMacAddress[i], + sizeof(struct qdf_mac_addr)); + if (sta_id < HDD_MAX_ADAPTERS) + hdd_ctx->sta_to_adapter[sta_id] = NULL; + else + hdd_debug("invalid sta_id %d", sta_id); + } + } else { + sta_id = sta_ctx->conn_info.staId[0]; + hdd_debug("roamResult: %d", roamResult); + + /* clear scan cache for Link Lost */ + if (eCSR_ROAM_RESULT_DEAUTH_IND == roamResult || + eCSR_ROAM_RESULT_DISASSOC_IND == roamResult || + eCSR_ROAM_LOSTLINK == roamStatus) { + wlan_hdd_cfg80211_unlink_bss(adapter, + sta_ctx->conn_info.bssId.bytes, + sta_ctx->conn_info.SSID.SSID.ssId, + sta_ctx->conn_info.SSID.SSID.length); + sme_remove_bssid_from_scan_list(mac_handle, + sta_ctx->conn_info.bssId.bytes); + } + if (sta_id < HDD_MAX_ADAPTERS) + hdd_ctx->sta_to_adapter[sta_id] = NULL; + else + hdd_debug("invalid sta_id %d", sta_id); + } + /* Clear saved connection information in HDD */ + hdd_conn_remove_connect_info(sta_ctx); + /* + * eConnectionState_Connecting state mean that connection is in + * progress so no need to set state to eConnectionState_NotConnected + */ + if ((eConnectionState_Connecting != sta_ctx->conn_info.connState)) { + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + hdd_set_roaming_in_progress(false); + } + pmo_ucfg_flush_gtk_offload_req(adapter->vdev); + + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode)) { + sme_ps_disable_auto_ps_timer(mac_handle, + adapter->session_id); + adapter->send_mode_change = true; + } + wlan_hdd_clear_link_layer_stats(adapter); + + hdd_debug("check for SAP restart"); + policy_mgr_check_concurrent_intf_and_restart_sap(hdd_ctx->psoc); + adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + + /* Unblock anyone waiting for disconnect to complete */ + complete(&adapter->disconnect_comp_var); + + hdd_nud_reset_tracking(adapter); + + hdd_set_disconnect_status(adapter, false); + + hdd_reset_limit_off_chan(adapter); + + hdd_print_bss_info(sta_ctx); + + if (policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) + sme_enable_roaming_on_connected_sta(mac_handle); + + return status; +} + +/** + * hdd_set_peer_authorized_event() - set peer_authorized_event + * @vdev_id: vdevid + * + * Return: None + */ +static void hdd_set_peer_authorized_event(uint32_t vdev_id) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter = NULL; + + if (!hdd_ctx) { + hdd_err("Invalid hdd context"); + return; + } + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (adapter == NULL) { + hdd_err("Invalid vdev_id"); + return; + } + complete(&adapter->sta_authorized_event); +} + +/** + * hdd_change_peer_state() - change peer state + * @adapter: HDD adapter + * @sta_state: peer state + * @roam_synch_in_progress: roam synch in progress + * + * Return: QDF status + */ +QDF_STATUS hdd_change_peer_state(struct hdd_adapter *adapter, + uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress) +{ + QDF_STATUS err; + uint8_t *peer_mac_addr; + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *peer; + + if (!pdev) { + hdd_err("Failed to get txrx context"); + return QDF_STATUS_E_FAULT; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + hdd_err("Invalid sta id: %d", sta_id); + return QDF_STATUS_E_INVAL; + } + + peer = cdp_peer_find_by_local_id(soc, + (struct cdp_pdev *)pdev, sta_id); + if (!peer) + return QDF_STATUS_E_FAULT; + + peer_mac_addr = cdp_peer_get_peer_mac_addr(soc, peer); + if (peer_mac_addr == NULL) { + hdd_err("peer mac addr is NULL"); + return QDF_STATUS_E_FAULT; + } + + err = cdp_peer_state_update(soc, pdev, peer_mac_addr, sta_state); + if (err != QDF_STATUS_SUCCESS) { + hdd_err("peer state update failed"); + return QDF_STATUS_E_FAULT; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_synch_in_progress) + return QDF_STATUS_SUCCESS; +#endif + + 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(adapter->hdd_ctx); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + /* make sure event is reset */ + INIT_COMPLETION(adapter->sta_authorized_event); +#endif + + err = sme_set_peer_authorized(peer_mac_addr, + hdd_set_peer_authorized_event, + adapter->session_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) { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + void *vdev; + unsigned long rc; + + /* wait for event from firmware to set the event */ + rc = wait_for_completion_timeout( + &adapter->sta_authorized_event, + msecs_to_jiffies(HDD_PEER_AUTHORIZE_WAIT)); + if (!rc) + hdd_debug("timeout waiting for sta_authorized_event"); + + vdev = (void *)cdp_peer_get_vdev(soc, peer); + cdp_fc_vdev_unpause(soc, (struct cdp_vdev *)vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_update_dp_vdev_flags() - update datapath vdev flags + * @cbk_data: callback data + * @sta_id: station 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 sta_id, + uint32_t vdev_param, + bool is_link_up) +{ + struct cdp_vdev *data_vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct hdd_context *hdd_ctx; + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct wlan_objmgr_psoc **psoc; + + if (!cbk_data) + return status; + + psoc = cbk_data; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD Context"); + return QDF_STATUS_E_INVAL; + } + + if (!hdd_ctx->tdls_nap_active) + return status; + + data_vdev = cdp_peer_get_vdev_by_sta_id(soc, pdev, sta_id); + if (NULL == data_vdev) { + status = QDF_STATUS_E_FAILURE; + return status; + } + + cdp_txrx_set_vdev_param(soc, data_vdev, vdev_param, is_link_up); + + return status; +} + +/** + * hdd_roam_register_sta() - register station + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @staId: station identifier + * @pPeerMacAddress: peer MAC address + * @pBssDesc: pointer to BSS description + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_register_sta(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint8_t staId, + struct qdf_mac_addr *pPeerMacAddress, + struct bss_description *pBssDesc) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; +#ifdef WLAN_DEBUG + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); +#endif + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pBssDesc) + return QDF_STATUS_E_FAILURE; + + /* Get the Station ID from the one saved during the association */ + staDesc.sta_id = staId; + + /* set the QoS field appropriately */ + if (hdd_wmm_is_active(adapter)) + staDesc.is_qos_enabled = 1; + else + staDesc.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) + staDesc.is_wapi_supported = 1; + else + staDesc.is_wapi_supported = 0; +#endif /* FEATURE_WLAN_WAPI */ + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_rx_packet_cbk; + txrx_ops.rx.stats_rx = hdd_tx_rx_collect_connectivity_stats_info; + + adapter->txrx_vdev = (void *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, + adapter->session_id); + if (!adapter->txrx_vdev) { + hdd_err("%s find vdev fail", __func__); + return QDF_STATUS_E_FAILURE; + } + + txrx_ops.tx.tx = NULL; + cdp_vdev_register(soc, + (struct cdp_vdev *)adapter->txrx_vdev, adapter, &txrx_ops); + if (!txrx_ops.tx.tx) { + hdd_err("%s vdev register fail", __func__); + return QDF_STATUS_E_FAILURE; + } + + adapter->tx_fn = txrx_ops.tx.tx; + qdf_status = cdp_peer_register(soc, + (struct cdp_pdev *)pdev, &staDesc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("cdp_peer_register() failed Status: %d [0x%08X]", + qdf_status, qdf_status); + return qdf_status; + } + + if (!roam_info->fAuthRequired) { + /* + * Connections that do not need Upper layer auth, transition + * TLSHIM directly to 'Authenticated' state + */ + qdf_status = + hdd_change_peer_state(adapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_AUTH, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + roam_info->roamSynchInProgress +#else + false +#endif + ); + + hdd_conn_set_authenticated(adapter, true); + hdd_objmgr_set_peer_mlme_auth_state(adapter->vdev, true); + } else { + hdd_debug("ULA auth StaId= %d. Changing TL state to CONNECTED at Join time", + sta_ctx->conn_info.staId[0]); + qdf_status = + hdd_change_peer_state(adapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_CONN, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + roam_info->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(adapter, false); + hdd_objmgr_set_peer_mlme_auth_state(adapter->vdev, false); + } + return qdf_status; +} + +/** + * hdd_send_roamed_ind() - send roamed indication to cfg80211 + * @dev: network device + * @bss: cfg80211 roamed bss pointer + * @req_ie: IEs used in reassociation request + * @req_ie_len: Length of the @req_ie + * @resp_ie: IEs received in successful reassociation response + * @resp_ie_len: Length of @resp_ie + * + * Return: none + */ +#if defined CFG80211_ROAMED_API_UNIFIED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) +static void hdd_send_roamed_ind(struct net_device *dev, + struct cfg80211_bss *bss, const uint8_t *req_ie, + size_t req_ie_len, const uint8_t *resp_ie, + size_t resp_ie_len) +{ + struct cfg80211_roam_info info = {0}; + + info.bss = bss; + info.req_ie = req_ie; + info.req_ie_len = req_ie_len; + info.resp_ie = resp_ie; + info.resp_ie_len = resp_ie_len; + cfg80211_roamed(dev, &info, GFP_KERNEL); +} +#else +static inline void hdd_send_roamed_ind(struct net_device *dev, + struct cfg80211_bss *bss, + const uint8_t *req_ie, size_t req_ie_len, + const uint8_t *resp_ie, + size_t resp_ie_len) +{ + cfg80211_roamed_bss(dev, bss, req_ie, req_ie_len, resp_ie, resp_ie_len, + GFP_KERNEL); +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) +#if defined(WLAN_FEATURE_FILS_SK) +void hdd_save_gtk_params(struct hdd_adapter *adapter, + struct csr_roam_info *csr_roam_info, bool is_reassoc) +{ + uint8_t *kek; + uint32_t kek_len; + + if (is_reassoc) { + kek = csr_roam_info->kek; + kek_len = csr_roam_info->kek_len; + } else { + /* + * This should come for FILS case only. + * Caller should make sure fils_join_rsp is + * not NULL, if there is need to use else where. + */ + kek = csr_roam_info->fils_join_rsp->kek; + kek_len = csr_roam_info->fils_join_rsp->kek_len; + } + + wlan_hdd_save_gtk_offload_params(adapter, NULL, kek, kek_len, + csr_roam_info->replay_ctr, true); + + hdd_debug("Kek len %d", kek_len); +} +#else +void hdd_save_gtk_params(struct hdd_adapter *adapter, + struct csr_roam_info *csr_roam_info, bool is_reassoc) +{ + uint8_t *kek; + uint32_t kek_len; + + /* + * is_reassoc is set to true always for Legacy GTK offload + * case, It is false only for FILS case + */ + kek = csr_roam_info->kek; + kek_len = csr_roam_info->kek_len; + + wlan_hdd_save_gtk_offload_params(adapter, NULL, kek, kek_len, + csr_roam_info->replay_ctr, true); + + hdd_debug("Kek len %d", kek_len); +} +#endif +#endif +/** + * hdd_send_re_assoc_event() - send reassoc event + * @dev: pointer to net device + * @adapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * @reqRsnIe: pointer to RSN Information element + * @reqRsnLength: length of RSN IE + * + * Return: none + */ +static void hdd_send_re_assoc_event(struct net_device *dev, + struct hdd_adapter *adapter, struct csr_roam_info *pCsrRoamInfo, + uint8_t *reqRsnIe, uint32_t reqRsnLength) +{ + unsigned int len = 0; + u8 *pFTAssocRsp = NULL; + uint8_t *rspRsnIe = qdf_mem_malloc(IW_GENERIC_IE_MAX); + uint8_t *assoc_req_ies = qdf_mem_malloc(IW_GENERIC_IE_MAX); + uint32_t rspRsnLength = 0; + struct ieee80211_channel *chan; + uint8_t buf_ssid_ie[2 + SIR_MAC_SSID_EID_MAX]; /* 2 bytes-EID and len */ + uint8_t *buf_ptr, ssid_ie_len; + struct cfg80211_bss *bss = NULL; + uint8_t *final_req_ie = NULL; + tCsrRoamConnectedProfile roam_profile; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int chan_no; + int freq; + + qdf_mem_zero(&roam_profile, sizeof(roam_profile)); + + if (!rspRsnIe) { + hdd_err("Unable to allocate RSN IE"); + goto done; + } + + if (!assoc_req_ies) { + hdd_err("Unable to allocate Assoc Req IE"); + goto done; + } + + if (!pCsrRoamInfo || !pCsrRoamInfo->pBssDesc) { + hdd_err("Invalid CSR roam info"); + goto done; + } + + if (pCsrRoamInfo->nAssocRspLength == 0) { + hdd_err("Assoc rsp length is 0"); + goto done; + } + + pFTAssocRsp = + (u8 *) (pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength + + pCsrRoamInfo->nAssocReqLength); + if (pFTAssocRsp == NULL) + goto done; + + /* pFTAssocRsp needs to point to the IEs */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hdd_debug("AssocRsp is now at %02x%02x", + (unsigned int)pFTAssocRsp[0], (unsigned int)pFTAssocRsp[1]); + + /* + * Active session count is decremented upon disconnection, but during + * roaming, there is no disconnect indication and hence active session + * count is not decremented. + * After roaming is completed, active session count is incremented + * as a part of connect indication but effectively after roaming the + * active session count should still be the same and hence upon + * successful reassoc decrement the active session count here. + */ + if (!hdd_is_roam_sync_in_progress(pCsrRoamInfo)) { + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + } + + /* Send the Assoc Resp, the supplicant needs this for initial Auth */ + len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET; + rspRsnLength = len; + qdf_mem_copy(rspRsnIe, pFTAssocRsp, len); + qdf_mem_zero(rspRsnIe + len, IW_GENERIC_IE_MAX - len); + + chan_no = pCsrRoamInfo->pBssDesc->channelId; + if (chan_no <= 14) + freq = ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_5GHZ); + chan = ieee80211_get_channel(adapter->wdev.wiphy, freq); + + sme_roam_get_connect_profile(hdd_ctx->mac_handle, adapter->session_id, + &roam_profile); + + bss = hdd_cfg80211_get_bss(adapter->wdev.wiphy, + chan, pCsrRoamInfo->bssid.bytes, + &roam_profile.SSID.ssId[0], + roam_profile.SSID.length); + + if (bss == NULL) + hdd_warn("Get BSS returned NULL"); + buf_ptr = buf_ssid_ie; + *buf_ptr = SIR_MAC_SSID_EID; + buf_ptr++; + *buf_ptr = roam_profile.SSID.length; /*len of ssid*/ + buf_ptr++; + qdf_mem_copy(buf_ptr, &roam_profile.SSID.ssId[0], + roam_profile.SSID.length); + ssid_ie_len = 2 + roam_profile.SSID.length; + hdd_debug("SSIDIE:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + buf_ssid_ie, ssid_ie_len); + final_req_ie = qdf_mem_malloc(IW_GENERIC_IE_MAX); + if (final_req_ie == NULL) { + if (bss) + cfg80211_put_bss(adapter->wdev.wiphy, bss); + goto done; + } + buf_ptr = final_req_ie; + qdf_mem_copy(buf_ptr, buf_ssid_ie, ssid_ie_len); + buf_ptr += ssid_ie_len; + qdf_mem_copy(buf_ptr, reqRsnIe, reqRsnLength); + qdf_mem_copy(rspRsnIe, pFTAssocRsp, len); + qdf_mem_zero(final_req_ie + (ssid_ie_len + reqRsnLength), + IW_GENERIC_IE_MAX - (ssid_ie_len + reqRsnLength)); + hdd_debug("Req RSN IE:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + final_req_ie, (ssid_ie_len + reqRsnLength)); + hdd_send_roamed_ind(dev, bss, final_req_ie, + (ssid_ie_len + reqRsnLength), rspRsnIe, + rspRsnLength); + + qdf_mem_copy(assoc_req_ies, + (u8 *)pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength, + pCsrRoamInfo->nAssocReqLength); + + hdd_save_gtk_params(adapter, pCsrRoamInfo, true); + + hdd_debug("ReAssoc Req IE dump"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + assoc_req_ies, pCsrRoamInfo->nAssocReqLength); + + wlan_hdd_send_roam_auth_event(adapter, pCsrRoamInfo->bssid.bytes, + assoc_req_ies, pCsrRoamInfo->nAssocReqLength, + rspRsnIe, rspRsnLength, + pCsrRoamInfo); + + hdd_update_hlp_info(dev, pCsrRoamInfo); + +done: + sme_roam_free_connect_profile(&roam_profile); + if (final_req_ie) + qdf_mem_free(final_req_ie); + qdf_mem_free(rspRsnIe); + qdf_mem_free(assoc_req_ies); +} + +/** + * hdd_is_roam_sync_in_progress()- Check if roam offloaded + * @roaminfo - Roaming Information + * + * Return: roam sync status if roaming offloaded else false + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +bool hdd_is_roam_sync_in_progress(struct csr_roam_info *roaminfo) +{ + if (roaminfo) + return roaminfo->roamSynchInProgress; + else + return false; +} +#endif + +/** + * hdd_get_ibss_peer_staid() - get sta id for IBSS peer + * @hddstactx: pointer to HDD sta context + * @roaminfo: pointer to roaminfo structure + * + * This function returns staid for IBSS peer. If peer is broadcast + * MAC address return self staid(0) else find the peer sta id of + * the peer. + * + * Return: sta_id (HDD_WLAN_INVALID_STA_ID if peer not found). + */ +static uint8_t hdd_get_ibss_peer_staid(struct hdd_station_ctx *hddstactx, + struct csr_roam_info *roaminfo) +{ + uint8_t staid = HDD_WLAN_INVALID_STA_ID; + QDF_STATUS status; + + if (qdf_is_macaddr_broadcast(&roaminfo->peerMac)) { + staid = 0; + } else { + status = hdd_get_peer_sta_id(hddstactx, + &roaminfo->peerMac, &staid); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Unable to find staid for " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roaminfo->peerMac.bytes)); + } + } + + return staid; +} + +/** + * hdd_change_sta_state_authenticated()- + * This function changes STA state to authenticated + * @adapter: pointer to the adapter structure. + * @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 hdd_adapter *adapter, + struct csr_roam_info *roaminfo) +{ + QDF_STATUS status; + uint32_t timeout; + uint8_t staid = HDD_WLAN_INVALID_STA_ID; + struct hdd_station_ctx *hddstactx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + timeout = hddstactx->hdd_reassoc_scenario ? + AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE : + hdd_ctx->config->auto_bmps_timer_val * 1000; + + if (QDF_IBSS_MODE == adapter->device_mode) + staid = hdd_get_ibss_peer_staid(hddstactx, roaminfo); + else + staid = hddstactx->conn_info.staId[0]; + + hdd_debug("Changing Peer state to AUTHENTICATED for StaId = %d", staid); + + /* Connections that do not need Upper layer authentication, + * transition TL to 'Authenticated' state after the keys are set + */ + status = hdd_change_peer_state(adapter, staid, OL_TXRX_PEER_STATE_AUTH, + hdd_is_roam_sync_in_progress(roaminfo)); + hdd_conn_set_authenticated(adapter, true); + hdd_objmgr_set_peer_mlme_auth_state(adapter->vdev, true); + + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode)) { + sme_ps_enable_auto_ps_timer(hdd_ctx->mac_handle, + adapter->session_id, + timeout); + } + + return qdf_status_to_os_return(status); +} + +/** + * hdd_is_key_install_required_for_ibss() - check encryption type to identify + * if key installation is required + * @encr_type: encryption type + * + * Return: true if key installation is required and false otherwise. + */ +static inline bool hdd_is_key_install_required_for_ibss( + eCsrEncryptionType encr_type) +{ + if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == encr_type || + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == encr_type || + eCSR_ENCRYPT_TYPE_TKIP == encr_type || + eCSR_ENCRYPT_TYPE_AES_GCMP == encr_type || + eCSR_ENCRYPT_TYPE_AES_GCMP_256 == encr_type || + eCSR_ENCRYPT_TYPE_AES == encr_type) + return true; + else + return false; +} + +/** + * hdd_change_peer_state_after_set_key() - change the peer state on set key + * complete + * @adapter: pointer to 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 hdd_adapter *adapter, + struct csr_roam_info *roaminfo, + eCsrRoamResult roam_result) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + eCsrEncryptionType encr_type = hdd_sta_ctx->conn_info.ucEncryptionType; + + /* + * If the security mode is one of the following, IBSS peer will be + * waiting in CONN state and we will move the peer state to AUTH + * here. For non-secure connection, no need to wait for set-key complete + * peer will be moved to AUTH in hdd_roam_register_sta. + */ + if (QDF_IBSS_MODE == adapter->device_mode) { + if (hdd_is_key_install_required_for_ibss(encr_type)) + hdd_change_sta_state_authenticated(adapter, roaminfo); + + return; + } + + 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, + adapter->session_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(adapter, roaminfo); + } else if (hdd_sta_ctx->conn_info.ptk_installed) { + hdd_change_sta_state_authenticated(adapter, 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 + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_roam_set_key_complete_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + eCsrEncryptionType connectedCipherAlgo; + bool connected = false; + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_enter(); + + if (NULL == roam_info) { + hdd_err("roam_info is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* + * 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 roamStatus =%d roamResult=%d " + MAC_ADDRESS_STR, roamStatus, roamResult, + MAC_ADDR_ARRAY(roam_info->peerMac.bytes)); + + connected = hdd_conn_get_connected_cipher_algo(sta_ctx, + &connectedCipherAlgo); + if (connected) { + hdd_change_peer_state_after_set_key(adapter, roam_info, + roamResult); + } + + hdd_exit(); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_perform_roam_set_key_complete() - perform set key complete + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_perform_roam_set_key_complete(struct hdd_adapter *adapter) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct csr_roam_info roamInfo; + + roamInfo.fAuthRequired = false; + qdf_mem_copy(roamInfo.bssid.bytes, + sta_ctx->roam_info.bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(roamInfo.peerMac.bytes, + sta_ctx->roam_info.peer_mac, QDF_MAC_ADDR_SIZE); + + qdf_ret_status = + hdd_roam_set_key_complete_handler(adapter, + &roamInfo, + sta_ctx->roam_info.roam_id, + sta_ctx->roam_info.roam_status, + eCSR_ROAM_RESULT_AUTHENTICATED); + if (qdf_ret_status != QDF_STATUS_SUCCESS) + hdd_err("Set Key complete failure"); + + sta_ctx->roam_info.defer_key_complete = false; +} + +#if defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) +void hdd_clear_fils_connection_info(struct hdd_adapter *adapter) +{ + struct csr_roam_profile *roam_profile; + + if ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) + return; + + roam_profile = hdd_roam_profile(adapter); + if (roam_profile->fils_con_info) { + qdf_mem_free(roam_profile->fils_con_info); + roam_profile->fils_con_info = NULL; + } + + if (roam_profile->hlp_ie) { + qdf_mem_free(roam_profile->hlp_ie); + roam_profile->hlp_ie = NULL; + roam_profile->hlp_ie_len = 0; + } +} +#endif + +/** + * hdd_association_completion_handler() - association completion handler + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_association_completion_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + struct net_device *dev = adapter->dev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint8_t reqRsnIe[DOT11F_IE_RSN_MAX_LEN]; + uint32_t reqRsnLength = DOT11F_IE_RSN_MAX_LEN, ie_len; + int ft_carrier_on = false; + bool hddDisconInProgress = false; + unsigned long rc; + tSirResultCodes timeout_reason = 0; + bool ok; + mac_handle_t mac_handle; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* validate config */ + if (!hdd_ctx->config) { + hdd_err("config is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* + * reset scan reject params if connection is success or we received + * final failure from CSR after trying with all APs. + */ + hdd_reset_scan_reject_params(hdd_ctx, roamStatus, roamResult); + + /* + * Enable roaming on other STA iface except this one. + * Firmware dosent support connection on one STA iface while + * roaming on other STA iface + */ + wlan_hdd_enable_roaming(adapter); + + /* HDD has initiated disconnect, do not send connect result indication + * to kernel as it will be handled by __cfg80211_disconnect. + */ + if (((eConnectionState_Disconnecting == + sta_ctx->conn_info.connState) || + (eConnectionState_NotConnected == + sta_ctx->conn_info.connState)) && + ((eCSR_ROAM_RESULT_ASSOCIATED == roamResult) || + (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus))) { + hdd_info("hddDisconInProgress state=%d, result=%d, status=%d", + sta_ctx->conn_info.connState, + roamResult, roamStatus); + hddDisconInProgress = true; + } + + mac_handle = hdd_ctx->mac_handle; + + if (eCSR_ROAM_RESULT_ASSOCIATED == roamResult) { + if (NULL == roam_info) { + hdd_err("roam_info is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (!hddDisconInProgress) { + hdd_conn_set_connection_state(adapter, + eConnectionState_Associated); + } + + /* Save the connection info from CSR... */ + hdd_conn_save_connect_info(adapter, roam_info, + eCSR_BSS_TYPE_INFRASTRUCTURE); + + if (hdd_add_beacon_filter(adapter) != 0) + hdd_err("hdd_add_beacon_filter() failed"); +#ifdef FEATURE_WLAN_WAPI + if (roam_info->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE + || roam_info->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_WAPI_WAI_PSK) { + adapter->wapi_info.is_wapi_sta = true; + } else { + adapter->wapi_info.is_wapi_sta = false; + } +#endif /* FEATURE_WLAN_WAPI */ + hdd_debug("bss_descr[%d] devicemode[%d]", !!roam_info->pBssDesc, + adapter->device_mode); + if ((QDF_STA_MODE == adapter->device_mode) && + roam_info->pBssDesc) { + ie_len = GET_IE_LEN_IN_BSS(roam_info->pBssDesc->length); + sta_ctx->ap_supports_immediate_power_save = + wlan_hdd_is_ap_supports_immediate_power_save( + (uint8_t *) roam_info->pBssDesc->ieFields, + ie_len); + hdd_debug("ap_supports_immediate_power_save flag [%d]", + sta_ctx->ap_supports_immediate_power_save); + } + + /* Indicate 'connect' status to user space */ + hdd_send_association_event(dev, roam_info); + + if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc)) { + if (hdd_ctx->miracast_value) + wlan_hdd_set_mas(adapter, + hdd_ctx->miracast_value); + } + + /* Initialize the Linkup event completion variable */ + INIT_COMPLETION(adapter->linkup_event_var); + + /* + * Sometimes Switching ON the Carrier is taking time to activate + * the device properly. Before allowing any packet to go up to + * the application, device activation has to be ensured for + * proper queue mapping by the kernel. we have registered net + * device notifier for device change notification. With this we + * will come to know that the device is getting + * activated properly. + */ + if (sta_ctx->ft_carrier_on == false) { + /* + * 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) + ); + if (!rc) + hdd_warn("Warning:ASSOC_LINKUP_TIMEOUT"); + + /* + * Disable Linkup Event Servicing - no more service + * required from the net device notifier call. + */ + adapter->is_link_up_service_needed = false; + } else { + sta_ctx->ft_carrier_on = false; + ft_carrier_on = true; + } + if (roam_info->staId < HDD_MAX_ADAPTERS) + hdd_ctx->sta_to_adapter[roam_info->staId] = adapter; + else + hdd_err("Wrong Staid: %d", roam_info->staId); + + if (ucfg_ipa_is_enabled()) + ucfg_ipa_wlan_evt(hdd_ctx->pdev, adapter->dev, + adapter->device_mode, + roam_info->staId, + adapter->session_id, + WLAN_IPA_STA_CONNECT, + roam_info->bssid.bytes); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(hdd_ctx, false); +#endif + + hdd_debug("check if STA chan ok for DNBS"); + if (policy_mgr_is_chan_ok_for_dnbs(hdd_ctx->psoc, + sta_ctx->conn_info.operationChannel, + &ok)) { + hdd_err("Unable to check DNBS eligibility for chan:%d", + sta_ctx->conn_info.operationChannel); + return QDF_STATUS_E_FAILURE; + } + + if (!ok) { + hdd_err("Chan:%d not suitable for DNBS", + sta_ctx->conn_info.operationChannel); + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_CARRIER_OFF, + WLAN_CONTROL_PATH); + if (!hddDisconInProgress) { + hdd_err("Disconnecting..."); + sme_roam_disconnect( + mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + return QDF_STATUS_E_FAILURE; + } + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + adapter->session_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_ASSOC)); + + /* + * For reassoc, the station is already registered, all we need + * is to change the state of the STA in TL. + * If authentication is required (WPA/WPA2/DWEP), change TL to + * CONNECTED instead of AUTHENTICATED. + */ + if (!roam_info->fReassocReq) { + struct cfg80211_bss *bss; + u8 *pFTAssocRsp = NULL; + unsigned int assocRsplen = 0; + u8 *pFTAssocReq = NULL; + unsigned int assocReqlen = 0; + struct ieee80211_channel *chan; + uint8_t rspRsnIe[DOT11F_IE_RSN_MAX_LEN]; + uint32_t rspRsnLength = DOT11F_IE_RSN_MAX_LEN; + + /* add bss_id to cfg80211 data base */ + bss = + wlan_hdd_cfg80211_update_bss_db(adapter, + roam_info); + if (NULL == bss) { + hdd_err("wlan: Not able to create BSS entry"); + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_CARRIER_OFF, + WLAN_CONTROL_PATH); + if (!hddDisconInProgress) { + /* + * Here driver was not able to add bss + * in cfg80211 database this can happen + * if connected channel is not valid, + * i.e reg domain was changed during + * connection. Queue disconnect for the + * session if disconnect is not in + * progress. + */ + hdd_debug("Disconnecting..."); + sme_roam_disconnect( + mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + return QDF_STATUS_E_FAILURE; + } + + cfg80211_put_bss(hdd_ctx->wiphy, bss); + + /* Association Response */ + pFTAssocRsp = + (u8 *) (roam_info->pbFrames + + roam_info->nBeaconLength + + roam_info->nAssocReqLength); + if (pFTAssocRsp != NULL) { + /* + * pFTAssocRsp needs to point to the IEs + */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hdd_debug("AssocRsp is now at %02x%02x", + (unsigned int)pFTAssocRsp[0], + (unsigned int)pFTAssocRsp[1]); + assocRsplen = + roam_info->nAssocRspLength - + FT_ASSOC_RSP_IES_OFFSET; + + hdd_debug("assocRsplen %d", assocRsplen); + hdd_debug("Assoc Rsp IE dump"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + pFTAssocRsp, + assocRsplen); + } else { + hdd_debug("AssocRsp is NULL"); + assocRsplen = 0; + } + + /* Association Request */ + pFTAssocReq = (u8 *) (roam_info->pbFrames + + roam_info->nBeaconLength); + if (pFTAssocReq != NULL) { + if (!ft_carrier_on) { + /* + * pFTAssocReq needs to point to + * the IEs + */ + pFTAssocReq += + FT_ASSOC_REQ_IES_OFFSET; + hdd_debug("pFTAssocReq is now at %02x%02x", + (unsigned int) + pFTAssocReq[0], + (unsigned int) + pFTAssocReq[1]); + assocReqlen = + roam_info->nAssocReqLength - + FT_ASSOC_REQ_IES_OFFSET; + } else { + /* + * This should contain only the + * FTIEs + */ + assocReqlen = + roam_info->nAssocReqLength; + } + + hdd_debug("assocReqlen %d", assocReqlen); + hdd_debug("Assoc/Reassoc Req IE dump"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + pFTAssocReq, + assocReqlen); + } else { + hdd_debug("AssocReq is NULL"); + assocReqlen = 0; + } + + if (roam_info->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_FT_RSN + || roam_info->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_FT_RSN_PSK) { + if (ft_carrier_on) { + if (!hddDisconInProgress && + roam_info->pBssDesc) { + struct cfg80211_bss *roam_bss; + + /* + * After roaming is completed, + * active session count is + * incremented as a part of + * connect indication but + * effectively the active + * session count should still + * be the same and hence upon + * successful reassoc + * decrement the active session + * count here. + */ + if (!hdd_is_roam_sync_in_progress + (roam_info)) { + policy_mgr_decr_session_set_pcl( + hdd_ctx->psoc, + adapter->device_mode, + adapter->session_id); + hdd_green_ap_start_state_mc( + hdd_ctx, + adapter->device_mode, + false); + } + hdd_debug("ft_carrier_on is %d, sending roamed indication", + ft_carrier_on); + chan = + ieee80211_get_channel + (adapter->wdev.wiphy, + (int)roam_info->pBssDesc-> + channelId); + + roam_bss = + hdd_cfg80211_get_bss( + adapter->wdev.wiphy, + chan, + roam_info->bssid.bytes, + roam_info->u. + pConnectedProfile->SSID.ssId, + roam_info->u. + pConnectedProfile->SSID.length); + hdd_send_roamed_ind( + dev, + roam_bss, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen); + wlan_hdd_send_roam_auth_event( + adapter, + roam_info->bssid.bytes, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + roam_info); + } + if (sme_get_ftptk_state + (mac_handle, + adapter->session_id)) { + sme_set_ftptk_state + (mac_handle, + adapter->session_id, + false); + roam_info->fAuthRequired = + false; + + qdf_mem_copy(sta_ctx-> + roam_info.bssid, + roam_info->bssid.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(sta_ctx-> + roam_info.peer_mac, + roam_info->peerMac.bytes, + QDF_MAC_ADDR_SIZE); + sta_ctx->roam_info.roam_id = + roamId; + sta_ctx->roam_info.roam_status = + roamStatus; + sta_ctx->roam_info. + defer_key_complete = true; + } + } else if (!hddDisconInProgress) { + hdd_debug("ft_carrier_on is %d, sending connect indication", + ft_carrier_on); + hdd_connect_result(dev, + roam_info-> + bssid.bytes, + roam_info, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + WLAN_STATUS_SUCCESS, + GFP_KERNEL, + false, + roam_info->statusCode); + } + } else { + /* + * wpa supplicant expecting WPA/RSN IE in + * connect result. + */ + sme_roam_get_wpa_rsn_req_ie(mac_handle, + adapter->session_id, + &reqRsnLength, + reqRsnIe); + + sme_roam_get_wpa_rsn_rsp_ie(mac_handle, + adapter->session_id, + &rspRsnLength, + rspRsnIe); + if (!hddDisconInProgress) { + if (ft_carrier_on) + hdd_send_re_assoc_event(dev, + adapter, + roam_info, + reqRsnIe, + reqRsnLength); + else { + hdd_debug("sending connect indication to nl80211:for bssid " + MAC_ADDRESS_STR + " result:%d and Status:%d", + MAC_ADDR_ARRAY + (roam_info->bssid.bytes), + roamResult, roamStatus); + + /* inform connect result to nl80211 */ + hdd_connect_result(dev, + roam_info-> + bssid.bytes, + roam_info, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + WLAN_STATUS_SUCCESS, + GFP_KERNEL, + false, + roam_info->statusCode); + } + } + } + if (!hddDisconInProgress) { + /* + * Perform any WMM-related association + * processing. + */ + hdd_wmm_assoc(adapter, roam_info, + eCSR_BSS_TYPE_INFRASTRUCTURE); + + /* + * Register the Station with DP after associated + */ + qdf_status = hdd_roam_register_sta(adapter, + roam_info, + sta_ctx->conn_info.staId[0], + NULL, roam_info->pBssDesc); + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + } + } else { + /* + * wpa supplicant expecting WPA/RSN IE in connect result + * in case of reassociation also need to indicate it to + * supplicant. + */ + sme_roam_get_wpa_rsn_req_ie( + mac_handle, + adapter->session_id, + &reqRsnLength, reqRsnIe); + + hdd_send_re_assoc_event(dev, adapter, roam_info, + reqRsnIe, reqRsnLength); + /* Reassoc successfully */ + if (roam_info->fAuthRequired) { + qdf_status = + hdd_change_peer_state(adapter, + sta_ctx->conn_info.staId[0], + OL_TXRX_PEER_STATE_CONN, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + roam_info->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(adapter, false); + hdd_objmgr_set_peer_mlme_auth_state( + adapter->vdev, + false); + } else { + hdd_debug("staId: %d Changing TL state to AUTHENTICATED", + sta_ctx->conn_info.staId[0]); + qdf_status = + hdd_change_peer_state(adapter, + sta_ctx->conn_info.staId[0], + OL_TXRX_PEER_STATE_AUTH, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + roam_info->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(adapter, true); + hdd_objmgr_set_peer_mlme_auth_state( + adapter->vdev, + true); + } + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* + * Perform any WMM-related association + * processing + */ + hdd_wmm_assoc(adapter, roam_info, + eCSR_BSS_TYPE_INFRASTRUCTURE); + } + + /* Start the tx queues */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_info->roamSynchInProgress) + hdd_debug("LFR3:netif_tx_wake_all_queues"); +#endif + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("STA register with TL failed status: %d [%08X]", + qdf_status, qdf_status); + } +#ifdef WLAN_FEATURE_11W + qdf_mem_zero(&adapter->hdd_stats.hdd_pmf_stats, + sizeof(adapter->hdd_stats.hdd_pmf_stats)); +#endif + hdd_debug("check for SAP restart"); + policy_mgr_check_concurrent_intf_and_restart_sap( + hdd_ctx->psoc); + if (roam_info->pBssDesc) + policy_mgr_checkn_update_hw_mode_single_mac_mode + (hdd_ctx->psoc, + roam_info->pBssDesc->channelId); + } else { + bool connect_timeout = false; + /* do we need to change the HW mode */ + policy_mgr_check_n_start_opportunistic_timer(hdd_ctx->psoc); + if (roam_info && roam_info->is_fils_connection && + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE == roamResult) + qdf_copy_macaddr(&roam_info->bssid, + &sta_ctx->requested_bssid); + if (roam_info) + hdd_err("wlan: connection failed with " MAC_ADDRESS_STR + " result: %d and Status: %d", + MAC_ADDR_ARRAY(roam_info->bssid.bytes), + roamResult, roamStatus); + else + hdd_err("wlan: connection failed with " MAC_ADDRESS_STR + " result: %d and Status: %d", + MAC_ADDR_ARRAY(sta_ctx->requested_bssid.bytes), + roamResult, roamStatus); + + if ((eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE == roamResult) || + (roam_info && + ((eSIR_SME_JOIN_TIMEOUT_RESULT_CODE == + roam_info->statusCode) || + (eSIR_SME_AUTH_TIMEOUT_RESULT_CODE == + roam_info->statusCode) || + (eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE == + roam_info->statusCode)))) { + uint8_t *ssid; + uint8_t ssid_len; + + if (roam_info && roam_info->pProfile && + roam_info->pProfile->SSIDs.SSIDList) { + ssid_len = + roam_info->pProfile->SSIDs. + SSIDList[0].SSID.length; + ssid = roam_info->pProfile->SSIDs. + SSIDList[0].SSID.ssId; + } else { + ssid_len = sta_ctx->conn_info.SSID.SSID.length; + ssid = sta_ctx->conn_info.SSID.SSID.ssId; + } + wlan_hdd_cfg80211_unlink_bss(adapter, + roam_info ? + roam_info->bssid.bytes : + sta_ctx->requested_bssid.bytes, ssid, ssid_len); + sme_remove_bssid_from_scan_list(mac_handle, + roam_info ? + roam_info->bssid.bytes : + sta_ctx->requested_bssid.bytes); + if (roamResult != + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE) + connect_timeout = true; + } + + /* + * CR465478: Only send up a connection failure result when CSR + * has completed operation - with a ASSOCIATION_FAILURE status. + */ + if (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus + && !hddDisconInProgress) { + if (roam_info) { + hdd_err("send connect failure to nl80211: for bssid " + MAC_ADDRESS_STR + " result: %d and Status: %d reasoncode: %d", + MAC_ADDR_ARRAY(roam_info->bssid.bytes), + roamResult, roamStatus, + roam_info->reasonCode); + sta_ctx->conn_info.assoc_status_code = + roam_info->statusCode; + } else { + hdd_err("connect failed: for bssid " + MAC_ADDRESS_STR + " result: %d and status: %d ", + MAC_ADDR_ARRAY(sta_ctx->requested_bssid.bytes), + roamResult, roamStatus); + } + hdd_debug("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + + /* inform association failure event to nl80211 */ + if (eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL == + roamResult) { + if (roam_info) + hdd_connect_result(dev, + roam_info->bssid.bytes, + roam_info, NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL, + connect_timeout, + roam_info->statusCode); + else + hdd_connect_result(dev, + sta_ctx->requested_bssid.bytes, + NULL, NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL, + connect_timeout, + timeout_reason); + } else { + if (roam_info) + hdd_connect_result(dev, + roam_info->bssid.bytes, + roam_info, NULL, 0, NULL, 0, + roam_info->reasonCode ? + roam_info->reasonCode : + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL, + connect_timeout, + roam_info->statusCode); + else + hdd_connect_result(dev, + sta_ctx->requested_bssid.bytes, + NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL, + connect_timeout, + timeout_reason); + } + hdd_clear_roam_profile_ie(adapter); + sme_reset_key(hdd_ctx->mac_handle, + adapter->session_id); + } else if ((eCSR_ROAM_CANCELLED == roamStatus + && !hddDisconInProgress)) { + hdd_connect_result(dev, + sta_ctx->requested_bssid.bytes, + NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL, + connect_timeout, + timeout_reason); + } + + /* Check to change TDLS state in FW + * as connection failed. + */ + if (roamStatus == eCSR_ROAM_ASSOCIATION_FAILURE || + roamStatus == eCSR_ROAM_CANCELLED) { + ucfg_tdls_notify_connect_failure(hdd_ctx->psoc); + } + + /* + * Set connection state to eConnectionState_NotConnected only + * when CSR has completed operation - with a + * ASSOCIATION_FAILURE or eCSR_ROAM_CANCELLED status. + */ + if (((eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus) || + (eCSR_ROAM_CANCELLED == roamStatus)) + && !hddDisconInProgress) { + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + } + hdd_wmm_init(adapter); + + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + /* + * if hddDisconInProgress is set and roamResult is + * eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE that mean HDD is + * waiting on disconnect_comp_var so unblock anyone waiting for + * disconnect to complete. + */ + if ((roamResult == eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE) && + hddDisconInProgress) + complete(&adapter->disconnect_comp_var); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_ibss_indication_handler() - update the status of the IBSS + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Here we update the status of the Ibss when we receive information that we + * have started/joined an ibss session. + * + * Return: none + */ +static void hdd_roam_ibss_indication_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_debug("%s: id %d, status %d, result %d", + adapter->dev->name, roamId, + roamStatus, roamResult); + + switch (roamResult) { + /* both IBSS Started and IBSS Join should come in here. */ + case eCSR_ROAM_RESULT_IBSS_STARTED: + case eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS: + case eCSR_ROAM_RESULT_IBSS_COALESCED: + { + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct qdf_mac_addr broadcastMacAddr = QDF_MAC_ADDR_BCAST_INIT; + + if (NULL == roam_info) { + QDF_ASSERT(0); + return; + } + + /* When IBSS Started comes from CSR, we need to move + * connection state to IBSS Disconnected (meaning no peers + * are in the IBSS). + */ + hdd_conn_set_connection_state(adapter, + eConnectionState_IbssDisconnected); + /* notify wmm */ + hdd_wmm_connect(adapter, roam_info, + eCSR_BSS_TYPE_IBSS); + + hdd_sta_ctx->broadcast_staid = roam_info->staId; + + if (roam_info->staId < HDD_MAX_ADAPTERS) + hdd_ctx->sta_to_adapter[roam_info->staId] = + adapter; + else + hdd_debug("invalid sta id %d", roam_info->staId); + + hdd_roam_register_sta(adapter, roam_info, + roam_info->staId, + &broadcastMacAddr, + roam_info->pBssDesc); + + if (roam_info->pBssDesc) { + struct cfg80211_bss *bss; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + struct ieee80211_channel *chan; + int chan_no; + unsigned int freq; +#endif + /* we created the IBSS, notify supplicant */ + hdd_debug("%s: created ibss " MAC_ADDRESS_STR, + adapter->dev->name, + MAC_ADDR_ARRAY( + roam_info->pBssDesc->bssId)); + + /* we must first give cfg80211 the BSS information */ + bss = wlan_hdd_cfg80211_update_bss_db(adapter, + roam_info); + if (NULL == bss) { + hdd_err("%s: unable to create IBSS entry", + adapter->dev->name); + return; + } + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + chan_no = roam_info->pBssDesc->channelId; + + if (chan_no <= 14) + freq = ieee80211_channel_to_frequency(chan_no, + HDD_NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(chan_no, + HDD_NL80211_BAND_5GHZ); + + chan = ieee80211_get_channel(adapter->wdev.wiphy, freq); + + if (chan) + cfg80211_ibss_joined(adapter->dev, + bss->bssid, chan, + GFP_KERNEL); + else + hdd_warn("%s: chanId: %d, can't find channel", + adapter->dev->name, + (int)roam_info->pBssDesc->channelId); +#else + cfg80211_ibss_joined(adapter->dev, bss->bssid, + GFP_KERNEL); +#endif + cfg80211_put_bss( + hdd_ctx->wiphy, + bss); + } + if (eCSR_ROAM_RESULT_IBSS_STARTED == roamResult) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + adapter->device_mode, adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, + adapter->device_mode, true); + } else if (eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS == roamResult || + eCSR_ROAM_RESULT_IBSS_COALESCED == roamResult) { + policy_mgr_update_connection_info(hdd_ctx->psoc, + adapter->session_id); + } + break; + } + + case eCSR_ROAM_RESULT_IBSS_START_FAILED: + { + hdd_err("%s: unable to create IBSS", adapter->dev->name); + break; + } + + default: + hdd_err("%s: unexpected result %d", + adapter->dev->name, (int)roamResult); + break; + } +} + +/** + * hdd_save_peer() - Save peer MAC address in adapter peer table. + * @sta_ctx: pointer to hdd station context + * @sta_id: station ID + * @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, uint8_t sta_id, + struct qdf_mac_addr *peer_mac_addr) +{ + int idx; + + for (idx = 0; idx < SIR_MAX_NUM_STA_IN_IBSS; idx++) { + if (HDD_WLAN_INVALID_STA_ID == sta_ctx->conn_info.staId[idx]) { + hdd_debug("adding peer: %pM, sta_id: %d, at idx: %d", + peer_mac_addr, sta_id, idx); + sta_ctx->conn_info.staId[idx] = sta_id; + qdf_copy_macaddr( + &sta_ctx->conn_info.peerMacAddress[idx], + peer_mac_addr); + return true; + } + } + return false; +} + +/** + * hdd_delete_peer() - removes peer from hdd station context peer table + * @sta_ctx: pointer to hdd station context + * @sta_id: station ID + * + * Return: None + */ +void hdd_delete_peer(struct hdd_station_ctx *sta_ctx, uint8_t sta_id) +{ + int i; + + for (i = 0; i < SIR_MAX_NUM_STA_IN_IBSS; i++) { + if (sta_id == sta_ctx->conn_info.staId[i]) { + sta_ctx->conn_info.staId[i] = HDD_WLAN_INVALID_STA_ID; + return; + } + } +} + +/** + * roam_remove_ibss_station() - Remove the IBSS peer MAC address in the adapter + * @adapter: pointer to adapter + * @staId: station id + * + * Return: + * true if we remove MAX_PEERS or less STA + * false otherwise. + */ +static bool roam_remove_ibss_station(struct hdd_adapter *adapter, uint8_t staId) +{ + bool fSuccess = false; + int idx = 0; + uint8_t valid_idx = 0; + uint8_t del_idx = 0; + uint8_t empty_slots = 0; + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (staId == sta_ctx->conn_info.staId[idx]) { + sta_ctx->conn_info.staId[idx] = + HDD_WLAN_INVALID_STA_ID; + + qdf_zero_macaddr(&sta_ctx->conn_info. + peerMacAddress[idx]); + + fSuccess = true; + + /* + * Note the deleted Index, if its 0 we need special + * handling. + */ + del_idx = idx; + + empty_slots++; + } else { + if (sta_ctx->conn_info.staId[idx] != + HDD_WLAN_INVALID_STA_ID) { + valid_idx = idx; + } else { + /* Found an empty slot */ + empty_slots++; + } + } + } + + if (MAX_PEERS == empty_slots) { + /* Last peer departed, set the IBSS state appropriately */ + hdd_conn_set_connection_state(adapter, + eConnectionState_IbssDisconnected); + hdd_debug("Last IBSS Peer Departed!!!"); + } + /* Find next active staId, to have a valid sta trigger for TL. */ + if (fSuccess == true) { + if (del_idx == 0) { + if (sta_ctx->conn_info.staId[valid_idx] != + HDD_WLAN_INVALID_STA_ID) { + sta_ctx->conn_info.staId[0] = + sta_ctx->conn_info.staId[valid_idx]; + qdf_copy_macaddr(&sta_ctx->conn_info. + peerMacAddress[0], + &sta_ctx->conn_info. + peerMacAddress[valid_idx]); + + sta_ctx->conn_info.staId[valid_idx] = + HDD_WLAN_INVALID_STA_ID; + qdf_zero_macaddr(&sta_ctx->conn_info. + peerMacAddress[valid_idx]); + } + } + } + return fSuccess; +} + +/** + * roam_ibss_connect_handler() - IBSS connection handler + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * + * We update the status of the IBSS to connected in this function. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS roam_ibss_connect_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + struct cfg80211_bss *bss; + /* + * Set the internal connection state to show 'IBSS Connected' (IBSS with + * a partner stations). + */ + hdd_conn_set_connection_state(adapter, eConnectionState_IbssConnected); + + /* Save the connection info from CSR... */ + hdd_conn_save_connect_info(adapter, roam_info, eCSR_BSS_TYPE_IBSS); + + /* Send the bssid address to the wext. */ + hdd_send_association_event(adapter->dev, roam_info); + /* add bss_id to cfg80211 data base */ + bss = wlan_hdd_cfg80211_update_bss_db(adapter, roam_info); + if (NULL == bss) { + hdd_err("%s: unable to create IBSS entry", + adapter->dev->name); + return QDF_STATUS_E_FAILURE; + } + cfg80211_put_bss( + WLAN_HDD_GET_CTX(adapter)->wiphy, + bss); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_mic_error_indication_handler() - MIC error indication handler + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * This function indicates the Mic failure to the supplicant + * + * Return: None + */ +static void +hdd_roam_mic_error_indication_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + tSirMicFailureInfo *mic_failure_info; + + if (eConnectionState_Associated != sta_ctx->conn_info.connState) + 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); +} + +/** + * roam_roam_connect_status_update_handler() - IBSS connect status update + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * The Ibss connection status is updated regularly here in this function. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +roam_roam_connect_status_update_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS qdf_status; + + switch (roamResult) { + case eCSR_ROAM_RESULT_IBSS_NEW_PEER: + { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct station_info *stainfo; + eCsrEncryptionType encr_type = sta_ctx->ibss_enc_key.encType; + + hdd_debug("IBSS New Peer indication from SME " + "with peerMac " MAC_ADDRESS_STR " BSSID: " + MAC_ADDRESS_STR " and stationID= %d", + MAC_ADDR_ARRAY(roam_info->peerMac.bytes), + MAC_ADDR_ARRAY(sta_ctx->conn_info.bssId.bytes), + roam_info->staId); + + if (!hdd_save_peer + (WLAN_HDD_GET_STATION_CTX_PTR(adapter), + roam_info->staId, + &roam_info->peerMac)) { + hdd_warn("Max reached: Can't register new IBSS peer"); + break; + } + + if (roam_info->staId < HDD_MAX_ADAPTERS) + hdd_ctx->sta_to_adapter[roam_info->staId] = adapter; + else + hdd_debug("invalid sta id %d", roam_info->staId); + + if (hdd_is_key_install_required_for_ibss(encr_type)) + roam_info->fAuthRequired = true; + + /* Register the Station with TL for the new peer. */ + qdf_status = hdd_roam_register_sta(adapter, + roam_info, + roam_info->staId, + &roam_info->peerMac, + roam_info->pBssDesc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Cannot register STA with TL for IBSS. qdf_status: %d [%08X]", + qdf_status, qdf_status); + } + sta_ctx->ibss_sta_generation++; + stainfo = qdf_mem_malloc(sizeof(*stainfo)); + if (stainfo == NULL) { + hdd_err("memory allocation for station_info failed"); + return QDF_STATUS_E_NOMEM; + } + stainfo->filled = 0; + stainfo->generation = sta_ctx->ibss_sta_generation; + + cfg80211_new_sta(adapter->dev, + (const u8 *)roam_info->peerMac.bytes, + stainfo, GFP_KERNEL); + qdf_mem_free(stainfo); + + if (hdd_is_key_install_required_for_ibss(encr_type)) { + sta_ctx->ibss_enc_key.keyDirection = + eSIR_TX_RX; + qdf_copy_macaddr(&sta_ctx->ibss_enc_key.peerMac, + &roam_info->peerMac); + + hdd_debug("New peer joined set PTK encType=%d", + encr_type); + + qdf_status = + sme_roam_set_key(hdd_ctx->mac_handle, + adapter->session_id, + &sta_ctx->ibss_enc_key, + &roamId); + + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("sme_roam_set_key failed, status: %d", + qdf_status); + return QDF_STATUS_E_FAILURE; + } + } + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + } + + case eCSR_ROAM_RESULT_IBSS_CONNECT: + { + + roam_ibss_connect_handler(adapter, roam_info); + + break; + } + case eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED: + { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (!roam_remove_ibss_station(adapter, roam_info->staId)) + hdd_warn("IBSS peer departed by cannot find peer in our registration table with TL"); + + hdd_debug("IBSS Peer Departed from SME " + "with peerMac " MAC_ADDRESS_STR " BSSID: " + MAC_ADDRESS_STR " and stationID= %d", + MAC_ADDR_ARRAY(roam_info->peerMac.bytes), + MAC_ADDR_ARRAY(sta_ctx->conn_info.bssId.bytes), + roam_info->staId); + + hdd_roam_deregister_sta(adapter, roam_info->staId); + + if (roam_info->staId < HDD_MAX_ADAPTERS) + hdd_ctx->sta_to_adapter[roam_info->staId] = NULL; + else + hdd_debug("invalid sta id %d", roam_info->staId); + + sta_ctx->ibss_sta_generation++; + + cfg80211_del_sta(adapter->dev, + (const u8 *)&roam_info->peerMac.bytes, + GFP_KERNEL); + break; + } + case eCSR_ROAM_RESULT_IBSS_INACTIVE: + { + hdd_debug("Received eCSR_ROAM_RESULT_IBSS_INACTIVE from SME"); + /* Stop only when we are inactive */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + + /* Send the bssid address to the wext. */ + hdd_send_association_event(adapter->dev, roam_info); + break; + } + default: + break; + + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS hdd_roam_register_tdlssta(struct hdd_adapter *adapter, + const uint8_t *peerMac, uint16_t staId, + uint8_t qos) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + /* + * 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 + */ + staDesc.sta_id = staId; + + /* set the QoS field appropriately .. */ + staDesc.is_qos_enabled = qos; + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_rx_packet_cbk; + cdp_vdev_register(soc, + (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, adapter->session_id), + adapter, &txrx_ops); + adapter->tx_fn = txrx_ops.tx.tx; + txrx_ops.rx.stats_rx = hdd_tx_rx_collect_connectivity_stats_info; + + /* Register the Station with TL... */ + qdf_status = cdp_peer_register(soc, + (struct cdp_pdev *)pdev, &staDesc); + 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; +} + +/** + * hdd_roam_deregister_tdlssta() - deregister new TDLS station + * @adapter: pointer to adapter + * @staId: station identifier + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_deregister_tdlssta(struct hdd_adapter *adapter, + uint8_t staId) +{ + QDF_STATUS qdf_status; + + qdf_status = cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_pdev *)cds_get_context(QDF_MODULE_ID_TXRX), + staId); + + return qdf_status; +} + +#else + +inline QDF_STATUS hdd_roam_deregister_tdlssta(struct hdd_adapter *adapter, + uint8_t staId) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +hdd_roam_tdls_status_update_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11W +/** + * hdd_indicate_unprot_mgmt_frame() - indicate unprotected management frame + * @adapter: pointer to the adapter + * @nFrameLength: Length of the unprotected frame being passed + * @pbFrames: Pointer to the frame buffer + * @frameType: 802.11 frame type + * + * This function forwards the unprotected management frame to the supplicant. + * + * Return: nothing + */ +static void +hdd_indicate_unprot_mgmt_frame(struct hdd_adapter *adapter, + uint32_t nFrameLength, + uint8_t *pbFrames, uint8_t frameType) +{ + uint8_t type = 0; + uint8_t subType = 0; + + hdd_debug("Frame Type = %d Frame Length = %d", + frameType, nFrameLength); + + /* Sanity Checks */ + if (NULL == adapter) { + hdd_err("adapter is NULL"); + return; + } + + if (NULL == adapter->dev) { + hdd_err("adapter->dev is NULL"); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("adapter has invalid magic"); + return; + } + + if (!nFrameLength) { + hdd_err("Frame Length is Invalid ZERO"); + return; + } + + if (NULL == pbFrames) { + hdd_err("pbFrames is NULL"); + return; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]); + subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]); + + /* Get adapter from Destination mac address of the frame */ + if (type == SIR_MAC_MGMT_FRAME && subType == SIR_MAC_MGMT_DISASSOC) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + cfg80211_rx_unprot_mlme_mgmt(adapter->dev, pbFrames, + nFrameLength); +#else + cfg80211_send_unprot_disassoc(adapter->dev, pbFrames, + nFrameLength); +#endif + adapter->hdd_stats.hdd_pmf_stats.num_unprot_disassoc_rx++; + } else if (type == SIR_MAC_MGMT_FRAME && + subType == SIR_MAC_MGMT_DEAUTH) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + cfg80211_rx_unprot_mlme_mgmt(adapter->dev, pbFrames, + nFrameLength); +#else + cfg80211_send_unprot_deauth(adapter->dev, pbFrames, + nFrameLength); +#endif + adapter->hdd_stats.hdd_pmf_stats.num_unprot_deauth_rx++; + } else { + hdd_warn("Frame type %d and subtype %d are not valid", + type, subType); + return; + } +} +#endif + +#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 (NULL == 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 */ + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_cckm_pre_auth() - send cckm preauth indication + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * + * This function sends cckm preauth indication to the supplicant + * via wireless custom event. + * + * Return: none + */ +static void +hdd_indicate_cckm_pre_auth(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + + if ((NULL == adapter) || (NULL == roam_info)) + return; + + /* 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=" MAC_ADDRESS_STR " %d:%d", + MAC_ADDR_ARRAY(roam_info->bssid.bytes), + roam_info->timestamp[0], roam_info->timestamp[1]); + + nBytes = snprintf(pos, freeBytes, "CCXPREAUTHNOTIFY="); + pos += nBytes; + freeBytes -= nBytes; + + qdf_mem_copy(pos, roam_info->bssid.bytes, QDF_MAC_ADDR_SIZE); + pos += QDF_MAC_ADDR_SIZE; + freeBytes -= QDF_MAC_ADDR_SIZE; + + nBytes = snprintf(pos, freeBytes, " %u:%u", + roam_info->timestamp[0], roam_info->timestamp[1]); + freeBytes -= nBytes; + + wrqu.data.pointer = buf; + wrqu.data.length = (IW_CUSTOM_MAX - freeBytes); + + /* send the event */ + wireless_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 ((NULL == adapter) || (NULL == 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 */ + wireless_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 */ + wireless_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 ((NULL == adapter) || (NULL == 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 */ + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, + buf); + lastSent += sendBss; + } + } +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_is_8021x_sha256_auth_type() - check authentication type to 8021x_sha256 + * @sta_ctx: Station Context + * + * API to check if the connection authentication type is 8021x_sha256. + * + * Return: bool + */ +#ifdef WLAN_FEATURE_11W +static inline bool +hdd_is_8021x_sha256_auth_type(struct hdd_station_ctx *sta_ctx) +{ + return eCSR_AUTH_TYPE_RSN_8021X_SHA256 == + sta_ctx->conn_info.authType; +} +#else +static inline bool +hdd_is_8021x_sha256_auth_type(struct hdd_station_ctx *sta_ctx) +{ + return false; +} +#endif + +/* + * hdd_roam_channel_switch_handler() - hdd channel switch handler + * @adapter: Pointer to adapter context + * @roam_info: Pointer to roam info + * + * Return: None + */ +static void hdd_roam_channel_switch_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + struct hdd_chan_change_params chan_change; + struct cfg80211_bss *bss; + struct net_device *dev = adapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + + hdd_debug("channel switch for session:%d to channel:%d", + adapter->session_id, roam_info->chan_info.chan_id); + + /* Enable Roaming on STA interface which was disabled before CSA */ + if (adapter->device_mode == QDF_STA_MODE) + sme_start_roaming(mac_handle, adapter->session_id, + REASON_DRIVER_ENABLED); + + chan_change.chan = roam_info->chan_info.chan_id; + 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.center_freq_seg0 = + roam_info->chan_info.band_center_freq1; + chan_change.chan_params.center_freq_seg1 = + roam_info->chan_info.band_center_freq2; + + bss = wlan_hdd_cfg80211_update_bss_db(adapter, roam_info); + if (NULL == bss) + hdd_err("%s: unable to create BSS entry", adapter->dev->name); + else + cfg80211_put_bss(wiphy, bss); + + status = hdd_chan_change_notify(adapter, adapter->dev, chan_change, + roam_info->mode == SIR_SME_PHY_MODE_LEGACY); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("channel change notification failed"); + + hdd_debug("check for SAP restart"); + policy_mgr_check_concurrent_intf_and_restart_sap(hdd_ctx->psoc); + + status = policy_mgr_set_hw_mode_on_channel_switch(hdd_ctx->psoc, + adapter->session_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("set hw mode change not done"); +} + +/** + * hdd_sme_roam_callback() - hdd sme roam callback + * @pContext: pointer to adapter context + * @roam_info: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +hdd_sme_roam_callback(void *pContext, struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus roamStatus, eCsrRoamResult roamResult) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + struct hdd_adapter *adapter = (struct hdd_adapter *) pContext; + struct hdd_station_ctx *sta_ctx = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct cfg80211_bss *bss_status; + struct hdd_context *hdd_ctx; + + hdd_debug("CSR Callback: status= %d result= %d roamID=%d", + roamStatus, roamResult, roamId); + + /* Sanity check */ + if ((NULL == adapter) || (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(adapter); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_RX_SME_MSG, + adapter->session_id, roamStatus)); + + switch (roamStatus) { + /* + * We did pre-auth,then we attempted a 11r or ese reassoc. + * reassoc failed due to failure, timeout, reject from ap + * in any case tell the OS, our carrier is off and mark + * interface down. + */ + case eCSR_ROAM_FT_REASSOC_FAILED: + hdd_err("Reassoc Failed with roamStatus: %d roamResult: %d SessionID: %d", + roamStatus, roamResult, adapter->session_id); + qdf_ret_status = + hdd_dis_connect_handler(adapter, roam_info, roamId, + roamStatus, roamResult); + sta_ctx->ft_carrier_on = false; + sta_ctx->hdd_reassoc_scenario = false; + hdd_debug("hdd_reassoc_scenario set to: %d, ReAssoc Failed, session: %d", + sta_ctx->hdd_reassoc_scenario, adapter->session_id); + break; + + case eCSR_ROAM_FT_START: + /* + * When we roam for ESE and 11r, we dont want the OS to be + * informed that the link is down. So mark the link ready for + * ft_start. After this the eCSR_ROAM_SHOULD_ROAM will + * be received. Where in we will not mark the link down + * Also we want to stop tx at this point when we will be + * doing disassoc at this time. This saves 30-60 msec + * after reassoc. + */ + hdd_debug("Disabling queues"); + hdd_debug("Roam Synch Ind: NAPI Serialize ON"); + hdd_napi_serialize(1); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + status = hdd_roam_deregister_sta(adapter, + sta_ctx->conn_info.staId[0]); + if (!QDF_IS_STATUS_SUCCESS(status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + sta_ctx->ft_carrier_on = true; + sta_ctx->hdd_reassoc_scenario = true; + hdd_debug("hdd_reassoc_scenario set to: %d, due to eCSR_ROAM_FT_START, session: %d", + sta_ctx->hdd_reassoc_scenario, adapter->session_id); + break; + case eCSR_ROAM_NAPI_OFF: + hdd_debug("After Roam Synch Comp: NAPI Serialize OFF"); + hdd_napi_serialize(0); + if (roamResult == eCSR_ROAM_RESULT_FAILURE) { + adapter->roam_ho_fail = true; + hdd_set_roaming_in_progress(false); + } else { + adapter->roam_ho_fail = false; + } + complete(&adapter->roaming_comp_var); + break; + case eCSR_ROAM_SYNCH_COMPLETE: + hdd_debug("LFR3: Roam synch complete"); + hdd_set_roaming_in_progress(false); + break; + case eCSR_ROAM_SHOULD_ROAM: + /* notify apps that we can't pass traffic anymore */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + if (sta_ctx->ft_carrier_on == false) { + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_CARRIER_OFF, + WLAN_CONTROL_PATH); + } + break; + case eCSR_ROAM_LOSTLINK: + if (roamResult == eCSR_ROAM_RESULT_LOSTLINK) { + hdd_debug("Roaming started due to connection lost"); + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + } + case eCSR_ROAM_DISASSOCIATED: + { + hdd_debug("****eCSR_ROAM_DISASSOCIATED****"); + hdd_napi_serialize(0); + hdd_set_connection_in_progress(false); + hdd_set_roaming_in_progress(false); + adapter->roam_ho_fail = false; + complete(&adapter->roaming_comp_var); + + /* Call to clear any MC Addr List filter applied after + * successful connection. + */ + hdd_disable_and_flush_mc_addr_list(adapter, + pmo_peer_disconnect); + qdf_ret_status = + hdd_dis_connect_handler(adapter, roam_info, roamId, + roamStatus, roamResult); + } + break; + case eCSR_ROAM_IBSS_LEAVE: + hdd_debug("****eCSR_ROAM_IBSS_LEAVE****"); + qdf_ret_status = + hdd_dis_connect_handler(adapter, roam_info, roamId, + roamStatus, roamResult); + break; + case eCSR_ROAM_ASSOCIATION_COMPLETION: + hdd_debug("****eCSR_ROAM_ASSOCIATION_COMPLETION****"); + /* + * To Do - address probable memory leak with WEP encryption upon + * successful association. + */ + if (eCSR_ROAM_RESULT_ASSOCIATED != roamResult) { + /* Clear saved connection information in HDD */ + hdd_conn_remove_connect_info( + WLAN_HDD_GET_STATION_CTX_PTR(adapter)); + } + qdf_ret_status = + hdd_association_completion_handler(adapter, roam_info, + roamId, roamStatus, + roamResult); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_info) + roam_info->roamSynchInProgress = false; +#endif + break; + case eCSR_ROAM_CANCELLED: + hdd_debug("****eCSR_ROAM_CANCELLED****"); + /* fallthrough */ + case eCSR_ROAM_ASSOCIATION_FAILURE: + qdf_ret_status = hdd_association_completion_handler(adapter, + roam_info, + roamId, + roamStatus, + roamResult); + break; + case eCSR_ROAM_IBSS_IND: + hdd_roam_ibss_indication_handler(adapter, roam_info, roamId, + roamStatus, roamResult); + break; + + case eCSR_ROAM_CONNECT_STATUS_UPDATE: + qdf_ret_status = + roam_roam_connect_status_update_handler(adapter, + roam_info, + roamId, + roamStatus, + roamResult); + break; + + case eCSR_ROAM_MIC_ERROR_IND: + hdd_roam_mic_error_indication_handler(adapter, roam_info); + break; + + case eCSR_ROAM_SET_KEY_COMPLETE: + { + qdf_ret_status = + hdd_roam_set_key_complete_handler(adapter, roam_info, + roamId, roamStatus, + roamResult); + if (eCSR_ROAM_RESULT_AUTHENTICATED == roamResult) { + sta_ctx->hdd_reassoc_scenario = false; + hdd_debug("hdd_reassoc_scenario set to: %d, set key complete, session: %d", + sta_ctx->hdd_reassoc_scenario, + adapter->session_id); + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_info != NULL) + roam_info->roamSynchInProgress = false; +#endif + break; + + case eCSR_ROAM_FT_RESPONSE: + hdd_send_ft_event(adapter); + break; + + case eCSR_ROAM_PMK_NOTIFY: + if (eCSR_AUTH_TYPE_RSN == sta_ctx->conn_info.authType + || hdd_is_8021x_sha256_auth_type(sta_ctx)) { + /* notify the supplicant of a new candidate */ + qdf_ret_status = + wlan_hdd_cfg80211_pmksa_candidate_notify( + adapter, roam_info, 1, false); + } + break; + +#ifdef FEATURE_WLAN_LFR_METRICS + case eCSR_ROAM_PREAUTH_INIT_NOTIFY: + /* This event is to notify pre-auth initiation */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth(adapter, + roam_info)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_PREAUTH_STATUS_SUCCESS: + /* + * This event will notify pre-auth completion in case of success + */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth_status(adapter, + roam_info, 1)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_PREAUTH_STATUS_FAILURE: + /* + * This event will notify pre-auth completion incase of failure. + */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth_status(adapter, + roam_info, 0)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_HANDOVER_SUCCESS: + /* This event is to notify handover success. + * It will be only invoked on success + */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_handover(adapter, + roam_info)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; +#endif +#ifdef WLAN_FEATURE_11W + case eCSR_ROAM_UNPROT_MGMT_FRAME_IND: + if (roam_info) + hdd_indicate_unprot_mgmt_frame(adapter, + roam_info->nFrameLength, + roam_info->pbFrames, + roam_info->frameType); + break; +#endif +#ifdef FEATURE_WLAN_ESE + case eCSR_ROAM_TSM_IE_IND: + if (roam_info) + hdd_indicate_tsm_ie(adapter, roam_info->tsmIe.tsid, + roam_info->tsmIe.state, + roam_info->tsmIe.msmt_interval); + break; + + case eCSR_ROAM_CCKM_PREAUTH_NOTIFY: + { + if (eCSR_AUTH_TYPE_CCKM_WPA == + sta_ctx->conn_info.authType + || eCSR_AUTH_TYPE_CCKM_RSN == + sta_ctx->conn_info.authType) { + hdd_indicate_cckm_pre_auth(adapter, roam_info); + } + 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(adapter, roam_info); + break; + + case eCSR_ROAM_UPDATE_SCAN_RESULT: + if ((NULL != roam_info) && (NULL != roam_info->pBssDesc)) { + bss_status = wlan_hdd_inform_bss_frame(adapter, + roam_info->pBssDesc); + if (NULL == bss_status) + hdd_debug("UPDATE_SCAN_RESULT returned NULL"); + else + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) || defined(WITH_BACKPORTS) + (WLAN_HDD_GET_CTX(adapter))->wiphy, +#endif + bss_status); + } + break; + case eCSR_ROAM_NDP_STATUS_UPDATE: + hdd_ndp_event_handler(adapter, roam_info, roamId, roamStatus, + roamResult); + break; + case eCSR_ROAM_START: + hdd_debug("Process ROAM_START from firmware"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + hdd_set_connection_in_progress(true); + hdd_set_roaming_in_progress(true); + policy_mgr_restart_opportunistic_timer(hdd_ctx->psoc, true); + break; + case eCSR_ROAM_ABORT: + hdd_debug("Firmware aborted roaming operation, previous connection is still valid"); + hdd_napi_serialize(0); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + hdd_set_connection_in_progress(false); + hdd_set_roaming_in_progress(false); + adapter->roam_ho_fail = false; + sta_ctx->ft_carrier_on = false; + complete(&adapter->roaming_comp_var); + break; + + case eCSR_ROAM_SAE_COMPUTE: + if (roam_info) + wlan_hdd_sae_callback(adapter, 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 eCsrAuthType + * + * Return: None + */ +static void hdd_translate_fils_rsn_to_csr_auth(int8_t auth_suite[4], + eCsrAuthType *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], + eCsrAuthType *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 eCsrAuthType + * + * Return: None + */ +static void hdd_translate_sae_rsn_to_csr_auth(int8_t auth_suite[4], + eCsrAuthType *auth_type) +{ + if (qdf_mem_cmp(auth_suite, ccp_rsn_oui_80, 4) == 0) + *auth_type = eCSR_AUTH_TYPE_SAE; +} +#else +static inline void hdd_translate_sae_rsn_to_csr_auth(int8_t auth_suite[4], + eCsrAuthType *auth_type) +{ +} +#endif + +/** + * hdd_translate_rsn_to_csr_auth_type() - Translate RSN to CSR auth type + * @auth_suite: auth suite + * + * Return: eCsrAuthType enumeration + */ +eCsrAuthType hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]) +{ + eCsrAuthType 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 */ +#ifdef WLAN_FEATURE_11W + 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 +#endif + 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 { + hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type); + hdd_translate_sae_rsn_to_csr_auth(auth_suite, &auth_type); + } + hdd_debug("auth_type: %d", auth_type); + return auth_type; +} + +/** + * hdd_translate_wpa_to_csr_auth_type() - Translate WPA to CSR auth type + * @auth_suite: auth suite + * + * Return: eCsrAuthType enumeration + */ +eCsrAuthType hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]) +{ + eCsrAuthType 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); + } + hdd_debug("auth_type: %d", 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; + + hdd_debug("cipher_type: %d", cipher_type); + 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; + + hdd_debug("cipher_type: %d", cipher_type); + return cipher_type; +} + +#ifdef WLAN_FEATURE_FILS_SK +bool hdd_is_fils_connection(struct hdd_adapter *adapter) +{ + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + if (roam_profile->fils_con_info) + return roam_profile->fils_con_info->is_fils_connection; + + return false; +} +#else +bool hdd_is_fils_connection(struct hdd_adapter *adapter) +{ + return false; +} +#endif + +/** + * hdd_process_genie() - process gen ie + * @adapter: pointer to adapter + * @bssid: pointer to mac address + * @pEncryptType: pointer to encryption type + * @mcEncryptType: pointer to multicast encryption type + * @pAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +static int32_t hdd_process_genie(struct hdd_adapter *adapter, + u8 *bssid, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, +#ifdef WLAN_FEATURE_11W + uint8_t *pMfpRequired, uint8_t *pMfpCapable, +#endif + uint16_t gen_ie_len, uint8_t *gen_ie) +{ + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + tDot11fIERSN dot11RSNIE = {0}; + tDot11fIEWPA dot11WPAIE = {0}; + uint8_t *pRsnIe; + uint16_t RSNIeLen; + uint32_t parse_status; + + /* + * Clear struct of tDot11fIERSN and tDot11fIEWPA specifically + * setting present flag to 0. + */ + memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA)); + memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN)); + + /* 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)) { + hdd_err("Invalid DOT11F RSN IE length: %d", + gen_ie_len); + return -EINVAL; + } + /* Skip past the EID byte and length byte */ + pRsnIe = gen_ie + 2; + RSNIeLen = gen_ie_len - 2; + /* Unpack the RSN IE */ + parse_status = sme_unpack_rsn_ie(mac_handle, pRsnIe, RSNIeLen, + &dot11RSNIE, false); + if (!DOT11F_SUCCEEDED(parse_status)) { + hdd_err("Invalid RSN IE: parse status %d", + parse_status); + return -EINVAL; + } + hdd_debug("gp_cipher_suite_present: %d", + dot11RSNIE.gp_cipher_suite_present); + /* Copy out the encryption and authentication types */ + hdd_debug("pairwise cipher suite count: %d", + dot11RSNIE.pwise_cipher_suite_count); + hdd_debug("authentication suite count: %d", + dot11RSNIE.akm_suite_cnt); + /* dot11RSNIE.akm_suite_cnt */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_rsn_to_csr_auth_type( + dot11RSNIE.akm_suite[0]); + /* dot11RSNIE.pwise_cipher_suite_count */ + *pEncryptType = + hdd_translate_rsn_to_csr_encryption_type( + dot11RSNIE.pwise_cipher_suites[0]); + /* dot11RSNIE.gp_cipher_suite_count */ + *mcEncryptType = + hdd_translate_rsn_to_csr_encryption_type( + dot11RSNIE.gp_cipher_suite); +#ifdef WLAN_FEATURE_11W + *pMfpRequired = (dot11RSNIE.RSN_Cap[0] >> 6) & 0x1; + *pMfpCapable = csr_is_mfpc_capable(&dot11RSNIE); +#endif + } 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)) { + hdd_err("Invalid DOT11F WPA IE length: %d", + gen_ie_len); + return -EINVAL; + } + /* Skip past the EID and length byte - and four byte WiFi OUI */ + pRsnIe = gen_ie + 2 + 4; + RSNIeLen = gen_ie_len - (2 + 4); + /* Unpack the WPA IE */ + parse_status = dot11f_unpack_ie_wpa((tpAniSirGlobal)mac_handle, + pRsnIe, RSNIeLen, &dot11WPAIE, false); + if (!DOT11F_SUCCEEDED(parse_status)) { + hdd_err("Invalid WPA IE: parse status %d", + parse_status); + return -EINVAL; + } + /* Copy out the encryption and authentication types */ + hdd_debug("WPA unicast cipher suite count: %d", + dot11WPAIE.unicast_cipher_count); + hdd_debug("WPA authentication suite count: %d", + dot11WPAIE.auth_suite_count); + /* dot11WPAIE.auth_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_wpa_to_csr_auth_type( + dot11WPAIE.auth_suites[0]); + /* dot11WPAIE.unicast_cipher_count */ + *pEncryptType = + hdd_translate_wpa_to_csr_encryption_type( + dot11WPAIE.unicast_ciphers[0]); + /* dot11WPAIE.unicast_cipher_count */ + *mcEncryptType = + hdd_translate_wpa_to_csr_encryption_type( + dot11WPAIE.multicast_cipher); + } else { + hdd_warn("gen_ie[0]: %d", gen_ie[0]); + return -EINVAL; + } + return 0; +} + +/** + * hdd_set_def_rsne_override() - set default encryption type and auth type + * in profile. + * @roam_profile: pointer to adapter + * @auth_type: pointer to auth type + * + * Set default value of encryption type and auth type in profile to + * search the AP using filter, as in force_rsne_override the RSNIE can be + * currupt and we might not get the proper encryption type and auth type + * while parsing the RSNIE. + * + * Return: void + */ +static void hdd_set_def_rsne_override( + struct csr_roam_profile *roam_profile, eCsrAuthType *auth_type) +{ + + hdd_debug("Set def values in roam profile"); + roam_profile->MFPCapable = roam_profile->MFPEnabled; + roam_profile->EncryptionType.numEntries = 2; + roam_profile->mcEncryptionType.numEntries = 2; + /* Use the cipher type in the RSN IE */ + roam_profile->EncryptionType.encryptionType[0] = eCSR_ENCRYPT_TYPE_AES; + roam_profile->EncryptionType.encryptionType[1] = eCSR_ENCRYPT_TYPE_TKIP; + roam_profile->mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_AES; + roam_profile->mcEncryptionType.encryptionType[1] = + eCSR_ENCRYPT_TYPE_TKIP; + *auth_type = eCSR_AUTH_TYPE_RSN_PSK; +} + +/** + * hdd_set_genie_to_csr() - set genie to csr + * @adapter: pointer to adapter + * @RSNAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_genie_to_csr(struct hdd_adapter *adapter, + eCsrAuthType *RSNAuthType) +{ + struct csr_roam_profile *roam_profile; + uint8_t *security_ie; + uint32_t status = 0; + eCsrEncryptionType RSNEncryptType; + eCsrEncryptionType mcRSNEncryptType; + struct hdd_context *hdd_ctx; +#ifdef WLAN_FEATURE_11W + uint8_t RSNMfpRequired = 0; + uint8_t RSNMfpCapable = 0; +#endif + u8 bssid[ETH_ALEN]; /* MAC address of assoc peer */ + + roam_profile = hdd_roam_profile(adapter); + security_ie = hdd_security_ie(adapter); + + /* MAC address of assoc peer */ + /* But, this routine is only called when we are NOT associated. */ + qdf_mem_copy(bssid, roam_profile->BSSIDs.bssid, sizeof(bssid)); + if (security_ie[0] == DOT11F_EID_RSN || + security_ie[0] == DOT11F_EID_WPA) { + /* continue */ + } else { + return 0; + } + + /* 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_process_genie(adapter, bssid, + &RSNEncryptType, + &mcRSNEncryptType, RSNAuthType, +#ifdef WLAN_FEATURE_11W + &RSNMfpRequired, &RSNMfpCapable, +#endif + security_ie[1] + 2, + security_ie); + + if (status == 0) { + /* + * Now copy over all the security attributes + * you have parsed out. + */ + roam_profile->EncryptionType.numEntries = 1; + roam_profile->mcEncryptionType.numEntries = 1; + + /* Use the cipher type in the RSN IE */ + roam_profile->EncryptionType.encryptionType[0] = + RSNEncryptType; + roam_profile->mcEncryptionType.encryptionType[0] = + mcRSNEncryptType; + + if ((QDF_IBSS_MODE == adapter->device_mode) && + ((eCSR_ENCRYPT_TYPE_AES == mcRSNEncryptType) || + (eCSR_ENCRYPT_TYPE_AES_GCMP == mcRSNEncryptType) || + (eCSR_ENCRYPT_TYPE_AES_GCMP_256 == mcRSNEncryptType) || + (eCSR_ENCRYPT_TYPE_TKIP == mcRSNEncryptType))) { + /* + * For wpa none supplicant sends the WPA IE with unicast + * cipher as eCSR_ENCRYPT_TYPE_NONE ,where as the + * multicast cipher as either AES/TKIP based on group + * cipher configuration mentioned in the + * wpa_supplicant.conf. + */ + + /* Set the unicast cipher same as multicast cipher */ + roam_profile->EncryptionType.encryptionType[0] + = mcRSNEncryptType; + } +#ifdef WLAN_FEATURE_11W + hdd_debug("RSNMfpRequired = %d, RSNMfpCapable = %d", + RSNMfpRequired, RSNMfpCapable); + roam_profile->MFPRequired = RSNMfpRequired; + roam_profile->MFPCapable = RSNMfpCapable; +#endif + hdd_debug("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d", + *RSNAuthType, RSNEncryptType, mcRSNEncryptType); + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx->force_rsne_override && + (security_ie[0] == DOT11F_EID_RSN)) { + hdd_warn("Test mode enabled set def Auth and enc type. RSN IE passed in connect req: "); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + roam_profile->pRSNReqIE, + roam_profile->nRSNReqIELength); + + roam_profile->force_rsne_override = true; + + hdd_debug("MFPEnabled %d", roam_profile->MFPEnabled); + /* + * Reset MFPEnabled if testmode RSNE passed doesn't have MFPR + * or MFPC bit set + */ + if (roam_profile->MFPEnabled && + !(roam_profile->MFPRequired || + roam_profile->MFPCapable)) { + hdd_debug("Reset MFPEnabled"); + roam_profile->MFPEnabled = 0; + } + /* If parsing failed set the def value for the roam profile */ + if (status) + hdd_set_def_rsne_override(roam_profile, RSNAuthType); + return 0; + } + return status; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * hdd_check_fils_rsn_n_set_auth_type() - This API checks whether a give + * auth type is fils if yes, sets it in profile. + * @rsn_auth_type: auth type + * + * Return: true if FILS auth else false + */ +static +bool hdd_check_fils_rsn_n_set_auth_type(struct csr_roam_profile *roam_profile, + eCsrAuthType rsn_auth_type) +{ + bool is_fils_rsn = false; + + if (!roam_profile->fils_con_info) + return false; + + if ((rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA256) || + (rsn_auth_type == eCSR_AUTH_TYPE_FILS_SHA384) || + (rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA256) || + (rsn_auth_type == eCSR_AUTH_TYPE_FT_FILS_SHA384)) + is_fils_rsn = true; + if (is_fils_rsn) + roam_profile->fils_con_info->akm_type = rsn_auth_type; + + return is_fils_rsn; +} +#else +static +bool hdd_check_fils_rsn_n_set_auth_type(struct csr_roam_profile *roam_profile, + eCsrAuthType rsn_auth_type) +{ + return false; +} +#endif + +/** + * hdd_set_csr_auth_type() - set csr auth type + * @adapter: pointer to adapter + * @RSNAuthType: auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_csr_auth_type(struct hdd_adapter *adapter, + eCsrAuthType RSNAuthType) +{ + struct csr_roam_profile *roam_profile; + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + enum hdd_auth_key_mgmt key_mgmt = sta_ctx->auth_key_mgmt; + + roam_profile = hdd_roam_profile(adapter); + roam_profile->AuthType.numEntries = 1; + hdd_debug("authType = %d RSNAuthType %d wpa_versions %d key_mgmt: 0x%x", + sta_ctx->conn_info.authType, RSNAuthType, + sta_ctx->wpa_versions, key_mgmt); + + switch (sta_ctx->conn_info.authType) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + case eCSR_AUTH_TYPE_AUTOSWITCH: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: +#endif + if (!sta_ctx->wpa_versions) { + + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + } else if (sta_ctx->wpa_versions & NL80211_WPA_VERSION_1) { + +#ifdef FEATURE_WLAN_ESE + if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) && + ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X)) { + hdd_debug("set authType to CCKM WPA. AKM also 802.1X."); + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_WPA; + } else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) { + hdd_debug("Last chance to set authType to CCKM WPA."); + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_WPA; + } else +#endif + if ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA; + } else + if ((key_mgmt & HDD_AUTH_KEY_MGMT_PSK) + == HDD_AUTH_KEY_MGMT_PSK) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA_PSK; + } else { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA_NONE; + } + } + if (sta_ctx->wpa_versions & NL80211_WPA_VERSION_2) { +#ifdef FEATURE_WLAN_ESE + if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) && + ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X)) { + hdd_debug("set authType to CCKM RSN. AKM also 802.1X."); + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_RSN; + } else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) { + hdd_debug("Last chance to set authType to CCKM RSN."); + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_RSN; + } else +#endif + if (RSNAuthType == eCSR_AUTH_TYPE_DPP_RSN) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_DPP_RSN; + } else if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN) && + ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X)) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_FT_RSN; + } else if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN_PSK) + && + ((key_mgmt & HDD_AUTH_KEY_MGMT_PSK) + == HDD_AUTH_KEY_MGMT_PSK)) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_FT_RSN_PSK; + } else + +#ifdef WLAN_FEATURE_11W + if (RSNAuthType == eCSR_AUTH_TYPE_RSN_PSK_SHA256) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } else if (RSNAuthType == + eCSR_AUTH_TYPE_RSN_8021X_SHA256) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } else +#endif + if (hdd_check_fils_rsn_n_set_auth_type(roam_profile, + RSNAuthType)) { + roam_profile->AuthType.authType[0] = + RSNAuthType; + hdd_debug("updated profile authtype as %d", + RSNAuthType); + + } else if ((RSNAuthType == eCSR_AUTH_TYPE_OWE) && + ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X)) { + /* OWE case */ + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_OWE; + } else if (RSNAuthType == eCSR_AUTH_TYPE_SAE) { + /* SAE with open authentication case */ + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_SAE; + } else if ((RSNAuthType == + eCSR_AUTH_TYPE_SUITEB_EAP_SHA256) && + ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X)) { + /* Suite B EAP SHA 256 */ + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_SUITEB_EAP_SHA256; + } else if ((RSNAuthType == + eCSR_AUTH_TYPE_SUITEB_EAP_SHA384) && + ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X)) { + /* Suite B EAP SHA 384 */ + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; + } else if ((key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) + == HDD_AUTH_KEY_MGMT_802_1X) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN; + } else + if ((key_mgmt & HDD_AUTH_KEY_MGMT_PSK) + == HDD_AUTH_KEY_MGMT_PSK) { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_PSK; + } else { + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_UNKNOWN; + } + } + break; + + case eCSR_AUTH_TYPE_SHARED_KEY: + + roam_profile->AuthType.authType[0] = eCSR_AUTH_TYPE_SHARED_KEY; + break; + + case eCSR_AUTH_TYPE_SAE: + roam_profile->AuthType.authType[0] = eCSR_AUTH_TYPE_SAE; + break; + + default: + +#ifdef FEATURE_WLAN_ESE + hdd_debug("In default, unknown auth type."); +#endif /* FEATURE_WLAN_ESE */ + roam_profile->AuthType.authType[0] = eCSR_AUTH_TYPE_UNKNOWN; + break; + } + + hdd_debug("Set roam Authtype to %d", + roam_profile->AuthType.authType[0]); + + return 0; +} + +#ifdef WLAN_FEATURE_FILS_SK +static void hdd_initialize_fils_info(struct hdd_adapter *adapter) +{ + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + roam_profile->fils_con_info = NULL; + roam_profile->hlp_ie = NULL; + roam_profile->hlp_ie_len = 0; +} +#else +static void hdd_initialize_fils_info(struct hdd_adapter *adapter) +{ } +#endif + +void hdd_roam_profile_init(struct hdd_adapter *adapter) +{ + struct csr_roam_profile *roam_profile; + uint8_t *security_ie; + tSirAddie *assoc_additional_ie; + struct hdd_station_ctx *sta_ctx; + + hdd_enter(); + + roam_profile = hdd_roam_profile(adapter); + qdf_mem_zero(roam_profile, sizeof(*roam_profile)); + + security_ie = hdd_security_ie(adapter); + qdf_mem_zero(security_ie, MAX_WPA_RSN_IE_LEN); + + assoc_additional_ie = hdd_assoc_additional_ie(adapter); + qdf_mem_zero(assoc_additional_ie, sizeof(*assoc_additional_ie)); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* 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.ChannelList = NULL; + + roam_profile->BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE; + + roam_profile->phyMode = eCSR_DOT11_MODE_AUTO; + sta_ctx->wpa_versions = 0; + + /* Set the default scan mode */ + adapter->scan_info.scan_mode = eSIR_ACTIVE_SCAN; + + hdd_clear_roam_profile_ie(adapter); + + hdd_initialize_fils_info(adapter); + + hdd_exit(); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c new file mode 100644 index 0000000000000000000000000000000000000000..0053546ee1bdcb4667cba344e856feb854ff82e0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c @@ -0,0 +1,10210 @@ +/* + * 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: 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 "wlan_hdd_he.h" +#include +#include "wifi_pos_api.h" +#include "wlan_hdd_green_ap.h" +#include "wlan_hdd_green_ap_cfg.h" +#include "wlan_hdd_twt.h" + +static void +cb_notify_set_roam_prefer5_g_hz(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_update_roam_prefer5_g_hz(hdd_ctx->mac_handle, + hdd_ctx->config->nRoamPrefer5GHz); +} + +static void +cb_notify_set_roam_rssi_diff(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_update_roam_rssi_diff(hdd_ctx->mac_handle, + 0, hdd_ctx->config->RoamRssiDiff); +} + +static void +cb_notify_set_fast_transition_enabled(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + bool enabled = hdd_ctx->config->isFastTransitionEnabled; + + sme_update_fast_transition_enabled(hdd_ctx->mac_handle, enabled); +} + +static void +cb_notify_set_roam_intra_band(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_set_roam_intra_band(hdd_ctx->mac_handle, + hdd_ctx->config->nRoamIntraBand); +} + +static void cb_notify_set_wes_mode(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_update_wes_mode(hdd_ctx->mac_handle, + hdd_ctx->config->isWESModeEnabled, 0); +} + +static void +cb_notify_set_roam_scan_n_probes(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_update_roam_scan_n_probes(hdd_ctx->mac_handle, 0, + hdd_ctx->config->nProbes); +} + +static void +cb_notify_set_roam_scan_home_away_time(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint16_t away_time = hdd_ctx->config->nRoamScanHomeAwayTime; + + sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle, 0, + away_time, true); +} + +static void +notify_is_fast_roam_ini_feature_enabled(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + bool enabled = hdd_ctx->config->isFastRoamIniFeatureEnabled; + + sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle, 0, + enabled); +} + +static void +notify_is_mawc_ini_feature_enabled(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_update_is_mawc_ini_feature_enabled(hdd_ctx->mac_handle, + hdd_ctx->config->MAWCEnabled); +} + +#ifdef FEATURE_WLAN_ESE +static void +cb_notify_set_ese_feature_enabled(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + bool enabled = hdd_ctx->config->isEseIniFeatureEnabled; + + sme_update_is_ese_feature_enabled(hdd_ctx->mac_handle, 0, enabled); +} +#endif + +static void +cb_notify_set_opportunistic_scan_threshold_diff(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint8_t diff = hdd_ctx->config->nOpportunisticThresholdDiff; + + sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle, + 0, diff); +} + +static void cb_notify_set_roam_rescan_rssi_diff(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle, + 0, hdd_ctx->config->nRoamRescanRssiDiff); +} + +static void +cb_notify_set_neighbor_lookup_rssi_threshold(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint8_t threshold = hdd_ctx->config->nNeighborLookupRssiThreshold; + + sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle, 0, + threshold); +} + +static void +cb_notify_set_delay_before_vdev_stop(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_set_delay_before_vdev_stop(hdd_ctx->mac_handle, 0, + hdd_ctx->config->delay_before_vdev_stop); +} + +static void +cb_notify_set_neighbor_scan_period(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_set_neighbor_scan_period(hdd_ctx->mac_handle, 0, + hdd_ctx->config->nNeighborScanPeriod); +} + +/* + * cb_notify_set_neighbor_scan_min_period() - configure min rest + * time during roaming scan + * + * @hdd_ctx: HDD context data structure + * @notify_id: Identifies 1 of the 4 parameters to be modified + * + * Picks up the value from hdd configuration and passes it to SME. + * Return: void + */ +static void +cb_notify_set_neighbor_scan_min_period(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint16_t period = hdd_ctx->config->neighbor_scan_min_period; + + sme_set_neighbor_scan_min_period(hdd_ctx->mac_handle, 0, + period); +} + +static void +cb_notify_set_neighbor_results_refresh_period(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint16_t period = hdd_ctx->config->nNeighborResultsRefreshPeriod; + + sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle, 0, + period); +} + +static void +cb_notify_set_empty_scan_refresh_period(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint16_t period = hdd_ctx->config->nEmptyScanRefreshPeriod; + + sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle, 0, + period); +} + +static void +cb_notify_set_neighbor_scan_min_chan_time(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint16_t min_chan_time = hdd_ctx->config->nNeighborScanMinChanTime; + + sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle, + min_chan_time, 0); +} + +static void +cb_notify_set_neighbor_scan_max_chan_time(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint16_t max_chan_time = hdd_ctx->config->nNeighborScanMaxChanTime; + + sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle, 0, + max_chan_time); +} + +static void cb_notify_set_roam_bmiss_first_bcnt(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_set_roam_bmiss_first_bcnt(hdd_ctx->mac_handle, + 0, hdd_ctx->config->nRoamBmissFirstBcnt); +} + +static void cb_notify_set_roam_bmiss_final_bcnt(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_set_roam_bmiss_final_bcnt(hdd_ctx->mac_handle, 0, + hdd_ctx->config->nRoamBmissFinalBcnt); +} + +static void cb_notify_set_roam_beacon_rssi_weight(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_set_roam_beacon_rssi_weight(hdd_ctx->mac_handle, 0, + hdd_ctx->config->nRoamBeaconRssiWeight); +} + +static void +cb_notify_set_dfs_scan_mode(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_update_dfs_scan_mode(hdd_ctx->mac_handle, 0, + hdd_ctx->config->allowDFSChannelRoam); +} + +static void cb_notify_set_enable_ssr(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + sme_update_enable_ssr(hdd_ctx->mac_handle, hdd_ctx->config->enableSSR); +} + +static void +cb_notify_set_g_sap_preferred_chan_location(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + uint8_t location = hdd_ctx->config->gSapPreferredChanLocation; + + wlansap_set_dfs_preferred_channel_location(hdd_ctx->mac_handle, + location); +} + +static void ch_notify_set_g_disable_dfs_japan_w53(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + bool disabled = hdd_ctx->config->gDisableDfsJapanW53; + + wlansap_set_dfs_restrict_japan_w53(hdd_ctx->mac_handle, disabled); +} + +static void +cb_notify_update_roam_scan_offload_enabled(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + bool enabled = hdd_ctx->config->isRoamOffloadScanEnabled; + + sme_update_roam_scan_offload_enabled(hdd_ctx->mac_handle, enabled); + if (enabled) + return; + + /* fate sharing */ + hdd_ctx->config->bFastRoamInConIniFeatureEnabled = false; + sme_update_enable_fast_roam_in_concurrency(hdd_ctx->mac_handle, false); +} + +static void +cb_notify_set_enable_fast_roam_in_concurrency(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + bool enabled = hdd_ctx->config->bFastRoamInConIniFeatureEnabled; + + sme_update_enable_fast_roam_in_concurrency(hdd_ctx->mac_handle, + enabled); +} + +/** + * cb_notify_set_roam_scan_hi_rssi_scan_params() - configure hi rssi + * scan params from cfg to sme. + * @hdd_ctx: HDD context data structure + * @notify_id: Identifies 1 of the 4 parameters to be modified + * + * Picks up the value from hdd configuration and passes it to SME. + * Return: void + */ + +static void +cb_notify_set_roam_scan_hi_rssi_scan_params(struct hdd_context *hdd_ctx, + unsigned long notify_id) +{ + int32_t val; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + switch (notify_id) { + case eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: + val = hdd_ctx->config->nhi_rssi_scan_max_count; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: + val = hdd_ctx->config->nhi_rssi_scan_rssi_delta; + break; + + case eCSR_HI_RSSI_SCAN_DELAY_ID: + val = hdd_ctx->config->nhi_rssi_scan_delay; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_UB_ID: + val = hdd_ctx->config->nhi_rssi_scan_rssi_ub; + break; + + default: + return; + } + + sme_update_roam_scan_hi_rssi_scan_params(hdd_ctx->mac_handle, 0, + notify_id, val); +} + + +struct reg_table_entry g_registry_table[] = { +#ifdef WLAN_NUD_TRACKING + REG_VARIABLE(CFG_ENABLE_NUD_TRACKING_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_nud_tracking, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NUD_TRACKING_DEFAULT, + CFG_ENABLE_NUD_TRACKING_MIN, + CFG_ENABLE_NUD_TRACKING_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_CONNECTED_SCAN_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_connected_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CONNECTED_SCAN_DEFAULT, + CFG_ENABLE_CONNECTED_SCAN_MIN, + CFG_ENABLE_CONNECTED_SCAN_MAX), + + REG_VARIABLE(CFG_RTS_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, RTSThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RTS_THRESHOLD_DEFAULT, + CFG_RTS_THRESHOLD_MIN, + CFG_RTS_THRESHOLD_MAX), + + REG_VARIABLE(CFG_FRAG_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, FragmentationThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FRAG_THRESHOLD_DEFAULT, + CFG_FRAG_THRESHOLD_MIN, + CFG_FRAG_THRESHOLD_MAX), + + REG_VARIABLE(CFG_OPERATING_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, OperatingChannel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPERATING_CHANNEL_DEFAULT, + CFG_OPERATING_CHANNEL_MIN, + CFG_OPERATING_CHANNEL_MAX), + + REG_VARIABLE(CFG_SHORT_SLOT_TIME_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortSlotTimeEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SHORT_SLOT_TIME_ENABLED_DEFAULT, + CFG_SHORT_SLOT_TIME_ENABLED_MIN, + CFG_SHORT_SLOT_TIME_ENABLED_MAX), + + REG_VARIABLE(CFG_11D_SUPPORT_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, Is11dSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_11D_SUPPORT_ENABLED_DEFAULT, + CFG_11D_SUPPORT_ENABLED_MIN, + CFG_11D_SUPPORT_ENABLED_MAX), + + REG_VARIABLE(CFG_11H_SUPPORT_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, Is11hSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_11H_SUPPORT_ENABLED_DEFAULT, + CFG_11H_SUPPORT_ENABLED_MIN, + CFG_11H_SUPPORT_ENABLED_MAX), + + REG_VARIABLE(CFG_COUNTRY_CODE_PRIORITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, fSupplicantCountryCodeHasPriority, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_COUNTRY_CODE_PRIORITY_DEFAULT, + CFG_COUNTRY_CODE_PRIORITY_MIN, + CFG_COUNTRY_CODE_PRIORITY_MAX), + + REG_VARIABLE(CFG_HEARTBEAT_THRESH_24_NAME, WLAN_PARAM_Integer, + struct hdd_config, HeartbeatThresh24, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HEARTBEAT_THRESH_24_DEFAULT, + CFG_HEARTBEAT_THRESH_24_MIN, + CFG_HEARTBEAT_THRESH_24_MAX), + + REG_VARIABLE_STRING(CFG_POWER_USAGE_NAME, WLAN_PARAM_String, + struct hdd_config, PowerUsageControl, + VAR_FLAGS_OPTIONAL, + (void *)CFG_POWER_USAGE_DEFAULT), + + REG_VARIABLE(CFG_ENABLE_IMPS_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsImpsEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_IMPS_DEFAULT, + CFG_ENABLE_IMPS_MIN, + CFG_ENABLE_IMPS_MAX), + + REG_VARIABLE(CFG_ENABLE_PS_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_ps_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PS_DEFAULT, + CFG_ENABLE_PS_MIN, + CFG_ENABLE_PS_MAX), + + REG_VARIABLE(CFG_AUTO_PS_ENABLE_TIMER_NAME, WLAN_PARAM_Integer, + struct hdd_config, auto_bmps_timer_val, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AUTO_PS_ENABLE_TIMER_DEFAULT, + CFG_AUTO_PS_ENABLE_TIMER_MIN, + CFG_AUTO_PS_ENABLE_TIMER_MAX), + +#ifdef WLAN_ICMP_DISABLE_PS + REG_VARIABLE(CFG_ICMP_DISABLE_PS_NAME, WLAN_PARAM_Integer, + struct hdd_config, icmp_disable_ps_val, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ICMP_DISABLE_PS_DEFAULT, + CFG_ICMP_DISABLE_PS_MIN, + CFG_ICMP_DISABLE_PS_MAX), +#endif + + REG_VARIABLE(CFG_BMPS_MINIMUM_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsMinListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MINIMUM_LI_DEFAULT, + CFG_BMPS_MINIMUM_LI_MIN, + CFG_BMPS_MINIMUM_LI_MAX), + + REG_VARIABLE(CFG_BMPS_MAXIMUM_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsMaxListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MAXIMUM_LI_DEFAULT, + CFG_BMPS_MAXIMUM_LI_MIN, + CFG_BMPS_MAXIMUM_LI_MAX), + + REG_VARIABLE(CFG_DOT11_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dot11Mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_DOT11_MODE_DEFAULT, + CFG_DOT11_MODE_MIN, + CFG_DOT11_MODE_MAX), + + REG_VARIABLE(CFG_CHANNEL_BONDING_MODE_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, nChannelBondingMode24GHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_CHANNEL_BONDING_MODE_DEFAULT, + CFG_CHANNEL_BONDING_MODE_MIN, + CFG_CHANNEL_BONDING_MODE_MAX), + + REG_VARIABLE(CFG_OVERRIDE_HT40_20_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, override_ht20_40_24g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OVERRIDE_HT40_20_24GHZ_DEFAULT, + CFG_OVERRIDE_HT40_20_24GHZ_MIN, + CFG_OVERRIDE_HT40_20_24GHZ_MAX), + + REG_VARIABLE(CFG_CHANNEL_BONDING_MODE_5GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, nChannelBondingMode5GHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_CHANNEL_BONDING_MODE_DEFAULT, + CFG_CHANNEL_BONDING_MODE_MIN, + CFG_CHANNEL_BONDING_MODE_MAX), + + REG_VARIABLE(CFG_MAX_RX_AMPDU_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, MaxRxAmpduFactor, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_MAX_RX_AMPDU_FACTOR_DEFAULT, + CFG_MAX_RX_AMPDU_FACTOR_MIN, + CFG_MAX_RX_AMPDU_FACTOR_MAX), + + REG_VARIABLE(CFG_HT_MPDU_DENSITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, ht_mpdu_density, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_HT_MPDU_DENSITY_DEFAULT, + CFG_HT_MPDU_DENSITY_MIN, + CFG_HT_MPDU_DENSITY_MAX), + + REG_VARIABLE(CFG_SHORT_GI_20MHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortGI20MhzEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_GI_20MHZ_DEFAULT, + CFG_SHORT_GI_20MHZ_MIN, + CFG_SHORT_GI_20MHZ_MAX), + + REG_VARIABLE(CFG_SCAN_RESULT_AGE_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, ScanResultAgeCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SCAN_RESULT_AGE_COUNT_DEFAULT, + CFG_SCAN_RESULT_AGE_COUNT_MIN, + CFG_SCAN_RESULT_AGE_COUNT_MAX), + + REG_VARIABLE(CFG_RSSI_CATEGORY_GAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRssiCatGap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RSSI_CATEGORY_GAP_DEFAULT, + CFG_RSSI_CATEGORY_GAP_MIN, + CFG_RSSI_CATEGORY_GAP_MAX), + + REG_VARIABLE(CFG_SHORT_PREAMBLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsShortPreamble, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_PREAMBLE_DEFAULT, + CFG_SHORT_PREAMBLE_MIN, + CFG_SHORT_PREAMBLE_MAX), + + REG_VARIABLE_STRING(CFG_IBSS_BSSID_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, IbssBssid, + VAR_FLAGS_OPTIONAL, + (void *)CFG_IBSS_BSSID_DEFAULT), + + REG_VARIABLE(CFG_AP_QOS_UAPSD_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apUapsdEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_QOS_UAPSD_MODE_DEFAULT, + CFG_AP_QOS_UAPSD_MODE_MIN, + CFG_AP_QOS_UAPSD_MODE_MAX), + + + REG_VARIABLE(CFG_AP_ENABLE_RANDOM_BSSID_NAME, WLAN_PARAM_Integer, + struct hdd_config, apRandomBssidEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_ENABLE_RANDOM_BSSID_DEFAULT, + CFG_AP_ENABLE_RANDOM_BSSID_MIN, + CFG_AP_ENABLE_RANDOM_BSSID_MAX), + + REG_VARIABLE(CFG_AP_ENABLE_PROTECTION_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apProtEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_ENABLE_PROTECTION_MODE_DEFAULT, + CFG_AP_ENABLE_PROTECTION_MODE_MIN, + CFG_AP_ENABLE_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_PROTECTION_MODE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, apProtection, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_PROTECTION_MODE_DEFAULT, + CFG_AP_PROTECTION_MODE_MIN, + CFG_AP_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_OBSS_PROTECTION_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apOBSSProtEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_OBSS_PROTECTION_MODE_DEFAULT, + CFG_AP_OBSS_PROTECTION_MODE_MIN, + CFG_AP_OBSS_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_STA_SECURITY_SEPERATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, apDisableIntraBssFwd, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_STA_SECURITY_SEPERATION_DEFAULT, + CFG_AP_STA_SECURITY_SEPERATION_MIN, + CFG_AP_STA_SECURITY_SEPERATION_MAX), + + REG_VARIABLE(CFG_ENABLE_LTE_COEX, WLAN_PARAM_Integer, + struct hdd_config, enableLTECoex, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LTE_COEX_DEFAULT, + CFG_ENABLE_LTE_COEX_MIN, + CFG_ENABLE_LTE_COEX_MAX), + + REG_VARIABLE(CFG_VC_MODE_BITMAP, WLAN_PARAM_HexInteger, + struct hdd_config, vc_mode_cfg_bitmap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VC_MODE_BITMAP_DEFAULT, + CFG_VC_MODE_BITMAP_MIN, + CFG_VC_MODE_BITMAP_MAX), + + REG_VARIABLE(CFG_ENABLE_SAP_MANDATORY_CHAN_LIST, WLAN_PARAM_Integer, + struct hdd_config, enable_sap_mandatory_chan_list, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_DEFAULT, + CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MIN, + CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MAX), + + REG_VARIABLE(CFG_AP_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_AP_KEEP_ALIVE_PERIOD_MIN, + CFG_AP_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_GO_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, goKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_GO_KEEP_ALIVE_PERIOD_MIN, + CFG_GO_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_AP_LINK_MONITOR_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apLinkMonitorPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_LINK_MONITOR_PERIOD_DEFAULT, + CFG_AP_LINK_MONITOR_PERIOD_MIN, + CFG_AP_LINK_MONITOR_PERIOD_MAX), + + REG_VARIABLE(CFG_GO_LINK_MONITOR_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, goLinkMonitorPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_LINK_MONITOR_PERIOD_DEFAULT, + CFG_GO_LINK_MONITOR_PERIOD_MIN, + CFG_GO_LINK_MONITOR_PERIOD_MAX), + + REG_VARIABLE(CFG_DISABLE_PACKET_FILTER, WLAN_PARAM_Integer, + struct hdd_config, disablePacketFilter, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_PACKET_FILTER_DEFAULT, + CFG_DISABLE_PACKET_FILTER_MIN, + CFG_DISABLE_PACKET_FILTER_MAX), + + REG_VARIABLE(CFG_BEACON_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBeaconInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_BEACON_INTERVAL_DEFAULT, + CFG_BEACON_INTERVAL_MIN, + CFG_BEACON_INTERVAL_MAX), + + REG_VARIABLE(CFG_VCC_RSSI_TRIGGER_NAME, WLAN_PARAM_Integer, + struct hdd_config, nVccRssiTrigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VCC_RSSI_TRIGGER_DEFAULT, + CFG_VCC_RSSI_TRIGGER_MIN, + CFG_VCC_RSSI_TRIGGER_MAX), + + REG_VARIABLE(CFG_VCC_UL_MAC_LOSS_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, nVccUlMacLossThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VCC_UL_MAC_LOSS_THRESH_DEFAULT, + CFG_VCC_UL_MAC_LOSS_THRESH_MIN, + CFG_VCC_UL_MAC_LOSS_THRESH_MAX), + + REG_VARIABLE(CFG_DROP_BCN_ON_CHANNEL_MISMATCH, WLAN_PARAM_Integer, + struct hdd_config, drop_bcn_on_chan_mismatch, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DROP_BCN_ON_CHANNEL_MISMATCH_DEFAULT, + CFG_DROP_BCN_ON_CHANNEL_MISMATCH_MIN, + CFG_DROP_BCN_ON_CHANNEL_MISMATCH_MAX), + + REG_VARIABLE(CFG_PASSIVE_MAX_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMaxChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_MIN, + CFG_PASSIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_PASSIVE_MIN_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMinChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_MIN, + CFG_PASSIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_ACTIVE_MAX_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMaxChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_MIN, + CFG_ACTIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_ACTIVE_MAX_2G_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, active_dwell_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_2G_CHANNEL_TIME_DEFAULT, + CFG_ACTIVE_MAX_2G_CHANNEL_TIME_MIN, + CFG_ACTIVE_MAX_2G_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_ACTIVE_MIN_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMinChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_MIN, + CFG_ACTIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_SCAN_NUM_PROBES_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_num_probes, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SCAN_NUM_PROBES_DEFAULT, + CFG_SCAN_NUM_PROBES_MIN, + CFG_SCAN_NUM_PROBES_MAX), + + REG_VARIABLE(CFG_SCAN_PROBE_REPEAT_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_probe_repeat_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SCAN_PROBE_REPEAT_TIME_DEFAULT, + CFG_SCAN_PROBE_REPEAT_TIME_MIN, + CFG_SCAN_PROBE_REPEAT_TIME_MAX), + + REG_VARIABLE(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMaxChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMinChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMaxChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMinChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_REST_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRestTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REST_TIME_CONC_DEFAULT, + CFG_REST_TIME_CONC_MIN, + CFG_REST_TIME_CONC_MAX), + + REG_VARIABLE(CFG_MIN_REST_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, min_rest_time_conc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MIN_REST_TIME_DEFAULT, + CFG_MIN_REST_TIME_MIN, + CFG_MIN_REST_TIME_MAX), + + REG_VARIABLE(CFG_IDLE_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, idle_time_conc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IDLE_TIME_DEFAULT, + CFG_IDLE_TIME_MIN, + CFG_IDLE_TIME_MAX), + + REG_VARIABLE(CFG_MAX_PS_POLL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nMaxPsPoll, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_PS_POLL_DEFAULT, + CFG_MAX_PS_POLL_MIN, + CFG_MAX_PS_POLL_MAX), + + REG_VARIABLE(CFG_MAX_TX_POWER_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTxPowerCap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_TX_POWER_DEFAULT, + CFG_MAX_TX_POWER_MIN, + CFG_MAX_TX_POWER_MAX), + + REG_VARIABLE(CFG_TX_POWER_CTRL_NAME, WLAN_PARAM_Integer, + struct hdd_config, allow_tpc_from_ap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_POWER_CTRL_DEFAULT, + CFG_TX_POWER_CTRL_MIN, + CFG_TX_POWER_CTRL_MAX), + + REG_VARIABLE(CFG_MAX_LI_MODULATED_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, fMaxLIModulatedDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_LI_MODULATED_DTIM_DEFAULT, + CFG_MAX_LI_MODULATED_DTIM_MIN, + CFG_MAX_LI_MODULATED_DTIM_MAX), + + REG_VARIABLE(CFG_FW_MCC_RTS_CTS_PROT_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcc_rts_cts_prot_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_MCC_RTS_CTS_PROT_DEFAULT, + CFG_FW_MCC_RTS_CTS_PROT_MIN, + CFG_FW_MCC_RTS_CTS_PROT_MAX), + + REG_VARIABLE(CFG_FW_MCC_BCAST_PROB_RESP_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcc_bcast_prob_resp_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_MCC_BCAST_PROB_RESP_DEFAULT, + CFG_FW_MCC_BCAST_PROB_RESP_MIN, + CFG_FW_MCC_BCAST_PROB_RESP_MAX), + + REG_VARIABLE(CFG_DATA_INACTIVITY_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nDataInactivityTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DATA_INACTIVITY_TIMEOUT_DEFAULT, + CFG_DATA_INACTIVITY_TIMEOUT_MIN, + CFG_DATA_INACTIVITY_TIMEOUT_MAX), + + REG_VARIABLE(CFG_WOW_DATA_INACTIVITY_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_data_inactivity_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_DATA_INACTIVITY_TIMEOUT_DEFAULT, + CFG_WOW_DATA_INACTIVITY_TIMEOUT_MIN, + CFG_WOW_DATA_INACTIVITY_TIMEOUT_MAX), + + REG_VARIABLE(CFG_QOS_WMM_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, WmmMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_MODE_DEFAULT, + CFG_QOS_WMM_MODE_MIN, + CFG_QOS_WMM_MODE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_80211E_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, b80211eIsEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_80211E_ENABLED_DEFAULT, + CFG_QOS_WMM_80211E_ENABLED_MIN, + CFG_QOS_WMM_80211E_ENABLED_MAX), + + REG_VARIABLE(CFG_QOS_WMM_UAPSD_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, UapsdMask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_UAPSD_MASK_DEFAULT, + CFG_QOS_WMM_UAPSD_MASK_MIN, + CFG_QOS_WMM_UAPSD_MASK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdVoSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdVoSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdViSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdViSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBeSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBeSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBkSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBkSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MAX), + +#ifdef FEATURE_WLAN_ESE + REG_VARIABLE(CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraInactivityInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_DEFAULT, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MIN, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ESE_FEATURE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isEseIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESE_FEATURE_ENABLED_DEFAULT, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX, + cb_notify_set_ese_feature_enabled, 0), +#endif /* FEATURE_WLAN_ESE */ + + /* flag to turn ON/OFF Legacy Fast Roaming */ + REG_DYNAMIC_VARIABLE(CFG_LFR_FEATURE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isFastRoamIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LFR_FEATURE_ENABLED_DEFAULT, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX, + notify_is_fast_roam_ini_feature_enabled, 0), + + /* flag to turn ON/OFF Motion assistance for Legacy Fast Roaming */ + REG_DYNAMIC_VARIABLE(CFG_LFR_MAWC_FEATURE_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, MAWCEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LFR_MAWC_FEATURE_ENABLED_DEFAULT, + CFG_LFR_MAWC_FEATURE_ENABLED_MIN, + CFG_LFR_MAWC_FEATURE_ENABLED_MAX, + notify_is_mawc_ini_feature_enabled, 0), + + REG_VARIABLE(CFG_MAWC_ROAM_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_roam_enabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_ROAM_ENABLED_DEFAULT, + CFG_MAWC_ROAM_ENABLED_MIN, + CFG_MAWC_ROAM_ENABLED_MAX), + + REG_VARIABLE(CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_roam_traffic_threshold, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_DEFAULT, + CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_MIN, + CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_MAX), + + REG_VARIABLE(CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, struct hdd_config, + mawc_roam_ap_rssi_threshold, VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_DEFAULT, + CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_MIN, + CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_roam_rssi_high_adjust, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_DEFAULT, + CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_MIN, + CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_MAX), + + REG_VARIABLE(CFG_MAWC_ROAM_RSSI_LOW_ADJUST_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_roam_rssi_low_adjust, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_ROAM_RSSI_LOW_ADJUST_DEFAULT, + CFG_MAWC_ROAM_RSSI_LOW_ADJUST_MIN, + CFG_MAWC_ROAM_RSSI_LOW_ADJUST_MAX), + + /* flag to turn ON/OFF 11r and ESE FastTransition */ + REG_DYNAMIC_VARIABLE(CFG_FAST_TRANSITION_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isFastTransitionEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT, + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX, + cb_notify_set_fast_transition_enabled, 0), + + /* Variable to specify the delta/difference between the + * RSSI of current AP and roamable AP while roaming + */ + REG_DYNAMIC_VARIABLE(CFG_ROAM_RSSI_DIFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, RoamRssiDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RSSI_DIFF_DEFAULT, + CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX, + cb_notify_set_roam_rssi_diff, 0), + + REG_VARIABLE(CFG_ROAM_RSSI_ABS_THRESHOLD_NAME, WLAN_PARAM_SignedInteger, + struct hdd_config, rssi_abs_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RSSI_ABS_THRESHOLD_DEFAULT, + CFG_ROAM_RSSI_ABS_THRESHOLD_MIN, + CFG_ROAM_RSSI_ABS_THRESHOLD_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_WES_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, isWESModeEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_WES_MODE_NAME_DEFAULT, + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX, + cb_notify_set_wes_mode, 0), + REG_VARIABLE(CFG_PMKID_MODES_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmkid_modes, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMKID_MODES_DEFAULT, + CFG_PMKID_MODES_MIN, + CFG_PMKID_MODES_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_OFFLOAD_ENABLED, WLAN_PARAM_Integer, + struct hdd_config, isRoamOffloadScanEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_MIN, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX, + cb_notify_update_roam_scan_offload_enabled, 0), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VO_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_VO_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VO_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_VI_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VI_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_VI_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VI_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_BE_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BE_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_BE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BE_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_BK_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BK_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_BK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BK_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_BK_MAX), + + REG_VARIABLE(CFG_TL_DELAYED_TRGR_FRM_INT_NAME, WLAN_PARAM_Integer, + struct hdd_config, DelayedTriggerFrmInt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TL_DELAYED_TRGR_FRM_INT_DEFAULT, + CFG_TL_DELAYED_TRGR_FRM_INT_MIN, + CFG_TL_DELAYED_TRGR_FRM_INT_MAX), + + REG_VARIABLE(CFG_QOS_IMPLICIT_SETUP_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, bImplicitQosEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_IMPLICIT_SETUP_ENABLED_DEFAULT, + CFG_QOS_IMPLICIT_SETUP_ENABLED_MIN, + CFG_QOS_IMPLICIT_SETUP_ENABLED_MAX), + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + REG_VARIABLE(CFG_WLAN_MCC_TO_SCC_SWITCH_MODE, WLAN_PARAM_Integer, + struct hdd_config, WlanMccToSccSwitchMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_DEFAULT, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MIN, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MAX), +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + REG_VARIABLE(CFG_WLAN_AUTO_SHUTDOWN, WLAN_PARAM_Integer, + struct hdd_config, WlanAutoShutdown, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_AUTO_SHUTDOWN_DEFAULT, + CFG_WLAN_AUTO_SHUTDOWN_MIN, + CFG_WLAN_AUTO_SHUTDOWN_MAX), +#endif + REG_VARIABLE(CFG_RRM_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fRrmEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_ENABLE_DEFAULT, + CFG_RRM_ENABLE_MIN, + CFG_RRM_ENABLE_MAX), + + REG_VARIABLE(CFG_RRM_MEAS_RANDOMIZATION_INTVL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRrmRandnIntvl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_DEFAULT, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_MIN, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_MAX), + + REG_VARIABLE_STRING(CFG_RM_CAPABILITY_NAME, WLAN_PARAM_String, + struct hdd_config, rm_capability, + VAR_FLAGS_OPTIONAL, + (void *) CFG_RM_CAPABILITY_DEFAULT), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_TIMER_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX, + cb_notify_set_neighbor_scan_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, neighbor_scan_min_period, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_MIN_TIMER_PERIOD_MAX, + cb_notify_set_neighbor_scan_min_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborLookupRssiThreshold, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX, + cb_notify_set_neighbor_lookup_rssi_threshold, 0), + + REG_VARIABLE(CFG_5G_RSSI_THRESHOLD_OFFSET_NAME, + WLAN_PARAM_SignedInteger, struct hdd_config, + rssi_thresh_offset_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_THRESHOLD_OFFSET_DEFAULT, + CFG_5G_RSSI_THRESHOLD_OFFSET_MIN, + CFG_5G_RSSI_THRESHOLD_OFFSET_MAX), + + REG_DYNAMIC_VARIABLE(CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nOpportunisticThresholdDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MIN, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MAX, + cb_notify_set_opportunistic_scan_threshold_diff, + 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_RESCAN_RSSI_DIFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamRescanRssiDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT, + CFG_ROAM_RESCAN_RSSI_DIFF_MIN, + CFG_ROAM_RESCAN_RSSI_DIFF_MAX, + cb_notify_set_roam_rescan_rssi_diff, 0), + + REG_VARIABLE_STRING(CFG_NEIGHBOR_SCAN_CHAN_LIST_NAME, WLAN_PARAM_String, + struct hdd_config, neighborScanChanList, + VAR_FLAGS_OPTIONAL, + (void *)CFG_NEIGHBOR_SCAN_CHAN_LIST_DEFAULT), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanMinChanTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX, + cb_notify_set_neighbor_scan_min_chan_time, 0), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanMaxChanTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX, + cb_notify_set_neighbor_scan_max_chan_time, 0), + + REG_VARIABLE(CFG_11R_NEIGHBOR_REQ_MAX_TRIES_NAME, WLAN_PARAM_Integer, + struct hdd_config, nMaxNeighborReqTries, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_DEFAULT, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MIN, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MAX), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborResultsRefreshPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX, + cb_notify_set_neighbor_results_refresh_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_EMPTY_SCAN_REFRESH_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nEmptyScanRefreshPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT, + CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN, + CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX, + cb_notify_set_empty_scan_refresh_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BMISS_FIRST_BCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamBmissFirstBcnt, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BMISS_FIRST_BCNT_DEFAULT, + CFG_ROAM_BMISS_FIRST_BCNT_MIN, + CFG_ROAM_BMISS_FIRST_BCNT_MAX, + cb_notify_set_roam_bmiss_first_bcnt, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BMISS_FINAL_BCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamBmissFinalBcnt, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BMISS_FINAL_BCNT_DEFAULT, + CFG_ROAM_BMISS_FINAL_BCNT_MIN, + CFG_ROAM_BMISS_FINAL_BCNT_MAX, + cb_notify_set_roam_bmiss_final_bcnt, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BEACON_RSSI_WEIGHT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nRoamBeaconRssiWeight, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BEACON_RSSI_WEIGHT_DEFAULT, + CFG_ROAM_BEACON_RSSI_WEIGHT_MIN, + CFG_ROAM_BEACON_RSSI_WEIGHT_MAX, + cb_notify_set_roam_beacon_rssi_weight, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAMING_DFS_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, allowDFSChannelRoam, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAMING_DFS_CHANNEL_DEFAULT, + CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX, + cb_notify_set_dfs_scan_mode, 0), + + REG_DYNAMIC_VARIABLE(CFG_DELAY_BEFORE_VDEV_STOP_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + delay_before_vdev_stop, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DELAY_BEFORE_VDEV_STOP_DEFAULT, + CFG_DELAY_BEFORE_VDEV_STOP_MIN, + CFG_DELAY_BEFORE_VDEV_STOP_MAX, + cb_notify_set_delay_before_vdev_stop, + 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_max_count, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MIN, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_MAXCOUNT_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_DELTA_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_rssi_delta, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELTA_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELTA_MIN, + CFG_ROAM_SCAN_HI_RSSI_DELTA_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_DELAY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_delay, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELAY_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELAY_MIN, + CFG_ROAM_SCAN_HI_RSSI_DELAY_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_DELAY_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_UB_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, + nhi_rssi_scan_rssi_ub, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_UB_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_UB_MIN, + CFG_ROAM_SCAN_HI_RSSI_UB_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_RSSI_UB_ID), + + REG_VARIABLE(CFG_QOS_WMM_BURST_SIZE_DEFN_NAME, WLAN_PARAM_Integer, + struct hdd_config, burstSizeDefinition, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_BURST_SIZE_DEFN_DEFAULT, + CFG_QOS_WMM_BURST_SIZE_DEFN_MIN, + CFG_QOS_WMM_BURST_SIZE_DEFN_MAX), + + REG_VARIABLE(CFG_ENABLE_HOST_ARPOFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, fhostArpOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_ARPOFFLOAD_DEFAULT, + CFG_ENABLE_HOST_ARPOFFLOAD_MIN, + CFG_ENABLE_HOST_ARPOFFLOAD_MAX), + + REG_VARIABLE(CFG_HW_FILTER_MODE_BITMAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, hw_filter_mode_bitmap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HW_FILTER_MODE_BITMAP_DEFAULT, + CFG_HW_FILTER_MODE_BITMAP_MIN, + CFG_HW_FILTER_MODE_BITMAP_MAX), + +#ifdef FEATURE_WLAN_RA_FILTERING + REG_VARIABLE(CFG_RA_FILTER_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IsRArateLimitEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RA_FILTER_ENABLE_DEFAULT, + CFG_RA_FILTER_ENABLE_MIN, + CFG_RA_FILTER_ENABLE_MAX), + + REG_VARIABLE(CFG_RA_RATE_LIMIT_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, RArateLimitInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RA_RATE_LIMIT_INTERVAL_DEFAULT, + CFG_RA_RATE_LIMIT_INTERVAL_MIN, + CFG_RA_RATE_LIMIT_INTERVAL_MAX), +#endif + + REG_VARIABLE(CFG_IGNORE_PEER_ERP_INFO_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignore_peer_erp_info, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_PEER_ERP_INFO_DEFAULT, + CFG_IGNORE_PEER_ERP_INFO_MIN, + CFG_IGNORE_PEER_ERP_INFO_MAX), + + REG_VARIABLE(CFG_ENABLE_HOST_SSDP_NAME, WLAN_PARAM_Integer, + struct hdd_config, ssdp, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_SSDP_DEFAULT, + CFG_ENABLE_HOST_SSDP_MIN, + CFG_ENABLE_HOST_SSDP_MAX), + +#ifdef FEATURE_RUNTIME_PM + REG_VARIABLE(CFG_ENABLE_RUNTIME_PM, WLAN_PARAM_Integer, + struct hdd_config, runtime_pm, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RUNTIME_PM_DEFAULT, + CFG_ENABLE_RUNTIME_PM_MIN, + CFG_ENABLE_RUNTIME_PM_MAX), + + REG_VARIABLE(CFG_RUNTIME_PM_DELAY_NAME, WLAN_PARAM_Integer, + struct hdd_config, runtime_pm_delay, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RUNTIME_PM_DELAY_DEFAULT, + CFG_RUNTIME_PM_DELAY_MIN, + CFG_RUNTIME_PM_DELAY_MAX), +#endif + + + REG_VARIABLE(CFG_ENABLE_HOST_NSOFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, fhostNSOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_NSOFFLOAD_DEFAULT, + CFG_ENABLE_HOST_NSOFFLOAD_MIN, + CFG_ENABLE_HOST_NSOFFLOAD_MAX), + + REG_VARIABLE(CFG_QOS_WMM_TS_INFO_ACK_POLICY_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, tsInfoAckPolicy, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_DEFAULT, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_MIN, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_MAX), + + REG_VARIABLE(CFG_SINGLE_TID_RC_NAME, WLAN_PARAM_Integer, + struct hdd_config, bSingleTidRc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SINGLE_TID_RC_DEFAULT, + CFG_SINGLE_TID_RC_MIN, + CFG_SINGLE_TID_RC_MAX), + + REG_VARIABLE(CFG_TELE_BCN_WAKEUP_EN_NAME, WLAN_PARAM_Integer, + struct hdd_config, teleBcnWakeupEn, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_WAKEUP_EN_DEFAULT, + CFG_TELE_BCN_WAKEUP_EN_MIN, + CFG_TELE_BCN_WAKEUP_EN_MAX), + + REG_VARIABLE(CFG_INFRA_STA_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, infraStaKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MIN, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_STA_KEEPALIVE_METHOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, sta_keepalive_method, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_KEEPALIVE_METHOD_DEFAULT, + CFG_STA_KEEPALIVE_METHOD_MIN, + CFG_STA_KEEPALIVE_METHOD_MAX), + + REG_VARIABLE(CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, AddTSWhenACMIsOff, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_DEFAULT, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MIN, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MAX), + + REG_VARIABLE(CFG_BAND_CAPABILITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBandCapability, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAND_CAPABILITY_DEFAULT, + CFG_BAND_CAPABILITY_MIN, + CFG_BAND_CAPABILITY_MAX), + +/* CFG_QDF_TRACE_ENABLE Parameters */ + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_WDI_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_wdi, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HDD_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_BMI_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_bmi, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_SME_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_sme, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_PE_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_pe, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_WMA_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_wma, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_SYS_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_sys, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_QDF_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_qdf, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_sap, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HDD_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd_sap, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_CFG_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_cfg, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_TXRX_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_txrx, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_DP_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_dp, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DP_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HTC_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_htc, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HIF_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hif, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDR_TRACE_ENABLE_HDD_SAP_DATA_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd_sap_data, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HDD_DATA_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd_data, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_EPPING, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_epping, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_QDF_DEVICES, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_qdf_devices, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_WIFI_POS, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_wifi_pos, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_NAN, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_nan, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_REGULATORY, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_regulatory, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_CP_STATS, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_cp_stats, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + +#ifdef ENABLE_MTRACE_LOG + REG_VARIABLE(CFG_ENABLE_MTRACE, WLAN_PARAM_Integer, + struct hdd_config, enable_mtrace, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_MTRACE_DEFAULT, + CFG_ENABLE_MTRACE_MIN, + CFG_ENABLE_MTRACE_MAX), +#endif + + REG_VARIABLE(CFG_TELE_BCN_MAX_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnMaxListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_MAX_LI_DEFAULT, + CFG_TELE_BCN_MAX_LI_MIN, + CFG_TELE_BCN_MAX_LI_MAX), + + REG_VARIABLE(CFG_ENABLE_BYPASS_11D_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableBypass11d, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BYPASS_11D_DEFAULT, + CFG_ENABLE_BYPASS_11D_MIN, + CFG_ENABLE_BYPASS_11D_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_CHNL_SCAN_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDFSChnlScan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_CHNL_SCAN_DEFAULT, + CFG_ENABLE_DFS_CHNL_SCAN_MIN, + CFG_ENABLE_DFS_CHNL_SCAN_MAX), + + REG_VARIABLE(CFG_HONOUR_NL_SCAN_POLICY_FLAGS, WLAN_PARAM_Integer, + struct hdd_config, honour_nl_scan_policy_flags, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HONOUR_NL_SCAN_POLICY_FLAGS_DEFAULT, + CFG_HONOUR_NL_SCAN_POLICY_FLAGS_MIN, + CFG_HONOUR_NL_SCAN_POLICY_FLAGS_MAX), + + REG_VARIABLE(CFG_ENABLE_WAKE_LOCK_IN_SCAN, WLAN_PARAM_Integer, + struct hdd_config, wake_lock_in_user_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_WAKE_LOCK_IN_SCAN_DEFAULT, + CFG_ENABLE_WAKE_LOCK_IN_SCAN_MIN, + CFG_ENABLE_WAKE_LOCK_IN_SCAN_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_PNO_CHNL_SCAN_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_dfs_pno_chnl_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_DEFAULT, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_MIN, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_MAX), + + REG_VARIABLE(CFG_ENABLE_DYNAMIC_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDynamicDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DYNAMIC_DTIM_DEFAULT, + CFG_ENABLE_DYNAMIC_DTIM_MIN, + CFG_ENABLE_DYNAMIC_DTIM_MAX), + + REG_VARIABLE(CFG_SHORT_GI_40MHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortGI40MhzEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_GI_40MHZ_DEFAULT, + CFG_SHORT_GI_40MHZ_MIN, + CFG_SHORT_GI_40MHZ_MAX), + + REG_DYNAMIC_VARIABLE(CFG_REPORT_MAX_LINK_SPEED, WLAN_PARAM_Integer, + struct hdd_config, reportMaxLinkSpeed, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REPORT_MAX_LINK_SPEED_DEFAULT, + CFG_REPORT_MAX_LINK_SPEED_MIN, + CFG_REPORT_MAX_LINK_SPEED_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_HIGH, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiHigh, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_HIGH_DEFAULT, + CFG_LINK_SPEED_RSSI_HIGH_MIN, + CFG_LINK_SPEED_RSSI_HIGH_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_MID, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiMid, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_MID_DEFAULT, + CFG_LINK_SPEED_RSSI_MID_MIN, + CFG_LINK_SPEED_RSSI_MID_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_LOW, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiLow, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_LOW_DEFAULT, + CFG_LINK_SPEED_RSSI_LOW_MIN, + CFG_LINK_SPEED_RSSI_LOW_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_PREFER_5GHZ, WLAN_PARAM_Integer, + struct hdd_config, nRoamPrefer5GHz, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_PREFER_5GHZ_DEFAULT, + CFG_ROAM_PREFER_5GHZ_MIN, + CFG_ROAM_PREFER_5GHZ_MAX, + cb_notify_set_roam_prefer5_g_hz, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_INTRA_BAND, WLAN_PARAM_Integer, + struct hdd_config, nRoamIntraBand, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_INTRA_BAND_DEFAULT, + CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX, + cb_notify_set_roam_intra_band, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_N_PROBES, WLAN_PARAM_Integer, + struct hdd_config, nProbes, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_N_PROBES_DEFAULT, + CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX, + cb_notify_set_roam_scan_n_probes, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HOME_AWAY_TIME, WLAN_PARAM_Integer, + struct hdd_config, nRoamScanHomeAwayTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX, + cb_notify_set_roam_scan_home_away_time, 0), + + REG_VARIABLE(CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isP2pDeviceAddrAdministrated, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_DEFAULT, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MIN, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MAX), + + REG_VARIABLE(CFG_ENABLE_MCC_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableMCC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MCC_ENABLED_DEFAULT, + CFG_ENABLE_MCC_ENABLED_MIN, + CFG_ENABLE_MCC_ENABLED_MAX), + + REG_VARIABLE(CFG_ALLOW_MCC_GO_DIFF_BI_NAME, WLAN_PARAM_Integer, + struct hdd_config, allowMCCGODiffBI, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ALLOW_MCC_GO_DIFF_BI_DEFAULT, + CFG_ALLOW_MCC_GO_DIFF_BI_MIN, + CFG_ALLOW_MCC_GO_DIFF_BI_MAX), + + REG_VARIABLE(CFG_THERMAL_MIGRATION_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalMitigationEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_MIGRATION_ENABLE_DEFAULT, + CFG_THERMAL_MIGRATION_ENABLE_MIN, + CFG_THERMAL_MIGRATION_ENABLE_MAX), + + REG_VARIABLE(CFG_THROTTLE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttlePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_PERIOD_DEFAULT, + CFG_THROTTLE_PERIOD_MIN, + CFG_THROTTLE_PERIOD_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL0_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL1_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL2_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL3_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MAX), + + REG_VARIABLE(CFG_ENABLE_MODULATED_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableModulatedDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MODULATED_DTIM_DEFAULT, + CFG_ENABLE_MODULATED_DTIM_MIN, + CFG_ENABLE_MODULATED_DTIM_MAX), + + REG_VARIABLE(CFG_MC_ADDR_LIST_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableMCAddrList, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MC_ADDR_LIST_ENABLE_DEFAULT, + CFG_MC_ADDR_LIST_ENABLE_MIN, + CFG_MC_ADDR_LIST_ENABLE_MAX), + + REG_VARIABLE(CFG_VHT_CHANNEL_WIDTH, WLAN_PARAM_Integer, + struct hdd_config, vhtChannelWidth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_CHANNEL_WIDTH_DEFAULT, + CFG_VHT_CHANNEL_WIDTH_MIN, + CFG_VHT_CHANNEL_WIDTH_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_RX_MCS_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtRxMCS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_RX_MCS_8_9_DEFAULT, + CFG_VHT_ENABLE_RX_MCS_8_9_MIN, + CFG_VHT_ENABLE_RX_MCS_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_MCS_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtTxMCS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_TX_MCS_8_9_DEFAULT, + CFG_VHT_ENABLE_TX_MCS_8_9_MIN, + CFG_VHT_ENABLE_TX_MCS_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_RX_MCS2x2_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtRxMCS2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_DEFAULT, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_MIN, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_MCS2x2_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtTxMCS2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_DEFAULT, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_MIN, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_MAX), + + REG_VARIABLE(CFG_ENABLE_VHT20_MCS9, WLAN_PARAM_Integer, + struct hdd_config, enable_vht20_mcs9, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_VHT20_MCS9_DEFAULT, + CFG_ENABLE_VHT20_MCS9_MIN, + CFG_ENABLE_VHT20_MCS9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_2x2_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enable2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_DEFAULT, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_MIN, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_DISABLE_HIGH_HT_RX_MCS_2x2, WLAN_PARAM_Integer, + struct hdd_config, disable_high_ht_mcs_2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_HIGH_HT_RX_MCS_2x2_DEFAULT, + CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MIN, + CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MAX), + + REG_VARIABLE(CFG_ENABLE_BT_CHAIN_SEPARATION, WLAN_PARAM_Integer, + struct hdd_config, enable_bt_chain_separation, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BT_CHAIN_SEPARATION_DEFAULT, + CFG_ENABLE_BT_CHAIN_SEPARATION_MIN, + CFG_ENABLE_BT_CHAIN_SEPARATION_MAX), + + REG_VARIABLE(CFG_STA_PREFER_80MHZ_OVER_160MHZ, WLAN_PARAM_Integer, + struct hdd_config, sta_prefer_80MHz_over_160MHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_PREFER_80MHZ_OVER_160MHZ_DEFAULT, + CFG_STA_PREFER_80MHZ_OVER_160MHZ_MIN, + CFG_STA_PREFER_80MHZ_OVER_160MHZ_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableMuBformee, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_DEFAULT, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MIN, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_PAID_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableVhtpAid, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_PAID_FEATURE_DEFAULT, + CFG_VHT_ENABLE_PAID_FEATURE_MIN, + CFG_VHT_ENABLE_PAID_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_GID_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableVhtGid, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_GID_FEATURE_DEFAULT, + CFG_VHT_ENABLE_GID_FEATURE_MIN, + CFG_VHT_ENABLE_GID_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_1x1_TX_CHAINMASK, WLAN_PARAM_Integer, + struct hdd_config, txchainmask1x1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_DEFAULT, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MIN, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_1x1_RX_CHAINMASK, WLAN_PARAM_Integer, + struct hdd_config, rxchainmask1x1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_DEFAULT, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MIN, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MAX), + + REG_VARIABLE(CFG_ENABLE_AMPDUPS_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableAmpduPs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_AMPDUPS_FEATURE_DEFAULT, + CFG_ENABLE_AMPDUPS_FEATURE_MIN, + CFG_ENABLE_AMPDUPS_FEATURE_MAX), + + REG_VARIABLE(CFG_HT_ENABLE_SMPS_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableHtSmps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_DEFAULT, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_MIN, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_HT_SMPS_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, htSmps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HT_SMPS_CAP_FEATURE_DEFAULT, + CFG_HT_SMPS_CAP_FEATURE_MIN, + CFG_HT_SMPS_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_DISABLE_DFS_CH_SWITCH, WLAN_PARAM_Integer, + struct hdd_config, disableDFSChSwitch, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_DFS_CH_SWITCH_DEFAULT, + CFG_DISABLE_DFS_CH_SWITCH_MIN, + CFG_DISABLE_DFS_CH_SWITCH_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_MASTER_CAPABILITY, WLAN_PARAM_Integer, + struct hdd_config, enableDFSMasterCap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_MASTER_CAPABILITY_DEFAULT, + CFG_ENABLE_DFS_MASTER_CAPABILITY_MIN, + CFG_ENABLE_DFS_MASTER_CAPABILITY_MAX), + + REG_DYNAMIC_VARIABLE(CFG_SAP_PREFERRED_CHANNEL_LOCATION, + WLAN_PARAM_Integer, + struct hdd_config, gSapPreferredChanLocation, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_DEFAULT, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_MIN, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_MAX, + cb_notify_set_g_sap_preferred_chan_location, 0), + REG_DYNAMIC_VARIABLE(CFG_DISABLE_DFS_JAPAN_W53, WLAN_PARAM_Integer, + struct hdd_config, gDisableDfsJapanW53, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_DFS_JAPAN_W53_DEFAULT, + CFG_DISABLE_DFS_JAPAN_W53_MIN, + CFG_DISABLE_DFS_JAPAN_W53_MAX, + ch_notify_set_g_disable_dfs_japan_w53, 0), + + REG_VARIABLE(CFG_MAX_HT_MCS_FOR_TX_DATA, WLAN_PARAM_HexInteger, + struct hdd_config, max_ht_mcs_txdata, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_HT_MCS_FOR_TX_DATA_DEFAULT, + CFG_MAX_HT_MCS_FOR_TX_DATA_MIN, + CFG_MAX_HT_MCS_FOR_TX_DATA_MAX), + + REG_VARIABLE(CFG_SAP_GET_PEER_INFO, WLAN_PARAM_Integer, + struct hdd_config, sap_get_peer_info, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_GET_PEER_INFO_DEFAULT, + CFG_SAP_GET_PEER_INFO_MIN, + CFG_SAP_GET_PEER_INFO_MAX), + + REG_VARIABLE(CFG_DISABLE_ABG_RATE_FOR_TX_DATA, WLAN_PARAM_Integer, + struct hdd_config, disable_abg_rate_txdata, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_ABG_RATE_FOR_TX_DATA_DEFAULT, + CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MIN, + CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MAX), + + REG_VARIABLE(CFG_RATE_FOR_TX_MGMT, WLAN_PARAM_HexInteger, + struct hdd_config, rate_for_tx_mgmt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RATE_FOR_TX_MGMT_DEFAULT, + CFG_RATE_FOR_TX_MGMT_MIN, + CFG_RATE_FOR_TX_MGMT_MAX), + + REG_VARIABLE(CFG_RATE_FOR_TX_MGMT_2G, WLAN_PARAM_HexInteger, + struct hdd_config, rate_for_tx_mgmt_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RATE_FOR_TX_MGMT_2G_DEFAULT, + CFG_RATE_FOR_TX_MGMT_2G_MIN, + CFG_RATE_FOR_TX_MGMT_2G_MAX), + + REG_VARIABLE(CFG_RATE_FOR_TX_MGMT_5G, WLAN_PARAM_HexInteger, + struct hdd_config, rate_for_tx_mgmt_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RATE_FOR_TX_MGMT_5G_DEFAULT, + CFG_RATE_FOR_TX_MGMT_5G_MIN, + CFG_RATE_FOR_TX_MGMT_5G_MAX), + + REG_VARIABLE(CFG_ENABLE_FIRST_SCAN_2G_ONLY_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableFirstScan2GOnly, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_DEFAULT, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_MIN, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_MAX), + + REG_VARIABLE(CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_NAME, WLAN_PARAM_Integer, + struct hdd_config, skipDfsChnlInP2pSearch, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_DEFAULT, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MIN, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MAX), + + REG_VARIABLE(CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, ignoreDynamicDtimInP2pMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_DEFAULT, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MIN, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MAX), + + REG_VARIABLE(CFG_ENABLE_RX_STBC, WLAN_PARAM_Integer, + struct hdd_config, enableRxSTBC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RX_STBC_DEFAULT, + CFG_ENABLE_RX_STBC_MIN, + CFG_ENABLE_RX_STBC_MAX), + + REG_VARIABLE(CFG_ENABLE_TX_STBC, WLAN_PARAM_Integer, + struct hdd_config, enableTxSTBC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TX_STBC_DEFAULT, + CFG_ENABLE_TX_STBC_MIN, + CFG_ENABLE_TX_STBC_MAX), + + REG_VARIABLE(CFG_PPS_ENABLE_5G_EBT, WLAN_PARAM_Integer, + struct hdd_config, enable5gEBT, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PPS_ENABLE_5G_EBT_FEATURE_DEFAULT, + CFG_PPS_ENABLE_5G_EBT_FEATURE_MIN, + CFG_PPS_ENABLE_5G_EBT_FEATURE_MAX), + + REG_VARIABLE(CFG_PREVENT_LINK_DOWN_NAME, WLAN_PARAM_Integer, + struct hdd_config, prevent_link_down, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PREVENT_LINK_DOWN_DEFAULT, + CFG_PREVENT_LINK_DOWN_MIN, + CFG_PREVENT_LINK_DOWN_MAX), + +#ifdef FEATURE_WLAN_TDLS + REG_VARIABLE(CFG_TDLS_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_SUPPORT_ENABLE_MIN, + CFG_TDLS_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_IMPLICIT_TRIGGER, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSImplicitTrigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IMPLICIT_TRIGGER_DEFAULT, + CFG_TDLS_IMPLICIT_TRIGGER_MIN, + CFG_TDLS_IMPLICIT_TRIGGER_MAX), + + REG_VARIABLE(CFG_TDLS_TX_STATS_PERIOD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSTxStatsPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_TX_STATS_PERIOD_DEFAULT, + CFG_TDLS_TX_STATS_PERIOD_MIN, + CFG_TDLS_TX_STATS_PERIOD_MAX), + + REG_VARIABLE(CFG_TDLS_TX_PACKET_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSTxPacketThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_TX_PACKET_THRESHOLD_DEFAULT, + CFG_TDLS_TX_PACKET_THRESHOLD_MIN, + CFG_TDLS_TX_PACKET_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_MAX_DISCOVERY_ATTEMPT, WLAN_PARAM_Integer, + struct hdd_config, fTDLSMaxDiscoveryAttempt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_DEFAULT, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX), + + REG_VARIABLE(CFG_TDLS_IDLE_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, tdls_idle_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IDLE_TIMEOUT_DEFAULT, + CFG_TDLS_IDLE_TIMEOUT_MIN, + CFG_TDLS_IDLE_TIMEOUT_MAX), + + REG_VARIABLE(CFG_TDLS_IDLE_PACKET_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSIdlePacketThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IDLE_PACKET_THRESHOLD_DEFAULT, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_TRIGGER_THRESHOLD, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSITriggerThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_DEFAULT, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_TEARDOWN_THRESHOLD, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSITeardownThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_DEFAULT, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_DELTA, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSIDelta, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_DELTA_DEFAULT, + CFG_TDLS_RSSI_DELTA_MIN, + CFG_TDLS_RSSI_DELTA_MAX), + + REG_VARIABLE(CFG_TDLS_QOS_WMM_UAPSD_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, fTDLSUapsdMask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_QOS_WMM_UAPSD_MASK_DEFAULT, + CFG_TDLS_QOS_WMM_UAPSD_MASK_MIN, + CFG_TDLS_QOS_WMM_UAPSD_MASK_MAX), + + REG_VARIABLE(CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSBufferSta, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MIN, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSOffChannel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MIN, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPrefOffChanNum, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX), + + REG_VARIABLE(CFG_TDLS_PREFERRED_OFF_CHANNEL_BW, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPrefOffChanBandwidth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MIN, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_INACTIVITY_TIME, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdInactivityTimer, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_DEFAULT, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_MIN, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSRxFrameThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_DEFAULT, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MIN, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW, + WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdPTIWindow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MIN, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT, + WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdPTRTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MIN, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MAX), + + REG_VARIABLE(CFG_TDLS_EXTERNAL_CONTROL, WLAN_PARAM_Integer, + struct hdd_config, fTDLSExternalControl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_EXTERNAL_CONTROL_DEFAULT, + CFG_TDLS_EXTERNAL_CONTROL_MIN, + CFG_TDLS_EXTERNAL_CONTROL_MAX), + REG_VARIABLE(CFG_TDLS_WMM_MODE_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSWmmMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_WMM_MODE_ENABLE_DEFAULT, + CFG_TDLS_WMM_MODE_ENABLE_MIN, + CFG_TDLS_WMM_MODE_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_SCAN_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, enable_tdls_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_SCAN_ENABLE_DEFAULT, + CFG_TDLS_SCAN_ENABLE_MIN, + CFG_TDLS_SCAN_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_PEER_KICKOUT_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, tdls_peer_kickout_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PEER_KICKOUT_THRESHOLD_DEFAULT, + CFG_TDLS_PEER_KICKOUT_THRESHOLD_MIN, + CFG_TDLS_PEER_KICKOUT_THRESHOLD_MAX), + +#endif + + REG_VARIABLE(CFG_SCAN_AGING_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, scanAgingTimeout, + VAR_FLAGS_OPTIONAL, + CFG_SCAN_AGING_PARAM_DEFAULT, + CFG_SCAN_AGING_PARAM_MIN, + CFG_SCAN_AGING_PARAM_MAX), + + REG_VARIABLE(CFG_TX_LDPC_ENABLE_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enable_tx_ldpc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_LDPC_ENABLE_FEATURE_DEFAULT, + CFG_TX_LDPC_ENABLE_FEATURE_MIN, + CFG_TX_LDPC_ENABLE_FEATURE_MAX), + + REG_VARIABLE(CFG_ENABLE_RX_LDPC, WLAN_PARAM_Integer, + struct hdd_config, enable_rx_ldpc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RX_LDPC_DEFAULT, + CFG_ENABLE_RX_LDPC_MIN, + CFG_ENABLE_RX_LDPC_MAX), + + REG_VARIABLE(CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enableMCCAdaptiveScheduler, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_DEFAULT, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MIN, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MAX), + + REG_VARIABLE(CFG_IBSS_ADHOC_CHANNEL_5GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, AdHocChannel5G, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_MIN, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_MAX), + + REG_VARIABLE(CFG_IBSS_ADHOC_CHANNEL_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, AdHocChannel24G, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_MIN, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_MAX), + + REG_VARIABLE(CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableTxBF, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_DEFAULT, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MIN, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_subfee_vendor_vhtie, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE_DEFAULT, + CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE_MIN, + CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TXBF_SAP_MODE, WLAN_PARAM_Integer, + struct hdd_config, enable_txbf_sap_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TXBF_SAP_MODE_DEFAULT, + CFG_VHT_ENABLE_TXBF_SAP_MODE_MIN, + CFG_VHT_ENABLE_TXBF_SAP_MODE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TXBF_IN_20MHZ, WLAN_PARAM_Integer, + struct hdd_config, enableTxBFin20MHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_DEFAULT, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_MIN, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_MAX), + + REG_VARIABLE(CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, WLAN_PARAM_Integer, + struct hdd_config, txBFCsnValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_DEFAULT, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MIN, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_SU_BEAM_FORMER, WLAN_PARAM_Integer, + struct hdd_config, enable_su_tx_bformer, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_DEFAULT, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MIN, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MAX), + + REG_VARIABLE(CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, sapAllowAllChannel, + VAR_FLAGS_OPTIONAL, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_DEFAULT, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MIN, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MAX), + + REG_VARIABLE(CFG_DISABLE_LDPC_WITH_TXBF_AP, WLAN_PARAM_Integer, + struct hdd_config, disableLDPCWithTxbfAP, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_LDPC_WITH_TXBF_AP_DEFAULT, + CFG_DISABLE_LDPC_WITH_TXBF_AP_MIN, + CFG_DISABLE_LDPC_WITH_TXBF_AP_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_SSR, WLAN_PARAM_Integer, + struct hdd_config, enableSSR, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SSR_DEFAULT, + CFG_ENABLE_SSR_MIN, + CFG_ENABLE_SSR_MAX, + cb_notify_set_enable_ssr, 0), + + REG_VARIABLE(CFG_ENABLE_DATA_STALL_DETECTION, WLAN_PARAM_Integer, + struct hdd_config, enable_data_stall_det, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DATA_STALL_DETECTION_DEFAULT, + CFG_ENABLE_DATA_STALL_DETECTION_MIN, + CFG_ENABLE_DATA_STALL_DETECTION_MAX), + + REG_VARIABLE(CFG_ENABLE_VHT_FOR_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableVhtFor24GHzBand, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_VHT_FOR_24GHZ_DEFAULT, + CFG_ENABLE_VHT_FOR_24GHZ_MIN, + CFG_ENABLE_VHT_FOR_24GHZ_MAX), + + + REG_VARIABLE(CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_sap_vendor_vht, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_DEFAULT, + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MIN, + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY, + WLAN_PARAM_Integer, + struct hdd_config, bFastRoamInConIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_DEFAULT, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MIN, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MAX, + cb_notify_set_enable_fast_roam_in_concurrency, 0), + + REG_VARIABLE(CFG_ENABLE_SNR_MONITORING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableSNRMonitoring, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_SNR_MONITORING_DEFAULT, + CFG_ENABLE_SNR_MONITORING_MIN, + CFG_ENABLE_SNR_MONITORING_MAX), + +#ifdef FEATURE_WLAN_SCAN_PNO + REG_VARIABLE(CFG_PNO_SCAN_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, configPNOScanSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SCAN_SUPPORT_DEFAULT, + CFG_PNO_SCAN_SUPPORT_DISABLE, + CFG_PNO_SCAN_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_PNO_SCAN_TIMER_REPEAT_VALUE, WLAN_PARAM_Integer, + struct hdd_config, configPNOScanTimerRepeatValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_DEFAULT, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MIN, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MAX), + + REG_VARIABLE(CFG_PNO_SLOW_SCAN_MULTIPLIER, WLAN_PARAM_Integer, + struct hdd_config, pno_slow_scan_multiplier, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SLOW_SCAN_MULTIPLIER_DEFAULT, + CFG_PNO_SLOW_SCAN_MULTIPLIER_MIN, + CFG_PNO_SLOW_SCAN_MULTIPLIER_MAX), +#endif + REG_VARIABLE(CFG_MAX_AMSDU_NUM_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_amsdu_num, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_AMSDU_NUM_DEFAULT, + CFG_MAX_AMSDU_NUM_MIN, + CFG_MAX_AMSDU_NUM_MAX), + + REG_VARIABLE(CFG_STRICT_5GHZ_PREF_BY_MARGIN, WLAN_PARAM_Integer, + struct hdd_config, nSelect5GHzMargin, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_DEFAULT, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_MIN, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_MAX), + + REG_VARIABLE(CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, enable_ip_tcp_udp_checksum_offload, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DEFAULT, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DISABLE, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE), + + REG_VARIABLE(CFG_POWERSAVE_OFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, enablePowersaveOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_POWERSAVE_OFFLOAD_DEFAULT, + CFG_POWERSAVE_OFFLOAD_MIN, + CFG_POWERSAVE_OFFLOAD_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_UART_PRINT_NAME, WLAN_PARAM_Integer, + struct hdd_config, enablefwprint, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_UART_PRINT_DEFAULT, + CFG_ENABLE_FW_UART_PRINT_DISABLE, + CFG_ENABLE_FW_UART_PRINT_ENABLE), + + REG_VARIABLE(CFG_ENABLE_FW_LOG_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_fw_log, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_LOG_DEFAULT, + CFG_ENABLE_FW_LOG_DISABLE, + CFG_ENABLE_FW_LOG_MAX), + +#ifdef IPA_OFFLOAD + REG_VARIABLE(CFG_IPA_OFFLOAD_CONFIG_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, IpaConfig, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_OFFLOAD_CONFIG_DEFAULT, + CFG_IPA_OFFLOAD_CONFIG_MIN, + CFG_IPA_OFFLOAD_CONFIG_MAX), + + REG_VARIABLE(CFG_IPA_DESC_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaDescSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_DESC_SIZE_DEFAULT, + CFG_IPA_DESC_SIZE_MIN, + CFG_IPA_DESC_SIZE_MAX), + + REG_VARIABLE(CFG_IPA_HIGH_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaHighBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_HIGH_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_HIGH_BANDWIDTH_MBPS_MIN, + CFG_IPA_HIGH_BANDWIDTH_MBPS_MAX), + + REG_VARIABLE(CFG_IPA_MEDIUM_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaMediumBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MIN, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MAX), + + REG_VARIABLE(CFG_IPA_LOW_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaLowBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_LOW_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_LOW_BANDWIDTH_MBPS_MIN, + CFG_IPA_LOW_BANDWIDTH_MBPS_MAX), +#endif + + REG_VARIABLE(CFG_VHT_AMPDU_LEN_EXPONENT_NAME, WLAN_PARAM_Integer, + struct hdd_config, fVhtAmpduLenExponent, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_AMPDU_LEN_EXPONENT_DEFAULT, + CFG_VHT_AMPDU_LEN_EXPONENT_MIN, + CFG_VHT_AMPDU_LEN_EXPONENT_MAX), + + REG_VARIABLE(CFG_VHT_MPDU_LEN_NAME, WLAN_PARAM_Integer, + struct hdd_config, vhtMpduLen, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_MPDU_LEN_DEFAULT, + CFG_VHT_MPDU_LEN_MIN, + CFG_VHT_MPDU_LEN_MAX), + + REG_VARIABLE(CFG_WOW_STATUS_NAME, WLAN_PARAM_Integer, + struct hdd_config, wowEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_STATUS_DEFAULT, + CFG_WOW_ENABLE_MIN, + CFG_WOW_ENABLE_MAX), + + REG_VARIABLE(CFG_COALESING_IN_IBSS_NAME, WLAN_PARAM_Integer, + struct hdd_config, isCoalesingInIBSSAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_COALESING_IN_IBSS_DEFAULT, + CFG_COALESING_IN_IBSS_MIN, + CFG_COALESING_IN_IBSS_MAX), + + REG_VARIABLE(CFG_IBSS_ATIM_WIN_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssATIMWinSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ATIM_WIN_SIZE_DEFAULT, + CFG_IBSS_ATIM_WIN_SIZE_MIN, + CFG_IBSS_ATIM_WIN_SIZE_MAX), + + REG_VARIABLE(CFG_SAP_MAX_NO_PEERS, WLAN_PARAM_Integer, + struct hdd_config, maxNumberOfPeers, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_MAX_NO_PEERS_DEFAULT, + CFG_SAP_MAX_NO_PEERS_MIN, + CFG_SAP_MAX_NO_PEERS_MAX), + + REG_VARIABLE(CFG_IBSS_IS_POWER_SAVE_ALLOWED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isIbssPowerSaveAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_DEFAULT, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_MIN, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_MAX), + + REG_VARIABLE(CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isIbssPowerCollapseAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_DEFAULT, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MIN, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MAX), + + REG_VARIABLE(CFG_IBSS_AWAKE_ON_TX_RX_NAME, WLAN_PARAM_Integer, + struct hdd_config, isIbssAwakeOnTxRx, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_AWAKE_ON_TX_RX_DEFAULT, + CFG_IBSS_AWAKE_ON_TX_RX_MIN, + CFG_IBSS_AWAKE_ON_TX_RX_MAX), + + REG_VARIABLE(CFG_IBSS_INACTIVITY_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssInactivityCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_INACTIVITY_TIME_DEFAULT, + CFG_IBSS_INACTIVITY_TIME_MIN, + CFG_IBSS_INACTIVITY_TIME_MAX), + + REG_VARIABLE(CFG_IBSS_TXSP_END_INACTIVITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssTxSpEndInactivityTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_TXSP_END_INACTIVITY_DEFAULT, + CFG_IBSS_TXSP_END_INACTIVITY_MIN, + CFG_IBSS_TXSP_END_INACTIVITY_MAX), + + REG_VARIABLE(CFG_IBSS_PS_WARMUP_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssPsWarmupTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_PS_WARMUP_TIME_DEFAULT, + CFG_IBSS_PS_WARMUP_TIME_MIN, + CFG_IBSS_PS_WARMUP_TIME_MAX), + + REG_VARIABLE(CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_NAME, + WLAN_PARAM_Integer, + struct hdd_config, ibssPs1RxChainInAtimEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_DEFAULT, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MIN, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL0_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL0_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL0_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL0_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL0_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL0_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL1_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL1_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL1_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL1_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL1_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL1_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL2_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL2_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL2_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL2_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL2_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL2_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL3_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL3_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL3_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL3_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL3_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL3_MAX), + + REG_VARIABLE(CFG_SET_TXPOWER_LIMIT2G_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxPower2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TXPOWER_LIMIT2G_DEFAULT, + CFG_SET_TXPOWER_LIMIT2G_MIN, + CFG_SET_TXPOWER_LIMIT2G_MAX), + + REG_VARIABLE(CFG_SET_TXPOWER_LIMIT5G_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxPower5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TXPOWER_LIMIT5G_DEFAULT, + CFG_SET_TXPOWER_LIMIT5G_MIN, + CFG_SET_TXPOWER_LIMIT5G_MAX), + + REG_VARIABLE(CFG_ENABLE_DEBUG_CONNECT_ISSUE, WLAN_PARAM_Integer, + struct hdd_config, gEnableDebugLog, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_MIN, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, fDfsPhyerrFilterOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX), + + REG_VARIABLE(CFG_ENABLE_OVERLAP_CH, WLAN_PARAM_Integer, + struct hdd_config, gEnableOverLapCh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_OVERLAP_CH_DEFAULT, + CFG_ENABLE_OVERLAP_CH_MIN, + CFG_ENABLE_OVERLAP_CH_MAX), + + REG_VARIABLE(CFG_REG_CHANGE_DEF_COUNTRY_NAME, WLAN_PARAM_Integer, + struct hdd_config, fRegChangeDefCountry, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REG_CHANGE_DEF_COUNTRY_DEFAULT, + CFG_REG_CHANGE_DEF_COUNTRY_MIN, + CFG_REG_CHANGE_DEF_COUNTRY_MAX), + + REG_VARIABLE(CFG_ACS_WITH_MORE_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, acs_with_more_param, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACS_WITH_MORE_PARAM_DEFAULT, + CFG_ACS_WITH_MORE_PARAM_MIN, + CFG_ACS_WITH_MORE_PARAM_MAX), + + REG_VARIABLE(CFG_AUTO_CHANNEL_SELECT_WEIGHT, WLAN_PARAM_HexInteger, + struct hdd_config, auto_channel_select_weight, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AUTO_CHANNEL_SELECT_WEIGHT_DEFAULT, + CFG_AUTO_CHANNEL_SELECT_WEIGHT_MIN, + CFG_AUTO_CHANNEL_SELECT_WEIGHT_MAX), + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + REG_VARIABLE(CFG_LL_TX_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_LWM_DEFAULT, + CFG_LL_TX_FLOW_LWM_MIN, + CFG_LL_TX_FLOW_LWM_MAX), + REG_VARIABLE(CFG_LL_TX_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_FLOW_HWM_OFFSET_MAX), + REG_VARIABLE(CFG_LL_TX_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_MAX), + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_LWM_DEFAULT, + CFG_LL_TX_LBW_FLOW_LWM_MIN, + CFG_LL_TX_LBW_FLOW_LWM_MAX), + + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MAX), + + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_LWM_DEFAULT, + CFG_LL_TX_HBW_FLOW_LWM_MIN, + CFG_LL_TX_HBW_FLOW_LWM_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MAX), +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + REG_VARIABLE(CFG_LL_TX_FLOW_STOP_QUEUE_TH, WLAN_PARAM_Integer, + struct hdd_config, TxFlowStopQueueThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_DEFAULT, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_MIN, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_MAX), + + REG_VARIABLE(CFG_LL_TX_FLOW_START_QUEUE_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxFlowStartQueueOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_DEFAULT, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MIN, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MAX), + + REG_VARIABLE(CFG_INITIAL_DWELL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nInitialDwellTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INITIAL_DWELL_TIME_DEFAULT, + CFG_INITIAL_DWELL_TIME_MIN, + CFG_INITIAL_DWELL_TIME_MAX), + + REG_VARIABLE(CFG_INITIAL_SCAN_NO_DFS_CHNL_NAME, WLAN_PARAM_Integer, + struct hdd_config, initial_scan_no_dfs_chnl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INITIAL_SCAN_NO_DFS_CHNL_DEFAULT, + CFG_INITIAL_SCAN_NO_DFS_CHNL_MIN, + CFG_INITIAL_SCAN_NO_DFS_CHNL_MAX), + + REG_VARIABLE(CFG_SAP_MAX_OFFLOAD_PEERS, WLAN_PARAM_Integer, + struct hdd_config, apMaxOffloadPeers, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MAX_OFFLOAD_PEERS_DEFAULT, + CFG_SAP_MAX_OFFLOAD_PEERS_MIN, + CFG_SAP_MAX_OFFLOAD_PEERS_MAX), + + REG_VARIABLE(CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS, WLAN_PARAM_Integer, + struct hdd_config, apMaxOffloadReorderBuffs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_DEFAULT, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MIN, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MAX), + + REG_VARIABLE(CFG_ADVERTISE_CONCURRENT_OPERATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, advertiseConcurrentOperation, + VAR_FLAGS_OPTIONAL, + CFG_ADVERTISE_CONCURRENT_OPERATION_DEFAULT, + CFG_ADVERTISE_CONCURRENT_OPERATION_MIN, + CFG_ADVERTISE_CONCURRENT_OPERATION_MAX), + + REG_VARIABLE(CFG_ENABLE_MEMORY_DEEP_SLEEP, WLAN_PARAM_Integer, + struct hdd_config, enableMemDeepSleep, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MEMORY_DEEP_SLEEP_DEFAULT, + CFG_ENABLE_MEMORY_DEEP_SLEEP_MIN, + CFG_ENABLE_MEMORY_DEEP_SLEEP_MAX), + + REG_VARIABLE(CFG_ENABLE_CCK_TX_FIR_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_cck_tx_fir_override, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CCK_TX_FIR_OVERRIDE_DEFAULT, + CFG_ENABLE_CCK_TX_FIR_OVERRIDE_MIN, + CFG_ENABLE_CCK_TX_FIR_OVERRIDE_MAX), + + REG_VARIABLE(CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, debugP2pRemainOnChannel, + VAR_FLAGS_OPTIONAL, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_DEFAULT, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MIN, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MAX), + +#ifndef REMOVE_PKT_LOG + REG_VARIABLE(CFG_ENABLE_PACKET_LOG, WLAN_PARAM_Integer, + struct hdd_config, enablePacketLog, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PACKET_LOG_DEFAULT, + CFG_ENABLE_PACKET_LOG_MIN, + CFG_ENABLE_PACKET_LOG_MAX), +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + REG_VARIABLE(CFG_ROAMING_OFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, isRoamOffloadEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ROAMING_OFFLOAD_DEFAULT, + CFG_ROAMING_OFFLOAD_MIN, + CFG_ROAMING_OFFLOAD_MAX), +#endif +#ifdef MSM_PLATFORM + REG_VARIABLE(CFG_BUS_BANDWIDTH_HIGH_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthHighThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthMediumThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_LOW_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthLowThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthComputeInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_DEFAULT, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MIN, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MAX), + + REG_VARIABLE(CFG_ENABLE_TCP_LIMIT_OUTPUT, WLAN_PARAM_Integer, + struct hdd_config, enable_tcp_limit_output, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TCP_LIMIT_OUTPUT_DEFAULT, + CFG_ENABLE_TCP_LIMIT_OUTPUT_MIN, + CFG_ENABLE_TCP_LIMIT_OUTPUT_MAX), + + REG_VARIABLE(CFG_ENABLE_TCP_ADV_WIN_SCALE, WLAN_PARAM_Integer, + struct hdd_config, enable_tcp_adv_win_scale, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TCP_ADV_WIN_SCALE_DEFAULT, + CFG_ENABLE_TCP_ADV_WIN_SCALE_MIN, + CFG_ENABLE_TCP_ADV_WIN_SCALE_MAX), + + REG_VARIABLE(CFG_ENABLE_TCP_DELACK, WLAN_PARAM_Integer, + struct hdd_config, enable_tcp_delack, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TCP_DELACK_DEFAULT, + CFG_ENABLE_TCP_DELACK_MIN, + CFG_ENABLE_TCP_DELACK_MAX), + + REG_VARIABLE(CFG_TCP_DELACK_THRESHOLD_HIGH, WLAN_PARAM_Integer, + struct hdd_config, tcpDelackThresholdHigh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_MIN, + CFG_TCP_DELACK_THRESHOLD_HIGH_MAX), + + REG_VARIABLE(CFG_TCP_DELACK_THRESHOLD_LOW, WLAN_PARAM_Integer, + struct hdd_config, tcpDelackThresholdLow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_MIN, + CFG_TCP_DELACK_THRESHOLD_LOW_MAX), + + REG_VARIABLE(CFG_TCP_DELACK_TIMER_COUNT, WLAN_PARAM_Integer, + struct hdd_config, tcp_delack_timer_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_TIMER_COUNT_DEFAULT, + CFG_TCP_DELACK_TIMER_COUNT_MIN, + CFG_TCP_DELACK_TIMER_COUNT_MAX), + + REG_VARIABLE(CFG_TCP_TX_HIGH_TPUT_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, tcp_tx_high_tput_thres, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_DEFAULT, + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MIN, + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MAX), + REG_VARIABLE(CFG_PERIODIC_STATS_DISPLAY_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, periodic_stats_disp_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PERIODIC_STATS_DISPLAY_TIME_DEFAULT, + CFG_PERIODIC_STATS_DISPLAY_TIME_MIN, + CFG_PERIODIC_STATS_DISPLAY_TIME_MAX), + REG_VARIABLE(CFG_ENABLE_TCP_PARAM_UPDATE, WLAN_PARAM_Integer, + struct hdd_config, enable_tcp_param_update, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TCP_PARAM_UPDATE_DEFAULT, + CFG_ENABLE_TCP_PARAM_UPDATE_MIN, + CFG_ENABLE_TCP_PARAM_UPDATE_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_FW_LOG_TYPE, WLAN_PARAM_Integer, + struct hdd_config, enableFwLogType, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_LOG_TYPE_DEFAULT, + CFG_ENABLE_FW_LOG_TYPE_MIN, + CFG_ENABLE_FW_LOG_TYPE_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_DEBUG_LOG_LEVEL, WLAN_PARAM_Integer, + struct hdd_config, enableFwLogLevel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_DEFAULT, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MIN, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_RTS_PROFILE, WLAN_PARAM_Integer, + struct hdd_config, rts_profile, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_RTS_PROFILE_DEFAULT, + CFG_ENABLE_FW_RTS_PROFILE_MIN, + CFG_ENABLE_FW_RTS_PROFILE_MAX), + + REG_VARIABLE_STRING(CFG_ENABLE_FW_MODULE_LOG_LEVEL, WLAN_PARAM_String, + struct hdd_config, enableFwModuleLogLevel, + VAR_FLAGS_OPTIONAL, + (void *)CFG_ENABLE_FW_MODULE_LOG_DEFAULT), + + REG_VARIABLE_STRING(CFG_ENABLE_CONCURRENT_STA, WLAN_PARAM_String, + struct hdd_config, enableConcurrentSTA, + VAR_FLAGS_NONE, + (void *)CFG_ENABLE_CONCURRENT_STA_DEFAULT), + +#ifdef WLAN_FEATURE_11W + REG_VARIABLE(CFG_PMF_SA_QUERY_MAX_RETRIES_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmfSaQueryMaxRetries, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMF_SA_QUERY_MAX_RETRIES_DEFAULT, + CFG_PMF_SA_QUERY_MAX_RETRIES_MIN, + CFG_PMF_SA_QUERY_MAX_RETRIES_MAX), + + REG_VARIABLE(CFG_PMF_SA_QUERY_RETRY_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmfSaQueryRetryInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_DEFAULT, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_MIN, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_MAX), +#endif + REG_VARIABLE(CFG_MAX_CONCURRENT_CONNECTIONS_NAME, WLAN_PARAM_Integer, + struct hdd_config, gMaxConcurrentActiveSessions, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_CONCURRENT_CONNECTIONS_DEFAULT, + CFG_MAX_CONCURRENT_CONNECTIONS_MIN, + CFG_MAX_CONCURRENT_CONNECTIONS_MAX), + + REG_VARIABLE(CFG_ENABLE_CRASH_INJECT, WLAN_PARAM_Integer, + struct hdd_config, crash_inject_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CRASH_INJECT_DEFAULT, + CFG_ENABLE_CRASH_INJECT_MIN, + CFG_ENABLE_CRASH_INJECT_MAX), + + REG_VARIABLE(CFG_IGNORE_CAC_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignoreCAC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_CAC_DEFAULT, + CFG_IGNORE_CAC_MIN, + CFG_IGNORE_CAC_MAX), + + REG_VARIABLE(CFG_DFS_RADAR_PRI_MULTIPLIER_NAME, WLAN_PARAM_Integer, + struct hdd_config, dfsRadarPriMultiplier, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT, + CFG_DFS_RADAR_PRI_MULTIPLIER_MIN, + CFG_DFS_RADAR_PRI_MULTIPLIER_MAX), + + REG_VARIABLE(CFG_REORDER_OFFLOAD_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, reorderOffloadSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REORDER_OFFLOAD_SUPPORT_DEFAULT, + CFG_REORDER_OFFLOAD_SUPPORT_MIN, + CFG_REORDER_OFFLOAD_SUPPORT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_BUF_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxBufCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_BUF_COUNT_DEFAULT, + CFG_IPA_UC_TX_BUF_COUNT_MIN, + CFG_IPA_UC_TX_BUF_COUNT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_BUF_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxBufSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_BUF_SIZE_DEFAULT, + CFG_IPA_UC_TX_BUF_SIZE_MIN, + CFG_IPA_UC_TX_BUF_SIZE_MAX), + + REG_VARIABLE(CFG_IPA_UC_RX_IND_RING_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcRxIndRingCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_RX_IND_RING_COUNT_DEFAULT, + CFG_IPA_UC_RX_IND_RING_COUNT_MIN, + CFG_IPA_UC_RX_IND_RING_COUNT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_PARTITION_BASE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxPartitionBase, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_PARTITION_BASE_DEFAULT, + CFG_IPA_UC_TX_PARTITION_BASE_MIN, + CFG_IPA_UC_TX_PARTITION_BASE_MAX), +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + REG_VARIABLE(CFG_WLAN_LOGGING_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, wlan_logging_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_SUPPORT_DEFAULT, + CFG_WLAN_LOGGING_SUPPORT_DISABLE, + CFG_WLAN_LOGGING_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_WLAN_LOGGING_CONSOLE_SUPPORT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, wlan_logging_to_console, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_CONSOLE_SUPPORT_DEFAULT, + CFG_WLAN_LOGGING_CONSOLE_SUPPORT_DISABLE, + CFG_WLAN_LOGGING_CONSOLE_SUPPORT_ENABLE), +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + +#ifdef WLAN_FEATURE_LPSS + REG_VARIABLE(CFG_ENABLE_LPASS_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, enable_lpass_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LPASS_SUPPORT_DEFAULT, + CFG_ENABLE_LPASS_SUPPORT_MIN, + CFG_ENABLE_LPASS_SUPPORT_MAX), +#endif + +#ifdef WLAN_FEATURE_NAN + REG_VARIABLE(CFG_ENABLE_NAN_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, enable_nan_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NAN_SUPPORT_DEFAULT, + CFG_ENABLE_NAN_SUPPORT_MIN, + CFG_ENABLE_NAN_SUPPORT_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_SELF_RECOVERY, WLAN_PARAM_Integer, + struct hdd_config, enableSelfRecovery, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SELF_RECOVERY_DEFAULT, + CFG_ENABLE_SELF_RECOVERY_MIN, + CFG_ENABLE_SELF_RECOVERY_MAX), + + REG_VARIABLE(CFG_ENABLE_SAP_SUSPEND, WLAN_PARAM_Integer, + struct hdd_config, enable_sap_suspend, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SAP_SUSPEND_DEFAULT, + CFG_ENABLE_SAP_SUSPEND_MIN, + CFG_ENABLE_SAP_SUSPEND_MAX), + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + REG_VARIABLE(CFG_EXTWOW_GO_TO_SUSPEND, WLAN_PARAM_Integer, + struct hdd_config, extWowGotoSuspend, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_GO_TO_SUSPEND_DEFAULT, + CFG_EXTWOW_GO_TO_SUSPEND_MIN, + CFG_EXTWOW_GO_TO_SUSPEND_MAX), + + REG_VARIABLE(CFG_EXTWOW_APP1_WAKE_PIN_NUMBER, WLAN_PARAM_Integer, + struct hdd_config, extWowApp1WakeupPinNumber, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_DEFAULT, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MIN, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MAX), + + REG_VARIABLE(CFG_EXTWOW_APP2_WAKE_PIN_NUMBER, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2WakeupPinNumber, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_DEFAULT, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MIN, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_INIT_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAInitPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_MIN_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAMinPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_MAX_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAMaxPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_INC_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAIncPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_INC_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_INC_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_INC_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_SRC_PORT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpSrcPort, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_SRC_PORT_DEFAULT, + CFG_EXTWOW_TCP_SRC_PORT_MIN, + CFG_EXTWOW_TCP_SRC_PORT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_DST_PORT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpDstPort, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_DST_PORT_DEFAULT, + CFG_EXTWOW_TCP_DST_PORT_MIN, + CFG_EXTWOW_TCP_DST_PORT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_TX_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpTxTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_TX_TIMEOUT_DEFAULT, + CFG_EXTWOW_TCP_TX_TIMEOUT_MIN, + CFG_EXTWOW_TCP_TX_TIMEOUT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_RX_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpRxTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_RX_TIMEOUT_DEFAULT, + CFG_EXTWOW_TCP_RX_TIMEOUT_MIN, + CFG_EXTWOW_TCP_RX_TIMEOUT_MAX), +#endif + REG_VARIABLE(CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, gEnableDeauthToDisassocMap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_DEFAULT, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MIN, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MAX), +#ifdef DHCP_SERVER_OFFLOAD + REG_VARIABLE(CFG_DHCP_SERVER_OFFLOAD_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDHCPServerOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MAX), + REG_VARIABLE(CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, dhcpMaxNumClients, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MIN, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX), + REG_VARIABLE_STRING(CFG_DHCP_SERVER_IP_NAME, WLAN_PARAM_String, + struct hdd_config, dhcpServerIP, + VAR_FLAGS_OPTIONAL, + (void *)CFG_DHCP_SERVER_IP_DEFAULT), +#endif /* DHCP_SERVER_OFFLOAD */ + + REG_VARIABLE(CFG_ENABLE_DEAUTH_BEFORE_CONNECTION, WLAN_PARAM_Integer, + struct hdd_config, send_deauth_before_con, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_DEFAULT, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MIN, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX), + + REG_VARIABLE(CFG_ENABLE_MAC_ADDR_SPOOFING, WLAN_PARAM_Integer, + struct hdd_config, enable_mac_spoofing, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT, + CFG_ENABLE_MAC_ADDR_SPOOFING_MIN, + CFG_ENABLE_MAC_ADDR_SPOOFING_MAX), + + REG_VARIABLE(CFG_ENABLE_CUSTOM_CONC_RULE1_NAME, WLAN_PARAM_Integer, + struct hdd_config, conc_custom_rule1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_DEFAULT, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MIN, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MAX), + + REG_VARIABLE(CFG_ENABLE_CUSTOM_CONC_RULE2_NAME, WLAN_PARAM_Integer, + struct hdd_config, conc_custom_rule2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_DEFAULT, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MIN, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MAX), + + REG_VARIABLE(CFG_ENABLE_STA_CONNECTION_IN_5GHZ, WLAN_PARAM_Integer, + struct hdd_config, is_sta_connection_in_5gz_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_DEFAULT, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MIN, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MAX), + + REG_VARIABLE(CFG_STA_MIRACAST_MCC_REST_TIME_VAL, WLAN_PARAM_Integer, + struct hdd_config, sta_miracast_mcc_rest_time_val, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_DEFAULT, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MIN, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MAX), + + REG_VARIABLE(CFG_STA_SCAN_BURST_DURATION_VAL, WLAN_PARAM_Integer, + struct hdd_config, sta_scan_burst_duration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_SCAN_BURST_DURATION_VAL_DEFAULT, + CFG_STA_SCAN_BURST_DURATION_VAL_MIN, + CFG_STA_SCAN_BURST_DURATION_VAL_MAX), + + REG_VARIABLE(CFG_P2P_SCAN_BURST_DURATION_VAL, WLAN_PARAM_Integer, + struct hdd_config, p2p_scan_burst_duration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_P2P_SCAN_BURST_DURATION_VAL_DEFAULT, + CFG_P2P_SCAN_BURST_DURATION_VAL_MIN, + CFG_P2P_SCAN_BURST_DURATION_VAL_MAX), + + REG_VARIABLE(CFG_GO_SCAN_BURST_DURATION_VAL, WLAN_PARAM_Integer, + struct hdd_config, go_scan_burst_duration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_SCAN_BURST_DURATION_VAL_DEFAULT, + CFG_GO_SCAN_BURST_DURATION_VAL_MIN, + CFG_GO_SCAN_BURST_DURATION_VAL_MAX), + + REG_VARIABLE(CFG_AP_SCAN_BURST_DURATION_VAL, WLAN_PARAM_Integer, + struct hdd_config, ap_scan_burst_duration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_SCAN_BURST_DURATION_VAL_DEFAULT, + CFG_AP_SCAN_BURST_DURATION_VAL_MIN, + CFG_AP_SCAN_BURST_DURATION_VAL_MAX), + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + REG_VARIABLE(CFG_SAP_MCC_CHANNEL_AVOIDANCE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + sap_channel_avoidance, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_DEFAULT, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_MIN, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_MAX), +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + REG_VARIABLE(CFG_SAP_11AC_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_11ac_override, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_11AC_OVERRIDE_DEFAULT, + CFG_SAP_11AC_OVERRIDE_MIN, + CFG_SAP_11AC_OVERRIDE_MAX), + + REG_VARIABLE(CFG_GO_11AC_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, go_11ac_override, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_11AC_OVERRIDE_DEFAULT, + CFG_GO_11AC_OVERRIDE_MIN, + CFG_GO_11AC_OVERRIDE_MAX), + + REG_VARIABLE(CFG_ENABLE_RAMDUMP_COLLECTION, WLAN_PARAM_Integer, + struct hdd_config, is_ramdump_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RAMDUMP_COLLECTION_DEFAULT, + CFG_ENABLE_RAMDUMP_COLLECTION_MIN, + CFG_ENABLE_RAMDUMP_COLLECTION_MAX), + + REG_VARIABLE(CFG_SAP_DOT11MC, WLAN_PARAM_Integer, + struct hdd_config, sap_dot11mc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_DOT11MC_DEFAULT, + CFG_SAP_DOT11MC_MIN, + CFG_SAP_DOT11MC_MAX), + + REG_VARIABLE(CFG_ENABLE_NON_DFS_CHAN_ON_RADAR, WLAN_PARAM_Integer, + struct hdd_config, prefer_non_dfs_on_radar, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX), + + REG_VARIABLE(CFG_P2P_LISTEN_DEFER_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, p2p_listen_defer_interval, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_P2P_LISTEN_DEFER_INTERVAL_DEFAULT, + CFG_P2P_LISTEN_DEFER_INTERVAL_MIN, + CFG_P2P_LISTEN_DEFER_INTERVAL_MAX), + + REG_VARIABLE(CFG_MULTICAST_HOST_FW_MSGS, WLAN_PARAM_Integer, + struct hdd_config, multicast_host_fw_msgs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MULTICAST_HOST_FW_MSGS_DEFAULT, + CFG_MULTICAST_HOST_FW_MSGS_MIN, + CFG_MULTICAST_HOST_FW_MSGS_MAX), + + REG_VARIABLE(CFG_CONC_SYSTEM_PREF, WLAN_PARAM_Integer, + struct hdd_config, conc_system_pref, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CONC_SYSTEM_PREF_DEFAULT, + CFG_CONC_SYSTEM_PREF_MIN, + CFG_CONC_SYSTEM_PREF_MAX), + + REG_VARIABLE(CFG_TSO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, tso_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TSO_ENABLED_DEFAULT, + CFG_TSO_ENABLED_MIN, + CFG_TSO_ENABLED_MAX), + + REG_VARIABLE(CFG_LRO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, lro_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LRO_ENABLED_DEFAULT, + CFG_LRO_ENABLED_MIN, + CFG_LRO_ENABLED_MAX), + + REG_VARIABLE(CFG_GRO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, gro_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GRO_ENABLED_DEFAULT, + CFG_GRO_ENABLED_MIN, + CFG_GRO_ENABLED_MAX), + + REG_VARIABLE(CFG_APF_PACKET_FILTER_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, apf_packet_filter_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_APF_PACKET_FILTER_OFFLOAD_DEFAULT, + CFG_APF_PACKET_FILTER_OFFLOAD_MIN, + CFG_APF_PACKET_FILTER_OFFLOAD_MAX), + + REG_VARIABLE(CFG_TDLS_ENABLE_DEFER_TIMER, WLAN_PARAM_Integer, + struct hdd_config, tdls_enable_defer_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_ENABLE_DEFER_TIMER_DEFAULT, + CFG_TDLS_ENABLE_DEFER_TIMER_MIN, + CFG_TDLS_ENABLE_DEFER_TIMER_MAX), + + REG_VARIABLE(CFG_FLOW_STEERING_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, flow_steering_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FLOW_STEERING_ENABLED_DEFAULT, + CFG_FLOW_STEERING_ENABLED_MIN, + CFG_FLOW_STEERING_ENABLED_MAX), + + REG_VARIABLE(CFG_MAX_MSDUS_PER_RXIND_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_msdus_per_rxinorderind, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_MSDUS_PER_RXIND_DEFAULT, + CFG_MAX_MSDUS_PER_RXIND_MIN, + CFG_MAX_MSDUS_PER_RXIND_MAX), + + REG_VARIABLE(CFG_ACTIVE_MODE_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, active_mode_offload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MODE_OFFLOAD_DEFAULT, + CFG_ACTIVE_MODE_OFFLOAD_MIN, + CFG_ACTIVE_MODE_OFFLOAD_MAX), + + REG_VARIABLE(CFG_FINE_TIME_MEAS_CAPABILITY, WLAN_PARAM_HexInteger, + struct hdd_config, fine_time_meas_cap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT, + CFG_FINE_TIME_MEAS_CAPABILITY_MIN, + CFG_FINE_TIME_MEAS_CAPABILITY_MAX), + +#ifdef WLAN_FEATURE_FASTPATH + REG_VARIABLE(CFG_ENABLE_FASTPATH, WLAN_PARAM_Integer, + struct hdd_config, fastpath_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FASTPATH_DEFAULT, + CFG_ENABLE_FASTPATH_MIN, + CFG_ENABLE_FASTPATH_MAX), +#endif + REG_VARIABLE(CFG_MAX_SCAN_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_scan_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_SCAN_COUNT_DEFAULT, + CFG_MAX_SCAN_COUNT_MIN, + CFG_MAX_SCAN_COUNT_MAX), + + REG_VARIABLE(CFG_DOT11P_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dot11p_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DOT11P_MODE_DEFAULT, + CFG_DOT11P_MODE_MIN, + CFG_DOT11P_MODE_MAX), + + REG_VARIABLE(CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE, WLAN_PARAM_Integer, + struct hdd_config, etsi13_srd_chan_in_master_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE_DEF, + CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE_MIN, + CFG_ETSI13_SRD_CHAN_IN_MASTER_MODE_MAX), + + REG_VARIABLE(CFG_NUM_TX_CHAINS_2G, WLAN_PARAM_Integer, + struct hdd_config, num_tx_chains_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_TX_CHAINS_2G_DEF, + CFG_NUM_TX_CHAINS_2G_MIN, + CFG_NUM_TX_CHAINS_2G_MAX), + + REG_VARIABLE(CFG_NUM_TX_CHAINS_5G, WLAN_PARAM_Integer, + struct hdd_config, num_tx_chains_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_TX_CHAINS_5G_DEF, + CFG_NUM_TX_CHAINS_5G_MIN, + CFG_NUM_TX_CHAINS_5G_MAX), + + REG_VARIABLE(CFG_NUM_RX_CHAINS_2G, WLAN_PARAM_Integer, + struct hdd_config, num_rx_chains_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_RX_CHAINS_2G_DEF, + CFG_NUM_RX_CHAINS_2G_MIN, + CFG_NUM_RX_CHAINS_2G_MAX), + + REG_VARIABLE(CFG_NUM_RX_CHAINS_5G, WLAN_PARAM_Integer, + struct hdd_config, num_rx_chains_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_RX_CHAINS_5G_DEF, + CFG_NUM_RX_CHAINS_5G_MIN, + CFG_NUM_RX_CHAINS_5G_MAX), + + REG_VARIABLE(CFG_TX_NSS_2G, WLAN_PARAM_Integer, + struct hdd_config, tx_nss_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_NSS_2G_DEF, + CFG_TX_NSS_2G_MIN, + CFG_TX_NSS_2G_MAX), + + REG_VARIABLE(CFG_TX_NSS_5G, WLAN_PARAM_Integer, + struct hdd_config, tx_nss_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_NSS_5G_DEF, + CFG_TX_NSS_5G_MIN, + CFG_TX_NSS_5G_MAX), + + REG_VARIABLE(CFG_RX_NSS_2G, WLAN_PARAM_Integer, + struct hdd_config, rx_nss_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_NSS_2G_DEF, + CFG_RX_NSS_2G_MIN, + CFG_RX_NSS_2G_MAX), + + REG_VARIABLE(CFG_RX_NSS_5G, WLAN_PARAM_Integer, + struct hdd_config, rx_nss_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_NSS_5G_DEF, + CFG_RX_NSS_5G_MIN, + CFG_RX_NSS_5G_MAX), + + REG_VARIABLE(CFG_NUM_TX_CHAINS_11b, WLAN_PARAM_Integer, + struct hdd_config, num_tx_chains_11b, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_TX_CHAINS_11b_DEF, + CFG_NUM_TX_CHAINS_11b_MIN, + CFG_NUM_TX_CHAINS_11b_MAX), + + REG_VARIABLE(CFG_NUM_TX_CHAINS_11g, WLAN_PARAM_Integer, + struct hdd_config, num_tx_chains_11g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_TX_CHAINS_11g_DEF, + CFG_NUM_TX_CHAINS_11g_MIN, + CFG_NUM_TX_CHAINS_11g_MAX), + + REG_VARIABLE(CFG_NUM_TX_CHAINS_11a, WLAN_PARAM_Integer, + struct hdd_config, num_tx_chains_11a, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_TX_CHAINS_11a_DEF, + CFG_NUM_TX_CHAINS_11a_MIN, + CFG_NUM_TX_CHAINS_11a_MAX), + + REG_VARIABLE(CFG_DISABLE_TX_MRC_2G, WLAN_PARAM_Integer, + struct hdd_config, disable_tx_mrc_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_TX_MRC_2G_DEF, + CFG_DISABLE_TX_MRC_2G_MIN, + CFG_DISABLE_TX_MRC_2G_MAX), + + REG_VARIABLE(CFG_DISABLE_TX_MRC_5G, WLAN_PARAM_Integer, + struct hdd_config, disable_tx_mrc_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_TX_MRC_5G_DEF, + CFG_DISABLE_TX_MRC_5G_MIN, + CFG_DISABLE_TX_MRC_5G_MAX), + + REG_VARIABLE(CFG_DISABLE_RX_MRC_2G, WLAN_PARAM_Integer, + struct hdd_config, disable_rx_mrc_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_RX_MRC_2G_DEF, + CFG_DISABLE_RX_MRC_2G_MIN, + CFG_DISABLE_RX_MRC_2G_MAX), + + REG_VARIABLE(CFG_DISABLE_RX_MRC_5G, WLAN_PARAM_Integer, + struct hdd_config, disable_rx_mrc_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_RX_MRC_5G_DEF, + CFG_DISABLE_RX_MRC_5G_MIN, + CFG_DISABLE_RX_MRC_5G_MAX), + +#ifdef FEATURE_WLAN_EXTSCAN + REG_VARIABLE(CFG_EXTSCAN_ALLOWED_NAME, WLAN_PARAM_Integer, + struct hdd_config, extscan_enabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ALLOWED_DEF, + CFG_EXTSCAN_ALLOWED_MIN, + CFG_EXTSCAN_ALLOWED_MAX), + + REG_VARIABLE(CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_passive_max_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MIN, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_passive_min_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MIN, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_active_max_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MIN, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_active_min_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MIN, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MAX), +#endif + +#ifdef WLAN_FEATURE_WOW_PULSE + REG_VARIABLE(CFG_WOW_PULSE_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_SUPPORT_DEFAULT, + CFG_WOW_PULSE_SUPPORT_MIN, + CFG_WOW_PULSE_SUPPORT_MAX), + + REG_VARIABLE(CFG_WOW_PULSE_PIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_pin, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_PIN_DEFAULT, + CFG_WOW_PULSE_PIN_MIN, + CFG_WOW_PULSE_PIN_MAX), + + REG_VARIABLE(CFG_WOW_PULSE_INTERVAL_LOW_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_interval_low, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_INTERVAL_LOW_DEFAULT, + CFG_WOW_PULSE_INTERVAL_LOW_MIN, + CFG_WOW_PULSE_INTERVAL_LOW_MAX), + + REG_VARIABLE(CFG_WOW_PULSE_INTERVAL_HIGH_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_interval_high, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_INTERVAL_HIGH_DEFAULT, + CFG_WOW_PULSE_INTERVAL_HIGH_MIN, + CFG_WOW_PULSE_INTERVAL_HIGH_MAX), +#endif + + + REG_VARIABLE(CFG_CE_CLASSIFY_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ce_classify_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CE_CLASSIFY_ENABLE_DEFAULT, + CFG_CE_CLASSIFY_ENABLE_MIN, + CFG_CE_CLASSIFY_ENABLE_MAX), + + REG_VARIABLE(CFG_DUAL_MAC_FEATURE_DISABLE, WLAN_PARAM_HexInteger, + struct hdd_config, dual_mac_feature_disable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DUAL_MAC_FEATURE_DISABLE_DEFAULT, + CFG_DUAL_MAC_FEATURE_DISABLE_MIN, + CFG_DUAL_MAC_FEATURE_DISABLE_MAX), + + REG_VARIABLE_STRING(CFG_DBS_SCAN_SELECTION_NAME, WLAN_PARAM_String, + struct hdd_config, dbs_scan_selection, + VAR_FLAGS_OPTIONAL, + (void *)CFG_DBS_SCAN_SELECTION_DEFAULT), + + REG_VARIABLE(CFG_STA_SAP_SCC_ON_DFS_CHAN, WLAN_PARAM_HexInteger, + struct hdd_config, sta_sap_scc_on_dfs_chan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_SAP_SCC_ON_DFS_CHAN_DEFAULT, + CFG_STA_SAP_SCC_ON_DFS_CHAN_MIN, + CFG_STA_SAP_SCC_ON_DFS_CHAN_MAX), + + REG_VARIABLE(CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN, WLAN_PARAM_HexInteger, + struct hdd_config, sta_sap_scc_on_lte_coex_chan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN_DEFAULT, + CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN_MIN, + CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN_MAX), + +#ifdef FEATURE_WLAN_SCAN_PNO + REG_VARIABLE(CFG_PNO_CHANNEL_PREDICTION_NAME, WLAN_PARAM_Integer, + struct hdd_config, pno_channel_prediction, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_CHANNEL_PREDICTION_DEFAULT, + CFG_PNO_CHANNEL_PREDICTION_MIN, + CFG_PNO_CHANNEL_PREDICTION_MAX), + + REG_VARIABLE(CFG_TOP_K_NUM_OF_CHANNELS_NAME, WLAN_PARAM_Integer, + struct hdd_config, top_k_num_of_channels, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TOP_K_NUM_OF_CHANNELS_DEFAULT, + CFG_TOP_K_NUM_OF_CHANNELS_MIN, + CFG_TOP_K_NUM_OF_CHANNELS_MAX), + + REG_VARIABLE(CFG_STATIONARY_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, stationary_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STATIONARY_THRESHOLD_DEFAULT, + CFG_STATIONARY_THRESHOLD_MIN, + CFG_STATIONARY_THRESHOLD_MAX), + + REG_VARIABLE(CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME, + WLAN_PARAM_Integer, + struct hdd_config, channel_prediction_full_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_DEFAULT, + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MIN, + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, pnoscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MAX), +#endif + + REG_VARIABLE(CFG_TX_CHAIN_MASK_CCK, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_cck, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_CCK_DEFAULT, + CFG_TX_CHAIN_MASK_CCK_MIN, + CFG_TX_CHAIN_MASK_CCK_MAX), + + REG_VARIABLE(CFG_TX_CHAIN_MASK_1SS, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_1ss, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_1SS_DEFAULT, + CFG_TX_CHAIN_MASK_1SS_MIN, + CFG_TX_CHAIN_MASK_1SS_MAX), + + REG_VARIABLE(CFG_ENABLE_SMART_CHAINMASK_NAME, WLAN_PARAM_Integer, + struct hdd_config, smart_chainmask_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SMART_CHAINMASK_DEFAULT, + CFG_ENABLE_SMART_CHAINMASK_MIN, + CFG_ENABLE_SMART_CHAINMASK_MAX), + + REG_VARIABLE(CFG_ENABLE_COEX_ALT_CHAINMASK_NAME, WLAN_PARAM_Integer, + struct hdd_config, alternative_chainmask_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_COEX_ALT_CHAINMASK_DEFAULT, + CFG_ENABLE_COEX_ALT_CHAINMASK_MIN, + CFG_ENABLE_COEX_ALT_CHAINMASK_MAX), + + REG_VARIABLE(CFG_SELF_GEN_FRM_PWR, WLAN_PARAM_Integer, + struct hdd_config, self_gen_frm_pwr, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SELF_GEN_FRM_PWR_DEFAULT, + CFG_SELF_GEN_FRM_PWR_MIN, + CFG_SELF_GEN_FRM_PWR_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, early_stop_scan_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_ENABLE_DEFAULT, + CFG_EARLY_STOP_SCAN_ENABLE_MIN, + CFG_EARLY_STOP_SCAN_ENABLE_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_MIN_THRESHOLD, + WLAN_PARAM_SignedInteger, struct hdd_config, + early_stop_scan_min_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_DEFAULT, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MIN, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_MAX_THRESHOLD, + WLAN_PARAM_SignedInteger, struct hdd_config, + early_stop_scan_max_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_DEFAULT, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MIN, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MAX), + + REG_VARIABLE(CFG_FIRST_SCAN_BUCKET_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, first_scan_bucket_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FIRST_SCAN_BUCKET_THRESHOLD_DEFAULT, + CFG_FIRST_SCAN_BUCKET_THRESHOLD_MIN, + CFG_FIRST_SCAN_BUCKET_THRESHOLD_MAX), + +#ifdef FEATURE_LFR_SUBNET_DETECTION + REG_VARIABLE(CFG_ENABLE_LFR_SUBNET_DETECTION, WLAN_PARAM_Integer, + struct hdd_config, enable_lfr_subnet_detection, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LFR_SUBNET_DEFAULT, + CFG_ENABLE_LFR_SUBNET_MIN, + CFG_ENABLE_LFR_SUBNET_MAX), +#endif + REG_VARIABLE(CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, obss_active_dwelltime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_DEFAULT, + CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MIN, + CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MAX), + + REG_VARIABLE(CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, obss_passive_dwelltime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_DEFAULT, + CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MIN, + CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MAX), + + REG_VARIABLE(CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_NAME, + WLAN_PARAM_Integer, + struct hdd_config, obss_width_trigger_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_DEFAULT, + CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MIN, + CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MAX), + + REG_VARIABLE(CFG_INFORM_BSS_RSSI_RAW_NAME, WLAN_PARAM_Integer, + struct hdd_config, inform_bss_rssi_raw, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INFORM_BSS_RSSI_RAW_DEFAULT, + CFG_INFORM_BSS_RSSI_RAW_MIN, + CFG_INFORM_BSS_RSSI_RAW_MAX), + +#ifdef WLAN_FEATURE_TSF + REG_VARIABLE(CFG_SET_TSF_GPIO_PIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, tsf_gpio_pin, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TSF_GPIO_PIN_DEFAULT, + CFG_SET_TSF_GPIO_PIN_MIN, + CFG_SET_TSF_GPIO_PIN_MAX), + +#ifdef WLAN_FEATURE_TSF_PLUS + REG_VARIABLE(CFG_SET_TSF_PTP_OPT_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, tsf_ptp_options, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TSF_PTP_OPT_DEFAULT, + CFG_SET_TSF_PTP_OPT_MIN, + CFG_SET_TSF_PTP_OPT_MAX), +#endif /* WLAN_FEATURE_TSF_PLUS */ +#endif + + REG_VARIABLE(CFG_ENABLE_TW_COEX_LEGACY_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_three_way_coex_config_legacy, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TW_COEX_LEGACY_DEFAULT, + CFG_ENABLE_TW_COEX_LEGACY_MIN, + CFG_ENABLE_TW_COEX_LEGACY_MAX), + + REG_VARIABLE(CFG_ROAM_DENSE_TRAFFIC_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, roam_dense_traffic_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_DEFAULT, + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MIN, + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MAX), + + REG_VARIABLE(CFG_ROAM_DENSE_RSSI_THRE_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, roam_dense_rssi_thresh_offset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_DENSE_RSSI_THRE_OFFSET_DEFAULT, + CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MIN, + CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MAX), + + REG_VARIABLE(CFG_IGNORE_PEER_HT_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignore_peer_ht_opmode, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_PEER_HT_MODE_DEFAULT, + CFG_IGNORE_PEER_HT_MODE_MIN, + CFG_IGNORE_PEER_HT_MODE_MAX), + + REG_VARIABLE(CFG_ROAM_DENSE_MIN_APS, WLAN_PARAM_Integer, + struct hdd_config, roam_dense_min_aps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_DENSE_MIN_APS_DEFAULT, + CFG_ROAM_DENSE_MIN_APS_MIN, + CFG_ROAM_DENSE_MIN_APS_MAX), + + REG_VARIABLE(CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, struct hdd_config, + roam_bg_scan_bad_rssi_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_DEFAULT, + CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_MIN, + CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_ROAM_BG_SCAN_CLIENT_BITMAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, roam_bg_scan_client_bitmap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BG_SCAN_CLIENT_BITMAP_DEFAULT, + CFG_ROAM_BG_SCAN_CLIENT_BITMAP_MIN, + CFG_ROAM_BG_SCAN_CLIENT_BITMAP_MAX), + + REG_VARIABLE(CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_NAME, + WLAN_PARAM_Integer, struct hdd_config, + roam_bad_rssi_thresh_offset_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_DEFAULT, + CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_MIN, + CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_MAX), + + REG_VARIABLE(CFG_ROAM_HO_DELAY_FOR_RX_NAME, + WLAN_PARAM_Integer, struct hdd_config, + ho_delay_for_rx, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_HO_DELAY_FOR_RX_DEFAULT, + CFG_ROAM_HO_DELAY_FOR_RX_MIN, + CFG_ROAM_HO_DELAY_FOR_RX_MAX), + + REG_VARIABLE(CFG_MIN_DELAY_BTW_ROAM_SCAN_NAME, + WLAN_PARAM_Integer, struct hdd_config, + min_delay_btw_roam_scans, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MIN_DELAY_BTW_ROAM_SCAN_DEFAULT, + CFG_MIN_DELAY_BTW_ROAM_SCAN_MIN, + CFG_MIN_DELAY_BTW_ROAM_SCAN_MAX), + + REG_VARIABLE(CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_NAME, + WLAN_PARAM_HexInteger, struct hdd_config, + roam_trigger_reason_bitmask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_DEFAULT, + CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MIN, + CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_MAX), + + REG_VARIABLE(CFG_ROAM_SCAN_SCAN_POLICY_NAME, WLAN_PARAM_Integer, + struct hdd_config, roaming_scan_policy, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_SCAN_POLICY_DEFAULT, + CFG_ROAM_SCAN_SCAN_POLICY_MIN, + CFG_ROAM_SCAN_SCAN_POLICY_MAX), + + REG_VARIABLE(CFG_ENABLE_FATAL_EVENT_TRIGGER, WLAN_PARAM_Integer, + struct hdd_config, enable_fatal_event, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FATAL_EVENT_TRIGGER_DEFAULT, + CFG_ENABLE_FATAL_EVENT_TRIGGER_MIN, + CFG_ENABLE_FATAL_EVENT_TRIGGER_MAX), + + REG_VARIABLE(CFG_ENABLE_EDCA_INI_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_edca_params, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_EDCA_INI_DEFAULT, + CFG_ENABLE_EDCA_INI_MIN, + CFG_ENABLE_EDCA_INI_MAX), + + REG_VARIABLE(CFG_ENABLE_GO_CTS2SELF_FOR_STA, WLAN_PARAM_Integer, + struct hdd_config, enable_go_cts2self_for_sta, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_GO_CTS2SELF_FOR_STA_DEFAULT, + CFG_ENABLE_GO_CTS2SELF_FOR_STA_MIN, + CFG_ENABLE_GO_CTS2SELF_FOR_STA_MAX), + + REG_VARIABLE(CFG_EDCA_VO_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vo_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_CWMIN_VALUE_DEFAULT, + CFG_EDCA_VO_CWMIN_VALUE_MIN, + CFG_EDCA_VO_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vi_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_CWMIN_VALUE_DEFAULT, + CFG_EDCA_VI_CWMIN_VALUE_MIN, + CFG_EDCA_VI_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_bk_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_CWMIN_VALUE_DEFAULT, + CFG_EDCA_BK_CWMIN_VALUE_MIN, + CFG_EDCA_BK_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_be_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_CWMIN_VALUE_DEFAULT, + CFG_EDCA_BE_CWMIN_VALUE_MIN, + CFG_EDCA_BE_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VO_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vo_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_CWMAX_VALUE_DEFAULT, + CFG_EDCA_VO_CWMAX_VALUE_MIN, + CFG_EDCA_VO_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vi_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_CWMAX_VALUE_DEFAULT, + CFG_EDCA_VI_CWMAX_VALUE_MIN, + CFG_EDCA_VI_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_bk_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_CWMAX_VALUE_DEFAULT, + CFG_EDCA_BK_CWMAX_VALUE_MIN, + CFG_EDCA_BK_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_be_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_CWMAX_VALUE_DEFAULT, + CFG_EDCA_BE_CWMAX_VALUE_MIN, + CFG_EDCA_BE_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VO_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vo_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_AIFS_VALUE_DEFAULT, + CFG_EDCA_VO_AIFS_VALUE_MIN, + CFG_EDCA_VO_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vi_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_AIFS_VALUE_DEFAULT, + CFG_EDCA_VI_AIFS_VALUE_MIN, + CFG_EDCA_VI_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_bk_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_AIFS_VALUE_DEFAULT, + CFG_EDCA_BK_AIFS_VALUE_MIN, + CFG_EDCA_BK_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_be_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_AIFS_VALUE_DEFAULT, + CFG_EDCA_BE_AIFS_VALUE_MIN, + CFG_EDCA_BE_AIFS_VALUE_MAX), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_VO_NAME, + WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_vo, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_VO_DEFAULT), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_VI_NAME, + WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_vi, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_VI_DEFAULT), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_BE_NAME, + WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_be, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_BE_DEFAULT), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_BK_NAME, + WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_bk, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_BK_DEFAULT), + +#ifdef WLAN_FEATURE_NAN_DATAPATH + REG_VARIABLE(CFG_ENABLE_NAN_DATAPATH_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_nan_datapath, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NAN_DATAPATH_DEFAULT, + CFG_ENABLE_NAN_DATAPATH_MIN, + CFG_ENABLE_NAN_DATAPATH_MAX), + + REG_VARIABLE(CFG_ENABLE_NAN_NDI_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nan_datapath_ndi_channel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NAN_NDI_CHANNEL_DEFAULT, + CFG_ENABLE_NAN_NDI_CHANNEL_MIN, + CFG_ENABLE_NAN_NDI_CHANNEL_MAX), +#endif + + REG_VARIABLE(CFG_CREATE_BUG_REPORT_FOR_SCAN, WLAN_PARAM_Integer, + struct hdd_config, bug_report_for_no_scan_results, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CREATE_BUG_REPORT_FOR_SCAN_DEFAULT, + CFG_CREATE_BUG_REPORT_FOR_SCAN_DISABLE, + CFG_CREATE_BUG_REPORT_FOR_SCAN_ENABLE), + + REG_VARIABLE(CFG_USER_AUTO_CHANNEL_SELECTION, WLAN_PARAM_Integer, + struct hdd_config, vendor_acs_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_USER_AUTO_CHANNEL_SELECTION_DEFAULT, + CFG_USER_AUTO_CHANNEL_SELECTION_DISABLE, + CFG_USER_AUTO_CHANNEL_SELECTION_ENABLE), + + REG_VARIABLE(CFG_USER_ACS_DFS_LTE, WLAN_PARAM_Integer, + struct hdd_config, acs_support_for_dfs_ltecoex, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_USER_ACS_DFS_LTE_DEFAULT, + CFG_USER_ACS_DFS_LTE_DISABLE, + CFG_USER_ACS_DFS_LTE_ENABLE), + +#ifdef CONFIG_DP_TRACE + REG_VARIABLE(CFG_ENABLE_DP_TRACE, WLAN_PARAM_Integer, + struct hdd_config, enable_dp_trace, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DP_TRACE_DEFAULT, + CFG_ENABLE_DP_TRACE_MIN, + CFG_ENABLE_DP_TRACE_MAX), + + + REG_VARIABLE_STRING(CFG_ENABLE_DP_TRACE_CONFIG, WLAN_PARAM_String, + struct hdd_config, dp_trace_config, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_DP_TRACE_CONFIG_DEFAULT), +#endif + + REG_VARIABLE(CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_SCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_adaptive_dwell_mode_nc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_MIN, + CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, roamscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, extscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, adaptive_dwell_mode_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_DEFAULT, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_MIN, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_MAX), + + REG_VARIABLE(CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, global_adapt_dwelltime_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_DEFAULT, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MIN, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_LPF_WEIGHT_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_lpf_weight, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_LPF_WEIGHT_DEFAULT, + CFG_ADAPT_DWELL_LPF_WEIGHT_MIN, + CFG_ADAPT_DWELL_LPF_WEIGHT_MAX), + + REG_VARIABLE(CFG_SUB_20_CHANNEL_WIDTH_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_sub_20_channel_width, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SUB_20_CHANNEL_WIDTH_DEFAULT, + CFG_SUB_20_CHANNEL_WIDTH_MIN, + CFG_SUB_20_CHANNEL_WIDTH_MAX), + + REG_VARIABLE(CFG_TGT_GTX_USR_CFG_NAME, WLAN_PARAM_Integer, + struct hdd_config, tgt_gtx_usr_cfg, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TGT_GTX_USR_CFG_DEFAULT, + CFG_TGT_GTX_USR_CFG_MIN, + CFG_TGT_GTX_USR_CFG_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_PASMON_INTVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_passive_mon_intval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_PASMON_INTVAL_DEFAULT, + CFG_ADAPT_DWELL_PASMON_INTVAL_MIN, + CFG_ADAPT_DWELL_PASMON_INTVAL_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_WIFI_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_wifi_act_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_WIFI_THRESH_DEFAULT, + CFG_ADAPT_DWELL_WIFI_THRESH_MIN, + CFG_ADAPT_DWELL_WIFI_THRESH_MAX), + + REG_VARIABLE(CFG_RX_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, rx_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_MODE_DEFAULT, + CFG_RX_MODE_MIN, + CFG_RX_MODE_MAX), + + REG_VARIABLE(CFG_CE_SERVICE_MAX_YIELD_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, ce_service_max_yield_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CE_SERVICE_MAX_YIELD_TIME_DEFAULT, + CFG_CE_SERVICE_MAX_YIELD_TIME_MIN, + CFG_CE_SERVICE_MAX_YIELD_TIME_MAX), + + REG_VARIABLE(CFG_CE_SERVICE_MAX_RX_IND_FLUSH_NAME, WLAN_PARAM_Integer, + struct hdd_config, ce_service_max_rx_ind_flush, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CE_SERVICE_MAX_RX_IND_FLUSH_DEFAULT, + CFG_CE_SERVICE_MAX_RX_IND_FLUSH_MIN, + CFG_CE_SERVICE_MAX_RX_IND_FLUSH_MAX), + + REG_VARIABLE(CFG_NAPI_CE_CPU_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, napi_cpu_affinity_mask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NAPI_CE_CPU_MASK_DEFAULT, + CFG_NAPI_CE_CPU_MASK_MIN, + CFG_NAPI_CE_CPU_MASK_MAX), + + REG_VARIABLE(CFG_RX_THREAD_CPU_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, rx_thread_affinity_mask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_THREAD_CPU_MASK_DEFAULT, + CFG_RX_THREAD_CPU_MASK_MIN, + CFG_RX_THREAD_CPU_MASK_MAX), + + REG_VARIABLE_STRING(CFG_RPS_RX_QUEUE_CPU_MAP_LIST_NAME, + WLAN_PARAM_String, + struct hdd_config, cpu_map_list, + VAR_FLAGS_OPTIONAL, + (void *)CFG_RPS_RX_QUEUE_CPU_MAP_LIST_DEFAULT), + + REG_VARIABLE(CFG_INDOOR_CHANNEL_SUPPORT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, indoor_channel_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INDOOR_CHANNEL_SUPPORT_DEFAULT, + CFG_INDOOR_CHANNEL_SUPPORT_MIN, + CFG_INDOOR_CHANNEL_SUPPORT_MAX), + + REG_VARIABLE(CFG_MARK_INDOOR_AS_DISABLE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, force_ssc_disable_indoor_channel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MARK_INDOOR_AS_DISABLE_DEFAULT, + CFG_MARK_INDOOR_AS_DISABLE_MIN, + CFG_MARK_INDOOR_AS_DISABLE_MAX), + + REG_VARIABLE(CFG_SAP_TX_LEAKAGE_THRESHOLD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, sap_tx_leakage_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_TX_LEAKAGE_THRESHOLD_DEFAULT, + CFG_SAP_TX_LEAKAGE_THRESHOLD_MIN, + CFG_SAP_TX_LEAKAGE_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUG_ON_REINIT_FAILURE_NAME, WLAN_PARAM_Integer, + struct hdd_config, bug_on_reinit_failure, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUG_ON_REINIT_FAILURE_DEFAULT, + CFG_BUG_ON_REINIT_FAILURE_MIN, + CFG_BUG_ON_REINIT_FAILURE_MAX), + + REG_VARIABLE(CFG_SAP_FORCE_11N_FOR_11AC_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_force_11n_for_11ac, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_FORCE_11N_FOR_11AC_DEFAULT, + CFG_SAP_FORCE_11N_FOR_11AC_MIN, + CFG_SAP_FORCE_11N_FOR_11AC_MAX), + + REG_VARIABLE(CFG_GO_FORCE_11N_FOR_11AC_NAME, WLAN_PARAM_Integer, + struct hdd_config, go_force_11n_for_11ac, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_FORCE_11N_FOR_11AC_DEFAULT, + CFG_GO_FORCE_11N_FOR_11AC_MIN, + CFG_GO_FORCE_11N_FOR_11AC_MAX), + + REG_VARIABLE(CFG_INTERFACE_CHANGE_WAIT_NAME, WLAN_PARAM_Integer, + struct hdd_config, iface_change_wait_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_INTERFACE_CHANGE_WAIT_DEFAULT, + CFG_INTERFACE_CHANGE_WAIT_MIN, + CFG_INTERFACE_CHANGE_WAIT_MAX), + + REG_VARIABLE(CFG_FILTER_MULTICAST_REPLAY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, multicast_replay_filter, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FILTER_MULTICAST_REPLAY_DEFAULT, + CFG_FILTER_MULTICAST_REPLAY_MIN, + CFG_FILTER_MULTICAST_REPLAY_MAX), + + REG_VARIABLE(CFG_ENABLE_PHY_REG, WLAN_PARAM_HexInteger, + struct hdd_config, enable_phy_reg_retention, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PHY_REG_DEFAULT, + CFG_PHY_REG_MIN, + CFG_PHY_REG_MAX), + + REG_VARIABLE(CFG_OPTIMIZE_CA_EVENT_NAME, WLAN_PARAM_Integer, + struct hdd_config, goptimize_chan_avoid_event, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPTIMIZE_CA_EVENT_DEFAULT, + CFG_OPTIMIZE_CA_EVENT_DISABLE, + CFG_OPTIMIZE_CA_EVENT_ENABLE), + + REG_VARIABLE(CFG_TX_AGGREGATION_SIZE, WLAN_PARAM_Integer, + struct hdd_config, tx_aggregation_size, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGREGATION_SIZE_DEFAULT, + CFG_TX_AGGREGATION_SIZE_MIN, + CFG_TX_AGGREGATION_SIZE_MAX), + + REG_VARIABLE(CFG_TX_AGGREGATION_SIZEBE, WLAN_PARAM_Integer, + struct hdd_config, tx_aggregation_size_be, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGREGATION_SIZEBE_DEFAULT, + CFG_TX_AGGREGATION_SIZEBE_MIN, + CFG_TX_AGGREGATION_SIZEBE_MAX), + + REG_VARIABLE(CFG_TX_AGGREGATION_SIZEBK, WLAN_PARAM_Integer, + struct hdd_config, tx_aggregation_size_bk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGREGATION_SIZEBK_DEFAULT, + CFG_TX_AGGREGATION_SIZEBK_MIN, + CFG_TX_AGGREGATION_SIZEBK_MAX), + + REG_VARIABLE(CFG_TX_AGGREGATION_SIZEVI, WLAN_PARAM_Integer, + struct hdd_config, tx_aggregation_size_vi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGREGATION_SIZEVI_DEFAULT, + CFG_TX_AGGREGATION_SIZEVI_MIN, + CFG_TX_AGGREGATION_SIZEVI_MAX), + + REG_VARIABLE(CFG_TX_AGGREGATION_SIZEVO, WLAN_PARAM_Integer, + struct hdd_config, tx_aggregation_size_vo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGREGATION_SIZEVO_DEFAULT, + CFG_TX_AGGREGATION_SIZEVO_MIN, + CFG_TX_AGGREGATION_SIZEVO_MAX), + + REG_VARIABLE(CFG_RX_AGGREGATION_SIZE, WLAN_PARAM_Integer, + struct hdd_config, rx_aggregation_size, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_AGGREGATION_SIZE_DEFAULT, + CFG_RX_AGGREGATION_SIZE_MIN, + CFG_RX_AGGREGATION_SIZE_MAX), + + REG_VARIABLE(CFG_TX_AGGR_SW_RETRY_BE, WLAN_PARAM_Integer, + struct hdd_config, tx_aggr_sw_retry_threshold_be, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGR_SW_RETRY_BE_DEFAULT, + CFG_TX_AGGR_SW_RETRY_BE_MIN, + CFG_TX_AGGR_SW_RETRY_BE_MAX), + + REG_VARIABLE(CFG_TX_AGGR_SW_RETRY_BK, WLAN_PARAM_Integer, + struct hdd_config, tx_aggr_sw_retry_threshold_bk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGR_SW_RETRY_BK_DEFAULT, + CFG_TX_AGGR_SW_RETRY_BK_MIN, + CFG_TX_AGGR_SW_RETRY_BK_MAX), + + REG_VARIABLE(CFG_TX_AGGR_SW_RETRY_VI, WLAN_PARAM_Integer, + struct hdd_config, tx_aggr_sw_retry_threshold_vi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGR_SW_RETRY_VI_DEFAULT, + CFG_TX_AGGR_SW_RETRY_VI_MIN, + CFG_TX_AGGR_SW_RETRY_VI_MAX), + + REG_VARIABLE(CFG_TX_AGGR_SW_RETRY_VO, WLAN_PARAM_Integer, + struct hdd_config, tx_aggr_sw_retry_threshold_vo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGR_SW_RETRY_VO_DEFAULT, + CFG_TX_AGGR_SW_RETRY_VO_MIN, + CFG_TX_AGGR_SW_RETRY_VO_MAX), + + REG_VARIABLE(CFG_TX_AGGR_SW_RETRY, WLAN_PARAM_Integer, + struct hdd_config, tx_aggr_sw_retry_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGR_SW_RETRY_DEFAULT, + CFG_TX_AGGR_SW_RETRY_MIN, + CFG_TX_AGGR_SW_RETRY_MAX), + + REG_VARIABLE(CFG_TX_NON_AGGR_SW_RETRY_BE, WLAN_PARAM_Integer, + struct hdd_config, tx_non_aggr_sw_retry_threshold_be, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_BE_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_BE_MIN, + CFG_TX_NON_AGGR_SW_RETRY_BE_MAX), + + REG_VARIABLE(CFG_TX_NON_AGGR_SW_RETRY_BK, WLAN_PARAM_Integer, + struct hdd_config, tx_non_aggr_sw_retry_threshold_bk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_BK_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_BK_MIN, + CFG_TX_NON_AGGR_SW_RETRY_BK_MAX), + + REG_VARIABLE(CFG_TX_NON_AGGR_SW_RETRY_VI, WLAN_PARAM_Integer, + struct hdd_config, tx_non_aggr_sw_retry_threshold_vi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_VI_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_VI_MIN, + CFG_TX_NON_AGGR_SW_RETRY_VI_MAX), + + REG_VARIABLE(CFG_TX_NON_AGGR_SW_RETRY_VO, WLAN_PARAM_Integer, + struct hdd_config, tx_non_aggr_sw_retry_threshold_vo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_VO_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_VO_MIN, + CFG_TX_NON_AGGR_SW_RETRY_VO_MAX), + + REG_VARIABLE(CFG_TX_NON_AGGR_SW_RETRY, WLAN_PARAM_Integer, + struct hdd_config, tx_non_aggr_sw_retry_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_DEFAULT, + CFG_TX_NON_AGGR_SW_RETRY_MIN, + CFG_TX_NON_AGGR_SW_RETRY_MAX), + + REG_VARIABLE(CFG_SAP_MAX_INACTIVITY_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_max_inactivity_override, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_MAX_INACTIVITY_OVERRIDE_DEFAULT, + CFG_SAP_MAX_INACTIVITY_OVERRIDE_MIN, + CFG_SAP_MAX_INACTIVITY_OVERRIDE_MAX), + REG_VARIABLE(CFG_CRASH_FW_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, fw_timeout_crash, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CRASH_FW_TIMEOUT_DEFAULT, + CFG_CRASH_FW_TIMEOUT_DISABLE, + CFG_CRASH_FW_TIMEOUT_ENABLE), + REG_VARIABLE(CFG_RX_WAKELOCK_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, rx_wakelock_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_WAKELOCK_TIMEOUT_DEFAULT, + CFG_RX_WAKELOCK_TIMEOUT_MIN, + CFG_RX_WAKELOCK_TIMEOUT_MAX), + REG_VARIABLE(CFG_SAP_CH_SWITCH_BEACON_CNT, WLAN_PARAM_Integer, + struct hdd_config, sap_chanswitch_beacon_cnt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_CH_SWITCH_BEACON_CNT_DEFAULT, + CFG_SAP_CH_SWITCH_BEACON_CNT_MIN, + CFG_SAP_CH_SWITCH_BEACON_CNT_MAX), + REG_VARIABLE(CFG_SAP_CH_SWITCH_MODE, WLAN_PARAM_Integer, + struct hdd_config, sap_chanswitch_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_CH_SWITCH_MODE_DEFAULT, + CFG_SAP_CH_SWITCH_MODE_MIN, + CFG_SAP_CH_SWITCH_MODE_MAX), + REG_VARIABLE(CFG_MAX_SCHED_SCAN_PLAN_INT_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_sched_scan_plan_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_INT_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_INT_MIN, + CFG_MAX_SCHED_SCAN_PLAN_INT_MAX), + REG_VARIABLE(CFG_MAX_SCHED_SCAN_PLAN_ITRNS_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_sched_scan_plan_iterations, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_ITRNS_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MIN, + CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MAX), + + REG_VARIABLE(CFG_PRIVATE_WEXT_CONTROL_NAME, WLAN_PARAM_Integer, + struct hdd_config, private_wext_control, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRIVATE_WEXT_CONTROL_DEFAULT, + CFG_PRIVATE_WEXT_CONTROL_MIN, + CFG_PRIVATE_WEXT_CONTROL_MAX), + + REG_VARIABLE(CFG_SAP_INTERNAL_RESTART_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_internal_restart, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_INTERNAL_RESTART_DEFAULT, + CFG_SAP_INTERNAL_RESTART_MIN, + CFG_SAP_INTERNAL_RESTART_MAX), + + REG_VARIABLE(CFG_RESTART_BEACONING_ON_CH_AVOID_NAME, WLAN_PARAM_Integer, + struct hdd_config, restart_beaconing_on_chan_avoid_event, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RESTART_BEACONING_ON_CH_AVOID_DEFAULT, + CFG_RESTART_BEACONING_ON_CH_AVOID_MIN, + CFG_RESTART_BEACONING_ON_CH_AVOID_MAX), + + REG_VARIABLE(CFG_PER_ROAM_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_per_roam_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_ENABLE_DEFAULT, + CFG_PER_ROAM_ENABLE_MIN, + CFG_PER_ROAM_ENABLE_MAX), + + REG_VARIABLE(CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_NAME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_high_rate_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_DEFAULT, + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MIN, + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MAX), + + REG_VARIABLE(CFG_PER_ROAM_CONFIG_LOW_RATE_TH_NAME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_low_rate_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_DEFAULT, + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MIN, + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MAX), + + REG_VARIABLE(CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_NAME, + WLAN_PARAM_Integer, struct hdd_config, per_roam_th_percent, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_DEFAULT, + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MIN, + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MAX), + + REG_VARIABLE(CFG_PER_ROAM_REST_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_rest_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_REST_TIME_DEFAULT, + CFG_PER_ROAM_REST_TIME_MIN, + CFG_PER_ROAM_REST_TIME_MAX), + + REG_VARIABLE(CFG_PER_ROAM_MONITOR_TIME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_mon_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_MONTIOR_TIME_DEFAULT, + CFG_PER_ROAM_MONITOR_TIME_MIN, + CFG_PER_ROAM_MONITOR_TIME_MAX), + + REG_VARIABLE(CFG_PER_ROAM_MIN_CANDIDATE_RSSI, WLAN_PARAM_Integer, + struct hdd_config, min_candidate_rssi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_MIN_CANDIDATE_RSSI_DEFAULT, + CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MIN, + CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MAX), + + REG_VARIABLE(CFG_ACTIVE_UC_APF_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, active_uc_apf_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_UC_APF_MODE_DEFAULT, + CFG_ACTIVE_UC_APF_MODE_MIN, + CFG_ACTIVE_UC_APF_MODE_MAX), + + REG_VARIABLE(CFG_ACTIVE_MC_BC_APF_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, active_mc_bc_apf_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MC_BC_APF_MODE_DEFAULT, + CFG_ACTIVE_MC_BC_APF_MODE_MIN, + CFG_ACTIVE_MC_BC_APF_MODE_MAX), + + REG_VARIABLE(CFG_ENABLE_BCAST_PROBE_RESP_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_bcast_probe_rsp, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BCAST_PROBE_RESP_DEFAULT, + CFG_ENABLE_BCAST_PROBE_RESP_MIN, + CFG_ENABLE_BCAST_PROBE_RESP_MAX), + +#ifdef WLAN_FEATURE_11AX + REG_VARIABLE(CFG_ENABLE_UL_MIMO_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_ul_mimo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_UL_MIMO_DEFAULT, + CFG_ENABLE_UL_MIMO_MIN, + CFG_ENABLE_UL_MIMO_MAX), + + REG_VARIABLE(CFG_HE_DYNAMIC_FRAGMENTATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, he_dynamic_frag_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HE_DYNAMIC_FRAGMENTATION_DEFAULT, + CFG_HE_DYNAMIC_FRAGMENTATION_MIN, + CFG_HE_DYNAMIC_FRAGMENTATION_MAX), + + REG_VARIABLE(CFG_ENABLE_UL_OFDMA_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_ul_ofdma, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_UL_OFDMA_DEFAULT, + CFG_ENABLE_UL_OFDMA_MIN, + CFG_ENABLE_UL_OFDMA_MAX), + + REG_VARIABLE(CFG_HE_STA_OBSSPD_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, he_sta_obsspd, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HE_STA_OBSSPD_DEFAULT, + CFG_HE_STA_OBSSPD_MIN, + CFG_HE_STA_OBSSPD_MAX), +#endif +#ifdef WLAN_SUPPORT_TWT + REG_VARIABLE(CFG_ENABLE_TWT_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_twt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TWT_DEFAULT, + CFG_ENABLE_TWT_MIN, + CFG_ENABLE_TWT_MAX), + + REG_VARIABLE(CFG_TWT_CONGESTION_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, twt_congestion_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TWT_CONGESTION_TIMEOUT_DEFAULT, + CFG_TWT_CONGESTION_TIMEOUT_MIN, + CFG_TWT_CONGESTION_TIMEOUT_MAX), +#endif + + REG_VARIABLE(CFG_ARP_AC_CATEGORY, WLAN_PARAM_Integer, + struct hdd_config, arp_ac_category, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ARP_AC_CATEGORY_DEFAULT, + CFG_ARP_AC_CATEGORY_MIN, + CFG_ARP_AC_CATEGORY_MAX), + + REG_VARIABLE(CFG_ENABLE_ANI_NAME, WLAN_PARAM_Integer, + struct hdd_config, ani_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_ANI_DEFAULT, + CFG_ENABLE_ANI_MIN, + CFG_ENABLE_ANI_MAX), + + REG_VARIABLE(CFG_QCN_IE_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, qcn_ie_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QCN_IE_SUPPORT_DEFAULT, + CFG_QCN_IE_SUPPORT_MIN, + CFG_QCN_IE_SUPPORT_MAX), + + REG_VARIABLE(CFG_TIMER_MULTIPLIER_NAME, WLAN_PARAM_Integer, + struct hdd_config, timer_multiplier, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TIMER_MULTIPLIER_DEFAULT, + CFG_TIMER_MULTIPLIER_MIN, + CFG_TIMER_MULTIPLIER_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_WHITELIST_NAME, WLAN_PARAM_Integer, + struct hdd_config, probe_req_ie_whitelist, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_WHITELIST_DEFAULT, + CFG_PRB_REQ_IE_WHITELIST_MIN, + CFG_PRB_REQ_IE_WHITELIST_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP0_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP0_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP0_MIN, + CFG_PRB_REQ_IE_BIT_MAP0_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP1_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP1_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP1_MIN, + CFG_PRB_REQ_IE_BIT_MAP1_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP2_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP2_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP2_MIN, + CFG_PRB_REQ_IE_BIT_MAP2_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP3_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP3_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP3_MIN, + CFG_PRB_REQ_IE_BIT_MAP3_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP4_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_4, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP4_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP4_MIN, + CFG_PRB_REQ_IE_BIT_MAP4_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP5_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_5, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP5_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP5_MIN, + CFG_PRB_REQ_IE_BIT_MAP5_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP6_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_6, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP6_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP6_MIN, + CFG_PRB_REQ_IE_BIT_MAP6_MAX), + + REG_VARIABLE(CFG_PRB_REQ_IE_BIT_MAP7_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, probe_req_ie_bitmap_7, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP7_DEFAULT, + CFG_PRB_REQ_IE_BIT_MAP7_MIN, + CFG_PRB_REQ_IE_BIT_MAP7_MAX), + + REG_VARIABLE_STRING(CFG_PROBE_REQ_OUI_NAME, WLAN_PARAM_String, + struct hdd_config, probe_req_ouis, + VAR_FLAGS_OPTIONAL, + (void *)CFG_PROBE_REQ_OUI_DEFAULT), + + REG_VARIABLE(CFG_FILS_MAX_CHAN_GUARD_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, fils_max_chan_guard_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FILS_MAX_CHAN_GUARD_TIME_DEFAULT, + CFG_FILS_MAX_CHAN_GUARD_TIME_MIN, + CFG_FILS_MAX_CHAN_GUARD_TIME_MAX), + + REG_VARIABLE(CFG_SCAN_BACKOFF_MULTIPLIER_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_backoff_multiplier, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SCAN_BACKOFF_MULTIPLIER_DEFAULT, + CFG_SCAN_BACKOFF_MULTIPLIER_MIN, + CFG_SCAN_BACKOFF_MULTIPLIER_MAX), + + REG_VARIABLE(CFG_MAWC_NLO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_nlo_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_NLO_ENABLED_DEFAULT, + CFG_MAWC_NLO_ENABLED_MIN, + CFG_MAWC_NLO_ENABLED_MAX), + + REG_VARIABLE(CFG_MAWC_NLO_EXP_BACKOFF_RATIO_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_nlo_exp_backoff_ratio, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_NLO_EXP_BACKOFF_RATIO_DEFAULT, + CFG_MAWC_NLO_EXP_BACKOFF_RATIO_MIN, + CFG_MAWC_NLO_EXP_BACKOFF_RATIO_MAX), + + REG_VARIABLE(CFG_MAWC_NLO_INIT_SCAN_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_nlo_init_scan_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_NLO_INIT_SCAN_INTERVAL_DEFAULT, + CFG_MAWC_NLO_INIT_SCAN_INTERVAL_MIN, + CFG_MAWC_NLO_INIT_SCAN_INTERVAL_MAX), + + REG_VARIABLE(CFG_MAWC_NLO_MAX_SCAN_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, mawc_nlo_max_scan_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAWC_NLO_MAX_SCAN_INTERVAL_DEFAULT, + CFG_MAWC_NLO_MAX_SCAN_INTERVAL_MIN, + CFG_MAWC_NLO_MAX_SCAN_INTERVAL_MAX), + + + REG_VARIABLE(CFG_EXTERNAL_ACS_POLICY, WLAN_PARAM_Integer, + struct hdd_config, external_acs_policy, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTERNAL_ACS_POLICY_DEFAULT, + CFG_EXTERNAL_ACS_POLICY_MIN, + CFG_EXTERNAL_ACS_POLICY_MAX), + + REG_VARIABLE(CFG_DROPPED_PKT_DISCONNECT_TH_NAME, WLAN_PARAM_Integer, + struct hdd_config, pkt_err_disconn_th, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DROPPED_PKT_DISCONNECT_TH_DEFAULT, + CFG_DROPPED_PKT_DISCONNECT_TH_MIN, + CFG_DROPPED_PKT_DISCONNECT_TH_MAX), + + REG_VARIABLE(CFG_FORCE_1X1_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_force_1x1_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_1X1_DEFAULT, + CFG_FORCE_1X1_MIN, + CFG_FORCE_1X1_MAX), + + REG_VARIABLE(CFG_SET_RTS_FOR_SIFS_BURSTING, WLAN_PARAM_Integer, + struct hdd_config, enable_rts_sifsbursting, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_RTS_FOR_SIFS_BURSTING_DEFAULT, + CFG_SET_RTS_FOR_SIFS_BURSTING_MIN, + CFG_SET_RTS_FOR_SIFS_BURSTING_MAX), + + REG_VARIABLE(CFG_MAX_MPDUS_IN_AMPDU, WLAN_PARAM_Integer, + struct hdd_config, max_mpdus_inampdu, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_MPDUS_IN_AMPDU_DEFAULT, + CFG_MAX_MPDUS_IN_AMPDU_MIN, + CFG_MAX_MPDUS_IN_AMPDU_MAX), + + REG_VARIABLE(CFG_SAP_MAX_MCS_FOR_TX_DATA, WLAN_PARAM_Integer, + struct hdd_config, sap_max_mcs_txdata, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_MAX_MCS_FOR_TX_DATA_DEFAULT, + CFG_SAP_MAX_MCS_FOR_TX_DATA_MIN, + CFG_SAP_MAX_MCS_FOR_TX_DATA_MAX), + + REG_VARIABLE(CFG_TX_ORPHAN_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, tx_orphan_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_ORPHAN_ENABLE_DEFAULT, + CFG_TX_ORPHAN_ENABLE_MIN, + CFG_TX_ORPHAN_ENABLE_MAX), + + REG_VARIABLE(CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, auto_pwr_save_fail_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AUTO_DETECT_POWER_FAIL_MODE_DEFAULT, + CFG_AUTO_DETECT_POWER_FAIL_MODE_MIN, + CFG_AUTO_DETECT_POWER_FAIL_MODE_MAX), + + REG_VARIABLE(CFG_11B_NUM_TX_CHAIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, num_11b_tx_chains, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_11B_NUM_TX_CHAIN_DEFAULT, + CFG_11B_NUM_TX_CHAIN_MIN, + CFG_11B_NUM_TX_CHAIN_MAX), + + REG_VARIABLE(CFG_11AG_NUM_TX_CHAIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, num_11ag_tx_chains, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_11AG_NUM_TX_CHAIN_DEFAULT, + CFG_11AG_NUM_TX_CHAIN_MIN, + CFG_11AG_NUM_TX_CHAIN_MAX), + + REG_VARIABLE(CFG_ITO_REPEAT_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, ito_repeat_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ITO_REPEAT_COUNT_DEFAULT, + CFG_ITO_REPEAT_COUNT_MIN, + CFG_ITO_REPEAT_COUNT_MAX), + + REG_VARIABLE(CFG_ROAM_DISALLOW_DURATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, disallow_duration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_DISALLOW_DURATION_DEFAULT, + CFG_ROAM_DISALLOW_DURATION_MIN, + CFG_ROAM_DISALLOW_DURATION_MAX), + + REG_VARIABLE(CFG_ROAM_RSSI_CHANNEL_PENALIZATION_NAME, + WLAN_PARAM_Integer, struct hdd_config, + rssi_channel_penalization, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RSSI_CHANNEL_PENALIZATION_DEFAULT, + CFG_ROAM_RSSI_CHANNEL_PENALIZATION_MIN, + CFG_ROAM_RSSI_CHANNEL_PENALIZATION_MAX), + + REG_VARIABLE(CFG_ROAM_NUM_DISALLOWED_APS_NAME, WLAN_PARAM_Integer, + struct hdd_config, num_disallowed_aps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_NUM_DISALLOWED_APS_DEFAULT, + CFG_ROAM_NUM_DISALLOWED_APS_MIN, + CFG_ROAM_NUM_DISALLOWED_APS_MAX), + + REG_VARIABLE(CFG_OCE_ENABLE_STA_NAME, WLAN_PARAM_Integer, + struct hdd_config, oce_sta_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_ENABLE_STA_DEFAULT, + CFG_OCE_ENABLE_STA_MIN, + CFG_OCE_ENABLE_STA_MAX), + + REG_VARIABLE(CFG_OCE_ENABLE_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, oce_sap_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_ENABLE_SAP_DEFAULT, + CFG_OCE_ENABLE_SAP_MIN, + CFG_OCE_ENABLE_SAP_MAX), + + REG_VARIABLE(CFG_ENABLE_11D_IN_WORLD_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_11d_in_world_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_11D_IN_WORLD_MODE_DEFAULT, + CFG_ENABLE_11D_IN_WORLD_MODE_MIN, + CFG_ENABLE_11D_IN_WORLD_MODE_MAX), + + REG_VARIABLE(CFG_ENABLE_5G_BAND_PREF_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_5g_band_pref, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_5G_BAND_PREF_DEFAULT, + CFG_ENABLE_5G_BAND_PREF_MIN, + CFG_ENABLE_5G_BAND_PREF_MAX), + + REG_VARIABLE(CFG_5G_RSSI_BOOST_THRESHOLD_NAME, WLAN_PARAM_SignedInteger, + struct hdd_config, rssi_boost_threshold_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_BOOST_THRESHOLD_DEFAULT, + CFG_5G_RSSI_BOOST_THRESHOLD_MIN, + CFG_5G_RSSI_BOOST_THRESHOLD_MAX), + + REG_VARIABLE(CFG_5G_RSSI_BOOST_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_boost_factor_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_BOOST_FACTOR_DEFAULT, + CFG_5G_RSSI_BOOST_FACTOR_MIN, + CFG_5G_RSSI_BOOST_FACTOR_MAX), + + REG_VARIABLE(CFG_5G_MAX_RSSI_BOOST_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_rssi_boost_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_MAX_RSSI_BOOST_DEFAULT, + CFG_5G_MAX_RSSI_BOOST_MIN, + CFG_5G_MAX_RSSI_BOOST_MAX), + + REG_VARIABLE(CFG_5G_RSSI_PENALIZE_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, rssi_penalize_threshold_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_PENALIZE_THRESHOLD_DEFAULT, + CFG_5G_RSSI_PENALIZE_THRESHOLD_MIN, + CFG_5G_RSSI_PENALIZE_THRESHOLD_MAX), + + REG_VARIABLE(CFG_5G_RSSI_PENALIZE_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_penalize_factor_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_PENALIZE_FACTOR_DEFAULT, + CFG_5G_RSSI_PENALIZE_FACTOR_MIN, + CFG_5G_RSSI_PENALIZE_FACTOR_MAX), + + REG_VARIABLE(CFG_5G_MAX_RSSI_PENALIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_rssi_penalize_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_MAX_RSSI_PENALIZE_DEFAULT, + CFG_5G_MAX_RSSI_PENALIZE_MIN, + CFG_5G_MAX_RSSI_PENALIZE_MAX), + + REG_VARIABLE(CFG_LPRx_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_lprx, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LPRx_DEFAULT, + CFG_LPRx_MIN, + CFG_LPRx_MAX), + + REG_VARIABLE(CFG_UPPER_BRSSI_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, upper_brssi_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_UPPER_BRSSI_THRESH_DEFAULT, + CFG_UPPER_BRSSI_THRESH_MIN, + CFG_UPPER_BRSSI_THRESH_MAX), + + REG_VARIABLE(CFG_LOWER_BRSSI_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, lower_brssi_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LOWER_BRSSI_THRESH_DEFAULT, + CFG_LOWER_BRSSI_THRESH_MIN, + CFG_LOWER_BRSSI_THRESH_MAX), + + REG_VARIABLE(CFG_ENABLE_ACTION_OUI, WLAN_PARAM_Integer, + struct hdd_config, action_oui_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_ACTION_OUI_DEFAULT, + CFG_ENABLE_ACTION_OUI_MIN, + CFG_ENABLE_ACTION_OUI_MAX), + + REG_VARIABLE_STRING(CFG_ACTION_OUI_CONNECT_1X1_NAME, WLAN_PARAM_String, + struct hdd_config, action_oui_str[0], + VAR_FLAGS_OPTIONAL, + (void *)CFG_ACTION_OUI_CONNECT_1X1_DEFAULT), + + REG_VARIABLE_STRING(CFG_ACTION_OUI_ITO_EXTENSION_NAME, + WLAN_PARAM_String, + struct hdd_config, action_oui_str[1], + VAR_FLAGS_OPTIONAL, + (void *)CFG_ACTION_OUI_ITO_EXTENSION_DEFAULT), + + REG_VARIABLE_STRING(CFG_ACTION_OUI_CCKM_1X1_NAME, WLAN_PARAM_String, + struct hdd_config, action_oui_str[2], + VAR_FLAGS_OPTIONAL, + (void *)CFG_ACTION_OUI_CCKM_1X1_DEFAULT), + + REG_VARIABLE_STRING(CFG_ACTION_OUI_ITO_ALTERNATE_NAME, + WLAN_PARAM_String, + struct hdd_config, action_oui_str[3], + VAR_FLAGS_OPTIONAL, + (void *)CFG_ACTION_OUI_ITO_ALTERNATE_DEFAULT), + REG_VARIABLE_STRING(CFG_ACTION_OUI_SWITCH_TO_11N_MODE_NAME, + WLAN_PARAM_String, + struct hdd_config, action_oui_str[4], + VAR_FLAGS_OPTIONAL, + (void *)CFG_ACTION_OUI_SWITCH_TO_11N_MODE_DEFAULT), + + REG_VARIABLE_STRING(CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN_NAME, + WLAN_PARAM_String, + struct hdd_config, action_oui_str[5], + VAR_FLAGS_OPTIONAL, + (void *) + CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN_DEFAULT), + + REG_VARIABLE_STRING(CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX_NAME, + WLAN_PARAM_String, + struct hdd_config, action_oui_str[6], + VAR_FLAGS_OPTIONAL, + (void *) + CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX_DEFAULT), + + REG_VARIABLE(CFG_DTIM_1CHRX_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_dtim_1chrx, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DTIM_1CHRX_ENABLE_DEFAULT, + CFG_DTIM_1CHRX_ENABLE_MIN, + CFG_DTIM_1CHRX_ENABLE_MAX), + + REG_VARIABLE(CFG_RANDOMIZE_NDI_MAC_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_ndi_mac_randomized, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RANDOMIZE_NDI_MAC_DEFAULT, + CFG_RANDOMIZE_NDI_MAC_MIN, + CFG_RANDOMIZE_NDI_MAC_MAX), + + REG_VARIABLE(CFG_SCAN_11D_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_11d_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SCAN_11D_INTERVAL_DEFAULT, + CFG_SCAN_11D_INTERVAL_MIN, + CFG_SCAN_11D_INTERVAL_MAX), + + REG_VARIABLE(CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, chan_switch_hostapd_rate_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_DEFAULT, + CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_MIN, + CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_MAX), + + REG_VARIABLE(CFG_IS_BSSID_HINT_PRIORITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_bssid_hint_priority, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IS_BSSID_HINT_PRIORITY_DEFAULT, + CFG_IS_BSSID_HINT_PRIORITY_MIN, + CFG_IS_BSSID_HINT_PRIORITY_MAX), + + REG_VARIABLE(CFG_LATENCY_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, wlm_latency_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LATENCY_ENABLE_DEFAULT, + CFG_LATENCY_ENABLE_MIN, + CFG_LATENCY_ENABLE_MAX), + + REG_VARIABLE(CFG_LATENCY_LEVEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, wlm_latency_level, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LATENCY_LEVEL_DEFAULT, + CFG_LATENCY_LEVEL_MIN, + CFG_LATENCY_LEVEL_MAX), + + REG_VARIABLE(CFG_LATENCY_FLAGS_NORMAL_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, wlm_latency_flags_normal, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LATENCY_FLAGS_NORMAL_DEFAULT, + CFG_LATENCY_FLAGS_NORMAL_MIN, + CFG_LATENCY_FLAGS_NORMAL_MAX), + + REG_VARIABLE(CFG_LATENCY_FLAGS_MODERATE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, wlm_latency_flags_moderate, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LATENCY_FLAGS_MODERATE_DEFAULT, + CFG_LATENCY_FLAGS_MODERATE_MIN, + CFG_LATENCY_FLAGS_MODERATE_MAX), + + REG_VARIABLE(CFG_LATENCY_FLAGS_LOW_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, wlm_latency_flags_low, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LATENCY_FLAGS_LOW_DEFAULT, + CFG_LATENCY_FLAGS_LOW_MIN, + CFG_LATENCY_FLAGS_LOW_MAX), + + REG_VARIABLE(CFG_LATENCY_FLAGS_ULTRALOW_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, wlm_latency_flags_ultralow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LATENCY_FLAGS_ULTRALOW_DEFAULT, + CFG_LATENCY_FLAGS_ULTRALOW_MIN, + CFG_LATENCY_FLAGS_ULTRALOW_MAX), + + REG_VARIABLE(CFG_RSSI_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RSSI_WEIGHTAGE_DEFAULT, + CFG_RSSI_WEIGHTAGE_MIN, + CFG_RSSI_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_HT_CAPABILITY_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ht_caps_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HT_CAPABILITY_WEIGHTAGE_DEFAULT, + CFG_HT_CAPABILITY_WEIGHTAGE_MIN, + CFG_HT_CAPABILITY_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_VHT_CAPABILITY_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, vht_caps_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_CAPABILITY_WEIGHTAGE_DEFAULT, + CFG_VHT_CAPABILITY_WEIGHTAGE_MIN, + CFG_VHT_CAPABILITY_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_HE_CAPABILITY_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, he_caps_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HE_CAPABILITY_WEIGHTAGE_DEFAULT, + CFG_HE_CAPABILITY_WEIGHTAGE_MIN, + CFG_HE_CAPABILITY_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_CHAN_WIDTH_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, chan_width_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CHAN_WIDTH_WEIGHTAGE_DEFAULT, + CFG_CHAN_WIDTH_WEIGHTAGE_MIN, + CFG_CHAN_WIDTH_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_CHAN_BAND_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, chan_band_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CHAN_BAND_WEIGHTAGE_DEFAULT, + CFG_CHAN_BAND_WEIGHTAGE_MIN, + CFG_CHAN_BAND_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_NSS_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, nss_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NSS_WEIGHTAGE_DEFAULT, + CFG_NSS_WEIGHTAGE_MIN, + CFG_NSS_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_BEAMFORMING_CAP_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, beamforming_cap_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BEAMFORMING_CAP_WEIGHTAGE_DEFAULT, + CFG_BEAMFORMING_CAP_WEIGHTAGE_MIN, + CFG_BEAMFORMING_CAP_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_PCL_WEIGHT_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, pcl_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PCL_WEIGHT_DEFAULT, + CFG_PCL_WEIGHT_MIN, + CFG_PCL_WEIGHT_MAX), + + REG_VARIABLE(CFG_CHANNEL_CONGESTION_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, channel_congestion_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CHANNEL_CONGESTION_WEIGHTAGE_DEFAULT, + CFG_CHANNEL_CONGESTION_WEIGHTAGE_MIN, + CFG_CHANNEL_CONGESTION_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_OCE_WAN_WEIGHTAGE_NAME, WLAN_PARAM_Integer, + struct hdd_config, oce_wan_weightage, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_WAN_WEIGHTAGE_DEFAULT, + CFG_OCE_WAN_WEIGHTAGE_MIN, + CFG_OCE_WAN_WEIGHTAGE_MAX), + + REG_VARIABLE(CFG_BEST_RSSI_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, best_rssi_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BEST_RSSI_THRESHOLD_DEFAULT, + CFG_BEST_RSSI_THRESHOLD_MIN, + CFG_BEST_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_GOOD_RSSI_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, good_rssi_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GOOD_RSSI_THRESHOLD_DEFAULT, + CFG_GOOD_RSSI_THRESHOLD_MIN, + CFG_GOOD_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BAD_RSSI_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, bad_rssi_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAD_RSSI_THRESHOLD_DEFAULT, + CFG_BAD_RSSI_THRESHOLD_MIN, + CFG_BAD_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_GOOD_RSSI_PCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, good_rssi_pcnt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GOOD_RSSI_PCNT_DEFAULT, + CFG_GOOD_RSSI_PCNT_MIN, + CFG_GOOD_RSSI_PCNT_MAX), + + REG_VARIABLE(CFG_BAD_RSSI_PCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, bad_rssi_pcnt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAD_RSSI_PCNT_DEFAULT, + CFG_BAD_RSSI_PCNT_MIN, + CFG_BAD_RSSI_PCNT_MAX), + + REG_VARIABLE(CFG_GOOD_RSSI_BUCKET_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, good_rssi_bucket_size, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GOOD_RSSI_BUCKET_SIZE_DEFAULT, + CFG_GOOD_RSSI_BUCKET_SIZE_MIN, + CFG_GOOD_RSSI_BUCKET_SIZE_MAX), + + REG_VARIABLE(CFG_BAD_RSSI_BUCKET_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, bad_rssi_bucket_size, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAD_RSSI_BUCKET_SIZE_DEFAULT, + CFG_BAD_RSSI_BUCKET_SIZE_MIN, + CFG_BAD_RSSI_BUCKET_SIZE_MAX), + + REG_VARIABLE(CFG_RSSI_PERF_5G_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_pref_5g_rssi_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RSSI_PERF_5G_THRESHOLD_DEFAULT, + CFG_RSSI_PERF_5G_THRESHOLD_MIN, + CFG_RSSI_PERF_5G_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BAND_WIDTH_WEIGHT_PER_INDEX_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, bandwidth_weight_per_index, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAND_WIDTH_WEIGHT_PER_INDEX_DEFAULT, + CFG_BAND_WIDTH_WEIGHT_PER_INDEX_MIN, + CFG_BAND_WIDTH_WEIGHT_PER_INDEX_MAX), + + REG_VARIABLE(CFG_NSS_WEIGHT_PER_INDEX_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, nss_weight_per_index, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NSS_WEIGHT_PER_INDEX_DEFAULT, + CFG_NSS_WEIGHT_PER_INDEX_MIN, + CFG_NSS_WEIGHT_PER_INDEX_MAX), + + REG_VARIABLE(CFG_BAND_WEIGHT_PER_INDEX_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, band_weight_per_index, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAND_WEIGHT_PER_INDEX_DEFAULT, + CFG_BAND_WEIGHT_PER_INDEX_MIN, + CFG_BAND_WEIGHT_PER_INDEX_MAX), + + REG_VARIABLE(CFG_ESP_QBSS_SLOTS_NAME, WLAN_PARAM_Integer, + struct hdd_config, num_esp_qbss_slots, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESP_QBSS_SLOTS_DEFAULT, + CFG_ESP_QBSS_SLOTS_MIN, + CFG_ESP_QBSS_SLOTS_MAX), + + REG_VARIABLE(CFG_ESP_QBSS_SCORE_IDX3_TO_0_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, esp_qbss_score_slots3_to_0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX3_TO_0_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX3_TO_0_MIN, + CFG_ESP_QBSS_SCORE_IDX3_TO_0_MAX), + + REG_VARIABLE(CFG_ESP_QBSS_SCORE_IDX7_TO_4_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, esp_qbss_score_slots7_to_4, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX7_TO_4_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX7_TO_4_MIN, + CFG_ESP_QBSS_SCORE_IDX7_TO_4_MAX), + + REG_VARIABLE(CFG_ESP_QBSS_SCORE_IDX11_TO_8_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, esp_qbss_score_slots11_to_8, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX11_TO_8_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX11_TO_8_MIN, + CFG_ESP_QBSS_SCORE_IDX11_TO_8_MAX), + + REG_VARIABLE(CFG_ESP_QBSS_SCORE_IDX15_TO_12_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, esp_qbss_score_slots15_to_12, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX15_TO_12_DEFAULT, + CFG_ESP_QBSS_SCORE_IDX15_TO_12_MIN, + CFG_ESP_QBSS_SCORE_IDX15_TO_12_MAX), + + REG_VARIABLE(CFG_OCE_WAN_SLOTS_NAME, WLAN_PARAM_Integer, + struct hdd_config, num_oce_wan_slots, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_WAN_SLOTS_DEFAULT, + CFG_OCE_WAN_SLOTS_MIN, + CFG_OCE_WAN_SLOTS_MAX), + + REG_VARIABLE(CFG_OCE_WAN_SCORE_IDX3_TO_0_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, oce_wan_score_slots3_to_0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_WAN_SCORE_IDX3_TO_0_DEFAULT, + CFG_OCE_WAN_SCORE_IDX3_TO_0_MIN, + CFG_OCE_WAN_SCORE_IDX3_TO_0_MAX), + + REG_VARIABLE(CFG_OCE_WAN_SCORE_IDX7_TO_4_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, oce_wan_score_slots7_to_4, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_WAN_SCORE_IDX7_TO_4_DEFAULT, + CFG_OCE_WAN_SCORE_IDX7_TO_4_MIN, + CFG_OCE_WAN_SCORE_IDX7_TO_4_MAX), + + REG_VARIABLE(CFG_OCE_WAN_SCORE_IDX11_TO_8_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, oce_wan_score_slots11_to_8, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_WAN_SCORE_IDX11_TO_8_DEFAULT, + CFG_OCE_WAN_SCORE_IDX11_TO_8_MIN, + CFG_OCE_WAN_SCORE_IDX11_TO_8_MAX), + + REG_VARIABLE(CFG_OCE_WAN_SCORE_IDX15_TO_12_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, oce_wan_score_slots15_to_12, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_WAN_SCORE_IDX15_TO_12_DEFAULT, + CFG_OCE_WAN_SCORE_IDX15_TO_12_MIN, + CFG_OCE_WAN_SCORE_IDX15_TO_12_MAX), + + REG_VARIABLE(CFG_ENABLE_SCORING_FOR_ROAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_scoring_for_roam, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SCORING_FOR_ROAM_DEFAULT, + CFG_ENABLE_SCORING_FOR_ROAM_MIN, + CFG_ENABLE_SCORING_FOR_ROAM_MAX), + + REG_VARIABLE(CFG_FORCE_RSNE_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, force_rsne_override, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_RSNE_OVERRIDE_DEFAULT, + CFG_FORCE_RSNE_OVERRIDE_MIN, + CFG_FORCE_RSNE_OVERRIDE_MAX), + + REG_VARIABLE(CFG_MBO_CANDIDATE_RSSI_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, struct hdd_config, + mbo_candidate_rssi_thres, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CANDIDATE_RSSI_THRESHOLD_DEFAULT, + CFG_CANDIDATE_RSSI_THRESHOLD_MIN, + CFG_CANDIDATE_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_MBO_CURRENT_RSSI_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, struct hdd_config, + mbo_current_rssi_thres, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CURRENT_RSSI_THRESHOLD_DEFAULT, + CFG_CURRENT_RSSI_THRESHOLD_MIN, + CFG_CURRENT_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_MBO_CUR_RSSI_MCC_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, struct hdd_config, + mbo_current_rssi_mcc_thres, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MBO_CUR_RSSI_MCC_THRESHOLD_DEFAULT, + CFG_MBO_CUR_RSSI_MCC_THRESHOLD_MIN, + CFG_MBO_CUR_RSSI_MCC_THRESHOLD_MAX), + + REG_VARIABLE(CFG_MBO_CAND_RSSI_BTC_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, struct hdd_config, + mbo_candidate_rssi_btc_thres, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MBO_CAND_RSSI_BTC_THRESHOLD_DEFAULT, + CFG_MBO_CAND_RSSI_BTC_THRESHOLD_MIN, + CFG_MBO_CAND_RSSI_BTC_THRESHOLD_MAX), + REG_VARIABLE(CFG_IS_FILS_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_fils_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IS_FILS_ENABLED_DEFAULT, + CFG_IS_FILS_ENABLED_MIN, + CFG_IS_FILS_ENABLED_MAX), + + REG_VARIABLE(CFG_ENABLE_PACKET_FILTERS_NAME, WLAN_PARAM_Integer, + struct hdd_config, packet_filters_bitmap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PACKET_FILTERS_DEFAULT, + CFG_ENABLE_PACKET_FILTERS_MIN, + CFG_ENABLE_PACKET_FILTERS_MAX), + + REG_VARIABLE(CFG_DFS_BEACON_TX_ENHANCED, WLAN_PARAM_Integer, + struct hdd_config, dfs_beacon_tx_enhanced, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DFS_BEACON_TX_ENHANCED_DEFAULT, + CFG_DFS_BEACON_TX_ENHANCED_MIN, + CFG_DFS_BEACON_TX_ENHANCED_MAX), + + REG_VARIABLE(CFG_REDUCED_BEACON_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, reduced_beacon_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REDUCED_BEACON_INTERVAL_DEFAULT, + CFG_REDUCED_BEACON_INTERVAL_MIN, + CFG_REDUCED_BEACON_INTERVAL_MAX), + + REG_VARIABLE(CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT_NAME, + WLAN_PARAM_Integer, struct hdd_config, + rssi_assoc_reject_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT_DEFAULT, + CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT_MIN, + CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT_MAX), + + REG_VARIABLE(CFG_OCE_PROBE_REQ_RATE_NAME, WLAN_PARAM_Integer, + struct hdd_config, oce_probe_req_rate_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_PROBE_REQ_RATE_DEFAULT, + CFG_OCE_PROBE_REQ_RATE_MIN, + CFG_OCE_PROBE_REQ_RATE_MAX), + + REG_VARIABLE(CFG_OCE_PROBE_RSP_RATE_NAME, WLAN_PARAM_Integer, + struct hdd_config, oce_probe_resp_rate_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_PROBE_RSP_RATE_DEFAULT, + CFG_OCE_PROBE_RSP_RATE_MIN, + CFG_OCE_PROBE_RSP_RATE_MAX), + + REG_VARIABLE(CFG_OCE_BEACON_RATE_NAME, WLAN_PARAM_Integer, + struct hdd_config, oce_beacon_rate_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OCE_BEACON_RATE_DEFAULT, + CFG_OCE_BEACON_RATE_MIN, + CFG_OCE_BEACON_RATE_MAX), + + REG_VARIABLE(CFG_ENABLE_PROBE_REQ_DEFERRAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, probe_req_deferral_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PROBE_REQ_DEFERRAL_DEFAULT, + CFG_ENABLE_PROBE_REQ_DEFERRAL_MIN, + CFG_ENABLE_PROBE_REQ_DEFERRAL_MAX), + + REG_VARIABLE(CFG_ENABLE_FILS_DISCOVERY_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, fils_discovery_sap_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FILS_DISCOVERY_SAP_DEFAULT, + CFG_ENABLE_FILS_DISCOVERY_SAP_MIN, + CFG_ENABLE_FILS_DISCOVERY_SAP_MAX), + + REG_VARIABLE(CFG_ENABLE_ESP_FEATURE_NAME, WLAN_PARAM_Integer, + struct hdd_config, esp_for_roam_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_ESP_FEATURE_DEFAULT, + CFG_ENABLE_ESP_FEATURE_MIN, + CFG_ENABLE_ESP_FEATURE_MAX), + + REG_VARIABLE(CFG_TX_CHAIN_MASK_2G_NAME, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_2G_DEFAULT, + CFG_TX_CHAIN_MASK_2G_MIN, + CFG_TX_CHAIN_MASK_2G_MAX), + + REG_VARIABLE(CFG_RX_CHAIN_MASK_2G_NAME, WLAN_PARAM_Integer, + struct hdd_config, rx_chain_mask_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_CHAIN_MASK_2G_DEFAULT, + CFG_RX_CHAIN_MASK_2G_MIN, + CFG_RX_CHAIN_MASK_2G_MAX), + + REG_VARIABLE(CFG_TX_CHAIN_MASK_5G_NAME, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_5G_DEFAULT, + CFG_TX_CHAIN_MASK_5G_MIN, + CFG_TX_CHAIN_MASK_5G_MAX), + + REG_VARIABLE(CFG_RX_CHAIN_MASK_5G_NAME, WLAN_PARAM_Integer, + struct hdd_config, rx_chain_mask_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_CHAIN_MASK_5G_DEFAULT, + CFG_RX_CHAIN_MASK_5G_MIN, + CFG_RX_CHAIN_MASK_5G_MAX), + + REG_VARIABLE(CFG_BTM_ENABLE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, btm_offload_config, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BTM_ENABLE_DEFAULT, + CFG_BTM_ENABLE_MIN, + CFG_BTM_ENABLE_MAX), + +#ifdef WLAN_FEATURE_SAE + REG_VARIABLE(CFG_IS_SAE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_sae_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IS_SAE_ENABLED_DEFAULT, + CFG_IS_SAE_ENABLED_MIN, + CFG_IS_SAE_ENABLED_MAX), +#endif + + REG_VARIABLE(CFG_BTM_SOLICITED_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, btm_solicited_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BTM_SOLICITED_TIMEOUT_DEFAULT, + CFG_BTM_SOLICITED_TIMEOUT_MIN, + CFG_BTM_SOLICITED_TIMEOUT_MAX), + + REG_VARIABLE(CFG_BTM_MAX_ATTEMPT_CNT, WLAN_PARAM_Integer, + struct hdd_config, btm_max_attempt_cnt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BTM_MAX_ATTEMPT_CNT_DEFAULT, + CFG_BTM_MAX_ATTEMPT_CNT_MIN, + CFG_BTM_MAX_ATTEMPT_CNT_MAX), + + REG_VARIABLE(CFG_BTM_STICKY_TIME, WLAN_PARAM_Integer, + struct hdd_config, btm_sticky_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BTM_STICKY_TIME_DEFAULT, + CFG_BTM_STICKY_TIME_MIN, + CFG_BTM_STICKY_TIME_MAX), + + REG_VARIABLE(CFG_ENABLE_GCMP_NAME, WLAN_PARAM_Integer, + struct hdd_config, gcmp_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_GCMP_DEFAULT, + CFG_ENABLE_GCMP_MIN, + CFG_ENABLE_GCMP_MAX), + + REG_VARIABLE(CFG_OFFLOAD_11K_ENABLE_BITMASK_NAME, + WLAN_PARAM_Integer, + struct hdd_config, offload_11k_enable_bitmask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_11K_ENABLE_BITMASK_DEFAULT, + CFG_OFFLOAD_11K_ENABLE_BITMASK_MIN, + CFG_OFFLOAD_11K_ENABLE_BITMASK_MAX), + + REG_VARIABLE(CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_NAME, + WLAN_PARAM_Integer, + struct hdd_config, neighbor_report_offload_params_bitmask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_MIN, + CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_MAX), + + REG_VARIABLE(CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_NAME, + WLAN_PARAM_Integer, + struct hdd_config, neighbor_report_offload_time_offset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_MIN, + CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_MAX), + + REG_VARIABLE(CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_NAME, + WLAN_PARAM_Integer, + struct hdd_config, neighbor_report_offload_low_rssi_offset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_MIN, + CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_MAX), + + REG_VARIABLE(CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + neighbor_report_offload_bmiss_count_trigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_MIN, + CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_MAX), + + REG_VARIABLE(CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + neighbor_report_offload_per_threshold_offset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_MIN, + CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_MAX), + + REG_VARIABLE(CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, neighbor_report_offload_cache_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_MIN, + CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_MAX), + + REG_VARIABLE(CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_NAME, + WLAN_PARAM_Integer, + struct hdd_config, neighbor_report_offload_max_req_cap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_DEFAULT, + CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_MIN, + CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_MAX), + + REG_VARIABLE(CFG_WMI_WQ_WATCHDOG, WLAN_PARAM_Integer, + struct hdd_config, wmi_wq_watchdog_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WMI_WQ_WATCHDOG_DEFAULT, + CFG_WMI_WQ_WATCHDOG_MIN, + CFG_WMI_WQ_WATCHDOG_MAX), + + REG_VARIABLE(CFG_DTIM_SELECTION_DIVERSITY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enable_dtim_selection_diversity, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DTIM_SELECTION_DIVERSITY_DEFAULT, + CFG_DTIM_SELECTION_DIVERSITY_MIN, + CFG_DTIM_SELECTION_DIVERSITY_MAX), + + REG_VARIABLE(CFG_CHANNEL_SELECT_LOGIC_CONC_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, channel_select_logic_conc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CHANNEL_SELECT_LOGIC_CONC_DEFAULT, + CFG_CHANNEL_SELECT_LOGIC_CONC_MIN, + CFG_CHANNEL_SELECT_LOGIC_CONC_MAX), + + REG_VARIABLE(CFG_TX_SCH_DELAY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enable_tx_sch_delay, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_SCH_DELAY_DEFAULT, + CFG_TX_SCH_DELAY_MIN, + CFG_TX_SCH_DELAY_MAX), + + HDD_GREEN_AP_REG_VARIABLES + + REG_VARIABLE(CFG_ENABLE_UNIT_TEST_FRAMEWORK_NAME, + WLAN_PARAM_Integer, + struct hdd_config, is_unit_test_framework_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_UINT_TEST_FRAMEWORK_DEFAULT, + CFG_ENABLE_UNIT_TEST_FRAMEWORK_MIN, + CFG_ENABLE_UNIT_TEST_FRAMEWORK_MAX), + + REG_VARIABLE(CFG_ROAM_FT_OPEN_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_ftopen, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_FT_OPEN_ENABLE_DEFAULT, + CFG_ROAM_FT_OPEN_ENABLE_MIN, + CFG_ROAM_FT_OPEN_ENABLE_MAX), + + REG_VARIABLE(CFG_ENABLE_RTT_MAC_RANDOMIZATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enable_rtt_mac_randomization, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RTT_MAC_RANDOMIZATION_DEFAULT, + CFG_ENABLE_RTT_MAC_RANDOMIZATION_MIN, + CFG_ENABLE_RTT_MAC_RANDOMIZATION_MAX), + + REG_VARIABLE(CFG_ENABLE_SECONDARY_RATE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, enable_secondary_rate, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SECONDARY_RATE_DEFAULT, + CFG_ENABLE_SECONDARY_RATE_MIN, + CFG_ENABLE_SECONDARY_RATE_MAX), + + REG_VARIABLE(CFG_ROAM_FORCE_RSSI_TRIGGER_NAME, + WLAN_PARAM_Integer, struct hdd_config, + roam_force_rssi_trigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_FORCE_RSSI_TRIGGER_DEFAULT, + CFG_ROAM_FORCE_RSSI_TRIGGER_MIN, + CFG_ROAM_FORCE_RSSI_TRIGGER_MAX), +#ifdef MWS_COEX + REG_VARIABLE(CFG_MWS_COEX_4G_QUICK_FTDM_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, mws_coex_4g_quick_tdm, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MWS_COEX_4G_QUICK_FTDM_DEFAULT, + CFG_MWS_COEX_4G_QUICK_FTDM_MIN, + CFG_MWS_COEX_4G_QUICK_FTDM_MAX), + + REG_VARIABLE(CFG_MWS_COEX_5G_NR_PWR_LIMIT_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, mws_coex_5g_nr_pwr_limit, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MWS_COEX_5G_NR_PWR_LIMIT_DEFAULT, + CFG_MWS_COEX_5G_NR_PWR_LIMIT_MIN, + CFG_MWS_COEX_5G_NR_PWR_LIMIT_MAX), +#endif + REG_VARIABLE(CFG_SET_BTC_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, set_btc_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BTC_MODE_DEFAULT, + CFG_SET_BTC_MODE_MIN, + CFG_SET_BTC_MODE_MAX), + + REG_VARIABLE(CFG_SET_ANTENNA_ISOLATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, set_antenna_isolation, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_ANTENNA_ISOLATION_DEFAULT, + CFG_SET_ANTENNA_ISOLATION_MIN, + CFG_SET_ANTENNA_ISOLATION_MAX), + + REG_VARIABLE(CFG_SET_MAX_TX_POWER_FOR_BTC_NAME, WLAN_PARAM_Integer, + struct hdd_config, set_max_tx_power_for_btc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_MAX_TX_POWER_FOR_BTC_DEFAULT, + CFG_SET_MAX_TX_POWER_FOR_BTC_MIN, + CFG_SET_MAX_TX_POWER_FOR_BTC_MAX), + + REG_VARIABLE(CFG_SET_WLAN_LOW_RSSI_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_wlan_low_rssi_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_WLAN_LOW_RSSI_THRESHOLD_DEFAULT, + CFG_SET_WLAN_LOW_RSSI_THRESHOLD_MIN, + CFG_SET_WLAN_LOW_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_SET_BT_LOW_RSSI_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_bt_low_rssi_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BT_LOW_RSSI_THRESHOLD_DEFAULT, + CFG_SET_BT_LOW_RSSI_THRESHOLD_MIN, + CFG_SET_BT_LOW_RSSI_THRESHOLD_MAX), + + REG_VARIABLE(CFG_SET_BT_INTERFERENCE_LOW_LL_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_bt_interference_low_ll, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BT_INTERFERENCE_LOW_LL_DEFAULT, + CFG_SET_BT_INTERFERENCE_LOW_LL_MIN, + CFG_SET_BT_INTERFERENCE_LOW_LL_MAX), + + REG_VARIABLE(CFG_SET_BT_INTERFERENCE_LOW_UL_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_bt_interference_low_ul, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BT_INTERFERENCE_LOW_UL_DEFAULT, + CFG_SET_BT_INTERFERENCE_LOW_UL_MIN, + CFG_SET_BT_INTERFERENCE_LOW_UL_MAX), + + REG_VARIABLE(CFG_SET_BT_INTERFERENCE_MEDIUM_LL_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_bt_interference_medium_ll, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BT_INTERFERENCE_MEDIUM_LL_DEFAULT, + CFG_SET_BT_INTERFERENCE_MEDIUM_LL_MIN, + CFG_SET_BT_INTERFERENCE_MEDIUM_LL_MAX), + + REG_VARIABLE(CFG_SET_BT_INTERFERENCE_MEDIUM_UL_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_bt_interference_medium_ul, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BT_INTERFERENCE_MEDIUM_UL_DEFAULT, + CFG_SET_BT_INTERFERENCE_MEDIUM_UL_MIN, + CFG_SET_BT_INTERFERENCE_MEDIUM_UL_MAX), + + REG_VARIABLE(CFG_SET_BT_INTERFERENCE_HIGH_LL_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_bt_interference_high_ll, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BT_INTERFERENCE_HIGH_LL_DEFAULT, + CFG_SET_BT_INTERFERENCE_HIGH_LL_MIN, + CFG_SET_BT_INTERFERENCE_HIGH_LL_MAX), + + REG_VARIABLE(CFG_SET_BT_INTERFERENCE_HIGH_UL_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, set_bt_interference_high_ul, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_BT_INTERFERENCE_HIGH_UL_DEFAULT, + CFG_SET_BT_INTERFERENCE_HIGH_UL_MIN, + CFG_SET_BT_INTERFERENCE_HIGH_UL_MAX), + +#ifdef FEATURE_MPTA_HELPER + REG_VARIABLE(CFG_SET_MPTA_HELPER_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, set_mpta_helper_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_MPTA_HELPER_ENABLE_DEFAULT, + CFG_SET_MPTA_HELPER_ENABLE_MIN, + CFG_SET_MPTA_HELPER_ENABLE_MAX), +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + REG_VARIABLE(CFG_ROAM_PREAUTH_RETRY_COUNT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, roam_preauth_retry_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_PREAUTH_RETRY_COUNT_DEFAULT, + CFG_ROAM_PREAUTH_RETRY_COUNT_MIN, + CFG_ROAM_PREAUTH_RETRY_COUNT_MAX), + + REG_VARIABLE(CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, roam_preauth_no_ack_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_DEFAULT, + CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_MIN, + CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_MAC_PROVISION_NAME, WLAN_PARAM_Integer, + struct hdd_config, mac_provision, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MAC_PROVISION_DEFAULT, + CFG_ENABLE_MAC_PROVISION_MIN, + CFG_ENABLE_MAC_PROVISION_MAX), + + REG_VARIABLE(CFG_PROVISION_INTERFACE_POOL_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, provisioned_intf_pool, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PROVISION_INTERFACE_POOL_DEFAULT, + CFG_PROVISION_INTERFACE_POOL_MIN, + CFG_PROVISION_INTERFACE_POOL_MAX), + + REG_VARIABLE(CFG_DERIVED_INTERFACE_POOL_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, derived_intf_pool, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DERIVED_INTERFACE_POOL_DEFAULT, + CFG_DERIVED_INTERFACE_POOL_MIN, + CFG_DERIVED_INTERFACE_POOL_MAX), + + REG_VARIABLE(CFG_ENABLE_PEER_UNMAP_CONF_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_peer_unmap_conf_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PEER_UNMAP_CONF_DEFAULT, + CFG_ENABLE_PEER_UNMAP_CONF_MIN, + CFG_ENABLE_PEER_UNMAP_CONF_MAX), + + REG_VARIABLE(CFG_ROAM_SCORE_DELTA, WLAN_PARAM_Integer, + struct hdd_config, roam_score_delta, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCORE_DELTA_DEFAULT, + CFG_ROAM_SCORE_DELTA_MIN, + CFG_ROAM_SCORE_DELTA_MAX), + + REG_VARIABLE(CFG_ROAM_TRIGGER_DELTA_BITMAP, WLAN_PARAM_Integer, + struct hdd_config, roam_score_delta_bitmap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_TRIGGER_DELTA_BITMAP_DEFAULT, + CFG_ROAM_TRIGGER_DELTA_BITMAP_MIN, + CFG_ROAM_TRIGGER_DELTA_BITMAP_MAX), + + REG_VARIABLE(CFG_PREFER_BTM_QUERY, WLAN_PARAM_Integer, + struct hdd_config, prefer_btm_query, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PREFER_BTM_QUERY_DEFAULT, + CFG_PREFER_BTM_QUERY_MIN, + CFG_PREFER_BTM_QUERY_MAX), + + REG_VARIABLE(CFG_ENABLE_BTM_ABRIDGE, WLAN_PARAM_Integer, + struct hdd_config, btm_abridge_config, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BTM_ABRIDGE_DEFAULT, + CFG_ENABLE_BTM_ABRIDGE_MIN, + CFG_ENABLE_BTM_ABRIDGE_MAX), + + REG_VARIABLE(CFG_BTM_VALIDITY_TIMER, WLAN_PARAM_Integer, + struct hdd_config, btm_validity_timer, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BTM_VALIDITY_TIMER_DEFAULT, + CFG_BTM_VALIDITY_TIMER_MIN, + CFG_ENABLE_BTM_ABRIDGE_MAX), + + REG_VARIABLE(CFG_BTM_DISASSOC_TIMER_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, btm_disassoc_timer_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BTM_DISASSOC_TIMER_THRESHOLD_DEFAULT, + CFG_BTM_DISASSOC_TIMER_THRESHOLD_MIN, + CFG_BTM_DISASSOC_TIMER_THRESHOLD_MAX), + + REG_VARIABLE(CFG_ENABLE_BEACON_RECEPTION_STATS_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_beacon_reception_stats, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BEACON_RECEPTION_STATS_DEFAULT, + CFG_ENABLE_BEACON_RECEPTION_STATS_MIN, + CFG_ENABLE_BEACON_RECEPTION_STATS_MAX), + + REG_VARIABLE(CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM, WLAN_PARAM_Integer, + struct hdd_config, enable_bss_load_roam_trigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM_DEFAULT, + CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM_MIN, + CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM_MAX), + + REG_VARIABLE(CFG_BSS_LOAD_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, bss_load_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BSS_LOAD_THRESHOLD_DEFAULT, + CFG_BSS_LOAD_THRESHOLD_MIN, + CFG_BSS_LOAD_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BSS_LOAD_SAMPLE_TIME, WLAN_PARAM_Integer, + struct hdd_config, bss_load_sample_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BSS_LOAD_SAMPLE_TIME_DEFAULT, + CFG_BSS_LOAD_SAMPLE_TIME_MIN, + CFG_BSS_LOAD_SAMPLE_TIME_MAX), + REG_VARIABLE(CFG_ENABLE_RTT_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, enable_rtt_support, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_RTT_SUPPORT_DEFAULT, + CFG_ENABLE_RTT_SUPPORT_MIN, + CFG_ENABLE_RTT_SUPPORT_MAX), +}; + + +/** + * 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 == NULL || *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; +} + +/* Maximum length of the confgiuration name and value */ +#define CFG_VALUE_MAX_LEN 256 +#define CFG_ENTRY_MAX_LEN (32+CFG_VALUE_MAX_LEN) + +/** + * hdd_cfg_get_config() - get the configuration content + * @reg_table: pointer to configuration table + * @cRegTableEntries: number of the configuration entries + * @ini_struct: pointer to the hdd config knob + * @hdd_ctx: pointer to hdd context + * @pBuf: buffer to store the configuration + * @buflen: size of the buffer + * + * Return: QDF_STATUS_SUCCESS if the configuration and buffer size can carry + * the content, otherwise QDF_STATUS_E_RESOURCES + */ +static QDF_STATUS hdd_cfg_get_config(struct reg_table_entry *reg_table, + unsigned long cRegTableEntries, + uint8_t *ini_struct, + struct hdd_context *hdd_ctx, char *pBuf, + int buflen) +{ + unsigned int idx; + struct reg_table_entry *pRegEntry = reg_table; + uint32_t value; + char valueStr[CFG_VALUE_MAX_LEN]; + char configStr[CFG_ENTRY_MAX_LEN]; + char *fmt; + void *pField; + struct qdf_mac_addr *pMacAddr; + char *pCur = pBuf; + int curlen; + + /* start with an empty string */ + *pCur = '\0'; + + for (idx = 0; idx < cRegTableEntries; idx++, pRegEntry++) { + pField = ini_struct + pRegEntry->VarOffset; + + if ((WLAN_PARAM_Integer == pRegEntry->RegType) || + (WLAN_PARAM_SignedInteger == pRegEntry->RegType) || + (WLAN_PARAM_HexInteger == pRegEntry->RegType)) { + value = 0; + + if ((pRegEntry->VarSize > sizeof(value)) || + (pRegEntry->VarSize == 0)) { + pr_warn("Invalid length of %s: %d", + pRegEntry->RegName, pRegEntry->VarSize); + continue; + } + + memcpy(&value, pField, pRegEntry->VarSize); + if (WLAN_PARAM_HexInteger == pRegEntry->RegType) { + fmt = "%x"; + } else if (WLAN_PARAM_SignedInteger == + pRegEntry->RegType) { + fmt = "%d"; + value = sign_extend32( + value, + pRegEntry->VarSize * 8 - 1); + } else { + fmt = "%u"; + } + snprintf(valueStr, CFG_VALUE_MAX_LEN, fmt, value); + } else if (WLAN_PARAM_String == pRegEntry->RegType) { + snprintf(valueStr, CFG_VALUE_MAX_LEN, "%s", + (char *)pField); + } else if (WLAN_PARAM_MacAddr == pRegEntry->RegType) { + pMacAddr = (struct qdf_mac_addr *) pField; + snprintf(valueStr, CFG_VALUE_MAX_LEN, + "%02x:%02x:%02x:%02x:%02x:%02x", + pMacAddr->bytes[0], + pMacAddr->bytes[1], + pMacAddr->bytes[2], + pMacAddr->bytes[3], + pMacAddr->bytes[4], pMacAddr->bytes[5]); + } else { + snprintf(valueStr, CFG_VALUE_MAX_LEN, "(unhandled)"); + } + curlen = scnprintf(configStr, CFG_ENTRY_MAX_LEN, + "%s=[%s]%s\n", + pRegEntry->RegName, + valueStr, + test_bit(idx, + (void *)&hdd_ctx->config-> + bExplicitCfg) ? "*" : ""); + + /* Ideally we want to return the config to the application, + * however the config is too big so we just printk() for now + */ +#ifdef RETURN_IN_BUFFER + if (curlen < buflen) { + /* copy string + '\0' */ + memcpy(pCur, configStr, curlen + 1); + + /* account for addition; */ + pCur += curlen; + buflen -= curlen; + } else { + /* buffer space exhausted, return what we have */ + return QDF_STATUS_E_RESOURCES; + } +#else + printk(KERN_INFO "%s", configStr); +#endif /* RETURN_IN_BUFFER */ + + } + +#ifndef RETURN_IN_BUFFER + /* notify application that output is in system log */ + snprintf(pCur, buflen, "WLAN configuration written to system log"); +#endif /* RETURN_IN_BUFFER */ + + return QDF_STATUS_SUCCESS; +} + +/** 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; +}; + +/** + * find_cfg_item() - find the configuration item + * @iniTable: pointer to configuration table + * @entries: number fo the configuration entries + * @name: the interested configuration to find + * @value: the value to read back + * + * Return: QDF_STATUS_SUCCESS if the interested configuration is found, + * otherwise QDF_STATUS_E_FAILURE + */ +static QDF_STATUS find_cfg_item(struct hdd_cfg_entry *iniTable, + unsigned long entries, + char *name, char **value) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + unsigned long i; + + for (i = 0; i < entries; i++) { + if (strcmp(iniTable[i].name, name) == 0) { + *value = iniTable[i].value; + hdd_debug("Found %s entry for Name=[%s] Value=[%s] ", + WLAN_INI_FILE, name, *value); + return QDF_STATUS_SUCCESS; + } + } + + return status; +} + +/** + * parse_hex_digit() - conversion to hex value + * @c: the character to convert + * + * Return: the hex value, otherwise 0 + */ +static int parse_hex_digit(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return 0; +} + +/** + * update_mac_from_string() - convert string to 6 bytes mac address + * @hdd_ctx: the pointer to hdd context + * @macTable: the macTable 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 *macTable, + 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 = macTable[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; +} + +/** + * hdd_apply_cfg_ini() - apply the ini configuration file + * @hdd_ctx: the pointer to hdd context + * @iniTable: pointer to configuration table + * @entries: number fo the configuration entries + * It overwrites the MAC address if config file exist. + * + * Return: QDF_STATUS_SUCCESS if the ini configuration file is correctly parsed, + * otherwise QDF_STATUS_E_INVAL + */ +static QDF_STATUS hdd_apply_cfg_ini(struct hdd_context *hdd_ctx, + struct hdd_cfg_entry *iniTable, + unsigned long entries) +{ + QDF_STATUS match_status = QDF_STATUS_E_FAILURE; + QDF_STATUS ret_status = QDF_STATUS_SUCCESS; + unsigned int idx; + void *pField; + char *value_str = NULL; + unsigned long len_value_str; + char *candidate; + uint32_t value; + int32_t svalue; + void *pStructBase = hdd_ctx->config; + struct reg_table_entry *pRegEntry = g_registry_table; + unsigned long cRegTableEntries = QDF_ARRAY_SIZE(g_registry_table); + uint32_t cbOutString; + int i; + int rv; + + BUILD_BUG_ON(MAX_CFG_INI_ITEMS < cRegTableEntries); + + for (idx = 0; idx < cRegTableEntries; idx++, pRegEntry++) { + /* Calculate the address of the destination field in the structure. */ + pField = ((uint8_t *) pStructBase) + pRegEntry->VarOffset; + + match_status = + find_cfg_item(iniTable, entries, pRegEntry->RegName, + &value_str); + + if ((match_status != QDF_STATUS_SUCCESS) + && (pRegEntry->Flags & VAR_FLAGS_REQUIRED)) { + /* If we could not read the cfg item and it is required, this is an error. */ + hdd_err("Failed to read required config parameter %s", pRegEntry->RegName); + ret_status = QDF_STATUS_E_FAILURE; + break; + } + + if ((WLAN_PARAM_Integer == pRegEntry->RegType) || + (WLAN_PARAM_HexInteger == pRegEntry->RegType)) { + /* If successfully read from the registry, use the value read. + * If not, use the default value. + */ + if (match_status == QDF_STATUS_SUCCESS + && (WLAN_PARAM_Integer == pRegEntry->RegType)) { + rv = kstrtou32(value_str, 10, &value); + if (rv < 0) { + hdd_warn("Reg Parameter %s invalid. Enforcing default", pRegEntry->RegName); + value = pRegEntry->VarDefault; + } + } else if (match_status == QDF_STATUS_SUCCESS + && (WLAN_PARAM_HexInteger == + pRegEntry->RegType)) { + rv = kstrtou32(value_str, 16, &value); + if (rv < 0) { + hdd_warn("Reg parameter %s invalid. Enforcing default", pRegEntry->RegName); + value = pRegEntry->VarDefault; + } + } else { + value = pRegEntry->VarDefault; + } + + /* Only if the parameter is set in the ini file, do the range check here */ + if (match_status == QDF_STATUS_SUCCESS && + pRegEntry->Flags & VAR_FLAGS_RANGE_CHECK) { + if (value > pRegEntry->VarMax) { + hdd_warn("Reg Parameter %s > allowed Maximum [%u > %lu]. Enforcing Maximum", pRegEntry->RegName, + value, pRegEntry->VarMax); + value = pRegEntry->VarMax; + } + + if (value < pRegEntry->VarMin) { + hdd_warn("Reg Parameter %s < allowed Minimum [%u < %lu]. Enforcing Minimum", pRegEntry->RegName, + value, pRegEntry->VarMin); + value = pRegEntry->VarMin; + } + } + /* Only if the parameter is set in the ini file, do the range check here */ + else if (match_status == QDF_STATUS_SUCCESS && + pRegEntry->Flags & + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT) { + if (value > pRegEntry->VarMax) { + hdd_warn("Reg Parameter %s > allowed Maximum [%u > %lu]. Enforcing Default: %lu", pRegEntry->RegName, + value, pRegEntry->VarMax, + pRegEntry->VarDefault); + value = pRegEntry->VarDefault; + } + + if (value < pRegEntry->VarMin) { + hdd_warn("Reg Parameter %s < allowed Minimum [%u < %lu]. Enforcing Default: %lu", pRegEntry->RegName, + value, pRegEntry->VarMin, + pRegEntry->VarDefault); + value = pRegEntry->VarDefault; + } + } + /* Move the variable into the output field. */ + memcpy(pField, &value, pRegEntry->VarSize); + } else if (WLAN_PARAM_SignedInteger == pRegEntry->RegType) { + /* If successfully read from the registry, use the value read. + * If not, use the default value. + */ + if (QDF_STATUS_SUCCESS == match_status) { + rv = kstrtos32(value_str, 10, &svalue); + if (rv < 0) { + hdd_warn("Reg Parameter %s invalid. Enforcing Default", pRegEntry->RegName); + svalue = + (int32_t) pRegEntry->VarDefault; + } + } else { + svalue = (int32_t) pRegEntry->VarDefault; + } + + /* Only if the parameter is set in the ini file, do the range check here */ + if (match_status == QDF_STATUS_SUCCESS && + pRegEntry->Flags & VAR_FLAGS_RANGE_CHECK) { + if (svalue > (int32_t) pRegEntry->VarMax) { + hdd_warn("Reg Parameter %s > allowed Maximum " + "[%d > %d]. Enforcing Maximum", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMax); + svalue = (int32_t) pRegEntry->VarMax; + } + + if (svalue < (int32_t) pRegEntry->VarMin) { + hdd_warn("Reg Parameter %s < allowed Minimum " + "[%d < %d]. Enforcing Minimum", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMin); + svalue = (int32_t) pRegEntry->VarMin; + } + } + /* Only if the parameter is set in the ini file, do the range check here */ + else if (match_status == QDF_STATUS_SUCCESS && + pRegEntry->Flags & + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT) { + if (svalue > (int32_t) pRegEntry->VarMax) { + hdd_warn("Reg Parameter %s > allowed Maximum " + "[%d > %d]. Enforcing Default: %d", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMax, + (int)pRegEntry->VarDefault); + svalue = + (int32_t) pRegEntry->VarDefault; + } + + if (svalue < (int32_t) pRegEntry->VarMin) { + hdd_warn("Reg Parameter %s < allowed Minimum " + "[%d < %d]. Enforcing Default: %d", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMin, + (int)pRegEntry->VarDefault); + svalue = pRegEntry->VarDefault; + } + } + /* Move the variable into the output field. */ + memcpy(pField, &svalue, pRegEntry->VarSize); + } + /* Handle string parameters */ + else if (WLAN_PARAM_String == pRegEntry->RegType) { +#ifdef WLAN_CFG_DEBUG + hdd_debug("RegName = %s, VarOffset %u VarSize %u VarDefault %s", + pRegEntry->RegName, pRegEntry->VarOffset, + pRegEntry->VarSize, + (char *)pRegEntry->VarDefault); +#endif + + if (match_status == QDF_STATUS_SUCCESS) { + len_value_str = strlen(value_str); + + if (len_value_str > (pRegEntry->VarSize - 1)) { + hdd_err("Invalid Value=[%s] specified for Name=[%s] in %s", value_str, + pRegEntry->RegName, + WLAN_INI_FILE); + cbOutString = + QDF_MIN(strlen + ((char *)pRegEntry-> + VarDefault), + pRegEntry->VarSize - 1); + memcpy(pField, + (void *)(pRegEntry->VarDefault), + cbOutString); + ((uint8_t *) pField)[cbOutString] = + '\0'; + } else { + memcpy(pField, (void *)(value_str), + len_value_str); + ((uint8_t *) pField)[len_value_str] = + '\0'; + } + } else { + /* Failed to read the string parameter from the registry. Use the default. */ + cbOutString = + QDF_MIN(strlen((char *)pRegEntry->VarDefault), + pRegEntry->VarSize - 1); + memcpy(pField, (void *)(pRegEntry->VarDefault), + cbOutString); + ((uint8_t *) pField)[cbOutString] = '\0'; + } + } else if (WLAN_PARAM_MacAddr == pRegEntry->RegType) { + if (pRegEntry->VarSize != QDF_MAC_ADDR_SIZE) { + hdd_warn("Invalid VarSize %u for Name=[%s]", pRegEntry->VarSize, + pRegEntry->RegName); + continue; + } + candidate = (char *)pRegEntry->VarDefault; + if (match_status == QDF_STATUS_SUCCESS) { + len_value_str = strlen(value_str); + if (len_value_str != (QDF_MAC_ADDR_SIZE * 2)) { + hdd_err("Invalid MAC addr [%s] specified for Name=[%s] in %s", value_str, + pRegEntry->RegName, + WLAN_INI_FILE); + } else + candidate = value_str; + } + /* parse the string and store it in the byte array */ + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) { + ((char *)pField)[i] = + (char)(parse_hex_digit(candidate[i * 2]) * + 16 + + parse_hex_digit(candidate[i * 2 + 1])); + } + } else { + hdd_warn("Unknown param type for name[%s] in registry table", pRegEntry->RegName); + } + + /* did we successfully parse a cfg item for this parameter? */ + if ((match_status == QDF_STATUS_SUCCESS) && + (idx < MAX_CFG_INI_ITEMS)) { + set_bit(idx, (void *)&hdd_ctx->config->bExplicitCfg); + } + } + + return ret_status; +} + +/** + * hdd_execute_config_command() - executes an arbitrary configuration command + * @reg_table: the pointer to configuration table + * @tableSize: the size of the configuration table + * @ini_struct: pointer to the hdd config knob + * @hdd_ctx: the pointer to hdd context + * @command: the command to run + * + * Return: QDF_STATUS_SUCCESS if the command is found and able to execute, + * otherwise the appropriate QDF_STATUS will be returned + */ +static QDF_STATUS hdd_execute_config_command(struct reg_table_entry *reg_table, + unsigned long tableSize, + uint8_t *ini_struct, + struct hdd_context *hdd_ctx, + char *command) +{ + struct reg_table_entry *pRegEntry; + char *clone; + char *pCmd; + void *pField; + char *name; + char *value_str; + uint32_t value; + int32_t svalue; + size_t len_value_str; + unsigned int idx; + unsigned int i; + QDF_STATUS vstatus; + int rv; + + /* assume failure until proven otherwise */ + vstatus = QDF_STATUS_E_FAILURE; + + /* clone the command so that we can manipulate it */ + clone = kstrdup(command, GFP_ATOMIC); + if (NULL == clone) + return vstatus; + + /* 'clone' will point to the beginning of the string so it can be freed + * 'pCmd' will be used to walk/parse the command + */ + pCmd = clone; + + /* get rid of leading/trailing whitespace */ + pCmd = i_trim(pCmd); + if ('\0' == *pCmd) { + /* only whitespace */ + hdd_err("invalid command, only whitespace:[%s]", command); + goto done; + } + /* parse the = */ + name = pCmd; + while (('=' != *pCmd) && ('\0' != *pCmd)) + pCmd++; + + if ('\0' == *pCmd) { + /* did not find '=' */ + hdd_err("invalid command, no '=':[%s]", command); + goto done; + } + /* replace '=' with NUL to terminate the */ + *pCmd++ = '\0'; + name = i_trim(name); + if ('\0' == *name) { + /* did not find a name */ + hdd_err("invalid command, no :[%s]", command); + goto done; + } + + value_str = i_trim(pCmd); + if ('\0' == *value_str) { + /* did not find a value */ + hdd_err("invalid command, no :[%s]", command); + goto done; + } + /* lookup the configuration item */ + for (idx = 0; idx < tableSize; idx++) { + if (0 == strcmp(name, reg_table[idx].RegName)) { + /* found a match */ + break; + } + } + if (tableSize == idx) { + /* did not match the name */ + hdd_err("invalid command, unknown configuration item:[%s]", command); + goto done; + } + + pRegEntry = ®_table[idx]; + if (!(pRegEntry->Flags & VAR_FLAGS_DYNAMIC_CFG)) { + /* does not support dynamic configuration */ + hdd_err("Global_Registry_Table. %s does not support " + "dynamic configuration", name); + vstatus = QDF_STATUS_E_PERM; + goto done; + } + + pField = ini_struct + pRegEntry->VarOffset; + + switch (pRegEntry->RegType) { + case WLAN_PARAM_Integer: + rv = kstrtou32(value_str, 10, &value); + if (rv < 0) + goto done; + if (value < pRegEntry->VarMin) { + /* out of range */ + hdd_err("Invalid command, value %u < min value %lu", value, pRegEntry->VarMin); + goto done; + } + if (value > pRegEntry->VarMax) { + /* out of range */ + hdd_err("Invalid command, value %u > max value %lu", value, pRegEntry->VarMax); + goto done; + } + memcpy(pField, &value, pRegEntry->VarSize); + break; + + case WLAN_PARAM_HexInteger: + rv = kstrtou32(value_str, 16, &value); + if (rv < 0) + goto done; + if (value < pRegEntry->VarMin) { + /* out of range */ + hdd_err("Invalid command, value %x < min value %lx", value, pRegEntry->VarMin); + goto done; + } + if (value > pRegEntry->VarMax) { + /* out of range */ + hdd_err("Invalid command, value %x > max value %lx", value, pRegEntry->VarMax); + goto done; + } + memcpy(pField, &value, pRegEntry->VarSize); + break; + + case WLAN_PARAM_SignedInteger: + rv = kstrtos32(value_str, 10, &svalue); + if (rv < 0) + goto done; + if (svalue < (int32_t) pRegEntry->VarMin) { + /* out of range */ + hdd_err("Invalid command, value %d < min value %d", svalue, (int)pRegEntry->VarMin); + goto done; + } + if (svalue > (int32_t) pRegEntry->VarMax) { + /* out of range */ + hdd_err("Invalid command, value %d > max value %d", svalue, (int)pRegEntry->VarMax); + goto done; + } + memcpy(pField, &svalue, pRegEntry->VarSize); + break; + + case WLAN_PARAM_String: + len_value_str = strlen(value_str); + if (len_value_str > (pRegEntry->VarSize - 1)) { + /* too big */ + hdd_err("Invalid command, string [%s] length " + "%zu exceeds maximum length %u", value_str, + len_value_str, (pRegEntry->VarSize - 1)); + goto done; + } + /* copy string plus NUL */ + memcpy(pField, value_str, (len_value_str + 1)); + break; + + case WLAN_PARAM_MacAddr: + len_value_str = strlen(value_str); + if (len_value_str != (QDF_MAC_ADDR_SIZE * 2)) { + /* out of range */ + hdd_err("Invalid command, MAC address [%s] length " + "%zu is not expected length %u", value_str, + len_value_str, (QDF_MAC_ADDR_SIZE * 2)); + goto done; + } + /* parse the string and store it in the byte array */ + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) { + ((char *)pField)[i] = (char) + ((parse_hex_digit(value_str[(i * 2)]) * 16) + + parse_hex_digit(value_str[(i * 2) + 1])); + } + break; + + default: + goto done; + } + + /* if we get here, we had a successful modification */ + vstatus = QDF_STATUS_SUCCESS; + + /* config table has been modified, is there a notifier? */ + if (NULL != pRegEntry->pfnDynamicnotify) + (pRegEntry->pfnDynamicnotify)(hdd_ctx, pRegEntry->notifyId); + + /* note that this item was explicitly configured */ + if (idx < MAX_CFG_INI_ITEMS) + set_bit(idx, (void *)&hdd_ctx->config->bExplicitCfg); + +done: + kfree(clone); + return vstatus; +} + +/** + * 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) +{ + struct hdd_config *pConfig = hdd_ctx->config; + uint32_t listenInterval = 0; + + if (strcmp(pConfig->PowerUsageControl, "Min") == 0) + listenInterval = pConfig->nBmpsMinListenInterval; + else if (strcmp(pConfig->PowerUsageControl, "Max") == 0) + listenInterval = pConfig->nBmpsMaxListenInterval; + + /* + * Based on Mode Set the LI + * Otherwise default LI value of 1 will + * be taken + */ + if (listenInterval) { + /* + * setcfg for listenInterval. + * Make sure CFG is updated because PE reads this + * from CFG at the time of assoc or reassoc + */ + sme_cfg_set_int(hdd_ctx->mac_handle, WNI_CFG_LISTEN_INTERVAL, + listenInterval); + } + +} + +#ifdef FEATURE_RUNTIME_PM +static void hdd_cfg_print_runtime_pm(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [gRuntimePM] Value = [%u] ", + hdd_ctx->config->runtime_pm); + + hdd_debug("Name = [gRuntimePMDelay] Value = [%u] ", + hdd_ctx->config->runtime_pm_delay); +} +#else +static void hdd_cfg_print_runtime_pm(struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * hdd_per_roam_print_ini_config()- Print PER roam specific INI configuration + * @hdd_ctx: handle to hdd context + * + * Return: None + */ +static void hdd_per_roam_print_ini_config(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_ENABLE_NAME, + hdd_ctx->config->is_per_roam_enabled); + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_NAME, + hdd_ctx->config->per_roam_high_rate_threshold); + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_NAME, + hdd_ctx->config->per_roam_low_rate_threshold); + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_NAME, + hdd_ctx->config->per_roam_th_percent); + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_REST_TIME_NAME, + hdd_ctx->config->per_roam_rest_time); + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_MONITOR_TIME, + hdd_ctx->config->per_roam_mon_time); + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_MIN_CANDIDATE_RSSI, + hdd_ctx->config->min_candidate_rssi); +} + +static void hdd_mawc_cfg_log(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [MAWCEnabled] Value = [%u] ", + hdd_ctx->config->MAWCEnabled); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_MAWC_ROAM_ENABLED_NAME, + hdd_ctx->config->mawc_roam_enabled); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_MAWC_ROAM_TRAFFIC_THRESHOLD_NAME, + hdd_ctx->config->mawc_roam_traffic_threshold); + hdd_debug("Name = [%s] Value = [%d] ", + CFG_MAWC_ROAM_AP_RSSI_THRESHOLD_NAME, + hdd_ctx->config->mawc_roam_ap_rssi_threshold); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_MAWC_ROAM_RSSI_HIGH_ADJUST_NAME, + hdd_ctx->config->mawc_roam_rssi_high_adjust); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_MAWC_ROAM_RSSI_LOW_ADJUST_NAME, + hdd_ctx->config->mawc_roam_rssi_low_adjust); +} + +/** + * hdd_cfg_print_ie_whitelist_attrs() - print the ie whitelist attrs + * @hdd_ctx: pointer to hdd context + * + * Return: None + */ +static void hdd_cfg_print_ie_whitelist_attrs(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_WHITELIST_NAME, + hdd_ctx->config->probe_req_ie_whitelist); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP0_NAME, + hdd_ctx->config->probe_req_ie_bitmap_0); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP1_NAME, + hdd_ctx->config->probe_req_ie_bitmap_1); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP2_NAME, + hdd_ctx->config->probe_req_ie_bitmap_2); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP3_NAME, + hdd_ctx->config->probe_req_ie_bitmap_3); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP4_NAME, + hdd_ctx->config->probe_req_ie_bitmap_4); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP5_NAME, + hdd_ctx->config->probe_req_ie_bitmap_5); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP6_NAME, + hdd_ctx->config->probe_req_ie_bitmap_6); + hdd_debug("Name = [%s] Value = [%x] ", + CFG_PRB_REQ_IE_BIT_MAP7_NAME, + hdd_ctx->config->probe_req_ie_bitmap_7); + hdd_debug("Name = [%s] Value =[%s]", + CFG_PROBE_REQ_OUI_NAME, + hdd_ctx->config->probe_req_ouis); +} + +static void hdd_wlm_cfg_log(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] value = [%u]", + CFG_LATENCY_ENABLE_NAME, + hdd_ctx->config->wlm_latency_enable); + hdd_debug("Name = [%s] value = [%u]", + CFG_LATENCY_LEVEL_NAME, + hdd_ctx->config->wlm_latency_level); + hdd_debug("Name = [%s] value = [%u]", + CFG_LATENCY_FLAGS_NORMAL_NAME, + hdd_ctx->config->wlm_latency_flags_normal); + hdd_debug("Name = [%s] value = [%u]", + CFG_LATENCY_FLAGS_MODERATE_NAME, + hdd_ctx->config->wlm_latency_flags_moderate); + hdd_debug("Name = [%s] value = [%u]", + CFG_LATENCY_FLAGS_LOW_NAME, + hdd_ctx->config->wlm_latency_flags_low); + hdd_debug("Name = [%s] value = [%u]", + CFG_LATENCY_FLAGS_ULTRALOW_NAME, + hdd_ctx->config->wlm_latency_flags_ultralow); +} + +#ifdef WLAN_FEATURE_SAE +static void hdd_cfg_print_sae(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] value = [%u]", + CFG_IS_SAE_ENABLED_NAME, + hdd_ctx->config->is_sae_enabled); +} +#else +static void hdd_cfg_print_sae(struct hdd_context *hdd_ctx) +{ +} +#endif + + +#ifdef CONFIG_DP_TRACE +static void hdd_cfg_print_dp_trace_params(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_DP_TRACE, + hdd_ctx->config->enable_dp_trace); + hdd_debug("Name = [%s] Value = [%s]", + CFG_ENABLE_DP_TRACE_CONFIG, + hdd_ctx->config->dp_trace_config); +} +#else +static void hdd_cfg_print_dp_trace_params(struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * hdd_cfg_print_roam_preauth() - Print the roam preauth cfg params + * @hdd_ctx: Pointer to the HDD context + * + * Return: None + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline void hdd_cfg_print_roam_preauth(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_PREAUTH_RETRY_COUNT_NAME, + hdd_ctx->config->roam_preauth_retry_count); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_PREAUTH_NO_ACK_TIMEOUT_NAME, + hdd_ctx->config->roam_preauth_no_ack_timeout); +} +#else +static inline void hdd_cfg_print_roam_preauth(struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * hdd_cgf_print_11k_offload_params() - Print 11k offload related parameters + * @hdd_ctx: Pointer to HDD context + * + * Return: None + */ +static +void hdd_cfg_print_11k_offload_params(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_11K_ENABLE_BITMASK_NAME, + hdd_ctx->config->offload_11k_enable_bitmask); + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK_NAME, + hdd_ctx->config->neighbor_report_offload_params_bitmask); + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET_NAME, + hdd_ctx->config->neighbor_report_offload_time_offset); + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET_NAME, + hdd_ctx->config->neighbor_report_offload_low_rssi_offset); + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER_NAME, + hdd_ctx->config->neighbor_report_offload_bmiss_count_trigger); + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET_NAME, + hdd_ctx->config-> + neighbor_report_offload_per_threshold_offset); + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT_NAME, + hdd_ctx->config->neighbor_report_offload_cache_timeout); + hdd_debug("Name = [%s] value = [%u]", + CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP_NAME, + hdd_ctx->config->neighbor_report_offload_max_req_cap); +} + +/** + * hdd_cfg_print_action_oui() - print the action OUI configurations + * @hdd_ctx: pointer to the HDD context + * + * Return: None + */ +static void hdd_cfg_print_action_oui(struct hdd_context *hdd_ctx) +{ +#ifdef WLAN_DEBUG + struct hdd_config *config = hdd_ctx->config; +#endif + + hdd_debug("Name = [%s] value = [%u]", + CFG_ENABLE_ACTION_OUI, + config->action_oui_enable); + + hdd_debug("Name = [%s] value = [%s]", + CFG_ACTION_OUI_CONNECT_1X1_NAME, + config->action_oui_str[ACTION_OUI_CONNECT_1X1]); + + hdd_debug("Name = [%s] value = [%s]", + CFG_ACTION_OUI_ITO_EXTENSION_NAME, + config->action_oui_str[ACTION_OUI_ITO_EXTENSION]); + + hdd_debug("Name = [%s] value = [%s]", + CFG_ACTION_OUI_CCKM_1X1_NAME, + config->action_oui_str[ACTION_OUI_CCKM_1X1]); + + hdd_debug("Name = [%s] value = [%s]", + CFG_ACTION_OUI_ITO_ALTERNATE_NAME, + config->action_oui_str[ACTION_OUI_ITO_ALTERNATE]); + + hdd_debug("Name = [%s] value = [%s]", + CFG_ACTION_OUI_SWITCH_TO_11N_MODE_NAME, + config->action_oui_str[ACTION_OUI_SWITCH_TO_11N_MODE]); + + hdd_debug("Name = [%s] value = [%s]", + CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN_NAME, + config->action_oui_str[ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN]); + + hdd_debug("Name = [%s] value = [%s]", + CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX_NAME, + config->action_oui_str[ACTION_OUI_DISABLE_AGGRESSIVE_TX]); +} + +/** + * hdd_cfg_print_btc_params() - print btc param values + * @hdd_ctx: pointer to hdd context + * + * Return: None + */ +static void hdd_cfg_print_btc_params(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BTC_MODE_NAME, + hdd_ctx->config->set_btc_mode); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_ANTENNA_ISOLATION_NAME, + hdd_ctx->config->set_antenna_isolation); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_MAX_TX_POWER_FOR_BTC_NAME, + hdd_ctx->config->set_max_tx_power_for_btc); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_WLAN_LOW_RSSI_THRESHOLD_NAME, + hdd_ctx->config->set_wlan_low_rssi_threshold); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BT_LOW_RSSI_THRESHOLD_NAME, + hdd_ctx->config->set_bt_low_rssi_threshold); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BT_INTERFERENCE_LOW_LL_NAME, + hdd_ctx->config->set_bt_interference_low_ll); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BT_INTERFERENCE_LOW_UL_NAME, + hdd_ctx->config->set_bt_interference_low_ul); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BT_INTERFERENCE_MEDIUM_LL_NAME, + hdd_ctx->config->set_bt_interference_medium_ll); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BT_INTERFERENCE_MEDIUM_UL_NAME, + hdd_ctx->config->set_bt_interference_medium_ul); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BT_INTERFERENCE_HIGH_LL_NAME, + hdd_ctx->config->set_bt_interference_high_ll); + hdd_debug("Name = [%s] value = [%d]", + CFG_SET_BT_INTERFERENCE_HIGH_UL_NAME, + hdd_ctx->config->set_bt_interference_high_ul); +} + +/** + * hdd_cfg_print() - print the hdd configuration + * @iniTable: pointer to hdd context + * + * Return: None + */ +void hdd_cfg_print(struct hdd_context *hdd_ctx) +{ + + hdd_debug("*********Config values in HDD Adapter*******"); + hdd_debug("Name = [RTSThreshold] Value = %u", + hdd_ctx->config->RTSThreshold); + hdd_debug("Name = [OperatingChannel] Value = [%u]", + hdd_ctx->config->OperatingChannel); + hdd_debug("Name = [PowerUsageControl] Value = [%s]", + hdd_ctx->config->PowerUsageControl); + hdd_debug("Name = [fIsImpsEnabled] Value = [%u]", + hdd_ctx->config->fIsImpsEnabled); + hdd_debug("Name = [nVccRssiTrigger] Value = [%u]", + hdd_ctx->config->nVccRssiTrigger); + hdd_debug("Name = [gIbssBssid] Value =[" MAC_ADDRESS_STR "]", + MAC_ADDR_ARRAY(hdd_ctx->config->IbssBssid.bytes)); + + hdd_debug("Name = [gApEnableUapsd] value = [%u]", + hdd_ctx->config->apUapsdEnabled); + + hdd_debug("Name = [gEnableApProt] value = [%u]", + hdd_ctx->config->apProtEnabled); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + hdd_debug("Name = [gWlanMccToSccSwitchMode] Value = [%u]", + hdd_ctx->config->WlanMccToSccSwitchMode); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + hdd_debug("Name = [gWlanAutoShutdown] Value = [%u]", + hdd_ctx->config->WlanAutoShutdown); +#endif + hdd_debug("Name = [gApProtection] value = [%u]", + hdd_ctx->config->apProtection); + hdd_debug("Name = [gEnableApOBSSProt] value = [%u]", + hdd_ctx->config->apOBSSProtEnabled); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + hdd_debug("Name = [sap_channel_avoidance] value = [%u]", + hdd_ctx->config->sap_channel_avoidance); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + hdd_debug("Name = [%s] value = [%u]", CFG_SAP_11AC_OVERRIDE_NAME, + hdd_ctx->config->sap_11ac_override); + hdd_debug("Name = [%s] value = [%u]", CFG_GO_11AC_OVERRIDE_NAME, + hdd_ctx->config->go_11ac_override); + hdd_debug("Name = [ChannelBondingMode] Value = [%u]", + hdd_ctx->config->nChannelBondingMode24GHz); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_OVERRIDE_HT40_20_24GHZ_NAME, + hdd_ctx->config->override_ht20_40_24g); + hdd_debug("Name = [ChannelBondingMode] Value = [%u]", + hdd_ctx->config->nChannelBondingMode5GHz); + hdd_debug("Name = [dot11Mode] Value = [%u]", + hdd_ctx->config->dot11Mode); + hdd_debug("Name = [WmmMode] Value = [%u] ", hdd_ctx->config->WmmMode); + hdd_debug("Name = [UapsdMask] Value = [0x%x] ", + hdd_ctx->config->UapsdMask); + hdd_debug("Name = [ImplicitQosIsEnabled] Value = [%u]", + (int)hdd_ctx->config->bImplicitQosEnabled); + + hdd_debug("Name = [InfraUapsdVoSrvIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdVoSrvIntv); + hdd_debug("Name = [InfraUapsdVoSuspIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdVoSuspIntv); + + hdd_debug("Name = [InfraUapsdViSrvIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdViSrvIntv); + hdd_debug("Name = [InfraUapsdViSuspIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdViSuspIntv); + + hdd_debug("Name = [InfraUapsdBeSrvIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdBeSrvIntv); + hdd_debug("Name = [InfraUapsdBeSuspIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdBeSuspIntv); + + hdd_debug("Name = [InfraUapsdBkSrvIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdBkSrvIntv); + hdd_debug("Name = [InfraUapsdBkSuspIntv] Value = [%u] ", + hdd_ctx->config->InfraUapsdBkSuspIntv); +#ifdef FEATURE_WLAN_ESE + hdd_debug("Name = [InfraInactivityInterval] Value = [%u] ", + hdd_ctx->config->InfraInactivityInterval); + hdd_debug("Name = [EseEnabled] Value = [%u] ", + hdd_ctx->config->isEseIniFeatureEnabled); + hdd_debug("Name = [FastTransitionEnabled] Value = [%u] ", + hdd_ctx->config->isFastTransitionEnabled); + hdd_debug("Name = [gTxPowerCap] Value = [%u] dBm ", + hdd_ctx->config->nTxPowerCap); +#endif + hdd_debug("Name = [gAllowTPCfromAP] Value = [%u] ", + hdd_ctx->config->allow_tpc_from_ap); + hdd_debug("Name = [FastRoamEnabled] Value = [%u] ", + hdd_ctx->config->isFastRoamIniFeatureEnabled); + hdd_mawc_cfg_log(hdd_ctx); + hdd_debug("Name = [RoamRssiDiff] Value = [%u] ", + hdd_ctx->config->RoamRssiDiff); + hdd_debug("Name = [%s] Value = [%u] ", CFG_ROAM_RSSI_ABS_THRESHOLD_NAME, + hdd_ctx->config->rssi_abs_thresh); + hdd_debug("Name = [isWESModeEnabled] Value = [%u] ", + hdd_ctx->config->isWESModeEnabled); + hdd_debug("Name = [pmkidModes] Value = [0x%x] ", + hdd_ctx->config->pmkid_modes); +#ifdef FEATURE_WLAN_SCAN_PNO + hdd_debug("Name = [configPNOScanSupport] Value = [%u] ", + hdd_ctx->config->configPNOScanSupport); + hdd_debug("Name = [configPNOScanTimerRepeatValue] Value = [%u] ", + hdd_ctx->config->configPNOScanTimerRepeatValue); + hdd_debug("Name = [gPNOSlowScanMultiplier] Value = [%u] ", + hdd_ctx->config->pno_slow_scan_multiplier); +#endif +#ifdef FEATURE_WLAN_TDLS + hdd_debug("Name = [fEnableTDLSSupport] Value = [%u] ", + hdd_ctx->config->fEnableTDLSSupport); + hdd_debug("Name = [fEnableTDLSImplicitTrigger] Value = [%u] ", + hdd_ctx->config->fEnableTDLSImplicitTrigger); + hdd_debug("Name = [fTDLSExternalControl] Value = [%u] ", + hdd_ctx->config->fTDLSExternalControl); + hdd_debug("Name = [fTDLSUapsdMask] Value = [%u] ", + hdd_ctx->config->fTDLSUapsdMask); + hdd_debug("Name = [fEnableTDLSBufferSta] Value = [%u] ", + hdd_ctx->config->fEnableTDLSBufferSta); + hdd_debug("Name = [fEnableTDLSWmmMode] Value = [%u] ", + hdd_ctx->config->fEnableTDLSWmmMode); + hdd_debug("Name = [enable_tdls_scan] Value = [%u]", + hdd_ctx->config->enable_tdls_scan); +#endif + hdd_debug("Name = [InfraDirAcVo] Value = [%u] ", + hdd_ctx->config->InfraDirAcVo); + hdd_debug("Name = [InfraNomMsduSizeAcVo] Value = [0x%x] ", + hdd_ctx->config->InfraNomMsduSizeAcVo); + hdd_debug("Name = [InfraMeanDataRateAcVo] Value = [0x%x] ", + hdd_ctx->config->InfraMeanDataRateAcVo); + hdd_debug("Name = [InfraMinPhyRateAcVo] Value = [0x%x] ", + hdd_ctx->config->InfraMinPhyRateAcVo); + hdd_debug("Name = [InfraSbaAcVo] Value = [0x%x] ", + hdd_ctx->config->InfraSbaAcVo); + + hdd_debug("Name = [InfraDirAcVi] Value = [%u] ", + hdd_ctx->config->InfraDirAcVi); + hdd_debug("Name = [InfraNomMsduSizeAcVi] Value = [0x%x] ", + hdd_ctx->config->InfraNomMsduSizeAcVi); + hdd_debug("Name = [InfraMeanDataRateAcVi] Value = [0x%x] ", + hdd_ctx->config->InfraMeanDataRateAcVi); + hdd_debug("Name = [InfraMinPhyRateAcVi] Value = [0x%x] ", + hdd_ctx->config->InfraMinPhyRateAcVi); + hdd_debug("Name = [InfraSbaAcVi] Value = [0x%x] ", + hdd_ctx->config->InfraSbaAcVi); + + hdd_debug("Name = [InfraDirAcBe] Value = [%u] ", + hdd_ctx->config->InfraDirAcBe); + hdd_debug("Name = [InfraNomMsduSizeAcBe] Value = [0x%x] ", + hdd_ctx->config->InfraNomMsduSizeAcBe); + hdd_debug("Name = [InfraMeanDataRateAcBe] Value = [0x%x] ", + hdd_ctx->config->InfraMeanDataRateAcBe); + hdd_debug("Name = [InfraMinPhyRateAcBe] Value = [0x%x] ", + hdd_ctx->config->InfraMinPhyRateAcBe); + hdd_debug("Name = [InfraSbaAcBe] Value = [0x%x] ", + hdd_ctx->config->InfraSbaAcBe); + + hdd_debug("Name = [InfraDirAcBk] Value = [%u] ", + hdd_ctx->config->InfraDirAcBk); + hdd_debug("Name = [InfraNomMsduSizeAcBk] Value = [0x%x] ", + hdd_ctx->config->InfraNomMsduSizeAcBk); + hdd_debug("Name = [InfraMeanDataRateAcBk] Value = [0x%x] ", + hdd_ctx->config->InfraMeanDataRateAcBk); + hdd_debug("Name = [InfraMinPhyRateAcBk] Value = [0x%x] ", + hdd_ctx->config->InfraMinPhyRateAcBk); + hdd_debug("Name = [InfraSbaAcBk] Value = [0x%x] ", + hdd_ctx->config->InfraSbaAcBk); + + hdd_debug("Name = [DelayedTriggerFrmInt] Value = [%u] ", + hdd_ctx->config->DelayedTriggerFrmInt); + hdd_debug("Name = [fhostArpOffload] Value = [%u] ", + hdd_ctx->config->fhostArpOffload); + hdd_debug("Name = [%s] Value = [%u]", + CFG_HW_FILTER_MODE_BITMAP_NAME, + hdd_ctx->config->hw_filter_mode_bitmap); + hdd_debug("Name = [%s] Value = [%u]", + CFG_MAWC_NLO_ENABLED_NAME, + hdd_ctx->config->mawc_nlo_enabled); + hdd_debug("Name = [%s] Value = [%u]", + CFG_MAWC_NLO_EXP_BACKOFF_RATIO_NAME, + hdd_ctx->config->mawc_nlo_exp_backoff_ratio); + hdd_debug("Name = [%s] Value = [%u]", + CFG_MAWC_NLO_INIT_SCAN_INTERVAL_NAME, + hdd_ctx->config->mawc_nlo_init_scan_interval); + hdd_debug("Name = [%s] Value = [%u]", + CFG_MAWC_NLO_MAX_SCAN_INTERVAL_NAME, + hdd_ctx->config->mawc_nlo_max_scan_interval); + hdd_debug("Name = [ssdp] Value = [%u] ", hdd_ctx->config->ssdp); + hdd_cfg_print_runtime_pm(hdd_ctx); +#ifdef FEATURE_WLAN_RA_FILTERING + hdd_debug("Name = [RArateLimitInterval] Value = [%u] ", + hdd_ctx->config->RArateLimitInterval); + hdd_debug("Name = [IsRArateLimitEnabled] Value = [%u] ", + hdd_ctx->config->IsRArateLimitEnabled); +#endif + hdd_debug("Name = [nNeighborLookupRssiThreshold] Value = [%u] ", + hdd_ctx->config->nNeighborLookupRssiThreshold); + hdd_debug("Name = [%s] Value = [%d] ", + CFG_5G_RSSI_THRESHOLD_OFFSET_NAME, + hdd_ctx->config->rssi_thresh_offset_5g); + hdd_debug("Name = [delay_before_vdev_stop] Value = [%u] ", + hdd_ctx->config->delay_before_vdev_stop); + hdd_debug("Name = [nOpportunisticThresholdDiff] Value = [%u] ", + hdd_ctx->config->nOpportunisticThresholdDiff); + hdd_debug("Name = [nRoamRescanRssiDiff] Value = [%u] ", + hdd_ctx->config->nRoamRescanRssiDiff); + hdd_debug("Name = [nNeighborScanMinChanTime] Value = [%u] ", + hdd_ctx->config->nNeighborScanMinChanTime); + hdd_debug("Name = [nNeighborScanMaxChanTime] Value = [%u] ", + hdd_ctx->config->nNeighborScanMaxChanTime); + hdd_debug("Name = [nMaxNeighborRetries] Value = [%u] ", + hdd_ctx->config->nMaxNeighborReqTries); + hdd_debug("Name = [nNeighborScanPeriod] Value = [%u] ", + hdd_ctx->config->nNeighborScanPeriod); + hdd_debug("Name = [n_neighbor_scan_min_period] Value = [%u] ", + hdd_ctx->config->neighbor_scan_min_period); + hdd_debug("Name = [nNeighborScanResultsRefreshPeriod] Value = [%u] ", + hdd_ctx->config->nNeighborResultsRefreshPeriod); + hdd_debug("Name = [nEmptyScanRefreshPeriod] Value = [%u] ", + hdd_ctx->config->nEmptyScanRefreshPeriod); + hdd_debug("Name = [nRoamBmissFirstBcnt] Value = [%u] ", + hdd_ctx->config->nRoamBmissFirstBcnt); + hdd_debug("Name = [nRoamBmissFinalBcnt] Value = [%u] ", + hdd_ctx->config->nRoamBmissFinalBcnt); + hdd_debug("Name = [nRoamBeaconRssiWeight] Value = [%u] ", + hdd_ctx->config->nRoamBeaconRssiWeight); + hdd_debug("Name = [allowDFSChannelRoam] Value = [%u] ", + hdd_ctx->config->allowDFSChannelRoam); + hdd_debug("Name = [nhi_rssi_scan_max_count] Value = [%u] ", + hdd_ctx->config->nhi_rssi_scan_max_count); + hdd_debug("Name = [nhi_rssi_scan_rssi_delta] Value = [%u] ", + hdd_ctx->config->nhi_rssi_scan_rssi_delta); + hdd_debug("Name = [nhi_rssi_scan_delay] Value = [%u] ", + hdd_ctx->config->nhi_rssi_scan_delay); + hdd_debug("Name = [nhi_rssi_scan_rssi_ub] Value = [%u] ", + hdd_ctx->config->nhi_rssi_scan_rssi_ub); + hdd_debug("Name = [burstSizeDefinition] Value = [0x%x] ", + hdd_ctx->config->burstSizeDefinition); + hdd_debug("Name = [tsInfoAckPolicy] Value = [0x%x] ", + hdd_ctx->config->tsInfoAckPolicy); + hdd_debug("Name = [bSingleTidRc] Value = [%u] ", + hdd_ctx->config->bSingleTidRc); + hdd_debug("Name = [gAddTSWhenACMIsOff] Value = [%u] ", + hdd_ctx->config->AddTSWhenACMIsOff); + hdd_debug("Name = [gStaKeepAlivePeriod] Value = [%u] ", + hdd_ctx->config->infraStaKeepAlivePeriod); + hdd_debug("Name = [BandCapability] Value = [%u] ", + hdd_ctx->config->nBandCapability); + hdd_debug("Name = [teleBcnWakeupEnable] Value = [%u] ", + hdd_ctx->config->teleBcnWakeupEn); + hdd_debug("Name = [maxListenInterval] Value = [%u] ", + hdd_ctx->config->nTeleBcnMaxListenInterval); + hdd_debug("Name = [gEnableBypass11d] Value = [%u] ", + hdd_ctx->config->enableBypass11d); + hdd_debug("Name = [gEnableDFSChnlScan] Value = [%u] ", + hdd_ctx->config->enableDFSChnlScan); + hdd_debug("Name = [honour_nl_scan_policy_flags] Value = [%u] ", + hdd_ctx->config->honour_nl_scan_policy_flags); + hdd_debug("Name = [wake_lock_in_user_scan] Value = [%u] ", + hdd_ctx->config->wake_lock_in_user_scan); + hdd_debug("Name = [gEnableDFSPnoChnlScan] Value = [%u] ", + hdd_ctx->config->enable_dfs_pno_chnl_scan); + hdd_debug("Name = [gReportMaxLinkSpeed] Value = [%u] ", + hdd_ctx->config->reportMaxLinkSpeed); + hdd_debug("Name = [thermalMitigationEnable] Value = [%u] ", + hdd_ctx->config->thermalMitigationEnable); + hdd_debug("Name = [gVhtChannelWidth] value = [%u]", + hdd_ctx->config->vhtChannelWidth); + hdd_debug("Name = [enableFirstScan2GOnly] Value = [%u] ", + hdd_ctx->config->enableFirstScan2GOnly); + hdd_debug("Name = [skipDfsChnlInP2pSearch] Value = [%u] ", + hdd_ctx->config->skipDfsChnlInP2pSearch); + hdd_debug("Name = [ignoreDynamicDtimInP2pMode] Value = [%u] ", + hdd_ctx->config->ignoreDynamicDtimInP2pMode); + hdd_debug("Name = [enableRxSTBC] Value = [%u] ", + hdd_ctx->config->enableRxSTBC); + hdd_debug("Name = [gEnableSSR] Value = [%u] ", + hdd_ctx->config->enableSSR); + hdd_debug("Name = [gEnableDataStallDetection] Value = [%u] ", + hdd_ctx->config->enable_data_stall_det); + hdd_debug("Name = [gEnableVhtFor24GHzBand] Value = [%u] ", + hdd_ctx->config->enableVhtFor24GHzBand); + hdd_debug("Name = [gGoLinkMonitorPeriod] Value = [%u]", + hdd_ctx->config->goLinkMonitorPeriod); + hdd_debug("Name = [gApLinkMonitorPeriod] Value = [%u]", + hdd_ctx->config->apLinkMonitorPeriod); + hdd_debug("Name = [gGoKeepAlivePeriod] Value = [%u]", + hdd_ctx->config->goKeepAlivePeriod); + hdd_debug("Name = [gApKeepAlivePeriod]Value = [%u]", + hdd_ctx->config->apKeepAlivePeriod); + hdd_debug("Name = [max_amsdu_num] Value = [%u] ", + hdd_ctx->config->max_amsdu_num); + hdd_debug("Name = [nSelect5GHzMargin] Value = [%u] ", + hdd_ctx->config->nSelect5GHzMargin); + hdd_debug("Name = [gCoalesingInIBSS] Value = [%u] ", + hdd_ctx->config->isCoalesingInIBSSAllowed); + hdd_debug("Name = [gIbssATIMWinSize] Value = [%u] ", + hdd_ctx->config->ibssATIMWinSize); + hdd_debug("Name = [gIbssIsPowerSaveAllowed] Value = [%u] ", + hdd_ctx->config->isIbssPowerSaveAllowed); + hdd_debug("Name = [gIbssIsPowerCollapseAllowed] Value = [%u] ", + hdd_ctx->config->isIbssPowerCollapseAllowed); + hdd_debug("Name = [gIbssAwakeOnTxRx] Value = [%u] ", + hdd_ctx->config->isIbssAwakeOnTxRx); + hdd_debug("Name = [gIbssInactivityTime] Value = [%u] ", + hdd_ctx->config->ibssInactivityCount); + hdd_debug("Name = [gIbssTxSpEndInactivityTime] Value = [%u] ", + hdd_ctx->config->ibssTxSpEndInactivityTime); + hdd_debug("Name = [gIbssPsWarmupTime] Value = [%u] ", + hdd_ctx->config->ibssPsWarmupTime); + hdd_debug("Name = [gIbssPs1RxChainInAtim] Value = [%u] ", + hdd_ctx->config->ibssPs1RxChainInAtimEnable); + hdd_debug("Name = [fDfsPhyerrFilterOffload] Value = [%u] ", + hdd_ctx->config->fDfsPhyerrFilterOffload); + hdd_debug("Name = [gIgnorePeerErpInfo] Value = [%u] ", + hdd_ctx->config->ignore_peer_erp_info); +#ifdef IPA_OFFLOAD + hdd_debug("Name = [gIPAConfig] Value = [0x%x] ", + hdd_ctx->config->IpaConfig); + hdd_debug("Name = [gIPADescSize] Value = [%u] ", + hdd_ctx->config->IpaDescSize); + hdd_debug("Name = [IpaHighBandwidthMbpsg] Value = [%u] ", + hdd_ctx->config->IpaHighBandwidthMbps); + hdd_debug("Name = [IpaMediumBandwidthMbps] Value = [%u] ", + hdd_ctx->config->IpaMediumBandwidthMbps); + hdd_debug("Name = [IpaLowBandwidthMbps] Value = [%u] ", + hdd_ctx->config->IpaLowBandwidthMbps); +#endif + hdd_debug("Name = [gEnableOverLapCh] Value = [%u] ", + hdd_ctx->config->gEnableOverLapCh); + hdd_debug("Name = [gMaxOffloadPeers] Value = [%u] ", + hdd_ctx->config->apMaxOffloadPeers); + hdd_debug("Name = [gMaxOffloadReorderBuffs] value = [%u] ", + hdd_ctx->config->apMaxOffloadReorderBuffs); + hdd_debug("Name = [%s] Value = [%d]", + CFG_ENABLE_CCK_TX_FIR_OVERRIDE_NAME, + hdd_ctx->config->enable_cck_tx_fir_override); + hdd_debug("Name = [gAllowDFSChannelRoam] Value = [%u] ", + hdd_ctx->config->allowDFSChannelRoam); + hdd_debug("Name = [gMaxConcurrentActiveSessions] Value = [%u] ", + hdd_ctx->config->gMaxConcurrentActiveSessions); + +#ifdef MSM_PLATFORM + hdd_debug("Name = [gBusBandwidthHighThreshold] Value = [%u] ", + hdd_ctx->config->busBandwidthHighThreshold); + hdd_debug("Name = [gBusBandwidthMediumThreshold] Value = [%u] ", + hdd_ctx->config->busBandwidthMediumThreshold); + hdd_debug("Name = [gBusBandwidthLowThreshold] Value = [%u] ", + hdd_ctx->config->busBandwidthLowThreshold); + hdd_debug("Name = [gbusBandwidthComputeInterval] Value = [%u] ", + hdd_ctx->config->busBandwidthComputeInterval); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_ENABLE_TCP_LIMIT_OUTPUT, + hdd_ctx->config->enable_tcp_limit_output); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_ENABLE_TCP_ADV_WIN_SCALE, + hdd_ctx->config->enable_tcp_adv_win_scale); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_ENABLE_TCP_DELACK, + hdd_ctx->config->enable_tcp_delack); + hdd_debug("Name = [gTcpDelAckThresholdHigh] Value = [%u] ", + hdd_ctx->config->tcpDelackThresholdHigh); + hdd_debug("Name = [gTcpDelAckThresholdLow] Value = [%u] ", + hdd_ctx->config->tcpDelackThresholdLow); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_TCP_DELACK_TIMER_COUNT, + hdd_ctx->config->tcp_delack_timer_count); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_NAME, + hdd_ctx->config->tcp_tx_high_tput_thres); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_PERIODIC_STATS_DISPLAY_TIME_NAME, + hdd_ctx->config->periodic_stats_disp_time); + hdd_debug("Name = [%s] Value = [%u] ", + CFG_ENABLE_TCP_PARAM_UPDATE, + hdd_ctx->config->enable_tcp_param_update); +#endif + + hdd_debug("Name = [gIgnoreCAC] Value = [%u] ", + hdd_ctx->config->ignoreCAC); + hdd_debug("Name = [gSapPreferredChanLocation] Value = [%u] ", + hdd_ctx->config->gSapPreferredChanLocation); + hdd_debug("Name = [gDisableDfsJapanW53] Value = [%u] ", + hdd_ctx->config->gDisableDfsJapanW53); + + hdd_green_ap_print_config(hdd_ctx); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + hdd_debug("Name = [isRoamOffloadEnabled] Value = [%u]", + hdd_ctx->config->isRoamOffloadEnabled); +#endif + +#ifdef WLAN_FEATURE_LPSS + hdd_debug("Name = [gEnableLpassSupport] Value = [%u] ", + hdd_ctx->config->enable_lpass_support); +#endif + + hdd_debug("Name = [gEnableSelfRecovery] Value = [%u]", + hdd_ctx->config->enableSelfRecovery); + + hdd_debug("Name = [gEnableSapSuspend] Value = [%u]", + hdd_ctx->config->enable_sap_suspend); + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + hdd_debug("Name = [gExtWoWgotoSuspend] Value = [%u]", + hdd_ctx->config->extWowGotoSuspend); + + hdd_debug("Name = [gExtWowApp1WakeupPinNumber] Value = [%u]", + hdd_ctx->config->extWowApp1WakeupPinNumber); + + hdd_debug("Name = [gExtWowApp2WakeupPinNumber] Value = [%u]", + hdd_ctx->config->extWowApp2WakeupPinNumber); + + hdd_debug("Name = [gExtWoWApp2KAInitPingInterval] Value = [%u]", + hdd_ctx->config->extWowApp2KAInitPingInterval); + + hdd_debug("Name = [gExtWoWApp2KAMinPingInterval] Value = [%u]", + hdd_ctx->config->extWowApp2KAMinPingInterval); + + hdd_debug("Name = [gExtWoWApp2KAMaxPingInterval] Value = [%u]", + hdd_ctx->config->extWowApp2KAMaxPingInterval); + + hdd_debug("Name = [gExtWoWApp2KAIncPingInterval] Value = [%u]", + hdd_ctx->config->extWowApp2KAIncPingInterval); + + hdd_debug("Name = [gExtWoWApp2TcpSrcPort] Value = [%u]", + hdd_ctx->config->extWowApp2TcpSrcPort); + + hdd_debug("Name = [gExtWoWApp2TcpDstPort] Value = [%u]", + hdd_ctx->config->extWowApp2TcpDstPort); + + hdd_debug("Name = [gExtWoWApp2TcpTxTimeout] Value = [%u]", + hdd_ctx->config->extWowApp2TcpTxTimeout); + + hdd_debug("Name = [gExtWoWApp2TcpRxTimeout] Value = [%u]", + hdd_ctx->config->extWowApp2TcpRxTimeout); +#endif + +#ifdef DHCP_SERVER_OFFLOAD + hdd_debug("Name = [gDHCPServerOffloadEnable] Value = [%u]", + hdd_ctx->config->enableDHCPServerOffload); + hdd_debug("Name = [gDHCPMaxNumClients] Value = [%u]", + hdd_ctx->config->dhcpMaxNumClients); + hdd_debug("Name = [gDHCPServerIP] Value = [%s]", + hdd_ctx->config->dhcpServerIP); +#endif + + hdd_debug("Name = [gEnableDumpCollect] Value = [%u]", + hdd_ctx->config->is_ramdump_enabled); + + hdd_debug("Name = [gP2PListenDeferInterval] Value = [%u]", + hdd_ctx->config->p2p_listen_defer_interval); + hdd_debug("Name = [is_ps_enabled] value = [%d]", + hdd_ctx->config->is_ps_enabled); + hdd_debug("Name = [tso_enable] value = [%d]", + hdd_ctx->config->tso_enable); + hdd_debug("Name = [LROEnable] value = [%d]", + hdd_ctx->config->lro_enable); + hdd_debug("Name = [%s] value = [%d]", + CFG_MAX_MSDUS_PER_RXIND_NAME, + hdd_ctx->config->max_msdus_per_rxinorderind); + hdd_debug("Name = [active_mode_offload] value = [%d]", + hdd_ctx->config->active_mode_offload); + hdd_debug("Name = [gEnableNAPI] value = [%d]", + hdd_ctx->napi_enable); + hdd_debug("Name = [gfine_time_meas_cap] value = [%u]", + hdd_ctx->config->fine_time_meas_cap); +#ifdef WLAN_FEATURE_FASTPATH + hdd_debug("Name = [fastpath_enable] Value = [%u]", + hdd_ctx->config->fastpath_enable); +#endif + hdd_debug("Name = [max_scan_count] value = [%d]", + hdd_ctx->config->max_scan_count); + hdd_debug("Name = [%s] value = [%d]", + CFG_RX_MODE_NAME, hdd_ctx->config->rx_mode); + hdd_debug("Name = [%s] value = [%d]", + CFG_CE_SERVICE_MAX_YIELD_TIME_NAME, + hdd_ctx->config->ce_service_max_yield_time); + hdd_debug("Name = [%s] value = [%d]", + CFG_CE_SERVICE_MAX_RX_IND_FLUSH_NAME, + hdd_ctx->config->ce_service_max_rx_ind_flush); + hdd_debug("Name = [%s] Value = [%u]", + CFG_CE_CLASSIFY_ENABLE_NAME, + hdd_ctx->config->ce_classify_enabled); + hdd_debug("Name = [%s] value = [%u]", + CFG_DUAL_MAC_FEATURE_DISABLE, + hdd_ctx->config->dual_mac_feature_disable); + hdd_debug("Name = [%s] Value = [%s]", + CFG_DBS_SCAN_SELECTION_NAME, + hdd_ctx->config->dbs_scan_selection); + hdd_debug("Name = [%s] value = [%u]", + CFG_STA_SAP_SCC_ON_DFS_CHAN, + hdd_ctx->config->sta_sap_scc_on_dfs_chan); + hdd_debug("Name = [%s] value = [%u]", + CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN, + hdd_ctx->config->sta_sap_scc_on_lte_coex_chan); +#ifdef FEATURE_WLAN_SCAN_PNO + hdd_debug("Name = [%s] Value = [%u]", + CFG_PNO_CHANNEL_PREDICTION_NAME, + hdd_ctx->config->pno_channel_prediction); + hdd_debug("Name = [%s] Value = [%u]", + CFG_TOP_K_NUM_OF_CHANNELS_NAME, + hdd_ctx->config->top_k_num_of_channels); + hdd_debug("Name = [%s] Value = [%u]", + CFG_STATIONARY_THRESHOLD_NAME, + hdd_ctx->config->stationary_thresh); + hdd_debug("Name = [%s] Value = [%u]", + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME, + hdd_ctx->config->channel_prediction_full_scan); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME, + hdd_ctx->config->pnoscan_adaptive_dwell_mode); +#endif + hdd_debug("Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_ENABLE, + hdd_ctx->config->early_stop_scan_enable); + hdd_debug("Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD, + hdd_ctx->config->early_stop_scan_min_threshold); + hdd_debug("Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD, + hdd_ctx->config->early_stop_scan_max_threshold); + hdd_debug("Name = [%s] Value = [%d]", + CFG_FIRST_SCAN_BUCKET_THRESHOLD_NAME, + hdd_ctx->config->first_scan_bucket_threshold); + hdd_debug("Name = [%s] Value = [%u]", + CFG_HT_MPDU_DENSITY_NAME, + hdd_ctx->config->ht_mpdu_density); + hdd_debug("Name = [%s] value = [%d]", + CFG_MARK_INDOOR_AS_DISABLE_NAME, + hdd_ctx->config->force_ssc_disable_indoor_channel); + +#ifdef FEATURE_LFR_SUBNET_DETECTION + hdd_debug("Name = [%s] Value = [%d]", + CFG_ENABLE_LFR_SUBNET_DETECTION, + hdd_ctx->config->enable_lfr_subnet_detection); +#endif + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD, + hdd_ctx->config->roam_dense_traffic_thresh); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_DENSE_RSSI_THRE_OFFSET, + hdd_ctx->config->roam_dense_rssi_thresh_offset); + hdd_debug("Name = [%s] Value = [%u]", + CFG_IGNORE_PEER_HT_MODE_NAME, + hdd_ctx->config->ignore_peer_ht_opmode); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_NAME, + hdd_ctx->config->enable_sap_vendor_vht); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_FATAL_EVENT_TRIGGER, + hdd_ctx->config->enable_fatal_event); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_DENSE_MIN_APS, + hdd_ctx->config->roam_dense_min_aps); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD_NAME, + hdd_ctx->config->roam_bg_scan_bad_rssi_thresh); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_BG_SCAN_CLIENT_BITMAP_NAME, + hdd_ctx->config->roam_bg_scan_client_bitmap); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G_NAME, + hdd_ctx->config->roam_bad_rssi_thresh_offset_2g); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_HO_DELAY_FOR_RX_NAME, + hdd_ctx->config->ho_delay_for_rx); + hdd_debug("Name = [%s] Value = [%u]", + CFG_MIN_DELAY_BTW_ROAM_SCAN_NAME, + hdd_ctx->config->min_delay_btw_roam_scans); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_SCAN_TRIGGER_REASON_BITMASK_NAME, + hdd_ctx->config->roam_trigger_reason_bitmask); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_SCAN_SCAN_POLICY_NAME, + hdd_ctx->config->roaming_scan_policy); + hdd_debug("Name = [%s] Value = [%u]", + CFG_MIN_REST_TIME_NAME, + hdd_ctx->config->min_rest_time_conc); + hdd_debug("Name = [%s] Value = [%u]", + CFG_IDLE_TIME_NAME, + hdd_ctx->config->idle_time_conc); + hdd_debug("Name = [%s] Value = [%d]", + CFG_BUG_ON_REINIT_FAILURE_NAME, + hdd_ctx->config->bug_on_reinit_failure); + hdd_debug("Name = [%s] Value = [%u]", + CFG_INTERFACE_CHANGE_WAIT_NAME, + hdd_ctx->config->iface_change_wait_time); + + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_EDCA_INI_NAME, + hdd_ctx->config->enable_edca_params); + + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_VO_CWMIN_VALUE_NAME, + hdd_ctx->config->edca_vo_cwmin); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_VI_CWMIN_VALUE_NAME, + hdd_ctx->config->edca_vi_cwmin); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_BK_CWMIN_VALUE_NAME, + hdd_ctx->config->edca_bk_cwmin); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_BE_CWMIN_VALUE_NAME, + hdd_ctx->config->edca_be_cwmin); + + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_VO_CWMAX_VALUE_NAME, + hdd_ctx->config->edca_vo_cwmax); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_VI_CWMAX_VALUE_NAME, + hdd_ctx->config->edca_vi_cwmax); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_BK_CWMAX_VALUE_NAME, + hdd_ctx->config->edca_bk_cwmax); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_BE_CWMAX_VALUE_NAME, + hdd_ctx->config->edca_be_cwmax); + + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_VO_AIFS_VALUE_NAME, + hdd_ctx->config->edca_vo_aifs); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_VI_AIFS_VALUE_NAME, + hdd_ctx->config->edca_vi_aifs); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_BK_AIFS_VALUE_NAME, + hdd_ctx->config->edca_bk_aifs); + hdd_debug("Name = [%s] Value = [%u]", + CFG_EDCA_BE_AIFS_VALUE_NAME, + hdd_ctx->config->edca_be_aifs); + + hdd_debug("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_VO_NAME, + hdd_ctx->config->tx_sched_wrr_vo); + hdd_debug("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_VI_NAME, + hdd_ctx->config->tx_sched_wrr_vi); + hdd_debug("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_BK_NAME, + hdd_ctx->config->tx_sched_wrr_bk); + hdd_debug("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_BE_NAME, + hdd_ctx->config->tx_sched_wrr_be); + + hdd_cfg_print_dp_trace_params(hdd_ctx); + + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME, + hdd_ctx->config->scan_adaptive_dwell_mode); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_SCAN_DWELL_MODE_NC_NAME, + hdd_ctx->config->scan_adaptive_dwell_mode_nc); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME, + hdd_ctx->config->roamscan_adaptive_dwell_mode); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME, + hdd_ctx->config->extscan_adaptive_dwell_mode); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME, + hdd_ctx->config->adaptive_dwell_mode_enabled); + hdd_debug("Name = [%s] Value = [%u]", + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME, + hdd_ctx->config->global_adapt_dwelltime_mode); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_LPF_WEIGHT_NAME, + hdd_ctx->config->adapt_dwell_lpf_weight); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_PASMON_INTVAL_NAME, + hdd_ctx->config->adapt_dwell_passive_mon_intval); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_WIFI_THRESH_NAME, + hdd_ctx->config->adapt_dwell_wifi_act_threshold); + hdd_debug("Name = [%s] value = [%u]", + CFG_SUB_20_CHANNEL_WIDTH_NAME, + hdd_ctx->config->enable_sub_20_channel_width); + hdd_debug("Name = [%s] Value = [%u]", + CFG_TGT_GTX_USR_CFG_NAME, + hdd_ctx->config->tgt_gtx_usr_cfg); + hdd_debug("Name = [%s] Value = [%u]", + CFG_SAP_MAX_INACTIVITY_OVERRIDE_NAME, + hdd_ctx->config->sap_max_inactivity_override); + hdd_ndp_print_ini_config(hdd_ctx); + hdd_debug("Name = [%s] Value = [%s]", + CFG_RM_CAPABILITY_NAME, + hdd_ctx->config->rm_capability); + hdd_debug("Name = [%s] Value = [%d]", + CFG_SAP_FORCE_11N_FOR_11AC_NAME, + hdd_ctx->config->sap_force_11n_for_11ac); + hdd_debug("Name = [%s] Value = [%d]", + CFG_GO_FORCE_11N_FOR_11AC_NAME, + hdd_ctx->config->go_force_11n_for_11ac); + hdd_debug("Name = [%s] Value = [%d]", + CFG_APF_PACKET_FILTER_OFFLOAD, + hdd_ctx->config->apf_packet_filter_enable); + hdd_debug("Name = [%s] Value = [%u]", + CFG_TDLS_ENABLE_DEFER_TIMER, + hdd_ctx->config->tdls_enable_defer_time); + hdd_debug("Name = [%s] Value = [%d]", + CFG_FILTER_MULTICAST_REPLAY_NAME, + hdd_ctx->config->multicast_replay_filter); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_GO_CTS2SELF_FOR_STA, + hdd_ctx->config->enable_go_cts2self_for_sta); + hdd_debug("Name = [%s] Value = [%u]", + CFG_CRASH_FW_TIMEOUT_NAME, + hdd_ctx->config->fw_timeout_crash); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ACTIVE_UC_APF_MODE_NAME, + hdd_ctx->config->active_uc_apf_mode); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ACTIVE_MC_BC_APF_MODE_NAME, + hdd_ctx->config->active_mc_bc_apf_mode); + hdd_debug("Name = [%s] Value = [%d]", + CFG_SAP_INTERNAL_RESTART_NAME, + hdd_ctx->config->sap_internal_restart); + hdd_debug("Name = [%s] Value = [%d]", + CFG_ACS_WITH_MORE_PARAM_NAME, + hdd_ctx->config->acs_with_more_param); + hdd_debug("Name = [%s] Value = [%u]", + CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME, + hdd_ctx->config->auto_pwr_save_fail_mode); + hdd_debug("Name = [%s] Value = [%d]", + CFG_RESTART_BEACONING_ON_CH_AVOID_NAME, + hdd_ctx->config->restart_beaconing_on_chan_avoid_event); + + hdd_per_roam_print_ini_config(hdd_ctx); + hdd_he_print_ini_config(hdd_ctx); + hdd_twt_print_ini_config(hdd_ctx); + hdd_debug("Name = [%s] Value = [%d]", + CFG_ARP_AC_CATEGORY, + hdd_ctx->config->arp_ac_category); + hdd_debug("Name = [%s] Value = [%u]", + CFG_SCAN_BACKOFF_MULTIPLIER_NAME, + hdd_ctx->config->scan_backoff_multiplier); + hdd_debug("Name = [%s] Value = [%d]", + CFG_EXTERNAL_ACS_POLICY, + hdd_ctx->config->external_acs_policy); + hdd_debug("Name = [%s] value = [%u]", + CFG_DROPPED_PKT_DISCONNECT_TH_NAME, + hdd_ctx->config->pkt_err_disconn_th); + + hdd_cfg_print_ie_whitelist_attrs(hdd_ctx); + + hdd_debug("Name = [%s] value = [%u]", + CFG_FORCE_1X1_NAME, + hdd_ctx->config->is_force_1x1_enable); + hdd_debug("Name = [%s] Value = %u", + CFG_ENABLE_CONNECTED_SCAN_NAME, + hdd_ctx->config->enable_connected_scan); + hdd_debug("Name = [%s] value = [%u]", + CFG_11B_NUM_TX_CHAIN_NAME, + hdd_ctx->config->num_11b_tx_chains); + hdd_debug("Name = [%s] value = [%u]", + CFG_11AG_NUM_TX_CHAIN_NAME, + hdd_ctx->config->num_11ag_tx_chains); + hdd_debug("Name = [%s] value = [%u]", + CFG_ITO_REPEAT_COUNT_NAME, + hdd_ctx->config->ito_repeat_count); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_DISALLOW_DURATION_NAME, + hdd_ctx->config->disallow_duration); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_RSSI_CHANNEL_PENALIZATION_NAME, + hdd_ctx->config->rssi_channel_penalization); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_NUM_DISALLOWED_APS_NAME, + hdd_ctx->config->num_disallowed_aps); + hdd_debug("Name = [%s] value = [%u]", + CFG_LPRx_NAME, + hdd_ctx->config->enable_lprx); + hdd_debug("Name = [%s] value = [%u]", + CFG_UPPER_BRSSI_THRESH_NAME, + hdd_ctx->config->upper_brssi_thresh); + hdd_debug("Name = [%s] value = [%u]", + CFG_LOWER_BRSSI_THRESH_NAME, + hdd_ctx->config->lower_brssi_thresh); + hdd_debug("Name = [%s] value = [%u]", + CFG_DTIM_1CHRX_ENABLE_NAME, + hdd_ctx->config->enable_dtim_1chrx); + hdd_debug("Name = [%s] value = [%u]", + CFG_RANDOMIZE_NDI_MAC_NAME, + hdd_ctx->config->is_ndi_mac_randomized); + hdd_debug("Name = [%s] value = [%u]", + CFG_DOT11P_MODE_NAME, + hdd_ctx->config->dot11p_mode); + hdd_debug("Name = [%s] value = [%u]", + CFG_PREVENT_LINK_DOWN_NAME, + hdd_ctx->config->prevent_link_down); + hdd_debug("Name = [%s] value = [%u]", + CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_NAME, + hdd_ctx->config->chan_switch_hostapd_rate_enabled); + hdd_debug("Name = [%s] value = [%u]", + CFG_IS_BSSID_HINT_PRIORITY_NAME, + hdd_ctx->config->is_bssid_hint_priority); + hdd_debug("Name = [%s] value = [%u]", + CFG_RSSI_WEIGHTAGE_NAME, + hdd_ctx->config->rssi_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_HT_CAPABILITY_WEIGHTAGE_NAME, + hdd_ctx->config->ht_caps_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_VHT_CAPABILITY_WEIGHTAGE_NAME, + hdd_ctx->config->vht_caps_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_HE_CAPABILITY_WEIGHTAGE_NAME, + hdd_ctx->config->he_caps_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_CHAN_WIDTH_WEIGHTAGE_NAME, + hdd_ctx->config->chan_width_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_CHAN_BAND_WEIGHTAGE_NAME, + hdd_ctx->config->chan_band_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_NSS_WEIGHTAGE_NAME, + hdd_ctx->config->nss_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_BEAMFORMING_CAP_WEIGHTAGE_NAME, + hdd_ctx->config->beamforming_cap_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_PCL_WEIGHT_WEIGHTAGE_NAME, + hdd_ctx->config->pcl_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_CHANNEL_CONGESTION_WEIGHTAGE_NAME, + hdd_ctx->config->channel_congestion_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_OCE_WAN_WEIGHTAGE_NAME, + hdd_ctx->config->oce_wan_weightage); + hdd_debug("Name = [%s] value = [%u]", + CFG_BAND_WIDTH_WEIGHT_PER_INDEX_NAME, + hdd_ctx->config->bandwidth_weight_per_index); + hdd_debug("Name = [%s] value = [%u]", + CFG_NSS_WEIGHT_PER_INDEX_NAME, + hdd_ctx->config->nss_weight_per_index); + hdd_debug("Name = [%s] value = [%u]", + CFG_BAND_WEIGHT_PER_INDEX_NAME, + hdd_ctx->config->band_weight_per_index); + hdd_debug("Name = [%s] value = [%u]", + CFG_BEST_RSSI_THRESHOLD_NAME, + hdd_ctx->config->best_rssi_threshold); + hdd_debug("Name = [%s] value = [%u]", + CFG_GOOD_RSSI_THRESHOLD_NAME, + hdd_ctx->config->good_rssi_threshold); + hdd_debug("Name = [%s] value = [%u]", + CFG_BAD_RSSI_THRESHOLD_NAME, + hdd_ctx->config->bad_rssi_threshold); + hdd_debug("Name = [%s] value = [%u]", + CFG_GOOD_RSSI_PCNT_NAME, + hdd_ctx->config->good_rssi_pcnt); + hdd_debug("Name = [%s] value = [%u]", + CFG_BAD_RSSI_PCNT_NAME, + hdd_ctx->config->bad_rssi_pcnt); + hdd_debug("Name = [%s] value = [%u]", + CFG_GOOD_RSSI_BUCKET_SIZE_NAME, + hdd_ctx->config->good_rssi_bucket_size); + hdd_debug("Name = [%s] value = [%u]", + CFG_BAD_RSSI_BUCKET_SIZE_NAME, + hdd_ctx->config->bad_rssi_bucket_size); + hdd_debug("Name = [%s] value = [%u]", + CFG_RSSI_PERF_5G_THRESHOLD_NAME, + hdd_ctx->config->rssi_pref_5g_rssi_thresh); + hdd_debug("Name = [%s] value = [%u]", + CFG_ESP_QBSS_SLOTS_NAME, + hdd_ctx->config->num_esp_qbss_slots); + hdd_debug("Name = [%s] value = [%u]", + CFG_ESP_QBSS_SCORE_IDX3_TO_0_NAME, + hdd_ctx->config->esp_qbss_score_slots3_to_0); + hdd_debug("Name = [%s] value = [%u]", + CFG_ESP_QBSS_SCORE_IDX7_TO_4_NAME, + hdd_ctx->config->esp_qbss_score_slots7_to_4); + hdd_debug("Name = [%s] value = [%u]", + CFG_ESP_QBSS_SCORE_IDX11_TO_8_NAME, + hdd_ctx->config->esp_qbss_score_slots11_to_8); + hdd_debug("Name = [%s] value = [%u]", + CFG_ESP_QBSS_SCORE_IDX15_TO_12_NAME, + hdd_ctx->config->esp_qbss_score_slots15_to_12); + hdd_debug("Name = [%s] value = [%u]", + CFG_ENABLE_SCORING_FOR_ROAM_NAME, + hdd_ctx->config->enable_scoring_for_roam); + + hdd_wlm_cfg_log(hdd_ctx); + + hdd_debug("Name = [%s] value = [%u]", + CFG_OCE_WAN_SLOTS_NAME, + hdd_ctx->config->num_oce_wan_slots); + hdd_debug("Name = [%s] value = [%u]", + CFG_OCE_WAN_SCORE_IDX3_TO_0_NAME, + hdd_ctx->config->oce_wan_score_slots3_to_0); + hdd_debug("Name = [%s] value = [%u]", + CFG_OCE_WAN_SCORE_IDX7_TO_4_NAME, + hdd_ctx->config->oce_wan_score_slots7_to_4); + hdd_debug("Name = [%s] value = [%u]", + CFG_OCE_WAN_SCORE_IDX11_TO_8_NAME, + hdd_ctx->config->oce_wan_score_slots11_to_8); + hdd_debug("Name = [%s] value = [%u]", + CFG_OCE_WAN_SCORE_IDX15_TO_12_NAME, + hdd_ctx->config->oce_wan_score_slots15_to_12); + hdd_debug("Name = [%s] Value = [%u]", + CFG_FORCE_RSNE_OVERRIDE_NAME, + hdd_ctx->config->force_rsne_override); + hdd_debug("Name = [%s] value = [0x%x]", CFG_VC_MODE_BITMAP, + hdd_ctx->config->vc_mode_cfg_bitmap); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_PHY_REG, + hdd_ctx->config->enable_phy_reg_retention); + hdd_debug("Name = [btm_offload_config] value = [0x%x]", + hdd_ctx->config->btm_offload_config); + hdd_cfg_print_sae(hdd_ctx); + hdd_debug("Name = [btm_solicited_timeout] value = [0x%x]", + hdd_ctx->config->btm_solicited_timeout); + hdd_debug("Name = [btm_max_attempt_cnt] value = [0x%x]", + hdd_ctx->config->btm_max_attempt_cnt); + hdd_debug("Name = [btm_sticky_time] value = [0x%x]", + hdd_ctx->config->btm_sticky_time); + hdd_debug("Name = [%s] value = [%d]", + CFG_ENABLE_GCMP_NAME, + hdd_ctx->config->gcmp_enabled); + hdd_debug("Name = [%s] value = [%d]", + CFG_DTIM_SELECTION_DIVERSITY_NAME, + hdd_ctx->config->enable_dtim_selection_diversity); + hdd_debug("Name = [%s] value = [%d]", + CFG_TX_SCH_DELAY_NAME, + hdd_ctx->config->enable_tx_sch_delay); + + hdd_cfg_print_11k_offload_params(hdd_ctx); + hdd_debug("Name = [%s] value = [0x%x]", + CFG_CHANNEL_SELECT_LOGIC_CONC_NAME, + hdd_ctx->config->channel_select_logic_conc); + + hdd_nud_cfg_print(hdd_ctx); + hdd_debug("Name = [%s] value = [0x%x]", + CFG_ENABLE_UNIT_TEST_FRAMEWORK_NAME, + hdd_ctx->config->is_unit_test_framework_enabled); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_FT_OPEN_ENABLE_NAME, + hdd_ctx->config->enable_ftopen); + + hdd_debug("Name = [%s] value = [0x%x]", + CFG_ENABLE_SECONDARY_RATE_NAME, + hdd_ctx->config->enable_secondary_rate); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ROAM_FORCE_RSSI_TRIGGER_NAME, + hdd_ctx->config->roam_force_rssi_trigger); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_PEER_UNMAP_CONF_NAME, + hdd_ctx->config->enable_peer_unmap_conf_support); + hdd_debug("Name = [%s] Value = [%u]", + CFG_ENABLE_TW_COEX_LEGACY_NAME, + hdd_ctx->config->enable_three_way_coex_config_legacy); + hdd_cfg_print_action_oui(hdd_ctx); + hdd_cfg_print_btc_params(hdd_ctx); + hdd_cfg_print_roam_preauth(hdd_ctx); +} + +/** + * 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 macTable[QDF_MAX_CONCURRENCY_PERSONA]; + tSirMacAddr customMacAddr; + + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + memset(macTable, 0, sizeof(macTable)); + status = request_firmware(&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 == NULL) { + hdd_err("fail to alloc memory"); + 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 != NULL) { + 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; + macTable[i].name = name; + macTable[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, &macTable[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(&customMacAddr, + &hdd_ctx->provisioned_mac_addr[0].bytes[0], + sizeof(tSirMacAddr)); + else + qdf_mem_copy(&customMacAddr, + &hdd_ctx->derived_mac_addr[0].bytes[0], + sizeof(tSirMacAddr)); + + sme_set_custom_mac_addr(customMacAddr); + +config_exit: + qdf_mem_free(temp); + release_firmware(fw); + return qdf_status; +} + +/** + * hdd_disable_runtime_pm() - Override to disable runtime_pm. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +#ifdef FEATURE_RUNTIME_PM +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ + cfg_ini->runtime_pm = 0; +} +#else +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ +} +#endif + +/** + * hdd_disable_auto_shutdown() - Override to disable auto_shutdown. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ + cfg_ini->WlanAutoShutdown = 0; +} +#else +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ +} +#endif + +/** + * 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 + * gEnableSuspend=0 + * gEnablePowerSaveOffload=0 + * gEnableWoW=0 + * + * Return: None + */ +static void hdd_override_all_ps(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + + cfg_ini->fIsImpsEnabled = 0; + cfg_ini->is_ps_enabled = 0; + hdd_disable_runtime_pm(cfg_ini); + hdd_disable_auto_shutdown(cfg_ini); + cfg_ini->enablePowersaveOffload = 0; + cfg_ini->wowEnable = 0; +} + +/** + * hdd_set_rx_mode_value() - set rx_mode values + * @hdd_ctx: hdd context + * + * Return: none + */ +static void hdd_set_rx_mode_value(struct hdd_context *hdd_ctx) +{ + /* RPS has higher priority than dynamic RPS when both bits are set */ + if (hdd_ctx->config->rx_mode & CFG_ENABLE_RPS && + hdd_ctx->config->rx_mode & CFG_ENABLE_DYNAMIC_RPS) + hdd_ctx->config->rx_mode &= ~CFG_ENABLE_DYNAMIC_RPS; + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_RX_THREAD && + hdd_ctx->config->rx_mode & CFG_ENABLE_RPS) { + hdd_warn("rx_mode wrong configuration. Make it default"); + hdd_ctx->config->rx_mode = CFG_RX_MODE_DEFAULT; + } + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_RX_THREAD) + hdd_ctx->enable_rxthread = true; + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_RPS) + hdd_ctx->rps = true; + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_NAPI) + hdd_ctx->napi_enable = true; + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_DYNAMIC_RPS) + hdd_ctx->dynamic_rps = true; +} + +/** + * hdd_parse_config_ini() - parse the ini configuration file + * @hdd_ctx: the pointer to hdd context + * + * This function reads the qcom_cfg.ini file and + * parses each 'Name=Value' pair in the ini file + * + * Return: QDF_STATUS_SUCCESS if the qcom_cfg.ini is correctly read, + * otherwise QDF_STATUS_E_INVAL + */ +QDF_STATUS hdd_parse_config_ini(struct hdd_context *hdd_ctx) +{ + int status = 0; + int i = 0; + int retry = 0; + /** Pointer for firmware image data */ + const struct firmware *fw = NULL; + char *buffer, *line, *pTemp = NULL; + size_t size; + char *name, *value; + /* cfgIniTable is static to avoid excess stack usage */ + static struct hdd_cfg_entry cfgIniTable[MAX_CFG_INI_ITEMS]; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + memset(cfgIniTable, 0, sizeof(cfgIniTable)); + + do { + if (status == -EAGAIN) + msleep(HDD_CFG_REQUEST_FIRMWARE_DELAY); + + status = request_firmware(&fw, WLAN_INI_FILE, + hdd_ctx->parent_dev); + + retry++; + } while ((retry < HDD_CFG_REQUEST_FIRMWARE_RETRIES) && + (status == -EAGAIN)); + + if (status) { + hdd_alert("request_firmware failed %d", status); + qdf_status = QDF_STATUS_E_FAILURE; + goto config_exit; + } + if (!fw || !fw->data || !fw->size) { + hdd_alert("%s download failed", WLAN_INI_FILE); + qdf_status = QDF_STATUS_E_FAILURE; + goto config_exit; + } + + hdd_debug("qcom_cfg.ini Size %zu", fw->size); + + buffer = (char *)qdf_mem_malloc(fw->size); + + if (NULL == buffer) { + hdd_err("qdf_mem_malloc failure"); + release_firmware(fw); + return QDF_STATUS_E_NOMEM; + } + pTemp = buffer; + + qdf_mem_copy((void *)buffer, (void *)fw->data, fw->size); + size = fw->size; + + while (buffer != NULL) { + line = get_next_line(buffer); + buffer = i_trim(buffer); + + hdd_debug("%s: item", buffer); + + if (strlen((char *)buffer) == 0 || *buffer == '#') { + buffer = line; + continue; + } + + if (strncmp(buffer, "END", 3) == 0) + break; + + name = buffer; + while (*buffer != '=' && *buffer != '\0') + buffer++; + if (*buffer != '\0') { + *buffer++ = '\0'; + i_trim(name); + if (strlen(name) != 0) { + buffer = i_trim(buffer); + if (strlen(buffer) > 0) { + value = buffer; + while (*buffer != '\0') + buffer++; + *buffer = '\0'; + cfgIniTable[i].name = name; + cfgIniTable[i++].value = value; + if (i >= MAX_CFG_INI_ITEMS) { + hdd_err("Number of items in %s > %d", + WLAN_INI_FILE, + MAX_CFG_INI_ITEMS); + break; + } + } + } + } + buffer = line; + } + + /* Loop through the registry table and apply all these configs */ + qdf_status = hdd_apply_cfg_ini(hdd_ctx, cfgIniTable, i); + hdd_set_rx_mode_value(hdd_ctx); + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + hdd_override_all_ps(hdd_ctx); + +config_exit: + release_firmware(fw); + qdf_mem_free(pTemp); + return qdf_status; +} + +/** + * 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; + } + +} + +/** + * 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_ctx->imps_enabled == val) { + hdd_info("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) +{ + struct hdd_config *config = hdd_ctx->config; + uint32_t capability = config->fine_time_meas_cap; + + /* Make sure only supported capabilities are enabled in INI */ + capability &= CFG_FINE_TIME_MEAS_CAPABILITY_MAX; + ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc, capability); + + hdd_debug("fine time meas capability - INI: %04x Enabled: %04x", + config->fine_time_meas_cap, + capability); +} + +/** + * hdd_convert_string_to_u8_array() - used to convert string into u8 array + * @str: String to be converted + * @hex_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 == NULL || array == NULL || len == NULL) + return QDF_STATUS_E_INVAL; + + format = (to_hex) ? "%02x" : "%d"; + + *len = 0; + while ((s != NULL) && (*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; +} + +/** + * hdd_hex_string_to_u8_array() - used to convert hex string into u8 array + * @str: Hexadecimal string + * @hex_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 hexadecimal string (each byte separated by + * a comma) into an u8 array + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_hex_string_to_u8_array(char *str, uint8_t *hex_array, + uint8_t *len, + uint8_t array_max_len) +{ + return hdd_convert_string_to_array(str, hex_array, len, + array_max_len, true); +} + +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 == NULL || int_array == NULL || len == NULL) + return QDF_STATUS_E_INVAL; + + hdd_debug("str %pK intArray %pK intArrayMaxLen %d", + s, int_array, int_array_max_len); + + *len = 0; + + while ((s != NULL) && (*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_ht_cap_in_cfg() - to update HT cap in global CFG + * @hdd_ctx: pointer to hdd context + * + * This API will update the HT config in CFG after taking intersection + * of INI and firmware capabilities provided reading CFG + * + * Return: true or false + */ +static bool hdd_update_ht_cap_in_cfg(struct hdd_context *hdd_ctx) +{ + uint32_t val32; + uint16_t val16; + bool status = true; + tSirMacHTCapabilityInfo *ht_cap_info; + + if (sme_cfg_get_int(hdd_ctx->mac_handle, WNI_CFG_HT_CAP_INFO, + &val32) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not get WNI_CFG_HT_CAP_INFO"); + } + val16 = (uint16_t) val32; + ht_cap_info = (tSirMacHTCapabilityInfo *) &val16; + ht_cap_info->advCodingCap &= hdd_ctx->config->enable_rx_ldpc; + ht_cap_info->rxSTBC = QDF_MIN(ht_cap_info->rxSTBC, + hdd_ctx->config->enableRxSTBC); + ht_cap_info->txSTBC &= hdd_ctx->config->enableTxSTBC; + ht_cap_info->shortGI20MHz &= hdd_ctx->config->ShortGI20MhzEnable; + ht_cap_info->shortGI40MHz &= hdd_ctx->config->ShortGI40MhzEnable; + val32 = val16; + if (sme_cfg_set_int(hdd_ctx->mac_handle, WNI_CFG_HT_CAP_INFO, val32) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not set WNI_CFG_HT_CAP_INFO"); + } + return status; +} + +/** + * hdd_update_vht_cap_in_cfg() - to update VHT cap in global CFG + * @hdd_ctx: pointer to hdd context + * + * This API will update the VHT config in CFG after taking intersection + * of INI and firmware capabilities provided reading CFG + * + * Return: true or false + */ +static bool hdd_update_vht_cap_in_cfg(struct hdd_context *hdd_ctx) +{ + bool status = true; + uint32_t val; + struct hdd_config *config = hdd_ctx->config; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + config->enableTxBFin20MHz) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't set value for WNI_CFG_VHT_ENABLE_TXBF_20MHZ"); + } + /* Based on cfg.ini, update the Basic MCS set, RX/TX MCS map + * in the cfg.dat. Valid values are 0(MCS0-7), 1(MCS0-8), 2(MCS0-9) + * we update only the least significant 2 bits in the + * corresponding fields. + */ + if ((config->dot11Mode == eHDD_DOT11_MODE_AUTO) || + (config->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) || + (config->dot11Mode == eHDD_DOT11_MODE_11ac)) { + /* Currently shortGI40Mhz is used for shortGI80Mhz and 160MHz*/ + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_SHORT_GI_80MHZ, + config->ShortGI40MhzEnable) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass WNI_VHT_SHORT_GI_80MHZ to CFG"); + } + + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + config->ShortGI40MhzEnable) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass SHORT_GI_160MHZ to CFG"); + } + + /* Hardware is capable of doing + * 128K AMPDU in 11AC mode + */ + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + config->fVhtAmpduLenExponent) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_AMPDU_LEN_EXPONENT to CFG"); + } + /* Change MU Bformee only when TxBF is enabled */ + if (config->enableTxBF) { + sme_cfg_get_int(mac_handle, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &val); + + if (val != config->enableMuBformee) { + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + config->enableMuBformee + ) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_MU_BEAMFORMEE_CAP to CFG"); + } + } + } + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_MAX_MPDU_LENGTH, + config->vhtMpduLen) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_MAX_MPDU_LENGTH to CFG"); + } + + if (config->enable2x2 && config->enable_su_tx_bformer) { + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + config->enable_su_tx_bformer) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("set SU_BEAMFORMER_CAP to CFG failed"); + } + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + NUM_OF_SOUNDING_DIMENSIONS) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("failed to set NUM_OF_SOUNDING_DIM"); + } + } + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_RXSTBC, + config->enableRxSTBC) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_RXSTBC to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_TXSTBC, + config->enableTxSTBC) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_TXSTBC to CFG"); + } + + /* first get HW RX LDPC capability */ + if (sme_cfg_get_int(mac_handle, WNI_CFG_VHT_LDPC_CODING_CAP, &val) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not get WNI_CFG_VHT_LDPC_CODING_CAP"); + } + + /* enable RX LDPC only when both INI and HW are enabled */ + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_LDPC_CODING_CAP, + config->enable_rx_ldpc && val) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_LDPC_CODING_CAP to CFG"); + } + + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + config->txBFCsnValue) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED to CFG"); + } + return status; + +} + +/** + * 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; + struct hdd_config *config = hdd_ctx->config; + mac_handle_t mac_handle; + + /* + * During the initialization both 2G and 5G capabilities should be same. + * So read 5G HT capablity and update 2G and 5G capablities. + */ + if (!hdd_update_ht_cap_in_cfg(hdd_ctx)) { + status = false; + hdd_err("Couldn't set HT CAP in cfg"); + } + + if (!hdd_update_vht_cap_in_cfg(hdd_ctx)) { + status = false; + hdd_err("Couldn't set VHT CAP in cfg"); + } + + if (0 != hdd_update_he_cap_in_cfg(hdd_ctx)) { + status = false; + hdd_err("Couldn't set HE CAP in cfg"); + } + + mac_handle = hdd_ctx->mac_handle; + + if (sme_cfg_set_int(mac_handle, WNI_CFG_MAX_RX_AMPDU_FACTOR, + config->MaxRxAmpduFactor) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_HT_AMPDU_PARAMS_MAX_RX_AMPDU_FACTOR to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_MPDU_DENSITY, + config->ht_mpdu_density) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_MPDU_DENSITY to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_SHORT_PREAMBLE, + config->fIsShortPreamble) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SHORT_PREAMBLE to CFG"); + } + + if (sme_cfg_set_int(mac_handle, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + config->nPassiveMinChnTime) + == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME to CFG"); + } + + if (sme_cfg_set_int(mac_handle, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + config->nPassiveMaxChnTime) + == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_BEACON_INTERVAL, + config->nBeaconInterval) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_BEACON_INTERVAL to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_MAX_PS_POLL, + config->nMaxPsPoll) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_MAX_PS_POLL to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + config->nDataInactivityTimeout) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(mac_handle, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + config->wow_data_inactivity_timeout) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Fail to pass WNI_CFG_PS_WOW_DATA_INACTIVITY_TO CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_ENABLE_LTE_COEX, + config->enableLTECoex) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_LTE_COEX to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + config->apKeepAlivePeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_AP_KEEP_ALIVE_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + config->goKeepAlivePeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_GO_KEEP_ALIVE_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + config->apLinkMonitorPeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_AP_LINK_MONITOR_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + config->goLinkMonitorPeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_GO_LINK_MONITOR_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_SINGLE_TID_RC, + config->bSingleTidRc) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SINGLE_TID_RC to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_TELE_BCN_WAKEUP_EN, + config->teleBcnWakeupEn) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TELE_BCN_WAKEUP_EN to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_TELE_BCN_MAX_LI, + config->nTeleBcnMaxListenInterval) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TELE_BCN_MAX_LI to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + config->infraStaKeepAlivePeriod) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_FRAGMENTATION_THRESHOLD, + config->FragmentationThreshold) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_FRAGMENTATION_THRESHOLD to CFG"); + } + if (sme_cfg_set_int(mac_handle, WNI_CFG_RTS_THRESHOLD, + config->RTSThreshold) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RTS_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_11D_ENABLED, + config->Is11dSupportEnabled) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_11D_ENABLED to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_DFS_MASTER_ENABLED, + config->enableDFSMasterCap) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Failure: Couldn't set value for WNI_CFG_DFS_MASTER_ENABLED"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_HEART_BEAT_THRESHOLD, + config->HeartbeatThresh24) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_HEART_BEAT_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_ENABLE_MC_ADDR_LIST, + config->fEnableMCAddrList) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_MC_ADDR_LIST to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + config->enableMCCAdaptiveScheduler) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED to CFG"); + } + if (sme_cfg_set_int(mac_handle, WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + config->disableLDPCWithTxbfAP) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP to CFG"); + } + +#ifdef FEATURE_WLAN_TDLS + + if (sme_cfg_set_int(mac_handle, WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + config->fTDLSUapsdMask) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK to CFG"); + } + if (sme_cfg_set_int(mac_handle, WNI_CFG_TDLS_BUF_STA_ENABLED, + config->fEnableTDLSBufferSta) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_BUF_STA_ENABLED to CFG"); + } + if (sme_cfg_set_int(mac_handle, WNI_CFG_TDLS_PUAPSD_INACT_TIME, + config->fTDLSPuapsdInactivityTimer) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_PUAPSD_INACT_TIME to CFG"); + } + if (sme_cfg_set_int(mac_handle, WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + config->fTDLSRxFrameThreshold) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_RX_FRAME_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + config->fEnableTDLSOffChannel) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_BUF_STA_ENABLED to CFG"); + } + if (sme_cfg_set_int(mac_handle, WNI_CFG_TDLS_WMM_MODE_ENABLED, + config->fEnableTDLSWmmMode) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_WMM_MODE_ENABLED to CFG"); + } +#endif + + if (sme_cfg_set_int(mac_handle, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + config->debugP2pRemainOnChannel) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL to CFG"); + } +#ifdef WLAN_FEATURE_11W + if (sme_cfg_set_int(mac_handle, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + config->pmfSaQueryMaxRetries) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SA_QUERY_MAX_RETRIES to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + config->pmfSaQueryRetryInterval) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SA_QUERY_RETRY_INTERVAL to CFG"); + } +#endif + + if (sme_cfg_set_int(mac_handle, WNI_CFG_IBSS_ATIM_WIN_SIZE, + config->ibssATIMWinSize) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_IBSS_ATIM_WIN_SIZE to CFG"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_TGT_GTX_USR_CFG, + config->tgt_gtx_usr_cfg) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TGT_GTX_USR_CFG to CCM"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_MAX_HT_MCS_TX_DATA, + config->max_ht_mcs_txdata) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_MAX_HT_MCS_TX_DATA to CCM"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + config->disable_abg_rate_txdata) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA to CCM"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_RATE_FOR_TX_MGMT, + config->rate_for_tx_mgmt) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RATE_FOR_TX_MGMT to CCM"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_SAP_MAX_MCS_DATA, + config->sap_max_mcs_txdata) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_SAP_MAX_MCS_DATA to CCM"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_RATE_FOR_TX_MGMT_2G, + config->rate_for_tx_mgmt_2g) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RATE_FOR_TX_MGMT_2G to CCM"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_RATE_FOR_TX_MGMT_5G, + config->rate_for_tx_mgmt_5g) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RATE_FOR_TX_MGMT_5G to CCM"); + } + + if (sme_cfg_set_int(mac_handle, WNI_CFG_ASSOC_STA_LIMIT, + config->maxNumberOfPeers) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ASSOC_STA_LIMIT to CFG"); + } + + return status; +} + +/** + * hdd_update_per_config_to_sme() -initializes the sme config for PER roam + * + * @hdd_ctx: the pointer to hdd context + * @sme_config: sme configuation pointer + * + * Return: None + */ +static void hdd_update_per_config_to_sme(struct hdd_context *hdd_ctx, + tSmeConfigParams *sme_config) +{ + sme_config->csrConfig.per_roam_config.enable = + hdd_ctx->config->is_per_roam_enabled; + + /* Assigning Tx and Rx for same value */ + sme_config->csrConfig.per_roam_config.tx_high_rate_thresh = + hdd_ctx->config->per_roam_high_rate_threshold; + sme_config->csrConfig.per_roam_config.rx_high_rate_thresh = + hdd_ctx->config->per_roam_high_rate_threshold; + + /* Assigning Tx and Rx for same value */ + sme_config->csrConfig.per_roam_config.tx_low_rate_thresh = + hdd_ctx->config->per_roam_low_rate_threshold; + sme_config->csrConfig.per_roam_config.rx_low_rate_thresh = + hdd_ctx->config->per_roam_low_rate_threshold; + + /* Assigning Tx and Rx for same value */ + sme_config->csrConfig.per_roam_config.tx_rate_thresh_percnt = + hdd_ctx->config->per_roam_th_percent; + sme_config->csrConfig.per_roam_config.rx_rate_thresh_percnt = + hdd_ctx->config->per_roam_th_percent; + + sme_config->csrConfig.per_roam_config.per_rest_time = + hdd_ctx->config->per_roam_rest_time; + sme_config->csrConfig.per_roam_config.tx_per_mon_time = + hdd_ctx->config->per_roam_mon_time; + sme_config->csrConfig.per_roam_config.rx_per_mon_time = + hdd_ctx->config->per_roam_mon_time; + + /* Assigning minimum roamable AP RSSI for candidate selection */ + sme_config->csrConfig.per_roam_config.min_candidate_rssi = + hdd_ctx->config->min_candidate_rssi; +} + +/** + * 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 (NULL == user_cfg) { + hdd_err("unable to allocate user_cfg"); + return QDF_STATUS_E_NOMEM; + } + + user_cfg->conc_system_pref = hdd_ctx->config->conc_system_pref; + user_cfg->enable_mcc_adaptive_scheduler = + hdd_ctx->config->enableMCCAdaptiveScheduler; + user_cfg->max_concurrent_active_sessions = + hdd_ctx->config->gMaxConcurrentActiveSessions; + user_cfg->enable2x2 = hdd_ctx->config->enable2x2; + user_cfg->mcc_to_scc_switch_mode = + hdd_ctx->config->WlanMccToSccSwitchMode; + user_cfg->sub_20_mhz_enabled = cds_is_sub_20_mhz_enabled(); + user_cfg->is_sta_sap_scc_allowed_on_dfs_chan = + hdd_ctx->config->sta_sap_scc_on_dfs_chan; + user_cfg->channel_select_logic_conc = + hdd_ctx->config->channel_select_logic_conc; + user_cfg->sta_sap_scc_on_lte_coex_chan = + hdd_ctx->config->sta_sap_scc_on_lte_coex_chan; + user_cfg->enable_dfs_master_cap = + hdd_ctx->config->enableDFSMasterCap; + status = policy_mgr_set_user_cfg(hdd_ctx->psoc, user_cfg); + qdf_mem_free(user_cfg); + + return status; +} + +eCsrRoamWmmUserModeType hdd_to_csr_wmm_mode(enum hdd_wmm_user_mode mode) +{ + switch (mode) { + case HDD_WMM_USER_MODE_QBSS_ONLY: + return eCsrRoamWmmQbssOnly; + case HDD_WMM_USER_MODE_NO_QOS: + return eCsrRoamWmmNoQos; + case HDD_WMM_USER_MODE_AUTO: + default: + return eCsrRoamWmmAuto; + } +} + +/** + * hdd_update_score_params() -initializes the sme config for bss score params + * + * @config: pointer to config + * @score_params: bss score params + * + * Return: None + */ +static void hdd_update_bss_score_params(struct hdd_config *config, + struct sir_score_config *score_params) +{ + int total_weight; + + score_params->enable_scoring_for_roam = + config->enable_scoring_for_roam; + score_params->weight_cfg.rssi_weightage = config->rssi_weightage; + score_params->weight_cfg.ht_caps_weightage = config->ht_caps_weightage; + score_params->weight_cfg.vht_caps_weightage = + config->vht_caps_weightage; + score_params->weight_cfg.he_caps_weightage = + config->he_caps_weightage; + score_params->weight_cfg.chan_width_weightage = + config->chan_width_weightage; + score_params->weight_cfg.chan_band_weightage = + config->chan_band_weightage; + score_params->weight_cfg.nss_weightage = config->nss_weightage; + score_params->weight_cfg.beamforming_cap_weightage = + config->beamforming_cap_weightage; + score_params->weight_cfg.pcl_weightage = config->pcl_weightage; + score_params->weight_cfg.channel_congestion_weightage = + config->channel_congestion_weightage; + score_params->weight_cfg.oce_wan_weightage = config->oce_wan_weightage; + + total_weight = score_params->weight_cfg.rssi_weightage + + score_params->weight_cfg.ht_caps_weightage + + score_params->weight_cfg.vht_caps_weightage + + score_params->weight_cfg.he_caps_weightage + + score_params->weight_cfg.chan_width_weightage + + score_params->weight_cfg.chan_band_weightage + + score_params->weight_cfg.nss_weightage + + score_params->weight_cfg.beamforming_cap_weightage + + score_params->weight_cfg.pcl_weightage + + score_params->weight_cfg.channel_congestion_weightage + + score_params->weight_cfg.oce_wan_weightage; + + if (total_weight > BEST_CANDIDATE_MAX_WEIGHT) { + hdd_err("total weight is greater than %d fallback to default values", + BEST_CANDIDATE_MAX_WEIGHT); + + score_params->weight_cfg.rssi_weightage = RSSI_WEIGHTAGE; + score_params->weight_cfg.ht_caps_weightage = + HT_CAPABILITY_WEIGHTAGE; + score_params->weight_cfg.vht_caps_weightage = VHT_CAP_WEIGHTAGE; + score_params->weight_cfg.he_caps_weightage = HE_CAP_WEIGHTAGE; + score_params->weight_cfg.chan_width_weightage = + CHAN_WIDTH_WEIGHTAGE; + score_params->weight_cfg.chan_band_weightage = + CHAN_BAND_WEIGHTAGE; + score_params->weight_cfg.nss_weightage = NSS_WEIGHTAGE; + score_params->weight_cfg.beamforming_cap_weightage = + BEAMFORMING_CAP_WEIGHTAGE; + score_params->weight_cfg.pcl_weightage = PCL_WEIGHT; + score_params->weight_cfg.channel_congestion_weightage = + CHANNEL_CONGESTION_WEIGHTAGE; + score_params->weight_cfg.oce_wan_weightage = OCE_WAN_WEIGHTAGE; + } + + score_params->bandwidth_weight_per_index = + hdd_limit_max_per_index_score( + config->bandwidth_weight_per_index); + score_params->nss_weight_per_index = + hdd_limit_max_per_index_score(config->nss_weight_per_index); + score_params->band_weight_per_index = + hdd_limit_max_per_index_score(config->band_weight_per_index); + + score_params->roam_score_delta = config->roam_score_delta; + score_params->roam_score_delta_bitmap = config->roam_score_delta_bitmap; + + score_params->rssi_score.best_rssi_threshold = + config->best_rssi_threshold; + score_params->rssi_score.good_rssi_threshold = + config->good_rssi_threshold; + score_params->rssi_score.bad_rssi_threshold = + config->bad_rssi_threshold; + score_params->rssi_score.good_rssi_pcnt = config->good_rssi_pcnt; + score_params->rssi_score.bad_rssi_pcnt = config->bad_rssi_pcnt; + score_params->rssi_score.good_rssi_bucket_size = + config->good_rssi_bucket_size; + score_params->rssi_score.bad_rssi_bucket_size = + config->bad_rssi_bucket_size; + score_params->rssi_score.rssi_pref_5g_rssi_thresh = + config->rssi_pref_5g_rssi_thresh; + + score_params->esp_qbss_scoring.num_slot = config->num_esp_qbss_slots; + score_params->esp_qbss_scoring.score_pcnt3_to_0 = + hdd_limit_max_per_index_score( + config->esp_qbss_score_slots3_to_0); + score_params->esp_qbss_scoring.score_pcnt7_to_4 = + hdd_limit_max_per_index_score( + config->esp_qbss_score_slots7_to_4); + score_params->esp_qbss_scoring.score_pcnt11_to_8 = + hdd_limit_max_per_index_score( + config->esp_qbss_score_slots11_to_8); + score_params->esp_qbss_scoring.score_pcnt15_to_12 = + hdd_limit_max_per_index_score( + config->esp_qbss_score_slots15_to_12); + + score_params->oce_wan_scoring.num_slot = config->num_oce_wan_slots; + score_params->oce_wan_scoring.score_pcnt3_to_0 = + hdd_limit_max_per_index_score( + config->oce_wan_score_slots3_to_0); + score_params->oce_wan_scoring.score_pcnt7_to_4 = + hdd_limit_max_per_index_score( + config->oce_wan_score_slots7_to_4); + score_params->oce_wan_scoring.score_pcnt11_to_8 = + hdd_limit_max_per_index_score( + config->oce_wan_score_slots11_to_8); + score_params->oce_wan_scoring.score_pcnt15_to_12 = + hdd_limit_max_per_index_score( + config->oce_wan_score_slots15_to_12); +} + +/** + * hdd_update_11k_offload_params() - initializes the 11k offload related params + * + * @config: pointer to hdd_config structure + * @csr_config: pointer to the csr config structure + * + * Return: None + */ +static +void hdd_update_11k_offload_params(struct hdd_config *config, + tCsrConfigParam *csr_config) +{ + csr_config->offload_11k_enable_bitmask = + config->offload_11k_enable_bitmask; + csr_config->neighbor_report_offload.params_bitmask = + config->neighbor_report_offload_params_bitmask; + csr_config->neighbor_report_offload.time_offset = + config->neighbor_report_offload_time_offset; + csr_config->neighbor_report_offload.low_rssi_offset = + config->neighbor_report_offload_low_rssi_offset; + csr_config->neighbor_report_offload.bmiss_count_trigger = + config->neighbor_report_offload_bmiss_count_trigger; + csr_config->neighbor_report_offload.per_threshold_offset = + config->neighbor_report_offload_per_threshold_offset; + csr_config->neighbor_report_offload.neighbor_report_cache_timeout = + config->neighbor_report_offload_cache_timeout; + csr_config->neighbor_report_offload.max_neighbor_report_req_cap = + config->neighbor_report_offload_max_req_cap; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_update_roam_preauth_params() - Update the roam preauth params + * @sme_config - The SME config handle + * @hdd_ctx - The HDD CTX handle + * + * Return: None + */ +static void sme_update_roam_preauth_params(tSmeConfigParams *sme_config, + struct hdd_context *hdd_ctx) +{ + sme_config->csrConfig.roam_preauth_no_ack_timeout = + hdd_ctx->config->roam_preauth_no_ack_timeout; + sme_config->csrConfig.roam_preauth_retry_count = + hdd_ctx->config->roam_preauth_retry_count; +} +#else +static void sme_update_roam_preauth_params(tSmeConfigParams *sme_config, + struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * sme_update_beacon_stats() - Update enable/disable beacon stats in mac ctx + * @mac_handle: Opaque mac handle + * @enable_beacon_reception_stats: Enabled/disabled + * + * Return: None + */ +static void sme_update_beacon_stats(mac_handle_t mac_handle, + bool enable_beacon_reception_stats) +{ + struct sAniSirGlobal *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->enable_beacon_reception_stats = enable_beacon_reception_stats; +} + +/** + * 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; + tSmeConfigParams *smeConfig; + uint8_t rrm_capab_len, val; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + struct hdd_config *pConfig = hdd_ctx->config; + + smeConfig = qdf_mem_malloc(sizeof(*smeConfig)); + if (NULL == smeConfig) { + hdd_err("unable to allocate smeConfig"); + return QDF_STATUS_E_NOMEM; + } + + hdd_debug("%s bWmmIsEnabled=%d 802_11e_enabled=%d dot11Mode=%d", + __func__, pConfig->WmmMode, pConfig->b80211eIsEnabled, + pConfig->dot11Mode); + + /* Config params obtained from the registry + * To Do: set regulatory information here + */ + + smeConfig->csrConfig.RTSThreshold = pConfig->RTSThreshold; + smeConfig->csrConfig.FragmentationThreshold = + pConfig->FragmentationThreshold; + smeConfig->csrConfig.shortSlotTime = pConfig->ShortSlotTimeEnabled; + smeConfig->csrConfig.Is11dSupportEnabled = pConfig->Is11dSupportEnabled; + smeConfig->csrConfig.HeartbeatThresh24 = pConfig->HeartbeatThresh24; + + smeConfig->csrConfig.phyMode = + hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode); + + if (pConfig->dot11Mode == eHDD_DOT11_MODE_abg || + pConfig->dot11Mode == eHDD_DOT11_MODE_11b || + pConfig->dot11Mode == eHDD_DOT11_MODE_11g || + pConfig->dot11Mode == eHDD_DOT11_MODE_11b_ONLY || + pConfig->dot11Mode == eHDD_DOT11_MODE_11g_ONLY) { + smeConfig->csrConfig.channelBondingMode24GHz = 0; + smeConfig->csrConfig.channelBondingMode5GHz = 0; + } else { + smeConfig->csrConfig.channelBondingMode24GHz = + pConfig->nChannelBondingMode24GHz; + smeConfig->csrConfig.channelBondingMode5GHz = + pConfig->nChannelBondingMode5GHz; + } + smeConfig->csrConfig.nScanResultAgeCount = pConfig->ScanResultAgeCount; + smeConfig->csrConfig.AdHocChannel24 = pConfig->OperatingChannel; + smeConfig->csrConfig.fSupplicantCountryCodeHasPriority = + pConfig->fSupplicantCountryCodeHasPriority; + smeConfig->csrConfig.bCatRssiOffset = pConfig->nRssiCatGap; + smeConfig->csrConfig.vccRssiThreshold = pConfig->nVccRssiTrigger; + smeConfig->csrConfig.vccUlMacLossThreshold = + pConfig->nVccUlMacLossThreshold; + smeConfig->csrConfig.nInitialDwellTime = pConfig->nInitialDwellTime; + smeConfig->csrConfig.initial_scan_no_dfs_chnl = + pConfig->initial_scan_no_dfs_chnl; + smeConfig->csrConfig.nActiveMaxChnTime = pConfig->nActiveMaxChnTime; + smeConfig->csrConfig.nActiveMinChnTime = pConfig->nActiveMinChnTime; + smeConfig->csrConfig.nPassiveMaxChnTime = pConfig->nPassiveMaxChnTime; + smeConfig->csrConfig.nPassiveMinChnTime = pConfig->nPassiveMinChnTime; + smeConfig->csrConfig.nActiveMaxChnTimeConc = + pConfig->nActiveMaxChnTimeConc; + smeConfig->csrConfig.nActiveMinChnTimeConc = + pConfig->nActiveMinChnTimeConc; + smeConfig->csrConfig.nPassiveMaxChnTimeConc = + pConfig->nPassiveMaxChnTimeConc; + smeConfig->csrConfig.nPassiveMinChnTimeConc = + pConfig->nPassiveMinChnTimeConc; + smeConfig->csrConfig.nRestTimeConc = pConfig->nRestTimeConc; + smeConfig->csrConfig.min_rest_time_conc = pConfig->min_rest_time_conc; + smeConfig->csrConfig.idle_time_conc = pConfig->idle_time_conc; + + smeConfig->csrConfig.Is11eSupportEnabled = pConfig->b80211eIsEnabled; + smeConfig->csrConfig.WMMSupportMode = + hdd_to_csr_wmm_mode(pConfig->WmmMode); + + smeConfig->rrmConfig.rrm_enabled = pConfig->fRrmEnable; + smeConfig->rrmConfig.max_randn_interval = pConfig->nRrmRandnIntvl; + hdd_hex_string_to_u8_array(pConfig->rm_capability, + smeConfig->rrmConfig.rm_capability, &rrm_capab_len, + DOT11F_IE_RRMENABLEDCAP_MAX_LEN); + /* Remaining config params not obtained from registry + * On RF EVB beacon using channel 1. + */ + smeConfig->csrConfig.nVhtChannelWidth = pConfig->vhtChannelWidth; + smeConfig->csrConfig.enableTxBF = pConfig->enableTxBF; + smeConfig->csrConfig.enable_subfee_vendor_vhtie = + pConfig->enable_subfee_vendor_vhtie; + + smeConfig->csrConfig.enable_txbf_sap_mode = + pConfig->enable_txbf_sap_mode; + smeConfig->csrConfig.enable2x2 = pConfig->enable2x2; + smeConfig->csrConfig.enableVhtFor24GHz = pConfig->enableVhtFor24GHzBand; + smeConfig->csrConfig.vendor_vht_sap = + pConfig->enable_sap_vendor_vht; + smeConfig->csrConfig.enableMuBformee = pConfig->enableMuBformee; + smeConfig->csrConfig.enableVhtpAid = pConfig->enableVhtpAid; + smeConfig->csrConfig.enableVhtGid = pConfig->enableVhtGid; + smeConfig->csrConfig.enableAmpduPs = pConfig->enableAmpduPs; + smeConfig->csrConfig.enableHtSmps = pConfig->enableHtSmps; + smeConfig->csrConfig.htSmps = pConfig->htSmps; + /* This param cannot be configured from INI */ + smeConfig->csrConfig.send_smps_action = true; + smeConfig->csrConfig.AdHocChannel5G = pConfig->AdHocChannel5G; + smeConfig->csrConfig.AdHocChannel24 = pConfig->AdHocChannel24G; + smeConfig->csrConfig.ProprietaryRatesEnabled = 0; + smeConfig->csrConfig.HeartbeatThresh50 = 40; + smeConfig->csrConfig.bandCapability = pConfig->nBandCapability; + if (pConfig->nBandCapability == BAND_2G) { + smeConfig->csrConfig.Is11hSupportEnabled = 0; + } else { + smeConfig->csrConfig.Is11hSupportEnabled = + pConfig->Is11hSupportEnabled; + } + smeConfig->csrConfig.eBand = pConfig->nBandCapability; + smeConfig->csrConfig.nTxPowerCap = pConfig->nTxPowerCap; + smeConfig->csrConfig.allow_tpc_from_ap = pConfig->allow_tpc_from_ap; + smeConfig->csrConfig.fEnableBypass11d = pConfig->enableBypass11d; + smeConfig->csrConfig.fEnableDFSChnlScan = pConfig->enableDFSChnlScan; + smeConfig->csrConfig.nRoamPrefer5GHz = pConfig->nRoamPrefer5GHz; + smeConfig->csrConfig.nRoamIntraBand = pConfig->nRoamIntraBand; + smeConfig->csrConfig.nProbes = pConfig->nProbes; + + smeConfig->csrConfig.nRoamScanHomeAwayTime = + pConfig->nRoamScanHomeAwayTime; + smeConfig->csrConfig.fFirstScanOnly2GChnl = + pConfig->enableFirstScan2GOnly; + + smeConfig->csrConfig.Csr11dinfo.Channels.numChannels = 0; + + hdd_set_power_save_offload_config(hdd_ctx); + + smeConfig->csrConfig.isFastRoamIniFeatureEnabled = + pConfig->isFastRoamIniFeatureEnabled; + smeConfig->csrConfig.csr_mawc_config.mawc_enabled = + pConfig->MAWCEnabled; + smeConfig->csrConfig.csr_mawc_config.mawc_roam_enabled = + pConfig->mawc_roam_enabled; + smeConfig->csrConfig.csr_mawc_config.mawc_roam_traffic_threshold = + pConfig->mawc_roam_traffic_threshold; + smeConfig->csrConfig.csr_mawc_config.mawc_roam_ap_rssi_threshold = + pConfig->mawc_roam_ap_rssi_threshold; + smeConfig->csrConfig.csr_mawc_config.mawc_roam_rssi_high_adjust = + pConfig->mawc_roam_rssi_high_adjust; + smeConfig->csrConfig.csr_mawc_config.mawc_roam_rssi_low_adjust = + pConfig->mawc_roam_rssi_low_adjust; +#ifdef FEATURE_WLAN_ESE + smeConfig->csrConfig.isEseIniFeatureEnabled = + pConfig->isEseIniFeatureEnabled; + if (pConfig->isEseIniFeatureEnabled) + pConfig->isFastTransitionEnabled = true; +#endif + smeConfig->csrConfig.isFastTransitionEnabled = + pConfig->isFastTransitionEnabled; + smeConfig->csrConfig.RoamRssiDiff = pConfig->RoamRssiDiff; + smeConfig->csrConfig.rssi_abs_thresh = pConfig->rssi_abs_thresh; + smeConfig->csrConfig.isWESModeEnabled = pConfig->isWESModeEnabled; + smeConfig->csrConfig.isRoamOffloadScanEnabled = + pConfig->isRoamOffloadScanEnabled; + smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = + pConfig->bFastRoamInConIniFeatureEnabled; + + if (0 == smeConfig->csrConfig.isRoamOffloadScanEnabled) { + /* Disable roaming in concurrency if roam scan + * offload is disabled + */ + smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = 0; + } + smeConfig->csrConfig.neighborRoamConfig.nNeighborLookupRssiThreshold = + pConfig->nNeighborLookupRssiThreshold; + smeConfig->csrConfig.neighborRoamConfig.rssi_thresh_offset_5g = + pConfig->rssi_thresh_offset_5g; + smeConfig->csrConfig.neighborRoamConfig.delay_before_vdev_stop = + pConfig->delay_before_vdev_stop; + smeConfig->csrConfig.neighborRoamConfig.nOpportunisticThresholdDiff = + pConfig->nOpportunisticThresholdDiff; + smeConfig->csrConfig.neighborRoamConfig.nRoamRescanRssiDiff = + pConfig->nRoamRescanRssiDiff; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanMaxChanTime = + pConfig->nNeighborScanMaxChanTime; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanMinChanTime = + pConfig->nNeighborScanMinChanTime; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanTimerPeriod = + pConfig->nNeighborScanPeriod; + smeConfig->csrConfig.neighborRoamConfig. + neighbor_scan_min_timer_period = + pConfig->neighbor_scan_min_period; + smeConfig->csrConfig.neighborRoamConfig.nMaxNeighborRetries = + pConfig->nMaxNeighborReqTries; + smeConfig->csrConfig.neighborRoamConfig.nNeighborResultsRefreshPeriod = + pConfig->nNeighborResultsRefreshPeriod; + smeConfig->csrConfig.neighborRoamConfig.nEmptyScanRefreshPeriod = + pConfig->nEmptyScanRefreshPeriod; + hdd_string_to_u8_array(pConfig->neighborScanChanList, + smeConfig->csrConfig.neighborRoamConfig. + neighborScanChanList.channelList, + &smeConfig->csrConfig.neighborRoamConfig. + neighborScanChanList.numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + smeConfig->csrConfig.neighborRoamConfig.nRoamBmissFirstBcnt = + pConfig->nRoamBmissFirstBcnt; + smeConfig->csrConfig.neighborRoamConfig.nRoamBmissFinalBcnt = + pConfig->nRoamBmissFinalBcnt; + smeConfig->csrConfig.neighborRoamConfig.nRoamBeaconRssiWeight = + pConfig->nRoamBeaconRssiWeight; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_max_count = + pConfig->nhi_rssi_scan_max_count; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_rssi_delta = + pConfig->nhi_rssi_scan_rssi_delta; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_delay = + pConfig->nhi_rssi_scan_delay; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_rssi_ub = + pConfig->nhi_rssi_scan_rssi_ub; + smeConfig->csrConfig.addTSWhenACMIsOff = pConfig->AddTSWhenACMIsOff; + smeConfig->csrConfig.allowDFSChannelRoam = pConfig->allowDFSChannelRoam; + + /* Enable/Disable MCC */ + smeConfig->csrConfig.fEnableMCCMode = pConfig->enableMCC; + smeConfig->csrConfig.mcc_rts_cts_prot_enable = + pConfig->mcc_rts_cts_prot_enable; + smeConfig->csrConfig.mcc_bcast_prob_resp_enable = + pConfig->mcc_bcast_prob_resp_enable; + smeConfig->csrConfig.fAllowMCCGODiffBI = pConfig->allowMCCGODiffBI; + + /* Scan Results Aging Time out value */ + smeConfig->csrConfig.scanCfgAgingTime = pConfig->scanAgingTimeout; + + smeConfig->csrConfig.enable_tx_ldpc = pConfig->enable_tx_ldpc; + smeConfig->csrConfig.enable_rx_ldpc = pConfig->enable_rx_ldpc; + smeConfig->csrConfig.disable_high_ht_mcs_2x2 = + pConfig->disable_high_ht_mcs_2x2; + smeConfig->csrConfig.enable_vht20_mcs9 = pConfig->enable_vht20_mcs9; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + smeConfig->csrConfig.cc_switch_mode = pConfig->WlanMccToSccSwitchMode; +#endif + + smeConfig->csrConfig.max_amsdu_num = pConfig->max_amsdu_num; + smeConfig->csrConfig.nSelect5GHzMargin = pConfig->nSelect5GHzMargin; + + smeConfig->csrConfig.isCoalesingInIBSSAllowed = + hdd_ctx->config->isCoalesingInIBSSAllowed; + smeConfig->csrConfig.ignore_peer_erp_info = + pConfig->ignore_peer_erp_info; + /* update SSR config */ + sme_update_enable_ssr(mac_handle, hdd_ctx->config->enableSSR); + + /* Update maximum interfaces information */ + smeConfig->csrConfig.max_intf_count = hdd_ctx->max_intf_count; + + smeConfig->csrConfig.fEnableDebugLog = hdd_ctx->config->gEnableDebugLog; + + smeConfig->csrConfig.enable5gEBT = hdd_ctx->config->enable5gEBT; + + smeConfig->csrConfig.enableSelfRecovery = + hdd_ctx->config->enableSelfRecovery; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + smeConfig->csrConfig.isRoamOffloadEnabled = + hdd_ctx->config->isRoamOffloadEnabled; +#endif + smeConfig->csrConfig.conc_custom_rule1 = + hdd_ctx->config->conc_custom_rule1; + smeConfig->csrConfig.conc_custom_rule2 = + hdd_ctx->config->conc_custom_rule2; + smeConfig->csrConfig.is_sta_connection_in_5gz_enabled = + hdd_ctx->config->is_sta_connection_in_5gz_enabled; + + smeConfig->csrConfig.f_sta_miracast_mcc_rest_time_val = + hdd_ctx->config->sta_miracast_mcc_rest_time_val; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + smeConfig->csrConfig.sap_channel_avoidance = + hdd_ctx->config->sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + smeConfig->csrConfig.acs_with_more_param = + hdd_ctx->config->acs_with_more_param; + + smeConfig->csrConfig.f_prefer_non_dfs_on_radar = + hdd_ctx->config->prefer_non_dfs_on_radar; + + smeConfig->csrConfig.is_ps_enabled = hdd_ctx->config->is_ps_enabled; + smeConfig->csrConfig.auto_bmps_timer_val = + hdd_ctx->config->auto_bmps_timer_val; + hdd_set_fine_time_meas_cap(hdd_ctx); + + cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs); + + smeConfig->csrConfig.send_deauth_before_con = + pConfig->send_deauth_before_con; + + smeConfig->csrConfig.max_scan_count = + hdd_ctx->config->max_scan_count; + + /* Update 802.11p config */ + smeConfig->csrConfig.enable_dot11p = + (hdd_ctx->config->dot11p_mode != WLAN_HDD_11P_DISABLED); + + smeConfig->csrConfig.early_stop_scan_enable = + hdd_ctx->config->early_stop_scan_enable; + smeConfig->csrConfig.early_stop_scan_min_threshold = + hdd_ctx->config->early_stop_scan_min_threshold; + smeConfig->csrConfig.early_stop_scan_max_threshold = + hdd_ctx->config->early_stop_scan_max_threshold; + smeConfig->csrConfig.first_scan_bucket_threshold = + hdd_ctx->config->first_scan_bucket_threshold; + + smeConfig->csrConfig.roam_dense_rssi_thresh_offset = + hdd_ctx->config->roam_dense_rssi_thresh_offset; + smeConfig->csrConfig.roam_dense_min_aps = + hdd_ctx->config->roam_dense_min_aps; + smeConfig->csrConfig.roam_dense_traffic_thresh = + hdd_ctx->config->roam_dense_traffic_thresh; + smeConfig->csrConfig.roam_bg_scan_bad_rssi_thresh = + hdd_ctx->config->roam_bg_scan_bad_rssi_thresh; + smeConfig->csrConfig.roam_bg_scan_client_bitmap = + hdd_ctx->config->roam_bg_scan_client_bitmap; + smeConfig->csrConfig.roam_bad_rssi_thresh_offset_2g = + hdd_ctx->config->roam_bad_rssi_thresh_offset_2g; + smeConfig->csrConfig.ho_delay_for_rx = + hdd_ctx->config->ho_delay_for_rx; + + sme_update_roam_preauth_params(smeConfig, hdd_ctx); + + smeConfig->csrConfig.min_delay_btw_roam_scans = + hdd_ctx->config->min_delay_btw_roam_scans; + smeConfig->csrConfig.roam_trigger_reason_bitmask = + hdd_ctx->config->roam_trigger_reason_bitmask; + smeConfig->csrConfig.roaming_scan_policy = + hdd_ctx->config->roaming_scan_policy; + smeConfig->csrConfig.obss_width_interval = + hdd_ctx->config->obss_width_trigger_interval; + smeConfig->csrConfig.obss_active_dwelltime = + hdd_ctx->config->obss_active_dwelltime; + smeConfig->csrConfig.obss_passive_dwelltime = + hdd_ctx->config->obss_passive_dwelltime; + smeConfig->csrConfig.ignore_peer_ht_opmode = + pConfig->ignore_peer_ht_opmode; + smeConfig->csrConfig.enable_fatal_event = + pConfig->enable_fatal_event; + smeConfig->csrConfig.scan_adaptive_dwell_mode = + hdd_ctx->config->scan_adaptive_dwell_mode; + smeConfig->csrConfig.scan_adaptive_dwell_mode_nc = + hdd_ctx->config->scan_adaptive_dwell_mode_nc; + smeConfig->csrConfig.roamscan_adaptive_dwell_mode = + hdd_ctx->config->roamscan_adaptive_dwell_mode; + smeConfig->csrConfig.enable_ftopen = + hdd_ctx->config->enable_ftopen; + smeConfig->csrConfig.roam_force_rssi_trigger = + hdd_ctx->config->roam_force_rssi_trigger; + + hdd_update_per_config_to_sme(hdd_ctx, smeConfig); + + smeConfig->csrConfig.enable_edca_params = + pConfig->enable_edca_params; + + smeConfig->csrConfig.edca_vo_cwmin = + pConfig->edca_vo_cwmin; + smeConfig->csrConfig.edca_vi_cwmin = + pConfig->edca_vi_cwmin; + smeConfig->csrConfig.edca_bk_cwmin = + pConfig->edca_bk_cwmin; + smeConfig->csrConfig.edca_be_cwmin = + pConfig->edca_be_cwmin; + + smeConfig->csrConfig.edca_vo_cwmax = + pConfig->edca_vo_cwmax; + smeConfig->csrConfig.edca_vi_cwmax = + pConfig->edca_vi_cwmax; + smeConfig->csrConfig.edca_bk_cwmax = + pConfig->edca_bk_cwmax; + smeConfig->csrConfig.edca_be_cwmax = + pConfig->edca_be_cwmax; + + smeConfig->csrConfig.edca_vo_aifs = + pConfig->edca_vo_aifs; + smeConfig->csrConfig.edca_vi_aifs = + pConfig->edca_vi_aifs; + smeConfig->csrConfig.edca_bk_aifs = + pConfig->edca_bk_aifs; + smeConfig->csrConfig.edca_be_aifs = + pConfig->edca_be_aifs; + smeConfig->csrConfig.sta_roam_policy_params.dfs_mode = + CSR_STA_ROAM_POLICY_DFS_ENABLED; + smeConfig->csrConfig.sta_roam_policy_params.skip_unsafe_channels = 0; + + smeConfig->snr_monitor_enabled = hdd_ctx->config->fEnableSNRMonitoring; + + smeConfig->csrConfig.tx_aggregation_size = + hdd_ctx->config->tx_aggregation_size; + smeConfig->csrConfig.tx_aggregation_size_be = + hdd_ctx->config->tx_aggregation_size_be; + smeConfig->csrConfig.tx_aggregation_size_bk = + hdd_ctx->config->tx_aggregation_size_bk; + smeConfig->csrConfig.tx_aggregation_size_vi = + hdd_ctx->config->tx_aggregation_size_vi; + smeConfig->csrConfig.tx_aggregation_size_vo = + hdd_ctx->config->tx_aggregation_size_vo; + smeConfig->csrConfig.rx_aggregation_size = + hdd_ctx->config->rx_aggregation_size; + smeConfig->csrConfig.tx_aggr_sw_retry_threshold_be = + hdd_ctx->config->tx_aggr_sw_retry_threshold_be; + smeConfig->csrConfig.tx_aggr_sw_retry_threshold_bk = + hdd_ctx->config->tx_aggr_sw_retry_threshold_bk; + smeConfig->csrConfig.tx_aggr_sw_retry_threshold_vi = + hdd_ctx->config->tx_aggr_sw_retry_threshold_vi; + smeConfig->csrConfig.tx_aggr_sw_retry_threshold_vo = + hdd_ctx->config->tx_aggr_sw_retry_threshold_vo; + smeConfig->csrConfig.tx_aggr_sw_retry_threshold = + hdd_ctx->config->tx_aggr_sw_retry_threshold; + smeConfig->csrConfig.tx_non_aggr_sw_retry_threshold_be = + hdd_ctx->config->tx_non_aggr_sw_retry_threshold_be; + smeConfig->csrConfig.tx_non_aggr_sw_retry_threshold_bk = + hdd_ctx->config->tx_non_aggr_sw_retry_threshold_bk; + smeConfig->csrConfig.tx_non_aggr_sw_retry_threshold_vi = + hdd_ctx->config->tx_non_aggr_sw_retry_threshold_vi; + smeConfig->csrConfig.tx_non_aggr_sw_retry_threshold_vo = + hdd_ctx->config->tx_non_aggr_sw_retry_threshold_vo; + smeConfig->csrConfig.tx_non_aggr_sw_retry_threshold = + hdd_ctx->config->tx_non_aggr_sw_retry_threshold; + smeConfig->csrConfig.enable_bcast_probe_rsp = + hdd_ctx->config->enable_bcast_probe_rsp; + smeConfig->csrConfig.is_fils_enabled = + hdd_ctx->config->is_fils_enabled; + smeConfig->csrConfig.qcn_ie_support = + hdd_ctx->config->qcn_ie_support; + smeConfig->csrConfig.fils_max_chan_guard_time = + hdd_ctx->config->fils_max_chan_guard_time; + + hdd_he_set_sme_config(smeConfig, pConfig); + + smeConfig->csrConfig.wlm_latency_enable = + hdd_ctx->config->wlm_latency_enable; + smeConfig->csrConfig.wlm_latency_level = + hdd_ctx->config->wlm_latency_level; + smeConfig->csrConfig.wlm_latency_flags[0] = + hdd_ctx->config->wlm_latency_flags_normal; + smeConfig->csrConfig.wlm_latency_flags[1] = + hdd_ctx->config->wlm_latency_flags_moderate; + smeConfig->csrConfig.wlm_latency_flags[2] = + hdd_ctx->config->wlm_latency_flags_low; + smeConfig->csrConfig.wlm_latency_flags[3] = + hdd_ctx->config->wlm_latency_flags_ultralow; + + smeConfig->csrConfig.pkt_err_disconn_th = + hdd_ctx->config->pkt_err_disconn_th; + smeConfig->csrConfig.disallow_duration = + hdd_ctx->config->disallow_duration; + smeConfig->csrConfig.rssi_channel_penalization = + hdd_ctx->config->rssi_channel_penalization; + smeConfig->csrConfig.num_disallowed_aps = + hdd_ctx->config->num_disallowed_aps; + + smeConfig->csrConfig.is_force_1x1_enable = + hdd_ctx->config->is_force_1x1_enable; + smeConfig->csrConfig.num_11b_tx_chains = + hdd_ctx->config->num_11b_tx_chains; + smeConfig->csrConfig.num_11ag_tx_chains = + hdd_ctx->config->num_11ag_tx_chains; + val = (pConfig->oce_probe_req_rate_enabled * + WMI_VDEV_OCE_PROBE_REQUEST_RATE_FEATURE_BITMAP) + + (pConfig->oce_probe_resp_rate_enabled * + WMI_VDEV_OCE_PROBE_RESPONSE_RATE_FEATURE_BITMAP) + + (pConfig->oce_beacon_rate_enabled * + WMI_VDEV_OCE_BEACON_RATE_FEATURE_BITMAP) + + (pConfig->probe_req_deferral_enabled * + WMI_VDEV_OCE_PROBE_REQUEST_DEFERRAL_FEATURE_BITMAP) + + (pConfig->fils_discovery_sap_enabled * + WMI_VDEV_OCE_FILS_DISCOVERY_FRAME_FEATURE_BITMAP) + + (pConfig->esp_for_roam_enabled * + WMI_VDEV_OCE_ESP_FEATURE_BITMAP) + + (pConfig->rssi_assoc_reject_enabled * + WMI_VDEV_OCE_REASSOC_REJECT_FEATURE_BITMAP); + smeConfig->csrConfig.oce_feature_bitmap = val; + smeConfig->csrConfig.mbo_thresholds.mbo_candidate_rssi_thres = + hdd_ctx->config->mbo_candidate_rssi_thres; + smeConfig->csrConfig.mbo_thresholds.mbo_current_rssi_thres = + hdd_ctx->config->mbo_current_rssi_thres; + smeConfig->csrConfig.mbo_thresholds.mbo_current_rssi_mcc_thres = + hdd_ctx->config->mbo_current_rssi_mcc_thres; + smeConfig->csrConfig.mbo_thresholds.mbo_candidate_rssi_btc_thres = + hdd_ctx->config->mbo_candidate_rssi_btc_thres; + smeConfig->csrConfig.btm_offload_config = + hdd_ctx->config->btm_offload_config; + smeConfig->csrConfig.btm_solicited_timeout = + hdd_ctx->config->btm_solicited_timeout; + smeConfig->csrConfig.btm_max_attempt_cnt = + hdd_ctx->config->btm_max_attempt_cnt; + smeConfig->csrConfig.btm_sticky_time = + hdd_ctx->config->btm_sticky_time; + hdd_update_bss_score_params(hdd_ctx->config, + &smeConfig->csrConfig.bss_score_params); + + hdd_update_11k_offload_params(hdd_ctx->config, + &smeConfig->csrConfig); + + if (pConfig->prefer_btm_query) { + smeConfig->csrConfig.btm_offload_config |= + (1 << BTM_OFFLOAD_CONFIG_BIT_8); + } + + if (pConfig->btm_abridge_config) { + smeConfig->csrConfig.btm_offload_config |= + (1 << BTM_OFFLOAD_CONFIG_BIT_7); + } + + smeConfig->csrConfig.btm_validity_timer = pConfig->btm_validity_timer; + smeConfig->csrConfig.btm_disassoc_timer_threshold = + pConfig->btm_disassoc_timer_threshold; + smeConfig->csrConfig.enable_bss_load_roam_trigger = + pConfig->enable_bss_load_roam_trigger; + smeConfig->csrConfig.bss_load_threshold = pConfig->bss_load_threshold; + smeConfig->csrConfig.bss_load_sample_time = + pConfig->bss_load_sample_time; + + + sme_update_beacon_stats(mac_handle, + hdd_ctx->config->enable_beacon_reception_stats); + status = sme_update_config(mac_handle, smeConfig); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("sme_update_config() failure: %d", status); + + qdf_mem_free(smeConfig); + return status; +} + +/** + * hdd_execute_global_config_command() - execute the global config command + * @hdd_ctx: the pointer to hdd context + * @command: the command to run + * + * Return: the QDF_STATUS return from hdd_execute_config_command + */ +QDF_STATUS hdd_execute_global_config_command(struct hdd_context *hdd_ctx, + char *command) +{ + return hdd_execute_config_command(g_registry_table, + ARRAY_SIZE(g_registry_table), + (uint8_t *) hdd_ctx->config, + hdd_ctx, command); +} + +/** + * hdd_cfg_get_global_config() - get the configuration table + * @hdd_ctx: pointer to hdd context + * @pBuf: buffer to store the configuration + * @buflen: size of the buffer + * + * Return: QDF_STATUS_SUCCESS if the configuration and buffer size can carry + * the content, otherwise QDF_STATUS_E_RESOURCES + */ +QDF_STATUS hdd_cfg_get_global_config(struct hdd_context *hdd_ctx, char *pBuf, + int buflen) +{ + return hdd_cfg_get_config(g_registry_table, + ARRAY_SIZE(g_registry_table), + (uint8_t *) hdd_ctx->config, hdd_ctx, pBuf, + buflen); +} + +/** + * hdd_get_pmkid_modes() - returns PMKID mode bits + * @hdd_ctx: the pointer to hdd context + * + * Return: value of pmkid_modes + */ +void hdd_get_pmkid_modes(struct hdd_context *hdd_ctx, + struct pmkid_mode_bits *pmkid_modes) +{ + pmkid_modes->fw_okc = (hdd_ctx->config->pmkid_modes & + CFG_PMKID_MODES_OKC) ? 1 : 0; + pmkid_modes->fw_pmksa_cache = (hdd_ctx->config->pmkid_modes & + CFG_PMKID_MODES_PMKSA_CACHING) ? 1 : 0; +} + +bool hdd_validate_prb_req_ie_bitmap(struct hdd_context *hdd_ctx) +{ + if (!(hdd_ctx->config->probe_req_ie_bitmap_0 || + hdd_ctx->config->probe_req_ie_bitmap_1 || + hdd_ctx->config->probe_req_ie_bitmap_2 || + hdd_ctx->config->probe_req_ie_bitmap_3 || + hdd_ctx->config->probe_req_ie_bitmap_4 || + hdd_ctx->config->probe_req_ie_bitmap_5 || + hdd_ctx->config->probe_req_ie_bitmap_6 || + hdd_ctx->config->probe_req_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 ((hdd_ctx->config->probe_req_ie_bitmap_6 & + VENDOR_SPECIFIC_IE_BITMAP) && + (strlen(hdd_ctx->config->probe_req_ouis) < 8)) + return false; + + /* check whether vendor oui IE is not set but OUIs are present */ + if (!(hdd_ctx->config->probe_req_ie_bitmap_6 & + VENDOR_SPECIFIC_IE_BITMAP) && + (strlen(hdd_ctx->config->probe_req_ouis) > 0)) + return false; + + return true; +} + +int hdd_parse_probe_req_ouis(struct hdd_context *hdd_ctx) +{ + uint32_t *voui = hdd_ctx->config->probe_req_voui; + char *str; + uint8_t *token; + uint32_t oui_indx = 0; + int ret; + uint32_t hex_value; + + str = (char *)(hdd_ctx->config->probe_req_ouis); + str[MAX_PRB_REQ_VENDOR_OUI_INI_LEN - 1] = '\0'; + hdd_ctx->config->no_of_probe_req_ouis = 0; + + if (!strlen(str)) { + hdd_info("NO OUIS to parse"); + return 0; + } + + token = strsep(&str, " "); + while (token) { + if (strlen(token) != 8) + goto next_token; + + ret = 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) + return -EINVAL; + + hdd_ctx->config->no_of_probe_req_ouis = oui_indx; + + return 0; +} + +static void +hdd_populate_vdev_nss(struct 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 hdd_adapter *adapter, + uint8_t tx_nss, + uint8_t rx_nss) +{ + enum nss_chains_band_info band; + struct mlme_nss_chains user_cfg; + mac_handle_t mac_handle; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + 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; + } + + if (!hdd_is_vdev_in_conn_state(adapter)) { + hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command", + adapter->session_id); + return QDF_STATUS_E_FAILURE; + } + + 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, + adapter->session_id))) + return QDF_STATUS_E_FAILURE; + + /* Check TDLS status and update antenna mode */ + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) && + policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) + wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter, rx_nss); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_update_nss() - Update the number of spatial streams supported. + * Ensure that nss is either 1 or 2 before calling this. + * + * @adapter: the pointer to adapter + * @nss: the number of 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 hdd_adapter *adapter, uint8_t nss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_config *hdd_config = hdd_ctx->config; + uint32_t temp = 0; + uint32_t rx_supp_data_rate, tx_supp_data_rate; + bool status = true; + tSirMacHTCapabilityInfo *ht_cap_info; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET] = {0}; + uint8_t mcs_set_temp[SIZE_OF_SUPPORTED_MCS_SET]; + uint32_t val, val32; + uint16_t val16; + uint8_t enable2x2; + mac_handle_t mac_handle; + uint8_t tx_nss, rx_nss; + + if ((nss == 2) && (hdd_ctx->num_rf_chains != 2)) { + hdd_err("No support for 2 spatial streams"); + return QDF_STATUS_E_INVAL; + } + + if (nss > MAX_VDEV_NSS) { + hdd_debug("Cannot support %d nss streams", nss); + return QDF_STATUS_E_INVAL; + } + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("NULL MAC handle"); + return QDF_STATUS_E_INVAL; + } + + /* Till now we dont have support for different rx, tx nss values */ + tx_nss = nss; + rx_nss = nss; + + if (hdd_ctx->dynamic_nss_chains_support) + return hdd_set_nss_params(adapter, tx_nss, rx_nss); + + enable2x2 = (nss == 1) ? 0 : 1; + + if (hdd_config->enable2x2 == 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; + } + + hdd_config->enable2x2 = enable2x2; + + if (!hdd_config->enable2x2) { + /* 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; + } else { + /* 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; + } + + /* Update Rx Highest Long GI data Rate */ + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + rx_supp_data_rate) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE to CFG"); + } + + /* Update Tx Highest Long GI data Rate */ + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + tx_supp_data_rate) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE to CFG"); + } + + sme_cfg_get_int(mac_handle, WNI_CFG_HT_CAP_INFO, &temp); + val16 = (uint16_t)temp; + ht_cap_info = (tSirMacHTCapabilityInfo *)&val16; + if (!(hdd_ctx->ht_tx_stbc_supported && hdd_config->enable2x2)) { + ht_cap_info->txSTBC = 0; + } else { + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_TXSTBC, &val32); + hdd_debug("STBC %d", val32); + ht_cap_info->txSTBC = val32; + } + temp = val16; + if (sme_cfg_set_int(mac_handle, WNI_CFG_HT_CAP_INFO, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_HT_CAP_INFO to CFG"); + } + + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_BASIC_MCS_SET, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtRxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtRxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_BASIC_MCS_SET, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_BASIC_MCS_SET to CFG"); + } + + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_RX_MCS_MAP, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtRxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtRxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_RX_MCS_MAP, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_RX_MCS_MAP to CFG"); + } + + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_TX_MCS_MAP, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtTxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtTxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_TX_MCS_MAP, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_TX_MCS_MAP to CFG"); + } + +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + val = SIZE_OF_SUPPORTED_MCS_SET; + sme_cfg_get_str(mac_handle, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set_temp, &val); + + mcs_set[0] = mcs_set_temp[0]; + if (hdd_config->enable2x2) + for (val = 0; val < nss; val++) + mcs_set[val] = WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + + if (sme_cfg_set_str(mac_handle, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, + SIZE_OF_SUPPORTED_MCS_SET) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on MCS SET to CFG"); + } + sme_update_he_cap_nss(mac_handle, adapter->session_id, nss); +#undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES + + if (QDF_STATUS_SUCCESS != sme_update_nss(mac_handle, nss)) + status = false; + + hdd_set_policy_mgr_user_cfg(hdd_ctx); + return (status == false) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c new file mode 100644 index 0000000000000000000000000000000000000000..c39236c3cb95c890e0d4aaee42480ce0c5a44821 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c @@ -0,0 +1,23180 @@ +/* + * 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: wlan_hdd_cfg80211.c + * + * WLAN Host Device Driver cfg80211 APIs implementation + * + */ + +#include +#include +#include +#include +#include +#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 "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_types.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 "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" + +#ifdef WLAN_UMAC_CONVERGENCE +#include "wlan_cfg80211.h" +#endif +#include +#include +#include + +#include "wlan_hdd_ext_scan.h" + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#include "wlan_hdd_stats.h" +#endif +#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 "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_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_hdd_object_manager.h" +#include "wlan_hdd_coex_config.h" +#include "wlan_hdd_hw_capability.h" + +#define g_mode_rates_size (12) +#define a_mode_rates_size (8) + +/* + * Android CTS verifier needs atleast this much wait time (in msec) + */ +#define MAX_REMAIN_ON_CHANNEL_DURATION (5000) + +/* + * Refer @tCfgProtection structure for definition of the bit map. + * below value is obtained by setting the following bit-fields. + * enable obss, fromllb, overlapOBSS and overlapFromllb protection. + */ +#define IBSS_CFG_PROTECTION_ENABLE_MASK 0x8282 + +#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, \ + } + +#ifndef WLAN_AKM_SUITE_FT_8021X +#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03 +#endif + +#ifndef WLAN_AKM_SUITE_FT_PSK +#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04 +#endif + +#define HDD_CHANNEL_14 14 + +#define IS_DFS_MODE_VALID(mode) ((mode >= DFS_MODE_NONE && \ + mode <= DFS_MODE_DEPRIORITIZE)) + +#define MAX_TXPOWER_SCALE 4 +#define CDS_MAX_FEATURE_SET 8 + +/* + * 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 +#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 + +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 +#ifdef WLAN_FEATURE_11W + 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 +#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_etsi13_srd_ch[] = { + HDD5GHZCHAN(5845, 169, 0), + HDD5GHZCHAN(5865, 173, 0), +}; +#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, +}; + +/* 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_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), + }, +}; + +/* Interface limits and combinations registered by the driver */ + +/* STA ( + STA ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_iface_limit[] = { + { + .max = 3, /* p2p0 is a STA as well */ + .types = BIT(NL80211_IFTYPE_STATION), + }, +}; + +/* ADHOC (IBSS) limit */ +static const struct ieee80211_iface_limit + wlan_hdd_adhoc_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; + +/* AP ( + AP ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_ap_iface_limit[] = { + { + .max = (QDF_MAX_NO_OF_SAP_MODE + SAP_MAX_OBSS_STA_CNT), + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +/* 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), + }, +}; + +static const struct ieee80211_iface_limit + wlan_hdd_sta_ap_iface_limit[] = { + { + /* We need 1 extra STA interface for OBSS scan when SAP starts + * with HT40 in STA+SAP concurrency mode + */ + .max = (1 + SAP_MAX_OBSS_STA_CNT), + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = QDF_MAX_NO_OF_SAP_MODE, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +/* STA + P2P combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_p2p_iface_limit[] = { + { + /* One reserved for dedicated P2PDEV usage */ + .max = 2, + .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 + P2PGO combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sta_ap_p2pgo_iface_limit[] = { + /* Support for AP+P2PGO interfaces */ + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + } +}; + +/* SAP + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sap_p2p_iface_limit[] = { + { + /* 1 dedicated for p2p0 which is a STA type */ + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* 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[] = { + { + /* 1 dedicated for p2p0 which is a STA type */ + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* 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) + }, +}; + +static const struct ieee80211_iface_limit + wlan_hdd_mon_iface_limit[] = { + { + .max = 3, /* Monitor interface */ + .types = BIT(NL80211_IFTYPE_MONITOR), + }, +}; + +static struct ieee80211_iface_combination + wlan_hdd_iface_combination[] = { + /* STA */ + { + .limits = wlan_hdd_sta_iface_limit, + .num_different_channels = 2, + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_iface_limit), + }, + /* ADHOC */ + { + .limits = wlan_hdd_adhoc_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_adhoc_iface_limit), + }, + /* AP */ + { + .limits = wlan_hdd_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (SAP_MAX_OBSS_STA_CNT + 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 + }, + /* P2P */ + { + .limits = wlan_hdd_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit), + }, + /* STA + AP */ + { + .limits = wlan_hdd_sta_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (1 + SAP_MAX_OBSS_STA_CNT + QDF_MAX_NO_OF_SAP_MODE), + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit), + .beacon_int_infra_match = true, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) || \ + defined(CFG80211_BEACON_INTERVAL_BACKPORT) + .beacon_int_min_gcd = 1, +#endif + }, + /* STA + P2P */ + { + .limits = wlan_hdd_sta_p2p_iface_limit, + .num_different_channels = 2, + /* one interface reserved for P2PDEV dedicated usage */ + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* STA + P2P GO + SAP */ + { + .limits = wlan_hdd_sta_ap_p2pgo_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, + /* one interface reserved for P2PDEV dedicated usage */ + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_p2pgo_iface_limit), + .beacon_int_infra_match = true, + }, + /* SAP + P2P */ + { + .limits = wlan_hdd_sap_p2p_iface_limit, + .num_different_channels = 2, + /* 1-p2p0 + 1-SAP + 1-P2P (on p2p0 or p2p-p2p0-x) */ + .max_interfaces = 3, + .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, + /* 1-p2p0 + 2-P2P (on p2p-p2p0-x) */ + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* Monitor */ + { + .limits = wlan_hdd_mon_iface_limit, + .max_interfaces = 3, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit), + }, +}; + +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 hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb; + uint32_t set = 0; + uint32_t max_num_tdls_sta = 0; + + 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; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (2 * sizeof(u32)) + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + goto fail; + } + + if (false == hdd_ctx->config->fEnableTDLSSupport) { + 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 { + set = set | WIFI_TDLS_SUPPORT; + set = set | (hdd_ctx->config->fTDLSExternalControl ? + WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT : 0); + set = set | (hdd_ctx->config->fEnableTDLSOffChannel ? + WIIF_TDLS_OFFCHANNEL_SUPPORT : 0); + if (hdd_ctx->config->fEnableTDLSSleepSta || + hdd_ctx->config->fEnableTDLSBufferSta || + hdd_ctx->config->fEnableTDLSOffChannel) + max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA_P_UAPSD_OFFCHAN; + else + max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA; + + hdd_debug("TDLS Feature supported value %x", set); + 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 cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_tdls_capabilities(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#ifdef QCA_HT_2040_COEX +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work); +#endif + +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 *vendor_event; + + 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; + } + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, sizeof(struct ch_avoid_ind_type), + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -EINVAL; + } + + memcpy(skb_put(vendor_event, sizeof(struct ch_avoid_ind_type)), + (void *)avoid_freq_list, sizeof(struct ch_avoid_ind_type)); + + cfg80211_vendor_event(vendor_event, 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_REASON_UNSPECIFIED: + default: + ret_val = QCA_WLAN_HANG_REASON_UNSPECIFIED; + } + 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 + * + * Return: 0 on success or failure reason + */ +int wlan_hdd_send_hang_reason_event(struct hdd_context *hdd_ctx, + enum qdf_hang_reason reason) +{ + 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 = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + sizeof(uint32_t), + HANG_REASON_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("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)) { + hdd_err("QCA_WLAN_VENDOR_ATTR_HANG_REASON put fail"); + kfree_skb(vendor_event); + return -EINVAL; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + hdd_exit(); + return 0; +} + +#undef HANG_REASON_INDEX + +/** + * wlan_hdd_get_adjacent_chan(): Gets next/previous channel + * with respect to the channel passed. + * @chan: Channel + * @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. + */ +int wlan_hdd_get_adjacent_chan(uint8_t chan, bool upper) +{ + enum channel_enum ch_idx = reg_get_chan_enum(chan); + + if (ch_idx == INVALID_CHANNEL) + return -EINVAL; + + if (upper && (ch_idx < (NUM_CHANNELS - 1))) + ch_idx++; + else if (!upper && (ch_idx > CHAN_ENUM_1)) + ch_idx--; + else + return -EINVAL; + + return WLAN_REG_CH_NUM(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_chan: AP/P2P-GO operating channel + * + * 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_chan = 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, uint8_t op_chan) +{ + struct ch_avoid_ind_type p2p_avoid_freq_list; + uint8_t min_chan, max_chan; + int ret; + int chan; + + 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_chan) { +#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(op_chan)) { + min_chan = REG_MIN_24GHZ_CH_NUM; + max_chan = REG_MAX_24GHZ_CH_NUM; + } else if WLAN_REG_IS_5GHZ_CH(op_chan) { + min_chan = REG_MIN_5GHZ_CH_NUM; + max_chan = REG_MAX_5GHZ_CH_NUM; + } else { + hdd_err("invalid channel:%d", op_chan); + return -EINVAL; + } + + if ((op_chan > min_chan) && (op_chan < max_chan)) { + p2p_avoid_freq_list.ch_avoid_range_cnt = 2; + p2p_avoid_freq_list.avoid_freq_range[0].start_freq = + wlan_chan_to_freq(min_chan); + + /* Get channel before the op_chan */ + chan = wlan_hdd_get_adjacent_chan(op_chan, false); + if (chan < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[0].end_freq = + wlan_chan_to_freq(chan); + + /* Get channel next to the op_chan */ + chan = wlan_hdd_get_adjacent_chan(op_chan, true); + if (chan < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[1].start_freq = + wlan_chan_to_freq(chan); + + p2p_avoid_freq_list.avoid_freq_range[1].end_freq = + wlan_chan_to_freq(max_chan); + } else if (op_chan == min_chan) { + p2p_avoid_freq_list.ch_avoid_range_cnt = 1; + + chan = wlan_hdd_get_adjacent_chan(op_chan, true); + if (chan < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[0].start_freq = + wlan_chan_to_freq(chan); + + p2p_avoid_freq_list.avoid_freq_range[0].end_freq = + wlan_chan_to_freq(max_chan); + } else { + p2p_avoid_freq_list.ch_avoid_range_cnt = 1; + p2p_avoid_freq_list.avoid_freq_range[0].start_freq = + wlan_chan_to_freq(min_chan); + + chan = wlan_hdd_get_adjacent_chan(op_chan, false); + if (chan < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[0].end_freq = + wlan_chan_to_freq(chan); + } +#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 + }, + +#ifdef WLAN_FEATURE_NAN + [QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_NAN + }, +#endif + +#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 */ +#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 */ + [QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI + }, +#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 */ + +#ifdef WLAN_FEATURE_NAN_DATAPATH + [QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NDP + }, +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + + [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, + }, +#ifdef WLAN_UMAC_CONVERGENCE + COMMON_VENDOR_EVENTS +#endif +}; + +/** + * __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 = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + NLMSG_HDRLEN); + + if (temp_skbuff != NULL) { + 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"); + kfree_skb(temp_skbuff); + + return ret_val; + } + + return 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __is_driver_dfs_capable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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; + tsap_config_t *sap_config, *con_sap_config; + int con_ch; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + 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->session.ap.sap_config; + con_sap_config = &con_sap_adapter->session.ap.sap_config; + con_ch = con_sap_adapter->session.ap.operating_channel; + + if (!wlan_reg_is_dfs_ch(hdd_ctx->pdev, con_ch)) + return 0; + + hdd_debug("Only SCC AP-AP DFS Permitted (ch=%d, con_ch=%d)", + sap_config->channel, con_ch); + hdd_debug("Overriding guest AP's channel"); + sap_config->channel = con_ch; + + if (con_sap_config->acs_cfg.acs_mode == true) { + if (con_ch != con_sap_config->acs_cfg.pri_ch && + con_ch != con_sap_config->acs_cfg.ht_sec_ch) { + hdd_err("Primary AP channel config error"); + hdd_err("Operating ch: %d ACS ch: %d %d", + con_ch, con_sap_config->acs_cfg.pri_ch, + con_sap_config->acs_cfg.ht_sec_ch); + 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.ch_list) + qdf_mem_free(sap_config->acs_cfg.ch_list); + + qdf_mem_copy(&sap_config->acs_cfg, + &con_sap_config->acs_cfg, + sizeof(struct sap_acs_cfg)); + sap_config->acs_cfg.ch_list = qdf_mem_malloc( + sizeof(uint8_t) * + con_sap_config->acs_cfg.ch_list_count); + if (!sap_config->acs_cfg.ch_list) { + hdd_err("ACS config alloc fail"); + sap_config->acs_cfg.ch_list_count = 0; + return -ENOMEM; + } + + qdf_mem_copy(sap_config->acs_cfg.ch_list, + con_sap_config->acs_cfg.ch_list, + con_sap_config->acs_cfg.ch_list_count); + sap_config->acs_cfg.ch_list_count = + con_sap_config->acs_cfg.ch_list_count; + + } else { + sap_config->acs_cfg.pri_ch = con_ch; + if (sap_config->acs_cfg.ch_width > eHT_CHANNEL_WIDTH_20MHZ) + sap_config->acs_cfg.ht_sec_ch = con_sap_config->sec_ch; + } + + return con_ch; +} + +/** + * 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( + tsap_config_t *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 = WLAN_REG_CH_NUM(CHAN_ENUM_1); + sap_cfg->acs_cfg.end_ch = WLAN_REG_CH_NUM(CHAN_ENUM_14); + } else if (hw_mode == QCA_ACS_MODE_IEEE80211G) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11g; + sap_cfg->acs_cfg.start_ch = WLAN_REG_CH_NUM(CHAN_ENUM_1); + sap_cfg->acs_cfg.end_ch = WLAN_REG_CH_NUM(CHAN_ENUM_13); + } else if (hw_mode == QCA_ACS_MODE_IEEE80211A) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11a; + sap_cfg->acs_cfg.start_ch = WLAN_REG_CH_NUM(CHAN_ENUM_36); + sap_cfg->acs_cfg.end_ch = WLAN_REG_CH_NUM(CHAN_ENUM_173); + } else if (hw_mode == QCA_ACS_MODE_IEEE80211ANY) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_abg; + sap_cfg->acs_cfg.start_ch = WLAN_REG_CH_NUM(CHAN_ENUM_1); + sap_cfg->acs_cfg.end_ch = WLAN_REG_CH_NUM(CHAN_ENUM_173); + } + + 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.ch_list) + return -EINVAL; + + sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[0]; + sap_cfg->acs_cfg.end_ch = + sap_cfg->acs_cfg.ch_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 > sap_cfg->acs_cfg.ch_list[i] && + sap_cfg->acs_cfg.ch_list[i] != 0) + sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[i]; + if (sap_cfg->acs_cfg.end_ch < sap_cfg->acs_cfg.ch_list[i]) + sap_cfg->acs_cfg.end_ch = sap_cfg->acs_cfg.ch_list[i]; + } + + return 0; +} + + +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work); + + +static void hdd_update_acs_channel_list(tsap_config_t *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( + sap_config->acs_cfg.ch_list[i])) { + sap_config->acs_cfg.ch_list[temp_count] = + sap_config->acs_cfg.ch_list[i]; + temp_count++; + } + } else if (BAND_5G == band) { + if (WLAN_REG_IS_5GHZ_CH( + sap_config->acs_cfg.ch_list[i])) { + sap_config->acs_cfg.ch_list[temp_count] = + sap_config->acs_cfg.ch_list[i]; + temp_count++; + } + } + } + sap_config->acs_cfg.ch_list_count = temp_count; +} + + +/** + * wlan_hdd_cfg80211_start_acs : Start ACS Procedure for SAP + * @adapter: pointer to SAP adapter struct + * + * 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 hdd_adapter *adapter) +{ + + struct hdd_context *hdd_ctx; + tsap_config_t *sap_config; + tpWLAN_SAPEventCB acs_event_callback; + int status; + + if (!adapter) { + hdd_err("adapter is NULL"); + return -EINVAL; + } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + sap_config = &adapter->session.ap.sap_config; + if (!sap_config) { + hdd_err("SAP config is NULL"); + return -EINVAL; + } + if (hdd_ctx->acs_policy.acs_channel) + sap_config->channel = hdd_ctx->acs_policy.acs_channel; + else + sap_config->channel = AUTO_CHANNEL_SELECT; + /* + * No DFS SCC is allowed in Auto use case. Hence not + * calling DFS override + */ + if (QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION != + hdd_ctx->config->WlanMccToSccSwitchMode) { + 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(adapter); + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + 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 (conc_connection_info[0].mac == + conc_connection_info[1].mac) { + if (WLAN_REG_IS_5GHZ_CH(sap_config->acs_cfg. + pcl_channels[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)); + hdd_info("ACS Started for %s", adapter->dev->name); + status = wlansap_acs_chselect( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + acs_event_callback, sap_config, adapter->dev); + + + if (status) { + hdd_err("ACS channel select failed"); + return -EINVAL; + } + if (sap_is_auto_channel_select(WLAN_HDD_GET_SAP_CTX_PTR(adapter))) + sap_config->acs_cfg.acs_mode = true; + set_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + + 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, + tsap_config_t *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.ch_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.ch_list[i] == + sap_config->acs_cfg.pcl_channels[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 contructs channel info + * for all the given channel + * @adapter: pointer to SAP adapter struct + * @channel_count: channel count + * @channel_list: channel list + * + * Return: Status of of channel information updation + */ +static int hdd_update_reg_chan_info(struct hdd_adapter *adapter, + uint32_t channel_count, + uint8_t *channel_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); + tsap_config_t *sap_config = &adapter->session.ap.sap_config; + mac_handle_t mac_handle; + + /* memory allocation */ + sap_config->channel_info = qdf_mem_malloc( + sizeof(struct hdd_channel_info) * + channel_count); + if (!sap_config->channel_info) { + hdd_err("memory allocation failed"); + return -ENOMEM; + + } + mac_handle = hdd_ctx->mac_handle; + sap_config->channel_info_count = channel_count; + for (i = 0; i < channel_count; i++) { + icv = &sap_config->channel_info[i]; + chan = channel_list[i]; + + if (chan == 0) + continue; + + if (sap_config->acs_cfg.ch_width == CH_WIDTH_40MHZ) + bw_offset = 1 << BW_40_OFFSET_BIT; + else if (sap_config->acs_cfg.ch_width == CH_WIDTH_20MHZ) + bw_offset = 1 << BW_20_OFFSET_BIT; + icv->freq = wlan_reg_get_channel_freq(hdd_ctx->pdev, chan); + icv->ieee_chan_number = chan; + icv->max_reg_power = wlan_reg_get_channel_reg_power( + hdd_ctx->pdev, chan); + + /* 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; + + icv->reg_class_id = + wlan_hdd_find_opclass(mac_handle, chan, bw_offset); + + if (WLAN_REG_IS_5GHZ_CH(chan)) { + ch_params.ch_width = sap_config->acs_cfg.ch_width; + wlan_reg_set_channel_params(hdd_ctx->pdev, chan, + 0, &ch_params); + 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, chan, + sap_config->acs_cfg.ch_width, + sap_config->acs_cfg.is_ht_enabled, + sap_config->acs_cfg.is_vht_enabled, + hdd_ctx->config->enable_sub_20_channel_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 + +/** + * hdd_cfg80211_update_channel_info() - add channel info attributes + * @skb: pointer to sk buff + * @hdd_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_cfg80211_update_channel_info(struct sk_buff *skb, + tsap_config_t *sap_config, int idx) +{ + struct nlattr *nla_attr, *channel; + struct hdd_channel_info *icv; + int i; + + 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; + } + 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)) { + 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 + +/** + * hdd_cfg80211_update_pcl() - add pcl info attributes + * @skb: pointer to sk buff + * @hdd_ctx: pointer to hdd station context + * @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 sk_buff *skb, + uint8_t ch_list_count, int idx, + uint8_t *vendor_pcl_list, uint8_t *vendor_weight_list) +{ + struct nlattr *nla_attr, *channel; + int i; + + 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; + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL, + 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, + tsap_config_t *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; + } +} + +/** + * hdd_get_freq_list: API to get Frequency list based on channel list + * @channel_list: channel list + * @freq_list: frequency list + * @channel_count: channel count + * + * Return: None + */ +static void hdd_get_freq_list(uint8_t *channel_list, uint32_t *freq_list, + uint32_t channel_count) +{ + int count; + + for (count = 0; count < channel_count ; count++) + freq_list[count] = cds_chan_to_freq(channel_list[count]); +} + +int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter, + uint8_t reason) +{ + struct sk_buff *skb; + tsap_config_t *sap_config; + uint32_t channel_count = 0, status = -EINVAL; + uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t freq_list[QDF_MAX_NUM_CHAN] = {0}; + uint8_t vendor_pcl_list[QDF_MAX_NUM_CHAN] = {0}; + uint8_t vendor_weight_list[QDF_MAX_NUM_CHAN] = {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; + + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return -EINVAL; + } + + hdd_enter(); + sap_config = &adapter->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 (conc_connection_info[0].mac == + conc_connection_info[1].mac) { + + if (WLAN_REG_IS_5GHZ_CH(sap_config->acs_cfg. + pcl_channels[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->session.ap.sap_config, &band); + + if (sap_config->acs_cfg.ch_list) { + /* Copy INI or hostapd provided ACS channel range*/ + qdf_mem_copy(channel_list, sap_config->acs_cfg.ch_list, + sap_config->acs_cfg.ch_list_count); + 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, + channel_list, + band); + } + + hdd_update_reg_chan_info(adapter, channel_count, channel_list); + hdd_get_freq_list(channel_list, freq_list, channel_count); + /* Get phymode */ + phy_mode = adapter->session.ap.sap_config.acs_cfg.hw_mode; + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &(adapter->wdev), + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_UPDATE_EXTERNAL_ACS_CONFIG, + GFP_KERNEL); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + /* + * 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.channel_count = channel_count; + acs_chan_params.channel_list = channel_list; + 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.channel_count) { + hdd_debug("ACS channel list: len: %d", + acs_chan_params.channel_count); + for (i = 0; i < acs_chan_params.channel_count; i++) + hdd_debug("%d ", acs_chan_params.channel_list[i]); + } + + 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:%d, weight:%d ", + acs_chan_params. + vendor_pcl_list[i], + acs_chan_params. + vendor_weight_list[i]); + } + + if (HDD_EXTERNAL_ACS_PCL_MANDATORY == + hdd_ctx->config->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(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; + + status = hdd_cfg80211_update_channel_info(skb, sap_config, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO); + + qdf_mem_free(sap_config->channel_info); + 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; + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; +fail: + if (skb) + kfree_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->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) { + hdd_err("Could not allocate for timer_context"); + return -ENOMEM; + } + timer_context->adapter = adapter; + + set_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->event_flags); + status = qdf_mc_timer_init(&adapter->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->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_UNSPEC }, + [QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST] = { .type = NLA_UNSPEC }, +}; + +int hdd_start_vendor_acs(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int status; + + 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; + } + + if (hdd_ctx->config->acs_support_for_dfs_ltecoex) + status = qdf_status_to_os_return(wlan_sap_set_vendor_acs( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + true)); + else + status = qdf_status_to_os_return(wlan_sap_set_vendor_acs( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + false)); + + return status; +} + +/** + * __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); + tsap_config_t *sap_config; + struct sk_buff *temp_skbuff; + int ret, i, ch_cnt = 0; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1]; + bool ht_enabled, ht40_enabled, vht_enabled; + uint8_t ch_width; + enum qca_wlan_vendor_acs_hw_mode hw_mode; + QDF_STATUS qdf_status; + uint8_t conc_channel; + mac_handle_t mac_handle; + bool skip_etsi13_srd_chan = false; + + /* ***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 paremeters from HDD to SAP is global. Thus All ACS related SME + * config shall be set only from start_acs. + */ + + 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; + + hdd_debug("current country is %s", hdd_ctx->reg.alpha2); + + 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; + } + + if (qdf_atomic_read(&adapter->session.ap.acs_in_progress) > 0) { + hdd_err("ACS rejected as previous req already in progress"); + return -EINVAL; + } else { + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 1); + } + + 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; + } + hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]) + ht_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]); + else + ht_enabled = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]) + ht40_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]); + else + ht40_enabled = 0; + + hdd_debug("ht40_enabled %d", ht40_enabled); + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]) + vht_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]); + else + vht_enabled = 0; + + if (((adapter->device_mode == QDF_SAP_MODE) && + (hdd_ctx->config->sap_force_11n_for_11ac)) || + ((adapter->device_mode == QDF_P2P_GO_MODE) && + (hdd_ctx->config->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]); + } else { + if (ht_enabled && ht40_enabled) + ch_width = 40; + else + ch_width = 20; + } + + /* 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; + } + + sap_config = &adapter->session.ap.sap_config; + + /* Check and free if memory is already allocated for acs channel list */ + wlan_hdd_undo_acs(adapter); + + qdf_mem_zero(&sap_config->acs_cfg, sizeof(struct sap_acs_cfg)); + sap_config->acs_cfg.dfs_master_mode = + hdd_ctx->config->enableDFSMasterCap; + hdd_debug("channel width =%d", ch_width); + 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; + + /* hw_mode = a/b/g: QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST and + * QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attrs are present, and + * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is used for obtaining the + * channel list, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST is ignored + * since it contains the frequency values of the channels in + * the channel list. + * hw_mode = any: only QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attr + * is present + */ + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]) { + char *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.ch_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count); + sap_config->acs_cfg.master_ch_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count); + if (!sap_config->acs_cfg.ch_list || + !sap_config->acs_cfg.master_ch_list) { + ret = -ENOMEM; + goto out; + } + + qdf_mem_copy(sap_config->acs_cfg.ch_list, tmp, + sap_config->acs_cfg.ch_list_count); + qdf_mem_copy(sap_config->acs_cfg.master_ch_list, tmp, + sap_config->acs_cfg.ch_list_count); + sap_config->acs_cfg.master_ch_list_count = + sap_config->acs_cfg.ch_list_count; + } + } else 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.ch_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count); + sap_config->acs_cfg.master_ch_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count); + if (!sap_config->acs_cfg.ch_list || + !sap_config->acs_cfg.master_ch_list) { + ret = -ENOMEM; + goto out; + } + + /* convert frequency to channel */ + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) + sap_config->acs_cfg.ch_list[i] = + ieee80211_frequency_to_channel(freq[i]); + qdf_mem_copy(sap_config->acs_cfg.master_ch_list, + sap_config->acs_cfg.ch_list, + sap_config->acs_cfg.ch_list_count); + 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; + } + + skip_etsi13_srd_chan = + !hdd_ctx->config->etsi13_srd_chan_in_master_mode && + wlan_reg_is_etsi13_regdmn(hdd_ctx->pdev); + + if (skip_etsi13_srd_chan) { + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) { + if (wlan_reg_is_etsi13_srd_chan(hdd_ctx->pdev, + sap_config->acs_cfg. + ch_list[i])) + sap_config->acs_cfg.ch_list[i] = 0; + else + sap_config->acs_cfg.ch_list[ch_cnt++] = + sap_config->acs_cfg.ch_list[i]; + } + sap_config->acs_cfg.ch_list_count = ch_cnt; + } + hdd_debug("get pcl for DO_ACS vendor command"); + + /* consult policy manager to get PCL */ + qdf_status = policy_mgr_get_pcl(hdd_ctx->psoc, PM_SAP_MODE, + sap_config->acs_cfg.pcl_channels, + &sap_config->acs_cfg.pcl_ch_count, + sap_config->acs_cfg.pcl_channels_weight_list, + QDF_MAX_NUM_CHAN); + if (qdf_status != QDF_STATUS_SUCCESS) + hdd_err("Get PCL failed"); + + if (sap_config->acs_cfg.pcl_ch_count) { + hdd_debug("ACS config PCL: len: %d", + sap_config->acs_cfg.pcl_ch_count); + for (i = 0; i < sap_config->acs_cfg.pcl_ch_count; i++) + hdd_debug("channel:%d, weight:%d ", + sap_config->acs_cfg. + pcl_channels[i], + sap_config->acs_cfg. + pcl_channels_weight_list[i]); + } + + if (hw_mode == QCA_ACS_MODE_IEEE80211ANY) + policy_mgr_trim_acs_channel_list(hdd_ctx->psoc, + sap_config->acs_cfg.ch_list, + &sap_config->acs_cfg.ch_list_count); + + sap_config->acs_cfg.band = hw_mode; + 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; + } + + /* ACS override for android */ + if (ht_enabled && + sap_config->acs_cfg.end_ch >= WLAN_REG_CH_NUM(CHAN_ENUM_36) && + ((adapter->device_mode == QDF_SAP_MODE && + !hdd_ctx->config->sap_force_11n_for_11ac && + hdd_ctx->config->sap_11ac_override) || + (adapter->device_mode == QDF_P2P_GO_MODE && + !hdd_ctx->config->go_force_11n_for_11ac && + hdd_ctx->config->go_11ac_override))) { + hdd_debug("ACS Config override for 11AC, vhtChannelWidth %d", + hdd_ctx->config->vhtChannelWidth); + vht_enabled = 1; + sap_config->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac; + sap_config->acs_cfg.ch_width = + hdd_ctx->config->vhtChannelWidth; + } + + /* No VHT80 in 2.4G so perform ACS accordingly */ + if (sap_config->acs_cfg.end_ch <= 14 && + sap_config->acs_cfg.ch_width == eHT_CHANNEL_WIDTH_80MHZ) { + sap_config->acs_cfg.ch_width = eHT_CHANNEL_WIDTH_40MHZ; + hdd_debug("resetting to 40Mhz in 2.4Ghz"); + } + + hdd_debug("ACS Config for %s: HW_MODE: %d ACS_BW: %d HT: %d VHT: %d START_CH: %d END_CH: %d band %d", + adapter->dev->name, sap_config->acs_cfg.hw_mode, + sap_config->acs_cfg.ch_width, ht_enabled, vht_enabled, + sap_config->acs_cfg.start_ch, sap_config->acs_cfg.end_ch, + sap_config->acs_cfg.band); + 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, + sap_config->acs_cfg.end_ch); + if (hdd_ctx->config->auto_channel_select_weight) + sap_config->auto_channel_select_weight = + hdd_ctx->config->auto_channel_select_weight; + + sap_config->acs_cfg.is_ht_enabled = ht_enabled; + sap_config->acs_cfg.is_vht_enabled = vht_enabled; + + if (sap_config->acs_cfg.ch_list_count) { + hdd_debug("ACS channel list: len: %d", + sap_config->acs_cfg.ch_list_count); + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) + hdd_debug("%d ", sap_config->acs_cfg.ch_list[i]); + } + + conc_channel = policy_mgr_mode_specific_get_channel(hdd_ctx->psoc, + PM_STA_MODE); + if ((hdd_ctx->config->external_acs_policy == + HDD_EXTERNAL_ACS_PCL_MANDATORY) && conc_channel) { + if ((conc_channel >= WLAN_REG_CH_NUM(CHAN_ENUM_36) && + sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211A) || + (conc_channel <= WLAN_REG_CH_NUM(CHAN_ENUM_14) && + (sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211B || + sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211G))) { + sap_config->acs_cfg.pri_ch = conc_channel; + wlan_sap_set_sap_ctx_acs_cfg( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), sap_config); + mac_handle = hdd_ctx->mac_handle; + sap_config_acs_result(mac_handle, + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + sap_config->acs_cfg.ht_sec_ch); + sap_config->ch_params.ch_width = + sap_config->acs_cfg.ch_width; + sap_config->ch_params.sec_ch_offset = + sap_config->acs_cfg.ht_sec_ch; + sap_config->ch_params.center_freq_seg0 = + sap_config->acs_cfg.vht_seg0_center_ch; + sap_config->ch_params.center_freq_seg1 = + sap_config->acs_cfg.vht_seg1_center_ch; + /*notify hostapd about channel override */ + wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + ret = 0; + goto out; + } + } + + sap_config->acs_cfg.acs_mode = true; + if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) { + /* ***Note*** Completion variable usage is not allowed + * here since ACS scan operation may take max 2.2 sec + * for 5G band: + * 9 Active channel X 40 ms active scan time + + * 16 Passive channel X 110ms passive scan time + * Since this CFG80211 call lock rtnl mutex, we cannot hold on + * for this long. So we split up the scanning part. + */ + set_bit(ACS_PENDING, &adapter->event_flags); + hdd_debug("ACS Pending for %s", adapter->dev->name); + ret = 0; + } else { + /* Check if vendor specific acs is enabled */ + if (hdd_ctx->config->vendor_acs_support) + ret = hdd_start_vendor_acs(adapter); + else + ret = wlan_hdd_cfg80211_start_acs(adapter); + } + +out: + if (ret == 0) { + temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + NLMSG_HDRLEN); + if (temp_skbuff != NULL) + return cfg80211_vendor_cmd_reply(temp_skbuff); + } + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + wlan_hdd_undo_acs(adapter); + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_do_acs(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_undo_acs : Do cleanup of DO_ACS + * @adapter: Pointer to adapter struct + * + * This function handle cleanup of what was done in DO_ACS, including free + * memory. + * + * Return: void + */ + +void wlan_hdd_undo_acs(struct hdd_adapter *adapter) +{ + if (adapter == NULL) + return; + if (adapter->session.ap.sap_config.acs_cfg.ch_list) { + hdd_debug("Clear acs cfg channel list"); + qdf_mem_free(adapter->session.ap.sap_config.acs_cfg.ch_list); + adapter->session.ap.sap_config.acs_cfg.ch_list = NULL; + } + adapter->session.ap.sap_config.acs_cfg.ch_list_count = 0; + if (adapter->session.ap.sap_config.acs_cfg.master_ch_list) { + hdd_debug("Clear acs cfg channel list"); + qdf_mem_free( + adapter->session.ap.sap_config.acs_cfg.master_ch_list); + adapter->session.ap.sap_config.acs_cfg.master_ch_list = NULL; + } + adapter->session.ap.sap_config.acs_cfg.master_ch_list_count = 0; +} + +/** + * wlan_hdd_cfg80211_start_pending_acs : Start pending ACS procedure for SAP + * @work: Linux workqueue struct pointer for ACS work + * + * This function starts the ACS procedure which was marked pending when an ACS + * procedure was in progress for a concurrent SAP interface. + * + * Return: None + */ + +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work) +{ + struct hdd_adapter *adapter = container_of(work, struct hdd_adapter, + acs_pending_work.work); + + cds_ssr_protect(__func__); + wlan_hdd_cfg80211_start_acs(adapter); + cds_ssr_unprotect(__func__); + clear_bit(ACS_PENDING, &adapter->event_flags); +} + +/** + * wlan_hdd_cfg80211_acs_ch_select_evt: Callback function for ACS evt + * @adapter: Pointer to SAP adapter struct + * @pri_channel: SAP ACS procedure selected Primary channel + * @sec_channel: SAP ACS procedure selected secondary channel + * + * This is a callback function from SAP module 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 hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tsap_config_t *sap_cfg = &(WLAN_HDD_GET_AP_CTX_PTR(adapter))->sap_config; + struct sk_buff *vendor_event; + int ret_val; + struct hdd_adapter *con_sap_adapter; + uint16_t ch_width; + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &(adapter->wdev), + 4 * sizeof(u8) + 1 * sizeof(u16) + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL, + sap_cfg->acs_cfg.pri_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL, + sap_cfg->acs_cfg.ht_sec_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + sap_cfg->acs_cfg.vht_seg0_center_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + sap_cfg->acs_cfg.vht_seg1_center_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + 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"); + kfree_skb(vendor_event); + return; + } + if (sap_cfg->acs_cfg.pri_ch > 14) + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211A); + else + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211G); + + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE put fail"); + kfree_skb(vendor_event); + return; + } + + hdd_debug("ACS result for %s: PRI_CH: %d SEC_CH: %d VHT_SEG0: %d VHT_SEG1: %d ACS_BW: %d", + adapter->dev->name, sap_cfg->acs_cfg.pri_ch, + sap_cfg->acs_cfg.ht_sec_ch, sap_cfg->acs_cfg.vht_seg0_center_ch, + sap_cfg->acs_cfg.vht_seg1_center_ch, ch_width); + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + /* ***Note*** As already mentioned Completion variable usage is not + * allowed here since ACS scan operation may take max 2.2 sec. + * Further in AP-AP mode pending ACS is resumed here to serailize ACS + * operation. + * TODO: Delayed operation is used since SME-PMAC strut is global. Thus + * when Primary AP ACS is complete and secondary AP ACS is started here + * immediately, Primary AP start_bss may come inbetween ACS operation + * and overwrite Sec AP ACS parameters. Thus Sec AP ACS is executed with + * delay. This path and below constraint will be removed on sessionizing + * SAP acs parameters and decoupling SAP from PMAC (WIP). + * As per design constraint user space control application must take + * care of serailizing hostapd start for each VIF in AP-AP mode to avoid + * this code path. Sec AP hostapd should be started after Primary AP + * start beaconing which can be confirmed by getchannel iwpriv command + */ + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, false); + if (con_sap_adapter && + test_bit(ACS_PENDING, &con_sap_adapter->event_flags)) { + INIT_DELAYED_WORK(&con_sap_adapter->acs_pending_work, + wlan_hdd_cfg80211_start_pending_acs); + /* Lets give 1500ms for OBSS + START_BSS to complete */ + schedule_delayed_work(&con_sap_adapter->acs_pending_work, + msecs_to_jiffies(1500)); + } +} + +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; + + /* 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; + +#ifdef FEATURE_WLAN_EXTSCAN + if (hdd_ctx->config->extscan_enabled && + sme_is_feature_supported_by_fw(EXTENDED_SCAN)) { + hdd_debug("EXTScan is supported by firmware"); + fset |= WIFI_FEATURE_EXTSCAN | WIFI_FEATURE_HAL_EPNO; + } +#endif + if (wlan_hdd_nan_is_supported(hdd_ctx)) { + hdd_debug("NAN is supported by firmware"); + fset |= WIFI_FEATURE_NAN; + } + if (sme_is_feature_supported_by_fw(RTT) && + hdd_ctx->config->enable_rtt_support) { + hdd_debug("RTT is supported by firmware and framework"); + fset |= WIFI_FEATURE_D2D_RTT; + fset |= WIFI_FEATURE_D2AP_RTT; + } +#ifdef FEATURE_WLAN_SCAN_PNO + if (hdd_ctx->config->configPNOScanSupport && + sme_is_feature_supported_by_fw(PNO)) { + hdd_debug("PNO is supported by firmware"); + fset |= WIFI_FEATURE_PNO; + } +#endif + fset |= WIFI_FEATURE_ADDITIONAL_STA; +#ifdef FEATURE_WLAN_TDLS + if ((true == hdd_ctx->config->fEnableTDLSSupport) && + sme_is_feature_supported_by_fw(TDLS)) { + hdd_debug("TDLS is supported by firmware"); + fset |= WIFI_FEATURE_TDLS; + } + if (sme_is_feature_supported_by_fw(TDLS) && + (true == hdd_ctx->config->fEnableTDLSOffChannel) && + 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_ctx->config->wlm_latency_enable && + sme_is_feature_supported_by_fw(VDEV_LATENCY_CONFIG)) { + fset |= WIFI_FEATURE_SET_LATENCY_MODE; + } + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(fset) + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("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 = cfg80211_vendor_cmd_reply(skb); + return ret; +nla_put_failure: + kfree_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) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_supported_features(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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) +{ + tpSirScanMacOui pReqMsg = NULL; + 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; + int len; + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + 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; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_ctx->config->enable_mac_spoofing) { + 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; + } + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]) { + hdd_err("attr mac oui failed"); + goto fail; + } + + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]); + if (len != sizeof(pReqMsg->oui)) { + hdd_err("attr mac oui invalid size %d expected %zu", + len, sizeof(pReqMsg->oui)); + goto fail; + } + + nla_memcpy(&pReqMsg->oui[0], + tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI], + sizeof(pReqMsg->oui)); + + /* populate pReqMsg for mac addr randomization */ + pReqMsg->vdev_id = adapter->session_id; + pReqMsg->enb_probe_req_sno_randomization = true; + + hdd_debug("Oui (%02x:%02x:%02x), vdev_id = %d", pReqMsg->oui[0], + pReqMsg->oui[1], pReqMsg->oui[2], pReqMsg->vdev_id); + + hdd_update_ie_whitelist_attr(&pReqMsg->ie_whitelist, hdd_ctx->config); + + mac_handle = hdd_ctx->mac_handle; + status = sme_set_scanning_mac_oui(mac_handle, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_scanning_mac_oui failed(err=%d)", status); + goto fail; + } + return 0; +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_scanning_mac_oui(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 +static 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; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + 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) + 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]); + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * feature_sets + NLMSG_HDRLEN); + 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"); + kfree_skb(reply_skb); + return -EINVAL; + } + return cfg80211_vendor_cmd_reply(reply_skb); +} + +#undef MAX_CONCURRENT_MATRIX +#undef MATRIX_CONFIG_PARAM_SET_SIZE_MAX + +/** + * 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 + */ +static int +wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_concurrency_matrix(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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. + **/ +#define NUM_BITS_IN_BYTE 8 +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_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. + **/ +#define MAX_CONCURRENT_CHAN_ON_24G 2 +#define MAX_CONCURRENT_CHAN_ON_5G 2 +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, twt_req, twt_res; + bool one_by_one_dbs, two_by_two_dbs; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + int ret_val; + + 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 (wma_is_p2p_lo_capable()) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD); + + if (hdd_ctx->config->oce_sta_enabled) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_OCE_STA); + + if (hdd_ctx->config->oce_sap_enabled) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON); + + sme_cfg_get_int(hdd_ctx->mac_handle, WNI_CFG_TWT_REQUESTOR, &twt_req); + sme_cfg_get_int(hdd_ctx->mac_handle, WNI_CFG_TWT_RESPONDER, &twt_res); + + if (twt_req || twt_res) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_TWT); + + /* 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 + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(feature_flags) + + NLMSG_HDRLEN); + + if (!skb) { + hdd_err("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; + + return cfg80211_vendor_cmd_reply(skb); + +nla_put_failure: + kfree_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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_features(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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_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 + + +static 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_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_NUM_BSSID] = {.type = NLA_U32}, + [PARAM_RSSI_MODIFIER] = {.type = NLA_U32}, + [PARAMS_NUM_BSSID] = {.type = NLA_U32}, + [PARAM_ROAM_BSSID] = {.type = NLA_UNSPEC, .len = QDF_MAC_ADDR_SIZE}, + [PARAM_SET_BSSID] = {.type = NLA_UNSPEC, .len = QDF_MAC_ADDR_SIZE}, +}; + +/** + * hdd_set_white_list() - parse white list + * @hdd_ctx: HDD context + * @roam_params: roam params + * @tb: list of attributes + * @session_id: session id + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_white_list(struct hdd_context *hdd_ctx, + struct roam_ext_params *roam_params, + struct nlattr **tb, uint8_t session_id) +{ + 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; + + 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 (wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_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 && (i < MAX_SSID_ALLOWED_LIST) && + ((buf_len - 1) <= SIR_MAC_MAX_SSID_LENGTH)) { + nla_memcpy(roam_params->ssid_allowed_list[i].ssId, + tb2[PARAM_LIST_SSID], buf_len - 1); + roam_params->ssid_allowed_list[i].length = buf_len - 1; + hdd_debug("SSID[%d]: %.*s,length = %d", + i, + roam_params->ssid_allowed_list[i].length, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + i++; + } else { + hdd_err("Invalid buffer length"); + } + } + } + + if (i != count) { + hdd_err("Invalid number of SSIDs i = %d, count = %d", i, count); + goto fail; + } + + roam_params->num_ssid_allowed_list = i; + hdd_debug("Num of Allowed SSID %d", roam_params->num_ssid_allowed_list); + mac_handle = hdd_ctx->mac_handle; + sme_update_roam_params(mac_handle, session_id, + roam_params, REASON_ROAM_SET_SSID_ALLOWED); + return 0; + +fail: + return -EINVAL; +} + +/** + * hdd_set_bssid_prefs() - parse set bssid prefs + * @hdd_ctx: HDD context + * @roam_params: roam params + * @tb: list of attributes + * @session_id: session id + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_bssid_prefs(struct hdd_context *hdd_ctx, + struct roam_ext_params *roam_params, + struct nlattr **tb, uint8_t session_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(roam_params->bssid_favored[i].bytes, + tb2[PARAM_ROAM_BSSID], + QDF_MAC_ADDR_SIZE); + hdd_debug(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_params->bssid_favored[i].bytes)); + /* Parse and fetch preference factor*/ + if (!tb2[PARAM_RSSI_MODIFIER]) { + hdd_err("BSSID Preference score failed"); + goto fail; + } + roam_params->bssid_favored_factor[i] = nla_get_u32( + tb2[PARAM_RSSI_MODIFIER]); + hdd_debug("BSSID Preference score (%d)", + roam_params->bssid_favored_factor[i]); + i++; + } + if (i < count) + hdd_warn("Num Preferred BSSID %u less than expected %u", + i, count); + + roam_params->num_bssid_favored = i; + mac_handle = hdd_ctx->mac_handle; + sme_update_roam_params(mac_handle, session_id, + roam_params, REASON_ROAM_SET_FAVORED_BSSID); + + return 0; + +fail: + return -EINVAL; +} + +/** + * hdd_set_blacklist_bssid() - parse set blacklist bssid + * @hdd_ctx: HDD context + * @roam_params: roam params + * @tb: list of attributes + * @session_id: session id + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_blacklist_bssid(struct hdd_context *hdd_ctx, + struct roam_ext_params *roam_params, + struct nlattr **tb, + uint8_t session_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 blacklist BSSID */ + if (!tb[PARAMS_NUM_BSSID]) { + hdd_err("attr num of blacklist bssid failed"); + goto fail; + } + count = nla_get_u32(tb[PARAMS_NUM_BSSID]); + if (count > MAX_BSSID_AVOID_LIST) { + hdd_err("Blacklist BSSID count %u exceeds max %u", + count, MAX_BSSID_AVOID_LIST); + goto fail; + } + hdd_debug("Num of blacklist BSSID (%d)", count); + + 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 Blacklist 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_SET_BSSID]) { + hdd_err("attr blacklist addr failed"); + goto fail; + } + nla_memcpy(roam_params->bssid_avoid_list[i].bytes, + tb2[PARAM_SET_BSSID], QDF_MAC_ADDR_SIZE); + hdd_debug(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_params->bssid_avoid_list[i].bytes)); + i++; + } + } + + if (i < count) + hdd_warn("Num Blacklist BSSID %u less than expected %u", + i, count); + + roam_params->num_bssid_avoid_list = i; + mac_handle = hdd_ctx->mac_handle; + sme_update_roam_params(mac_handle, session_id, + roam_params, REASON_ROAM_SET_BLACKLIST_BSSID); + + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_set_ext_roam_params() - parse ext roam params + * @hdd_ctx: HDD context + * @roam_params: roam params + * @tb: list of attributes + * @session_id: session id + * + * 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 session_id, + struct roam_ext_params *roam_params) +{ + 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_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST: + ret = hdd_set_white_list(hdd_ctx, roam_params, tb, session_id); + if (ret) + goto fail; + break; + + case QCA_WLAN_VENDOR_ATTR_ROAM_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; + } + roam_params->raise_rssi_thresh_5g = nla_get_s32( + tb[PARAM_A_BAND_BOOST_THLD]); + hdd_debug("5G Boost Threshold (%d)", + roam_params->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; + } + roam_params->drop_rssi_thresh_5g = nla_get_s32( + tb[PARAM_A_BAND_PELT_THLD]); + hdd_debug("5G Penalty Threshold (%d)", + roam_params->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; + } + roam_params->raise_factor_5g = nla_get_u32( + tb[PARAM_A_BAND_BOOST_FACTOR]); + hdd_debug("5G Boost Factor (%d)", + roam_params->raise_factor_5g); + /* Parse and fetch 5G Penalty factor */ + if (!tb[PARAM_A_BAND_PELT_FACTOR]) { + hdd_err("5G Penalty Factor failed"); + goto fail; + } + roam_params->drop_factor_5g = nla_get_u32( + tb[PARAM_A_BAND_PELT_FACTOR]); + hdd_debug("5G Penalty factor (%d)", + roam_params->drop_factor_5g); + /* Parse and fetch 5G Max Boost */ + if (!tb[PARAM_A_BAND_MAX_BOOST]) { + hdd_err("5G Max Boost failed"); + goto fail; + } + roam_params->max_raise_rssi_5g = nla_get_u32( + tb[PARAM_A_BAND_MAX_BOOST]); + hdd_debug("5G Max Boost (%d)", + roam_params->max_raise_rssi_5g); + /* Parse and fetch Rssi Diff */ + if (!tb[PARAM_ROAM_HISTERESYS]) { + hdd_err("Rssi Diff failed"); + goto fail; + } + roam_params->rssi_diff = nla_get_s32( + tb[PARAM_ROAM_HISTERESYS]); + hdd_debug("RSSI Diff (%d)", + roam_params->rssi_diff); + /* Parse and fetch Alert Rssi Threshold */ + if (!tb[PARAM_RSSI_TRIGGER]) { + hdd_err("Alert Rssi Threshold failed"); + goto fail; + } + roam_params->alert_rssi_threshold = nla_get_u32( + tb[PARAM_RSSI_TRIGGER]); + hdd_debug("Alert RSSI Threshold (%d)", + roam_params->alert_rssi_threshold); + sme_update_roam_params(mac_handle, session_id, + roam_params, + REASON_ROAM_EXT_SCAN_PARAMS_CHANGED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_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; + } + roam_params->good_rssi_roam = nla_get_s32( + tb[PARAM_ROAM_ENABLE]); + hdd_debug("Activate Good Rssi Roam (%d)", + roam_params->good_rssi_roam); + sme_update_roam_params(mac_handle, session_id, + roam_params, + REASON_ROAM_GOOD_RSSI_CHANGED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS: + ret = hdd_set_bssid_prefs(hdd_ctx, roam_params, tb, session_id); + if (ret) + goto fail; + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID: + ret = hdd_set_blacklist_bssid(hdd_ctx, roam_params, + tb, session_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 roam_ext_params *roam_params = NULL; + 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 (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + roam_params = qdf_mem_malloc(sizeof(*roam_params)); + if (!roam_params) { + hdd_err("failed to allocate memory"); + return -ENOMEM; + } + + ret = hdd_set_ext_roam_params(hdd_ctx, data, data_len, + adapter->session_id, roam_params); + if (ret) + goto fail; + + if (roam_params) + qdf_mem_free(roam_params); + return 0; +fail: + if (roam_params) + qdf_mem_free(roam_params); + + return ret; +} +#undef PARAM_NUM_NW +#undef PARAM_SET_BSSID +#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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ext_roam_params(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, NLMSG_HDRLEN + + sizeof(data->failure_reason_code) + + NLMSG_HDRLEN, PWR_SAVE_FAIL_CMD_INDEX, + flags); + + if (!skb) { + hdd_info("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; + + cfg80211_vendor_event(skb, flags); + hdd_exit(); + return; + +fail: + kfree_skb(skb); +} +#undef PWR_SAVE_FAIL_CMD_INDEX + +static 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; + struct hdd_ap_ctx *ap_ctx; + struct hdd_station_ctx *sta_ctx; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if ((device_mode == adapter->device_mode) && + (device_mode == QDF_SAP_MODE)) { + ap_ctx = + WLAN_HDD_GET_AP_CTX_PTR(adapter); + + /* + * 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 !! + */ + if (CHANNEL_STATE_DFS == wlan_reg_get_channel_state( + hdd_ctx->pdev, + ap_ctx->operating_channel)) { + hdd_err("SAP running on DFS channel"); + return true; + } + } + + if ((device_mode == adapter->device_mode) && + (device_mode == QDF_STA_MODE)) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* + * if STA is already connected on DFS channel, + * do not disable scan on dfs channels + */ + if (hdd_conn_is_connected(sta_ctx) && + (CHANNEL_STATE_DFS == + wlan_reg_get_channel_state(hdd_ctx->pdev, + sta_ctx->conn_info.operationChannel))) { + hdd_err("client connected on DFS channel"); + return true; + } + } + } + + 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; + + if (enable_dfs_channels == hdd_ctx->config->enableDFSChnlScan) { + 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; + } + + hdd_ctx->config->enableDFSChnlScan = 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) +{ +#ifdef WLAN_DEBUG + struct net_device *dev = wdev->netdev; +#endif + 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; + + hdd_enter_dev(dev); + + 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; + } + + ret_val = wlan_hdd_enable_dfs_chan_scan(hdd_ctx, !no_dfs_flag); + 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_disable_dfs_chan_scan(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + 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->session_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 == false) + cdp_set_wisa_mode(soc, + (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, + adapter->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_handle_wisa_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * 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 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 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 +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) + #define REMOTE_PAD\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_PAD +#endif + +static 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}, +}; + +#ifdef QCA_SUPPORT_CP_STATS +static int hdd_get_sta_congestion(struct hdd_adapter *adapter, + uint32_t *congestion) +{ + QDF_STATUS status; + struct cca_stats cca_stats; + + status = ucfg_mc_cp_stats_cca_stats_get(adapter->vdev, &cca_stats); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + *congestion = cca_stats.congestion; + return 0; +} +#else +static int hdd_get_sta_congestion(struct hdd_adapter *adapter, + uint32_t *congestion) +{ + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + *congestion = hdd_sta_ctx->conn_info.cca; + return 0; +} +#endif + +/** + * hdd_get_station_assoc_fail() - Handle get station assoc fail + * @hdd_ctx: HDD context within host driver + * @wdev: wireless device + * + * 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 hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len; + struct hdd_station_ctx *hdd_sta_ctx; + uint32_t congestion; + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += sizeof(uint32_t); + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + 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(adapter, &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 cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +/** + * hdd_map_auth_type() - transform auth type specific to + * vendor command + * @auth_type: csr auth type + * + * Return: Success(0) or reason code for failure + */ +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_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_map_dot_11_mode() - transform dot11mode type specific to + * vendor command + * @dot11mode: dot11mode + * + * Return: Success(0) or reason code for failure + */ +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_AUTO: + case eCSR_CFG_DOT11_MODE_ABG: + default: + ret_val = QCA_WLAN_802_11_MODE_INVALID; + } + return ret_val; +} + +/** + * hdd_add_tx_bitrate() - add tx bitrate 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_tx_bitrate(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, + int idx) +{ + struct nlattr *nla_attr; + uint32_t bitrate, bitrate_compat; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) { + hdd_err("nla_nest_start failed"); + goto fail; + } + + /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ + bitrate = cfg80211_calculate_bitrate(&hdd_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, + hdd_sta_ctx->cache_conn_info.txrate.nss)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_sta_info() - add station 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_sta_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) { + 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_add_tx_bitrate(skb, hdd_sta_ctx, 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_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.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_add_link_standard_info() - add link 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_link_standard_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) { + 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, hdd_sta_ctx, 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_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; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present) + if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, + sizeof(hdd_sta_ctx->cache_conn_info.vht_caps), + &hdd_sta_ctx->cache_conn_info.vht_caps)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present) + if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, + sizeof(hdd_sta_ctx->cache_conn_info.ht_caps), + &hdd_sta_ctx->cache_conn_info.ht_caps)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_get_station_info() - send BSS information to supplicant + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * + * Return: 0 if success else error status + */ +static int hdd_get_station_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct sk_buff *skb = NULL; + uint8_t *tmp_hs20 = NULL; + uint32_t nl_buf_len; + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += sizeof(hdd_sta_ctx-> + cache_conn_info.last_ssid.SSID.length) + + QDF_MAC_ADDR_SIZE + + sizeof(hdd_sta_ctx->cache_conn_info.freq) + + sizeof(hdd_sta_ctx->cache_conn_info.noise) + + sizeof(hdd_sta_ctx->cache_conn_info.signal) + + (sizeof(uint32_t) * 2) + + sizeof(hdd_sta_ctx->cache_conn_info.txrate.nss) + + sizeof(hdd_sta_ctx->cache_conn_info.roam_count) + + sizeof(hdd_sta_ctx->cache_conn_info.last_auth_type) + + sizeof(hdd_sta_ctx->cache_conn_info.dot11Mode); + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present) + nl_buf_len += sizeof(hdd_sta_ctx->cache_conn_info.vht_caps); + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present) + nl_buf_len += sizeof(hdd_sta_ctx->cache_conn_info.ht_caps); + if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) { + tmp_hs20 = (uint8_t *)&(hdd_sta_ctx-> + cache_conn_info.hs20vendor_ie); + nl_buf_len += (sizeof(hdd_sta_ctx-> + cache_conn_info.hs20vendor_ie) - 1); + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) + nl_buf_len += sizeof(hdd_sta_ctx-> + cache_conn_info.ht_operation); + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) + nl_buf_len += sizeof(hdd_sta_ctx-> + cache_conn_info.vht_operation); + + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (hdd_add_link_standard_info(skb, hdd_sta_ctx, + LINK_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_ap_standard_info(skb, hdd_sta_ctx, + AP_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("put fail"); + goto fail; + } + 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("put fail"); + goto fail; + } + 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("put fail"); + goto fail; + } + 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("put fail"); + goto fail; + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) + if (nla_put(skb, AP_INFO_HS20_INDICATION, + (sizeof(hdd_sta_ctx->cache_conn_info.hs20vendor_ie) + - 1), + tmp_hs20 + 1)) { + hdd_err("put fail"); + goto fail; + } + + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +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; +} + +#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 - 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); + 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); + 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 + * @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); + 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 attribut + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds link info attribut 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; + } + } + 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; + } + } + 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 uint8_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; + 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 = hdd_get_stainfo( + adapter->cache_sta_info, + mac_addr); + struct sk_buff *skb = NULL; + uint32_t nl_buf_len = NLMSG_HDRLEN; + uint8_t channel_width; + + if (!stainfo) { + hdd_err("peer " MAC_ADDRESS_STR " not found", + MAC_ADDR_ARRAY(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); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("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 = hdd_decode_ch_width(stainfo->ch_width); + + if (nla_put_u32(skb, REMOTE_SUPPORTED_MODE, + stainfo->support_mode) || + nla_put_u8(skb, REMOTE_CH_WIDTH, channel_width)) { + hdd_err("remote ch put fail"); + goto fail; + } + if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate)) { + hdd_err("tx rate put fail"); + goto fail; + } + if (nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate)) { + 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; + } + + qdf_mem_zero(stainfo, sizeof(*stainfo)); + + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + + return -EINVAL; +} + +/** + * hdd_get_cached_station_remote() - get connected peer's info + * @hdd_ctx: hdd context + * @adapter: hostapd interface + * @mac_addr: mac address of requested peer + * + * 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 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; + struct sir_peer_info_ext peer_info; + bool txrx_rate = true; + + 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); + + if (!hdd_ctx->config->sap_get_peer_info || + wlan_hdd_get_peer_info(adapter, mac_addr, &peer_info)) { + hdd_err("fail to get tx/rx rate"); + txrx_rate = false; + } else { + stainfo->tx_rate = peer_info.tx_rate; + stainfo->rx_rate = peer_info.rx_rate; + nl_buf_len += (sizeof(stainfo->tx_rate) + NLA_HDRLEN) + + (sizeof(stainfo->rx_rate) + NLA_HDRLEN); + } + + /* 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 = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + goto fail; + } + + 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 cfg80211_vendor_cmd_reply(skb); + +fail: + if (skb) + kfree_skb(skb); + + return -EINVAL; +} + +/** + * hdd_get_station_remote() - get remote peer's info + * @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(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + struct hdd_station_info *stainfo = hdd_get_stainfo(adapter->sta_info, + mac_addr); + int status = 0; + bool is_associated = false; + + if (!stainfo) { + status = hdd_get_cached_station_remote(hdd_ctx, adapter, + mac_addr); + return status; + } + + is_associated = hdd_is_peer_associated(adapter, &mac_addr); + if (!is_associated) { + status = hdd_get_cached_station_remote(hdd_ctx, adapter, + mac_addr); + return status; + } + + status = hdd_get_connected_station_info(hdd_ctx, adapter, + mac_addr, stainfo); + 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 (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + status = -EPERM; + goto out; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + 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(hdd_ctx, adapter); + } else if (tb[STATION_ASSOC_FAIL_REASON]) { + status = hdd_get_station_assoc_fail(hdd_ctx, adapter); + } 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 " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac_addr.bytes)); + + status = hdd_get_station_remote(hdd_ctx, adapter, mac_addr); + } else { + hdd_err("get station info cmd type failed"); + status = -EINVAL; + goto out; + } + hdd_exit(); +out: + return status; +} + +/** + * wlan_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 int32_t +hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_cfg80211_get_station_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * 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) +{ + uint8_t local_pmk[SIR_ROAM_SCAN_PSK_SIZE]; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *hdd_adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int status; + struct pmkid_mode_bits pmkid_modes; + 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 == NULL) || (data_len <= 0) || + (data_len > SIR_ROAM_SCAN_PSK_SIZE)) { + 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; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + + mac_handle = hdd_ctx->mac_handle; + sme_update_roam_key_mgmt_offload_enabled(mac_handle, + hdd_adapter->session_id, + true, &pmkid_modes); + qdf_mem_zero(&local_pmk, SIR_ROAM_SCAN_PSK_SIZE); + qdf_mem_copy(local_pmk, data, data_len); + sme_roam_set_psk_pmk(mac_handle, hdd_adapter->session_id, + local_pmk, data_len); + qdf_mem_zero(&local_pmk, SIR_ROAM_SCAN_PSK_SIZE); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_keymgmt_set_key(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +static 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]; + tSirVersionString driver_version; + tSirVersionString firmware_version; + int status; + struct sk_buff *reply_skb; + uint32_t skb_len = 0, count = 0; + + 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"); + strlcpy(driver_version, QWLAN_VERSIONSTR, + sizeof(driver_version)); + skb_len += strlen(driver_version) + 1; + count++; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { + hdd_debug("Rcvd req for FW version"); + snprintf(firmware_version, sizeof(firmware_version), + "FW:%d.%d.%d.%d.%d.%d HW:%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); + skb_len += strlen(firmware_version) + 1; + count++; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX]) { + hdd_debug("Rcvd req for Radio index"); + skb_len += sizeof(uint32_t); + count++; + } + + if (count == 0) { + hdd_err("unknown attribute in get_wifi_info request"); + return -EINVAL; + } + + skb_len += (NLA_HDRLEN * count) + NLMSG_HDRLEN; + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + + if (!reply_skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + 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, + driver_version)) + 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; + } + + return cfg80211_vendor_cmd_reply(reply_skb); + +error_nla_fail: + hdd_err("nla put fail"); + kfree_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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_wifi_info(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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; + + 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; + + 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; + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(uint32_t) + NLA_HDRLEN + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_debug("Supported logger features: 0x%0x", features); + if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED, + features)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + + return 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_logger_supp_feature(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter, + uint8_t *kck_ptr, 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; + + gtk_req = qdf_mem_malloc(sizeof(*gtk_req)); + if (!gtk_req) { + hdd_err("cannot allocate gtk_req"); + return; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (kck_ptr) + qdf_mem_copy(gtk_req->kck, kck_ptr, NL80211_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(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(adapter); + if (!vdev) + goto end; + status = pmo_ucfg_cache_gtk_offload_req(adapter->vdev, gtk_req); + hdd_objmgr_put_vdev(vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Failed to cache GTK Offload"); +end: + qdf_mem_free(gtk_req); +} +#else +void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter, + uint8_t *kck_ptr, + uint8_t *kek_ptr, + uint32_t kek_len, + uint8_t *replay_ctr, + bool big_endian) +{ +} +#endif + +#if defined(WLAN_FEATURE_FILS_SK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * wlan_hdd_add_fils_params_roam_auth_event() - Adds FILS params in roam auth + * @skb: SK buffer + * @roam_info: Roam info + * + * API adds fils params[pmk, pmkid, next sequence number] to roam auth event + * + * Return: zero on success, error code on failure + */ +static int +wlan_hdd_add_fils_params_roam_auth_event(struct sk_buff *skb, + struct csr_roam_info *roam_info) +{ + if (roam_info->pmk_len && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK, + roam_info->pmk_len, roam_info->pmk)) { + hdd_err("pmk send fail"); + return -EINVAL; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID, + SIR_PMKID_LEN, roam_info->pmkid)) { + hdd_err("pmkid send fail"); + return -EINVAL; + } + + hdd_debug("Update ERP Seq Num %d, Next ERP Seq Num %d", + roam_info->update_erp_next_seq_num, + roam_info->next_erp_seq_num); + if (roam_info->update_erp_next_seq_num && + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM, + roam_info->next_erp_seq_num)) { + hdd_err("ERP seq num send fail"); + return -EINVAL; + } + + return 0; +} +#else +static inline int +wlan_hdd_add_fils_params_roam_auth_event(struct sk_buff *skb, + struct csr_roam_info *roam_info) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_hdd_send_roam_auth_event() - Send the roamed and authorized event + * @adapter: Pointer to adapter struct + * @bssid: pointer to bssid of roamed AP. + * @req_rsn_ie: Pointer to request RSN IE + * @req_rsn_len: Length of the request RSN IE + * @rsp_rsn_ie: Pointer to response RSN IE + * @rsp_rsn_len: Length of the response RSN IE + * @roam_info_ptr: Pointer to the roaming related information + * + * This is called when wlan driver needs to send the roaming and + * authorization information after roaming. + * + * The information that would be sent is the request RSN IE, response + * RSN IE and BSSID of the newly roamed AP. + * + * If the Authorized status is authenticated, then additional parameters + * like PTK's KCK and KEK and Replay Counter would also be passed to the + * supplicant. + * + * The supplicant upon receiving this event would ignore the legacy + * cfg80211_roamed call and use the entire information from this event. + * The cfg80211_roamed should still co-exist since the kernel will + * make use of the parameters even if the supplicant ignores it. + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, uint8_t *bssid, + uint8_t *req_rsn_ie, uint32_t req_rsn_len, uint8_t *rsp_rsn_ie, + uint32_t rsp_rsn_len, struct csr_roam_info *roam_info_ptr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sk_buff *skb = NULL; + eCsrAuthType auth_type; + uint32_t fils_params_len; + int status; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (!roaming_offload_enabled(hdd_ctx) || + !roam_info_ptr->roamSynchInProgress) + return 0; + + /* + * PMK is sent from FW in Roam Synch Event for FILS Roaming. + * In that case, add three more NL attributes.ie. PMK, PMKID + * and ERP next sequence number. Add corresponding lengths + * with 3 extra NL message headers for each of the + * aforementioned params. + */ + fils_params_len = roam_info_ptr->pmk_len + SIR_PMKID_LEN + + sizeof(uint16_t) + (3 * NLMSG_HDRLEN); + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &(adapter->wdev), + ETH_ALEN + req_rsn_len + rsp_rsn_len + + sizeof(uint8_t) + SIR_REPLAY_CTR_LEN + + SIR_KCK_KEY_LEN + roam_info_ptr->kek_len + + sizeof(uint8_t) + (8 * NLMSG_HDRLEN) + + fils_params_len, + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX, + GFP_KERNEL); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -EINVAL; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, + ETH_ALEN, bssid) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, + req_rsn_len, req_rsn_ie) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, + rsp_rsn_len, rsp_rsn_ie)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + if (roam_info_ptr->synchAuthStatus == + CSR_ROAM_AUTH_STATUS_AUTHENTICATED) { + hdd_debug("Include Auth Params TLV's"); + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, true)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + auth_type = roam_info_ptr->u.pConnectedProfile->AuthType; + /* if FT or CCKM connection: dont send replay counter */ + if (auth_type != eCSR_AUTH_TYPE_FT_RSN && + auth_type != eCSR_AUTH_TYPE_FT_RSN_PSK && + auth_type != eCSR_AUTH_TYPE_CCKM_WPA && + auth_type != eCSR_AUTH_TYPE_CCKM_RSN && + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, + SIR_REPLAY_CTR_LEN, + roam_info_ptr->replay_ctr)) { + hdd_err("non FT/non CCKM connection"); + hdd_err("failed to send replay counter"); + goto nla_put_failure; + } + if (roam_info_ptr->kek_len > SIR_KEK_KEY_LEN_FILS || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, + SIR_KCK_KEY_LEN, roam_info_ptr->kck) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, + roam_info_ptr->kek_len, roam_info_ptr->kek)) { + hdd_err("nla put fail, kek_len %d", + roam_info_ptr->kek_len); + goto nla_put_failure; + } + + status = wlan_hdd_add_fils_params_roam_auth_event(skb, + roam_info_ptr); + if (status) + goto nla_put_failure; + + /* + * Save the gtk rekey parameters in HDD STA context. They will + * be used next time when host enables GTK offload and goes + * into power save state. + */ + wlan_hdd_save_gtk_offload_params(adapter, roam_info_ptr->kck, + roam_info_ptr->kek, + roam_info_ptr->kek_len, + roam_info_ptr->replay_ctr, + true); + hdd_debug("roam_info_ptr->replay_ctr 0x%llx", + *((uint64_t *)roam_info_ptr->replay_ctr)); + + } else { + hdd_debug("No Auth Params TLV's"); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, + false)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + } + + hdd_debug("Auth Status = %d Subnet Change Status = %d", + roam_info_ptr->synchAuthStatus, + roam_info_ptr->subnet_change_status); + + /* + * Add subnet change status if subnet has changed + * 0 = unchanged + * 1 = changed + * 2 = unknown + */ + if (roam_info_ptr->subnet_change_status) { + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS, + roam_info_ptr->subnet_change_status)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} +#endif + +#define ANT_DIV_PROBE_PERIOD \ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_PERIOD +#define ANT_DIV_STAY_PERIOD \ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_STAY_PERIOD +#define ANT_DIV_SNR_DIFF \ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SNR_DIFF +#define ANT_DIV_PROBE_DWELL_TIME \ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_DWELL_TIME +#define ANT_DIV_MGMT_SNR_WEIGHT \ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_MGMT_SNR_WEIGHT +#define ANT_DIV_DATA_SNR_WEIGHT \ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_DATA_SNR_WEIGHT +#define ANT_DIV_ACK_SNR_WEIGHT \ + QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ACK_SNR_WEIGHT +#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 +static const struct nla_policy +wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { + + [QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_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_TX_FAIL_COUNT] = {.type = NLA_U32 }, + [ANT_DIV_PROBE_PERIOD] = {.type = NLA_U32}, + [ANT_DIV_STAY_PERIOD] = {.type = NLA_U32}, + [ANT_DIV_SNR_DIFF] = {.type = NLA_U32}, + [ANT_DIV_PROBE_DWELL_TIME] = {.type = NLA_U32}, + [ANT_DIV_MGMT_SNR_WEIGHT] = {.type = NLA_U32}, + [ANT_DIV_DATA_SNR_WEIGHT] = {.type = NLA_U32}, + [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] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [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_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}, +}; + +static 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_BA_TID] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE] = { + .type = NLA_U8}, + [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}, +}; + +/** + * wlan_hdd_add_qcn_ie() - Add QCN IE to a given IE buffer + * @ie_data: IE buffer + * @ie_len: length of the @ie_data + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_hdd_add_qcn_ie(uint8_t *ie_data, uint16_t *ie_len) +{ + tDot11fIEQCN_IE qcn_ie; + uint8_t qcn_ie_hdr[QCN_IE_HDR_LEN] + = {IE_EID_VENDOR, DOT11F_IE_QCN_IE_MAX_LEN, + 0x8C, 0xFD, 0xF0, 0x1}; + + if (((*ie_len) + QCN_IE_HDR_LEN + + QCN_IE_VERSION_SUBATTR_DATA_LEN) > MAX_DEFAULT_SCAN_IE_LEN) { + hdd_err("IE buffer not enough for QCN IE"); + return QDF_STATUS_E_FAILURE; + } + + /* Add QCN IE header */ + qdf_mem_copy(ie_data + (*ie_len), qcn_ie_hdr, QCN_IE_HDR_LEN); + (*ie_len) += QCN_IE_HDR_LEN; + + /* Retrieve Version sub-attribute data */ + populate_dot11f_qcn_ie(&qcn_ie); + + /* Add QCN IE data[version sub attribute] */ + qdf_mem_copy(ie_data + (*ie_len), qcn_ie.version, + (QCN_IE_VERSION_SUBATTR_LEN)); + (*ie_len) += (QCN_IE_VERSION_SUBATTR_LEN); + + return QDF_STATUS_SUCCESS; +} + +/** + * 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 = hdd_ctx->config->qcn_ie_support; + + 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; + + 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) + wlan_hdd_add_qcn_ie(scan_info->default_scan_ies, + &(scan_info->default_scan_ies_len)); + + hdd_debug("Saved default scan IE:"); + 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(adapter); + if (!vdev) + return -EINVAL; + if (restrict_offchan == 1) { + enum policy_mgr_con_mode pmode = + policy_mgr_convert_device_mode_to_qdf_type(dev_mode); + int chan; + + u32 vdev_id = wlan_vdev_get_id(vdev); + + wlan_vdev_obj_lock(vdev); + wlan_vdev_mlme_cap_set(vdev, + WLAN_VDEV_C_RESTRICT_OFFCHAN); + wlan_vdev_obj_unlock(vdev); + chan = policy_mgr_get_channel(hdd_ctx->psoc, pmode, + &vdev_id); + if (!chan || + wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, chan)) { + 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(vdev); + return ret_val; +} + +/** + * wlan_hdd_cfg80211_wifi_set_reorder_timeout - set reorder timeout + * @hdd_ctx: hdd context + * @tb: array of pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static +int wlan_hdd_cfg80211_wifi_set_reorder_timeout(struct hdd_context *hdd_ctx, + struct nlattr *tb[]) +{ + 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 + * + * @hdd_ctx: hdd context + * @adapter: 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 hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct nlattr *tb[]) +{ + 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_PEER_MAC] || + tb[RX_BLOCKSIZE_WINLIMIT]) { + + /* if one is specified, both must be specified */ + if (!tb[RX_BLOCKSIZE_PEER_MAC] || + !tb[RX_BLOCKSIZE_WINLIMIT]) { + 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 = adapter->session_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; +} + +static int hdd_config_scan_default_ies(struct hdd_adapter *adapter, + const struct nlattr *attr) +{ + 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; + + if (!attr) + return 0; + + scan_ie_len = nla_len(attr); + hdd_debug("IE len %d session %d device mode %d", + scan_ie_len, adapter->session_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, + adapter->session_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; +} + +/** + * __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]; + const struct nlattr *attr; + int ret; + int ret_val = 0; + u32 modulated_dtim, override_li; + u16 stats_avg_factor; + u32 guard_time; + uint8_t set_value; + u32 ftm_capab; + u8 qpower; + QDF_STATUS status; + int attr_len; + int access_policy = 0; + char vendor_ie[SIR_MAC_MAX_IE_LENGTH + 2]; + bool vendor_ie_present = false, access_policy_present = false; + struct sir_set_tx_rx_aggregation_size request; + QDF_STATUS qdf_status; + uint8_t retry, delay, enable_flag; + uint32_t abs_delay; + int param_id; + uint32_t tx_fail_count; + uint32_t ant_div_usrcfg; + uint32_t antdiv_enable, antdiv_chain; + uint32_t antdiv_selftest, antdiv_selftest_intvl; + uint8_t bmiss_bcnt; + uint16_t latency_level; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + qdf_mem_zero(&request, sizeof(request)); + + 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_CONFIG_MAX, data, + data_len, wlan_hdd_wifi_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + mac_handle = hdd_ctx->mac_handle; + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT]) { + ftm_capab = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT]); + hdd_ctx->config->fine_time_meas_cap = + hdd_ctx->fine_time_meas_cap_target & ftm_capab; + sme_update_fine_time_measurement_capab(mac_handle, + adapter->session_id, + hdd_ctx->config->fine_time_meas_cap); + ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc, + hdd_ctx->config->fine_time_meas_cap); + hdd_debug("FTM capability: user value: 0x%x, target value: 0x%x, final value: 0x%x", + ftm_capab, hdd_ctx->fine_time_meas_cap_target, + hdd_ctx->config->fine_time_meas_cap); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]) { + modulated_dtim = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]); + + status = pmo_ucfg_config_modulated_dtim(adapter->vdev, + modulated_dtim); + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL]) { + override_li = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL]); + + if (override_li > CFG_ENABLE_DYNAMIC_DTIM_MAX) { + hdd_err_rl("Invalid value for listen interval - %d", + override_li); + return -EINVAL; + } + + status = pmo_ucfg_config_listen_interval(adapter->vdev, + override_li); + if (status != QDF_STATUS_SUCCESS) + ret_val = -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LRO]) { + enable_flag = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LRO]); + ret_val = hdd_lro_set_reset(hdd_ctx, adapter, + enable_flag); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE]) { + enable_flag = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE]); + sme_set_scan_disable(mac_handle, !enable_flag); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]) { + qpower = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]); + if (hdd_set_qpower_config(hdd_ctx, adapter, qpower) != 0) + ret_val = -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]) { + stats_avg_factor = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]); + status = sme_configure_stats_avg_factor(mac_handle, + adapter->session_id, + stats_avg_factor); + + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]) { + guard_time = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]); + status = sme_configure_guard_time(mac_handle, + adapter->session_id, + guard_time); + + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST]) { + qdf_mem_zero(&vendor_ie[0], SIR_MAC_MAX_IE_LENGTH + 2); + attr_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST]); + if (attr_len < 0 || attr_len > SIR_MAC_MAX_IE_LENGTH + 2) { + hdd_err("Invalid value. attr_len %d", + attr_len); + return -EINVAL; + } + + nla_memcpy(&vendor_ie, + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST], + attr_len); + vendor_ie_present = true; + hdd_debug("Access policy vendor ie present.attr_len %d", + attr_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY]) { + access_policy = (int) nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY]); + if ((access_policy < QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED) || + (access_policy > + QCA_ACCESS_POLICY_DENY_UNLESS_LISTED)) { + hdd_err("Invalid value. access_policy %d", + access_policy); + return -EINVAL; + } + access_policy_present = true; + hdd_debug("Access policy present. access_policy %d", + access_policy); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY]) { + retry = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY]); + retry = retry > CFG_NON_AGG_RETRY_MAX ? + CFG_NON_AGG_RETRY_MAX : retry; + param_id = WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH; + ret_val = wma_cli_set_command(adapter->session_id, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY]) { + retry = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY]); + retry = retry > CFG_AGG_RETRY_MAX ? + CFG_AGG_RETRY_MAX : retry; + + /* Value less than CFG_AGG_RETRY_MIN has side effect to t-put */ + retry = ((retry > 0) && (retry < CFG_AGG_RETRY_MIN)) ? + CFG_AGG_RETRY_MIN : retry; + param_id = WMI_PDEV_PARAM_AGG_SW_RETRY_TH; + ret_val = wma_cli_set_command(adapter->session_id, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY]) { + retry = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY]); + retry = retry > CFG_MGMT_RETRY_MAX ? + CFG_MGMT_RETRY_MAX : retry; + param_id = WMI_PDEV_PARAM_MGMT_RETRY_LIMIT; + ret_val = wma_cli_set_command(adapter->session_id, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY]) { + retry = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY]); + retry = retry > CFG_CTRL_RETRY_MAX ? + CFG_CTRL_RETRY_MAX : retry; + param_id = WMI_PDEV_PARAM_CTRL_RETRY_LIMIT; + ret_val = wma_cli_set_command(adapter->session_id, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY]) { + delay = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY]); + 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; + ret_val = wma_cli_set_command(adapter->session_id, param_id, + abs_delay, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_ABS_DELAY]) { + abs_delay = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_ABS_DELAY]); + param_id = WMI_PDEV_PARAM_PROPAGATION_DELAY; + ret_val = wma_cli_set_command(adapter->session_id, param_id, + abs_delay, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT]) { + tx_fail_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT]); + if (tx_fail_count) { + status = sme_update_tx_fail_cnt_threshold(mac_handle, + adapter->session_id, tx_fail_count); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_update_tx_fail_cnt_threshold (err=%d)", + status); + return -EINVAL; + } + } + } + + if (vendor_ie_present && access_policy_present) { + if (access_policy == QCA_ACCESS_POLICY_DENY_UNLESS_LISTED) { + access_policy = + WLAN_HDD_VENDOR_IE_ACCESS_ALLOW_IF_LISTED; + } else { + access_policy = WLAN_HDD_VENDOR_IE_ACCESS_NONE; + } + + hdd_debug("calling sme_update_access_policy_vendor_ie"); + status = sme_update_access_policy_vendor_ie(mac_handle, + adapter->session_id, &vendor_ie[0], + access_policy); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to set vendor ie and access policy."); + return -EINVAL; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND]) { + set_value = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND]); + hdd_debug("set_value: %d", set_value); + ret_val = hdd_enable_disable_ca_event(hdd_ctx, set_value); + } + + attr = tb[QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES]; + ret = hdd_config_scan_default_ies(adapter, attr); + if (ret) + ret_val = ret; + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION] || + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION]) { + /* if one is specified, both must be specified */ + if (!tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION] || + !tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION]) { + hdd_err("Both TX and RX MPDU Aggregation required"); + return -EINVAL; + } + + request.tx_aggregation_size = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION]); + request.rx_aggregation_size = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION]); + request.vdev_id = adapter->session_id; + request.aggr_type = WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU; + + if (request.tx_aggregation_size >= + CFG_TX_AGGREGATION_SIZE_MIN && + request.tx_aggregation_size <= + CFG_TX_AGGREGATION_SIZE_MAX && + request.rx_aggregation_size >= + CFG_RX_AGGREGATION_SIZE_MIN && + request.rx_aggregation_size <= + CFG_RX_AGGREGATION_SIZE_MAX) { + qdf_status = wma_set_tx_rx_aggregation_size(&request); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to set aggr sizes err %d", + qdf_status); + ret_val = -EPERM; + } + } else { + hdd_err("TX %d RX %d MPDU aggr size not in range", + request.tx_aggregation_size, + request.rx_aggregation_size); + ret_val = -EINVAL; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED]) { + uint8_t ignore_assoc_disallowed; + + ignore_assoc_disallowed + = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED]); + hdd_debug("Set ignore_assoc_disallowed value - %d", + ignore_assoc_disallowed); + if ((ignore_assoc_disallowed < + QCA_IGNORE_ASSOC_DISALLOWED_DISABLE) || + (ignore_assoc_disallowed > + QCA_IGNORE_ASSOC_DISALLOWED_ENABLE)) + return -EPERM; + + sme_update_session_param(mac_handle, + adapter->session_id, + SIR_PARAM_IGNORE_ASSOC_DISALLOWED, + ignore_assoc_disallowed); + } + +#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)) + + if (tb[ANT_DIV_PROBE_PERIOD] || + tb[ANT_DIV_STAY_PERIOD]) { + + if (!tb[ANT_DIV_PROBE_PERIOD] || + !tb[ANT_DIV_STAY_PERIOD]) { + hdd_err("Both probe and stay period required"); + return -EINVAL; + } + + ant_div_usrcfg = ANT_DIV_SET_PERIOD( + nla_get_u32(tb[ANT_DIV_PROBE_PERIOD]), + nla_get_u32(tb[ANT_DIV_STAY_PERIOD])); + hdd_debug("ant div set period: %x", ant_div_usrcfg); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_ANT_DIV_USRCFG, + ant_div_usrcfg, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set ant div period"); + return ret_val; + } + } + + if (tb[ANT_DIV_SNR_DIFF]) { + ant_div_usrcfg = ANT_DIV_SET_SNR_DIFF( + nla_get_u32(tb[ANT_DIV_SNR_DIFF])); + hdd_debug("ant div set snr diff: %x", ant_div_usrcfg); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_ANT_DIV_USRCFG, + ant_div_usrcfg, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set ant snr diff"); + return ret_val; + } + } + + if (tb[ANT_DIV_PROBE_DWELL_TIME]) { + ant_div_usrcfg = ANT_DIV_SET_PROBE_DWELL_TIME( + nla_get_u32(tb[ANT_DIV_PROBE_DWELL_TIME])); + hdd_debug("ant div set probe dewll time: %x", + ant_div_usrcfg); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_ANT_DIV_USRCFG, + ant_div_usrcfg, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set ant div probe dewll time"); + return ret_val; + } + } + + if (tb[ANT_DIV_MGMT_SNR_WEIGHT] || + tb[ANT_DIV_DATA_SNR_WEIGHT] || + tb[ANT_DIV_ACK_SNR_WEIGHT]) { + + if (!tb[ANT_DIV_MGMT_SNR_WEIGHT] || + !tb[ANT_DIV_DATA_SNR_WEIGHT] || + !tb[ANT_DIV_ACK_SNR_WEIGHT]) { + hdd_err("Mgmt snr, data snr and ack snr weight are required"); + return -EINVAL; + } + + ant_div_usrcfg = ANT_DIV_SET_WEIGHT( + nla_get_u32(tb[ANT_DIV_MGMT_SNR_WEIGHT]), + nla_get_u32(tb[ANT_DIV_DATA_SNR_WEIGHT]), + nla_get_u32(tb[ANT_DIV_ACK_SNR_WEIGHT])); + hdd_debug("ant div set weight: %x", ant_div_usrcfg); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_ANT_DIV_USRCFG, + ant_div_usrcfg, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set ant div weight"); + return ret_val; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL]) { + u8 restrict_offchan = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL]); + + hdd_debug("Restrict offchannel:%d", restrict_offchan); + if (restrict_offchan <= 1) + ret_val = + wlan_hdd_handle_restrict_offchan_config(adapter, + restrict_offchan); + else { + ret_val = -EINVAL; + hdd_err("Invalid RESTRICT_OFFCHAN setting"); + } + } + + ret_val = + wlan_hdd_cfg80211_wifi_set_reorder_timeout(hdd_ctx, tb); + if (ret_val != 0) + return ret_val; + + ret_val = + wlan_hdd_cfg80211_wifi_set_rx_blocksize(hdd_ctx, adapter, tb); + if (ret_val != 0) + return ret_val; + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA]) { + antdiv_enable = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA]); + hdd_debug("antdiv_enable: %d", antdiv_enable); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_ENA_ANT_DIV, + antdiv_enable, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set antdiv_enable"); + return ret_val; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN]) { + antdiv_chain = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN]); + hdd_debug("antdiv_chain: %d", antdiv_chain); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_FORCE_CHAIN_ANT, + antdiv_chain, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set antdiv_chain"); + return ret_val; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST]) { + antdiv_selftest = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST]); + hdd_debug("antdiv_selftest: %d", antdiv_selftest); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_ANT_DIV_SELFTEST, + antdiv_selftest, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set antdiv_selftest"); + return ret_val; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL]) { + antdiv_selftest_intvl = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL]); + hdd_debug("antdiv_selftest_intvl: %d", + antdiv_selftest_intvl); + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_ANT_DIV_SELFTEST_INTVL, + antdiv_selftest_intvl, PDEV_CMD); + if (ret_val) { + hdd_err("Failed to set antdiv_selftest_intvl"); + return ret_val; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT]) { + bmiss_bcnt = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT]); + if (hdd_ctx->config->nRoamBmissFirstBcnt < bmiss_bcnt) { + hdd_ctx->config->nRoamBmissFinalBcnt = bmiss_bcnt + - hdd_ctx->config->nRoamBmissFirstBcnt; + hdd_debug("Bmiss first cnt(%d), Bmiss final cnt(%d)", + hdd_ctx->config->nRoamBmissFirstBcnt, + hdd_ctx->config->nRoamBmissFinalBcnt); + ret_val = sme_set_roam_bmiss_final_bcnt(mac_handle, + 0, hdd_ctx->config->nRoamBmissFinalBcnt); + + if (ret_val) { + hdd_err("Failed to set bmiss final Bcnt"); + return ret_val; + } + + ret_val = sme_set_bmiss_bcnt(adapter->session_id, + hdd_ctx->config->nRoamBmissFirstBcnt, + hdd_ctx->config->nRoamBmissFinalBcnt); + if (ret_val) { + hdd_err("Failed to set bmiss Bcnt"); + return ret_val; + } + } else { + hdd_err("Bcnt(%d) needs to exceed BmissFirstBcnt(%d)", + bmiss_bcnt, + hdd_ctx->config->nRoamBmissFirstBcnt); + return -EINVAL; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL]) { + latency_level = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL]); + + if ((latency_level > + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_MAX) || + (latency_level == + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_INVALID)) { + hdd_err("Invalid Wlan latency level value"); + return -EINVAL; + } + + /* Mapping the latency value to the level which fw expected + * 0 - normal, 1 - moderate, 2 - low, 3 - ultralow + */ + latency_level = latency_level - 1; + qdf_status = sme_set_wlm_latency_level(mac_handle, + adapter->session_id, + latency_level); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("set Wlan latency level failed"); + ret_val = -EINVAL; + } + } + + if (adapter->device_mode == QDF_STA_MODE && + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS]) { + uint8_t disable_fils; + + disable_fils = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS]); + hdd_debug("Set disable_fils - %d", disable_fils); + + qdf_status = sme_update_fils_setting(mac_handle, + adapter->session_id, + disable_fils); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("set disable_fils failed"); + ret_val = -EINVAL; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE] && + hdd_ctx->config->force_rsne_override) { + uint8_t force_rsne_override; + + force_rsne_override = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE]); + if (force_rsne_override > 1) { + hdd_err("Invalid test_mode %d", force_rsne_override); + ret_val = -EINVAL; + } + + hdd_ctx->force_rsne_override = force_rsne_override; + hdd_debug("force_rsne_override - %d", + hdd_ctx->force_rsne_override); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GTX]) { + uint8_t config_gtx; + + config_gtx = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GTX]); + if (config_gtx > 1) { + hdd_err_rl("Invalid config_gtx value %d", config_gtx); + return -EINVAL; + } + ret_val = sme_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_ENABLE, + config_gtx, VDEV_CMD); + if (ret_val) + hdd_err("Failed to set GTX"); + } + + return ret_val; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_configuration_set(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 set_val = 0; + tSmeConfigParams *sme_config; + bool update_sme_cfg = false; + uint8_t tid = 0, ac; + uint16_t buff_size = 0; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("mem alloc failed for 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, adapter->session_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, adapter->session_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->csrConfig.WMMSupportMode = + hdd_to_csr_wmm_mode(HDD_WMM_USER_MODE_NO_QOS); + hdd_debug("wmm is disabled"); + } else { + sme_config->csrConfig.WMMSupportMode = + hdd_to_csr_wmm_mode(hdd_ctx->config->WmmMode); + 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 = 0; + hdd_debug("BA operating mode is set to auto"); + } else { + /*Manual BA mode*/ + set_val = 1; + hdd_debug("BA operating mode is set to Manual"); + } + + ret_val = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_BA_MODE, set_val, VDEV_CMD); + if (ret_val) { + hdd_err("Set BA operating mode failed"); + goto send_err; + } + if (!cfg_val) { + ret_val = wma_cli_set_command(adapter->session_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, + adapter->session_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->csrConfig.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_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE]); + ret_val = sme_send_addba_req(mac_handle, + adapter->session_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]) { + buff_size = nla_get_u8(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, + adapter->session_id, buff_size); + if (ret_val) + goto send_err; + if (buff_size > 64) + /* Configure ADDBA req buffer size to 256 */ + set_val = 3; + else + /* Configure ADDBA req buffer size to 64 */ + set_val = 2; + ret_val = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_BA_MODE, set_val, VDEV_CMD); + } + + 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, + adapter->session_id, + cfg_val, ac); + if (cfg_val) { + if (sme_config->csrConfig.enable2x2) + /*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"); + } + } + + 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, + adapter->session_id, + cfg_val); + if (ret_val) + sme_err("Failed to set auto rate HE LTF"); + + ret_val = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_HE_LTF, + cfg_val, VDEV_CMD); + if (ret_val) + goto send_err; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_TX_BEAMFORMEE]) { + 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, + adapter->session_id, + cfg_val); + if (ret_val) + sme_err("Failed to set Tx beamformee cap"); + + } + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_wifi_test_config(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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; + } + + 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; + } + 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) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_logger_start(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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_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, + 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_info("Bug report triggered by framework"); + + status = cds_flush_logs(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_UNUSED, + true, false); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to trigger bug report"); + return -EINVAL; + } + } 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) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_logger_get_ring_data(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 + +/** + * 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_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + add_req = qdf_mem_malloc(sizeof(*add_req)); + if (!add_req) { + hdd_err("memory allocation failed"); + 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: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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) { + hdd_err("memory allocation failed"); + return -ENOMEM; + } + + qdf_copy_macaddr(&del_req->mac_address, &adapter->mac_addr); + hdd_debug(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(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; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_SRC_MAC_ADDR] = { .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [PARAM_DST_MAC_ADDR] = { .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [PARAM_PERIOD] = { .type = NLA_U32 }, + [PARAM_PROTO_TYPE] = {.type = NLA_U16}, + }; + + 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, 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_offloaded_packets(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/* + * 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 + +/** + * __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_req req; + QDF_STATUS status; + int ret; + uint32_t control; + mac_handle_t mac_handle; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_MIN_RSSI] = { .type = NLA_S8 }, + [PARAM_MAX_RSSI] = { .type = NLA_S8 }, + }; + + hdd_enter_dev(dev); + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, 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.session_id = adapter->session_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 Session_id: %d Control: %d", + req.request_id, req.session_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 + +/** + * 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 + */ +static int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_rssi_threshold_breached() - rssi breached NL event + * @hddctx: HDD context + * @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(void *hddctx, + struct rssi_breach_event *data) +{ + struct hdd_context *hdd_ctx = hddctx; + struct sk_buff *skb; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_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: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); +} + +static 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); + + hdd_enter_dev(wdev->netdev); + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + if (!hdd_ctx->config->fhostNSOffload) { + hdd_err("ND Offload not supported"); + return -EINVAL; + } + + if (!hdd_ctx->config->active_mode_offload) { + 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]); + + if (QDF_IBSS_MODE == adapter->device_mode) { + hdd_debug("NS Offload is not supported in IBSS mode"); + return -EINVAL; + } + + /* update ns offload in case it is already enabled/disabled */ + if (hdd_ctx->ns_offload_enable) + hdd_enable_ns_offload(adapter, pmo_ns_offload_dynamic_update); + else + hdd_disable_ns_offload(adapter, pmo_ns_offload_dynamic_update); + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ns_offload(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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}, +}; + +/** __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; + uint8_t pcl[QDF_MAX_NUM_CHAN], weight_list[QDF_MAX_NUM_CHAN]; + uint32_t pcl_len = 0; + uint32_t freq_list[QDF_MAX_NUM_CHAN]; + 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; + + hdd_enter_dev(wdev->netdev); + + 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"); + + status = policy_mgr_get_pcl(hdd_ctx->psoc, + intf_mode, pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Get pcl failed"); + return -EINVAL; + } + + /* convert channel number to frequency */ + for (i = 0; i < pcl_len; i++) { + if (pcl[i] <= ARRAY_SIZE(hdd_channels_2_4_ghz)) + freq_list[i] = + ieee80211_channel_to_frequency(pcl[i], + HDD_NL80211_BAND_2GHZ); + else + freq_list[i] = + ieee80211_channel_to_frequency(pcl[i], + HDD_NL80211_BAND_5GHZ); + } + + /* send the freq_list back to supplicant */ + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * + pcl_len + + NLMSG_HDRLEN); + + if (!reply_skb) { + hdd_err("Allocate reply_skb failed"); + 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, + freq_list)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + + return 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) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_preferred_freq_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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 channel_hint; + + hdd_enter_dev(ndev); + + 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; + } + + channel_hint = cds_freq_to_chan(nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ])); + + /* check pcl table */ + if (!policy_mgr_allow_concurrency(hdd_ctx->psoc, intf_mode, + channel_hint, HW_MODE_20_MHZ)) { + hdd_err("Set channel hint failed due to concurrency check"); + return -EINVAL; + } + + if (0 != wlan_hdd_check_remain_on_channel(adapter)) + hdd_warn("Remain On Channel Pending"); + + if (wlan_hdd_change_hw_mode_for_given_chnl(adapter, channel_hint, + 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_probable_oper_channel(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_attr_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 nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX+1]; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + uint32_t sta_id; + 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, qca_wlan_vendor_attr_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="MAC_ADDRESS_STR" for device_mode:%d", + MAC_ADDR_ARRAY(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); + if ((hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) || + qdf_mem_cmp(hdd_sta_ctx->conn_info.bssId.bytes, + peer_mac, QDF_MAC_ADDR_SIZE)) { + hdd_err("Not Associated to mac "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + nss = hdd_sta_ctx->conn_info.nss; + freq = cds_chan_to_freq( + hdd_sta_ctx->conn_info.operationChannel); + rate_flags = hdd_sta_ctx->conn_info.rate_flags; + } else if (adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_SAP_MODE) { + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + if (adapter->sta_info[sta_id].in_use && + !qdf_is_macaddr_broadcast( + &adapter->sta_info[sta_id].sta_mac) && + !qdf_mem_cmp( + &adapter->sta_info[sta_id].sta_mac.bytes, + peer_mac, QDF_MAC_ADDR_SIZE)) + break; + } + + if (WLAN_MAX_STA_COUNT == sta_id) { + hdd_err("No active peer with mac="MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + nss = adapter->sta_info[sta_id].nss; + freq = cds_chan_to_freq( + (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operating_channel); + rate_flags = adapter->sta_info[sta_id].rate_flags; + } else { + hdd_err("Not Associated! with mac "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(u8) + sizeof(u8) + sizeof(u32) + NLMSG_HDRLEN); + + if (NULL == 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"); + kfree_skb(reply_skb); + return -EINVAL; + } + + return 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_link_properties(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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 (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_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->session_id); + status = sme_stop_roaming(mac_handle, adapter->session_id, + eCsrHddIssued); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Enable/Disable roaming failed"); + return -EINVAL; + } + + status = sme_ps_enable_disable(mac_handle, adapter->session_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->session_id, + eCsrHddIssued); + else if (current_roam_state == eCSR_ROAMING_STATE_STOP || + current_roam_state == eCSR_ROAMING_STATE_IDLE) + status = sme_stop_roaming(mac_handle, + adapter->session_id, + eCsrHddIssued); + + if (status != QDF_STATUS_SUCCESS) + hdd_err("Restoring roaming state failed"); + + return -EINVAL; + } + + + return 0; +} + +/** + * 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 + */ +static int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ota_test(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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); + + 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->session_id, scale_value); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set tx power scale failed"); + return -EINVAL; + } + + return 0; +} + +/** + * 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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); + + 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->session_id, + scale_value); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set tx power decrease db failed"); + return -EINVAL; + } + + return 0; +} + +/** + * 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale_decr_db(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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; + uint8_t chans[QDF_MAX_NUM_CHAN] = {0}; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_ctx->config->enableDFSMasterCap) { + hdd_err("DFS master capability is not present in the driver"); + return -EINVAL; + } + + 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 (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, NULL)) { + 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 > QDF_MAX_NUM_CHAN) { + 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++) { + if (freq[i] == 0) + chans[i] = 0; + else + chans[i] = ieee80211_frequency_to_channel(freq[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(chans[0]); + if (ret) { + hdd_err("pre cac request failed with reason:%d", ret); + return ret; + } + + return 0; +} + +/* 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) + +static 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_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 (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 ((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->session_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 == NULL) { + 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 == NULL) { + 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); +} + + +/** + * 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 inovkes internal __wlan_hdd_cfg80211_p2p_lo_start() + * to process p2p listen offload start vendor command. + * + * 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 = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_p2p_lo_start(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 (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 ((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); +} + +/** + * 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 + */ +static int wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_p2p_lo_stop(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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 + * + * Inovkes internal API __wlan_hdd_cfg80211_conditional_chan_switch() + * to process the conditional 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; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_conditional_chan_switch(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_set_pre_cac_status() - Set the pre cac status + * @pre_cac_adapter: AP adapter used for pre cac + * @status: Status (true or false) + * @handle: Global handle + * + * Sets the status of pre cac i.e., whether the pre cac is active or not + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_set_pre_cac_status(struct hdd_adapter *pre_cac_adapter, + bool status, mac_handle_t handle) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_pre_cac_status( + WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter), status, handle); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +/** + * wlan_hdd_set_chan_before_pre_cac() - Save the channel before pre cac + * @ap_adapter: AP adapter + * @chan_before_pre_cac: Channel + * + * Saves the channel which the AP was beaconing on before moving to the pre + * cac channel. If radar is detected on the pre cac channel, this saved + * channel will be used for AP operations. + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_set_chan_before_pre_cac(struct hdd_adapter *ap_adapter, + uint8_t chan_before_pre_cac) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_chan_before_pre_cac( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), chan_before_pre_cac); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter, + uint32_t *channel_count, + uint8_t *channel_list, + enum band_info band) +{ + tsap_config_t *sap_config; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t tmp_chan_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t chan_count; + uint8_t i; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev = hdd_ctx->pdev; + uint8_t tmp_chan; + + sap_config = &adapter->session.ap.sap_config; + + status = + policy_mgr_get_valid_chans(hdd_ctx->psoc, + tmp_chan_list, + &chan_count); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get channel list"); + return -EINVAL; + } + + for (i = 0; i < chan_count; i++) { + tmp_chan = tmp_chan_list[i]; + if (*channel_count < QDF_MAX_NUM_CHAN) { + if ((BAND_2G == band) && + (WLAN_REG_IS_24GHZ_CH(tmp_chan)) && + (!wlan_reg_is_disable_ch(pdev, tmp_chan))) { + channel_list[*channel_count] = tmp_chan; + *channel_count += 1; + } else if ((BAND_5G == band) && + (WLAN_REG_IS_5GHZ_CH(tmp_chan)) && + (!wlan_reg_is_disable_ch(pdev, tmp_chan))) { + channel_list[*channel_count] = tmp_chan; + *channel_count += 1; + } + } else { + break; + } + } + + if (*channel_count == 0) { + hdd_err("no valid channel found"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_validate_and_get_pre_cac_ch() - Validate and get pre cac channel + * @hdd_ctx: HDD context + * @ap_adapter: AP adapter + * @channel: Channel requested by userspace + * @pre_cac_chan: Pointer to the pre CAC channel + * + * 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 + */ +static int wlan_hdd_validate_and_get_pre_cac_ch(struct hdd_context *hdd_ctx, + struct hdd_adapter *ap_adapter, + uint8_t channel, + uint8_t *pre_cac_chan) +{ + uint32_t i; + QDF_STATUS status; + uint32_t weight_len = 0; + uint32_t len = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0}; + uint8_t pcl_weights[QDF_MAX_NUM_CHAN] = {0}; + mac_handle_t mac_handle; + + if (0 == channel) { + /* 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(hdd_ctx->psoc, + channel_list, &len); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get channel list"); + return -EINVAL; + } + policy_mgr_update_with_safe_channel_list(hdd_ctx->psoc, + channel_list, &len, pcl_weights, weight_len); + for (i = 0; i < len; i++) { + if (wlan_reg_is_dfs_ch(hdd_ctx->pdev, + channel_list[i])) { + *pre_cac_chan = channel_list[i]; + break; + } + } + if (*pre_cac_chan == 0) { + hdd_err("unable to find outdoor channel"); + return -EINVAL; + } + } else { + /* 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. + */ + mac_handle = hdd_ctx->mac_handle; + if (!sme_is_channel_valid(mac_handle, channel) || + !wlan_reg_is_dfs_ch(hdd_ctx->pdev, channel)) { + hdd_err("Invalid channel for pre cac:%d", channel); + return -EINVAL; + } + *pre_cac_chan = channel; + } + hdd_debug("selected pre cac channel:%d", *pre_cac_chan); + return 0; +} + +/** + * wlan_hdd_request_pre_cac() - Start pre CAC in the driver + * @channel: Channel 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(uint8_t channel) +{ + uint8_t pre_cac_chan = 0, *mac_addr; + struct hdd_context *hdd_ctx; + int ret; + struct hdd_adapter *ap_adapter, *pre_cac_adapter; + struct hdd_ap_ctx *hdd_ap_ctx; + QDF_STATUS status; + struct wiphy *wiphy; + struct net_device *dev; + struct cfg80211_chan_def chandef; + enum nl80211_channel_type channel_type; + uint32_t freq; + struct ieee80211_channel *chan; + mac_handle_t mac_handle; + bool val; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (0 != wlan_hdd_validate_context(hdd_ctx)) + 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; + } + + mac_handle = hdd_ctx->mac_handle; + val = wlan_sap_is_pre_cac_active(mac_handle); + if (val) { + hdd_err("pre cac is already in progress"); + return -EINVAL; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + if (!hdd_ap_ctx) { + hdd_err("SAP context is NULL"); + return -EINVAL; + } + + if (wlan_reg_is_dfs_ch(hdd_ctx->pdev, hdd_ap_ctx->operating_channel)) { + hdd_err("SAP is already on DFS channel:%d", + hdd_ap_ctx->operating_channel); + return -EINVAL; + } + + if (!WLAN_REG_IS_24GHZ_CH(hdd_ap_ctx->operating_channel)) { + hdd_err("pre CAC alllowed only when SAP is in 2.4GHz:%d", + hdd_ap_ctx->operating_channel); + return -EINVAL; + } + + 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; + } + + hdd_debug("channel:%d", channel); + + ret = wlan_hdd_validate_and_get_pre_cac_ch(hdd_ctx, ap_adapter, channel, + &pre_cac_chan); + 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"); + + /* 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. + */ + pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, "precac%d", + mac_addr, NET_NAME_UNKNOWN, true); + if (!pre_cac_adapter) { + hdd_err("error opening the pre cac adapter"); + goto release_intf_addr_and_return_failure; + } + + /* + * 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)) { + 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_adapter->session.ap.beacon = qdf_mem_malloc( + sizeof(*ap_adapter->session.ap.beacon)); + if (!pre_cac_adapter->session.ap.beacon) { + hdd_err("failed to alloc mem for beacon"); + goto stop_close_pre_cac_adapter; + } + qdf_mem_copy(pre_cac_adapter->session.ap.beacon, + ap_adapter->session.ap.beacon, + sizeof(*pre_cac_adapter->session.ap.beacon)); + pre_cac_adapter->session.ap.sap_config.ch_width_orig = + ap_adapter->session.ap.sap_config.ch_width_orig; + pre_cac_adapter->session.ap.sap_config.authType = + ap_adapter->session.ap.sap_config.authType; + + /* 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. + */ + switch (ap_adapter->session.ap.sap_config.ch_width_orig) { + case CH_WIDTH_20MHZ: + channel_type = NL80211_CHAN_HT20; + break; + case CH_WIDTH_40MHZ: + if (ap_adapter->session.ap.sap_config.sec_ch > + ap_adapter->session.ap.sap_config.channel) + channel_type = NL80211_CHAN_HT40PLUS; + else + channel_type = NL80211_CHAN_HT40MINUS; + break; + default: + channel_type = NL80211_CHAN_NO_HT; + break; + } + + freq = cds_chan_to_freq(pre_cac_chan); + chan = ieee80211_get_channel(wiphy, freq); + if (!chan) { + hdd_err("channel converion failed"); + goto stop_close_pre_cac_adapter; + } + + cfg80211_chandef_create(&chandef, chan, channel_type); + + hdd_debug("orig width:%d channel_type:%d freq:%d", + ap_adapter->session.ap.sap_config.ch_width_orig, + channel_type, 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, + ap_adapter->session_id, + pre_cac_chan, + 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 (0 != ret) { + hdd_err("failed to set channel"); + goto stop_close_pre_cac_adapter; + } + + status = wlan_hdd_cfg80211_start_bss(pre_cac_adapter, 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 = wlan_hdd_set_pre_cac_status(pre_cac_adapter, true, mac_handle); + if (0 != ret) { + hdd_err("failed to set pre cac status"); + goto stop_close_pre_cac_adapter; + } + + ret = wlan_hdd_set_chan_before_pre_cac(ap_adapter, + hdd_ap_ctx->operating_channel); + if (0 != ret) { + hdd_err("failed to set channel before pre cac"); + goto stop_close_pre_cac_adapter; + } + + ap_adapter->pre_cac_chan = pre_cac_chan; + + return 0; + +stop_close_pre_cac_adapter: + hdd_stop_adapter(hdd_ctx, pre_cac_adapter); + qdf_mem_free(pre_cac_adapter->session.ap.beacon); + pre_cac_adapter->session.ap.beacon = NULL; +close_pre_cac_adapter: + hdd_close_adapter(hdd_ctx, pre_cac_adapter, false); +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 + */ + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + return -EINVAL; +} + +static 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_MANDATORY_FREQUENCY_LIST] = { + .type = NLA_NESTED }, +}; + +static 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 }, +}; + +static 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 }, +}; + +/** + * __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; + int channel_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_CHANNEL_HINT]) + channel_hint = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT]); + + if (!IS_CHANNEL_VALID(channel_hint)) { + hdd_err("acs channel is not valid"); + return -EINVAL; + } + acs_policy->acs_channel = channel_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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_acs_dfs_mode(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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 CSR_STA_ROAM_POLICY_DFS_ENABLED; + case DFS_MODE_DISABLE: + return CSR_STA_ROAM_POLICY_DFS_DISABLED; + case DFS_MODE_DEPRIORITIZE: + return CSR_STA_ROAM_POLICY_DFS_DEPRIORITIZE; + default: + hdd_err("STA Roam policy dfs mode is NONE"); + return CSR_STA_ROAM_POLICY_NONE; + } +} + +/* + * 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; + uint8_t operating_channel = 0; + uint8_t sap_operating_band = 0; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode != QDF_SAP_MODE) + continue; + + operating_channel = adapter->session.ap.operating_channel; + if (IS_24G_CH(operating_channel)) + sap_operating_band = BAND_2G; + else if (IS_5G_CH(operating_channel)) + sap_operating_band = BAND_5G; + else + sap_operating_band = BAND_ALL; + } + + return sap_operating_band; +} + +static 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->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sta_roam_policy(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_CH_AVOID + +static int hdd_validate_avoid_freq_chanlist( + struct hdd_context *hdd_ctx, + struct ch_avoid_ind_type *channel_list) +{ + unsigned int range_idx, ch_idx; + unsigned int unsafe_channel_index, unsafe_channel_count = 0; + bool ch_found = false; + + unsafe_channel_count = QDF_MIN((uint16_t)hdd_ctx->unsafe_channel_count, + (uint16_t)NUM_CHANNELS); + + for (range_idx = 0; range_idx < channel_list->ch_avoid_range_cnt; + range_idx++) { + if ((channel_list->avoid_freq_range[range_idx].start_freq < + CDS_24_GHZ_CHANNEL_1) || + (channel_list->avoid_freq_range[range_idx].end_freq > + CDS_5_GHZ_CHANNEL_165) || + (channel_list->avoid_freq_range[range_idx].start_freq > + channel_list->avoid_freq_range[range_idx].end_freq)) + continue; + + for (ch_idx = channel_list-> + avoid_freq_range[range_idx].start_freq; + ch_idx <= channel_list-> + avoid_freq_range[range_idx].end_freq; + ch_idx++) { + if (INVALID_CHANNEL == reg_get_chan_enum(ch_idx)) + continue; + for (unsafe_channel_index = 0; + unsafe_channel_index < unsafe_channel_count; + unsafe_channel_index++) { + if (ch_idx == + hdd_ctx->unsafe_channel_list[ + unsafe_channel_index]) { + hdd_info("Duplicate channel %d", + ch_idx); + ch_found = true; + break; + } + } + if (!ch_found) { + hdd_ctx->unsafe_channel_list[ + unsafe_channel_count++] = ch_idx; + } + ch_found = false; + } + } + return unsafe_channel_count; +} + +/** + * __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); + uint16_t *local_unsafe_list; + uint16_t unsafe_channel_index, local_unsafe_list_count; + struct ch_avoid_ind_type *channel_list; + enum QDF_GLOBAL_MODE curr_mode; + uint8_t num_args = 0; + + hdd_enter_dev(wdev->netdev); + + if (!qdf_ctx) { + hdd_err("qdf_ctx is NULL"); + 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; + 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; + } + + ret = hdd_clone_local_unsafe_chan(hdd_ctx, + &local_unsafe_list, + &local_unsafe_list_count); + if (0 != ret) { + hdd_err("failed to clone the cur unsafe chan list"); + return ret; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, hdd_ctx->unsafe_channel_list, + &(hdd_ctx->unsafe_channel_count), + sizeof(hdd_ctx->unsafe_channel_list)); + + hdd_ctx->unsafe_channel_count = hdd_validate_avoid_freq_chanlist( + hdd_ctx, + channel_list); + + pld_set_wlan_unsafe_channel(qdf_ctx->dev, hdd_ctx->unsafe_channel_list, + hdd_ctx->unsafe_channel_count); + + for (unsafe_channel_index = 0; + unsafe_channel_index < hdd_ctx->unsafe_channel_count; + unsafe_channel_index++) { + hdd_debug("Channel %d is not safe", + hdd_ctx->unsafe_channel_list[unsafe_channel_index]); + } + if (hdd_local_unsafe_channel_updated(hdd_ctx, local_unsafe_list, + local_unsafe_list_count)) + hdd_unsafe_channel_restart_sap(hdd_ctx); + qdf_mem_free(local_unsafe_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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_avoid_freq(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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]; + uint8_t config_channel = 0; + struct hdd_ap_ctx *ap_ctx; + int ret; + QDF_STATUS status; + + 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; + + 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_CHANNEL]) { + if (!test_bit(SOFTAP_BSS_STARTED, + &hostapd_adapter->event_flags)) { + hdd_err("SAP is not started yet. Restart sap will be invalid"); + return -EINVAL; + } + + config_channel = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL]); + + if (!((IS_24G_CH(config_channel)) || + (IS_5G_CH(config_channel)))) { + hdd_err("Channel %d is not valid to restart SAP", + config_channel); + return -ENOTSUPP; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(hostapd_adapter); + ap_ctx->sap_config.channel = config_channel; + 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; + + wlan_reg_set_channel_params(hdd_ctx->pdev, + ap_ctx->sap_config.channel, + ap_ctx->sap_config.sec_ch, + &ap_ctx->sap_config.ch_params); + + hdd_restart_sap(hostapd_adapter); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST]) { + uint32_t freq_len, i; + uint32_t *freq; + uint8_t chans[QDF_MAX_NUM_CHAN]; + + 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 > QDF_MAX_NUM_CHAN) { + 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++) { + chans[i] = ieee80211_frequency_to_channel(freq[i]); + hdd_debug("freq[%d]=%d", i, freq[i]); + } + + status = policy_mgr_set_sap_mandatory_channels( + hdd_ctx->psoc, chans, 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sap_configuration_set(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#undef APF_INVALID +#undef APF_SET_RESET +#undef APF_VERSION +#undef APF_ID +#undef APF_PACKET_SIZE +#undef APF_CURRENT_OFFSET +#undef APF_PROGRAM +#undef APF_MAX + +#ifndef QCA_SUPPORT_CP_STATS +/** + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_wakelock_stats_rsp_callback() + */ +#define PARAM_TOTAL_CMD_EVENT_WAKE \ + QCA_WLAN_VENDOR_ATTR_TOTAL_CMD_EVENT_WAKE +#define PARAM_CMD_EVENT_WAKE_CNT_PTR \ + QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_PTR +#define PARAM_CMD_EVENT_WAKE_CNT_SZ \ + QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_SZ +#define PARAM_TOTAL_DRIVER_FW_LOCAL_WAKE \ + QCA_WLAN_VENDOR_ATTR_TOTAL_DRIVER_FW_LOCAL_WAKE +#define PARAM_DRIVER_FW_LOCAL_WAKE_CNT_PTR \ + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_PTR +#define PARAM_DRIVER_FW_LOCAL_WAKE_CNT_SZ \ + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_SZ +#define PARAM_TOTAL_RX_DATA_WAKE \ + QCA_WLAN_VENDOR_ATTR_TOTAL_RX_DATA_WAKE +#define PARAM_RX_UNICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_RX_UNICAST_CNT +#define PARAM_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_RX_MULTICAST_CNT +#define PARAM_RX_BROADCAST_CNT \ + QCA_WLAN_VENDOR_ATTR_RX_BROADCAST_CNT +#define PARAM_ICMP_PKT \ + QCA_WLAN_VENDOR_ATTR_ICMP_PKT +#define PARAM_ICMP6_PKT \ + QCA_WLAN_VENDOR_ATTR_ICMP6_PKT +#define PARAM_ICMP6_RA \ + QCA_WLAN_VENDOR_ATTR_ICMP6_RA +#define PARAM_ICMP6_NA \ + QCA_WLAN_VENDOR_ATTR_ICMP6_NA +#define PARAM_ICMP6_NS \ + QCA_WLAN_VENDOR_ATTR_ICMP6_NS +#define PARAM_ICMP4_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_ICMP4_RX_MULTICAST_CNT +#define PARAM_ICMP6_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_ICMP6_RX_MULTICAST_CNT +#define PARAM_OTHER_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_OTHER_RX_MULTICAST_CNT +#define PARAM_RSSI_BREACH_CNT \ + QCA_WLAN_VENDOR_ATTR_RSSI_BREACH_CNT +#define PARAM_LOW_RSSI_CNT \ + QCA_WLAN_VENDOR_ATTR_LOW_RSSI_CNT +#define PARAM_GSCAN_CNT \ + QCA_WLAN_VENDOR_ATTR_GSCAN_CNT +#define PARAM_PNO_COMPLETE_CNT \ + QCA_WLAN_VENDOR_ATTR_PNO_COMPLETE_CNT +#define PARAM_PNO_MATCH_CNT \ + QCA_WLAN_VENDOR_ATTR_PNO_MATCH_CNT + +/** + * hdd_send_wakelock_stats() - API to send wakelock stats + * @ctx: context to be passed to callback + * @data: data passed to callback + * + * This function is used to send wake lock stats to HAL layer + * + * Return: 0 on success, error number otherwise. + */ +static uint32_t hdd_send_wakelock_stats(struct hdd_context *hdd_ctx, + const struct sir_wake_lock_stats *data) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + uint32_t total_rx_data_wake, rx_multicast_cnt; + uint32_t ipv6_rx_multicast_addr_cnt; + uint32_t icmpv6_cnt; + + hdd_enter(); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += + QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX * + (NLMSG_HDRLEN + sizeof(uint32_t)); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_debug("wow_ucast_wake_up_count %d", + data->wow_ucast_wake_up_count); + hdd_debug("wow_bcast_wake_up_count %d", + data->wow_bcast_wake_up_count); + hdd_debug("wow_ipv4_mcast_wake_up_count %d", + data->wow_ipv4_mcast_wake_up_count); + hdd_debug("wow_ipv6_mcast_wake_up_count %d", + data->wow_ipv6_mcast_wake_up_count); + hdd_debug("wow_ipv6_mcast_ra_stats %d", + data->wow_ipv6_mcast_ra_stats); + hdd_debug("wow_ipv6_mcast_ns_stats %d", + data->wow_ipv6_mcast_ns_stats); + hdd_debug("wow_ipv6_mcast_na_stats %d", + data->wow_ipv6_mcast_na_stats); + hdd_debug("wow_icmpv4_count %d", data->wow_icmpv4_count); + hdd_debug("wow_icmpv6_count %d", + data->wow_icmpv6_count); + hdd_debug("wow_rssi_breach_wake_up_count %d", + data->wow_rssi_breach_wake_up_count); + hdd_debug("wow_low_rssi_wake_up_count %d", + data->wow_low_rssi_wake_up_count); + hdd_debug("wow_gscan_wake_up_count %d", + data->wow_gscan_wake_up_count); + hdd_debug("wow_pno_complete_wake_up_count %d", + data->wow_pno_complete_wake_up_count); + hdd_debug("wow_pno_match_wake_up_count %d", + data->wow_pno_match_wake_up_count); + + ipv6_rx_multicast_addr_cnt = + data->wow_ipv6_mcast_wake_up_count; + + icmpv6_cnt = + data->wow_icmpv6_count; + + rx_multicast_cnt = + data->wow_ipv4_mcast_wake_up_count + + ipv6_rx_multicast_addr_cnt; + + total_rx_data_wake = + data->wow_ucast_wake_up_count + + data->wow_bcast_wake_up_count + + rx_multicast_cnt; + + if (nla_put_u32(skb, PARAM_TOTAL_CMD_EVENT_WAKE, 0) || + nla_put_u32(skb, PARAM_CMD_EVENT_WAKE_CNT_PTR, 0) || + nla_put_u32(skb, PARAM_CMD_EVENT_WAKE_CNT_SZ, 0) || + nla_put_u32(skb, PARAM_TOTAL_DRIVER_FW_LOCAL_WAKE, 0) || + nla_put_u32(skb, PARAM_DRIVER_FW_LOCAL_WAKE_CNT_PTR, 0) || + nla_put_u32(skb, PARAM_DRIVER_FW_LOCAL_WAKE_CNT_SZ, 0) || + nla_put_u32(skb, PARAM_TOTAL_RX_DATA_WAKE, + total_rx_data_wake) || + nla_put_u32(skb, PARAM_RX_UNICAST_CNT, + data->wow_ucast_wake_up_count) || + nla_put_u32(skb, PARAM_RX_MULTICAST_CNT, + rx_multicast_cnt) || + nla_put_u32(skb, PARAM_RX_BROADCAST_CNT, + data->wow_bcast_wake_up_count) || + nla_put_u32(skb, PARAM_ICMP_PKT, + data->wow_icmpv4_count) || + nla_put_u32(skb, PARAM_ICMP6_PKT, + icmpv6_cnt) || + nla_put_u32(skb, PARAM_ICMP6_RA, + data->wow_ipv6_mcast_ra_stats) || + nla_put_u32(skb, PARAM_ICMP6_NA, + data->wow_ipv6_mcast_na_stats) || + nla_put_u32(skb, PARAM_ICMP6_NS, + data->wow_ipv6_mcast_ns_stats) || + nla_put_u32(skb, PARAM_ICMP4_RX_MULTICAST_CNT, + data->wow_ipv4_mcast_wake_up_count) || + nla_put_u32(skb, PARAM_ICMP6_RX_MULTICAST_CNT, + ipv6_rx_multicast_addr_cnt) || + nla_put_u32(skb, PARAM_OTHER_RX_MULTICAST_CNT, 0) || + nla_put_u32(skb, PARAM_RSSI_BREACH_CNT, + data->wow_rssi_breach_wake_up_count) || + nla_put_u32(skb, PARAM_LOW_RSSI_CNT, + data->wow_low_rssi_wake_up_count) || + nla_put_u32(skb, PARAM_GSCAN_CNT, + data->wow_gscan_wake_up_count) || + nla_put_u32(skb, PARAM_PNO_COMPLETE_CNT, + data->wow_pno_complete_wake_up_count) || + nla_put_u32(skb, PARAM_PNO_MATCH_CNT, + data->wow_pno_match_wake_up_count)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + + hdd_exit(); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} +#endif + +#ifdef QCA_SUPPORT_CP_STATS +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); +} +#else +/** + * 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) +{ + int ret; + QDF_STATUS qdf_status; + struct sir_wake_lock_stats wake_lock_stats = {0}; + + qdf_status = wma_get_wakelock_stats(&wake_lock_stats); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to get wakelock stats(err=%d)", qdf_status); + return -EINVAL; + } + + ret = hdd_send_wakelock_stats(hdd_ctx, &wake_lock_stats); + if (ret) + hdd_err("Failed to post wake lock stats"); + + return ret; +} +#endif + +/** + * __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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_wakelock_stats(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("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; + } + + cfg80211_vendor_cmd_reply(skb); + + hdd_exit(); + + return 0; + +nla_put_failure: + kfree_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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_bus_size(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + *__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; + static const struct nla_policy policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] + = {[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE] = { .type = NLA_U32 } }; + + hdd_enter(); + + 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, policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]) { + hdd_err("attr SETBAND_VALUE failed"); + return -EINVAL; + } + + ret = hdd_reg_set_band(dev, + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE])); + + hdd_exit(); + return ret; +} + +/** + *wlan_hdd_validate_acs_channel() - validate channel provided by ACS + * @adapter: hdd adapter + * @channel: channel number + * + * return: QDF status based on success or failure + */ +static QDF_STATUS wlan_hdd_validate_acs_channel(struct hdd_adapter *adapter, + int channel, int chan_bw) +{ + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel)) + return QDF_STATUS_E_FAILURE; + if ((wlansap_is_channel_in_nol_list(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + channel, + PHY_SINGLE_CHANNEL_CENTERED))) { + hdd_info("channel %d is in nol", channel); + return -EINVAL; + } + + if ((wlansap_is_channel_leaking_in_nol( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + channel, chan_bw))) { + hdd_info("channel %d is leaking in nol", channel); + return -EINVAL; + } + + return 0; + +} + +static void hdd_update_acs_sap_config(struct hdd_context *hdd_ctx, + tsap_config_t *sap_config, + struct hdd_vendor_chan_info *channel_list) +{ + sap_config->channel = channel_list->pri_ch; + + sap_config->ch_params.center_freq_seg0 = + channel_list->vht_seg0_center_ch; + sap_config->ch_params.center_freq_seg1 = + channel_list->vht_seg1_center_ch; + + sap_config->ch_params.sec_ch_offset = channel_list->ht_sec_ch; + sap_config->ch_params.ch_width = channel_list->chan_width; + if (sap_config->channel >= 36) + sap_config->ch_width_orig = + hdd_ctx->config->vhtChannelWidth; + else + sap_config->ch_width_orig = + hdd_ctx->config->nChannelBondingMode24GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + + sap_config->acs_cfg.pri_ch = channel_list->pri_ch; + sap_config->acs_cfg.ch_width = channel_list->chan_width; + sap_config->acs_cfg.vht_seg0_center_ch = + channel_list->vht_seg0_center_ch; + sap_config->acs_cfg.vht_seg1_center_ch = + channel_list->vht_seg1_center_ch; + sap_config->acs_cfg.ht_sec_ch = channel_list->ht_sec_ch; +} + +static int hdd_update_acs_channel(struct hdd_adapter *adapter, uint8_t reason, + uint8_t channel_cnt, + struct hdd_vendor_chan_info *channel_list) +{ + tsap_config_t *sap_config; + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status = QDF_STATUS_SUCCESS; + mac_handle_t mac_handle; + + if (!channel_list) { + hdd_err("channel_list is NULL"); + return -EINVAL; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + sap_config = &adapter->session.ap.sap_config; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&adapter->session. + ap.vendor_acs_timer)) { + qdf_mc_timer_stop(&adapter->session.ap.vendor_acs_timer); + } + + if (channel_list->pri_ch == 0) { + /* Check mode, set default channel */ + channel_list->pri_ch = 6; + /* + * 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(adapter); + break; + + /* DFS detected on current channel */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS: + wlan_sap_update_next_channel( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + channel_list->pri_ch, + channel_list->chan_width); + status = sme_update_new_channel_event( + mac_handle, + adapter->session_id); + break; + + /* LTE coex event on current channel */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX: + sap_config->acs_cfg.pri_ch = channel_list->pri_ch; + sap_config->acs_cfg.ch_width = channel_list->chan_width; + hdd_ap_ctx->sap_config.ch_width_orig = + channel_list->chan_width; + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->session_id, + CSA_REASON_LTE_COEX); + hdd_switch_sap_channel(adapter, sap_config->acs_cfg.pri_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_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}, +}; + +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}, +}; + +/** + * hdd_parse_vendor_acs_chan_config() - API to parse vendor acs channel config + * @channel_list: 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_vendor_chan_info + **chan_list_ptr, uint8_t *reason, 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; + } + + if (tb[SET_CHAN_REASON]) + *reason = nla_get_u8(tb[SET_CHAN_REASON]); + + if (!tb[SET_CHAN_CHAN_LIST]) { + hdd_err("channel list empty"); + return -EINVAL; + } + + nla_for_each_nested(curr_attr, tb[SET_CHAN_CHAN_LIST], rem) + i++; + + if (i > MAX_CHANNEL) { + hdd_err("Error: Exceeded max channels: %u", MAX_CHANNEL); + return -ENOMEM; + } + + *channel_cnt = (uint8_t)i; + + if (i == 0) + hdd_err("incorrect channel count"); + + channel_list = qdf_mem_malloc(sizeof(struct hdd_vendor_chan_info) * + (*channel_cnt)); + if (NULL == channel_list) { + hdd_err("Could not allocate for channel_list"); + return -ENOMEM; + } + + 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); + return -EINVAL; + } + if (tb2[SET_EXT_ACS_BAND]) { + channel_list[i].band = + nla_get_u8(tb2[SET_EXT_ACS_BAND]); + } + /* Parse and Fetch allowed SSID list*/ + if (tb2[SET_CHAN_PRIMARY_CHANNEL]) { + channel_list[i].pri_ch = + nla_get_u8( + tb2[SET_CHAN_PRIMARY_CHANNEL]); + } + if (tb2[SET_CHAN_SECONDARY_CHANNEL]) { + channel_list[i].ht_sec_ch = + nla_get_u8(tb2[SET_CHAN_SECONDARY_CHANNEL]); + } + if (tb2[SET_CHAN_SEG0_CENTER_CHANNEL]) { + channel_list[i].vht_seg0_center_ch = + nla_get_u8(tb2[SET_CHAN_SEG0_CENTER_CHANNEL]); + } + if (tb2[SET_CHAN_SEG1_CENTER_CHANNEL]) { + channel_list[i].vht_seg1_center_ch = + nla_get_u8(tb2[SET_CHAN_SEG1_CENTER_CHANNEL]); + } + if (tb2[SET_CHAN_CHANNEL_WIDTH]) { + channel_list[i].chan_width = + nla_get_u8(tb2[SET_CHAN_CHANNEL_WIDTH]); + } + hdd_debug("index %d pri %d sec %d seg0 %d seg1 %d width %d", + i, channel_list[i].pri_ch, + channel_list[i].ht_sec_ch, + channel_list[i].vht_seg0_center_ch, + channel_list[i].vht_seg1_center_ch, + channel_list[i].chan_width); + i++; + } + *chan_list_ptr = channel_list; + + return 0; +} + +/** + * Undef short names for vendor set channel configuration + */ +#undef SET_CHAN_REASON +#undef SET_CHAN_CHANNEL_COUNT +#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_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 qdf_status; + uint8_t channel_cnt = 0, reason = -1; + struct hdd_vendor_chan_info *channel_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 *channel_list_ptr; + + 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, &adapter->event_flags)) + clear_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->event_flags); + else { + hdd_err("already timeout happened for acs"); + return -EINVAL; + } + + ret_val = hdd_parse_vendor_acs_chan_config(&channel_list, &reason, + &channel_cnt, data, data_len); + channel_list_ptr = channel_list; + if (ret_val) + return ret_val; + + /* Validate channel to be set */ + while (channel_cnt && channel_list) { + qdf_status = wlan_hdd_validate_acs_channel(adapter, + channel_list->pri_ch, + channel_list->chan_width); + if (qdf_status == QDF_STATUS_SUCCESS) + break; + else if (channel_cnt == 1) { + hdd_err("invalid channel %d received from app", + channel_list->pri_ch); + channel_list->pri_ch = 0; + break; + } + + channel_cnt--; + channel_list++; + } + + if ((channel_cnt <= 0) || !channel_list) { + hdd_err("no available channel/chanlist %d/%pK", channel_cnt, + channel_list); + qdf_mem_free(channel_list_ptr); + return -EINVAL; + } + + hdd_debug("received primary channel as %d", channel_list->pri_ch); + + ret_val = hdd_update_acs_channel(adapter, reason, + channel_cnt, channel_list); + qdf_mem_free(channel_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_update_vendor_channel(wiphy, wdev, data, + data_len); + cds_ssr_protect(__func__); + + return ret; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_setband(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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; + + if (hdd_ctx->sar_version != SAR_VERSION_2) { + 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; + + 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; +} + +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; + } +} + +#define WLAN_WAIT_TIME_SAR 5000 + +/** + * hdd_sar_context - hdd sar context + * @event: sar limit event + */ +struct hdd_sar_context { + struct sar_limit_event event; +}; + +/** + * 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 = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + errno = hdd_sar_fill_response(skb, event); + if (errno) { + kfree_skb(skb); + return errno; + } + + return 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 (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; + + 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; +} + +/** + * 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 + */ +static int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_get_sar_power_limits(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +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); +} + +#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 + +static const struct nla_policy +sar_limits_policy[SAR_LIMITS_MAX + 1] = { + [SAR_LIMITS_SAR_ENABLE] = {.type = NLA_U32}, + [SAR_LIMITS_NUM_SPECS] = {.type = NLA_U32}, + [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}, +}; + +/** + * hdd_extract_sar_nested_attrs() - Extract nested SAR attribute + * @spec: nested nla attribue + * @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; + + 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, + sar_limits_policy)) { + hdd_err("Invalid SAR attributes"); + return -EINVAL; + } + + sar_limit_cmd = qdf_mem_malloc(sizeof(struct sar_limit_cmd_params)); + if (!sar_limit_cmd) + return -ENOMEM; + + /* is special SAR V1 => SAR V2 logic enabled and applicable? */ + if (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_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]); + uint32_t *sar_ptr = &sar_limit_cmd->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) { + hdd_err("Failed to allocate memory for sar_limit_row_list"); + 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), + 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 + +/** + * 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 + */ +static int wlan_hdd_cfg80211_set_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_sar_power_limits(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 hdd_adapter *adapter; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, rso_status->vdev_id); + if (!adapter) { + hdd_err("adapter NULL"); + return; + } + + adapter->lfr_fw_status.is_disabled = rso_status->status; + complete(&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; + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + 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; + } + + 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("isFastRoamEnabled %d", is_fast_roam_enabled); + + /* Update roaming */ + mac_handle = hdd_ctx->mac_handle; + qdf_status = sme_config_fast_roaming(mac_handle, adapter->session_id, + is_fast_roam_enabled); + if (qdf_status != QDF_STATUS_SUCCESS) + hdd_err("sme_config_fast_roaming failed with status=%d", + qdf_status); + ret = qdf_status_to_os_return(qdf_status); + + if (eConnectionState_Associated == hdd_sta_ctx->conn_info.connState && + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_fast_roaming(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * 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[STATS_SET_MAX + 1] = { + [STATS_SET_START] = {.type = NLA_FLAG }, + [STATS_GW_IPV4] = {.type = NLA_U32 }, + [STATS_SET_DATA_PKT_INFO] = {.type = NLA_U32 }, +}; + +/* 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 }, +}; + +/** + * hdd_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 *hdd_dns_unmake_name_query(uint8_t *name) +{ + uint8_t *p; + unsigned int len; + + p = name; + while ((len = *p)) { + *(p++) = '.'; + p += len; + } + + return name + 1; +} + +/** + * hdd_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 + * + * DNS names consist of "element" pairs. + * + * Return: Byte following constructed DNS name + */ +static uint8_t *hdd_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]) { + hdd_debug("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; +} + +/** + * hdd_set_clear_connectivity_check_stats_info() - set/clear stats info + * @adapter: Pointer to hdd adapter + * @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 hdd_set_clear_connectivity_check_stats_info( + struct hdd_adapter *adapter, + struct 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; + + /* 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), + qca_wlan_vendor_set_connectivity_check_stats)) { + hdd_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) { + hdd_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; + adapter->pkt_type_bitmap |= + arp_stats_params->pkt_type_bitmap; + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_ARP) { + if (!tb[STATS_GW_IPV4]) { + hdd_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; + adapter->track_arp_ip = + arp_stats_params->ip_addr; + } + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + uint8_t *domain_name; + + if (!tb2[STATS_DNS_DOMAIN_NAME]) { + hdd_err("DNS domain id is not present"); + err = -EINVAL; + goto end; + } + domain_name = nla_data( + tb2[STATS_DNS_DOMAIN_NAME]); + adapter->track_dns_domain_len = + nla_len(tb2[ + STATS_DNS_DOMAIN_NAME]); + if (!hdd_dns_make_name_query( + domain_name, + adapter->dns_payload, + adapter->track_dns_domain_len)) + adapter->track_dns_domain_len = + 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]) { + hdd_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]); + adapter->track_src_port = + arp_stats_params->tcp_src_port; + adapter->track_dest_port = + arp_stats_params->tcp_dst_port; + } + + if (pkt_bitmap & + CONNECTIVITY_CHECK_SET_ICMPV4) { + if (!tb2[STATS_DEST_IPV4]) { + hdd_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]); + adapter->track_dest_ipv4 = + arp_stats_params->icmp_ipv4; + } + } else { + /* clear stats command received */ + arp_stats_params->pkt_type_bitmap = pkt_bitmap; + arp_stats_params->flag = false; + adapter->pkt_type_bitmap &= + (~arp_stats_params->pkt_type_bitmap); + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_ARP) { + arp_stats_params->pkt_type = + WLAN_NUD_STATS_ARP_PKT_TYPE; + qdf_mem_zero(&adapter->hdd_stats. + hdd_arp_stats, + sizeof(adapter->hdd_stats. + hdd_arp_stats)); + adapter->track_arp_ip = 0; + } + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + /* DNStracking isn't supported in FW. */ + arp_stats_params->pkt_type_bitmap &= + ~CONNECTIVITY_CHECK_SET_DNS; + qdf_mem_zero(&adapter->hdd_stats. + hdd_dns_stats, + sizeof(adapter->hdd_stats. + hdd_dns_stats)); + qdf_mem_zero(adapter->dns_payload, + adapter->track_dns_domain_len); + adapter->track_dns_domain_len = 0; + } + + if (pkt_bitmap & + CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE) { + qdf_mem_zero(&adapter->hdd_stats. + hdd_tcp_stats, + sizeof(adapter->hdd_stats. + hdd_tcp_stats)); + adapter->track_src_port = 0; + adapter->track_dest_port = 0; + } + + if (pkt_bitmap & + CONNECTIVITY_CHECK_SET_ICMPV4) { + qdf_mem_zero(&adapter->hdd_stats. + hdd_icmpv4_stats, + sizeof(adapter->hdd_stats. + hdd_icmpv4_stats)); + adapter->track_dest_ipv4 = 0; + } + } + } else { + hdd_err("stats list empty"); + err = -EINVAL; + goto end; + } + } + +end: + return err; +} + +void hdd_update_cca_info_cb(hdd_handle_t hdd_handle, uint32_t congestion, + uint32_t vdev_id) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + int status; + struct hdd_adapter *adapter = NULL; + struct hdd_station_ctx *hdd_sta_ctx; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (adapter == NULL) { + hdd_err("vdev_id %d does not exist with host", vdev_id); + return; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_sta_ctx->conn_info.cca = congestion; + hdd_info("congestion:%d", congestion); +} + +static 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] = {.type = NLA_NESTED }, + [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 controle 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_trace_level(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 nlattr *tb[STATS_SET_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); + struct set_arp_stats_params arp_stats_params = {0}; + int err = 0; + mac_handle_t mac_handle; + + 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 = wlan_cfg80211_nla_parse(tb, STATS_SET_MAX, data, data_len, + qca_wlan_vendor_set_nud_stats); + if (err) { + hdd_err("STATS_SET_START ATTR"); + return err; + } + + if (adapter->session_id == HDD_SESSION_ID_INVALID) { + hdd_err("Invalid session id"); + return -EINVAL; + } + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("STATS supported in only STA mode!"); + return -EINVAL; + } + + if (tb[STATS_SET_START]) { + /* tracking is enabled for stats other than arp. */ + if (tb[STATS_SET_DATA_PKT_INFO]) { + err = hdd_set_clear_connectivity_check_stats_info( + adapter, + &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]) { + hdd_err("STATS_SET_START CMD"); + return -EINVAL; + } + + arp_stats_params.pkt_type_bitmap = + CONNECTIVITY_CHECK_SET_ARP; + adapter->pkt_type_bitmap |= + arp_stats_params.pkt_type_bitmap; + arp_stats_params.flag = true; + arp_stats_params.ip_addr = + nla_get_u32(tb[STATS_GW_IPV4]); + adapter->track_arp_ip = 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 = hdd_set_clear_connectivity_check_stats_info( + adapter, + &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; + adapter->pkt_type_bitmap &= + (~arp_stats_params.pkt_type_bitmap); + arp_stats_params.flag = false; + qdf_mem_zero(&adapter->hdd_stats.hdd_arp_stats, + sizeof(adapter->hdd_stats.hdd_arp_stats)); + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + } + } + + hdd_debug("STATS_SET_START Received flag %d!", arp_stats_params.flag); + + arp_stats_params.vdev_id = adapter->session_id; + + mac_handle = hdd_ctx->mac_handle; + if (QDF_STATUS_SUCCESS != + sme_set_nud_debug_stats(mac_handle, &arp_stats_params)) { + hdd_err("STATS_SET_START CMD Failed!"); + return -EINVAL; + } + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_nud_stats(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 }, +}; + +/** + * hdd_populate_dns_stats_info() - send dns stats info to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ +static int hdd_populate_dns_stats_info(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + uint8_t *dns_query; + + dns_query = qdf_mem_malloc(adapter->track_dns_domain_len + 1); + if (!dns_query) { + hdd_err("mem alloc fail"); + return -EINVAL; + } + + qdf_mem_copy(dns_query, adapter->dns_payload, + adapter->track_dns_domain_len); + + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_DNS) || + nla_put(skb, CHECK_STATS_PKT_DNS_DOMAIN_NAME, + adapter->track_dns_domain_len, + hdd_dns_unmake_name_query(dns_query)) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_dns_stats.tx_dns_req_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_dns_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_dns_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_dns_stats.tx_ack_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_dns_stats.rx_dns_rsp_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_dns_stats.rx_delivered) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_dns_stats.rx_host_drop)) { + hdd_err("nla put fail"); + qdf_mem_free(dns_query); + kfree_skb(skb); + return -EINVAL; + } + qdf_mem_free(dns_query); + return 0; +} + +/** + * hdd_populate_tcp_stats_info() - send tcp stats info to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * @pkt_type: tcp pkt type + * + * Return: An error code or 0 on success. + */ +static int hdd_populate_tcp_stats_info(struct hdd_adapter *adapter, + struct sk_buff *skb, + uint8_t pkt_type) +{ + 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, + adapter->track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + adapter->track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_ack_cnt)) { + hdd_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, + adapter->track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + adapter->track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats.rx_fw_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + rx_tcp_syn_ack_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_tcp_stats.rx_delivered) || + nla_put_u16(skb, + CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_tcp_stats.rx_host_drop)) { + hdd_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, + adapter->track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + adapter->track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_ack_cnt)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + break; + default: + break; + } + return 0; +} + +/** + * hdd_populate_icmpv4_stats_info() - send icmpv4 stats info to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ +static int hdd_populate_icmpv4_stats_info(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_ICMPV4) || + nla_put_u32(skb, CHECK_STATS_PKT_DEST_IPV4, + adapter->track_dest_ipv4) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_icmpv4_stats.tx_icmpv4_req_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_icmpv4_stats.tx_ack_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.rx_fw_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_icmpv4_stats.rx_icmpv4_rsp_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_icmpv4_stats.rx_delivered) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_icmpv4_stats.rx_host_drop)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + return 0; +} + +/** + * hdd_populate_connectivity_check_stats_info() - send connectivity stats info + * to network stack + * @adapter: pointer to adapter context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ + +static int hdd_populate_connectivity_check_stats_info( + struct hdd_adapter *adapter, struct sk_buff *skb) +{ + struct nlattr *connect_stats, *connect_info; + uint32_t count = 0; + + connect_stats = nla_nest_start(skb, DATA_PKT_STATS); + if (connect_stats == NULL) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + if (adapter->pkt_type_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + + if (hdd_populate_dns_stats_info(adapter, skb)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + if (adapter->pkt_type_bitmap & CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE) { + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (hdd_populate_tcp_stats_info(adapter, 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 == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (hdd_populate_tcp_stats_info(adapter, 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 == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (hdd_populate_tcp_stats_info(adapter, skb, + CONNECTIVITY_CHECK_SET_TCP_ACK)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + if (adapter->pkt_type_bitmap & CONNECTIVITY_CHECK_SET_ICMPV4) { + connect_info = nla_nest_start(skb, count); + if (connect_info == NULL) { + hdd_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + + if (hdd_populate_icmpv4_stats_info(adapter, skb)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + nla_nest_end(skb, connect_stats); + return 0; + +put_attr_fail: + hdd_err("QCA_WLAN_VENDOR_ATTR put fail. count %u", count); + return -EINVAL; +} + + +/** + * __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 get_arp_stats_params arp_stats_params; + mac_handle_t mac_handle; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t pkt_type_bitmap; + struct sk_buff *skb; + struct osif_request *request = NULL; + static const struct osif_request_params params = { + .priv_size = 0, + .timeout_ms = WLAN_WAIT_TIME_NUD_STATS, + }; + void *cookie = NULL; + + 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; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + arp_stats_params.vdev_id = adapter->session_id; + + pkt_type_bitmap = adapter->pkt_type_bitmap; + + /* send NUD failure event only when ARP tracking is enabled. */ + if (hdd_ctx->config->enable_data_stall_det && + (pkt_type_bitmap & CONNECTIVITY_CHECK_SET_ARP)) + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_FRAMEWORK, + DATA_STALL_LOG_NUD_FAILURE, + 0xFF, 0XFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + + mac_handle = hdd_ctx->mac_handle; + if (sme_set_nud_debug_stats_cb(mac_handle, hdd_get_nud_stats_cb, + cookie) != QDF_STATUS_SUCCESS) { + hdd_err("Setting NUD debug stats callback failure"); + err = -EINVAL; + goto exit; + } + + if (QDF_STATUS_SUCCESS != + sme_get_nud_debug_stats(mac_handle, &arp_stats_params)) { + hdd_err("STATS_SET_START CMD Failed!"); + err = -EINVAL; + goto exit; + } + + err = osif_request_wait_for_response(request); + if (err) { + hdd_err("SME timedout while retrieving NUD stats"); + err = -ETIMEDOUT; + goto exit; + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + WLAN_NUD_STATS_LEN); + if (!skb) { + hdd_err("%s: cfg80211_vendor_cmd_alloc_reply_skb failed", + __func__); + err = -ENOMEM; + goto exit; + } + + if (nla_put_u16(skb, COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_arp_stats.tx_arp_req_count) || + nla_put_u16(skb, COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.tx_host_fw_sent) || + nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.tx_host_fw_sent) || + nla_put_u16(skb, COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_arp_stats.tx_ack_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.rx_fw_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_arp_stats.rx_arp_rsp_count) || + nla_put_u16(skb, RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_arp_stats.rx_delivered) || + nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_arp_stats. + rx_host_drop_reorder)) { + hdd_err("nla put fail"); + kfree_skb(skb); + err = -EINVAL; + goto exit; + } + if (adapter->con_status) + nla_put_flag(skb, AP_LINK_ACTIVE); + if (adapter->dad) + nla_put_flag(skb, AP_LINK_DAD); + + /* ARP tracking is done above. */ + pkt_type_bitmap &= ~CONNECTIVITY_CHECK_SET_ARP; + + if (pkt_type_bitmap) { + if (hdd_populate_connectivity_check_stats_info(adapter, skb)) { + err = -EINVAL; + goto exit; + } + } + + cfg80211_vendor_cmd_reply(skb); +exit: + osif_request_put(request); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_nud_stats(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 + return; + + ucfg_scan_set_bt_activity(hdd_ctx->psoc, hdd_ctx->bt_a2dp_active); + hdd_debug("a2dp_active: %d vo_active: %d", hdd_ctx->bt_a2dp_active, + hdd_ctx->bt_vo_active); +} + + +/** + * 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 inline 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; +} + +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); +} + +/** + * hdd_post_get_chain_rssi_rsp - send rsp to user space + * @hdd_ctx: pointer to hdd context + * @result: chain rssi result + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_post_get_chain_rssi_rsp(struct hdd_context *hdd_ctx, + struct chain_rssi_result *result) +{ + struct sk_buff *skb; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + (sizeof(result->chain_rssi) + NLA_HDRLEN) + + (sizeof(result->chain_evm) + NLA_HDRLEN) + + (sizeof(result->ant_id) + NLA_HDRLEN) + + NLMSG_HDRLEN); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI, + sizeof(result->chain_rssi), + result->chain_rssi)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_CHAIN_EVM, + sizeof(result->chain_evm), + result->chain_evm)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ANTENNA_INFO, + sizeof(result->ant_id), + result->ant_id)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * __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); + mac_handle_t mac_handle; + struct get_chain_rssi_req_params req_msg; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + QDF_STATUS status; + int retval; + void *cookie; + struct osif_request *request; + struct chain_rssi_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + hdd_enter(); + + 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, NULL)) { + 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; + } + memcpy(&req_msg.peer_macaddr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + req_msg.session_id = adapter->session_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 (QDF_STATUS_SUCCESS != status) { + 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_get_chain_rssi_rsp(hdd_ctx, + &priv->chain_rssi); + if (retval) + hdd_err("Failed to post chain rssi"); + } + } + osif_request_put(request); + + hdd_exit(); + return retval; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_chain_rssi(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + 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(); + + 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 >= HDD_MAX_AC) { + hdd_err("tos value %d exceeded Max value %d", + tos, HDD_MAX_AC); + 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; +} + +/** + * 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) + +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_limit_offchan_param(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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"); + kfree_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"); + kfree_skb(reply_skb); + return -EINVAL; + } + + nla_nest_end(reply_skb, attr); + + return 0; +} + +/** + * __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 *reply_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 = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + mac_handle_t mac_handle; + + 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] = { + .type = NLA_NESTED}, + }; + 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}, + }; + + 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 (adapter->device_mode != QDF_STA_MODE || + hdd_sta_ctx->conn_info.connState != eConnectionState_Associated) { + 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.connState); + 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; + ret = sme_get_bss_transition_status(mac_handle, transition_reason, + &hdd_sta_ctx->conn_info.bssId, + candidate_info, + nof_candidates, + is_bt_in_progress); + if (ret) + return -EINVAL; + + /* Prepare the reply and send it to userspace */ + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + ((QDF_MAC_ADDR_SIZE + sizeof(uint32_t)) * + nof_candidates) + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("reply buffer alloc failed"); + return -ENOMEM; + } + + attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO); + if (!attr) { + hdd_err("nla_nest_start failed"); + kfree_skb(reply_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(reply_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(reply_skb, + &candidate_info[i], j)) + return -EINVAL; + j++; + } + } + nla_nest_end(reply_skb, attr); + + hdd_exit(); + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_fetch_bss_transition_status(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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 hdd_adapter *hdd_adapter; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + goto error; + + hdd_adapter = hdd_get_adapter_by_vdev(hdd_ctx, info->vdev_id); + if (!hdd_adapter) + 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, + hdd_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"); + kfree_skb(skb); + 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"); + kfree_skb(skb); + 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; + + hdd_enter(); + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + 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 = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + (sizeof(uint32_t) * 4) * + MAX_NUMBER_OF_CONC_CONNECTIONS + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO_INDEX, + GFP_KERNEL); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_MAC_INFO); + if (!attr) { + hdd_err("nla_nest_start failed"); + kfree_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)) + return -EINVAL; + } + + nla_nest_end(skb, attr); + + cfg80211_vendor_event(skb, GFP_KERNEL); + hdd_exit(); + + return err; +} + +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 + }, + +#ifdef WLAN_FEATURE_NAN + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_nan_request + }, +#endif + +#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 + }, +#endif +#ifdef FEATURE_WLAN_EXTSCAN + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + { + .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 + }, + + { + .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 + }, + + { + .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 + }, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ +#ifdef FEATURE_WLAN_TDLS + { + .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 + }, + { + .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 + }, + { + .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 + }, +#endif + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + + { + .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 + }, +#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 + }, +#endif +#ifdef FEATURE_WLAN_EXTSCAN + { + .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 + }, + { + .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 + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + { + .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 + }, +#ifndef WLAN_UMAC_CONVERGENCE + { + .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 + }, +#endif + { + .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 + }, + + { + .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 + }, + { + .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 + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data + }, + { + .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 + }, + { + .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 + }, +#ifdef WLAN_FEATURE_TSF + { + .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 + }, +#endif +#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 + }, +#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 + }, +#endif + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 abort scan */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_vendor_abort_scan + }, + + /* OCB 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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, +#ifdef FEATURE_LFR_SUBNET_DETECTION + { + .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 + }, +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + { + .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 + }, + { + .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 + }, +#ifdef FEATURE_WLAN_APF + { + .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 + }, +#endif /* FEATURE_WLAN_APF */ + { + .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 + }, + { + .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 + }, +#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 + }, +#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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, +#ifdef WLAN_FEATURE_NAN_DATAPATH + { + .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 + }, +#endif + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, +#ifdef WLAN_FEATURE_DISA + { + .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 + }, +#endif +#ifdef FEATURE_WLAN_TDLS + { + .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 + }, +#endif + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + { + .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 + }, + FEATURE_SPECTRAL_SCAN_VENDOR_COMMANDS +#ifdef WLAN_UMAC_CONVERGENCE + COMMON_VENDOR_COMMANDS +#endif + 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 + }, + { + .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 + }, + + FEATURE_COEX_CONFIG_COMMANDS + FEATURE_MPTA_HELPER_COMMANDS + FEATURE_HW_CAPABILITY_COMMANDS +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) +static inline void +hdd_wiphy_set_max_sched_scans(struct wiphy *wiphy, uint8_t max_scans) +{ + if (max_scans == 0) + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + else + wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +} +#else +static inline void +hdd_wiphy_set_max_sched_scans(struct wiphy *wiphy, uint8_t max_scans) +{ + wiphy->max_sched_scan_reqs = max_scans; +} +#endif /* KERNEL_VERSION(4, 12, 0) */ + +/** + * wlan_hdd_cfg80211_add_connected_pno_support() - Set connected PNO support + * @wiphy: Pointer to wireless phy + * + * This function is used to set connected PNO support to kernel + * + * Return: None + */ +#if defined(CFG80211_REPORT_BETTER_BSS_IN_SCHED_SCAN) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) +static void wlan_hdd_cfg80211_add_connected_pno_support(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_SCHED_SCAN_RELATIVE_RSSI); +} +#else +static void wlan_hdd_cfg80211_add_connected_pno_support(struct wiphy *wiphy) +{ +} +#endif + +#if ((LINUX_VERSION_CODE > KERNEL_VERSION(4, 4, 0)) || \ + defined(CFG80211_MULTI_SCAN_PLAN_BACKPORT)) && \ + defined(FEATURE_WLAN_SCAN_PNO) +/** + * hdd_config_sched_scan_plans_to_wiphy() - configure sched scan plans to wiphy + * @wiphy: pointer to wiphy + * @config: pointer to config + * + * Return: None + */ +static void hdd_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy, + struct hdd_config *config) +{ + if (config->configPNOScanSupport) { + hdd_wiphy_set_max_sched_scans(wiphy, 1); + wiphy->max_sched_scan_ssids = SCAN_PNO_MAX_SUPP_NETWORKS; + wiphy->max_match_sets = SCAN_PNO_MAX_SUPP_NETWORKS; + wiphy->max_sched_scan_ie_len = SIR_MAC_MAX_IE_LENGTH; + wiphy->max_sched_scan_plans = SCAN_PNO_MAX_PLAN_REQUEST; + if (config->max_sched_scan_plan_interval) + wiphy->max_sched_scan_plan_interval = + config->max_sched_scan_plan_interval; + if (config->max_sched_scan_plan_iterations) + wiphy->max_sched_scan_plan_iterations = + config->max_sched_scan_plan_iterations; + } +} +#else +static void hdd_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy, + struct hdd_config *config) +{ +} +#endif + + +/** + * hdd_cfg80211_wiphy_alloc() - Allocate wiphy context + * @priv_size: Size of the hdd context. + * + * Allocate wiphy context and hdd context. + * + * Return: hdd context on success and NULL on failure. + */ +struct hdd_context *hdd_cfg80211_wiphy_alloc(int priv_size) +{ + struct wiphy *wiphy; + struct hdd_context *hdd_ctx; + + hdd_enter(); + + wiphy = wiphy_new(&wlan_hdd_cfg80211_ops, priv_size); + + if (!wiphy) { + hdd_err("wiphy init failed!"); + return NULL; + } + + hdd_ctx = wiphy_priv(wiphy); + + hdd_ctx->wiphy = wiphy; + + return hdd_ctx; +} + +/* + * FUNCTION: wlan_hdd_cfg80211_update_band + * This function is called from the supplicant through a + * private ioctl to change the band value + */ +int wlan_hdd_cfg80211_update_band(struct hdd_context *hdd_ctx, struct wiphy *wiphy, + enum band_info eBand) +{ + int i, j; + enum channel_state channelEnabledState; + + hdd_enter(); + + for (i = 0; i < HDD_NUM_NL80211_BANDS; i++) { + + if (NULL == wiphy->bands[i]) + continue; + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + channelEnabledState = wlan_reg_get_channel_state( + hdd_ctx->pdev, + band->channels[j].hw_value); + + if (HDD_NL80211_BAND_2GHZ == i && + BAND_5G == eBand) { + /* 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 == + channelEnabledState) + 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 == eBand) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + + if (CHANNEL_STATE_DISABLE != channelEnabledState) + 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) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = wiphy_priv(wiphy); + + if (false == hdd_ctx->config->enable_mac_spoofing) { + hdd_warn("MAC address spoofing is not enabled"); + } else { + 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_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) +/** + * wlan_hdd_cfg80211_set_wiphy_sae_feature() - Indicates support of SAE feature + * @wiphy: Pointer to wiphy + * @config: pointer to config + * + * 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_config *config) +{ + if (config->is_sae_enabled) + wiphy->features |= NL80211_FEATURE_SAE; +} +#else +static void wlan_hdd_cfg80211_set_wiphy_sae_feature(struct wiphy *wiphy, + struct hdd_config *config) +{ +} +#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_srd_chan_info() - Populate SRD chan info in hdd context + * @hdd_ctx: pointer to hdd context + * @index: SRD channel beginning index in chan_info of @hdd_ctx + * + * Return: Number of SRD channels populated + */ +static uint32_t +wlan_hdd_populate_srd_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_etsi13_srd_ch); + *ch_len = sizeof(hdd_etsi13_srd_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_etsi13_srd_ch[0], ch_arr_len); +} + +/** + * wlan_hdd_populate_srd_chan_info() - Populate SRD chan info in hdd context + * @hdd_ctx: pointer to hdd context + * @index: SRD channel beginning index in chan_info of @hdd_ctx + * + * Return: Number of SRD channels populated + */ +static uint32_t +wlan_hdd_populate_srd_chan_info(struct hdd_context *hdd_ctx, uint32_t index) +{ + uint32_t num_srd_ch, i; + struct scan_chan_info *chan_info; + + num_srd_ch = QDF_ARRAY_SIZE(hdd_etsi13_srd_ch); + chan_info = hdd_ctx->chan_info; + + for (i = 0; i < num_srd_ch; i++) + chan_info[index + i].freq = hdd_etsi13_srd_ch[i].center_freq; + + return num_srd_ch; +} + +#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 *pCfg) +{ + int i, j; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int len_5g_ch = 0, num_ch, ch_arr_size; + int num_dsrc_ch, len_dsrc_ch, num_srd_ch, len_srd_ch; + 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; + + 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; + +#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 + + if (pCfg->isFastTransitionEnabled || pCfg->isFastRoamIniFeatureEnabled +#ifdef FEATURE_WLAN_ESE + || pCfg->isEseIniFeatureEnabled +#endif + ) { + wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + } +#ifdef FEATURE_WLAN_TDLS + wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS + | WIPHY_FLAG_TDLS_EXTERNAL_SETUP; +#endif + + wiphy->features |= NL80211_FEATURE_HT_IBSS; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); +#endif + if (pCfg->is_fils_enabled) + wlan_hdd_cfg80211_set_wiphy_fils_feature(wiphy); + + wlan_hdd_cfg80211_set_wiphy_scan_flags(wiphy); + + if (pCfg->oce_sta_enabled) + wlan_hdd_cfg80211_set_wiphy_oce_scan_flags(wiphy); + + wlan_hdd_cfg80211_set_wiphy_sae_feature(wiphy, pCfg); + + hdd_config_sched_scan_plans_to_wiphy(wiphy, pCfg); + wlan_hdd_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_ADHOC) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_AP) + | BIT(NL80211_IFTYPE_MONITOR); + + if (pCfg->advertiseConcurrentOperation) { + if (pCfg->enableMCC) { + int i; + + for (i = 0; + i < ARRAY_SIZE(wlan_hdd_iface_combination); + i++) { + if (!pCfg->allowMCCGODiffBI) + wlan_hdd_iface_combination[i]. + beacon_int_infra_match = true; + } + } + wiphy->n_iface_combinations = + ARRAY_SIZE(wlan_hdd_iface_combination); + wiphy->iface_combinations = wlan_hdd_iface_combination; + } + + /* Before registering we need to update the ht capabilitied based + * on ini values + */ + if (!pCfg->ShortGI20MhzEnable) { + wlan_hdd_band_2_4_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + wlan_hdd_band_5_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + } + + if (!pCfg->ShortGI40MhzEnable) + wlan_hdd_band_5_ghz.ht_cap.cap &= + ~IEEE80211_HT_CAP_SGI_40; + + if (!pCfg->nChannelBondingMode5GHz) + wlan_hdd_band_5_ghz.ht_cap.cap &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + /* + * 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. + */ + wiphy->bands[HDD_NL80211_BAND_2GHZ] = &wlan_hdd_band_2_4_ghz; + wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels = + qdf_mem_malloc(sizeof(hdd_channels_2_4_ghz)); + if (wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels == NULL) { + hdd_err("Not enough memory to allocate channels"); + return -ENOMEM; + } + qdf_mem_copy(wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels, + &hdd_channels_2_4_ghz[0], + sizeof(hdd_channels_2_4_ghz)); + if ((hdd_is_5g_supported(hdd_ctx)) && + ((eHDD_DOT11_MODE_11b != pCfg->dot11Mode) && + (eHDD_DOT11_MODE_11g != pCfg->dot11Mode) && + (eHDD_DOT11_MODE_11b_ONLY != pCfg->dot11Mode) && + (eHDD_DOT11_MODE_11g_ONLY != pCfg->dot11Mode))) { + wiphy->bands[HDD_NL80211_BAND_5GHZ] = &wlan_hdd_band_5_ghz; + wlan_hdd_get_num_dsrc_ch_and_len(pCfg, &num_dsrc_ch, + &len_dsrc_ch); + wlan_hdd_get_num_srd_ch_and_len(pCfg, &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); + ch_arr_size = len_5g_ch + len_dsrc_ch + len_srd_ch; + + wiphy->bands[HDD_NL80211_BAND_5GHZ]->channels = + qdf_mem_malloc(ch_arr_size); + if (!wiphy->bands[HDD_NL80211_BAND_5GHZ]->channels) + goto mem_fail; + 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); + } + + for (i = 0; i < HDD_NUM_NL80211_BANDS; i++) { + + if (NULL == wiphy->bands[i]) + continue; + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + if (HDD_NL80211_BAND_2GHZ == i && + BAND_5G == pCfg->nBandCapability) { + /* 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 && + BAND_2G == pCfg->nBandCapability) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + } + } + /*Initialise the supported cipher suite details */ + if (pCfg->gcmp_enabled) { + cipher_suites = qdf_mem_malloc(sizeof(hdd_cipher_suites) + + sizeof(hdd_gcmp_cipher_suits)); + if (cipher_suites == NULL) { + hdd_err("Not enough memory for cipher suites"); + return -ENOMEM; + } + 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 == NULL) { + hdd_err("Not enough memory for cipher suites"); + return -ENOMEM; + } + 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; + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { + 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); + } + + if (pCfg->enableDFSMasterCap) + wlan_hdd_cfg80211_set_dfs_offload_feature(wiphy); + + wiphy->max_ap_assoc_sta = pCfg->maxNumberOfPeers; + +#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; + if (pCfg->enable_mac_spoofing) + wlan_hdd_cfg80211_scan_randomization_init(wiphy); + wlan_hdd_cfg80211_action_frame_randomization_init(wiphy); + + hdd_exit(); + return 0; + +mem_fail: + hdd_err("Not enough memory to allocate channels"); + if (wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels != NULL) { + qdf_mem_free(wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels); + wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels = 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; + + for (i = 0; i < HDD_NUM_NL80211_BANDS; i++) { + if (NULL != wiphy->bands[i] && + (NULL != wiphy->bands[i]->channels)) { + qdf_mem_free(wiphy->bands[i]->channels); + wiphy->bands[i]->channels = 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_band_cap() - update capabilities for supported bands + * @hdd_ctx: HDD context + * + * this function will update capabilities for supported bands + * + * Return: void + */ +static void wlan_hdd_update_band_cap(struct hdd_context *hdd_ctx) +{ + uint32_t val32; + uint16_t val16; + tSirMacHTCapabilityInfo *ht_cap_info; + QDF_STATUS status; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + status = sme_cfg_get_int(mac_handle, WNI_CFG_HT_CAP_INFO, &val32); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("could not get HT capability info"); + val32 = 0; + } + val16 = (uint16_t)val32; + ht_cap_info = (tSirMacHTCapabilityInfo *)&val16; + + if (ht_cap_info->txSTBC == true) { + if (NULL != hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]) + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]->ht_cap.cap |= + IEEE80211_HT_CAP_TX_STBC; + if (NULL != hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]) + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]->ht_cap.cap |= + IEEE80211_HT_CAP_TX_STBC; + } + + if (!sme_is_feature_supported_by_fw(DOT11AC)) { + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]-> + vht_cap.vht_supported = 0; + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]->vht_cap.cap = 0; + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]-> + vht_cap.vht_supported = 0; + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]->vht_cap.cap = 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) +{ + hdd_ctx->wiphy->max_ap_assoc_sta = hdd_ctx->config->maxNumberOfPeers; + + wlan_hdd_update_band_cap(hdd_ctx); +} + +/** + * wlan_hdd_update_11n_mode - update 11n mode in hdd cfg + * @cfg: hdd cfg + * + * this function update 11n mode in hdd cfg + * + * Return: void + */ +void wlan_hdd_update_11n_mode(struct hdd_config *cfg) +{ + 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; + cfg->sap_11ac_override = 0; + cfg->go_11ac_override = 0; + } + } +} + +/* In this function we are registering wiphy. */ +int wlan_hdd_cfg80211_register(struct wiphy *wiphy) +{ + hdd_enter(); + /* Register our wiphy dev with cfg80211 */ + if (0 > wiphy_register(wiphy)) { + hdd_err("wiphy register failed"); + return -EIO; + } + + hdd_exit(); + return 0; +} + +/* + * HDD function to update wiphy capability based on target offload status. + * + * wlan_hdd_cfg80211_init() does initialization of all wiphy related + * capability even before downloading firmware to the target. In discrete + * case, host will get know certain offload capability (say sched_scan + * caps) only after downloading firmware to the target and target boots up. + * This function is used to override setting done in wlan_hdd_cfg80211_init() + * based on target capability. + */ +void wlan_hdd_cfg80211_update_wiphy_caps(struct wiphy *wiphy) +{ +#ifdef FEATURE_WLAN_SCAN_PNO + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_config *pCfg = hdd_ctx->config; + + /* wlan_hdd_cfg80211_init() sets sched_scan caps already in wiphy before + * control comes here. Here just we need to clear it if firmware doesn't + * have PNO support. + */ + if (!pCfg->PnoOffload) { + hdd_wiphy_set_max_sched_scans(wiphy, 0); + wiphy->max_sched_scan_ssids = 0; + wiphy->max_match_sets = 0; + wiphy->max_sched_scan_ie_len = 0; + } +#endif +} + +/* 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; + + hdd_enter(); + if (adapter->device_mode == QDF_FTM_MODE) { + hdd_info("No need to register frames in FTM mode"); + return 0; + } + + /* 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->session_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(); + + /* 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->session_id, type, + (uint8_t *) WNM_NOTIFICATION_FRAME, + WNM_NOTIFICATION_FRAME_SIZE); +} + +#ifdef FEATURE_WLAN_WAPI +static void wlan_hdd_cfg80211_set_key_wapi(struct hdd_adapter *adapter, + uint8_t key_index, + const uint8_t *mac_addr, + const uint8_t *key, + int key_Len) +{ + tCsrRoamSetKey setKey; + bool isConnected = true; + QDF_STATUS status; + uint32_t roamId = INVALID_ROAM_ID; + uint8_t *pKeyPtr = NULL; + mac_handle_t mac_handle; + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; /* Store Key ID */ + setKey.encType = eCSR_ENCRYPT_TYPE_WPI; /* SET WAPI Encryption */ + setKey.keyDirection = eSIR_TX_RX; /* Key Directionn both TX and RX */ + setKey.paeRole = 0; /* the PAE role */ + if (!mac_addr || is_broadcast_ether_addr(mac_addr)) + qdf_set_macaddr_broadcast(&setKey.peerMac); + else + qdf_mem_copy(setKey.peerMac.bytes, mac_addr, QDF_MAC_ADDR_SIZE); + + setKey.keyLength = key_Len; + pKeyPtr = setKey.Key; + memcpy(pKeyPtr, key, key_Len); + + hdd_debug("WAPI KEY LENGTH:0x%04x", key_Len); + + if (isConnected) { + mac_handle = hdd_adapter_get_mac_handle(adapter); + status = sme_roam_set_key(mac_handle, + adapter->session_id, + &setKey, &roamId); + if (status != QDF_STATUS_SUCCESS) + hdd_err("sme_roam_set_key failed status: %d", status); + } +} +#endif /* FEATURE_WLAN_WAPI */ + +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; +} + +/* + * FUNCTION: wlan_hdd_validate_operation_channel + * called by wlan_hdd_cfg80211_start_bss() and + * wlan_hdd_set_channel() + * This function validates whether given channel is part of valid + * channel list. + */ +QDF_STATUS wlan_hdd_validate_operation_channel(struct hdd_adapter *adapter, + int channel) +{ + uint32_t num_ch = 0; + u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + u32 indx = 0; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + uint8_t fValidChannel = false, count = 0; + struct hdd_config *hdd_pConfig_ini = + (WLAN_HDD_GET_CTX(adapter))->config; + + num_ch = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (hdd_pConfig_ini->sapAllowAllChannel) { + /* Validate the channel */ + for (count = CHAN_ENUM_1; count <= CHAN_ENUM_173; count++) { + if (channel == WLAN_REG_CH_NUM(count)) { + fValidChannel = true; + break; + } + } + if (fValidChannel != true) { + hdd_err("Invalid Channel: %d", channel); + return QDF_STATUS_E_FAILURE; + } + } else { + if (0 != sme_cfg_get_str(mac_handle, WNI_CFG_VALID_CHANNEL_LIST, + valid_ch, &num_ch)) { + hdd_err("failed to get valid channel list"); + return QDF_STATUS_E_FAILURE; + } + for (indx = 0; indx < num_ch; indx++) { + if (channel == valid_ch[indx]) + break; + } + + if (indx >= num_ch) { + hdd_err("Invalid Channel: %d", channel); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; + +} + +#ifdef DHCP_SERVER_OFFLOAD +static void wlan_hdd_set_dhcp_server_offload(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tpSirDhcpSrvOffloadInfo pDhcpSrvInfo; + uint8_t numEntries = 0; + uint8_t srv_ip[IPADDR_NUM_ENTRIES]; + uint8_t num; + uint32_t temp; + mac_handle_t mac_handle; + + pDhcpSrvInfo = qdf_mem_malloc(sizeof(*pDhcpSrvInfo)); + if (NULL == pDhcpSrvInfo) { + hdd_err("could not allocate tDhcpSrvOffloadInfo!"); + return; + } + pDhcpSrvInfo->vdev_id = adapter->session_id; + pDhcpSrvInfo->dhcpSrvOffloadEnabled = true; + pDhcpSrvInfo->dhcpClientNum = hdd_ctx->config->dhcpMaxNumClients; + hdd_string_to_u8_array(hdd_ctx->config->dhcpServerIP, + srv_ip, &numEntries, IPADDR_NUM_ENTRIES); + if (numEntries != IPADDR_NUM_ENTRIES) { + hdd_err("Incorrect IP address (%s) assigned for DHCP server!", hdd_ctx->config->dhcpServerIP); + goto end; + } + if ((srv_ip[0] >= 224) && (srv_ip[0] <= 239)) { + hdd_err("Invalid IP address (%s)! It could NOT be multicast IP address!", hdd_ctx->config->dhcpServerIP); + goto end; + } + if (srv_ip[IPADDR_NUM_ENTRIES - 1] >= 100) { + hdd_err("Invalid IP address (%s)! The last field must be less than 100!", hdd_ctx->config->dhcpServerIP); + goto end; + } + for (num = 0; num < numEntries; num++) { + temp = srv_ip[num]; + pDhcpSrvInfo->dhcpSrvIP |= (temp << (8 * num)); + } + mac_handle = hdd_ctx->mac_handle; + if (QDF_STATUS_SUCCESS != + sme_set_dhcp_srv_offload(mac_handle, pDhcpSrvInfo)) { + hdd_err("sme_setDHCPSrvOffload fail!"); + goto end; + } + hdd_debug("enable DHCP Server offload successfully!"); +end: + qdf_mem_free(pDhcpSrvInfo); +} +#endif /* DHCP_SERVER_OFFLOAD */ + +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); + int ret = 0; + QDF_STATUS qdf_ret_status; + mac_handle_t mac_handle; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BSS, + adapter->session_id, params->ap_isolate); + + hdd_debug("Device_mode %s(%d), ap_isolate = %d", + hdd_device_mode_to_string(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) { + adapter->session.ap.disable_intrabss_fwd = + !!params->ap_isolate; + + mac_handle = hdd_ctx->mac_handle; + qdf_ret_status = sme_ap_disable_intra_bss_fwd(mac_handle, + adapter->session_id, + adapter->session. + ap. + disable_intrabss_fwd); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) + ret = -EINVAL; + + ucfg_ipa_set_ap_ibss_fwd(hdd_ctx->pdev, + adapter->session.ap. + disable_intrabss_fwd); + } + + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_change_client_iface_to_new_mode() - to change iface to provided mode + * @ndev: pointer to net device provided by supplicant + * @type: type of the interface, upper layer wanted to change + * + * Upper layer provides the new interface mode that needs to be changed + * for given net device + * + * Return: success or failure in terms of integer value + */ +static int wlan_hdd_change_client_iface_to_new_mode(struct net_device *ndev, + enum nl80211_iftype type) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_config *config = hdd_ctx->config; + struct csr_roam_profile *roam_profile; + struct wireless_dev *wdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + hdd_enter(); + + if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) { + hdd_warn("ACS is in progress, don't change iface!"); + return -EBUSY; + } + + wdev = ndev->ieee80211_ptr; + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + wdev->iftype = type; + /*Check for sub-string p2p to confirm its a p2p interface */ + if (NULL != strnstr(ndev->name, "p2p", 3)) { + adapter->device_mode = + (type == NL80211_IFTYPE_STATION) ? + QDF_P2P_DEVICE_MODE : QDF_P2P_CLIENT_MODE; + } else if (type == NL80211_IFTYPE_ADHOC) { + adapter->device_mode = QDF_IBSS_MODE; + } else { + adapter->device_mode = + (type == NL80211_IFTYPE_STATION) ? + QDF_STA_MODE : QDF_P2P_CLIENT_MODE; + } + memset(&adapter->session, 0, sizeof(adapter->session)); + hdd_set_station_ops(adapter->dev); + + roam_profile = hdd_roam_profile(adapter); + roam_profile->pAddIEScan = adapter->scan_info.scan_add_ie.addIEdata; + roam_profile->nAddIEScanLength = + adapter->scan_info.scan_add_ie.length; + if (type == NL80211_IFTYPE_ADHOC) { + status = hdd_start_station_adapter(adapter); + roam_profile->BSSType = eCSR_BSS_TYPE_START_IBSS; + roam_profile->phyMode = + hdd_cfg_xlate_to_csr_phy_mode(config->dot11Mode); + } + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_change_bss(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 wireless_dev *wdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + struct csr_roam_profile *roam_profile = NULL; + eCsrRoamBssType LastBSSType; + struct hdd_config *pConfig = NULL; + int status; + bool iff_up = (ndev->flags & IFF_UP); + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (cds_is_fw_down()) { + hdd_err("Ignore if FW is already down"); + return -EINVAL; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_IFACE, + adapter->session_id, type); + + hdd_debug("Device_mode = %d, IFTYPE = 0x%x", + adapter->device_mode, type); + + status = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (status) { + hdd_err("Failed to start modules"); + return -EINVAL; + } + + pConfig = hdd_ctx->config; + wdev = ndev->ieee80211_ptr; + + /* Reset the current device mode bit mask */ + policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, + adapter->device_mode); + + 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_IBSS_MODE)) { + + roam_profile = hdd_roam_profile(adapter); + LastBSSType = roam_profile->BSSType; + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_ADHOC: + if (type == NL80211_IFTYPE_ADHOC) { + hdd_deregister_tx_flow_control(adapter); + hdd_debug("Setting interface Type to ADHOC"); + } + status = wlan_hdd_change_client_iface_to_new_mode(ndev, + type); + if (status) { + hdd_err("Failed to change iface to new mode:%d status %d", + type, status); + goto err; + } + if (iff_up) { + if (hdd_start_adapter(adapter)) { + hdd_err("Failed to start adapter: %d", + adapter->device_mode); + status = -EINVAL; + goto err; + } + } + goto done; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + { + hdd_debug("Setting interface Type to %s", + (type == + NL80211_IFTYPE_AP) ? "SoftAP" : + "P2pGo"); + + /* Cancel any remain on channel for GO mode */ + if (NL80211_IFTYPE_P2P_GO == type) { + wlan_hdd_cancel_existing_remain_on_channel + (adapter); + } + + hdd_stop_adapter(hdd_ctx, adapter); + /* De-init the adapter */ + hdd_deinit_adapter(hdd_ctx, adapter, true); + memset(&adapter->session, 0, + sizeof(adapter->session)); + adapter->device_mode = + (type == + NL80211_IFTYPE_AP) ? QDF_SAP_MODE : + QDF_P2P_GO_MODE; + + /* + * Fw will take care incase of concurrency + */ + + if ((QDF_SAP_MODE == adapter->device_mode) + && (pConfig->apRandomBssidEnabled)) { + /* To meet Android requirements create + * a randomized MAC address of the + * form 02:1A:11:Fx:xx:xx + */ + get_random_bytes(&ndev->dev_addr[3], 3); + ndev->dev_addr[0] = 0x02; + ndev->dev_addr[1] = 0x1A; + ndev->dev_addr[2] = 0x11; + ndev->dev_addr[3] |= 0xF0; + memcpy(adapter->mac_addr. + bytes, ndev->dev_addr, + QDF_MAC_ADDR_SIZE); + pr_info("wlan: Generated HotSpot BSSID " + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(ndev->dev_addr)); + } + + hdd_set_ap_ops(adapter->dev); + + if (iff_up) { + if (hdd_start_adapter(adapter)) { + hdd_err("Failed to start adapter: %d", + adapter->device_mode); + status = -EINVAL; + goto err; + } + } + /* Interface type changed update in wiphy structure */ + if (wdev) { + wdev->iftype = type; + } else { + hdd_err("Wireless dev is NULL"); + status = -EINVAL; + goto err; + } + goto done; + } + + default: + hdd_err("Unsupported interface type: %d", type); + status = -EOPNOTSUPP; + goto err; + } + } else if ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) { + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_ADHOC: + status = wlan_hdd_change_client_iface_to_new_mode(ndev, + type); + if (status) { + hdd_err("Failed change iface to new mode:%d status %d", + type, status); + goto err; + } + if (iff_up) { + if (hdd_start_adapter(adapter)) { + hdd_err("Failed to start adapter: %d", + adapter->device_mode); + status = -EINVAL; + goto err; + } + } + goto done; + + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + wdev->iftype = type; + adapter->device_mode = (type == NL80211_IFTYPE_AP) ? + QDF_SAP_MODE : QDF_P2P_GO_MODE; + goto done; + + default: + hdd_err("Unsupported interface type: %d", type); + status = -EOPNOTSUPP; + goto err; + } + } else { + hdd_err("Unsupported device mode: %d", + adapter->device_mode); + status = -EOPNOTSUPP; + goto err; + } +done: + hdd_lpass_notify_mode_change(adapter); +err: + /* Set bitmask based on updated value */ + policy_mgr_set_concurrency_mode(hdd_ctx->psoc, + adapter->device_mode); + + hdd_exit(); + return status; +} + +#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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = + __wlan_hdd_cfg80211_change_iface(wiphy, ndev, type, flags, params); + cds_ssr_unprotect(__func__); + + return ret; +} +#else +static int wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + struct vif_params *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_change_iface(wiphy, ndev, type, + ¶ms->flags, params); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /* KERNEL_VERSION(4, 12, 0) */ + +/** + * __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 STAMacAddress; + 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->session_id, params->listen_interval); + + if (wlan_hdd_validate_session_id(adapter->session_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); + + qdf_mem_copy(STAMacAddress.bytes, mac, QDF_MAC_ADDR_SIZE); + + 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); + /* + * For Encrypted SAP session, this will be done as + * part of eSAP_STA_SET_KEY_EVENT + */ + 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, + &STAMacAddress, + OL_TXRX_PEER_STATE_AUTH); + + if (status != QDF_STATUS_SUCCESS) { + hdd_debug("Not able to change TL state to AUTHENTICATED"); + 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(adapter); + if (!vdev) + return -EINVAL; + ret = wlan_cfg80211_tdls_update_peer(vdev, + mac, params); + hdd_objmgr_put_vdev(vdev); +#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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_change_station(wiphy, dev, mac, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_add_key + * This function is used to initialize the key information + */ +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) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + tCsrRoamSetKey setKey; + int status; + uint32_t roamId = INVALID_ROAM_ID; + QDF_STATUS qdf_ret_status; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_KEY, + adapter->session_id, params->key_len); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + if (CSR_MAX_NUM_KEY <= key_index) { + hdd_err("Invalid key index %d", key_index); + + return -EINVAL; + } + + if (CSR_MAX_KEY_LEN < params->key_len) { + hdd_err("Invalid key length %d", params->key_len); + + return -EINVAL; + } + + if (CSR_MAX_RSC_LEN < params->seq_len) { + hdd_err("Invalid seq length %d", params->seq_len); + + return -EINVAL; + } + + hdd_debug("key index %d, key length %d, seq length %d", + key_index, params->key_len, params->seq_len); + + /*extract key idx, key len and key */ + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; + setKey.keyLength = params->key_len; + qdf_mem_copy(&setKey.Key[0], params->key, params->key_len); + qdf_mem_copy(&setKey.keyRsc[0], params->seq, params->seq_len); + + mac_handle = hdd_ctx->mac_handle; + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + setKey.encType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + break; + + case WLAN_CIPHER_SUITE_WEP104: + setKey.encType = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + break; + + case WLAN_CIPHER_SUITE_TKIP: + { + u8 *pKey = &setKey.Key[0]; + + setKey.encType = eCSR_ENCRYPT_TYPE_TKIP; + qdf_mem_zero(pKey, CSR_MAX_KEY_LEN); + + /* Supplicant sends the 32bytes key in this order + * + * |--------------|----------|----------| + * | Tk1 |TX-MIC | RX Mic | + * |--------------|----------|----------| + * <---16bytes---><--8bytes--><--8bytes--> + * + * Sme expects the 32 bytes key to be in the below order + * + * |--------------|----------|----------| + * | Tk1 |RX-MIC | TX Mic | + * |--------------|----------|----------| + * <---16bytes---><--8bytes--><--8bytes--> + */ + /* Copy the Temporal Key 1 (TK1) */ + qdf_mem_copy(pKey, params->key, 16); + + /*Copy the rx mic first */ + qdf_mem_copy(&pKey[16], ¶ms->key[24], 8); + + /*Copy the tx mic */ + qdf_mem_copy(&pKey[24], ¶ms->key[16], 8); + + break; + } + + case WLAN_CIPHER_SUITE_CCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES; + break; + +#ifdef FEATURE_WLAN_WAPI + case WLAN_CIPHER_SUITE_SMS4: + { + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + wlan_hdd_cfg80211_set_key_wapi(adapter, key_index, + mac_addr, params->key, + params->key_len); + return 0; + } +#endif + +#ifdef FEATURE_WLAN_ESE + case WLAN_CIPHER_SUITE_KRK: + setKey.encType = eCSR_ENCRYPT_TYPE_KRK; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WLAN_CIPHER_SUITE_BTK: + setKey.encType = eCSR_ENCRYPT_TYPE_BTK; + break; +#endif +#endif + +#ifdef WLAN_FEATURE_11W + case WLAN_CIPHER_SUITE_AES_CMAC: + setKey.encType = eCSR_ENCRYPT_TYPE_AES_CMAC; + break; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + setKey.encType = eCSR_ENCRYPT_TYPE_AES_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + setKey.encType = eCSR_ENCRYPT_TYPE_AES_GMAC_256; + break; +#endif +#endif + case WLAN_CIPHER_SUITE_GCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES_GCMP; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + setKey.encType = eCSR_ENCRYPT_TYPE_AES_GCMP_256; + break; + + default: + hdd_err("Unsupported cipher type: %u", params->cipher); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return -EOPNOTSUPP; + } + + hdd_debug("encryption type %d", setKey.encType); + + if (!pairwise) { + /* set group key */ + hdd_debug("setting Broadcast key"); + setKey.keyDirection = eSIR_RX_ONLY; + qdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + /* set pairwise key */ + hdd_debug("setting pairwise key"); + setKey.keyDirection = eSIR_TX_RX; + qdf_mem_copy(setKey.peerMac.bytes, mac_addr, QDF_MAC_ADDR_SIZE); + } + if ((QDF_IBSS_MODE == adapter->device_mode) && !pairwise) { + /* if a key is already installed, block all subsequent ones */ + if (adapter->session.station.ibss_enc_key_installed) { + hdd_debug("IBSS key installed already"); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return 0; + } + + setKey.keyDirection = eSIR_TX_RX; + /*Set the group key */ + status = sme_roam_set_key(mac_handle, + adapter->session_id, &setKey, &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed, status: %d", status); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return -EINVAL; + } + /* Save the keys here and call sme_roam_set_key for setting + * the PTK after peer joins the IBSS network + */ + qdf_mem_copy(&adapter->session.station.ibss_enc_key, + &setKey, sizeof(tCsrRoamSetKey)); + + adapter->session.station.ibss_enc_key_installed = 1; + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return status; + } + if ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) { + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + struct hdd_ap_ctx *ap_ctx = + WLAN_HDD_GET_AP_CTX_PTR(adapter); + + if (hostapd_state->bss_state == BSS_START) { + status = wlansap_set_key_sta( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), &setKey); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("wlansap_set_key_sta failed status: %d", + status); + } + } + + /* Save the key in ap ctx for use on START_BSS and restart */ + if (pairwise || + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == setKey.encType || + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == setKey.encType) + qdf_mem_copy(&ap_ctx->wep_key[key_index], &setKey, + sizeof(tCsrRoamSetKey)); + else + qdf_mem_copy(&ap_ctx->group_key, &setKey, + sizeof(tCsrRoamSetKey)); + + } else if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct csr_roam_profile *roam_profile; + + if (!pairwise) { + /* set group key */ + if (sta_ctx->roam_info.defer_key_complete) { + hdd_debug("Perform Set key Complete"); + hdd_perform_roam_set_key_complete(adapter); + } + } + + roam_profile = hdd_roam_profile(adapter); + roam_profile->Keys.KeyLength[key_index] = params->key_len; + + roam_profile->Keys.defaultIndex = key_index; + + qdf_mem_copy(&roam_profile->Keys.KeyMaterial[key_index][0], + params->key, params->key_len); + + hdd_debug("Set key for peerMac "MAC_ADDRESS_STR" direction %d", + MAC_ADDR_ARRAY(setKey.peerMac.bytes), + setKey.keyDirection); + + /* The supplicant may attempt to set the PTK once + * pre-authentication is done. Save the key in the + * UMAC and include it in the ADD BSS request + */ + qdf_ret_status = sme_ft_update_key(mac_handle, + adapter->session_id, &setKey); + if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_SUCCESS) { + hdd_debug("Update PreAuth Key success"); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return 0; + } else if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_FAILED) { + hdd_err("Update PreAuth Key failed"); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return -EINVAL; + } + + /* issue set key request to SME */ + status = sme_roam_set_key(mac_handle, + adapter->session_id, &setKey, &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed, status: %d", status); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return -EINVAL; + } + + if (adapter->send_mode_change) { + wlan_hdd_send_mode_change_event(); + adapter->send_mode_change = false; + } + + /* in case of IBSS as there was no information + * available about WEP keys during IBSS join, group + * key initialized with NULL key, so re-initialize + * group key with correct value + */ + if ((eCSR_BSS_TYPE_START_IBSS == roam_profile->BSSType) && + !((HDD_AUTH_KEY_MGMT_802_1X == + (sta_ctx->auth_key_mgmt & HDD_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + sta_ctx->conn_info.authType) + ) + && ((WLAN_CIPHER_SUITE_WEP40 == params->cipher) + || (WLAN_CIPHER_SUITE_WEP104 == params->cipher) + ) + ) { + setKey.keyDirection = eSIR_RX_ONLY; + qdf_set_macaddr_broadcast(&setKey.peerMac); + + hdd_debug("Set key peerMac "MAC_ADDRESS_STR" direction %d", + MAC_ADDR_ARRAY(setKey.peerMac.bytes), + setKey.keyDirection); + + status = sme_roam_set_key(mac_handle, + adapter->session_id, &setKey, + &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed for group key (IBSS), returned %d", status); + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + return -EINVAL; + } + } + } + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + hdd_exit(); + return 0; +} + +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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_add_key(wiphy, ndev, key_index, pairwise, + mac_addr, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_get_key + * This function is used to get the key information + */ +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 *) + ) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct csr_roam_profile *roam_profile; + struct key_params params; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + memset(¶ms, 0, sizeof(params)); + + if (CSR_MAX_NUM_KEY <= key_index) { + hdd_err("Invalid key index: %d", key_index); + return -EINVAL; + } + + if ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) { + struct hdd_ap_ctx *ap_ctx = + WLAN_HDD_GET_AP_CTX_PTR(adapter); + + roam_profile = + wlan_sap_get_roam_profile(ap_ctx->sap_context); + } else { + roam_profile = hdd_roam_profile(adapter); + } + + if (roam_profile == NULL) { + hdd_err("Get roam profile failed!"); + return -EINVAL; + } + + switch (roam_profile->EncryptionType.encryptionType[0]) { + 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, + adapter->session_id, params.cipher); + + params.key_len = roam_profile->Keys.KeyLength[key_index]; + params.seq_len = 0; + params.seq = NULL; + params.key = &roam_profile->Keys.KeyMaterial[key_index][0]; + callback(cookie, ¶ms); + + hdd_exit(); + return 0; +} + +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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_key(wiphy, ndev, key_index, pairwise, + mac_addr, cookie, callback); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 + * @unicast: true if it is unicast key + * @multicast: true if it is multicast key + * + * 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. It is automatically deleted when the peer is + * removed. Hence this function currently does nothing. + * Future implementation may interprete 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) +{ + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_del_key() - cfg80211 delete key handler function + * @wiphy: Pointer to wiphy structure. + * @dev: Pointer to net_device 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. + */ +static int wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_del_key(wiphy, dev, key_index, + pairwise, mac_addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_WAPI +static bool hdd_is_wapi_enc_type(eCsrEncryptionType ucEncryptionType) +{ + if (ucEncryptionType == eCSR_ENCRYPT_TYPE_WPI) + return true; + + return false; +} +#else +static bool hdd_is_wapi_enc_type(eCsrEncryptionType ucEncryptionType) +{ + return false; +} +#endif + +/* + * FUNCTION: __wlan_hdd_cfg80211_set_default_key + * This function is used to set the default tx key index + */ +static int __wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool unicast, bool multicast) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + int 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_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY, + adapter->session_id, key_index); + + hdd_debug("Device_mode %s(%d) key_index = %d", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode, key_index); + + if (CSR_MAX_NUM_KEY <= key_index) { + hdd_err("Invalid key index: %d", key_index); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + mac_handle = hdd_ctx->mac_handle; + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + + if ((eCSR_ENCRYPT_TYPE_TKIP != + sta_ctx->conn_info.ucEncryptionType) && + !hdd_is_wapi_enc_type( + sta_ctx->conn_info.ucEncryptionType) && + (eCSR_ENCRYPT_TYPE_AES != + sta_ctx->conn_info.ucEncryptionType) && + (eCSR_ENCRYPT_TYPE_AES_GCMP != + sta_ctx->conn_info.ucEncryptionType) && + (eCSR_ENCRYPT_TYPE_AES_GCMP_256 != + sta_ctx->conn_info.ucEncryptionType)) { + /* If default key index is not same as previous one, + * then update the default key index + */ + + tCsrRoamSetKey setKey; + uint32_t roamId = INVALID_ROAM_ID; + tCsrKeys *Keys = &roam_profile->Keys; + + hdd_debug("Default tx key index %d", key_index); + + Keys->defaultIndex = (u8) key_index; + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; + setKey.keyLength = Keys->KeyLength[key_index]; + + qdf_mem_copy(&setKey.Key[0], + &Keys->KeyMaterial[key_index][0], + Keys->KeyLength[key_index]); + + setKey.keyDirection = eSIR_TX_RX; + + qdf_copy_macaddr(&setKey.peerMac, + &sta_ctx->conn_info.bssId); + + if (Keys->KeyLength[key_index] == CSR_WEP40_KEY_LEN && + roam_profile->EncryptionType. + encryptionType[0] == eCSR_ENCRYPT_TYPE_WEP104) { + /* In the case of dynamic wep + * supplicant hardcodes DWEP type to + * eCSR_ENCRYPT_TYPE_WEP104 even + * though ap is configured for WEP-40 + * encryption. In this canse the key + * length is 5 but the encryption type + * is 104 hence checking the key + * length(5) and encryption type(104) + * and switching encryption type to 40 + */ + roam_profile->EncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40; + roam_profile->mcEncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40; + } + + setKey.encType = + roam_profile->EncryptionType. + encryptionType[0]; + + /* Issue set key request */ + status = sme_roam_set_key(mac_handle, + adapter->session_id, &setKey, + &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed, status: %d", + status); + return -EINVAL; + } + } + } else if (QDF_SAP_MODE == adapter->device_mode) { + struct hdd_ap_ctx *ap_ctx = + WLAN_HDD_GET_AP_CTX_PTR(adapter); + struct csr_roam_profile *profile = + wlan_sap_get_roam_profile(ap_ctx->sap_context); + + if (!profile) { + hdd_err("Failed to get SAP Roam Profile"); + return -EINVAL; + } + /* In SoftAp mode setting key direction for default mode */ + if ((eCSR_ENCRYPT_TYPE_TKIP != + profile->EncryptionType.encryptionType[0]) && + (eCSR_ENCRYPT_TYPE_AES != + profile->EncryptionType.encryptionType[0]) && + (eCSR_ENCRYPT_TYPE_AES_GCMP != + profile->EncryptionType.encryptionType[0]) && + (eCSR_ENCRYPT_TYPE_AES_GCMP_256 != + profile->EncryptionType.encryptionType[0])) { + /* Saving key direction for default key index to TX default */ + ap_ctx->wep_key[key_index].keyDirection = + eSIR_TX_DEFAULT; + hdd_debug("WEP default key index set to SAP context %d", + key_index); + ap_ctx->wep_def_key_idx = key_index; + } + } + + hdd_exit(); + return status; +} + +static int wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool unicast, bool multicast) +{ + int ret; + + cds_ssr_protect(__func__); + ret = + __wlan_hdd_cfg80211_set_default_key(wiphy, ndev, key_index, unicast, + multicast); + cds_ssr_unprotect(__func__); + + return ret; +} + +void wlan_hdd_cfg80211_unlink_bss(struct hdd_adapter *adapter, + tSirMacAddr bssid, uint8_t *ssid, + uint8_t ssid_len) +{ + struct net_device *dev = adapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + + __wlan_cfg80211_unlink_bss_list(wiphy, bssid, ssid, ssid_len); +} + +#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS +static inline int +wlan_hdd_get_frame_len(struct bss_description *bss_desc) +{ + return GET_IE_LEN_IN_BSS(bss_desc->length) + sizeof(qcom_ie_age); +} + +static inline void wlan_hdd_add_age_ie(struct ieee80211_mgmt *mgmt, + uint32_t *ie_length, struct bss_description *bss_desc) +{ + qcom_ie_age *qie_age = NULL; + + /* + * GPS Requirement: need age ie per entry. Using vendor specific. + * Assuming this is the last IE, copy at the end + */ + *ie_length -= sizeof(qcom_ie_age); + qie_age = (qcom_ie_age *)(mgmt->u.probe_resp.variable + *ie_length); + qie_age->element_id = QCOM_VENDOR_IE_ID; + qie_age->len = QCOM_VENDOR_IE_AGE_LEN; + qie_age->oui_1 = QCOM_OUI1; + qie_age->oui_2 = QCOM_OUI2; + qie_age->oui_3 = QCOM_OUI3; + qie_age->type = QCOM_VENDOR_IE_AGE_TYPE; + /* + * Lowi expects the timestamp of bss in units of 1/10 ms. In driver + * all bss related timestamp is in units of ms. Due to this when scan + * results are sent to lowi the scan age is high.To address this, + * send age in units of 1/10 ms. + */ + qie_age->age = (uint32_t)(qdf_mc_timer_get_system_time() - + bss_desc->received_time)/10; + qie_age->tsf_delta = bss_desc->tsf_delta; + memcpy(&qie_age->beacon_tsf, bss_desc->timeStamp, + sizeof(qie_age->beacon_tsf)); + memcpy(&qie_age->seq_ctrl, &bss_desc->seq_ctrl, + sizeof(qie_age->seq_ctrl)); +} +#else +static inline int +wlan_hdd_get_frame_len(struct bss_description *bss_desc) +{ + return GET_IE_LEN_IN_BSS(bss_desc->length); +} +static inline void wlan_hdd_add_age_ie(struct ieee80211_mgmt *mgmt, + uint32_t *ie_length, struct bss_description *bss_desc) +{ +} +#endif /* WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS */ + + +struct cfg80211_bss * +wlan_hdd_inform_bss_frame(struct hdd_adapter *adapter, + struct bss_description *bss_desc) +{ + struct wireless_dev *wdev = adapter->dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + uint32_t ie_length = wlan_hdd_get_frame_len(bss_desc); + const char *ie = + ((ie_length != 0) ? (const char *)&bss_desc->ieFields : NULL); + uint32_t freq, i; + struct cfg80211_bss *bss_status = NULL; + struct hdd_context *hdd_ctx; + struct timespec ts; + struct hdd_config *cfg_param; + struct wlan_cfg80211_inform_bss bss_data = {0}; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + /* + * wlan_hdd_validate_context should not be used here, In validate ctx + * start_modules_in_progress or stop_modules_in_progress is validated, + * If the start_modules_in_progress is set to true means the interface + * is not UP yet if the stop_modules_in_progress means that interface + * is already down. So in both the two scenario's driver should not be + * informing bss to kernel. Hence removing the validate context. + */ + + if (!hdd_ctx || !hdd_ctx->config) { + hdd_debug("HDD context is Null"); + return NULL; + } + + if (cds_is_driver_recovering() || + cds_is_load_or_unload_in_progress()) { + hdd_debug("Recovery or load/unload in progress. State: 0x%x", + cds_get_driver_state()); + return NULL; + } + + cfg_param = hdd_ctx->config; + bss_data.frame_len = ie_length + offsetof(struct ieee80211_mgmt, + u.probe_resp.variable); + bss_data.mgmt = qdf_mem_malloc(bss_data.frame_len); + if (!bss_data.mgmt) { + hdd_err("memory allocation failed"); + return NULL; + } + + memcpy(bss_data.mgmt->bssid, bss_desc->bssId, ETH_ALEN); + + /* Android does not want the timestamp from the frame. + * Instead it wants a monotonic increasing value + */ + get_monotonic_boottime(&ts); + bss_data.mgmt->u.probe_resp.timestamp = + ((u64) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); + + bss_data.mgmt->u.probe_resp.beacon_int = bss_desc->beaconInterval; + bss_data.mgmt->u.probe_resp.capab_info = bss_desc->capabilityInfo; + + wlan_hdd_add_age_ie(bss_data.mgmt, &ie_length, bss_desc); + + memcpy(bss_data.mgmt->u.probe_resp.variable, ie, ie_length); + if (bss_desc->fProbeRsp) { + bss_data.mgmt->frame_control |= + (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); + } else { + bss_data.mgmt->frame_control |= + (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); + } + + if (bss_desc->channelId <= ARRAY_SIZE(hdd_channels_2_4_ghz) && + (wiphy->bands[HDD_NL80211_BAND_2GHZ] != NULL)) { + freq = + ieee80211_channel_to_frequency(bss_desc->channelId, + HDD_NL80211_BAND_2GHZ); + } else if ((bss_desc->channelId > ARRAY_SIZE(hdd_channels_2_4_ghz)) + && (wiphy->bands[HDD_NL80211_BAND_5GHZ] != NULL)) { + freq = + ieee80211_channel_to_frequency(bss_desc->channelId, + HDD_NL80211_BAND_5GHZ); + } else { + hdd_err("Invalid channel: %d", bss_desc->channelId); + qdf_mem_free(bss_data.mgmt); + return NULL; + } + + bss_data.chan = ieee80211_get_channel(wiphy, freq); + if (!bss_data.chan) { + hdd_err("chan pointer is NULL, chan_no: %d freq: %d", + bss_desc->channelId, freq); + qdf_mem_free(bss_data.mgmt); + return NULL; + } + + /* + * Based on .ini configuration, raw rssi can be reported for bss. + * Raw rssi is typically used for estimating power. + */ + bss_data.rssi = (cfg_param->inform_bss_rssi_raw) ? bss_desc->rssi_raw : + bss_desc->rssi; + + /* Supplicant takes the signal strength in terms of mBm(100*dBm) */ + bss_data.rssi = QDF_MIN(bss_data.rssi, 0) * 100; + + bss_data.boottime_ns = bss_desc->scansystimensec; + + /* Set all per chain rssi as invalid */ + for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) + bss_data.per_chain_snr[i] = WLAN_INVALID_PER_CHAIN_RSSI; + + hdd_debug("BSSID: " MAC_ADDRESS_STR " Channel:%d RSSI:%d TSF %u seq %d is_prob_resp %d", + MAC_ADDR_ARRAY(bss_data.mgmt->bssid), + bss_data.chan->center_freq, (int)(bss_data.rssi / 100), + bss_desc->timeStamp[0], ((bss_desc->seq_ctrl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | bss_desc->seq_ctrl.seqNumLo), + bss_desc->fProbeRsp); + + bss_status = wlan_cfg80211_inform_bss_frame_data(wiphy, &bss_data); + hdd_ctx->beacon_probe_rsp_cnt_per_scan++; + qdf_mem_free(bss_data.mgmt); + return bss_status; +} + +/** + * wlan_hdd_cfg80211_update_bss_db() - update bss database of CF80211 + * @adapter: Pointer to adapter + * @roam_info: Pointer to roam info + * + * This function is used to update the BSS data base of CFG8011 + * + * Return: struct cfg80211_bss pointer + */ +struct cfg80211_bss * +wlan_hdd_cfg80211_update_bss_db(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + tCsrRoamConnectedProfile roamProfile; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + struct cfg80211_bss *bss = NULL; + + memset(&roamProfile, 0, sizeof(tCsrRoamConnectedProfile)); + sme_roam_get_connect_profile(mac_handle, adapter->session_id, + &roamProfile); + + if (NULL != roamProfile.pBssDesc) { + bss = wlan_hdd_inform_bss_frame(adapter, roamProfile.pBssDesc); + + if (NULL == bss) + hdd_debug("wlan_hdd_inform_bss_frame returned NULL"); + + sme_roam_free_connect_profile(&roamProfile); + } else { + hdd_err("roamProfile.pBssDesc is NULL"); + } + return bss; +} + +/** + * wlan_hdd_cfg80211_pmksa_candidate_notify() - notify a new PMSKA candidate + * @adapter: Pointer to adapter + * @roam_info: Pointer to roam info + * @index: Index + * @preauth: Preauth flag + * + * This function is used to notify the supplicant of a new PMKSA candidate. + * PMK value is notified to supplicant whether PMK caching or OKC is enabled + * in firmware or not. Supplicant needs this value becaue it uses PMK caching + * by default. + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_pmksa_candidate_notify(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + int index, bool preauth) +{ + struct net_device *dev = adapter->dev; + + hdd_enter(); + hdd_debug("is going to notify supplicant of:"); + + if (NULL == roam_info) { + hdd_err("roam_info is NULL"); + return -EINVAL; + } + + hdd_info(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(roam_info->bssid.bytes)); + cfg80211_pmksa_candidate_notify(dev, index, + roam_info->bssid.bytes, + preauth, GFP_KERNEL); + return 0; +} + +#ifdef FEATURE_WLAN_LFR_METRICS +/** + * wlan_hdd_cfg80211_roam_metrics_preauth() - roam metrics preauth + * @adapter: Pointer to adapter + * @roam_info: Pointer to roam info + * + * 802.11r/LFR metrics reporting function to report preauth initiation + * + * Return: QDF status + */ +#define MAX_LFR_METRICS_EVENT_LENGTH 100 +QDF_STATUS +wlan_hdd_cfg80211_roam_metrics_preauth(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + hdd_enter(); + + if (NULL == adapter) { + hdd_err("adapter is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = scnprintf(metrics_notification, + sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_INIT " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_info->bssid.bytes)); + + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over + * @adapter: Pointer to adapter + * @roam_info: Pointer to roam info + * @preauth_status: Preauth status + * + * 802.11r/LFR metrics reporting function to report handover initiation + * + * Return: QDF status + */ +QDF_STATUS +wlan_hdd_cfg80211_roam_metrics_preauth_status(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + bool preauth_status) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + hdd_enter(); + + if (NULL == adapter) { + hdd_err("adapter is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + scnprintf(metrics_notification, sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_STATUS " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_info->bssid.bytes)); + + if (1 == preauth_status) + strlcat(metrics_notification, " true", + sizeof(metrics_notification)); + else + strlcat(metrics_notification, " false", + sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = strlen(metrics_notification); + + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over + * @adapter: Pointer to adapter + * @roam_info: Pointer to roam info + * + * 802.11r/LFR metrics reporting function to report handover initiation + * + * Return: QDF status + */ +QDF_STATUS +wlan_hdd_cfg80211_roam_metrics_handover(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + hdd_enter(); + + if (NULL == adapter) { + hdd_err("adapter is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = scnprintf(metrics_notification, + sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_HANDOVER " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_info->bssid.bytes)); + + wireless_send_event(adapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +static +void hdd_mon_select_cbmode(struct hdd_adapter *adapter, + uint8_t operationChannel, + struct ch_params *ch_params) +{ + struct hdd_station_ctx *station_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + 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: + 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->channel = operationChannel; + ch_info->cb_mode = ch_params->ch_width; + hdd_debug("ch_info width %d, phymode %d channel %d", + ch_info->channel_width, ch_info->phy_mode, + ch_info->channel); +} +#else +static +void hdd_mon_select_cbmode(struct hdd_adapter *adapter, + uint8_t operationChannel, + struct ch_params *ch_params) +{ +} +#endif + +/** + * hdd_select_cbmode() - select channel bonding mode + * @adapter: Pointer to adapter + * @operatingChannel: Operating channel + * @ch_params: channel info struct to populate + * + * Return: none + */ +void hdd_select_cbmode(struct hdd_adapter *adapter, uint8_t operationChannel, + struct ch_params *ch_params) +{ + uint8_t sec_ch = 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(operationChannel))) { + if (operationChannel >= 1 && operationChannel <= 5) + sec_ch = operationChannel + 4; + else if (operationChannel >= 6 && operationChannel <= 13) + sec_ch = operationChannel - 4; + } + + /* This call decides required channel bonding mode */ + wlan_reg_set_channel_params(hdd_ctx->pdev, operationChannel, + sec_ch, ch_params); + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + hdd_mon_select_cbmode(adapter, operationChannel, ch_params); +} + +/** + * wlan_hdd_handle_sap_sta_dfs_conc() - to handle SAP STA DFS conc + * @adapter: STA adapter + * @roam_profile: STA roam profile + * + * 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_handle_sap_sta_dfs_conc(struct hdd_adapter *adapter, + struct csr_roam_profile *roam_profile) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *ap_adapter; + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_hostapd_state *hostapd_state; + uint8_t channel = 0; + QDF_STATUS status; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return true; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + /* probably no sap running, no handling required */ + if (ap_adapter == NULL) + return true; + + /* + * sap is not in started state, so it is fine to go ahead with sta. + * if sap is currently doing CAC then don't allow sta to go further. + */ + if (!test_bit(SOFTAP_BSS_STARTED, &(ap_adapter)->event_flags) && + (hdd_ctx->dev_dfs_cac_status != DFS_CAC_IN_PROGRESS)) + return true; + + 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); + if (NULL == hdd_ap_ctx) { + hdd_err("AP context not found"); + return false; + } + + /* sap is on non-dfs channel, nothing to handle */ + if (!wlan_reg_is_dfs_ch(hdd_ctx->pdev, + hdd_ap_ctx->operating_channel)) { + hdd_info("sap is on non-dfs channel, sta is allowed"); + return true; + } + /* + * find out by looking in to scan cache where sta is going to + * connect by passing its roam_profile. + */ + status = policy_mgr_get_channel_from_scan_result(hdd_ctx->psoc, + roam_profile, &channel); + + /* + * 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(channel)) { + hdd_info("sap is on dfs, new sta conn on 2.4 is allowed"); + 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. + */ + if (!channel || wlan_reg_is_dfs_ch(hdd_ctx->pdev, channel) || + !policy_mgr_is_safe_channel(hdd_ctx->psoc, channel)) + channel = policy_mgr_get_nondfs_preferred_channel( + hdd_ctx->psoc, PM_SAP_MODE, true); + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + qdf_event_reset(&hostapd_state->qdf_event); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->session_id, + CSA_REASON_STA_CONNECT_DFS_TO_NON_DFS); + + status = wlansap_set_channel_change_with_csa( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), channel, + hdd_ap_ctx->sap_config.ch_width_orig, 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; +} + +#ifdef WLAN_FEATURE_11W +/** + * wlan_hdd_cfg80211_check_pmf_valid() - check if pmf status is ok + * @roam_profile: pointer to roam profile + * + * if MFPEnabled is set but the peer AP is non-PMF i.e 80211w=2 + * or pmf=2 is an explicit configuration in the supplicant + * configuration, drop the connection request. + * + * Return: 0 if check result is valid, otherwise return error code + */ +static +int wlan_hdd_cfg80211_check_pmf_valid(struct csr_roam_profile *roam_profile) +{ + if (roam_profile->MFPEnabled && + !(roam_profile->MFPRequired || roam_profile->MFPCapable)) { + hdd_err("Drop connect req as supplicant has indicated PMF required for the non-PMF peer. MFPEnabled %d MFPRequired %d MFPCapable %d", + roam_profile->MFPEnabled, + roam_profile->MFPRequired, + roam_profile->MFPCapable); + return -EINVAL; + } + return 0; +} +#else +static inline +int wlan_hdd_cfg80211_check_pmf_valid(struct csr_roam_profile *roam_profile) +{ + return 0; +} +#endif + +/** + * wlan_hdd_cfg80211_connect_start() - to start the association process + * @adapter: Pointer to adapter + * @ssid: Pointer to ssid + * @ssid_len: Length of ssid + * @bssid: Pointer to bssid + * @bssid_hint: Pointer to bssid hint + * @operatingChannel: Operating channel + * @ch_width: channel width. this is needed only for IBSS + * + * This function is used to start the association process + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_connect_start(struct hdd_adapter *adapter, + const u8 *ssid, size_t ssid_len, + const u8 *bssid, const u8 *bssid_hint, + u8 operatingChannel, + enum nl80211_chan_width ch_width) +{ + int status = 0; + QDF_STATUS qdf_status; + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *hdd_sta_ctx; + uint32_t roamId = INVALID_ROAM_ID; + struct csr_roam_profile *roam_profile; + eCsrAuthType RSNAuthType; + tSmeConfigParams *sme_config; + uint8_t channel = 0; + mac_handle_t mac_handle; + + hdd_enter(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + goto ret_status; + + if (SIR_MAC_MAX_SSID_LENGTH < ssid_len) { + hdd_err("wrong SSID len"); + status = -EINVAL; + goto ret_status; + } + + if (true == hdd_is_connection_in_progress(NULL, NULL)) { + hdd_err("Connection refused: conn in progress"); + status = -EINVAL; + goto ret_status; + } + + /* Disable roaming on all other adapters before connect start */ + wlan_hdd_disable_roaming(adapter); + + hdd_notify_teardown_tdls_links(hdd_ctx->psoc); + + qdf_mem_zero(&hdd_sta_ctx->conn_info.conn_flag, + sizeof(hdd_sta_ctx->conn_info.conn_flag)); + + roam_profile = hdd_roam_profile(adapter); + if (roam_profile) { + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* Restart the opportunistic timer + * + * If hw_mode_change_in_progress is true, then wait + * till firmware sends the callback for hw_mode change. + * + * Else set connect_in_progress as true and proceed. + */ + policy_mgr_restart_opportunistic_timer( + hdd_ctx->psoc, false); + if (policy_mgr_is_hw_mode_change_in_progress( + hdd_ctx->psoc)) { + qdf_status = policy_mgr_wait_for_connection_update( + hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("qdf wait for event failed!!"); + status = -EINVAL; + goto ret_status; + } + } + hdd_set_connection_in_progress(true); + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(adapter))->config->WmmMode) { + /*QoS not enabled in cfg file */ + roam_profile->uapsd_mask = 0; + } else { + /*QoS enabled, update uapsd mask from cfg file */ + roam_profile->uapsd_mask = + (WLAN_HDD_GET_CTX(adapter))->config->UapsdMask; + } + + roam_profile->SSIDs.numOfSSIDs = 1; + roam_profile->SSIDs.SSIDList->SSID.length = ssid_len; + qdf_mem_zero(roam_profile->SSIDs.SSIDList->SSID.ssId, + sizeof(roam_profile->SSIDs.SSIDList->SSID.ssId)); + qdf_mem_copy((void *)(roam_profile->SSIDs.SSIDList->SSID.ssId), + ssid, ssid_len); + + /* cleanup bssid hint */ + qdf_mem_zero(roam_profile->bssid_hint.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_zero((void *)(roam_profile->BSSIDs.bssid), + QDF_MAC_ADDR_SIZE); + + if (bssid) { + roam_profile->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy((void *)(roam_profile->BSSIDs.bssid), + bssid, QDF_MAC_ADDR_SIZE); + /* + * Save BSSID in separate variable as + * roam_profile's BSSID is getting zeroed out in the + * association process. In case of join failure + * we should send valid BSSID to supplicant + */ + qdf_mem_copy(sta_ctx->requested_bssid.bytes, + bssid, QDF_MAC_ADDR_SIZE); + hdd_debug("bssid is given by upper layer %pM", bssid); + } else if (bssid_hint) { + qdf_mem_copy(roam_profile->bssid_hint.bytes, + bssid_hint, QDF_MAC_ADDR_SIZE); + /* + * Save BSSID in a separate variable as + * roam_profile's BSSID is getting zeroed out in the + * association process. In case of join failure + * we should send valid BSSID to supplicant + */ + qdf_mem_copy(sta_ctx->requested_bssid.bytes, + bssid_hint, QDF_MAC_ADDR_SIZE); + hdd_debug("bssid_hint is given by upper layer %pM", + bssid_hint); + } + + hdd_debug("Connect to SSID: %.*s operating Channel: %u", + roam_profile->SSIDs.SSIDList->SSID.length, + roam_profile->SSIDs.SSIDList->SSID.ssId, + operatingChannel); + + if (hdd_sta_ctx->wpa_versions) { + hdd_set_genie_to_csr(adapter, &RSNAuthType); + hdd_set_csr_auth_type(adapter, RSNAuthType); + } +#ifdef FEATURE_WLAN_WAPI + if (adapter->wapi_info.wapi_mode) { + hdd_debug("Setting WAPI AUTH Type and Encryption Mode values"); + switch (adapter->wapi_info.wapi_auth_mode) { + case WAPI_AUTH_MODE_PSK: + { + hdd_debug("WAPI AUTH TYPE: PSK: %d", + adapter->wapi_info.wapi_auth_mode); + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_PSK; + break; + } + case WAPI_AUTH_MODE_CERT: + { + hdd_debug("WAPI AUTH TYPE: CERT: %d", + adapter->wapi_info.wapi_auth_mode); + roam_profile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + break; + } + default: + break; + } /* End of switch */ + if (adapter->wapi_info.wapi_auth_mode == + WAPI_AUTH_MODE_PSK + || adapter->wapi_info.wapi_auth_mode == + WAPI_AUTH_MODE_CERT) { + hdd_debug("WAPI PAIRWISE/GROUP ENCRYPTION: WPI"); + roam_profile->AuthType.numEntries = 1; + roam_profile->EncryptionType.numEntries = 1; + roam_profile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_WPI; + roam_profile->mcEncryptionType.numEntries = 1; + roam_profile->mcEncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WPI; + } + } +#endif + pmo_ucfg_flush_gtk_offload_req(adapter->vdev); + roam_profile->csrPersona = adapter->device_mode; + + if (operatingChannel) { + roam_profile->ChannelInfo.ChannelList = + &operatingChannel; + roam_profile->ChannelInfo.numOfChannels = 1; + } else { + roam_profile->ChannelInfo.ChannelList = NULL; + roam_profile->ChannelInfo.numOfChannels = 0; + } + if ((QDF_IBSS_MODE == adapter->device_mode) + && operatingChannel) { + /* + * Need to post the IBSS power save parameters + * to WMA. WMA will configure this parameters + * to firmware if power save is enabled by the + * firmware. + */ + qdf_status = hdd_set_ibss_power_save_params(adapter); + + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Set IBSS Power Save Params Failed"); + status = -EINVAL; + goto conn_failure; + } + roam_profile->ch_params.ch_width = + hdd_map_nl_chan_width(ch_width); + /* + * In IBSS mode while operating in 2.4 GHz, + * the device supports only 20 MHz. + */ + if (WLAN_REG_IS_24GHZ_CH(operatingChannel)) + roam_profile->ch_params.ch_width = + CH_WIDTH_20MHZ; + hdd_select_cbmode(adapter, operatingChannel, + &roam_profile->ch_params); + } + + if (wlan_hdd_cfg80211_check_pmf_valid(roam_profile)) { + status = -EINVAL; + goto conn_failure; + } + + /* + * After 8-way handshake supplicant should give the scan command + * in that it update the additional IEs, But because of scan + * enhancements, the supplicant is not issuing the scan command + * now. So the unicast frames which are sent from the host are + * not having the additional IEs. If it is P2P CLIENT and there + * is no additional IE present in roamProfile, then use the + * addtional IE form scan_info + */ + + if ((adapter->device_mode == QDF_P2P_CLIENT_MODE) && + (!roam_profile->pAddIEScan)) { + roam_profile->pAddIEScan = + &adapter->scan_info.scan_add_ie.addIEdata[0]; + roam_profile->nAddIEScanLength = + adapter->scan_info.scan_add_ie.length; + } + + if ((policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) == true) + && (false == wlan_hdd_handle_sap_sta_dfs_conc(adapter, + roam_profile))) { + hdd_err("sap-sta conc will fail, can't allow sta"); + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + status = -ENOMEM; + goto conn_failure; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("unable to allocate sme_config"); + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + status = -ENOMEM; + goto conn_failure; + } + + mac_handle = hdd_ctx->mac_handle; + sme_get_config_param(mac_handle, sme_config); + /* These values are not sessionized. So, any change in these SME + * configs on an older or parallel interface will affect the + * cb mode. So, restoring the default INI params before starting + * interfaces such as sta, cli etc., + */ + sme_config->csrConfig.channelBondingMode5GHz = + hdd_ctx->config->nChannelBondingMode5GHz; + sme_config->csrConfig.channelBondingMode24GHz = + hdd_ctx->config->nChannelBondingMode24GHz; + sme_update_config(mac_handle, sme_config); + qdf_mem_free(sme_config); + /* + * Change conn_state to connecting before sme_roam_connect(), + * because sme_roam_connect() has a direct path to call + * hdd_sme_roam_callback(), which will change the conn_state + * If direct path, conn_state will be accordingly changed to + * NotConnected or Associated by either + * hdd_association_completion_handler() or + * hdd_dis_connect_handler() in sme_RoamCallback()if + * sme_RomConnect is to be queued, + * Connecting state will remain until it is completed. + * + * If connection state is not changed, connection state will + * remain in eConnectionState_NotConnected state. + * In hdd_association_completion_handler, "hddDisconInProgress" + * is set to true if conn state is + * eConnectionState_NotConnected. + * If "hddDisconInProgress" is set to true then cfg80211 layer + * is not informed of connect result indication which + * is an issue. + */ + if (QDF_STA_MODE == adapter->device_mode || + QDF_P2P_CLIENT_MODE == adapter->device_mode) + hdd_conn_set_connection_state(adapter, + eConnectionState_Connecting); + + hdd_set_disconnect_status(adapter, false); + + qdf_runtime_pm_prevent_suspend( + &hdd_ctx->runtime_context.connect); + hdd_prevent_suspend_timeout(HDD_WAKELOCK_CONNECT_COMPLETE, + WIFI_POWER_EVENT_WAKELOCK_CONNECT); + qdf_status = sme_roam_connect(mac_handle, + adapter->session_id, roam_profile, + &roamId); + if (QDF_IS_STATUS_ERROR(qdf_status)) + status = qdf_status_to_os_return(qdf_status); + + if ((QDF_STATUS_SUCCESS != qdf_status) && + (QDF_STA_MODE == adapter->device_mode || + QDF_P2P_CLIENT_MODE == adapter->device_mode)) { + hdd_err("sme_roam_connect (session %d) failed with " + "qdf_status %d. -> NotConnected", + adapter->session_id, qdf_status); + /* change back to NotAssociated */ + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + qdf_runtime_pm_allow_suspend( + &hdd_ctx->runtime_context.connect); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT); + } + + /* Reset connect_in_progress */ + hdd_set_connection_in_progress(false); + + roam_profile->ChannelInfo.ChannelList = NULL; + roam_profile->ChannelInfo.numOfChannels = 0; + + if ((QDF_STA_MODE == adapter->device_mode) + && policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) + && !policy_mgr_is_hw_dbs_2x2_capable( + hdd_ctx->psoc)) { + policy_mgr_get_channel_from_scan_result( + hdd_ctx->psoc, + roam_profile, &channel); + hdd_info("Move to single MAC mode(optimization) if applicable"); + if (channel) + policy_mgr_checkn_update_hw_mode_single_mac_mode( + hdd_ctx->psoc, channel); + } + + } else { + hdd_err("No valid Roam profile"); + status = -EINVAL; + } + goto ret_status; + +conn_failure: + /* Reset connect_in_progress */ + hdd_set_connection_in_progress(false); + +ret_status: + /* + * Enable roaming on other STA adapter for failure case. + * For success case, it is enabled in assoc completion handler + */ + if (status) + wlan_hdd_enable_roaming(adapter); + + hdd_exit(); + return status; +} + +/** + * wlan_hdd_cfg80211_set_auth_type() - set auth type + * @adapter: Pointer to adapter + * @auth_type: Auth type + * + * This function is used to set the authentication type (OPEN/SHARED). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_auth_type(struct hdd_adapter *adapter, + enum nl80211_auth_type auth_type) +{ + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct csr_roam_profile *roam_profile; + + /*set authentication type */ + switch (auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + hdd_debug("set authentication type to AUTOSWITCH"); + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_AUTOSWITCH; + break; + + case NL80211_AUTHTYPE_OPEN_SYSTEM: + case NL80211_AUTHTYPE_FT: + hdd_debug("set authentication type to OPEN"); + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + hdd_debug("set authentication type to SHARED"); + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_SHARED_KEY; + break; +#ifdef FEATURE_WLAN_ESE + case NL80211_AUTHTYPE_NETWORK_EAP: + hdd_debug("set authentication type to CCKM WPA"); + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_CCKM_WPA; + break; +#endif +#if defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) + case NL80211_AUTHTYPE_FILS_SK: + hdd_debug("set authentication type to FILS SHARED"); + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; +#endif + case NL80211_AUTHTYPE_SAE: + hdd_debug("set authentication type to SAE"); + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_SAE; + break; + default: + hdd_err("Unsupported authentication type: %d", auth_type); + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_UNKNOWN; + return -EINVAL; + } + + roam_profile = hdd_roam_profile(adapter); + roam_profile->AuthType.authType[0] = sta_ctx->conn_info.authType; + return 0; +} + +#if defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) +static bool hdd_validate_fils_info_ptr(struct csr_roam_profile *roam_profile) +{ + struct cds_fils_connection_info *fils_con_info; + + fils_con_info = roam_profile->fils_con_info; + if (!fils_con_info) { + hdd_err("No valid Roam profile"); + return false; + } + + return true; +} + +static enum eAniAuthType wlan_hdd_get_fils_auth_type( + enum nl80211_auth_type auth) +{ + switch (auth) { + case NL80211_AUTHTYPE_FILS_SK: + return SIR_FILS_SK_WITHOUT_PFS; + case NL80211_AUTHTYPE_FILS_SK_PFS: + return SIR_FILS_SK_WITH_PFS; + case NL80211_AUTHTYPE_FILS_PK: + return SIR_FILS_PK_AUTH; + default: + return eSIR_DONOT_USE_AUTH_TYPE; + } +} + +static bool wlan_hdd_fils_data_in_limits(struct cfg80211_connect_params *req) +{ + hdd_debug("seq=%d auth=%d lengths: user=%zu rrk=%zu realm=%zu", + req->fils_erp_next_seq_num, req->auth_type, + req->fils_erp_username_len, req->fils_erp_rrk_len, + req->fils_erp_realm_len); + if (!req->fils_erp_rrk_len || !req->fils_erp_realm_len || + !req->fils_erp_username_len || + req->fils_erp_rrk_len > FILS_MAX_RRK_LENGTH || + req->fils_erp_realm_len > FILS_MAX_REALM_LEN || + req->fils_erp_username_len > FILS_MAX_KEYNAME_NAI_LENGTH) { + hdd_err("length incorrect, user=%zu rrk=%zu realm=%zu", + req->fils_erp_username_len, req->fils_erp_rrk_len, + req->fils_erp_realm_len); + return false; + } + + if (!req->fils_erp_rrk || !req->fils_erp_realm || + !req->fils_erp_username) { + hdd_err("buffer incorrect, user=%pK rrk=%pK realm=%pK", + req->fils_erp_username, req->fils_erp_rrk, + req->fils_erp_realm); + return false; + } + + return true; +} + +/** + * wlan_hdd_cfg80211_set_fils_config() - set fils config params during connect + * @adapter: Pointer to adapter + * @req: Pointer to fils parameters + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_fils_config(struct hdd_adapter *adapter, + struct cfg80211_connect_params *req) +{ + struct csr_roam_profile *roam_profile; + enum eAniAuthType auth_type; + uint8_t *buf; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + roam_profile = hdd_roam_profile(adapter); + + if (!hdd_ctx->config->is_fils_enabled) { + hdd_err("FILS disabled"); + return -EINVAL; + } + hdd_clear_fils_connection_info(adapter); + roam_profile->fils_con_info = + qdf_mem_malloc(sizeof(*roam_profile->fils_con_info)); + + if (!roam_profile->fils_con_info) { + hdd_err("failed to allocate memory"); + return -EINVAL; + } + /* + * The initial connection for FILS may happen with an OPEN + * auth type. Hence we need to allow the connection to go + * through in that case as well. Below is_fils_connection + * flag is propagated down to CSR and PE sessions through + * the JOIN request. As the flag is used, do not free the + * memory allocated to fils_con_info and return success. + */ + if (req->auth_type != NL80211_AUTHTYPE_FILS_SK) { + roam_profile->fils_con_info->is_fils_connection = false; + return 0; + } + + /* + * Once above check is done, then we can check for valid FILS + * auth types. Currently only NL80211_AUTHTYPE_FILS_SK is + * supported. Once all auth types are supported, then we can + * merge these 2 conditions into one. + */ + auth_type = wlan_hdd_get_fils_auth_type(req->auth_type); + if (auth_type == eSIR_DONOT_USE_AUTH_TYPE) { + hdd_err("invalid auth type for fils %d", req->auth_type); + goto fils_conn_fail; + } + if (!wlan_hdd_fils_data_in_limits(req)) + goto fils_conn_fail; + + roam_profile->fils_con_info->is_fils_connection = true; + roam_profile->fils_con_info->sequence_number = + (req->fils_erp_next_seq_num + 1); + roam_profile->fils_con_info->auth_type = auth_type; + + roam_profile->fils_con_info->r_rk_length = + req->fils_erp_rrk_len; + if (req->fils_erp_rrk_len) + qdf_mem_copy(roam_profile->fils_con_info->r_rk, + req->fils_erp_rrk, + roam_profile->fils_con_info->r_rk_length); + + roam_profile->fils_con_info->realm_len = req->fils_erp_realm_len; + if (req->fils_erp_realm_len) + qdf_mem_copy(roam_profile->fils_con_info->realm, + req->fils_erp_realm, + roam_profile->fils_con_info->realm_len); + + roam_profile->fils_con_info->key_nai_length = + req->fils_erp_username_len + sizeof(char) + + req->fils_erp_realm_len; + hdd_debug("key_nai_length = %d", + roam_profile->fils_con_info->key_nai_length); + if (roam_profile->fils_con_info->key_nai_length > + FILS_MAX_KEYNAME_NAI_LENGTH) { + hdd_err("Do not allow FILS conn due to excess NAI Length %d", + roam_profile->fils_con_info->key_nai_length); + goto fils_conn_fail; + } + buf = roam_profile->fils_con_info->keyname_nai; + 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); + + return 0; + +fils_conn_fail: + if (roam_profile->fils_con_info) { + qdf_mem_free(roam_profile->fils_con_info); + roam_profile->fils_con_info = NULL; + } + return -EINVAL; +} + +static bool wlan_hdd_is_akm_suite_fils(uint32_t key_mgmt) +{ + switch (key_mgmt) { + case WLAN_AKM_SUITE_FILS_SHA256: + case WLAN_AKM_SUITE_FILS_SHA384: + case WLAN_AKM_SUITE_FT_FILS_SHA256: + case WLAN_AKM_SUITE_FT_FILS_SHA384: + return true; + default: + return false; + } +} + +static bool wlan_hdd_is_conn_type_fils(struct cfg80211_connect_params *req) +{ + enum nl80211_auth_type auth_type = req->auth_type; + /* + * Below n_akm_suites is defined as int in the kernel, even though it + * is supposed to be unsigned. + */ + int num_akm_suites = req->crypto.n_akm_suites; + uint32_t key_mgmt = req->crypto.akm_suites[0]; + enum eAniAuthType fils_auth_type = + wlan_hdd_get_fils_auth_type(req->auth_type); + + hdd_debug("Num of AKM suites = %d", num_akm_suites); + if (num_akm_suites <= 0) + return false; + + /* + * Auth type will be either be OPEN or FILS type for a FILS connection + */ + if ((auth_type != NL80211_AUTHTYPE_OPEN_SYSTEM) && + (fils_auth_type == eSIR_DONOT_USE_AUTH_TYPE)) { + hdd_debug("Not a FILS auth type, auth = %d, fils auth = %d", + auth_type, fils_auth_type); + return false; + } + + if (!wlan_hdd_is_akm_suite_fils(key_mgmt)) { + hdd_debug("Not a FILS AKM SUITE %d", key_mgmt); + return false; + } + + return true; +} + +#else +static bool hdd_validate_fils_info_ptr(struct csr_roam_profile *roam_profile) +{ + return true; +} + +static int wlan_hdd_cfg80211_set_fils_config(struct hdd_adapter *adapter, + struct cfg80211_connect_params *req) +{ + return 0; +} + +static bool wlan_hdd_is_akm_suite_fils(uint32_t key_mgmt) +{ + return false; +} + +static bool wlan_hdd_is_conn_type_fils(struct cfg80211_connect_params *req) +{ + return false; +} +#endif + +/** + * wlan_hdd_set_akm_suite() - set key management type + * @adapter: Pointer to adapter + * @key_mgmt: Key management type + * + * This function is used to set the key mgmt type(PSK/8021x). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_set_akm_suite(struct hdd_adapter *adapter, u32 key_mgmt) +{ + struct hdd_station_ctx *sta_ctx; + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + + if (wlan_hdd_is_akm_suite_fils(key_mgmt) && + !hdd_validate_fils_info_ptr(roam_profile)) + return -EINVAL; +#ifndef WLAN_AKM_SUITE_8021X_SHA256 +#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05 +#endif +#ifndef WLAN_AKM_SUITE_PSK_SHA256 +#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06 +#endif + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /*set key mgmt type */ + switch (key_mgmt) { + case WLAN_AKM_SUITE_PSK: + case WLAN_AKM_SUITE_PSK_SHA256: + case WLAN_AKM_SUITE_FT_PSK: + case WLAN_AKM_SUITE_DPP_RSN: + hdd_debug("setting key mgmt type to PSK"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_PSK; + break; + + case WLAN_AKM_SUITE_8021X_SHA256: + case WLAN_AKM_SUITE_8021X: + case WLAN_AKM_SUITE_FT_8021X: + hdd_debug("setting key mgmt type to 8021x"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + break; +#ifdef FEATURE_WLAN_ESE +#define WLAN_AKM_SUITE_CCKM 0x00409600 /* Should be in ieee802_11_defs.h */ + case WLAN_AKM_SUITE_CCKM: + hdd_debug("setting key mgmt type to CCKM"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_CCKM; + break; +#endif +#ifndef WLAN_AKM_SUITE_OSEN +#define WLAN_AKM_SUITE_OSEN 0x506f9a01 /* Should be in ieee802_11_defs.h */ +#endif + case WLAN_AKM_SUITE_OSEN: + hdd_debug("setting key mgmt type to OSEN"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + break; +#if defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) + case WLAN_AKM_SUITE_FILS_SHA256: + hdd_debug("setting key mgmt type to FILS SHA256"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FILS_SHA256; + break; + + case WLAN_AKM_SUITE_FILS_SHA384: + hdd_debug("setting key mgmt type to FILS SHA384"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FILS_SHA384; + break; + + case WLAN_AKM_SUITE_FT_FILS_SHA256: + hdd_debug("setting key mgmt type to FILS FT SHA256"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FT_FILS_SHA256; + break; + + case WLAN_AKM_SUITE_FT_FILS_SHA384: + hdd_debug("setting key mgmt type to FILS FT SHA384"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + roam_profile->fils_con_info->akm_type = + eCSR_AUTH_TYPE_FT_FILS_SHA384; + break; +#endif + + case WLAN_AKM_SUITE_OWE: + hdd_debug("setting key mgmt type to OWE"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + break; + + case WLAN_AKM_SUITE_EAP_SHA256: + hdd_debug("setting key mgmt type to EAP_SHA256"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + break; + case WLAN_AKM_SUITE_EAP_SHA384: + hdd_debug("setting key mgmt type to EAP_SHA384"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + break; + + case WLAN_AKM_SUITE_SAE: + hdd_debug("setting key mgmt type to SAE"); + sta_ctx->auth_key_mgmt |= HDD_AUTH_KEY_MGMT_802_1X; + break; + + default: + hdd_err("Unsupported key mgmt type: %d", key_mgmt); + return -EINVAL; + + } + return 0; +} + +/** + * wlan_hdd_cfg80211_set_cipher() - set encryption type + * @adapter: Pointer to adapter + * @cipher: Cipher type + * @ucast: Unicast flag + * + * This function is used to set the encryption type + * (NONE/WEP40/WEP104/TKIP/CCMP). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_cipher(struct hdd_adapter *adapter, + u32 cipher, bool ucast) +{ + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct csr_roam_profile *roam_profile; + + if (!cipher) { + hdd_debug("received cipher %d - considering none", cipher); + encryptionType = eCSR_ENCRYPT_TYPE_NONE; + } else { + + /*set encryption method */ + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + encryptionType = eCSR_ENCRYPT_TYPE_NONE; + break; + + case WLAN_CIPHER_SUITE_WEP40: + encryptionType = eCSR_ENCRYPT_TYPE_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + encryptionType = eCSR_ENCRYPT_TYPE_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + encryptionType = eCSR_ENCRYPT_TYPE_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + encryptionType = eCSR_ENCRYPT_TYPE_AES; + break; +#ifdef FEATURE_WLAN_WAPI + case WLAN_CIPHER_SUITE_SMS4: + encryptionType = eCSR_ENCRYPT_TYPE_WPI; + break; +#endif + +#ifdef FEATURE_WLAN_ESE + case WLAN_CIPHER_SUITE_KRK: + encryptionType = eCSR_ENCRYPT_TYPE_KRK; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WLAN_CIPHER_SUITE_BTK: + encryptionType = eCSR_ENCRYPT_TYPE_BTK; + break; +#endif +#endif + case WLAN_CIPHER_SUITE_GCMP: + encryptionType = eCSR_ENCRYPT_TYPE_AES_GCMP; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + encryptionType = eCSR_ENCRYPT_TYPE_AES_GCMP_256; + break; + default: + hdd_err("Unsupported cipher type: %d", cipher); + return -EOPNOTSUPP; + } + } + + roam_profile = hdd_roam_profile(adapter); + if (ucast) { + hdd_debug("setting unicast cipher type to %d", encryptionType); + sta_ctx->conn_info.ucEncryptionType = encryptionType; + roam_profile->EncryptionType.numEntries = 1; + roam_profile->EncryptionType.encryptionType[0] = + encryptionType; + } else { + hdd_debug("setting mcast cipher type to %d", encryptionType); + sta_ctx->conn_info.mcEncryptionType = encryptionType; + roam_profile->mcEncryptionType.numEntries = 1; + roam_profile->mcEncryptionType.encryptionType[0] = + encryptionType; + } + + return 0; +} + +/** + * wlan_hdd_add_assoc_ie() - Add Assoc IE to roamProfile + * @adapter: Pointer to adapter + * @gen_ie: Pointer to IE data + * @len: length of IE data + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_add_assoc_ie(struct hdd_adapter *adapter, + const uint8_t *gen_ie, uint16_t len) +{ + struct csr_roam_profile *roam_profile; + tSirAddie *assoc_add_ie; + uint16_t cur_add_ie_len; + + assoc_add_ie = hdd_assoc_additional_ie(adapter); + cur_add_ie_len = assoc_add_ie->length; + if (SIR_MAC_MAX_ADD_IE_LENGTH < (cur_add_ie_len + len)) { + hdd_err("current len %u, new ie of len %u will overflow", + cur_add_ie_len, len); + return -ENOMEM; + } + memcpy(assoc_add_ie->addIEdata + cur_add_ie_len, gen_ie, len); + assoc_add_ie->length += len; + + roam_profile = hdd_roam_profile(adapter); + roam_profile->pAddIEAssoc = assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = assoc_add_ie->length; + + return 0; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * wlan_hdd_save_hlp_ie - API to save HLP IE + * @roam_profile: Pointer to roam profile + * @gen_ie: IE buffer to store + * @len: length of the IE buffer @gen_ie + * @flush: Flush the older saved HLP if any + * + * Return: None + */ +static void wlan_hdd_save_hlp_ie(struct csr_roam_profile *roam_profile, + const uint8_t *gen_ie, uint16_t len, + bool flush) +{ + uint8_t *hlp_ie = roam_profile->hlp_ie; + + if (flush) { + roam_profile->hlp_ie_len = 0; + if (hlp_ie) { + qdf_mem_free(hlp_ie); + roam_profile->hlp_ie = NULL; + } + } + + if ((roam_profile->hlp_ie_len + + len) > FILS_MAX_HLP_DATA_LEN) { + hdd_err("HLP len exceeds: hlp_ie_len %d len %d", + roam_profile->hlp_ie_len, len); + return; + } + + if (!roam_profile->hlp_ie) { + roam_profile->hlp_ie = + qdf_mem_malloc(FILS_MAX_HLP_DATA_LEN); + hlp_ie = roam_profile->hlp_ie; + if (!hlp_ie) { + hdd_err("HLP IE mem alloc fails"); + return; + } + } + + qdf_mem_copy(hlp_ie + roam_profile->hlp_ie_len, gen_ie, len); + roam_profile->hlp_ie_len += len; +} +#else +static inline void wlan_hdd_save_hlp_ie(struct csr_roam_profile *roam_profile, + const uint8_t *gen_ie, uint16_t len, + bool flush) +{} +#endif +/** + * wlan_hdd_cfg80211_set_ie() - set IEs + * @adapter: Pointer to adapter + * @ie: Pointer ot ie + * @ie: IE length + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_ie(struct hdd_adapter *adapter, + const uint8_t *ie, + size_t ie_len) +{ + struct csr_roam_profile *roam_profile; + tSirAddie *assoc_add_ie; + const uint8_t *genie = ie; + uint16_t remLen = ie_len; +#ifdef FEATURE_WLAN_WAPI + uint32_t akmsuite[MAX_NUM_AKM_SUITES]; + uint8_t *tmp; + uint16_t akmsuiteCount; + uint32_t *akmlist; +#endif + int status; + uint8_t *security_ie; + + roam_profile = hdd_roam_profile(adapter); + + /* clear previous assocAddIE */ + assoc_add_ie = hdd_assoc_additional_ie(adapter); + assoc_add_ie->length = 0; + roam_profile->bWPSAssociation = false; + roam_profile->bOSENAssociation = false; + security_ie = hdd_security_ie(adapter); + + while (remLen >= 2) { + uint16_t eLen = 0; + uint8_t elementId; + + elementId = *genie++; + eLen = *genie++; + remLen -= 2; + + /* Sanity check on eLen */ + if (eLen > remLen) { + hdd_err("%s: Invalid IE length[%d] for IE[0x%X]", + __func__, eLen, elementId); + QDF_ASSERT(0); + return -EINVAL; + } + + hdd_debug("IE[0x%X], LEN[%d]", elementId, eLen); + + switch (elementId) { + case DOT11F_EID_WPA: + if (4 > eLen) { /* should have at least OUI which is 4 bytes so extra 2 bytes not needed */ + hdd_err("Invalid WPA IE"); + return -EINVAL; + } else if (0 == + memcmp(&genie[0], "\x00\x50\xf2\x04", 4)) { + uint16_t curAddIELen = assoc_add_ie->length; + + hdd_debug("Set WPS IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (assoc_add_ie->length + eLen)) { + hdd_err("Cannot accommodate assocAddIE. Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + /* WSC IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */ + memcpy(assoc_add_ie->addIEdata + + curAddIELen, genie - 2, eLen + 2); + assoc_add_ie->length += eLen + 2; + + roam_profile->bWPSAssociation = true; + roam_profile->pAddIEAssoc = + assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = + assoc_add_ie->length; + } else if (0 == memcmp(&genie[0], "\x00\x50\xf2", 3)) { + if (eLen > (MAX_WPA_RSN_IE_LEN - 2)) { + hdd_err("%s: Invalid WPA IE length[%d]", + __func__, eLen); + QDF_ASSERT(0); + return -EINVAL; + } + hdd_debug("Set WPA IE (len %d)", eLen + 2); + memset(security_ie, 0, MAX_WPA_RSN_IE_LEN); + memcpy(security_ie, genie - 2, (eLen + 2)); + roam_profile->pWPAReqIE = security_ie; + roam_profile->nWPAReqIELength = eLen + 2; /* ie_len; */ + } else if ((0 == memcmp(&genie[0], P2P_OUI_TYPE, + P2P_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + assoc_add_ie->length; + hdd_debug("Set P2P IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (assoc_add_ie->length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + /* P2P IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */ + memcpy(assoc_add_ie->addIEdata + + curAddIELen, genie - 2, eLen + 2); + assoc_add_ie->length += eLen + 2; + + roam_profile->pAddIEAssoc = + assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = + assoc_add_ie->length; + } +#ifdef WLAN_FEATURE_WFD + else if ((0 == memcmp(&genie[0], WFD_OUI_TYPE, + WFD_OUI_TYPE_SIZE)) && + /* Consider WFD IE, only for P2P Client */ + (QDF_P2P_CLIENT_MODE == + adapter->device_mode)) { + uint16_t curAddIELen = + assoc_add_ie->length; + hdd_debug("Set WFD IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (assoc_add_ie->length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + /* WFD IE is saved to Additional IE ; it should + * be accumulated to handle WPS IE + P2P IE + + * WFD IE + */ + memcpy(assoc_add_ie->addIEdata + + curAddIELen, genie - 2, eLen + 2); + assoc_add_ie->length += eLen + 2; + + roam_profile->pAddIEAssoc = + assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = + assoc_add_ie->length; + } +#endif + /* Appending HS 2.0 Indication Element in Assiciation Request */ + else if ((0 == memcmp(&genie[0], HS20_OUI_TYPE, + HS20_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + assoc_add_ie->length; + hdd_debug("Set HS20 IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (assoc_add_ie->length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + memcpy(assoc_add_ie->addIEdata + + curAddIELen, genie - 2, eLen + 2); + assoc_add_ie->length += eLen + 2; + + roam_profile->pAddIEAssoc = + assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = + assoc_add_ie->length; + } + /* Appending OSEN Information Element in Assiciation Request */ + else if ((0 == memcmp(&genie[0], OSEN_OUI_TYPE, + OSEN_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + assoc_add_ie->length; + hdd_debug("Set OSEN IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (assoc_add_ie->length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + memcpy(assoc_add_ie->addIEdata + + curAddIELen, genie - 2, eLen + 2); + assoc_add_ie->length += eLen + 2; + + roam_profile->bOSENAssociation = true; + roam_profile->pAddIEAssoc = + assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = + assoc_add_ie->length; + } else if ((0 == memcmp(&genie[0], MBO_OUI_TYPE, + MBO_OUI_TYPE_SIZE))){ + hdd_debug("Set MBO IE(len %d)", eLen + 2); + status = wlan_hdd_add_assoc_ie(adapter, + genie - 2, eLen + 2); + if (status) + return status; + } else { + uint16_t add_ie_len = + assoc_add_ie->length; + + hdd_debug("Set OSEN IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (assoc_add_ie->length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + + memcpy(assoc_add_ie->addIEdata + + add_ie_len, genie - 2, eLen + 2); + assoc_add_ie->length += eLen + 2; + + roam_profile->pAddIEAssoc = + assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = + assoc_add_ie->length; + } + break; + case DOT11F_EID_RSN: + if (eLen > DOT11F_IE_RSN_MAX_LEN) { + hdd_err("%s: Invalid WPA RSN IE length[%d]", + __func__, eLen); + return -EINVAL; + } + memset(security_ie, 0, MAX_WPA_RSN_IE_LEN); + memcpy(security_ie, genie - 2, (eLen + 2)); + roam_profile->pRSNReqIE = security_ie; + roam_profile->nRSNReqIELength = eLen + 2; /* ie_len; */ + hdd_debug("Set RSN IE(len %d)", eLen + 2); + break; + /* + * Appending Extended Capabilities with Interworking bit set + * in Assoc Req. + * + * In assoc req this EXT Cap will only be taken into account if + * interworkingService bit is set to 1. Currently + * driver is only interested in interworkingService capability + * from supplicant. If in future any other EXT Cap info is + * required from supplicat, it needs to be handled while + * sending Assoc Req in LIM. + */ + case DOT11F_EID_EXTCAP: + { + uint16_t curAddIELen = + assoc_add_ie->length; + hdd_debug("Set Extended CAPS IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (assoc_add_ie->length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + memcpy(assoc_add_ie->addIEdata + curAddIELen, genie - 2, eLen + 2); + assoc_add_ie->length += eLen + 2; + + roam_profile->pAddIEAssoc = assoc_add_ie->addIEdata; + roam_profile->nAddIEAssocLength = assoc_add_ie->length; + break; + } +#ifdef FEATURE_WLAN_WAPI + case WLAN_EID_WAPI: + /* Setting WAPI Mode to ON=1 */ + adapter->wapi_info.wapi_mode = 1; + hdd_debug("WAPI MODE IS %u", adapter->wapi_info.wapi_mode); + /* genie is pointing to data field of WAPI IE's buffer */ + tmp = (uint8_t *)genie; + /* Validate length for Version(2 bytes) and Number + * of AKM suite (2 bytes) in WAPI IE buffer, coming from + * supplicant*/ + if (eLen < 4) { + hdd_err("Invalid IE Len: %u", eLen); + return -EINVAL; + } + tmp = tmp + 2; /* Skip Version */ + /* Get the number of AKM suite */ + akmsuiteCount = WPA_GET_LE16(tmp); + /* Skip the number of AKM suite */ + tmp = tmp + 2; + /* Validate total length for WAPI IE's buffer */ + if (eLen < (4 + (akmsuiteCount * sizeof(uint32_t)))) { + hdd_err("Invalid IE Len: %u", eLen); + return -EINVAL; + } + /* AKM suite list, each OUI contains 4 bytes */ + akmlist = (uint32_t *)(tmp); + if (akmsuiteCount <= MAX_NUM_AKM_SUITES) { + qdf_mem_copy(akmsuite, akmlist, + sizeof(uint32_t) * akmsuiteCount); + } else { + hdd_err("Invalid akmSuite count: %u", + akmsuiteCount); + QDF_ASSERT(0); + return -EINVAL; + } + + if (WAPI_PSK_AKM_SUITE == akmsuite[0]) { + hdd_debug("WAPI AUTH MODE SET TO PSK"); + adapter->wapi_info.wapi_auth_mode = + WAPI_AUTH_MODE_PSK; + } + if (WAPI_CERT_AKM_SUITE == akmsuite[0]) { + hdd_debug("WAPI AUTH MODE SET TO CERTIFICATE"); + adapter->wapi_info.wapi_auth_mode = + WAPI_AUTH_MODE_CERT; + } + break; +#endif + case DOT11F_EID_SUPPOPERATINGCLASSES: + { + hdd_debug("Set Supported Operating Classes IE(len %d)", eLen + 2); + status = wlan_hdd_add_assoc_ie(adapter, + genie - 2, eLen + 2); + if (status) + return status; + break; + } + case SIR_MAC_REQUEST_EID_MAX: + { + if (genie[0] == SIR_FILS_HLP_EXT_EID) { + hdd_debug("Set HLP EXT IE(len %d)", + eLen + 2); + wlan_hdd_save_hlp_ie(roam_profile, + genie - 2, eLen + 2, + true); + status = wlan_hdd_add_assoc_ie( + adapter, genie - 2, + eLen + 2); + if (status) + return status; + } else if (genie[0] == + SIR_DH_PARAMETER_ELEMENT_EXT_EID) { + hdd_debug("Set DH EXT IE(len %d)", + eLen + 2); + status = wlan_hdd_add_assoc_ie( + adapter, genie - 2, + eLen + 2); + if (status) + return status; + } else { + hdd_err("UNKNOWN EID: %X", genie[0]); + } + break; + } + case DOT11F_EID_FRAGMENT_IE: + { + hdd_debug("Set Fragment IE(len %d)", eLen + 2); + wlan_hdd_save_hlp_ie(roam_profile, + genie - 2, eLen + 2, + false); + status = wlan_hdd_add_assoc_ie(adapter, + genie - 2, eLen + 2); + if (status) + return status; + break; + } + default: + hdd_err("Set UNKNOWN IE: %X", elementId); + /* when Unknown IE is received we break + * and continue to the next IE in the buffer + */ + break; + } + genie += eLen; + remLen -= eLen; + } + return 0; +} + +/** + * hdd_is_wpaie_present() - check for WPA ie + * @ie: Pointer to ie + * @ie_len: Ie length + * + * Parse the received IE to find the WPA IE + * + * Return: true if wpa ie is found else false + */ +static bool hdd_is_wpaie_present(const uint8_t *ie, uint8_t ie_len) +{ + uint8_t eLen = 0; + uint16_t remLen = ie_len; + uint8_t elementId = 0; + + while (remLen >= 2) { + elementId = *ie++; + eLen = *ie++; + remLen -= 2; + if (eLen > remLen) { + hdd_err("Invalid IE length: %d", eLen); + return false; + } + if ((elementId == DOT11F_EID_WPA) && (remLen > 5)) { + /* OUI - 0x00 0X50 0XF2 + * WPA Information Element - 0x01 + * WPA version - 0x01 + */ + if (0 == memcmp(&ie[0], "\x00\x50\xf2\x01\x01", 5)) + return true; + } + ie += eLen; + remLen -= eLen; + } + return false; +} + +/** + * wlan_hdd_cfg80211_set_privacy() - set security parameters during connection + * @adapter: Pointer to adapter + * @req: Pointer to security parameters + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_privacy(struct hdd_adapter *adapter, + struct cfg80211_connect_params *req) +{ + int status = 0; + struct hdd_station_ctx *sta_ctx; + struct csr_roam_profile *roam_profile; + + hdd_enter(); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + sta_ctx->wpa_versions = req->crypto.wpa_versions; + hdd_debug("set wpa version to %d", sta_ctx->wpa_versions); + + roam_profile = hdd_roam_profile(adapter); + + /*set authentication type */ + status = wlan_hdd_cfg80211_set_auth_type(adapter, req->auth_type); + + if (wlan_hdd_is_conn_type_fils(req)) { + status = wlan_hdd_cfg80211_set_fils_config(adapter, req); + + if (0 > status) { + hdd_err("Failed to set fils config"); + return status; + } + } + + /*set key mgmt type */ + if (req->crypto.n_akm_suites) { + status = + wlan_hdd_set_akm_suite(adapter, req->crypto.akm_suites[0]); + if (0 > status) { + hdd_err("Failed to set akm suite"); + return status; + } + } + + /*set pairwise cipher type */ + if (req->crypto.n_ciphers_pairwise) { + status = wlan_hdd_cfg80211_set_cipher(adapter, + req->crypto. + ciphers_pairwise[0], + true); + if (0 > status) { + hdd_err("Failed to set unicast cipher type"); + return status; + } + } else { + /*Reset previous cipher suite to none */ + status = wlan_hdd_cfg80211_set_cipher(adapter, 0, true); + if (0 > status) { + hdd_err("Failed to set unicast cipher type"); + return status; + } + } + + /*set group cipher type */ + status = + wlan_hdd_cfg80211_set_cipher(adapter, req->crypto.cipher_group, + false); + + if (0 > status) { + hdd_err("Failed to set mcast cipher type"); + return status; + } +#ifdef WLAN_FEATURE_11W + roam_profile->MFPEnabled = (req->mfp == NL80211_MFP_REQUIRED); +#endif + + /*parse WPA/RSN IE, and set the correspoing fileds in Roam profile */ + if (req->ie_len) { + status = + wlan_hdd_cfg80211_set_ie(adapter, req->ie, req->ie_len); + if (0 > status) { + hdd_err("Failed to parse the WPA/RSN IE"); + return status; + } + } + + /*incase of WEP set default key information */ + if (req->key && req->key_len) { + u8 key_len = req->key_len; + u8 key_idx = req->key_idx; + u32 cipher = req->crypto.ciphers_pairwise[0]; + + if ((WLAN_CIPHER_SUITE_WEP40 == cipher) || + (WLAN_CIPHER_SUITE_WEP104 == cipher)) { + enum hdd_auth_key_mgmt key_mgmt = + sta_ctx->auth_key_mgmt; + + if (key_mgmt & HDD_AUTH_KEY_MGMT_802_1X) { + hdd_err("Dynamic WEP not supported"); + return -EOPNOTSUPP; + } + + if ((eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES >= key_len) + && (CSR_MAX_NUM_KEY > key_idx)) { + hdd_debug("setting default wep key, key_idx = %hu key_len %hu", + key_idx, key_len); + qdf_mem_copy(&roam_profile->Keys. + KeyMaterial[key_idx][0], + req->key, key_len); + roam_profile->Keys. + KeyLength[key_idx] = (u8) key_len; + roam_profile->Keys. + defaultIndex = (u8) key_idx; + } + } + } + + return status; +} + +/** + * wlan_hdd_clear_wapi_privacy() - reset WAPI settings in HDD layer + * @adapter: pointer to HDD adapter object + * + * This function resets all WAPI related parameters imposed before STA + * connection starts. It's invoked when privacy checking against concurrency + * fails, to make sure no improper WAPI settings are still populated before + * returning an error to the upper layer requester. + * + * Return: none + */ +#ifdef FEATURE_WLAN_WAPI +static inline void wlan_hdd_clear_wapi_privacy(struct hdd_adapter *adapter) +{ + adapter->wapi_info.wapi_mode = 0; + adapter->wapi_info.wapi_auth_mode = WAPI_AUTH_MODE_OPEN; +} +#else +static inline void wlan_hdd_clear_wapi_privacy(struct hdd_adapter *adapter) +{ +} +#endif + +/** + * wlan_hdd_cfg80211_clear_privacy() - reset STA security parameters + * @adapter: pointer to HDD adapter object + * + * This function resets all privacy related parameters imposed + * before STA connection starts. It's invoked when privacy checking + * against concurrency fails, to make sure no improper settings are + * still populated before returning an error to the upper layer requester. + * + * Return: none + */ +static void wlan_hdd_cfg80211_clear_privacy(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_debug("resetting all privacy configurations"); + + hdd_sta_ctx->wpa_versions = 0; + + hdd_sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_NONE; + hdd_sta_ctx->roam_profile.AuthType.authType[0] = eCSR_AUTH_TYPE_NONE; + + hdd_sta_ctx->conn_info.ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + hdd_sta_ctx->roam_profile.EncryptionType.numEntries = 0; + hdd_sta_ctx->conn_info.mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + hdd_sta_ctx->roam_profile.mcEncryptionType.numEntries = 0; + + wlan_hdd_clear_wapi_privacy(adapter); +} + +int wlan_hdd_try_disconnect(struct hdd_adapter *adapter) +{ + unsigned long rc; + struct hdd_station_ctx *sta_ctx; + int status, result = 0; + mac_handle_t mac_handle; + uint32_t wait_time = WLAN_WAIT_TIME_DISCONNECT; + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (adapter->device_mode == QDF_STA_MODE) { + hdd_debug("Stop firmware roaming"); + sme_stop_roaming(mac_handle, adapter->session_id, + eCsrForcedDisassoc); + + /* + * If firmware has already started roaming process, driver + * needs to wait for processing of this disconnect request. + * + */ + INIT_COMPLETION(adapter->roaming_comp_var); + if (hdd_is_roaming_in_progress(hdd_ctx)) { + rc = wait_for_completion_timeout( + &adapter->roaming_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_STOP_ROAM)); + if (!rc) { + hdd_err("roaming comp var timed out session Id: %d", + adapter->session_id); + } + if (adapter->roam_ho_fail) { + INIT_COMPLETION(adapter->disconnect_comp_var); + hdd_conn_set_connection_state(adapter, + eConnectionState_Disconnecting); + } + } + } + + if ((QDF_IBSS_MODE == adapter->device_mode) || + (eConnectionState_Associated == sta_ctx->conn_info.connState) || + (eConnectionState_Connecting == sta_ctx->conn_info.connState) || + (eConnectionState_IbssConnected == sta_ctx->conn_info.connState)) { + eConnectionState prev_conn_state; + + prev_conn_state = sta_ctx->conn_info.connState; + hdd_conn_set_connection_state(adapter, + eConnectionState_Disconnecting); + /* Issue disconnect to CSR */ + INIT_COMPLETION(adapter->disconnect_comp_var); + + status = sme_roam_disconnect(mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + + if ((status == QDF_STATUS_CMD_NOT_QUEUED) && + prev_conn_state != eConnectionState_Connecting) { + hdd_debug("Already disconnect in progress"); + result = 0; + /* + * Wait here instead of returning directly. This will + * block the connect command and allow processing + * of the disconnect in SME. As disconnect is already + * in progress, wait here for 1 sec instead of 5 sec. + */ + wait_time = WLAN_WAIT_DISCONNECT_ALREADY_IN_PROGRESS; + } else if (status == QDF_STATUS_CMD_NOT_QUEUED) { + /* + * Wait here instead of returning directly, this will + * block the connect command and allow processing + * of the scan for ssid and the previous connect command + * in CSR. + */ + hdd_debug("Already disconnected or connect was in sme/roam pending list and removed by disconnect"); + } else if (0 != status) { + hdd_err("sme_roam_disconnect failure, status: %d", + (int)status); + sta_ctx->sta_debug_state = status; + result = -EINVAL; + goto disconnected; + } + + rc = wait_for_completion_timeout(&adapter->disconnect_comp_var, + msecs_to_jiffies(wait_time)); + if (!rc && (QDF_STATUS_CMD_NOT_QUEUED != status)) { + hdd_err("Sme disconnect event timed out session Id: %d sta_debug_state: %d", + adapter->session_id, sta_ctx->sta_debug_state); + result = -ETIMEDOUT; + } + } else if (eConnectionState_Disconnecting == + sta_ctx->conn_info.connState) { + rc = wait_for_completion_timeout(&adapter->disconnect_comp_var, + msecs_to_jiffies(wait_time)); + if (!rc) { + hdd_err("Disconnect event timed out session Id: %d sta_debug_state: %d", + adapter->session_id, sta_ctx->sta_debug_state); + result = -ETIMEDOUT; + } + } +disconnected: + hdd_conn_set_connection_state(adapter, eConnectionState_NotConnected); + return result; +} + +/** + * wlan_hdd_reassoc_bssid_hint() - Start reassociation if bssid is present + * @adapter: Pointer to the HDD adapter + * @req: Pointer to the structure cfg_connect_params receieved from user space + * + * This function will start reassociation if prev_bssid is set and bssid/ + * bssid_hint, channel/channel_hint parameters are present in connect request. + * + * Return: 0 if connect was for ReAssociation, non-zero error code otherwise + */ +#if defined(CFG80211_CONNECT_PREV_BSSID) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +static int wlan_hdd_reassoc_bssid_hint(struct hdd_adapter *adapter, + struct cfg80211_connect_params *req) +{ + int status = -EINVAL; + const uint8_t *bssid = NULL; + uint16_t channel = 0; + struct hdd_station_ctx *sta_ctx; + + if (req->bssid) + bssid = req->bssid; + else if (req->bssid_hint) + bssid = req->bssid_hint; + + if (req->channel) + channel = req->channel->hw_value; + else if (req->channel_hint) + channel = req->channel_hint->hw_value; + + if (bssid && channel && req->prev_bssid) { + hdd_debug("REASSOC Attempt on channel %d to " MAC_ADDRESS_STR, + channel, MAC_ADDR_ARRAY(bssid)); + /* + * Save BSSID in a separate variable as + * roam_profile's BSSID is getting zeroed out in the + * association process. In case of join failure + * we should send valid BSSID to supplicant + */ + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + qdf_mem_copy(sta_ctx->requested_bssid.bytes, bssid, + QDF_MAC_ADDR_SIZE); + + status = hdd_reassoc(adapter, bssid, channel, + CONNECT_CMD_USERSPACE); + hdd_debug("hdd_reassoc: status: %d", status); + } + return status; +} +#else +static int wlan_hdd_reassoc_bssid_hint(struct hdd_adapter *adapter, + struct cfg80211_connect_params *req) +{ + return -ENOTSUPP; +} +#endif + + +/** + * wlan_hdd_check_ht20_ht40_ind() - check if Supplicant has indicated to + * connect in HT20 mode + * @hdd_ctx: hdd context + * @adapter: Pointer to the HDD adapter + * @req: Pointer to the structure cfg_connect_params receieved from user space + * + * This function will check if supplicant has indicated to to connect in HT20 + * mode. this is currently applicable only for 2.4Ghz mode only. + * if feature is enabled and supplicant indicate HT20 set + * force_24ghz_in_ht20 to true to force 2.4Ghz in HT20 else set it to false. + * + * Return: void + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0) +static void +wlan_hdd_check_ht20_ht40_ind(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct cfg80211_connect_params *req) +{ + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + + roam_profile->force_24ghz_in_ht20 = false; + + if (hdd_ctx->config->override_ht20_40_24g && + !(req->ht_capa.cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)) + roam_profile->force_24ghz_in_ht20 = true; + + hdd_debug("req->ht_capa.cap_info %x override_ht20_40_24g %d", + req->ht_capa.cap_info, + hdd_ctx->config->override_ht20_40_24g); +} +#else +static inline void +wlan_hdd_check_ht20_ht40_ind(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct cfg80211_connect_params *req) +{ + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + + roam_profile->force_24ghz_in_ht20 = false; +} +#endif + +/** + * __wlan_hdd_cfg80211_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @req: Pointer to cfg80211 connect request + * + * This function is used to start the association process + * + * 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 status; + u16 channel; + const u8 *bssid = NULL; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + const u8 *bssid_hint = req->bssid_hint; +#else + const u8 *bssid_hint = NULL; +#endif + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CONNECT, + adapter->session_id, adapter->device_mode); + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + 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", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (req->bssid) + bssid = req->bssid; + else if (bssid_hint) + bssid = bssid_hint; + + if (bssid && hdd_get_adapter_by_macaddr(hdd_ctx, (uint8_t *)bssid)) { + hdd_err("adapter exist with same mac address " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssid)); + return -EINVAL; + } + + /* + * Check if this is reassoc to same bssid, if reassoc is success, return + */ + status = wlan_hdd_reassoc_bssid_hint(adapter, req); + if (!status) { + hdd_set_roaming_in_progress(true); + return status; + } + + /* Try disconnecting if already in connected state */ + status = wlan_hdd_try_disconnect(adapter); + if (0 > status) { + hdd_err("Failed to disconnect the existing connection"); + return -EALREADY; + } + + /*initialise security parameters */ + status = wlan_hdd_cfg80211_set_privacy(adapter, req); + + if (status < 0) { + hdd_err("Failed to set security params"); + return status; + } + + /* + * Check for max concurrent connections after doing disconnect if any, + * must be called after the invocation of wlan_hdd_cfg80211_set_privacy + * so privacy is already set for the current adapter before it's + * checked against concurrency. + */ + if (req->channel) { + bool ok = false; + + if (req->channel->hw_value && policy_mgr_is_chan_ok_for_dnbs( + hdd_ctx->psoc, + req->channel->hw_value, + &ok)) { + hdd_warn("Unable to get channel:%d eligibility for DNBS", + req->channel->hw_value); + return -EINVAL; + } + /** + * Send connection timedout, so that Android framework does not + * blacklist us. + */ + if (!ok) { + struct ieee80211_channel *chan = + ieee80211_get_channel(wiphy, + wlan_chan_to_freq(req->channel->hw_value)); + struct cfg80211_bss *bss; + + hdd_warn("Channel:%d not OK for DNBS", + req->channel->hw_value); + if (chan) { + bss = hdd_cfg80211_get_bss(wiphy, + chan, + req->bssid, req->ssid, + req->ssid_len); + if (bss) { + cfg80211_assoc_timeout(ndev, bss); + return -ETIMEDOUT; + } + } + return -EINVAL; + } + + if (!policy_mgr_allow_concurrency(hdd_ctx->psoc, + policy_mgr_convert_device_mode_to_qdf_type( + adapter->device_mode), + req->channel->hw_value, HW_MODE_20_MHZ)) { + hdd_warn("This concurrency combination is not allowed"); + status = -ECONNREFUSED; + goto con_chk_failed; + } + } else { + if (!policy_mgr_allow_concurrency(hdd_ctx->psoc, + policy_mgr_convert_device_mode_to_qdf_type( + adapter->device_mode), 0, HW_MODE_20_MHZ)) { + hdd_warn("This concurrency combination is not allowed"); + status = -ECONNREFUSED; + goto con_chk_failed; + } + } + + if (req->channel) + channel = req->channel->hw_value; + else + channel = 0; + + wlan_hdd_check_ht20_ht40_ind(hdd_ctx, adapter, req); + + status = wlan_hdd_cfg80211_connect_start(adapter, req->ssid, + req->ssid_len, req->bssid, + bssid_hint, channel, 0); + if (0 > status) { + hdd_err("connect failed"); + } + return status; + +con_chk_failed: + wlan_hdd_cfg80211_clear_privacy(adapter); + hdd_exit(); + return status; +} + +/** + * wlan_hdd_cfg80211_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @dev: 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_connect(wiphy, ndev, req); + cds_ssr_unprotect(__func__); + + return ret; +} + +int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason) +{ + QDF_STATUS status; + int result = 0; + unsigned long rc; + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + eConnectionState prev_conn_state; + mac_handle_t mac_handle; + uint32_t wait_time = WLAN_WAIT_TIME_DISCONNECT; + + hdd_enter(); + + mac_handle = hdd_ctx->mac_handle; + if (adapter->device_mode == QDF_STA_MODE) { + hdd_debug("Stop firmware roaming"); + status = sme_stop_roaming(mac_handle, adapter->session_id, + eCsrForcedDisassoc); + /* + * If firmware has already started roaming process, driver + * needs to wait for processing of this disconnect request. + * + */ + INIT_COMPLETION(adapter->roaming_comp_var); + if (hdd_is_roaming_in_progress(hdd_ctx)) { + rc = wait_for_completion_timeout( + &adapter->roaming_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_STOP_ROAM)); + if (!rc) { + hdd_err("roaming comp var timed out session Id: %d", + adapter->session_id); + } + if (adapter->roam_ho_fail) { + INIT_COMPLETION(adapter->disconnect_comp_var); + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + hdd_conn_set_connection_state(adapter, + eConnectionState_Disconnecting); + goto wait_for_disconnect; + } + } + } + + prev_conn_state = sta_ctx->conn_info.connState; + /*stop tx queues */ + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, WLAN_CONTROL_PATH); + hdd_debug("Set HDD connState to eConnectionState_Disconnecting"); + hdd_conn_set_connection_state(adapter, eConnectionState_Disconnecting); + + INIT_COMPLETION(adapter->disconnect_comp_var); + + /* issue disconnect */ + + status = sme_roam_disconnect(mac_handle, + adapter->session_id, reason); + if ((QDF_STATUS_CMD_NOT_QUEUED == status) && + prev_conn_state != eConnectionState_Connecting) { + hdd_debug("status = %d, already disconnected", status); + result = 0; + /* + * Wait here instead of returning directly. This will block the + * next connect command and allow processing of the disconnect + * in SME else we might hit some race conditions leading to SME + * and HDD out of sync. As disconnect is already in progress, + * wait here for 1 sec instead of 5 sec. + */ + wait_time = WLAN_WAIT_DISCONNECT_ALREADY_IN_PROGRESS; + } else if (QDF_STATUS_CMD_NOT_QUEUED == status) { + /* + * Wait here instead of returning directly, this will block the + * next connect command and allow processing of the scan for + * ssid and the previous connect command in CSR. Else we might + * hit some race conditions leading to SME and HDD out of sync. + */ + hdd_debug("Already disconnected or connect was in sme/roam pending list and removed by disconnect"); + } else if (0 != status) { + hdd_err("csr_roam_disconnect failure, status: %d", (int)status); + sta_ctx->sta_debug_state = status; + result = -EINVAL; + goto disconnected; + } +wait_for_disconnect: + rc = wait_for_completion_timeout(&adapter->disconnect_comp_var, + msecs_to_jiffies(wait_time)); + + if (!rc && (QDF_STATUS_CMD_NOT_QUEUED != status)) { + hdd_err("Failed to disconnect, timed out"); + result = -ETIMEDOUT; + } +disconnected: + hdd_conn_set_connection_state(adapter, eConnectionState_NotConnected); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + /* Sending disconnect event to userspace for kernel version < 3.11 + * is handled by __cfg80211_disconnect call to __cfg80211_disconnected + */ + hdd_debug("Send disconnected event to userspace"); + wlan_hdd_cfg80211_indicate_disconnect(adapter->dev, true, + WLAN_REASON_UNSPECIFIED); +#endif + + return result; +} + +/** + * hdd_ieee80211_reason_code_to_str() - return string conversion of reason code + * @reason: ieee80211 reason code. + * + * This utility function helps log string conversion of reason code. + * + * Return: string conversion of reason code, if match found; + * "Unknown" otherwise. + */ +#ifdef WLAN_DEBUG +static const char *hdd_ieee80211_reason_code_to_str(uint16_t reason) +{ + switch (reason) { + CASE_RETURN_STRING(WLAN_REASON_UNSPECIFIED); + CASE_RETURN_STRING(WLAN_REASON_PREV_AUTH_NOT_VALID); + CASE_RETURN_STRING(WLAN_REASON_DEAUTH_LEAVING); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_AP_BUSY); + CASE_RETURN_STRING(WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); + CASE_RETURN_STRING(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_STA_HAS_LEFT); + CASE_RETURN_STRING(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_BAD_POWER); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_BAD_SUPP_CHAN); + CASE_RETURN_STRING(WLAN_REASON_INVALID_IE); + CASE_RETURN_STRING(WLAN_REASON_MIC_FAILURE); + CASE_RETURN_STRING(WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_IE_DIFFERENT); + CASE_RETURN_STRING(WLAN_REASON_INVALID_GROUP_CIPHER); + CASE_RETURN_STRING(WLAN_REASON_INVALID_PAIRWISE_CIPHER); + CASE_RETURN_STRING(WLAN_REASON_INVALID_AKMP); + CASE_RETURN_STRING(WLAN_REASON_UNSUPP_RSN_VERSION); + CASE_RETURN_STRING(WLAN_REASON_INVALID_RSN_IE_CAP); + CASE_RETURN_STRING(WLAN_REASON_IEEE8021X_FAILED); + CASE_RETURN_STRING(WLAN_REASON_CIPHER_SUITE_REJECTED); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_UNSPECIFIED_QOS); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_LOW_ACK); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_QAP_EXCEED_TXOP); + CASE_RETURN_STRING(WLAN_REASON_QSTA_LEAVE_QBSS); + CASE_RETURN_STRING(WLAN_REASON_QSTA_NOT_USE); + CASE_RETURN_STRING(WLAN_REASON_QSTA_REQUIRE_SETUP); + CASE_RETURN_STRING(WLAN_REASON_QSTA_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_QSTA_CIPHER_NOT_SUPP); + CASE_RETURN_STRING(WLAN_REASON_MESH_PEER_CANCELED); + CASE_RETURN_STRING(WLAN_REASON_MESH_MAX_PEERS); + CASE_RETURN_STRING(WLAN_REASON_MESH_CONFIG); + CASE_RETURN_STRING(WLAN_REASON_MESH_CLOSE); + CASE_RETURN_STRING(WLAN_REASON_MESH_MAX_RETRIES); + CASE_RETURN_STRING(WLAN_REASON_MESH_CONFIRM_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_MESH_INVALID_GTK); + CASE_RETURN_STRING(WLAN_REASON_MESH_INCONSISTENT_PARAM); + CASE_RETURN_STRING(WLAN_REASON_MESH_INVALID_SECURITY); + CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_ERROR); + CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_NOFORWARD); + CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE); + CASE_RETURN_STRING(WLAN_REASON_MAC_EXISTS_IN_MBSS); + CASE_RETURN_STRING(WLAN_REASON_MESH_CHAN_REGULATORY); + CASE_RETURN_STRING(WLAN_REASON_MESH_CHAN); + default: + return "Unknown"; + } +} +#endif + +/** + * 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 + */ +static 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++) { +#ifdef WLAN_DEBUG + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); +#endif + + hdd_debug("netdev tx queue[%u] state: 0x%lx", i, txq->state); + } +} + +/** + * __wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @reason: Disconnect reason code + * + * This function is used to issue a disconnect request to SME + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int status; + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + 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_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DISCONNECT, + adapter->session_id, reason); + + hdd_print_netdev_txq_status(dev); + hdd_debug("Device_mode %s(%d) reason code(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode, reason); + + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + qdf_mutex_acquire(&adapter->disconnection_status_lock); + if (adapter->disconnection_in_progress) { + qdf_mutex_release(&adapter->disconnection_status_lock); + hdd_debug("Disconnect is already in progress"); + return 0; + } + adapter->disconnection_in_progress = true; + qdf_mutex_release(&adapter->disconnection_status_lock); + + /* Issue disconnect request to SME, if station is in connected state */ + if ((sta_ctx->conn_info.connState == eConnectionState_Associated) || + (sta_ctx->conn_info.connState == eConnectionState_Connecting)) { + eCsrRoamDisconnectReason reasonCode = + eCSR_DISCONNECT_REASON_UNSPECIFIED; + + switch (reason) { + case WLAN_REASON_MIC_FAILURE: + reasonCode = eCSR_DISCONNECT_REASON_MIC_ERROR; + break; + + case WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY: + case WLAN_REASON_DISASSOC_AP_BUSY: + case WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA: + reasonCode = eCSR_DISCONNECT_REASON_DISASSOC; + break; + + case WLAN_REASON_PREV_AUTH_NOT_VALID: + case WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA: + reasonCode = eCSR_DISCONNECT_REASON_DEAUTH; + break; + + case WLAN_REASON_DEAUTH_LEAVING: + reasonCode = + hdd_ctx->config-> + gEnableDeauthToDisassocMap ? + eCSR_DISCONNECT_REASON_STA_HAS_LEFT : + eCSR_DISCONNECT_REASON_DEAUTH; + qdf_dp_trace_dump_all( + WLAN_DEAUTH_DPTRACE_DUMP_COUNT, + QDF_TRACE_DEFAULT_PDEV_ID); + break; + case WLAN_REASON_DISASSOC_STA_HAS_LEFT: + reasonCode = eCSR_DISCONNECT_REASON_STA_HAS_LEFT; + break; + default: + reasonCode = eCSR_DISCONNECT_REASON_UNSPECIFIED; + break; + } + + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev && + ucfg_scan_get_vdev_status(vdev) != SCAN_NOT_IN_PROGRESS) { + hdd_debug("Disconnect is in progress, Aborting Scan"); + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_id, INVALID_SCAN_ID, + false); + } + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + /* First clean up the tdls peers if any */ + hdd_notify_sta_disconnect(adapter->session_id, + false, true, vdev); + if (vdev) + hdd_objmgr_put_vdev(vdev); + + hdd_info("Disconnect from userspace; reason:%d (%s)", + reason, hdd_ieee80211_reason_code_to_str(reason)); + status = wlan_hdd_disconnect(adapter, reasonCode); + if (0 != status) { + hdd_err("wlan_hdd_disconnect failed, status: %d", status); + hdd_set_disconnect_status(adapter, false); + return -EINVAL; + } + } else { + hdd_err("Unexpected cfg disconnect called while in state: %d", + sta_ctx->conn_info.connState); + hdd_set_disconnect_status(adapter, false); + } + + return status; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_disconnect(wiphy, dev, reason); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_set_privacy_ibss() - set ibss privacy + * @adapter: Pointer to adapter + * @param: Pointer to IBSS parameters + * + * This function is used to initialize the security settings in IBSS mode + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_privacy_ibss(struct hdd_adapter *adapter, + struct cfg80211_ibss_params + *params) +{ + uint32_t ret; + int status = 0; + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct csr_roam_profile *roam_profile; + + hdd_enter(); + + sta_ctx->wpa_versions = 0; + qdf_mem_zero(&sta_ctx->ibss_enc_key, sizeof(tCsrRoamSetKey)); + sta_ctx->ibss_enc_key_installed = 0; + + if (params->ie_len && (NULL != params->ie)) { + if (wlan_get_ie_ptr_from_eid(WLAN_EID_RSN, params->ie, + params->ie_len)) { + sta_ctx->wpa_versions = NL80211_WPA_VERSION_2; + encryptionType = eCSR_ENCRYPT_TYPE_AES; + } else if (hdd_is_wpaie_present(params->ie, params->ie_len)) { + tDot11fIEWPA dot11WPAIE; + mac_handle_t mac_handle = + hdd_adapter_get_mac_handle(adapter); + const u8 *ie; + + memset(&dot11WPAIE, 0, sizeof(dot11WPAIE)); + ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_WPA, + params->ie, params->ie_len); + if (NULL != ie) { + sta_ctx->wpa_versions = NL80211_WPA_VERSION_1; + /* Unpack the WPA IE + * Skip past the EID byte and length byte + * and four byte WiFi OUI + */ + if (ie[1] < DOT11F_IE_WPA_MIN_LEN || + ie[1] > DOT11F_IE_WPA_MAX_LEN) { + hdd_err("invalid ie len:%d", ie[1]); + return -EINVAL; + } + ret = dot11f_unpack_ie_wpa( + (tpAniSirGlobal) mac_handle, + (uint8_t *)&ie[2 + 4], + ie[1] - 4, &dot11WPAIE, false); + if (DOT11F_FAILED(ret)) { + hdd_err("unpack failed ret: 0x%x", ret); + return -EINVAL; + } + /* + * Extract the multicast cipher, the + * encType for unicast cipher for + * wpa-none is none + */ + encryptionType = + hdd_translate_wpa_to_csr_encryption_type + (dot11WPAIE.multicast_cipher); + } + } + + status = + wlan_hdd_cfg80211_set_ie(adapter, params->ie, + params->ie_len); + + if (0 > status) { + hdd_err("Failed to parse WPA/RSN IE"); + return status; + } + } + + roam_profile = hdd_roam_profile(adapter); + roam_profile->AuthType.authType[0] = + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + if (params->privacy) { + /* Security enabled IBSS, At this time there is no information + * available about the security parameters, so initialise the + * encryption type to eCSR_ENCRYPT_TYPE_WEP40_STATICKEY. + * The correct security parameters will be updated later in + * wlan_hdd_cfg80211_add_key Hal expects encryption type to be + * set inorder enable privacy bit in beacons + */ + + encryptionType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + hdd_debug("encryptionType=%d", encryptionType); + sta_ctx->conn_info.ucEncryptionType = encryptionType; + roam_profile->EncryptionType.numEntries = 1; + roam_profile->EncryptionType.encryptionType[0] = + encryptionType; + return status; +} + +/** + * __wlan_hdd_cfg80211_join_ibss() - join ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to IBSS join parameters + * + * This function is used to create/join an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct csr_roam_profile *roam_profile; + int status; + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct qdf_mac_addr bssid; + u8 channelNum = 0; + mac_handle_t mac_handle; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_JOIN_IBSS, + adapter->session_id, adapter->device_mode); + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + mac_handle = hdd_ctx->mac_handle; + if (NULL != + params->chandef.chan) { + uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + int indx; + + /* Get channel number */ + channelNum = ieee80211_frequency_to_channel( + params-> + chandef. + chan-> + center_freq); + + if (0 != sme_cfg_get_str(mac_handle, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans)) { + hdd_err("No valid channel list"); + return -EOPNOTSUPP; + } + + for (indx = 0; indx < numChans; indx++) { + if (channelNum == validChan[indx]) + break; + } + if (indx >= numChans) { + hdd_err("Not valid Channel: %d", channelNum); + return -EINVAL; + } + } + + if (!policy_mgr_allow_concurrency(hdd_ctx->psoc, + PM_IBSS_MODE, channelNum, HW_MODE_20_MHZ)) { + hdd_err("This concurrency combination is not allowed"); + return -ECONNREFUSED; + } + + status = policy_mgr_reset_connection_update(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("qdf_reset_connection_update failed status: %d", status); + + status = policy_mgr_current_connections_update(hdd_ctx->psoc, + adapter->session_id, channelNum, + POLICY_MGR_UPDATE_REASON_JOIN_IBSS); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("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; + } + } + + /*Try disconnecting if already in connected state */ + status = wlan_hdd_try_disconnect(adapter); + if (0 > status) { + hdd_err("Failed to disconnect the existing IBSS connection"); + return -EALREADY; + } + + roam_profile = hdd_roam_profile(adapter); + + if (eCSR_BSS_TYPE_START_IBSS != roam_profile->BSSType) { + hdd_err("Interface type is not set to IBSS"); + return -EINVAL; + } + + /* enable selected protection checks in IBSS mode */ + roam_profile->cfg_protection = IBSS_CFG_PROTECTION_ENABLE_MASK; + + if (QDF_STATUS_E_FAILURE == sme_cfg_set_int(mac_handle, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + hdd_ctx->config-> + ibssATIMWinSize)) { + hdd_err("Could not pass on WNI_CFG_IBSS_ATIM_WIN_SIZE to CCM"); + } + + /* BSSID is provided by upper layers hence no need to AUTO generate */ + if (NULL != params->bssid) { + if (sme_cfg_set_int(mac_handle, WNI_CFG_IBSS_AUTO_BSSID, 0) + == QDF_STATUS_E_FAILURE) { + hdd_err("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID"); + return -EIO; + } + qdf_mem_copy(bssid.bytes, params->bssid, QDF_MAC_ADDR_SIZE); + } else if (hdd_ctx->config->isCoalesingInIBSSAllowed == 0) { + if (sme_cfg_set_int(mac_handle, WNI_CFG_IBSS_AUTO_BSSID, 0) + == QDF_STATUS_E_FAILURE) { + hdd_err("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID"); + return -EIO; + } + qdf_copy_macaddr(&bssid, &hdd_ctx->config->IbssBssid); + } + if ((params->beacon_interval > CFG_BEACON_INTERVAL_MIN) + && (params->beacon_interval <= CFG_BEACON_INTERVAL_MAX)) + roam_profile->beaconInterval = params->beacon_interval; + else { + roam_profile->beaconInterval = CFG_BEACON_INTERVAL_DEFAULT; + hdd_debug("input beacon interval %d TU is invalid, use default %d TU", + params->beacon_interval, roam_profile->beaconInterval); + } + + /* Set Channel */ + if (channelNum) { + /* Set the Operational Channel */ + hdd_debug("set channel %d", channelNum); + roam_profile->ChannelInfo.numOfChannels = 1; + sta_ctx->conn_info.operationChannel = channelNum; + roam_profile->ChannelInfo.ChannelList = + &sta_ctx->conn_info.operationChannel; + } + + /* Initialize security parameters */ + status = wlan_hdd_cfg80211_set_privacy_ibss(adapter, params); + if (status < 0) { + hdd_err("failed to set security parameters"); + return status; + } + + /* Issue connect start */ + status = wlan_hdd_cfg80211_connect_start(adapter, params->ssid, + params->ssid_len, + bssid.bytes, NULL, + sta_ctx->conn_info. + operationChannel, + params->chandef.width); + + if (0 > status) { + hdd_err("connect failed"); + return status; + } + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_join_ibss() - join ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to IBSS join parameters + * + * This function is used to create/join an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_join_ibss(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_leave_ibss() - leave ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * This function is used to leave an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct csr_roam_profile *roam_profile; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int status; + mac_handle_t mac_handle; + unsigned long rc; + tSirUpdateIE updateIE; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_LEAVE_IBSS, + adapter->session_id, eCSR_DISCONNECT_REASON_IBSS_LEAVE); + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + roam_profile = hdd_roam_profile(adapter); + + /* Issue disconnect only if interface type is set to IBSS */ + if (eCSR_BSS_TYPE_START_IBSS != roam_profile->BSSType) { + hdd_err("BSS Type is not set to IBSS"); + return -EINVAL; + } + /* Clearing add IE of beacon */ + qdf_mem_copy(updateIE.bssid.bytes, adapter->mac_addr.bytes, + sizeof(tSirMacAddr)); + updateIE.smeSessionId = adapter->session_id; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = true; + mac_handle = hdd_ctx->mac_handle; + if (sme_update_add_ie(mac_handle, + &updateIE, + eUPDATE_IE_PROBE_BCN) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } + + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(adapter); + + /* Issue Disconnect request */ + INIT_COMPLETION(adapter->disconnect_comp_var); + status = sme_roam_disconnect(mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_roam_disconnect failed status: %d", + status); + return -EAGAIN; + } + + /* wait for mc thread to cleanup and then return to upper stack + * so by the time upper layer calls the change interface, we are + * all set to proceed further + */ + rc = wait_for_completion_timeout(&adapter->disconnect_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) { + hdd_err("Failed to disconnect, timed out"); + return -ETIMEDOUT; + } + + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_leave_ibss() - leave ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * This function is used to leave an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_leave_ibss(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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); + mac_handle_t mac_handle; + 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; + + mac_handle = hdd_ctx->mac_handle; + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + u32 rts_threshold = (wiphy->rts_threshold == -1) ? + WNI_CFG_RTS_THRESHOLD_STAMAX : wiphy->rts_threshold; + + if ((WNI_CFG_RTS_THRESHOLD_STAMIN > rts_threshold) || + (WNI_CFG_RTS_THRESHOLD_STAMAX < rts_threshold)) { + hdd_err("Invalid RTS Threshold value: %u", + rts_threshold); + return -EINVAL; + } + + if (0 != sme_cfg_set_int(mac_handle, WNI_CFG_RTS_THRESHOLD, + rts_threshold)) { + hdd_err("sme_cfg_set_int failed for rts_threshold value %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) ? + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX : + wiphy->frag_threshold; + + if ((WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN > frag_threshold) || + (WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX < frag_threshold)) { + hdd_err("Invalid frag_threshold value %hu", + frag_threshold); + return -EINVAL; + } + + if (0 != sme_cfg_set_int(mac_handle, + WNI_CFG_FRAGMENTATION_THRESHOLD, + frag_threshold)) { + hdd_err("sme_cfg_set_int failed for frag_threshold value %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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_wiphy_params(wiphy, changed); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_set_default_mgmt_key() - dummy implementation of set default mgmt + * key + * @wiphy: Pointer to wiphy + * @dev: 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 + * @netdev: pointer to net_device structure + * @key_index: key index + * + * Return: 0 on success, error number on failure + */ +static int wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_default_mgmt_key(wiphy, netdev, key_index); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_set_txq_params() - dummy implementation of set tx queue params + * @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) +{ + hdd_enter(); + return 0; +} + +/** + * wlan_hdd_set_txq_params() - SSR wrapper for wlan_hdd_set_txq_params + * @wiphy: pointer to wiphy + * @netdev: 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_txq_params(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_del_station() - delete station v2 + * @wiphy: Pointer to wiphy + * @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 *pDelStaParams) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct hdd_hostapd_state *hapd_state; + uint8_t staId; + uint8_t *mac; + mac_handle_t mac_handle; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DEL_STA, + adapter->session_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 *) pDelStaParams->peerMacAddr.bytes; + mac_handle = hdd_ctx->mac_handle; + + if ((QDF_SAP_MODE == adapter->device_mode) || + (QDF_P2P_GO_MODE == adapter->device_mode)) { + + hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (!hapd_state) { + hdd_err("Hostapd State is Null"); + return 0; + } + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *) mac)) { + uint16_t i; + + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if ((adapter->sta_info[i].in_use) && + (!adapter->sta_info[i]. + is_deauth_in_progress)) { + qdf_mem_copy( + mac, + adapter->sta_info[i]. + sta_mac.bytes, + QDF_MAC_ADDR_SIZE); + + hdd_debug("Delete STA with MAC::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + + if (hdd_ctx->dev_dfs_cac_status == + DFS_CAC_IN_PROGRESS) + goto fn_end; + + qdf_event_reset(&hapd_state->qdf_sta_disassoc_event); + qdf_status = + hdd_softap_sta_deauth(adapter, + pDelStaParams); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + adapter->sta_info[i]. + is_deauth_in_progress = true; + qdf_status = + qdf_wait_for_event_completion( + &hapd_state-> + qdf_sta_disassoc_event, + SME_CMD_TIMEOUT_VALUE); + if (!QDF_IS_STATUS_SUCCESS( + qdf_status)) + hdd_warn("Deauth wait time expired"); + } + } + } + } else { + qdf_status = + hdd_softap_get_sta_id(adapter, + (struct qdf_mac_addr *) mac, + &staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_debug("Skip DEL STA as this is not used::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } + + if (adapter->sta_info[staId].is_deauth_in_progress == + true) { + hdd_debug("Skip DEL STA as deauth is in progress::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } + + adapter->sta_info[staId].is_deauth_in_progress = true; + + hdd_debug("Delete STA with MAC::" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + + /* Case: SAP in ACS selected DFS ch and client connected + * Now Radar detected. Then if random channel is another + * DFS ch then new CAC is initiated and no TX allowed. + * So do not send any mgmt frames as it will timeout + * during CAC. + */ + + if (hdd_ctx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS) + goto fn_end; + + qdf_event_reset(&hapd_state->qdf_sta_disassoc_event); + sme_send_disassoc_req_frame(mac_handle, + adapter->session_id, + (uint8_t *)&pDelStaParams->peerMacAddr, + pDelStaParams->reason_code, 0); + qdf_status = hdd_softap_sta_deauth(adapter, + pDelStaParams); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + adapter->sta_info[staId].is_deauth_in_progress = + false; + hdd_debug("STA removal failed for ::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } + qdf_status = qdf_wait_for_event_completion( + &hapd_state-> + qdf_sta_disassoc_event, + SME_CMD_TIMEOUT_VALUE); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_warn("Deauth wait time expired"); + + } + } + +fn_end: + hdd_exit(); + return 0; +} + +#if defined(USE_CFG80211_DEL_STA_V2) +/** + * wlan_hdd_del_station() - delete station wrapper + * @adapter: pointer to the hdd adapter + * + * Return: None + */ +void wlan_hdd_del_station(struct hdd_adapter *adapter) +{ + struct station_del_parameters del_sta; + + del_sta.mac = NULL; + del_sta.subtype = SIR_MAC_MGMT_DEAUTH >> 4; + del_sta.reason_code = eCsrForcedDeauthSta; + + wlan_hdd_cfg80211_del_station(adapter->wdev.wiphy, adapter->dev, + &del_sta); +} +#else +void wlan_hdd_del_station(struct hdd_adapter *adapter) +{ + wlan_hdd_cfg80211_del_station(adapter->wdev.wiphy, adapter->dev, NULL); +} +#endif + +#if defined(USE_CFG80211_DEL_STA_V2) +/** + * wlan_hdd_cfg80211_del_station() - delete station v2 + * @wiphy: Pointer to wiphy + * @param: Pointer to delete station parameter + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param) +#else +/** + * wlan_hdd_cfg80211_del_station() - delete station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * + * Return: 0 for success, non-zero for failure + */ +#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 +{ + int ret; + struct csr_del_sta_params delStaParams; + + cds_ssr_protect(__func__); +#if defined(USE_CFG80211_DEL_STA_V2) + if (NULL == param) { + hdd_err("Invalid argument passed"); + return -EINVAL; + } + wlansap_populate_del_sta_params(param->mac, param->reason_code, + param->subtype, &delStaParams); +#else + wlansap_populate_del_sta_params(mac, eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); +#endif + ret = __wlan_hdd_cfg80211_del_station(wiphy, dev, &delStaParams); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * @pmksa: 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; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_STA, + adapter->session_id, params->listen_interval); + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + mask = params->sta_flags_mask; + + set = params->sta_flags_set; + + hdd_debug("mask 0x%x set 0x%x " MAC_ADDRESS_STR, mask, set, + MAC_ADDR_ARRAY(mac)); + + if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + status = wlan_cfg80211_tdls_add_peer(vdev, + mac); + hdd_objmgr_put_vdev(vdev); + } + } + } +#endif + hdd_exit(); + return status; +} + +/** + * wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * @pmksa: 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_add_station(wiphy, dev, mac, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 (%pK) is NULL", + pmksa->bssid); + if (!pmksa->ssid || !pmksa->cache_id) { + hdd_err("either ssid (%pK) or cache_id (%pK) are NULL", + pmksa->ssid, pmksa->cache_id); + 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 udated + * @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, + tPmkidCacheInfo *pmk_cache, + struct cfg80211_pmksa *pmksa, bool is_delete) +{ + if (pmksa->bssid) { + hdd_debug("%s PMKSA for " MAC_ADDRESS_STR, + is_delete ? "Delete" : "Set", + MAC_ADDR_ARRAY(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 %*.*s cache_id %x %x", + is_delete ? "Delete" : "Set", + pmk_cache->ssid_len, pmk_cache->ssid_len, + pmk_cache->ssid, pmk_cache->cache_id[0], + pmk_cache->cache_id[1]); + } + + if (is_delete) + return; + + qdf_mem_copy(pmk_cache->PMKID, pmksa->pmkid, CSR_RSN_PMKID_SIZE); + if (pmksa->pmk_len && (pmksa->pmk_len <= CSR_RSN_MAX_PMK_LEN)) { + qdf_mem_copy(pmk_cache->pmk, pmksa->pmk, pmksa->pmk_len); + pmk_cache->pmk_len = pmksa->pmk_len; + } else + hdd_debug("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 tPmkidCacheInfo 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, + tPmkidCacheInfo *pmk_cache, + struct cfg80211_pmksa *pmksa, bool is_delete) +{ + mac_handle_t mac_handle; + hdd_debug("%s PMKSA for " MAC_ADDRESS_STR, is_delete ? "Delete" : "Set", + MAC_ADDR_ARRAY(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->session_id, pmk_cache); + qdf_mem_copy(pmk_cache->PMKID, pmksa->pmkid, CSR_RSN_PMKID_SIZE); +} +#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); + mac_handle_t mac_handle; + QDF_STATUS result = QDF_STATUS_SUCCESS; + int status; + tPmkidCacheInfo 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_session_id(adapter->session_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; + + mac_handle = hdd_ctx->mac_handle; + + qdf_mem_zero(&pmk_cache, sizeof(pmk_cache)); + + 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 = sme_roam_set_pmkid_cache(mac_handle, adapter->session_id, + &pmk_cache, 1, false); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_PMKSA, + adapter->session_id, result); + + sme_set_del_pmkid_cache(mac_handle, adapter->session_id, + &pmk_cache, true); + + qdf_mem_zero(&pmk_cache, sizeof(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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_pmksa(wiphy, dev, pmksa); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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); + mac_handle_t mac_handle; + int status = 0; + tPmkidCacheInfo 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_session_id(adapter->session_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; + + mac_handle = hdd_ctx->mac_handle; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DEL_PMKSA, + adapter->session_id, 0); + + qdf_mem_zero(&pmk_cache, sizeof(pmk_cache)); + + hdd_fill_pmksa_info(adapter, &pmk_cache, pmksa, true); + + /* Delete the PMKID CSR cache */ + if (QDF_STATUS_SUCCESS != + sme_roam_del_pmkid_from_cache(mac_handle, + adapter->session_id, &pmk_cache, + false)) { + hdd_err("Failed to delete PMKSA for " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pmksa->bssid)); + status = -EINVAL; + } + + sme_set_del_pmkid_cache(mac_handle, adapter->session_id, &pmk_cache, + false); + qdf_mem_zero(&pmk_cache, sizeof(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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_del_pmksa(wiphy, dev, pmksa); + cds_ssr_unprotect(__func__); + + return ret; + +} + +/** + * __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); + mac_handle_t mac_handle; + 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_session_id(adapter->session_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; + + mac_handle = hdd_ctx->mac_handle; + + status = sme_roam_del_pmkid_from_cache(mac_handle, + adapter->session_id, + NULL, true); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Cannot flush PMKIDCache"); + errno = -EINVAL; + } + + sme_set_del_pmkid_cache(mac_handle, adapter->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_flush_pmksa(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + int status; + mac_handle_t mac_handle; + + 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_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES, + adapter->session_id, sta_ctx->conn_info.connState); + + /* Added for debug on reception of Re-assoc Req. */ + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + hdd_err("Called with Ie of length = %zu when not associated", + ftie->ie_len); + hdd_err("Should be Re-assoc Req IEs"); + } + hdd_debug("%s called with Ie of length = %zu", __func__, + ftie->ie_len); + + /* Pass the received FT IEs to SME */ + mac_handle = hdd_ctx->mac_handle; + sme_set_ft_ies(mac_handle, adapter->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_update_ft_ies(wiphy, dev, ftie); + cds_ssr_unprotect(__func__); + + return ret; +} +#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 %pM", 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 + */ +#ifdef CFG80211_REKEY_DATA_KEK_LEN +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_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; + 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_session_id(adapter->session_id)) { + result = -EINVAL; + goto out; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA, + adapter->session_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) { + hdd_err("cannot allocate 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); + qdf_mem_copy(gtk_req->kck, data->kck, NL80211_KCK_LEN); + gtk_req->is_fils_connection = hdd_is_fils_connection(adapter); + status = pmo_ucfg_cache_gtk_offload_req(adapter->vdev, gtk_req); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_rekey_data(wiphy, dev, data); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +/** + * __wlan_hdd_cfg80211_set_mac_acl() - set access control policy + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: 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; + tsap_config_t *pConfig; + 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 (NULL == 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); + + if (NULL == 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->session_id, adapter->device_mode); + + if (QDF_SAP_MODE == adapter->device_mode) { + pConfig = &adapter->session.ap.sap_config; + + /* default value */ + pConfig->num_accept_mac = 0; + pConfig->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) { + pConfig->SapMacaddr_acl = eSAP_DENY_UNLESS_ACCEPTED; + } else if (NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED == + params->acl_policy) { + pConfig->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 == pConfig->SapMacaddr_acl) { + pConfig->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 :" + MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY( + params->mac_addrs[i].addr)); + + qdf_mem_copy(&pConfig->accept_mac[i], + params->mac_addrs[i].addr, + sizeof(qcmacaddr)); + } + } else if (eSAP_ACCEPT_UNLESS_DENIED == pConfig->SapMacaddr_acl) { + pConfig->num_deny_mac = params->n_acl_entries; + for (i = 0; i < params->n_acl_entries; i++) { + hdd_debug("** Add ACL MAC entry %i in BlackList :" + MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY( + params->mac_addrs[i].addr)); + + qdf_mem_copy(&pConfig->deny_mac[i], + params->mac_addrs[i].addr, + sizeof(qcmacaddr)); + } + } + qdf_status = wlansap_set_mac_acl( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), pConfig); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SAP Set Mac Acl fail"); + return -EINVAL; + } + } else { + hdd_debug("Invalid device_mode %s(%d)", + hdd_device_mode_to_string(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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_mac_acl(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 + * @lphbInd: 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 (NULL == hb_params) { + hdd_err("Request Buffer Alloc Fail"); + return -ENOMEM; + } + + qdf_mem_zero(hb_params, sizeof(*hb_params)); + qdf_mem_copy(hb_params, buf, buf_len); + status = pmo_ucfg_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("Command not allowed in FTM 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 + * @dev: Pointer to network 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_testmode(wiphy, data, len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_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; + + hdd_debug("Channel width changed to %d ", + cfg80211_get_chandef_type(chandef)); + + /* Change SAP ht2040 mode */ + status = hdd_set_sap_ht2040_mode(adapter, + cfg80211_get_chandef_type(chandef)); + 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 + * @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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ap_channel_width(wiphy, dev, chandef); + cds_ssr_unprotect(__func__); + + return ret; +} +#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; + uint8_t channel; + uint16_t freq; + int ret; + enum phy_ch_width ch_width; + + hdd_debug("Set Freq %d", + csa_params->chandef.chan->center_freq); + + if (wlan_hdd_validate_session_id(adapter->session_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; + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->session_id, + CSA_REASON_USER_INITIATED); + + freq = csa_params->chandef.chan->center_freq; + channel = cds_freq_to_chan(freq); + + ch_width = hdd_map_nl_chan_width(csa_params->chandef.width); + + ret = hdd_softap_set_channel_change(dev, channel, ch_width, false); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_channel_switch(wiphy, dev, csa_params); + cds_ssr_unprotect(__func__); + return ret; +} +#endif + +/** + * wlan_hdd_convert_nl_iftype_to_hdd_type() - provides the type + * translation from NL to policy manager type + * @type: Generic connection mode type defined in NL + * + * + * This function provides the type translation + * + * Return: cds_con_mode enum + */ +enum policy_mgr_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type( + enum nl80211_iftype type) +{ + enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE; + + switch (type) { + case NL80211_IFTYPE_STATION: + mode = PM_STA_MODE; + break; + case NL80211_IFTYPE_P2P_CLIENT: + mode = PM_P2P_CLIENT_MODE; + break; + case NL80211_IFTYPE_P2P_GO: + mode = PM_P2P_GO_MODE; + break; + case NL80211_IFTYPE_AP: + mode = PM_SAP_MODE; + break; + case NL80211_IFTYPE_ADHOC: + mode = PM_IBSS_MODE; + break; + default: + hdd_err("Unsupported interface type: %d", type); + } + return mode; +} + +int wlan_hdd_change_hw_mode_for_given_chnl(struct hdd_adapter *adapter, + uint8_t channel, + enum policy_mgr_conn_update_reason reason) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + 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->session_id, channel, reason); + 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:%d (SMM->DBS)", channel); + 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 csr_roam_profile roam_profile; + struct ch_params ch_params; + uint8_t sec_ch = 0; + int ret; + uint16_t chan_num = cds_freq_to_chan(chandef->chan->center_freq); + + 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 Channel %d and freq %d", + adapter->dev->name, chan_num, chandef->chan->center_freq); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + ch_info = &sta_ctx->ch_info; + roam_profile.ChannelInfo.ChannelList = &ch_info->channel; + roam_profile.ChannelInfo.numOfChannels = 1; + roam_profile.phyMode = ch_info->phy_mode; + roam_profile.ch_params.ch_width = hdd_map_nl_chan_width(chandef->width); + hdd_select_cbmode(adapter, chan_num, &roam_profile.ch_params); + + qdf_mem_copy(bssid.bytes, adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = hdd_map_nl_chan_width(chandef->width); + /* + * CDS api expects secondary channel for calculating + * the channel params + */ + if ((ch_params.ch_width == CH_WIDTH_40MHZ) && + (WLAN_REG_IS_24GHZ_CH(chan_num))) { + if (chan_num >= 1 && chan_num <= 5) + sec_ch = chan_num + 4; + else if (chan_num >= 6 && chan_num <= 13) + sec_ch = chan_num - 4; + } + wlan_reg_set_channel_params(hdd_ctx->pdev, chan_num, + sec_ch, &ch_params); + if (wlan_hdd_change_hw_mode_for_given_chnl(adapter, chan_num, + POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN)) { + hdd_err("Failed to change hw mode"); + return -EINVAL; + } + status = sme_roam_channel_change_req(mac_handle, bssid, &ch_params, + &roam_profile); + if (status) { + hdd_err("Failed to set sme_RoamChannel for monitor mode status: %d", + status); + ret = qdf_status_to_os_return(status); + return ret; + } + 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_mon_ch(wiphy, chandef); + cds_ssr_unprotect(__func__); + return ret; +} +#endif + +/** + * 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; + link_layer_stats_clear_req.stopReq = 0; + link_layer_stats_clear_req.reqId = 1; + link_layer_stats_clear_req.staId = adapter->session_id; + sme_ll_stats_clear_req(mac_handle, &link_layer_stats_clear_req); +} + +#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 + +#if defined(WLAN_FEATURE_FILS_SK) &&\ + defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) &&\ + (defined(CFG80211_UPDATE_CONNECT_PARAMS) ||\ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))) + +#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 + +/** + * __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) +{ + struct csr_roam_profile *roam_profile; + uint8_t *buf; + int ret; + enum eAniAuthType auth_type; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + QDF_STATUS status; + struct cds_fils_connection_info *fils_info; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + roam_profile = hdd_roam_profile(adapter); + fils_info = roam_profile->fils_con_info; + + if (!fils_info) { + hdd_err("No valid FILS conn info"); + return -EINVAL; + } + + if (req->ie_len) + wlan_hdd_cfg80211_set_ie(adapter, req->ie, req->ie_len); + + if (changed) + fils_info->is_fils_connection = true; + + if (changed & UPDATE_FILS_ERP_INFO) { + if (!wlan_hdd_fils_data_in_limits(req)) + return -EINVAL; + fils_info->key_nai_length = req->fils_erp_username_len + + sizeof(char) + + req->fils_erp_realm_len; + if (fils_info->key_nai_length > + FILS_MAX_KEYNAME_NAI_LENGTH) { + hdd_err("Key NAI Length %d", + fils_info->key_nai_length); + return -EINVAL; + } + if (req->fils_erp_username_len && req->fils_erp_username) { + buf = fils_info->keyname_nai; + 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->sequence_number = req->fils_erp_next_seq_num + 1; + fils_info->r_rk_length = req->fils_erp_rrk_len; + + if (req->fils_erp_rrk_len && req->fils_erp_rrk) + qdf_mem_copy(fils_info->r_rk, req->fils_erp_rrk, + fils_info->r_rk_length); + + fils_info->realm_len = req->fils_erp_realm_len; + 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 = wlan_hdd_get_fils_auth_type(req->auth_type); + if (auth_type == eSIR_DONOT_USE_AUTH_TYPE) { + hdd_err("invalid auth type for fils %d", + req->auth_type); + return -EINVAL; + } + + roam_profile->fils_con_info->auth_type = auth_type; + } + + hdd_debug("fils conn update: changed %x is_fils %d keyname nai len %d", + changed, roam_profile->fils_con_info->is_fils_connection, + roam_profile->fils_con_info->key_nai_length); + + if (!hdd_ctx->is_fils_roaming_supported) { + hdd_debug("FILS roaming support %d", + hdd_ctx->is_fils_roaming_supported); + return 0; + } + + mac_handle = hdd_ctx->mac_handle; + status = sme_update_fils_config(mac_handle, adapter->session_id, + roam_profile); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Update FILS 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_update_connect_params(wiphy, dev, + req, changed); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#if defined(WLAN_FEATURE_SAE) && \ + defined(CFG80211_EXTERNAL_AUTH_SUPPORT) +/** + * __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) +{ + 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; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + + hdd_debug("external_auth status: %d", params->status); + mac_handle = hdd_ctx->mac_handle; + sme_handle_sae_msg(mac_handle, adapter->session_id, params->status); + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_external_auth(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/** + * wlan_hdd_chan_info_cb() - channel info callback + * @chan_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_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx) != 0) { + hdd_err("hdd_ctx is invalid"); + return; + } + + if (!hdd_ctx->chan_info) { + hdd_err("chan_info is NULL"); + return; + } + + chan = hdd_ctx->chan_info; + for (idx = 0; idx < SIR_MAX_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; + + } + } + + hdd_exit(); +} + +/** + * 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 (!hdd_ctx->config->fEnableSNRMonitoring) { + hdd_debug("SNR monitoring is disabled"); + return; + } + + hdd_ctx->chan_info = + qdf_mem_malloc(sizeof(struct scan_chan_info) + * QDF_MAX_NUM_CHAN); + if (hdd_ctx->chan_info == NULL) { + hdd_err("Failed to malloc for 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++) { + if (wlan_reg_is_dsrc_chan(hdd_ctx->pdev, + hdd_channels_5_ghz[index - num_2g].hw_value)) + continue; + hdd_ctx->chan_info[index].freq = + hdd_channels_5_ghz[index - num_2g].center_freq; + } + + index = num_2g + num_5g; + index = wlan_hdd_populate_srd_chan_info(hdd_ctx, 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(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; + } + + 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 + +/** + * struct cfg80211_ops - cfg80211_ops + * + * @add_virtual_intf: Add virtual interface + * @del_virtual_intf: Delete virtual interface + * @change_virtual_intf: Change virtual interface + * @change_station: Change station + * @add_beacon: Add beacon in sap mode + * @del_beacon: Delete beacon in sap mode + * @set_beacon: Set beacon in sap mode + * @start_ap: Start ap + * @change_beacon: Change beacon + * @stop_ap: Stop ap + * @change_bss: Change bss + * @add_key: Add key + * @get_key: Get key + * @del_key: Delete key + * @set_default_key: Set default key + * @set_channel: Set channel + * @scan: Scan + * @connect: Connect + * @disconnect: Disconnect + * @join_ibss = Join ibss + * @leave_ibss = Leave ibss + * @set_wiphy_params = Set wiphy params + * @set_tx_power = Set tx power + * @get_tx_power = get tx power + * @remain_on_channel = Remain on channel + * @cancel_remain_on_channel = Cancel remain on channel + * @mgmt_tx = Tx management frame + * @mgmt_tx_cancel_wait = Cancel management tx wait + * @set_default_mgmt_key = Set default management key + * @set_txq_params = Set tx queue parameters + * @get_station = Get station + * @set_power_mgmt = Set power management + * @del_station = Delete station + * @add_station = Add station + * @set_pmksa = Set pmksa + * @del_pmksa = Delete pmksa + * @flush_pmksa = Flush pmksa + * @update_ft_ies = Update FT IEs + * @tdls_mgmt = Tdls management + * @tdls_oper = Tdls operation + * @set_rekey_data = Set rekey data + * @sched_scan_start = Scheduled scan start + * @sched_scan_stop = Scheduled scan stop + * @resume = Resume wlan + * @suspend = Suspend wlan + * @set_mac_acl = Set mac acl + * @testmode_cmd = Test mode command + * @set_ap_chanwidth = Set AP channel bandwidth + * @dump_survey = Dump survey + * @key_mgmt_set_pmk = Set pmk key management + * @update_connect_params = Update connect params + */ +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, + .join_ibss = wlan_hdd_cfg80211_join_ibss, + .leave_ibss = wlan_hdd_cfg80211_leave_ibss, + .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, + .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 +#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(WLAN_FEATURE_FILS_SK) &&\ + defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) &&\ + (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) + .external_auth = wlan_hdd_cfg80211_external_auth, +#endif +}; diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h new file mode 100644 index 0000000000000000000000000000000000000000..d66addd5eccd1cd6f1cf4419d3ca4df649606acc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h @@ -0,0 +1,656 @@ +/* + * 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: wlan_hdd_cfg80211.h + * + * WLAN host device driver cfg80211 functions declaration + */ + +#if !defined(HDD_CFG80211_H__) +#define HDD_CFG80211_H__ + +#include +#include +#include +#include + +struct hdd_context; + +/* 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 HDD_P2P_WILDCARD_SSID "DIRECT-" +#define HDD_P2P_WILDCARD_SSID_LEN 7 + +#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 BLACKLIST_OUI_TYPE "\x00\x50\x00\x00" +#define WHITELIST_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 WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 +#define WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 +#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 + +#define WLAN_AKM_SUITE_OWE 0x000FAC12 +#define WLAN_AKM_SUITE_EAP_SHA256 0x000FAC0B +#define WLAN_AKM_SUITE_EAP_SHA384 0x000FAC0C + + +#ifndef WLAN_AKM_SUITE_SAE +#define WLAN_AKM_SUITE_SAE 0x000FAC08 +#endif + +#ifdef FEATURE_WLAN_TDLS +#define WLAN_IS_TDLS_SETUP_ACTION(action) \ + ((SIR_MAC_TDLS_SETUP_REQ <= action) && \ + (SIR_MAC_TDLS_SETUP_CNF >= action)) +#if !defined(TDLS_MGMT_VERSION2) +#define TDLS_MGMT_VERSION2 0 +#endif + +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter); +#else +static inline void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter) {} +#endif + +#define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS) +#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 + +#define OL_TXRX_INVALID_TDLS_PEER_ID 0xff + +/** + * enum eDFS_CAC_STATUS: CAC status + * + * @DFS_CAC_NEVER_DONE: CAC never done + * @DFS_CAC_IN_PROGRESS: CAC is in progress + * @DFS_CAC_IN_PROGRESS: 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_WHITELIST 0x1000000 /* Support Probe IE white listing */ +#define WIFI_FEATURE_SCAN_RAND 0x2000000 /* Support MAC & Probe Sequence Number randomization */ +#define WIFI_FEATURE_SET_LATENCY_MODE 0x40000000 /* Set latency mode */ + + +/* 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 WIIF_TDLS_OFFCHANNEL_SUPPORT BIT(2) + +#define CFG_NON_AGG_RETRY_MAX (31) +#define CFG_AGG_RETRY_MAX (31) +#define CFG_MGMT_RETRY_MAX (31) +#define CFG_CTRL_RETRY_MAX (31) +#define CFG_PROPAGATION_DELAY_MAX (63) +#define CFG_PROPAGATION_DELAY_BASE (64) +#define CFG_AGG_RETRY_MIN (5) + +struct cfg80211_bss * +wlan_hdd_cfg80211_update_bss_db(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info); + +#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 + + +int wlan_hdd_cfg80211_pmksa_candidate_notify(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + int index, bool preauth); + +#ifdef FEATURE_WLAN_LFR_METRICS +QDF_STATUS +wlan_hdd_cfg80211_roam_metrics_preauth(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info); + +QDF_STATUS +wlan_hdd_cfg80211_roam_metrics_preauth_status(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + bool preauth_status); + +QDF_STATUS +wlan_hdd_cfg80211_roam_metrics_handover(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info); +#endif + +struct hdd_context *hdd_cfg80211_wiphy_alloc(int priv_size); + +int wlan_hdd_cfg80211_tdls_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source); + +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 *pCfg); + +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_config *cfg); + +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); + +extern void hdd_conn_set_connection_state(struct hdd_adapter *adapter, + eConnectionState connState); +QDF_STATUS wlan_hdd_validate_operation_channel(struct hdd_adapter *adapter, + int channel); +#ifdef FEATURE_WLAN_TDLS +int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, + struct net_device *dev, u8 *peer); +#endif + +void hdd_select_cbmode(struct hdd_adapter *adapter, uint8_t operationChannel, + 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); +void wlan_hdd_del_station(struct hdd_adapter *adapter); + +#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 + * + * Return: 0 on success or failure reason + */ +int wlan_hdd_send_hang_reason_event(struct hdd_context *hdd_ctx, + uint32_t reason); + +int wlan_hdd_send_avoid_freq_for_dnbs(struct hdd_context *hdd_ctx, + uint8_t op_chan); + +#ifdef FEATURE_WLAN_EXTSCAN +void wlan_hdd_cfg80211_extscan_callback(void *ctx, + const uint16_t evType, void *pMsg); +#else +static inline void wlan_hdd_cfg80211_extscan_callback(void *ctx, + const uint16_t evType, void *pMsg) +{ +} +#endif /* FEATURE_WLAN_EXTSCAN */ +/** + * 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); + +void hdd_rssi_threshold_breached(void *hddctx, + struct rssi_breach_event *data); + +/* + * wlan_hdd_cfg80211_unlink_bss :to inform nl80211 + * interface that BSS might have been lost. + * @adapter: adapter + * @bssid: bssid which might have been lost + * @ssid: SSID + * @ssid_len: length of the SSID + * + * Return: void + */ +void wlan_hdd_cfg80211_unlink_bss(struct hdd_adapter *adapter, + tSirMacAddr bssid, uint8_t *ssid, + uint8_t ssid_len); + +void wlan_hdd_cfg80211_acs_ch_select_evt(struct hdd_adapter *adapter); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, uint8_t *bssid, + uint8_t *req_rsn_ie, uint32_t req_rsn_length, uint8_t + *rsp_rsn_ie, uint32_t rsp_rsn_length, struct csr_roam_info + *roam_info_ptr); +#else +static inline int wlan_hdd_send_roam_auth_event(struct hdd_adapter *adapter, + uint8_t *bssid, uint8_t *req_rsn_ie, uint32_t req_rsn_length, + uint8_t *rsp_rsn_ie, uint32_t rsp_rsn_length, + struct csr_roam_info *roam_info_ptr) +{ + return 0; +} +#endif + +int wlan_hdd_cfg80211_update_apies(struct hdd_adapter *adapter); +int wlan_hdd_request_pre_cac(uint8_t channel); +int wlan_hdd_sap_cfg_dfs_override(struct hdd_adapter *adapter); + +enum policy_mgr_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type( + enum nl80211_iftype type); + +int wlan_hdd_enable_dfs_chan_scan(struct hdd_context *hdd_ctx, + bool enable_dfs_channels); + +int wlan_hdd_cfg80211_update_band(struct hdd_context *hdd_ctx, + struct wiphy *wiphy, + enum band_info eBand); + +/** + * wlan_hdd_try_disconnect() - try disconnnect from previous connection + * @adapter: Pointer to adapter + * + * This function is used to disconnect from previous connection + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_try_disconnect(struct hdd_adapter *adapter); + +#if defined(CFG80211_DISCONNECTED_V2) || \ +(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + locally_generated, GFP_KERNEL); +} +#else +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + GFP_KERNEL); +} +#endif + +/** + * wlan_hdd_inform_bss_frame() - inform bss details to NL80211 + * @adapter: Pointer to adapter + * @bss_desc: Pointer to bss descriptor + * + * This function is used to inform the BSS details to nl80211 interface. + * + * Return: struct cfg80211_bss pointer + */ +struct cfg80211_bss * +wlan_hdd_inform_bss_frame(struct hdd_adapter *adapter, + struct bss_description *bss_desc); + +/** + * wlan_hdd_change_hw_mode_for_given_chnl() - change HW mode for given channel + * @adapter: pointer to adapter + * @channel: given channel number + * @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, + uint8_t channel, + enum policy_mgr_conn_update_reason reason); + +/** + * 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 + */ +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_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_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); +/* + * 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_try_disconnect() - try disconnnect from previous connection + * @adapter: Pointer to adapter + * + * This function is used to disconnect from previous connection + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_try_disconnect(struct hdd_adapter *adapter); + +/** + * wlan_hdd_disconnect() - hdd disconnect api + * @adapter: Pointer to adapter + * @reason: Disconnect reason code + * + * This function is used to issue a disconnect request to SME + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_disconnect(struct hdd_adapter *adapter, u16 reason); + +/** + * hdd_update_cca_info_cb() - stores congestion value in station context + * @hdd_handle: HDD handle + * @congestion: congestion + * @vdev_id: vdev id + * + * Return: None + */ +void hdd_update_cca_info_cb(hdd_handle_t hdd_handle, uint32_t congestion, + uint32_t vdev_id); + +/** + * wlan_hdd_get_adjacent_chan(): Gets next/previous channel + * to the channel passed. + * @chan: Channel + * @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. + */ +int wlan_hdd_get_adjacent_chan(uint8_t chan, bool upper); + +/** + * 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); + +/** + * wlan_hdd_save_gtk_offload_params() - Save gtk offload parameters in STA + * context for offload operations. + * @adapter: Adapter context + * @kck_ptr: KCK buffer pointer + * @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 *kek_ptr, + uint32_t kek_len, + uint8_t *replay_ctr, + bool big_endian); +/* + * 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 + * @notify_sap_event: Indicates if SAP event needs to be notified + * + * Return: 0 on success, Error code on failure + */ +int wlan_hdd_restore_channels(struct hdd_context *hdd_ctx, + bool notify_sap_event); + +/** + * 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); + +/** + * 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); +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.c new file mode 100644 index 0000000000000000000000000000000000000000..50c290626892b29fbb5634323d3c8c78ff49f98e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.c @@ -0,0 +1,194 @@ +/* + * 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_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 "wlan_hdd_cfg.h" + +static 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 hdd_config *config; + int errno; + QDF_STATUS status; + + hdd_enter(); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno != 0) + return errno; + + config = hdd_ctx->config; + if (!config) { + hdd_err("hdd config got NULL"); + return -EINVAL; + } + + if (!config->enable_three_way_coex_config_legacy) { + 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_COEX_RESET || + 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->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_coex_config(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.h new file mode 100644 index 0000000000000000000000000000000000000000..fbba0d03160bb0502ed90ea7d03d1bc5f0d29f21 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.h @@ -0,0 +1,57 @@ +/* + * 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_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); + +#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 \ +}, +#else /* FEATURE_COEX_CONFIG */ +#define FEATURE_COEX_CONFIG_COMMANDS +#endif /* FEATURE_COEX_CONFIG */ + +#endif /* __WLAN_HDD_COEX_CONFIG_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_conc_ut.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_conc_ut.c new file mode 100644 index 0000000000000000000000000000000000000000..f67b482094a5c41d8f2c7e8ea0131e9e0a711715 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_conc_ut.c @@ -0,0 +1,880 @@ +/* + * Copyright (c) 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. + */ + +/* Include files */ + +#include +#include +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_conc_ut.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "wma_types.h" +#include "wma.h" +#include "wma_api.h" + +#define NUMBER_OF_SCENARIO 300 +#define MAX_ALLOWED_CHAR_IN_REPORT 50 + +/** + * struct report_t: Data structure to fill report + * + * @title: title of the concurrency case scenario + * @first_persona: device type of first persona + * @second_persona: device type of second persona + * @third_persona: device type of third persona + * @dbs_value: string to mention whether dbs enable or disable + * @system_conf: string to mention what is system's configuration + * @status: status field + * @result_code: string to mention whether test case passed or failed + * @reason: reason why test case failed + * @pcl: preferred channel list + * + * This structure will be used by unit test framework to fill + * report after running various concurrency scenarios. + */ +struct report_t { + char title[2 * MAX_ALLOWED_CHAR_IN_REPORT]; + char first_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char second_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char third_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char dbs_value[MAX_ALLOWED_CHAR_IN_REPORT]; + char system_conf[MAX_ALLOWED_CHAR_IN_REPORT]; + bool status; + char result_code[MAX_ALLOWED_CHAR_IN_REPORT]; + char reason[MAX_ALLOWED_CHAR_IN_REPORT]; + char pcl[2 * QDF_MAX_NUM_CHAN]; +}; + +static struct report_t report[NUMBER_OF_SCENARIO]; +static uint32_t report_idx; + +static uint8_t wlan_hdd_valid_type_of_persona(uint32_t sub_type) +{ + switch (sub_type) { + case PM_STA_MODE: + return WMI_VDEV_TYPE_STA; + case PM_IBSS_MODE: + return WMI_VDEV_TYPE_IBSS; + case PM_SAP_MODE: + case PM_P2P_CLIENT_MODE: + case PM_P2P_GO_MODE: + return WMI_VDEV_TYPE_AP; + default: + return WMI_VDEV_TYPE_STA; + } +} + +static const char *system_config_to_string(uint8_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(PM_THROUGHPUT); + CASE_RETURN_STRING(PM_POWERSAVE); + CASE_RETURN_STRING(PM_LATENCY); + default: + return "Unknown"; + } + +} + +static const char *device_mode_to_string(uint8_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_IBSS_MODE); + default: + return "none"; + } +} + +static const char *pcl_type_to_string(uint8_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_SCC_ON_24_24G); + CASE_RETURN_STRING(PM_SCC_ON_5_SCC_ON_24_5G); + 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_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); + default: + return "Unknown"; + } +} + +void clean_report(struct hdd_context *hdd_ctx) +{ + uint32_t idx = 0; + + while (idx < NUMBER_OF_SCENARIO) { + qdf_mem_zero(&report[idx], sizeof(struct report_t)); + idx++; + } + report_idx = 0; +} + +void print_report(struct hdd_context *hdd_ctx) +{ + uint32_t idx = 0; + + pr_info("+----------Report start -----------+\n"); + while (idx < report_idx) { + pr_info("Idx:[%d]\nTitle:%s\nResult:[%s]\n\t1st_person[%s]\n\t2nd_persona[%s]\n\t3rd_persona[%s]\n\tDBS[%s]\n\tsystem_config[%s]\n\treason[%s]\n\tpcl[%s]\n", + idx, + report[idx].title, report[idx].result_code, + report[idx].first_persona, report[idx].second_persona, + report[idx].third_persona, report[idx].dbs_value, + report[idx].system_conf, report[idx].reason, + report[idx].pcl); + idx++; + } + pr_info("+----------Report end -----------+\n"); +} + +void fill_report(struct hdd_context *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum policy_mgr_pcl_type pcl_type, char *reason, + uint8_t *pcl) +{ + int i; + char buf[4] = {0}; + + if (report_idx >= NUMBER_OF_SCENARIO) + return; + snprintf(report[report_idx].title, + 2 * MAX_ALLOWED_CHAR_IN_REPORT, "pcl for[%s] pcl_type[%s]", + title, pcl_type_to_string(pcl_type)); + if (chnl_1st_conn == 0) + snprintf(report[report_idx].first_persona, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + device_mode_to_string(first_persona)); + else + snprintf(report[report_idx].first_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(first_persona), chnl_1st_conn); + if (chnl_2nd_conn == 0) + snprintf(report[report_idx].second_persona, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + device_mode_to_string(second_persona)); + else + snprintf(report[report_idx].second_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(second_persona), chnl_2nd_conn); + if (chnl_3rd_conn == 0) + snprintf(report[report_idx].third_persona, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + device_mode_to_string(third_persona)); + else + snprintf(report[report_idx].third_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(third_persona), chnl_3rd_conn); + + report[report_idx].status = status; + snprintf(report[report_idx].dbs_value, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) + ? "enable" : "disable"); + snprintf(report[report_idx].system_conf, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + system_config_to_string(hdd_ctx->config->conc_system_pref)); + snprintf(report[report_idx].result_code, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + status ? "PASS" : "FAIL"); + snprintf(report[report_idx].reason, + MAX_ALLOWED_CHAR_IN_REPORT, + reason); + if (pcl) { + qdf_mem_zero(report[report_idx].pcl, + sizeof(report[report_idx].pcl)); + for (i = 0; i < QDF_MAX_NUM_CHAN; i++) { + if (pcl[i] == 0) + break; + qdf_mem_zero(buf, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d ", pcl[i]); + strlcat(report[report_idx].pcl, buf, + sizeof(report[report_idx].pcl)); + strlcat(report[report_idx].pcl, ", ", + sizeof(report[report_idx].pcl)); + } + } + report_idx++; +} + +static bool wlan_hdd_validate_pcl(struct hdd_context *hdd_ctx, + enum policy_mgr_pcl_type pcl_type, uint8_t *pcl, uint32_t pcl_len, + uint8_t first_connection_chnl, uint8_t second_connection_chnl, + char *reason, uint32_t reason_length) +{ + bool status = true; + uint32_t first_idx = 0; + + if ((pcl_type != PM_NONE) && (pcl_len == 0)) { + snprintf(reason, reason_length, "no of channels = 0"); + return false; + } + + switch (pcl_type) { + case PM_NONE: + if (pcl_len != 0) { + snprintf(reason, reason_length, "no of channels>0"); + return false; + } + break; + case PM_5G: + for (first_idx = 0; first_idx < pcl_len; first_idx++) { + if (!WLAN_REG_IS_5GHZ_CH(pcl[first_idx])) { + snprintf(reason, reason_length, + "2G channel found"); + return false; + } + } + break; + case PM_24G: + for (first_idx = 0; first_idx < pcl_len; first_idx++) { + if (!WLAN_REG_IS_24GHZ_CH(pcl[first_idx])) { + snprintf(reason, reason_length, + "5G channel found"); + return false; + } + } + break; + case PM_SCC_CH: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case PM_MCC_CH: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case PM_SCC_CH_24G: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + if (!WLAN_REG_IS_24GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 2.4Ghz chnl"); + return false; + } + break; + case PM_SCC_CH_5G: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + if (!WLAN_REG_IS_5GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + break; + case PM_24G_SCC_CH: + if (!WLAN_REG_IS_24GHZ_CH(pcl[0])) { + snprintf(reason, reason_length, + "No 2.4Ghz chnl"); + return false; + } + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[pcl_len-1] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case PM_5G_SCC_CH: + if (!WLAN_REG_IS_5GHZ_CH(pcl[0])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[pcl_len-1] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case PM_MCC_CH_24G: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if (!WLAN_REG_IS_24GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 24Ghz chnl"); + return false; + } + break; + case PM_MCC_CH_5G: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if (!WLAN_REG_IS_5GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + break; + case PM_24G_MCC_CH: + if (!WLAN_REG_IS_24GHZ_CH(pcl[0])) { + snprintf(reason, reason_length, + "No 24Ghz chnl"); + return false; + } + if ((pcl[pcl_len-1] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[pcl_len-1] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[pcl_len-2] != first_connection_chnl && + pcl[pcl_len-2] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case PM_5G_MCC_CH: + if (!WLAN_REG_IS_5GHZ_CH(pcl[0])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + if ((pcl[pcl_len-1] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[pcl_len-1] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[pcl_len-2] != first_connection_chnl && + pcl[pcl_len-2] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case PM_SCC_ON_5_SCC_ON_24_24G: + if (!WLAN_REG_IS_5GHZ_CH(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_24GHZ_CH(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_24GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 24Ghz chnls"); + return false; + } + break; + case PM_SCC_ON_5_SCC_ON_24_5G: + if (!WLAN_REG_IS_5GHZ_CH(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_24GHZ_CH(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_5GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 5Ghz chnls"); + return false; + } + break; + case PM_SCC_ON_24_SCC_ON_5_24G: + if (!WLAN_REG_IS_24GHZ_CH(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_5GHZ_CH(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_24GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 24Ghz chnls"); + return false; + } + break; + case PM_SCC_ON_24_SCC_ON_5_5G: + if (!WLAN_REG_IS_24GHZ_CH(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_5GHZ_CH(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_5GHZ_CH(pcl[pcl_len - 1])) { + snprintf(reason, reason_length, + "No 5Ghz chnls"); + return false; + } + break; + case PM_SCC_ON_5_SCC_ON_24: + if (!WLAN_REG_IS_5GHZ_CH(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_24GHZ_CH(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (pcl_len != 2) { + snprintf(reason, reason_length, + "more than 2 chnls"); + return false; + } + break; + case PM_SCC_ON_24_SCC_ON_5: + if (!WLAN_REG_IS_24GHZ_CH(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!WLAN_REG_IS_5GHZ_CH(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (pcl_len != 2) { + snprintf(reason, reason_length, + "more than 2 chnls"); + return false; + } + break; + default: + snprintf(reason, reason_length, + "Unknown option"); + status = false; + } + if (status == true) { + snprintf(reason, reason_length, + "success"); + } + return status; +} + +static void wlan_hdd_map_subtypes_hdd_wma(enum policy_mgr_con_mode *dst, + enum policy_mgr_con_mode *src) +{ + /* + * wma defined sap subtype as 0 + * Rest of the mappings are same + * In future, if mapping gets changed then re-map it here + */ + if (*src == PM_SAP_MODE) + *dst = 0; + else + *dst = *src; +} + +void wlan_hdd_one_connection_scenario(struct hdd_context *hdd_ctx) +{ + enum policy_mgr_con_mode sub_type; + enum policy_mgr_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + uint8_t pcl[QDF_MAX_NUM_CHAN] = {0}, + weight_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + bool status = false; + enum policy_mgr_pcl_type pcl_type; + char reason[20] = {0}; + QDF_STATUS ret; + struct policy_mgr_sme_cbacks sme_cbacks; + + sme_cbacks.sme_get_valid_channels = sme_get_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + /* flush the entire table first */ + ret = policy_mgr_psoc_enable(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + for (sub_type = 0; sub_type < PM_MAX_NUM_OF_MODE; sub_type++) { + /* validate one connection is created or no */ + if (policy_mgr_get_connection_count(hdd_ctx->psoc) != 0) { + hdd_err("Test failed - No. of connection is not 0"); + return; + } + qdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = policy_mgr_get_pcl_from_first_conn_table( + sub_type, system_pref); + + /* check PCL value for second connection is correct or no */ + policy_mgr_get_pcl(hdd_ctx->psoc, sub_type, pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, 0, 0, + reason, sizeof(reason)); + if ((pcl_type == PM_MAX_PCL_TYPE) && (pcl[0] == 0)) + continue; + + fill_report(hdd_ctx, "1 connection", sub_type, + PM_MAX_NUM_OF_MODE, + PM_MAX_NUM_OF_MODE, + 0, 0, 0, + status, pcl_type, reason, pcl); + } +} + +void wlan_hdd_two_connections_scenario(struct hdd_context *hdd_ctx, + uint8_t first_chnl, enum policy_mgr_chain_mode first_chain_mask) +{ + uint8_t vdevid = 0, tx_stream = 2, rx_stream = 2; + uint8_t type = WMI_VDEV_TYPE_STA, channel_id = first_chnl, mac_id = 1; + uint8_t pcl[QDF_MAX_NUM_CHAN] = {0}, + weight_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + enum policy_mgr_chain_mode chain_mask = first_chain_mask; + enum policy_mgr_con_mode sub_type, next_sub_type, dummy_type; + enum policy_mgr_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + enum policy_mgr_pcl_type pcl_type; + enum policy_mgr_one_connection_mode second_index; + char reason[20] = {0}; + bool status = false; + QDF_STATUS ret; + struct policy_mgr_sme_cbacks sme_cbacks; + + for (sub_type = PM_STA_MODE; + sub_type < PM_MAX_NUM_OF_MODE; sub_type++) { + type = wlan_hdd_valid_type_of_persona(sub_type); + + sme_cbacks.sme_get_valid_channels = sme_get_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + /* flush the entire table first */ + ret = policy_mgr_psoc_enable(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type, &sub_type); + /* add first connection as STA */ + policy_mgr_incr_connection_count_utfw(hdd_ctx->psoc, + vdevid, tx_stream, + rx_stream, chain_mask, type, dummy_type, + channel_id, mac_id); + /* validate one connection is created or no */ + if (policy_mgr_get_connection_count(hdd_ctx->psoc) != 1) { + hdd_err("Test failed - No. of connection is not 1"); + return; + } + next_sub_type = PM_STA_MODE; + while (next_sub_type < PM_MAX_NUM_OF_MODE) { + /* get the PCL value & check the channels accordingly */ + second_index = + policy_mgr_get_second_connection_pcl_table_index( + hdd_ctx->psoc); + if (PM_MAX_ONE_CONNECTION_MODE == second_index) { + /* not valid combination*/ + hdd_err("couldn't find index for 2nd connection pcl table"); + next_sub_type++; + continue; + } + qdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = policy_mgr_get_pcl_from_second_conn_table( + second_index, next_sub_type, system_pref, + policy_mgr_is_hw_dbs_capable( + hdd_ctx->psoc)); + /* check PCL for second connection is correct or no */ + policy_mgr_get_pcl(hdd_ctx->psoc, + next_sub_type, pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, channel_id, 0, + reason, sizeof(reason)); + if ((pcl_type == PM_MAX_PCL_TYPE) && (pcl[0] == 0)) { + next_sub_type++; + continue; + } + fill_report(hdd_ctx, "2 connections", sub_type, + next_sub_type, + PM_MAX_NUM_OF_MODE, first_chnl, + 0, 0, status, pcl_type, reason, pcl); + next_sub_type++; + } + } +} + +void wlan_hdd_three_connections_scenario(struct hdd_context *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum policy_mgr_chain_mode chain_mask, uint8_t use_same_mac) +{ + uint8_t vdevid_1 = 0, tx_stream_1 = 2, rx_stream_1 = 2; + uint8_t vdevid_2 = 1, tx_stream_2 = 2, rx_stream_2 = 2; + uint8_t channel_id_1 = first_chnl, channel_id_2 = second_chnl; + uint8_t mac_id_1, mac_id_2; + uint8_t type_1 = WMI_VDEV_TYPE_STA, type_2 = WMI_VDEV_TYPE_STA; + uint8_t pcl[MAX_NUM_CHAN] = {0}, weight_list[MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + enum policy_mgr_chain_mode chain_mask_1; + enum policy_mgr_chain_mode chain_mask_2; + enum policy_mgr_con_mode sub_type_1, sub_type_2, next_sub_type; + enum policy_mgr_con_mode dummy_type_1, dummy_type_2; + enum policy_mgr_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + enum policy_mgr_pcl_type pcl_type; + enum policy_mgr_two_connection_mode third_index; + char reason[20] = {0}; + bool status = false; + QDF_STATUS ret; + struct policy_mgr_sme_cbacks sme_cbacks; + + /* let's set the chain_mask, mac_ids*/ + if (chain_mask == POLICY_MGR_TWO_TWO) { + mac_id_1 = 1; + mac_id_2 = 1; + chain_mask_1 = POLICY_MGR_TWO_TWO; + chain_mask_2 = POLICY_MGR_TWO_TWO; + } else if (use_same_mac == 1) { + mac_id_1 = 1; + mac_id_2 = 1; + chain_mask_1 = POLICY_MGR_ONE_ONE; + chain_mask_2 = POLICY_MGR_ONE_ONE; + } else { + mac_id_1 = 1; + mac_id_2 = 2; + chain_mask_1 = POLICY_MGR_ONE_ONE; + chain_mask_2 = POLICY_MGR_ONE_ONE; + } + + for (sub_type_1 = PM_STA_MODE; + sub_type_1 < PM_MAX_NUM_OF_MODE; sub_type_1++) { + + type_1 = wlan_hdd_valid_type_of_persona(sub_type_1); + + sme_cbacks.sme_get_valid_channels = sme_get_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + /* flush the entire table first */ + ret = policy_mgr_psoc_enable(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type_1, &sub_type_1); + /* add first connection as STA */ + policy_mgr_incr_connection_count_utfw(hdd_ctx->psoc, + vdevid_1, tx_stream_1, rx_stream_1, chain_mask_1, + type_1, dummy_type_1, channel_id_1, mac_id_1); + /* validate one connection is created or no */ + if (policy_mgr_get_connection_count(hdd_ctx->psoc) != 1) { + hdd_err("Test fail - No. of connection not 1"); + return; + } + for (sub_type_2 = PM_STA_MODE; + sub_type_2 < PM_MAX_NUM_OF_MODE; sub_type_2++) { + + type_2 = wlan_hdd_valid_type_of_persona(sub_type_2); + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type_2, + &sub_type_2); + policy_mgr_incr_connection_count_utfw(hdd_ctx->psoc, + vdevid_2, tx_stream_2, rx_stream_2, + chain_mask_2, type_2, + dummy_type_2, channel_id_2, mac_id_2); + /* validate two connections are created or no */ + if (policy_mgr_get_connection_count(hdd_ctx->psoc) + != 2) { + hdd_err("Test fail - No. connection not 2"); + return; + } + next_sub_type = PM_STA_MODE; + while (next_sub_type < PM_MAX_NUM_OF_MODE) { + third_index = + policy_mgr_get_third_connection_pcl_table_index( + hdd_ctx->psoc); + if (PM_MAX_TWO_CONNECTION_MODE == + third_index) { + /* not valid combination */ + next_sub_type++; + continue; + } + qdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = + policy_mgr_get_pcl_from_third_conn_table( + third_index, next_sub_type, + system_pref, + policy_mgr_is_hw_dbs_capable( + hdd_ctx->psoc)); + policy_mgr_get_pcl(hdd_ctx->psoc, + next_sub_type, + pcl, &pcl_len, + weight_list, + QDF_ARRAY_SIZE(weight_list)); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, + channel_id_1, channel_id_2, + reason, sizeof(reason)); + if ((pcl_type == PM_MAX_PCL_TYPE) && + (pcl[0] == 0)) { + next_sub_type++; + continue; + } + fill_report(hdd_ctx, "3 connections", + sub_type_1, sub_type_2, + next_sub_type, first_chnl, + second_chnl, 0, status, + pcl_type, reason, pcl); + next_sub_type++; + } + /* remove entry to make a room for next iteration */ + policy_mgr_decr_connection_count(hdd_ctx->psoc, + vdevid_2); + } + next_sub_type = PM_STA_MODE; + } +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_data_stall_detection.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_data_stall_detection.c new file mode 100644 index 0000000000000000000000000000000000000000..b7f3917952362dd07db5029f09977c463aa2bff4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_data_stall_detection.c @@ -0,0 +1,85 @@ +/* + * 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_hdd_data_stall_detection.c + * + * WLAN Host Device Driver Data Stall detection API implementation + */ + +#include "wlan_hdd_data_stall_detection.h" +#include "cdp_txrx_cmn.h" +#include "cdp_txrx_misc.h" +#include "ol_txrx_types.h" + +#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; + WLAN_HOST_DIAG_EVENT_REPORT(&sta_data_stall, EVENT_WLAN_STA_DATASTALL); +} +#else +static inline void hdd_data_stall_send_event(uint32_t reason) +{ +} +#endif + +/** + * hdd_data_stall_process_cb() - Process data stall message + * @message: data stall message + * + * Process data stall message + * + * Return: void + */ +static void hdd_data_stall_process_cb( + struct data_stall_event_info *data_stall_info) +{ + hdd_data_stall_send_event(data_stall_info->data_stall_type); +} + +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 */ + status = cdp_data_stall_cb_register(soc, 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 */ + status = cdp_data_stall_cb_deregister(soc, hdd_data_stall_process_cb); + return qdf_status_to_os_return(status); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..eeb2bf44d95d14b43097da6dcafe3e99d4a18b09 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c @@ -0,0 +1,536 @@ +/* + * 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: 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. + */ + +#ifdef WLAN_OPEN_SOURCE +#include +#include +#include +#include +#include +#include + +#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 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 + * @file: debugfs file handle + * @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 file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) file->private_data; + 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 ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != 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) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_wowpattern_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wcnss_patterngen_write() - pattern_gen debugfs handler + * @file: debugfs file handle + * @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 file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct hdd_adapter *adapter; + 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(); + + adapter = (struct hdd_adapter *)file->private_data; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != 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) { + delPeriodicTxPtrnParams = + qdf_mem_malloc(sizeof(tSirDelPeriodicTxPtrn)); + if (!delPeriodicTxPtrnParams) { + hdd_err("Memory allocation failed!"); + qdf_mem_free(cmd); + return -ENOMEM; + } + delPeriodicTxPtrnParams->ucPtrnId = pattern_idx; + delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << 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; + } + 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_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter)))) { + 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) { + hdd_err("Memory allocation failed!"); + 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; + } + 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) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_patterngen_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wcnss_debugfs_open() - Generic debugfs open() handler + * @inode: inode of the debugfs file + * @file: file handle of the debugfs file + * + * Return: 0 + */ +static int __wcnss_debugfs_open(struct inode *inode, struct file *file) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter(); + + if (inode->i_private) + file->private_data = inode->i_private; + + adapter = (struct hdd_adapter *)file->private_data; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != 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; + hdd_exit(); + return 0; +} + +/** + * 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wcnss_debugfs_open(inode, file); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 *dev = adapter->dev; + + adapter->debugfs_phy = debugfs_create_dir(dev->name, 0); + + if (NULL == adapter->debugfs_phy) + return QDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("wow_pattern", 00400 | 00200, + adapter->debugfs_phy, adapter, + &fops_wowpattern)) + return QDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("pattern_gen", 00400 | 00200, + adapter->debugfs_phy, adapter, + &fops_patterngen)) + return QDF_STATUS_E_FAILURE; + + if (0 != 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); +} +#endif /* #ifdef WLAN_OPEN_SOURCE */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_coex.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_coex.c new file mode 100644 index 0000000000000000000000000000000000000000..a959d71cfb1267fd17d14b82c8baaf936526f436 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_coex.c @@ -0,0 +1,645 @@ +/* + * 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_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 "cds_sched.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("obselete 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->session_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 hdd_context *hdd_ctx = arg; + QDF_STATUS status; + + cds_ssr_protect(__func__); + status = __hdd_debugfs_mws_coex_state_read(hdd_ctx, file); + cds_ssr_unprotect(__func__); + + return status; +} + +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->session_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" + "sinr_wlan_off = %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 hdd_context *hdd_ctx = arg; + QDF_STATUS status; + + cds_ssr_protect(__func__); + status = __hdd_debugfs_mws_coex_dpwb_read(hdd_ctx, file); + cds_ssr_unprotect(__func__); + + return status; +} + +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->session_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 hdd_context *hdd_ctx = arg; + QDF_STATUS status; + + cds_ssr_protect(__func__); + status = __hdd_debugfs_mws_tdm_state_read(hdd_ctx, file); + cds_ssr_unprotect(__func__); + + return status; +} + +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->session_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" + "sub0_techid = %d\n" + "sub0_policy = %d\n" + "sub0_is_link_critical = %d\n" + "sub0_static_power = %u\n" + "sub0_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 hdd_context *hdd_ctx = arg; + QDF_STATUS status; + + cds_ssr_protect(__func__); + status = __hdd_debugfs_mws_coex_idrx_read(hdd_ctx, file); + cds_ssr_unprotect(__func__); + + return status; +} + +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->session_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 hdd_context *hdd_ctx = arg; + QDF_STATUS status; + + cds_ssr_protect(__func__); + status = __hdd_debugfs_mws_antenna_sharing_read(hdd_ctx, file); + cds_ssr_unprotect(__func__); + + return status; +} + +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 dosent have a directory it is removed as part of qdf remove + */ +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_connect.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_connect.c new file mode 100644 index 0000000000000000000000000000000000000000..8cbedd2a267026c68a5bdccf73d8232d42a58c7c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_connect.c @@ -0,0 +1,452 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_debugfs_connect.c + * + * WLAN Host Device Driver implementation to update + * debugfs with connect information + */ + +#include +#include +#include +#include +#include "qwlan_version.h" +#include "wmi_unified_param.h" + +/** + * wlan_hdd_version_info_debugfs() - 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_debugfs(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_WPA: + return "WPA"; + case eCSR_AUTH_TYPE_WPA_PSK: + return "WPA PSK"; + case eCSR_AUTH_TYPE_AUTOSWITCH: + return "AUTO SWITCH"; + 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"; + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + return "WAPI WAI CERTIFICATE"; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + return "WAPI WAI PSK"; + 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_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"; + } + + return "UNKNOWN"; +} + +/** + * hdd_ch_width_str() - Get string for channel width + * @ch_width: channel width from connect info + * + * Return: User readable string for channel width + */ +static +uint8_t *hdd_ch_width_str(enum phy_ch_width ch_width) +{ + switch (ch_width) { + case CH_WIDTH_20MHZ: + return "20MHz"; + case CH_WIDTH_40MHZ: + return "40MHz"; + case CH_WIDTH_80MHZ: + return "80MHz"; + case CH_WIDTH_160MHZ: + return "160MHz"; + case CH_WIDTH_80P80MHZ: + return "(80 + 80)MHz"; + case CH_WIDTH_5MHZ: + return "5MHz"; + case CH_WIDTH_10MHZ: + return "10MHz"; + case CH_WIDTH_INVALID: + /* Fallthrough */ + case CH_WIDTH_MAX: + /* Fallthrough */ + default: + return "UNKNOWN"; + } +} + +/** + * wlan_hdd_connect_info_debugfs() - 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_debugfs(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); + if (hdd_sta_ctx->conn_info.connState != eConnectionState_Associated) { + 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_sta_ctx->hdd_reassoc_scenario) { + 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 = " MAC_ADDRESS_STR "\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, + MAC_ADDR_ARRAY(conn_info->bssId.bytes), + conn_info->connect_time, + conn_info->auth_time, + conn_info->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; +} + +ssize_t +wlan_hdd_debugfs_update_connect_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t len; + int ret_val; + + 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 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_version_info_debugfs(hdd_ctx, 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_connect_info_debugfs(adapter, buf + len, + buf_avail_len - len); + + hdd_exit(); + + return len; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_csr.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_csr.c new file mode 100644 index 0000000000000000000000000000000000000000..3c88bd7fd3d42d26fe8dfd6cc6db6446915122da --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_csr.c @@ -0,0 +1,383 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_debugfs_csr.c + * + * WLAN Host Device Driver implementation to update + * debugfs with roaming related information + */ + +#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_CONNECT_INFO: + /* populate connect info */ + len = wlan_hdd_debugfs_update_connect_info(hdd_ctx, adapter, + buf, buf_avail_len); + break; + 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 + * @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; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + int ret; + ssize_t length; + + hdd_enter(); + + info = file->private_data; + if (!info || !info->data) { + hdd_err("No valid private data"); + return 0; + } + + adapter = info->adapter; + if ((!adapter) || (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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_read_debugfs_csr(file, buf, count, pos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_open_debugfs_csr() - Allocates memory for private data + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int __wlan_hdd_open_debugfs_csr(struct inode *inode, + struct file *file) +{ + struct wlan_hdd_debugfs_buffer_info *info; + struct hdd_debugfs_file_info *csr; + struct hdd_adapter *adapter = NULL; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter(); + + csr = inode->i_private; + if (!csr) { + hdd_err("No private data"); + return -EINVAL; + } + + adapter = qdf_container_of(csr, struct hdd_adapter, + csr_file[csr->id]); + if (!adapter || (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) { + hdd_err("Not enough memory for file private data"); + return -ENOMEM; + } + + info->data = qdf_mem_malloc(csr->buf_max_size); + if (!info->data) { + hdd_err("roam stats debugfs buffer allocation failed"); + 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: zero + */ +static int wlan_hdd_open_debugfs_csr(struct inode *inode, + struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + + hdd_debugfs_thread_increment(); + ret = __wlan_hdd_open_debugfs_csr(inode, file); + if (ret) + hdd_debugfs_thread_decrement(); + + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_release_debugfs_csr() - Function to free private memory on + * release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int __wlan_hdd_release_debugfs_csr(struct inode *inode, + struct file *file) +{ + struct wlan_hdd_debugfs_buffer_info *info = file->private_data; + + hdd_enter(); + + if (!info) + return 0; + + 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: zero + */ +static int wlan_hdd_release_debugfs_csr(struct inode *inode, struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_release_debugfs_csr(inode, file); + hdd_debugfs_thread_decrement(); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 debufs 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_CONNECT_INFO]; + if (!csr->entry) { + strlcpy(csr->name, "connect_info", max_len); + csr->id = HDD_DEBUFS_FILE_ID_CONNECT_INFO; + csr->buf_max_size = DEBUGFS_CONNECT_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 debugfs file: %s", + csr->name); + } + + 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_llstat.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_llstat.c new file mode 100644 index 0000000000000000000000000000000000000000..eb2ebd62b781118004938136cb2b58b1eaa22dda --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_llstat.c @@ -0,0 +1,560 @@ +/* + * 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: wlan_hdd_debugfs_llstat.c + * + * WLAN Host Device Driver implementation to update + * debugfs with Link Layer statistics + */ + +#include +#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 hdd_adapter *adapter, + void *data, uint32_t num_peers) +{ + tpSirWifiIfaceStat iface_stat; + tpSirWifiInterfaceInfo iface_info; + wmi_iface_link_stats *link_stats; + wmi_wmm_ac_stats *ac_stats; + wmi_iface_offload_stats *offload_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 (false == hdd_get_interface_info(adapter, &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: %pM, state: %u, roaming: %u, capabilities: %u, SSID: %s, BSSID_MAC: %pM, ap_country_str: %s, country_str: %s", + iface_info->mode, &iface_info->macAddr.bytes[0], + iface_info->state, iface_info->roaming, + iface_info->capabilities, iface_info->ssid, + &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: %u, rssi_data: %u, rssi_ack: %u, 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,\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->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, rx_ampdu: %u tx_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->rx_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); + } + + ll_stats.len += len; + mutex_unlock(&llstats_mutex); + hdd_exit(); +} + +void hdd_debugfs_process_peer_stats(struct hdd_adapter *adapter, void *data) +{ + tpSirWifiPeerStat peer_stat; + tpSirWifiPeerInfo peer_info; + tpSirWifiRateStat 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 = (tpSirWifiPeerStat) 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->numPeers); + + peer_info = (tpSirWifiPeerInfo) ((uint8_t *) peer_stat->peerInfo); + for (i = 1; i <= peer_stat->numPeers; i++) { + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nType: %d, peer_mac: %pM, capabilities: %u\nnum_rates: %d", + wmi_to_sir_peer_type(peer_info->type), + &peer_info->peerMacAddress.bytes[0], + peer_info->capabilities, peer_info->numRate); + + num_rate = peer_info->numRate; + for (j = 0; j < num_rate; j++) { + rate_stat = (tpSirWifiRateStat) ((uint8_t *) + peer_info->rateStats + (j * + sizeof(tSirWifiRateStat))); + 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.rateMcsIdx, + rate_stat->rate.bitrate, rate_stat->txMpdu, + rate_stat->rxMpdu, rate_stat->mpduLost, + rate_stat->retries, rate_stat->retriesShort, + rate_stat->retriesLong); + } + peer_info = (tpSirWifiPeerInfo) ((uint8_t *) + peer_stat->peerInfo + (i * + sizeof(tSirWifiPeerInfo)) + + (num_rate * sizeof(tSirWifiRateStat))); + } + 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; + tSirWifiRadioStat *radio_stat = (tpSirWifiRadioStat) data; + tSirWifiChannelStats *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, + "\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->onTime, + radio_stat->txTime, radio_stat->rxTime, + radio_stat->onTimeScan, radio_stat->onTimeNbd, + radio_stat->onTimeGscan, + radio_stat->onTimeRoamScan, + radio_stat->onTimePnoScan, + radio_stat->onTimeHs20, + 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->numChannels); + + for (j = 0; j < radio_stat->numChannels; j++) { + chan_stat = (tSirWifiChannelStats *) + ((uint8_t *)radio_stat->channels + + (j * sizeof(tSirWifiChannelStats))); + + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nChan width: %d, center_freq: %d, center_freq0: %d, center_freq1: %d, on_time: %d, cca_busy_time: %d", + chan_stat->channel.width, + chan_stat->channel.centerFreq, + chan_stat->channel.centerFreq0, + chan_stat->channel.centerFreq1, + chan_stat->onTime, chan_stat->ccaBusyTime); + } + + 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); + hdd_err("LL Stats buffer allocation failed"); + 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 + * @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 hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + ssize_t ret = 0; + + hdd_enter(); + + adapter = (struct hdd_adapter *)file->private_data; + if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != 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; + + /* All the events are received and buffer is populated */ + ret = hdd_debugfs_stats_update(buf, count, pos); + hdd_info("%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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_read_ll_stats_debugfs(file, buf, count, pos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_open_ll_stats_debugfs() - Function to save private on open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int __wlan_hdd_open_ll_stats_debugfs(struct inode *inode, + struct file *file) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter(); + + if (inode->i_private) + file->private_data = inode->i_private; + + adapter = (struct hdd_adapter *)file->private_data; + 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, 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: zero + */ +static int wlan_hdd_open_ll_stats_debugfs(struct inode *inode, + struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_open_ll_stats_debugfs(inode, file); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_release_ll_stats_debugfs() - Function to save private on release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int __wlan_hdd_release_ll_stats_debugfs(struct inode *inode, + struct file *file) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter(); + + if (inode->i_private) + file->private_data = inode->i_private; + + adapter = (struct hdd_adapter *)file->private_data; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != 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; + + wlan_hdd_llstats_free_buf(); + + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_release_ll_stats_debugfs() - SSR wrapper function to save private + * on release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int wlan_hdd_release_ll_stats_debugfs(struct inode *inode, + struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_release_ll_stats_debugfs(inode, file); + cds_ssr_unprotect(__func__); + + return ret; +} + +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, &fops_ll_stats_debugfs)) + return -EINVAL; + + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_offload.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_offload.c new file mode 100644 index 0000000000000000000000000000000000000000..a2ade38d92b4f78d88304b9e0b47f77385992b12 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_offload.c @@ -0,0 +1,423 @@ + +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN 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" + +/* 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 (!hdd_ctx->config->fEnableMCAddrList) { + ret = scnprintf(buf, buf_avail_len, + "\nMC addr ini is disabled\n"); + if (ret > 0) + length = ret; + return length; + } + + status = pmo_ucfg_get_mc_addr_list(hdd_ctx->psoc, + adapter->session_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, + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(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}; + QDF_STATUS status; + + status = pmo_ucfg_get_arp_offload_params(adapter->vdev, + &info); + 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}; + QDF_STATUS status; + uint32_t i; + + status = pmo_ucfg_get_ns_offload_params(adapter->vdev, + &info); + 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 + +/** + * 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; +} + +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); + if (hdd_sta_ctx->conn_info.connState != eConnectionState_Associated) { + 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_roam.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..98adc01f552f12d446c40e26c5fef74f662543c1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_roam.c @@ -0,0 +1,584 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN 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) { + hdd_err("No memory for response"); + 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 conatins 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->session_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) { + hdd_err("No memory for response"); + 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 COMMMAND"; + default: + return "UNKNOWN REASON"; + } + return "UNKNOWN REASON"; +} + +/** + * hdd_roam_scan_trigger_value_to_str() - Get trigger value string for + * enum WMI_ROAM_TRIGGER_REASON_ID + * @roam_scan_trigger: roam scan trigger ID + * @bool: 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 meaninful 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 + * @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 " + MAC_ADDRESS_STR " to " + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(scan->old_bssid), + MAC_ADDR_ARRAY(scan->new_bssid)); + } else { + ret = scnprintf(buf + length, + buf_avail_len - length, + "\nSTA is connected to " MAC_ADDRESS_STR + " before and after scan, not roamed\n", + MAC_ADDR_ARRAY(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, + MAC_ADDRESS_STR " %4u %3u %3u\n", + MAC_ADDR_ARRAY(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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c new file mode 100644 index 0000000000000000000000000000000000000000..374b2e122cff24ea0b8da83813c189d8096c8577 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 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. + */ + +/** + * DOC : wlan_hdd_disa.c + * + * WLAN Host Device Driver file for DISA certification + * + */ + +#include "wlan_hdd_disa.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 + + +/** + * 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) { + hdd_err("memory allocation failed"); + 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 + * @encrypt_decrypt_rsp_params: 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 = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("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; + } + } + + cfg80211_vendor_cmd_reply(skb); + hdd_exit(); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +static 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->session_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 += IEEE80211_ADDR_LEN; + } + + /* + * 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 == NULL) { + hdd_err("memory allocation failed"); + 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; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (hdd_ctx->config->is_ps_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_encrypt_decrypt_msg(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h new file mode 100644 index 0000000000000000000000000000000000000000..2116ea14ecdf6316c5b35c9def99a23462795fb2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 _WLAN_HDD_DISA_H +#define _WLAN_HDD_DISA_H + +#include "wlan_hdd_main.h" +#include "sir_api.h" + +#ifdef WLAN_FEATURE_DISA +/** + * 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); +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c new file mode 100644 index 0000000000000000000000000000000000000000..57de127373c1dea1bddeafb714e3dd0a9bacd21b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c @@ -0,0 +1,1701 @@ +/* + * 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. + */ + +#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 "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 "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" + +#ifdef MODULE +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#else +#define WLAN_MODULE_NAME "wlan" +#endif + +#define DISABLE_KRAIT_IDLE_PS_VAL 1 + +#define SSR_MAX_FAIL_CNT 3 +static uint8_t re_init_fail_cnt, probe_fail_cnt; + +/* + * 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_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); +} + +/** + * 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_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; +} + +/** + * 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_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: + return QDF_BUS_TYPE_PCI; + 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; + 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) { + hdd_err("hdd_ctx error"); + return -EFAULT; + } + + hdd_hif_init_driver_state_callbacks(dev, &cbk); + + hif_ctx = hif_open(qdf_ctx, mode, bus_type, &cbk); + 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; + } + + 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_hif_close; + } else { + cds_set_target_ready(true); + ret = hdd_napi_create(); + hdd_debug("hdd_napi_create returned: %d", ret); + if (ret == 0) + hdd_warn("NAPI: no instances are created"); + else if (ret < 0) { + hdd_err("NAPI creation error, rc: 0x%x, reinit: %d", + ret, reinit); + ret = -EFAULT; + goto err_hif_close; + } else { + hdd_napi_event(NAPI_EVT_INI_FILE, + (void *)hdd_ctx->napi_enable); + } + } + + hif_set_ce_service_max_yield_time(hif_ctx, + hdd_ctx->config->ce_service_max_yield_time); + pmo_ucfg_psoc_set_hif_handle(hdd_ctx->psoc, hif_ctx); + hif_set_ce_service_max_rx_ind_flush(hif_ctx, + hdd_ctx->config->ce_service_max_rx_ind_flush); + return 0; + +err_hif_close: + hdd_deinit_cds_hif_context(); + 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 == NULL) + return; + + hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE); + + hdd_napi_destroy(true); + + hdd_deinit_cds_hif_context(); + hif_close(hif_ctx); + + pmo_ucfg_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) { + hdd_err("Invalid QDF device"); + return -EINVAL; + } + + qdf_dev->dev = dev; + qdf_dev->drv_hdl = bdev; + qdf_dev->bus_type = bus_type; + qdf_dev->bid = bid; + + if (cds_smmu_mem_map_setup(qdf_dev, ucfg_ipa_is_present()) != + QDF_STATUS_SUCCESS) { + hdd_err("cds_smmu_mem_map_setup() failed"); + return -EFAULT; + } + + 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 + +static void hdd_soc_load_lock(struct device *dev, int load_op) +{ + mutex_lock(&hdd_init_deinit_lock); + hdd_start_driver_ops_timer(load_op); + 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); + hdd_stop_driver_ops_timer(); + mutex_unlock(&hdd_init_deinit_lock); +} + +static int hdd_soc_probe(struct device *dev, + void *bdev, + const struct hif_bus_id *bid, + enum qdf_bus_type bus_type) +{ + int errno; + + hdd_info("probing driver"); + + hdd_soc_load_lock(dev, eHDD_DRV_OP_PROBE); + cds_set_load_in_progress(true); + cds_set_driver_in_bad_state(false); + + /* + * Set Recovery in progress flag to flase + * as probe is started which ensures that FW is ready + */ + cds_set_recovery_in_progress(false); + + errno = hdd_init_qdf_ctx(dev, bdev, bus_type, bid); + if (errno) + goto unlock; + + errno = hdd_wlan_startup(dev); + if (errno) { + probe_fail_cnt++; + goto assert_fail_count; + } + + probe_fail_cnt = 0; + cds_set_driver_loaded(true); + hdd_start_complete(0); + cds_set_load_in_progress(false); + + hdd_soc_load_unlock(dev); + + return 0; + +assert_fail_count: + 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); +} + +static int hdd_soc_reinit(struct device *dev, void *bdev, + const struct hif_bus_id *bid, + enum qdf_bus_type bus_type) +{ + int errno; + + hdd_info("re-probing driver"); + + hdd_soc_load_lock(dev, eHDD_DRV_OP_REINIT); + cds_set_recovery_in_progress(true); + 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; + cds_set_recovery_in_progress(false); + + hdd_soc_load_unlock(dev); + + 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); + cds_set_recovery_in_progress(false); + hdd_soc_load_unlock(dev); + + return check_for_probe_defer(errno); +} + +/** + * wlan_hdd_probe() - handles probe request + * + * This function is called to probe the wlan driver + * + * @dev: wlan device structure + * @bdev: bus device structure + * @bid: bus identifier for shared busses + * @bus_type: underlying bus type + * @reinit: true if we are reinitiallizing the driver after a subsystem restart + * + * Return: 0 on successful probe + */ +static int wlan_hdd_probe(struct device *dev, void *bdev, + const struct hif_bus_id *bid, + enum qdf_bus_type bus_type, bool reinit) +{ + if (reinit) + return hdd_soc_reinit(dev, bdev, bid, bus_type); + else + return hdd_soc_probe(dev, bdev, bid, bus_type); +} + +/** + * wlan_hdd_remove() - wlan_hdd_remove + * + * This function is called by the platform driver to remove the + * driver + * + * Return: void + */ +static void wlan_hdd_remove(struct device *dev) +{ + pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + + cds_set_driver_loaded(false); + cds_set_unload_in_progress(true); + + if (!cds_wait_for_external_threads_completion(__func__)) + hdd_warn("External threads are still active attempting driver unload anyway"); + + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_warn("Debugfs threads are still active attempting driver unload anyway"); + + mutex_lock(&hdd_init_deinit_lock); + hdd_start_driver_ops_timer(eHDD_DRV_OP_REMOVE); + if (QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + epping_disable(); + epping_close(); + } else { + __hdd_wlan_exit(); + } + hdd_stop_driver_ops_timer(); + mutex_unlock(&hdd_init_deinit_lock); + + cds_set_driver_in_bad_state(false); + cds_set_unload_in_progress(false); + + pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_ssr_shutdown_event()- send ssr shutdown state + * + * This Function send send 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_send_hang_reason() - Send hang reason to the userspace + * + * Return: None + */ +static void hdd_send_hang_reason(void) +{ + enum qdf_hang_reason reason = QDF_REASON_UNSPECIFIED; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + cds_get_recovery_reason(&reason); + cds_reset_recovery_reason(); + wlan_hdd_send_hang_reason_event(hdd_ctx, reason); +} + +/** + * wlan_hdd_shutdown() - wlan_hdd_shutdown + * + * This is routine is called by platform driver to shutdown the + * driver + * + * Return: void + */ +static void wlan_hdd_shutdown(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hif_ctx) { + hdd_err("Failed to get HIF context, ignore SSR shutdown"); + return; + } + + if (!hdd_ctx) { + hdd_err("Failed to get HDD context, ignore SSR shutdown"); + return; + } + + /* mask the host controller interrupts */ + hif_mask_interrupt_call(hif_ctx); + + if (cds_is_load_or_unload_in_progress()) { + hdd_err("Load/unload in progress, ignore SSR shutdown"); + return; + } + + /* + * Force Complete all the wait events before shutdown. + * This is done at "hdd_cleanup_on_fw_down" api also to clean up the + * wait events of north bound apis. + * In case of SSR there is significant dely between FW down event and + * wlan_hdd_shutdown, there is a possibility of race condition that + * these wait events gets complete at "hdd_cleanup_on_fw_down" and + * some new event is added before shutdown. + */ + qdf_complete_wait_events(); + + /* this is for cases, where shutdown invoked from platform */ + cds_set_recovery_in_progress(true); + if (pld_is_pdr(hdd_ctx->parent_dev) && ucfg_ipa_is_enabled()) + ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev); + hdd_wlan_ssr_shutdown_event(); + hdd_send_hang_reason(); + + if (!cds_wait_for_external_threads_completion(__func__)) + hdd_err("Host is not ready for SSR, attempting anyway"); + + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_err("Debufs threads are still pending, attempting SSR anyway"); + + if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + hif_disable_isr(hif_ctx); + hdd_wlan_shutdown(); + } +} + +/** + * 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) { + hdd_err("wma_handle is null"); + 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 wont'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; +} + +/** + * __wlan_hdd_bus_suspend() - handles platform supsend + * @wow_params: collection of wow enable override parameters + * + * Does precondtion 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 opperation 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) +{ + int err; + QDF_STATUS status; + struct hdd_context *hdd_ctx; + void *hif_ctx; + void *dp_soc; + void *dp_pdev; + struct pmo_wow_enable_params pmo_params; + + hdd_info("starting bus suspend"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + err = wlan_hdd_validate_context(hdd_ctx); + if (err) { + hdd_err("Invalid hdd context: %d", err); + return err; + } + + 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) { + hdd_err("Failed to get hif context"); + 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); + dp_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + err = qdf_status_to_os_return(cdp_bus_suspend(dp_soc, dp_pdev)); + if (err) { + hdd_err("Failed cdp bus suspend: %d", err); + return err; + } + + err = hif_bus_early_suspend(hif_ctx); + if (err) { + hdd_err("Failed hif bus early suspend"); + goto resume_cdp; + } + + status = pmo_ucfg_psoc_bus_suspend_req(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND, + &pmo_params); + err = qdf_status_to_os_return(status); + if (err) { + hdd_err("Failed pmo bus suspend: %d", status); + goto late_hif_resume; + } + + err = hif_bus_suspend(hif_ctx); + if (err) { + hdd_err("Failed hif bus suspend: %d", err); + goto resume_pmo; + } + + hdd_info("bus suspend succeeded"); + return 0; + +resume_pmo: + status = pmo_ucfg_psoc_bus_resume_req(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + +late_hif_resume: + status = hif_bus_late_resume(hif_ctx); + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + +resume_cdp: + status = cdp_bus_resume(dp_soc, dp_pdev); + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + + return err; +} + +int wlan_hdd_bus_suspend(void) +{ + int ret; + struct wow_enable_params default_params = {0}; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_suspend(default_params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_SUSPEND_RESUME_TEST +int wlan_hdd_unit_test_bus_suspend(struct wow_enable_params wow_params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_suspend(wow_params); + cds_ssr_unprotect(__func__); + + return ret; +} +#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 + */ +static 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_info("start bus_suspend_noirq"); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) { + hdd_err("Invalid HDD context: errno %d", errno); + return errno; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver module closed; skip bus-noirq suspend"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("hif_ctx is null"); + return -EINVAL; + } + + errno = hif_bus_suspend_noirq(hif_ctx); + if (errno) + goto done; + + errno = pmo_ucfg_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_info("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; +} + +int wlan_hdd_bus_suspend_noirq(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_suspend_noirq(); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_bus_resume() - handles platform resume + * + * Does precondtion 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 opperation. + * Calls into wma to handshake with firmware and notify it that the bus is up. + * Calls into ol_txrx for symetry. + * Failures are treated as catastrophic. + * + * return: error code or 0 for success + */ +static int __wlan_hdd_bus_resume(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int status; + QDF_STATUS qdf_status; + void *dp_soc; + void *dp_pdev; + + if (cds_is_driver_recovering()) + return 0; + + hdd_info("starting bus resume"); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) { + hdd_err("Invalid hdd context"); + return status; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Module closed; return success"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (NULL == hif_ctx) { + hdd_err("Failed to get hif context"); + return -EINVAL; + } + + status = hif_bus_resume(hif_ctx); + if (status) { + hdd_err("Failed hif bus resume"); + goto out; + } + + qdf_status = pmo_ucfg_psoc_bus_resume_req(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + status = qdf_status_to_os_return(qdf_status); + if (status) { + hdd_err("Failed pmo bus resume"); + goto out; + } + + 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); + dp_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + qdf_status = cdp_bus_resume(dp_soc, dp_pdev); + 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: + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() || + cds_is_fw_down()) + return 0; + + QDF_BUG(false); + + return status; +} + +int wlan_hdd_bus_resume(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_resume(); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 + */ +static 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_info("starting bus_resume_noirq"); + if (cds_is_driver_recovering()) + return 0; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) { + hdd_err("Invalid HDD context: %d", status); + return status; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Module closed return success"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (NULL == hif_ctx) + return -EINVAL; + + qdf_status = pmo_ucfg_psoc_clear_target_wake_up(hdd_ctx->psoc); + QDF_BUG(!qdf_status); + + status = hif_bus_resume_noirq(hif_ctx); + QDF_BUG(!status); + + hdd_info("bus_resume_noirq done"); + return status; +} + +int wlan_hdd_bus_resume_noirq(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_resume_noirq(); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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) +{ + int ret; + struct hif_opaque_softc *scn = NULL; + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + hdd_err("Failed to get HIF context"); + return -EFAULT; + } + + cds_ssr_protect(__func__); + ret = hif_bus_reset_resume(scn); + cds_ssr_unprotect(__func__); + return ret; +} + +#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) { + hdd_err("Invalid context"); + return -EINVAL; + } + + return pld_auto_suspend(qdf_dev->dev); +} + +/** + * __wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend + * + * 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; + + 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 (ucfg_scan_get_pdev_status(hdd_ctx->pdev) != + SCAN_NOT_IN_PROGRESS) { + hdd_debug("Scan in progress, ignore runtime suspend"); + return -EBUSY; + } + + status = pmo_ucfg_psoc_bus_runtime_suspend(hdd_ctx->psoc, + hdd_pld_runtime_suspend_cb); + err = qdf_status_to_os_return(status); + + hdd_debug("Runtime suspend done result: %d", err); + + return err; +} + +/** + * wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend + * + * This function is called by the platform driver to suspend the + * wlan bus separately from system suspend + * + * Return: 0 or errno + */ +static int wlan_hdd_runtime_suspend(struct device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_runtime_suspend(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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) { + hdd_err("Invalid context"); + return -EINVAL; + } + + return pld_auto_resume(qdf_dev->dev); +} + +/** + * __wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend + * + * 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 = cds_get_context(QDF_MODULE_ID_HDD); + QDF_STATUS status; + + hdd_debug("Starting runtime resume"); + + if (wlan_hdd_validate_context(hdd_ctx)) + return 0; + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver module closed skipping runtime resume"); + return 0; + } + + status = pmo_ucfg_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); + + hdd_debug("Runtime resume done"); + + return 0; +} + +/** + * wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend + * + * This function is called by the platform driver to resume the + * wlan bus separately from system suspend + * + * Return: success since failure is a bug + */ +static int wlan_hdd_runtime_resume(struct device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_runtime_resume(dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#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; + + 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 wlan_hdd_probe(dev, bdev, id, bus_type, false); +} + +/** + * wlan_hdd_pld_remove() - remove function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_remove(struct device *dev, + enum pld_bus_type bus_type) +{ + hdd_enter(); + + wlan_hdd_remove(dev); + + hdd_exit(); +} + +/** + * wlan_hdd_pld_shutdown() - shutdown function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_shutdown(struct device *dev, + enum pld_bus_type bus_type) +{ + hdd_enter(); + mutex_lock(&hdd_init_deinit_lock); + hdd_start_driver_ops_timer(eHDD_DRV_OP_SHUTDOWN); + + wlan_hdd_shutdown(); + + hdd_stop_driver_ops_timer(); + mutex_unlock(&hdd_init_deinit_lock); + 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; + + 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 wlan_hdd_probe(dev, bdev, id, bus_type, true); +} + +/** + * wlan_hdd_pld_crash_shutdown() - crash_shutdown function registered to PLD + * @dev: device + * @pld_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 + * @pld_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) + +{ + return wlan_hdd_bus_suspend(); +} + +/** + * wlan_hdd_pld_resume() - resume function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_resume(struct device *dev, + enum pld_bus_type bus_type) +{ + return wlan_hdd_bus_resume(); +} + + +/** + * wlan_hdd_pld_suspend_noirq() - handle suspend no irq + * @dev: device + * @pld_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) +{ + return wlan_hdd_bus_suspend_noirq(); +} + +/** + * wlan_hdd_pld_resume_noirq() - handle resume no irq + * @dev: device + * @pld_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) +{ + return wlan_hdd_bus_resume_noirq(); +} + +/** + * wlan_hdd_pld_reset_resume() - reset resume function registered to PLD + * @dev: device + * @pld_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) +{ + return wlan_hdd_bus_reset_resume(); +} + +/** + * wlan_hdd_pld_notify_handler() - notify_handler function registered to PLD + * @dev: device + * @pld_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); +} + +static void wlan_hdd_purge_notifier(void) +{ + struct hdd_context *hdd_ctx; + + hdd_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd context is NULL return!!"); + return; + } + + mutex_lock(&hdd_ctx->iface_change_lock); + cds_shutdown_notifier_call(); + cds_shutdown_notifier_purge(); + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_exit(); +} + +/** + * wlan_hdd_set_the_pld_uevent() - set the pld event + * @uevent: uevent status + * + * Return: void + */ +static void wlan_hdd_set_the_pld_uevent(struct pld_uevent_data *uevent) +{ + switch (uevent->uevent) { + case PLD_RECOVERY: + cds_set_target_ready(false); + cds_set_recovery_in_progress(true); + break; + case PLD_FW_DOWN: + cds_set_target_ready(false); + cds_set_recovery_in_progress(true); + break; + } +} + +/** + * wlan_hdd_handle_the_pld_uevent() - handle the pld event + * @uevent: uevent status + * + * Return: void + */ +static void wlan_hdd_handle_the_pld_uevent(struct pld_uevent_data *uevent) +{ + enum cds_driver_state driver_state; + struct hdd_context *hdd_ctx; + + driver_state = cds_get_driver_state(); + + if (driver_state == CDS_DRIVER_STATE_UNINITIALIZED) + return; + + if (cds_is_driver_loading()) + return; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL return"); + return; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_info("Driver modules are already closed!"); + return; + } + + switch (uevent->uevent) { + case PLD_RECOVERY: + cds_set_target_ready(false); + hdd_pld_ipa_uc_shutdown_pipes(); + qdf_complete_wait_events(); + break; + case PLD_FW_DOWN: + cds_set_target_ready(false); + wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL); + if (pld_is_fw_rejuvenate(hdd_ctx->parent_dev) && + ucfg_ipa_is_enabled()) + ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev); + qdf_complete_wait_events(); + break; + default: + break; + } +} + +/** + * wlan_hdd_pld_uevent() - update driver status + * @dev: device + * @uevent: uevent status + * + * Return: void + */ +static void wlan_hdd_pld_uevent(struct device *dev, + struct pld_uevent_data *uevent) +{ + + struct hdd_context *hdd_ctx; + + hdd_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL return"); + return; + } + + hdd_info("pld event %d", uevent->uevent); + + wlan_hdd_set_the_pld_uevent(uevent); + + hdd_psoc_idle_timer_stop(hdd_ctx); + mutex_lock(&hdd_init_deinit_lock); + wlan_hdd_handle_the_pld_uevent(uevent); + mutex_unlock(&hdd_init_deinit_lock); + + wlan_hdd_purge_notifier(); + hdd_exit(); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * wlan_hdd_pld_runtime_suspend() - runtime suspend function registered to PLD + * @dev: device + * @pld_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) +{ + return wlan_hdd_runtime_suspend(dev); +} + +/** + * wlan_hdd_pld_runtime_resume() - runtime resume function registered to PLD + * @dev: device + * @pld_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) +{ + return wlan_hdd_runtime_resume(dev); +} +#endif + +/** + * wlan_hdd_pld_idle_shutdown() - wifi module idle shutdown after interface + * inactivity timeout has trigerred idle shutdown + * @dev: device to remove + * @pld_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) +{ + return hdd_psoc_idle_shutdown(dev); +} + +/** + * wlan_hdd_pld_idle_restart() - wifi module idle restart after idle shutdown + * @dev: device to remove + * @pld_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); +} + +struct pld_driver_ops wlan_drv_ops = { + .probe = wlan_hdd_pld_probe, + .remove = wlan_hdd_pld_remove, + .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 FEATURE_RUNTIME_PM + .runtime_suspend = wlan_hdd_pld_runtime_suspend, + .runtime_resume = wlan_hdd_pld_runtime_resume, +#endif + .idle_shutdown = wlan_hdd_pld_idle_shutdown, + .idle_restart = wlan_hdd_pld_idle_restart, + +}; + +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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c new file mode 100644 index 0000000000000000000000000000000000000000..adc27971076b0df87814e4a838a5606442ca656b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c @@ -0,0 +1,4325 @@ +/* + * 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: wlan_hdd_ext_scan.c + * + * WLAN Host Device Driver EXT SCAN feature implementation + * + */ + +#ifdef FEATURE_WLAN_EXTSCAN + +#include "wlan_hdd_ext_scan.h" +#include "wlan_hdd_regulatory.h" +#include "cds_utils.h" +#include "cds_sched.h" +#include + +#define EXTSCAN_PARAM_MAX QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + +/* 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; + +static const struct nla_policy wlan_hdd_extscan_config_policy +[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS] = { + .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] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [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}, +}; + +static 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 + }, +}; + +static const struct nla_policy +wlan_hdd_extscan_results_policy[QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD] = { + .type = NLA_U16}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY] = { + .type = NLA_U16}, +}; + +/** + * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target + * @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(void *ctx, + struct ext_scan_capabilities_response *data) +{ + struct hdd_ext_scan_context *context; + struct hdd_context *hdd_ctx = ctx; + + 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 + * @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(void *ctx, + struct extscan_cached_scan_results *data) +{ + struct hdd_context *hdd_ctx = ctx; + 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 = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("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: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Beacon Period %u " + "Capability 0x%x " + "Ie length %d", + ap->ts, + ap->ssid, + MAC_ADDR_ARRAY(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); + } + + 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: + if (skb) + kfree_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 + * @ctx: Pointer to hdd context + * @pData: 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(void *ctx, + struct extscan_hotlist_match *data) +{ + struct hdd_context *hdd_ctx = ctx; + 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 = cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, flags); + + if (!skb) { + hdd_err("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: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u", + i, + data->ap[i].ts, + data->ap[i].ssid, + MAC_ADDR_ARRAY(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; + } + + cfg80211_vendor_event(skb, flags); + hdd_exit(); + return; + +fail: + kfree_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() - + * significant wifi change results indication + * @ctx: Pointer to hdd context + * @pData: 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( + void *ctx, + tpSirWifiSignificantChangeEvent pData) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) ctx; + 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 (!pData) { + hdd_err("pData is null"); + return; + } + + skb = 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("cfg80211_vendor_event_alloc failed"); + return; + } + hdd_debug("Req Id %u Num results %u More Data %u", + pData->requestId, pData->numResults, pData->moreData); + + ap_info = &pData->ap[0]; + for (i = 0; i < pData->numResults; i++) { + hdd_debug("[i=%d] " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "numOfRssi %d", + i, + MAC_ADDR_ARRAY(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, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + pData->numResults)) { + hdd_err("put fail"); + goto fail; + } + + if (pData->numResults) { + struct nlattr *aps; + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) + goto fail; + + ap_info = &pData->ap[0]; + for (i = 0; i < pData->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, + pData->moreData)) + goto fail; + } + + cfg80211_vendor_event(skb, flags); + return; + +fail: + kfree_skb(skb); + return; + +} + +/** + * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event + * @ctx: Pointer to hdd context + * @pData: 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(void *ctx, + tpSirWifiFullScanResultEvent + pData) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) ctx; + struct sk_buff *skb = NULL; + struct timespec ts; + 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 (!pData) { + hdd_err("pData is null"); + return; + } + + if ((sizeof(*pData) + pData->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) { + hdd_err("Frame exceeded NL size limitation, drop it!!"); + return; + } + skb = 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("cfg80211_vendor_event_alloc failed"); + return; + } + + pData->ap.channel = cds_chan_to_freq(pData->ap.channel); + + /* + * Android does not want the time stamp from the frame. + * Instead it wants a monotonic increasing value since boot + */ + get_monotonic_boottime(&ts); + pData->ap.ts = ((u64)ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); + + hdd_debug("Req Id %u More Data %u", pData->requestId, + pData->moreData); + hdd_debug("AP Info: Timestamp %llu Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + pData->ap.ts, + pData->ap.ssid, + MAC_ADDR_ARRAY(pData->ap.bssid.bytes), + pData->ap.channel, + pData->ap.rssi, + pData->ap.rtt, + pData->ap.rtt_sd, + pData->ap.beaconPeriod, + pData->ap.capability, pData->ap.ieLength); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + hdd_wlan_nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + pData->ap.ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(pData->ap.ssid), + pData->ap.ssid) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(pData->ap.bssid), + pData->ap.bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + pData->ap.channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + pData->ap.rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + pData->ap.rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + pData->ap.rtt_sd) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, + pData->ap.beaconPeriod) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, + pData->ap.capability) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, + pData->ap.ieLength) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + if (pData->ap.ieLength) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + pData->ap.ieLength, pData->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); + + cfg80211_vendor_event(skb, flags); + return; + +nla_put_failure: + kfree_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event + * @ctx: Pointer to hdd context + * @pData: 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( + void *ctx, + tpSirExtScanResultsAvailableIndParams pData) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) ctx; + struct sk_buff *skb = NULL; + int flags = cds_get_gfp_flags(); + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!pData) { + hdd_err("pData is null"); + return; + } + + skb = 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("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("Req Id %u Num results %u", + pData->requestId, pData->numResultsAvailable); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + pData->numResultsAvailable)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, flags); + hdd_exit(); + return; + +nla_put_failure: + kfree_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event + * @ctx: Pointer to hdd context + * @pData: 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(void *ctx, + tpSirExtScanOnScanEventIndParams + pData) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) ctx; + struct sk_buff *skb = NULL; + 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 (!pData) { + hdd_err("pData is null"); + return; + } + + skb = 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("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("Request Id: %u Scan event type: %u Scan event status: %u buckets scanned: %u", + pData->requestId, pData->scanEventType, pData->status, + pData->buckets_scanned); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (pData->scanEventType == WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT) { + context->buckets_scanned = 0; + pData->scanEventType = WIFI_EXTSCAN_RESULTS_AVAILABLE; + spin_unlock(&context->context_lock); + } else if (pData->scanEventType == WIFI_EXTSCAN_CYCLE_STARTED_EVENT) { + context->buckets_scanned = pData->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, + pData->requestId) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE, + pData->scanEventType)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, flags); + return; + +nla_put_failure: + kfree_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found + * @hddctx: 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(void *ctx, + struct pno_match_found *data) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)ctx; + struct sk_buff *skb = NULL; + uint32_t len, i; + 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 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 = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX, + flags); + + if (!skb) { + hdd_err("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: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + data->ap[i].ts, + data->ap[i].ssid, + MAC_ADDR_ARRAY(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); + } + + cfg80211_vendor_event(skb, flags); + return; + +fail: + kfree_skb(skb); +} + +/** + * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found + * @hddctx: 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(); + + 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 = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX, + flags); + + if (!skb) { + hdd_err("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: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + data->ap.ts, + data->ap.ssid, + MAC_ADDR_ARRAY(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); + + cfg80211_vendor_event(skb, flags); + return; + +fail: + kfree_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_generic_rsp() - + * Handle a generic ExtScan Response message + * @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 + (void *ctx, + struct sir_extscan_generic_response *response) +{ + struct hdd_context *hdd_ctx = ctx; + 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); +} + +/** + * wlan_hdd_cfg80211_extscan_callback() - ext scan callback + * @ctx: Pointer to hdd context + * @evType: Event type + * @pMag: Pointer to message + * + * Return: none + */ +void wlan_hdd_cfg80211_extscan_callback(void *ctx, const uint16_t evType, + void *pMsg) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) ctx; + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_debug("Rcvd Event %d", evType); + + switch (evType) { + 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(ctx, + (struct ext_scan_capabilities_response *) pMsg); + break; + + case eSIR_EXTSCAN_HOTLIST_MATCH_IND: + wlan_hdd_cfg80211_extscan_hotlist_match_ind(ctx, pMsg); + break; + + case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND: + wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(ctx, + (tpSirWifiSignificantChangeEvent) pMsg); + break; + + case eSIR_EXTSCAN_CACHED_RESULTS_IND: + wlan_hdd_cfg80211_extscan_cached_results_ind(ctx, pMsg); + break; + + case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND: + wlan_hdd_cfg80211_extscan_scan_res_available_event(ctx, + (tpSirExtScanResultsAvailableIndParams) pMsg); + break; + + case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND: + wlan_hdd_cfg80211_extscan_full_scan_result_event(ctx, + (tpSirWifiFullScanResultEvent) pMsg); + break; + + case eSIR_EPNO_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_extscan_epno_match_found(ctx, + (struct pno_match_found *)pMsg); + break; + + case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND: + wlan_hdd_cfg80211_extscan_scan_progress_event(ctx, + (tpSirExtScanOnScanEventIndParams) pMsg); + break; + + case eSIR_PASSPOINT_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_passpoint_match_found(ctx, + (struct wifi_passpoint_match *) pMsg); + 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(ctx, pMsg); + break; + + default: + hdd_err("Unknown event type: %u", evType); + 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_SCAN_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_white_listed_ssid) + NLA_HDRLEN) + + (sizeof(data->max_number_of_black_listed_bssid) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("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_white_listed_ssid %u", + data->max_number_of_white_listed_ssid); + hdd_debug("max_number_of_black_listed_bssid (%u)", + data->max_number_of_black_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_SCAN_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_white_listed_ssid) || + nla_put_u32(skb, MAX_NUM_BLACKLISTED_BSSID, + data->max_number_of_black_listed_bssid)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + kfree_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_SCAN_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 ret; + unsigned long rc; + struct hdd_ext_scan_context *context; + tpSirGetExtScanCapabilitiesReqParams pReqMsg = NULL; + 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_EXTSCAN_SUBCMD_CONFIG_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 (!hdd_ctx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + pReqMsg->sessionId = adapter->session_id; + hdd_debug("Req Id %d Session Id %d", + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = pReqMsg->requestId; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_ext_scan_get_capabilities(hdd_ctx->mac_handle, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_get_capabilities failed(err=%d)", + status); + goto fail; + } + + 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; +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_get_cached_results() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_FLUSH \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH +/** + * __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 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) +{ + tpSirExtScanGetCachedResultsReqParams pReqMsg = NULL; + 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_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + int retval = 0; + 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 (!hdd_ctx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = adapter->session_id; + + /* Parse and fetch flush parameter */ + if (!tb[PARAM_FLUSH]) { + hdd_err("attr flush failed"); + goto fail; + } + pReqMsg->flush = nla_get_u8(tb[PARAM_FLUSH]); + hdd_debug("Req Id: %u Session Id: %d Flush: %d", + pReqMsg->requestId, pReqMsg->sessionId, pReqMsg->flush); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = pReqMsg->requestId; + context->ignore_cached_results = false; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_get_cached_results(hdd_ctx->mac_handle, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_get_cached_results failed(err=%d)", status); + goto fail; + } + + 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; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_get_cached_results() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_FLUSH + +/** + * 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 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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: " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(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 (!hdd_ctx->config->extscan_enabled) { + 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) { + hdd_err("qdf_mem_malloc failed"); + 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->session_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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * __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) { + hdd_err("qdf_mem_malloc failed"); + 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->session_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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_remove_dsrc_channels () - remove dsrc chanels + * @hdd_ctx: hdd context + * @wiphy: Pointer to wireless phy + * @chan_list: channel list + * @num_channels: number of channels + * + * Return: none + */ +static void hdd_remove_dsrc_channels(struct hdd_context *hdd_ctx, + struct wiphy *wiphy, uint32_t *chan_list, + uint8_t *num_channels) +{ + uint8_t num_chan_temp = 0; + int i; + + for (i = 0; i < *num_channels; i++) { + if (!wlan_reg_is_dsrc_chan(hdd_ctx->pdev, + wlan_reg_freq_to_chan( + hdd_ctx->pdev, + chan_list[i]))) { + chan_list[num_chan_temp] = chan_list[i]; + num_chan_temp++; + } + } + *num_channels = num_chan_temp; +} + +/** + * 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] == NULL) + 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[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint8_t num_channels = 0, i, buf[256] = {0}; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + uint32_t requestId, maxChannels; + tWifiBand wifiBand; + 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 (!hdd_ctx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + /* Parse and fetch wifi band */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]) { + hdd_err("attr wifi band failed"); + return -EINVAL; + } + wifiBand = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]); + + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]) { + hdd_err("attr max channels failed"); + return -EINVAL; + } + maxChannels = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]); + + if (maxChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("Max channels %d exceeded Valid channel list len %d", + maxChannels, WNI_CFG_VALID_CHANNEL_LIST_LEN); + return -EINVAL; + } + + hdd_debug("Req Id: %u Wifi band: %d Max channels: %d", requestId, + wifiBand, maxChannels); + status = sme_get_valid_channels_by_band(hdd_ctx->mac_handle, + wifiBand, 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, maxChannels); + + hdd_remove_dsrc_channels(hdd_ctx, wiphy, chan_list, &num_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 = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * + num_channels + + NLMSG_HDRLEN); + + if (reply_skb) { + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS, + num_channels) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS, + sizeof(u32) * num_channels, chan_list)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + ret = cfg80211_vendor_cmd_reply(reply_skb); + return ret; + } + + hdd_err("valid channels: buffer alloc fail"); + return -EINVAL; +} + +/** + * 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 + */ +int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_valid_channels(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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( + tpSirWifiScanCmdReqParams 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(tSirWifiScanCmdReqParams *req, + uint8_t total_channels) +{ + if (total_channels == WLAN_EXTSCAN_MAX_CHANNELS) { + hdd_warn( + "max #of channels %d reached, take only first %d bucket(s)", + total_channels, req->numBuckets); + 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 + * @tb: pointer to NL attributes + * + * Return: 0 on success; error number otherwise + */ +static int hdd_extscan_start_fill_bucket_channel_spec( + struct hdd_context *hdd_ctx, + tpSirWifiScanCmdReqParams req_msg, + struct nlattr **tb) +{ + mac_handle_t mac_handle; + struct nlattr *bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *buckets; + struct nlattr *channels; + int rem1, rem2; + QDF_STATUS status; + uint8_t bkt_index, j, num_channels, total_channels = 0; + uint32_t expected_buckets; + uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + + uint32_t min_dwell_time_active_bucket = + hdd_ctx->config->extscan_active_max_chn_time; + uint32_t max_dwell_time_active_bucket = + hdd_ctx->config->extscan_active_max_chn_time; + uint32_t min_dwell_time_passive_bucket = + hdd_ctx->config->extscan_passive_max_chn_time; + uint32_t max_dwell_time_passive_bucket = + hdd_ctx->config->extscan_passive_max_chn_time; + + req_msg->min_dwell_time_active = + req_msg->max_dwell_time_active = + hdd_ctx->config->extscan_active_max_chn_time; + + req_msg->min_dwell_time_passive = + req_msg->max_dwell_time_passive = + hdd_ctx->config->extscan_passive_max_chn_time; + + expected_buckets = req_msg->numBuckets; + req_msg->numBuckets = 0; + bkt_index = 0; + + mac_handle = hdd_ctx->mac_handle; + nla_for_each_nested(buckets, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC], rem1) { + + if (bkt_index >= expected_buckets) { + hdd_warn("ignoring excess buckets"); + break; + } + + if (wlan_cfg80211_nla_parse(bucket, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(buckets), nla_len(buckets), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch bucket spec */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]) { + hdd_err("attr bucket index failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].bucket = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]); + + /* Parse and fetch wifi band */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]) { + hdd_err("attr wifi band failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].band = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]); + + /* Parse and fetch period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]) { + hdd_err("attr period failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]); + + /* Parse and fetch report events */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]) { + hdd_err("attr report events failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].reportEvents = nla_get_u8( + bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]); + + /* Parse and fetch max period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]) { + hdd_err("attr max period failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].max_period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]); + + /* Parse and fetch base */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE]) { + hdd_err("attr base failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].exponent = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE]); + + /* Parse and fetch step count */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]) { + hdd_err("attr step count failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].step_count = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]); + hdd_debug("Bucket spec Index: %d Wifi band: %d period: %d report events: %d max period: %u base: %u Step count: %u", + req_msg->buckets[bkt_index].bucket, + req_msg->buckets[bkt_index].band, + req_msg->buckets[bkt_index].period, + req_msg->buckets[bkt_index].reportEvents, + req_msg->buckets[bkt_index].max_period, + req_msg->buckets[bkt_index].exponent, + req_msg->buckets[bkt_index].step_count); + + /* start with known good values for bucket dwell times */ + req_msg->buckets[bkt_index].min_dwell_time_active = + req_msg->buckets[bkt_index].max_dwell_time_active = + hdd_ctx->config->extscan_active_max_chn_time; + + req_msg->buckets[bkt_index].min_dwell_time_passive = + req_msg->buckets[bkt_index].max_dwell_time_passive = + hdd_ctx->config->extscan_passive_max_chn_time; + + /* Framework shall pass the channel list if the input WiFi band + * is WIFI_BAND_UNSPECIFIED. + * If the input WiFi band is specified (any value other than + * WIFI_BAND_UNSPECIFIED) then driver populates the channel list + */ + if (req_msg->buckets[bkt_index].band != 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, + req_msg->buckets[bkt_index].band, + chan_list, &num_channels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_GetValidChannelsByBand failed (err=%d)", + status); + return -EINVAL; + } + hdd_debug("before trimming, num_channels: %d", + num_channels); + + req_msg->buckets[bkt_index].numChannels = + QDF_MIN(num_channels, + (WLAN_EXTSCAN_MAX_CHANNELS - + total_channels)); + hdd_debug("Adj Num channels/bucket: %d total_channels: %d", + req_msg->buckets[bkt_index].numChannels, + total_channels); + total_channels += + req_msg->buckets[bkt_index].numChannels; + + for (j = 0; j < req_msg->buckets[bkt_index].numChannels; + j++) { + req_msg->buckets[bkt_index].channels[j].channel = + chan_list[j]; + req_msg->buckets[bkt_index].channels[j]. + chnlClass = 0; + if ((wlan_reg_get_channel_state( + hdd_ctx->pdev, + cds_freq_to_chan(chan_list[j]))) != + CHANNEL_STATE_ENABLE) { + req_msg->buckets[bkt_index].channels[j]. + passive = 1; + req_msg->buckets[bkt_index].channels[j]. + dwellTimeMs = + hdd_ctx->config-> + extscan_passive_max_chn_time; + /* reconfigure per-bucket dwell time */ + if (min_dwell_time_passive_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_passive_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + + } else { + req_msg->buckets[bkt_index].channels[j]. + passive = 0; + req_msg->buckets[bkt_index].channels[j]. + dwellTimeMs = + hdd_ctx->config->extscan_active_max_chn_time; + /* reconfigure per-bucket dwell times */ + if (min_dwell_time_active_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_active_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + + } + + hdd_debug("Channel: %u Passive: %u Dwell time: %u ms Class: %u", + req_msg->buckets[bkt_index].channels[j].channel, + req_msg->buckets[bkt_index].channels[j].passive, + req_msg->buckets[bkt_index].channels[j].dwellTimeMs, + req_msg->buckets[bkt_index].channels[j].chnlClass); + } + + 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, + req_msg->buckets[bkt_index].min_dwell_time_active, + req_msg->buckets[bkt_index].max_dwell_time_active, + req_msg->buckets[bkt_index].min_dwell_time_passive, + req_msg->buckets[bkt_index].max_dwell_time_passive); + + bkt_index++; + req_msg->numBuckets++; + continue; + } + + /* Parse and fetch number of channels */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]) { + hdd_err("attr num channels failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].numChannels = + nla_get_u32(bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]); + hdd_debug("before trimming: num channels %d", + req_msg->buckets[bkt_index].numChannels); + + req_msg->buckets[bkt_index].numChannels = + QDF_MIN(req_msg->buckets[bkt_index].numChannels, + (WLAN_EXTSCAN_MAX_CHANNELS - total_channels)); + hdd_debug("Num channels/bucket: %d total_channels: %d", + req_msg->buckets[bkt_index].numChannels, + total_channels); + if (hdd_extscan_channel_max_reached(req_msg, total_channels)) + return 0; + + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC]) { + hdd_err("attr channel spec failed"); + return -EINVAL; + } + + j = 0; + nla_for_each_nested(channels, + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC], rem2) { + if ((j >= req_msg->buckets[bkt_index].numChannels) || + hdd_extscan_channel_max_reached(req_msg, + total_channels)) + break; + + if (wlan_cfg80211_nla_parse(channel, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(channels), nla_len(channels), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch channel */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) { + hdd_err("attr channel failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].channel = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]); + hdd_debug("channel %u", + req_msg->buckets[bkt_index].channels[j].channel); + + /* Parse and fetch dwell time */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) { + hdd_err("attr dwelltime failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]); + + /* Override dwell time if required */ + if (req_msg->buckets[bkt_index].channels[j].dwellTimeMs < + hdd_ctx->config->extscan_active_min_chn_time || + req_msg->buckets[bkt_index].channels[j].dwellTimeMs > + hdd_ctx->config->extscan_active_max_chn_time) { + hdd_debug("WiFi band is unspecified, dwellTime:%d", + req_msg->buckets[bkt_index].channels[j].dwellTimeMs); + + if ((wlan_reg_get_channel_state( + hdd_ctx->pdev, + cds_freq_to_chan( + req_msg->buckets[bkt_index]. + channels[j].channel))) + != CHANNEL_STATE_ENABLE) { + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + hdd_ctx->config->extscan_passive_max_chn_time; + } else { + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + hdd_ctx->config->extscan_active_max_chn_time; + } + } + + hdd_debug("New Dwell time %u ms", + req_msg->buckets[bkt_index].channels[j].dwellTimeMs); + + if ((wlan_reg_get_channel_state(hdd_ctx->pdev, + cds_freq_to_chan( + req_msg->buckets[bkt_index]. + channels[j].channel))) + != CHANNEL_STATE_ENABLE) { + if (min_dwell_time_passive_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_passive_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + } else { + if (min_dwell_time_active_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_active_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + } + + /* Parse and fetch channel spec passive */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) { + hdd_err("attr channel spec passive failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].passive = + nla_get_u8(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]); + hdd_debug("Chnl spec passive %u", + req_msg->buckets[bkt_index].channels[j].passive); + /* Override scan type if required */ + if ((wlan_reg_get_channel_state(hdd_ctx->pdev, + cds_freq_to_chan( + req_msg->buckets[bkt_index]. + channels[j].channel))) + != CHANNEL_STATE_ENABLE) { + req_msg->buckets[bkt_index].channels[j].passive = true; + } else { + req_msg->buckets[bkt_index].channels[j].passive = false; + } + j++; + total_channels++; + } + + if (j != req_msg->buckets[bkt_index].numChannels) { + hdd_err("Input parameters didn't match"); + return -EINVAL; + } + + 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, + req_msg->buckets[bkt_index].min_dwell_time_active, + req_msg->buckets[bkt_index].max_dwell_time_active, + req_msg->buckets[bkt_index].min_dwell_time_passive, + req_msg->buckets[bkt_index].max_dwell_time_passive); + + bkt_index++; + req_msg->numBuckets++; + } + + 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; +} + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_start() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_BASE_PERIOD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD +#define PARAM_MAX_AP_PER_SCAN \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN +#define PARAM_RPT_THRHLD_PERCENT \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT +#define PARAM_RPT_THRHLD_NUM_SCANS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS +#define PARAM_NUM_BUCKETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS +#define PARAM_CONFIG_FLAGS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_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) +{ + tpSirWifiScanCmdReqParams pReqMsg; + 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 hdd_ext_scan_context *context; + uint32_t request_id, num_buckets; + QDF_STATUS status; + int 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; + } + + 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 (!hdd_ctx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("memory allocation failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = adapter->session_id; + + /* Parse and fetch base period */ + if (!tb[PARAM_BASE_PERIOD]) { + hdd_err("attr base period failed"); + goto fail; + } + pReqMsg->basePeriod = nla_get_u32(tb[PARAM_BASE_PERIOD]); + + /* Parse and fetch max AP per scan */ + if (!tb[PARAM_MAX_AP_PER_SCAN]) { + hdd_err("attr max_ap_per_scan failed"); + goto fail; + } + pReqMsg->maxAPperScan = nla_get_u32(tb[PARAM_MAX_AP_PER_SCAN]); + + /* Parse and fetch report threshold percent */ + if (!tb[PARAM_RPT_THRHLD_PERCENT]) { + hdd_err("attr report_threshold percent failed"); + goto fail; + } + pReqMsg->report_threshold_percent = nla_get_u8(tb[PARAM_RPT_THRHLD_PERCENT]); + + /* Parse and fetch report threshold num scans */ + if (!tb[PARAM_RPT_THRHLD_NUM_SCANS]) { + hdd_err("attr report_threshold num scans failed"); + goto fail; + } + pReqMsg->report_threshold_num_scans = nla_get_u8(tb[PARAM_RPT_THRHLD_NUM_SCANS]); + hdd_debug("Req Id: %d Session Id: %d Base Period: %d Max AP per Scan: %d Report Threshold percent: %d Report Threshold num scans: %d", + pReqMsg->requestId, pReqMsg->sessionId, + pReqMsg->basePeriod, pReqMsg->maxAPperScan, + pReqMsg->report_threshold_percent, + pReqMsg->report_threshold_num_scans); + + /* Parse and fetch number of buckets */ + if (!tb[PARAM_NUM_BUCKETS]) { + hdd_err("attr number of buckets failed"); + goto fail; + } + num_buckets = nla_get_u8(tb[PARAM_NUM_BUCKETS]); + if (num_buckets > WLAN_EXTSCAN_MAX_BUCKETS) { + hdd_warn("Exceeded MAX number of buckets: %d", + WLAN_EXTSCAN_MAX_BUCKETS); + num_buckets = WLAN_EXTSCAN_MAX_BUCKETS; + } + hdd_debug("Input: Number of Buckets %d", num_buckets); + pReqMsg->numBuckets = num_buckets; + + /* This is optional attribute, if not present set it to 0 */ + if (!tb[PARAM_CONFIG_FLAGS]) + pReqMsg->configuration_flags = 0; + else + pReqMsg->configuration_flags = + hdd_extscan_map_usr_drv_config_flags( + nla_get_u32(tb[PARAM_CONFIG_FLAGS])); + + pReqMsg->extscan_adaptive_dwell_mode = + hdd_ctx->config->extscan_adaptive_dwell_mode; + + hdd_debug("Configuration flags: %u", + pReqMsg->configuration_flags); + + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC]) { + hdd_err("attr bucket spec failed"); + goto fail; + } + + if (hdd_extscan_start_fill_bucket_channel_spec(hdd_ctx, pReqMsg, tb)) + goto fail; + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + context->buckets_scanned = 0; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_start(hdd_ctx->mac_handle, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_start failed(err=%d)", 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 == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_start() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_BASE_PERIOD +#undef PARAMS_MAX_AP_PER_SCAN +#undef PARAMS_RPT_THRHLD_PERCENT +#undef PARAMS_RPT_THRHLD_NUM_SCANS +#undef PARAMS_NUM_BUCKETS +#undef PARAM_CONFIG_FLAGS + +/** + * 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_stop() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID + +/** + * __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) +{ + tpSirExtScanStopReqParams pReqMsg = NULL; + 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 hdd_ext_scan_context *context; + QDF_STATUS status; + uint32_t request_id; + int 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 (!hdd_ctx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = adapter->session_id; + hdd_debug("Req Id %d Session Id %d", + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_stop(hdd_ctx->mac_handle, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_stop failed(err=%d)", 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_ext_scan_stop timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_stop() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID + + +/** + * 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * __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 (!hdd_ctx->config->extscan_enabled) { + 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->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 (!hdd_ctx->config->extscan_enabled) { + 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->session_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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * hdd_extscan_epno_fill_network_list() - epno fill network list + * @hddctx: HDD context + * @req_msg: request message + * @tb: vendor attribute table + * + * This function reads the network block NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +static int hdd_extscan_epno_fill_network_list( + struct hdd_context *hddctx, + struct wifi_epno_params *req_msg, + struct nlattr **tb) +{ + struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + struct nlattr *networks; + int rem1, ssid_len; + uint8_t index, *ssid; + uint32_t expected_networks; + + expected_networks = req_msg->num_networks; + index = 0; + + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST]) { + hdd_err("attr networks list failed"); + return -EINVAL; + } + nla_for_each_nested(networks, + tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST], + rem1) { + + if (index == expected_networks) { + hdd_warn("ignoring excess networks"); + break; + } + + if (wlan_cfg80211_nla_parse(network, + QCA_WLAN_VENDOR_ATTR_PNO_MAX, + nla_data(networks), + nla_len(networks), + wlan_hdd_pno_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch ssid */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]) { + hdd_err("attr network ssid failed"); + return -EINVAL; + } + ssid_len = nla_len( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]); + + /* 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--; + + req_msg->networks[index].ssid.length = ssid_len; + hdd_debug("network ssid length %d", ssid_len); + ssid = nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]); + qdf_mem_copy(req_msg->networks[index].ssid.ssId, + ssid, ssid_len); + hdd_debug("Ssid (%.*s)", + req_msg->networks[index].ssid.length, + req_msg->networks[index].ssid.ssId); + + /* Parse and fetch epno flags */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]) { + hdd_err("attr epno flags failed"); + return -EINVAL; + } + req_msg->networks[index].flags = nla_get_u8( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]); + hdd_debug("flags %u", req_msg->networks[index].flags); + + /* Parse and fetch auth bit */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]) { + hdd_err("attr auth bit failed"); + return -EINVAL; + } + req_msg->networks[index].auth_bit_field = nla_get_u8( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]); + hdd_debug("auth bit %u", + req_msg->networks[index].auth_bit_field); + + index++; + } + 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 %tb and + * fill 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_epno_params *req_msg = NULL; + 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; + uint32_t num_networks, len; + int ret_val; + + hdd_enter_dev(dev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (!hdd_ctx->config->extscan_enabled) { + 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 */ + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]) { + 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[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]); + + 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(struct wifi_epno_network)); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID]); + hdd_debug("Req Id %u", req_msg->request_id); + + req_msg->session_id = adapter->session_id; + hdd_debug("Session Id %d", req_msg->session_id); + + if (num_networks) { + + /* Parse and fetch min_5ghz_rssi */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI]) { + hdd_err("min_5ghz_rssi id failed"); + goto fail; + } + req_msg->min_5ghz_rssi = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI]); + + /* Parse and fetch min_24ghz_rssi */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI]) { + hdd_err("min_24ghz_rssi id failed"); + goto fail; + } + req_msg->min_24ghz_rssi = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI]); + + /* Parse and fetch initial_score_max */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX]) { + hdd_err("initial_score_max id failed"); + goto fail; + } + req_msg->initial_score_max = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX]); + + /* Parse and fetch current_connection_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS]) { + hdd_err("current_connection_bonus id failed"); + goto fail; + } + req_msg->current_connection_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS] + ); + + /* Parse and fetch same_network_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS]) { + hdd_err("same_network_bonus id failed"); + goto fail; + } + req_msg->same_network_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS]); + + /* Parse and fetch secure_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS]) { + hdd_err("secure_bonus id failed"); + goto fail; + } + req_msg->secure_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS]); + + /* Parse and fetch band_5ghz_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS]) { + hdd_err("band_5ghz_bonus id failed"); + goto fail; + } + req_msg->band_5ghz_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS]); + + 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); + + if (hdd_extscan_epno_fill_network_list(hdd_ctx, req_msg, tb)) + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define PARAM_ID QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID +#define PARAM_REALM QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM +#define PARAM_ROAM_ID \ + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID +#define PARAM_ROAM_PLMN \ + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN + +/** + * hdd_extscan_passpoint_fill_network_list() - passpoint fill network list + * @hddctx: HDD context + * @req_msg: request message + * @tb: vendor attribute table + * + * This function reads the network block NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +static int hdd_extscan_passpoint_fill_network_list( + struct hdd_context *hddctx, + struct wifi_passpoint_req *req_msg, + struct nlattr **tb) +{ + struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + struct nlattr *networks; + int rem1; + size_t len; + uint8_t index; + uint32_t expected_networks; + + expected_networks = req_msg->num_networks; + index = 0; + + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY]) { + hdd_err("attr network array failed"); + return -EINVAL; + } + nla_for_each_nested(networks, + tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY], + rem1) { + + if (index == expected_networks) { + hdd_warn("ignoring excess networks"); + break; + } + + if (wlan_cfg80211_nla_parse(network, + QCA_WLAN_VENDOR_ATTR_PNO_MAX, + nla_data(networks), + nla_len(networks), + wlan_hdd_pno_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch identifier */ + if (!network[PARAM_ID]) { + hdd_err("attr passpoint id failed"); + return -EINVAL; + } + req_msg->networks[index].id = nla_get_u32(network[PARAM_ID]); + hdd_debug("Id %u", req_msg->networks[index].id); + + /* Parse and fetch realm */ + if (!network[PARAM_REALM]) { + hdd_err("attr realm failed"); + return -EINVAL; + } + len = nla_strlcpy(req_msg->networks[index].realm, + network[PARAM_REALM], + SIR_PASSPOINT_REALM_LEN); + /* Don't send partial realm to firmware */ + if (len >= SIR_PASSPOINT_REALM_LEN) { + hdd_err("user passed invalid realm, len:%zu", len); + return -EINVAL; + } + + hdd_debug("realm: %s", req_msg->networks[index].realm); + + /* Parse and fetch roaming consortium ids */ + if (!network[PARAM_ROAM_ID]) { + hdd_err("attr roaming consortium ids failed"); + return -EINVAL; + } + nla_memcpy(&req_msg->networks[index].roaming_consortium_ids, + network[PARAM_ROAM_ID], + sizeof(req_msg->networks[0].roaming_consortium_ids)); + hdd_debug("roaming consortium ids"); + + /* Parse and fetch plmn */ + if (!network[PARAM_ROAM_PLMN]) { + hdd_err("attr plmn failed"); + return -EINVAL; + } + nla_memcpy(&req_msg->networks[index].plmn, + network[PARAM_ROAM_PLMN], + SIR_PASSPOINT_PLMN_LEN); + hdd_debug("plmn %02x:%02x:%02x)", + req_msg->networks[index].plmn[0], + req_msg->networks[index].plmn[1], + req_msg->networks[index].plmn[2]); + + index++; + } + 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 *req_msg = NULL; + 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; + uint32_t num_networks = 0; + int 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 */ + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]) { + hdd_err("attr num networks failed"); + return -EINVAL; + } + num_networks = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]); + 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) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + req_msg->session_id = adapter->session_id; + hdd_debug("Req Id %u Session Id %d", req_msg->request_id, + req_msg->session_id); + + if (hdd_extscan_passpoint_fill_network_list(hdd_ctx, req_msg, tb)) + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 *req_msg = NULL; + 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 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) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + req_msg->session_id = adapter->session_id; + hdd_debug("Req Id %u Session Id %d", + req_msg->request_id, req_msg->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#undef PARAM_ID +#undef PARAM_REALM +#undef PARAM_ROAM_ID +#undef PARAM_ROAM_PLMN + +/** + * 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h new file mode 100644 index 0000000000000000000000000000000000000000..3c98fe213e924f51a4bc9a167b9255aad4550856 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2012-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. + */ + +#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_valid_channels(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); + +void wlan_hdd_cfg80211_extscan_init(struct hdd_context *hdd_ctx); + +#else /* FEATURE_WLAN_EXTSCAN */ + +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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_fips.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_fips.c new file mode 100644 index 0000000000000000000000000000000000000000..a2bf8ced2dd7c456a3f3ebe82963df10221e3fc8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_fips.c @@ -0,0 +1,289 @@ +/* + * 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: wlan_hdd_fips.c + * + * WLAN Host Device Driver FIPS Certification Feature + */ + +#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 + +/** + * 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) { + hdd_err("memory allocation failed"); + 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 ret; + + cds_ssr_protect(__func__); + ret = __hdd_fips_test(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_fips.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_fips.h new file mode 100644 index 0000000000000000000000000000000000000000..945d5c630ff7088fe5ff16ae8e8e5ee681f90a94 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_fips.h @@ -0,0 +1,73 @@ +/* + * 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_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[0]; +}; + +struct iw_fips_test_response { + uint32_t status; + uint32_t data_len; + uint8_t data[0]; +}; + + +/** + * 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 formated 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c new file mode 100644 index 0000000000000000000000000000000000000000..9fc02984e56095ea1015a47c9f0acdbcf060ac0c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c @@ -0,0 +1,208 @@ +/* + * 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: 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" +#include "cfg_api.h" + +#ifdef QCA_WIFI_FTM + +#include "wlan_hdd_cfg80211.h" +#include "hif.h" +#include +#include + +struct qcmbr_data { + unsigned int cmd; + unsigned int length; + unsigned char buf[WLAN_FTM_DATA_MAX_LEN + 4]; + unsigned int copy_to_user; +}; + +/** + * 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; + + cds_cfg = qdf_mem_malloc(sizeof(*cds_cfg)); + if (!cds_cfg) { + hdd_err("failed to allocate cds config"); + return -ENOMEM; + } + + cds_cfg->driver_type = QDF_DRIVER_TYPE_MFG; + cds_cfg->powersave_offload_enabled = + hdd_ctx->config->enablePowersaveOffload; + hdd_lpass_populate_cds_config(cds_cfg, hdd_ctx); + cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE; + cds_init_ini_config(cds_cfg); + + return 0; +} + +#ifdef LINUX_QCMBR + +/** + * wlan_hdd_qcmbr_command() - QCMBR command handler + * @adapter: adapter upon which the command was received + * @pqcmbr_data: QCMBR command + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_command(struct hdd_adapter *adapter, + struct qcmbr_data *pqcmbr_data) +{ + int ret = 0; + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + ret = wlan_ioctl_ftm_testmode_cmd(hdd_ctx->pdev, + pqcmbr_data->cmd, + pqcmbr_data->buf, + pqcmbr_data->length); + + return ret; +} + +#ifdef CONFIG_COMPAT + +/** + * wlan_hdd_qcmbr_ioctl() - Compatibility-mode QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_compat_ioctl(struct hdd_adapter *adapter, + struct ifreq *ifr) +{ + struct qcmbr_data *qcmbr_data; + int ret = 0; + + qcmbr_data = qdf_mem_malloc(sizeof(*qcmbr_data)); + if (qcmbr_data == NULL) + return -ENOMEM; + + if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) { + ret = -EFAULT; + goto exit; + } + + ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data); + if ((ret == 0) && (qcmbr_data->cmd == 0x1001)) { + ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf, + (WLAN_FTM_DATA_MAX_LEN + 4)); + } + +exit: + qdf_mem_free(qcmbr_data); + return ret; +} +#else /* CONFIG_COMPAT */ +static int wlan_hdd_qcmbr_compat_ioctl(struct hdd_adapter *adapter, + struct ifreq *ifr) +{ + return 0; +} +#endif /* CONFIG_COMPAT */ + +/** + * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr) +{ + struct qcmbr_data *qcmbr_data; + int ret = 0; + + qcmbr_data = qdf_mem_malloc(sizeof(*qcmbr_data)); + if (qcmbr_data == NULL) + return -ENOMEM; + + if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) { + ret = -EFAULT; + goto exit; + } + + ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data); + if ((ret == 0) && (qcmbr_data->cmd == 0x1001)) { + ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf, + (WLAN_FTM_DATA_MAX_LEN + 4)); + } + +exit: + qdf_mem_free(qcmbr_data); + return ret; +} + +/** + * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_qcmbr_unified_ioctl(struct hdd_adapter *adapter, + struct ifreq *ifr) +{ + int ret = 0; + + if (in_compat_syscall()) + ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr); + else + ret = wlan_hdd_qcmbr_ioctl(adapter, ifr); + + return ret; +} + +#endif /* LINUX_QCMBR */ +#endif /* QCA_WIFI_FTM */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c new file mode 100644 index 0000000000000000000000000000000000000000..df5b332ae7af76e6bce068ed08d3329a24f9f205 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c @@ -0,0 +1,207 @@ +/* + * 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: wlan_hdd_green_ap.c + * + * WLAN Host Device Driver Green AP implementation + * + */ + +#include +#include +#include +#include + +/** + * hdd_green_ap_check_enable() - to check whether to enable green ap or not + * @hdd_ctx: hdd context + * @enable_green_ap: 1 - enable green ap enabled, 0 - disbale 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); + hdd_debug("No. of active sessions for mode: %d is %d", + 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; + 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; +} + +void hdd_green_ap_print_config(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [gEnableGreenAp] Value = [%u] ", + hdd_ctx->config->enable_green_ap); + hdd_debug("Name = [gEenableEGAP] Value = [%u] ", + hdd_ctx->config->enable_egap); + hdd_debug("Name = [gEGAPInactTime] Value = [%u] ", + hdd_ctx->config->egap_inact_time); + hdd_debug("Name = [gEGAPWaitTime] Value = [%u] ", + hdd_ctx->config->egap_wait_time); + hdd_debug("Name = [gEGAPFeatures] Value = [%u] ", + hdd_ctx->config->egap_feature_flag); +} + +int hdd_green_ap_update_config(struct hdd_context *hdd_ctx) +{ + struct green_ap_user_cfg green_ap_cfg; + struct hdd_config *cfg = hdd_ctx->config; + QDF_STATUS status; + + green_ap_cfg.host_enable_egap = cfg->enable_egap; + green_ap_cfg.egap_inactivity_time = cfg->egap_inact_time; + green_ap_cfg.egap_wait_time = cfg->egap_wait_time; + green_ap_cfg.egap_feature_flags = cfg->egap_feature_flag; + + status = ucfg_green_ap_update_user_config(hdd_ctx->pdev, + &green_ap_cfg); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed to update green ap user configuration"); + return -EINVAL; + } + + 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; + + cfg = hdd_ctx->config; + if (!cfg) { + hdd_err("NULL hdd config"); + return -EINVAL; + } + + if (!cfg->enable2x2 || !cfg->enable_green_ap) { + hdd_debug("Green AP not enabled: enable2x2:%d, enable_green_ap:%d", + cfg->enable2x2, cfg->enable_green_ap); + 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: + case QDF_IBSS_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; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h new file mode 100644 index 0000000000000000000000000000000000000000..b01a2542a809ca491d75a21c02dea5ee4470981d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#if !defined(WLAN_HDD_GREEN_AP_H) +#define WLAN_HDD_GREEN_AP_H + +#include "qdf_types.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_print_config() - Print Green AP component configuration + * @hdd_ctx: Global HDD context + * + * This function will print the static Green AP configuration + * + * Return: void + */ +void hdd_green_ap_print_config(struct hdd_context *hdd_ctx); + +/** + * hdd_green_ap_update_config() - Update Green AP component configuration + * @hdd_ctx: Global HDD context + * + * This function will take the static Green AP configuration and apply it + * to the Green AP component. + * + * Return: 0 on success, negative errno on any failure + */ +int hdd_green_ap_update_config(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 +void hdd_green_ap_print_config(struct hdd_context *hdd_ctx) +{ +} + +static inline +int hdd_green_ap_update_config(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 */ + +#endif /* !defined(WLAN_HDD_GREEN_AP_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap_cfg.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..7471b56e6a0ac5118605e3b8753e7255b7bdc8ca --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap_cfg.h @@ -0,0 +1,108 @@ +/* + * 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. + */ + +#ifdef WLAN_SUPPORT_GREEN_AP + +#define CFG_ENABLE_GREEN_AP_FEATURE "gEnableGreenAp" +#define CFG_ENABLE_GREEN_AP_FEATURE_MIN (0) +#define CFG_ENABLE_GREEN_AP_FEATURE_MAX (1) +#define CFG_ENABLE_GREEN_AP_FEATURE_DEFAULT (1) +#define CFG_ENABLE_GREEN_AP_FEATURE_FIELD bool enable_green_ap; +#define CFG_ENABLE_GREEN_AP_FEATURE_REG_VARIABLE \ + REG_VARIABLE(CFG_ENABLE_GREEN_AP_FEATURE, WLAN_PARAM_Integer,\ + struct hdd_config, enable_green_ap,\ + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,\ + CFG_ENABLE_GREEN_AP_FEATURE_DEFAULT,\ + CFG_ENABLE_GREEN_AP_FEATURE_MIN,\ + CFG_ENABLE_GREEN_AP_FEATURE_MAX), + +/* Enhanced Green AP (EGAP) flags/params */ +#define CFG_ENABLE_EGAP_ENABLE_FEATURE "gEnableEGAP" +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_MAX (1) +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_DEFAULT (1) +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_FIELD bool enable_egap; +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_REG_VARIABLE \ + REG_VARIABLE(CFG_ENABLE_EGAP_ENABLE_FEATURE, WLAN_PARAM_Integer,\ + struct hdd_config, enable_egap,\ + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,\ + CFG_ENABLE_EGAP_ENABLE_FEATURE_DEFAULT,\ + CFG_ENABLE_EGAP_ENABLE_FEATURE_MIN,\ + CFG_ENABLE_EGAP_ENABLE_FEATURE_MAX), + +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE "gEGAPInactTime" +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MAX (300000) +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_DEFAULT (2000) +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_FIELD uint32_t egap_inact_time; +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_REG_VARIABLE \ + REG_VARIABLE(CFG_ENABLE_EGAP_INACT_TIME_FEATURE, WLAN_PARAM_Integer,\ + struct hdd_config, egap_inact_time,\ + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,\ + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_DEFAULT,\ + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MIN,\ + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MAX),\ + +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE "gEGAPWaitTime" +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MAX (300000) +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_DEFAULT (150) +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_FIELD uint32_t egap_wait_time; +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_REG_VARIABLE \ + REG_VARIABLE(CFG_ENABLE_EGAP_WAIT_TIME_FEATURE, WLAN_PARAM_Integer,\ + struct hdd_config, egap_wait_time,\ + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,\ + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_DEFAULT,\ + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MIN,\ + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MAX),\ + +#define CFG_ENABLE_EGAP_FLAGS_FEATURE "gEGAPFeatures" +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_MAX (15) +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_DEFAULT (3) +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_FIELD uint32_t egap_feature_flag; +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_REG_VARIABLE \ + REG_VARIABLE(CFG_ENABLE_EGAP_FLAGS_FEATURE, WLAN_PARAM_Integer,\ + struct hdd_config, egap_feature_flag,\ + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT,\ + CFG_ENABLE_EGAP_FLAGS_FEATURE_DEFAULT,\ + CFG_ENABLE_EGAP_FLAGS_FEATURE_MIN,\ + CFG_ENABLE_EGAP_FLAGS_FEATURE_MAX), + +/* end Enhanced Green AP flags/params */ + +#define HDD_GREEN_AP_REG_VARIABLES \ + CFG_ENABLE_GREEN_AP_FEATURE_REG_VARIABLE \ + CFG_ENABLE_EGAP_ENABLE_FEATURE_REG_VARIABLE \ + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_REG_VARIABLE \ + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_REG_VARIABLE \ + CFG_ENABLE_EGAP_FLAGS_FEATURE_REG_VARIABLE + +#define HDD_GREEN_AP_CFG_FIELDS \ + CFG_ENABLE_GREEN_AP_FEATURE_FIELD \ + CFG_ENABLE_EGAP_ENABLE_FEATURE_FIELD \ + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_FIELD \ + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_FIELD \ + CFG_ENABLE_EGAP_FLAGS_FEATURE_FIELD + +#else /* WLAN_SUPPORT_GREEN_AP */ + +#define HDD_GREEN_AP_REG_VARIABLES +#define HDD_GREEN_AP_CFG_FIELDS + +#endif /* WLAN_SUPPORT_GREEN_AP */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_he.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_he.c new file mode 100644 index 0000000000000000000000000000000000000000..f0bfd1bc2276cb9176b3ff02f5fa6559f86a1b64 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_he.c @@ -0,0 +1,422 @@ +/* + * 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 : 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 "wma_he.h" +#include "wlan_utility.h" + +/** + * hdd_he_set_wni_cfg() - Update WNI CFG + * @hdd_ctx: HDD context + * @cfg_id: CFG to be updated + * @new_value: Value to be updated + * + * Update WNI CFG with the value passed. + * + * Return: 0 on success and errno on failure + */ +static int hdd_he_set_wni_cfg(struct hdd_context *hdd_ctx, + uint16_t cfg_id, uint32_t new_value) +{ + QDF_STATUS status; + + status = sme_cfg_set_int(hdd_ctx->mac_handle, cfg_id, new_value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not set %s", cfg_get_string(cfg_id)); + + return qdf_status_to_os_return(status); +} + +void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + uint8_t chan_width; + QDF_STATUS status; + tDot11fIEhe_cap *he_cap = &cfg->he_cap; + struct hdd_config *config = hdd_ctx->config; + + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CONTROL, he_cap->htc_he); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TWT_REQUESTOR, + he_cap->twt_request); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TWT_RESPONDER, + he_cap->twt_responder); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_FRAGMENTATION, + QDF_MIN(he_cap->fragmentation, + hdd_ctx->config->he_dynamic_frag_support)); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MAX_FRAG_MSDU, + he_cap->max_num_frag_msdu); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MIN_FRAG_SIZE, + he_cap->min_frag_size); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TRIG_PAD, + he_cap->trigger_frm_mac_pad); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MTID_AGGR, + he_cap->multi_tid_aggr); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_LINK_ADAPTATION, + he_cap->he_link_adaptation); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_ALL_ACK, he_cap->all_ack); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_UL_MU_RSP_SCHEDULING, + he_cap->ul_mu_rsp_sched); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BUFFER_STATUS_RPT, + he_cap->a_bsr); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BCAST_TWT, + he_cap->broadcast_twt); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BA_32BIT, + he_cap->ba_32bit_bitmap); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MU_CASCADING, + he_cap->mu_cascade); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MULTI_TID, + he_cap->ack_enabled_multitid); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_DL_MU_BA, he_cap->dl_mu_ba); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_OMI, he_cap->omi_a_ctrl); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_OFDMA_RA, he_cap->ofdma_ra); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MAX_AMPDU_LEN, + he_cap->max_ampdu_len); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_AMSDU_FRAG, he_cap->amsdu_frag); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_FLEX_TWT_SCHED, + he_cap->flex_twt_sched); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_CTRL, he_cap->rx_ctrl_frame); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BSRP_AMPDU_AGGR, + he_cap->bsrp_ampdu_aggr); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_QTP, he_cap->qtp); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_A_BQR, he_cap->a_bqr); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_SR_RESPONDER, + he_cap->sr_responder); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_NDP_FEEDBACK_SUPP, + he_cap->ndp_feedback_supp); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_OPS_SUPP, + he_cap->ops_supp); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_AMSDU_IN_AMPDU, + he_cap->amsdu_in_ampdu); + + he_cap->dual_band = ((cfg->band_cap == BAND_ALL) && + (hdd_ctx->config->nBandCapability == BAND_ALL)); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_DUAL_BAND, he_cap->dual_band); + 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); + + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CHAN_WIDTH, chan_width); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_PREAM_PUNC, + he_cap->rx_pream_puncturing); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CLASS_OF_DEVICE, + he_cap->device_class); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_LDPC, he_cap->ldpc_coding); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_LTF_PPDU, + he_cap->he_1x_ltf_800_gi_ppdu); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS, + he_cap->midamble_rx_max_nsts); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_LTF_NDP, + he_cap->he_4x_ltf_3200_gi_ndp); + if (config->enableRxSTBC) { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_STBC_LT80, + he_cap->rx_stbc_lt_80mhz); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_STBC_GT80, + he_cap->rx_stbc_gt_80mhz); + } else { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_STBC_LT80, 0); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_STBC_GT80, 0); + } + if (config->enableTxSTBC) { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_STBC_LT80, + he_cap->tx_stbc_lt_80mhz); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_STBC_GT80, + he_cap->tx_stbc_gt_80mhz); + } else { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_STBC_LT80, 0); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_STBC_GT80, 0); + } + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_DOPPLER, he_cap->doppler); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_UL_MUMIMO, he_cap->ul_mu); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_DCM_TX, he_cap->dcm_enc_tx); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_DCM_RX, he_cap->dcm_enc_rx); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MU_PPDU, he_cap->ul_he_mu); + + if (config->enable_su_tx_bformer) { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_SU_BEAMFORMER, + he_cap->su_beamformer); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_NUM_SOUND_LT80, + he_cap->num_sounding_lt_80); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_NUM_SOUND_GT80, + he_cap->num_sounding_gt_80); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MU_BEAMFORMER, + he_cap->mu_beamformer); + } else { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_SU_BEAMFORMER, 0); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_NUM_SOUND_LT80, 0); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_NUM_SOUND_GT80, 0); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MU_BEAMFORMER, 0); + } + + if (config->enableTxBF) { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_SU_BEAMFORMEE, + he_cap->su_beamformee); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BFEE_STS_LT80, + he_cap->bfee_sts_lt_80); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BFEE_STS_GT80, + he_cap->bfee_sts_gt_80); + } else { + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_SU_BEAMFORMEE, 0); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BFEE_STS_LT80, 0); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BFEE_STS_GT80, 0); + } + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_SU_FEED_TONE16, + he_cap->su_feedback_tone16); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MU_FEED_TONE16, + he_cap->mu_feedback_tone16); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CODEBOOK_SU, + he_cap->codebook_su); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_CODEBOOK_MU, + he_cap->codebook_mu); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_BFRM_FEED, + he_cap->beamforming_feedback); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_ER_SU_PPDU, + he_cap->he_er_su_ppdu); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_DL_PART_BW, + he_cap->dl_mu_mimo_part_bw); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_PPET_PRESENT, + he_cap->ppet_present); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_SRP, he_cap->srp); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_POWER_BOOST, + he_cap->power_boost); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_4x_LTF_GI, + he_cap->he_ltf_800_gi_4x); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MAX_NC, he_cap->max_nc); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_ER_4x_LTF_GI, + he_cap->er_he_ltf_800_gi_4x); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_PPDU_20_IN_40MHZ_2G, + he_cap->he_ppdu_20_in_40Mhz_2G); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ, + he_cap->he_ppdu_20_in_160_80p80Mhz); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ, + he_cap->he_ppdu_80_in_160_80p80Mhz); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_ER_1X_HE_LTF_GI, + he_cap->er_1x_he_ltf_gi); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF, + he_cap->midamble_rx_1x_he_ltf); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_MCS_MAP_LT_80, + he_cap->rx_he_mcs_map_lt_80); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_MCS_MAP_LT_80, + he_cap->tx_he_mcs_map_lt_80); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_MCS_MAP_160, + *((uint16_t *)he_cap->rx_he_mcs_map_160)); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_MCS_MAP_160, + *((uint16_t *)he_cap->tx_he_mcs_map_160)); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_RX_MCS_MAP_80_80, + *((uint16_t *)he_cap->rx_he_mcs_map_80_80)); + hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_TX_MCS_MAP_80_80, + *((uint16_t *)he_cap->tx_he_mcs_map_80_80)); + + /* PPET can not be configured by user - Set per band values from FW */ + status = sme_cfg_set_str(hdd_ctx->mac_handle, WNI_CFG_HE_PPET_2G, + cfg->ppet_2g, HE_MAX_PPET_SIZE); + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("could not set 2G HE PPET"); + + status = sme_cfg_set_str(hdd_ctx->mac_handle, WNI_CFG_HE_PPET_5G, + cfg->ppet_5g, HE_MAX_PPET_SIZE); + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("could not set 5G HE PPET"); +} + +void wlan_hdd_check_11ax_support(struct hdd_beacon_data *beacon, + tsap_config_t *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; +} + +void hdd_he_print_ini_config(struct hdd_context *hdd_ctx) +{ + hdd_info("Name = [%s] Value = [%d]", CFG_ENABLE_UL_MIMO_NAME, + hdd_ctx->config->enable_ul_mimo); + hdd_info("Name = [%s] Value = [%d]", CFG_ENABLE_UL_OFDMA_NAME, + hdd_ctx->config->enable_ul_ofdma); + hdd_info("Name = [%s] Value = [%d]", CFG_HE_STA_OBSSPD_NAME, + hdd_ctx->config->he_sta_obsspd); + hdd_info("Name = [%s] Value = [%d]", CFG_HE_DYNAMIC_FRAGMENTATION_NAME, + hdd_ctx->config->he_dynamic_frag_support); +} + +int hdd_update_he_cap_in_cfg(struct hdd_context *hdd_ctx) +{ + uint32_t val, val1 = 0; + QDF_STATUS status; + int ret; + struct hdd_config *config = hdd_ctx->config; + + ret = hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_STA_OBSSPD, + config->he_sta_obsspd); + if (ret) + return ret; + + status = sme_cfg_get_int(hdd_ctx->mac_handle, + WNI_CFG_HE_UL_MUMIMO, &val); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get WNI_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 + */ + if (val & 0x1) + val1 = config->enable_ul_mimo & 0x1; + + if ((val >> 1) & 0x1) + val1 |= ((config->enable_ul_ofdma & 0x1) << 1); + + ret = hdd_he_set_wni_cfg(hdd_ctx, WNI_CFG_HE_UL_MUMIMO, val1); + + return ret; +} + +void hdd_he_set_sme_config(tSmeConfigParams *sme_config, + struct hdd_config *config) +{ + sme_config->csrConfig.enable_ul_ofdma = config->enable_ul_ofdma; + sme_config->csrConfig.enable_ul_mimo = config->enable_ul_mimo; +} + +/* + * __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 = 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 = cfg80211_vendor_cmd_reply(reply_skb); + hdd_exit(); + return ret; + +nla_put_failure: + hdd_err("nla put fail"); + kfree_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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_he_cap(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c new file mode 100644 index 0000000000000000000000000000000000000000..b4dc83c6cc5dbd75fa22771374d5e2b10cca4f22 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c @@ -0,0 +1,9398 @@ +/* + * 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: wlan_hdd_hostapd.c + * + * WLAN Host Device Driver implementation + */ + +/* Include Files */ + +#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 "wlan_hdd_p2p.h" +#include +#include "cfg_api.h" +#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 "wlan_hdd_cfg.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_tsf.h" +#include +#include "wlan_hdd_power.h" +#include "wlan_hdd_object_manager.h" +#include +#include +#include +#include "wlan_hdd_he.h" +#include "wlan_dfs_tgt_api.h" +#include "wlan_dfs_utils_api.h" +#include +#include "wlan_utility.h" +#include +#include "sir_api.h" +#include "sme_api.h" +#include "wlan_hdd_regulatory.h" +#include +#include +#include +#include "wlan_action_oui_ucfg_api.h" + +#define IS_UP(_dev) \ + (((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP)) +#define IS_UP_AUTO(_ic) \ + (IS_UP((_ic)->ic_dev) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO) +#define WE_WLAN_VERSION 1 +#define WE_GET_STA_INFO_SIZE 30 +/* 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) + +#define SAP_24GHZ_CH_COUNT (14) +#define ACS_SCAN_EXPIRY_TIMEOUT_S 4 + +/* Defines the BIT position of HT caps is support mode field of stainfo */ +#define HDD_HT_CAPS_PRESENT 0 +/* Defines the BIT position of VHT caps is support mode field of stainfo */ +#define HDD_VHT_CAPS_PRESENT 1 +/* Defines the BIT position of HE caps is support mode field of stainfo */ +#define HDD_HE_CAPS_PRESENT 2 + +/* + * 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} } +}; + +/*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}, {1560, 1733} } +}; + +/* 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"); + qdf_spinlock_create(&hdd_ctx->sap_update_info_lock); + + 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->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->session_id, reinit); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("wlansap_start failed!! status: %d", status); + adapter->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->session_id); + + return NULL; +} + +/** + * hdd_hostapd_deinit_sap_session() - To de-init the sap session completely + * @adapter: SAP/GO 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 hdd_adapter *adapter) +{ + struct sap_context *sap_ctx; + int status = 0; + + if (!adapter) { + hdd_err("invalid adapter"); + return -EINVAL; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + if (!sap_ctx) { + hdd_debug("sap context already released, nothing to be done"); + return 0; + } + + if (!QDF_IS_STATUS_SUCCESS(sap_deinit_ctx(sap_ctx))) { + hdd_err("Error stopping the sap session"); + status = -EINVAL; + } + + if (!QDF_IS_STATUS_SUCCESS(sap_destroy_ctx(sap_ctx))) { + hdd_err("Error closing the sap session"); + status = -EINVAL; + } + adapter->session.ap.sap_context = NULL; + + 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 + * @channel: current channel + * + * Return: None + */ +static void hdd_hostapd_channel_allow_suspend(struct hdd_adapter *adapter, + uint8_t channel) +{ + + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + hdd_debug("bss_state: %d, channel: %d, dfs_ref_cnt: %d", + hostapd_state->bss_state, channel, + atomic_read(&hdd_ctx->sap_dfs_ref_cnt)); + + /* Return if BSS is already stopped */ + if (hostapd_state->bss_state == BSS_STOP) + return; + + if (wlan_reg_get_channel_state(hdd_ctx->pdev, channel) != + CHANNEL_STATE_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: %d)", channel); + 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 + * @channel: current channel + * + * Return - None + */ +static void hdd_hostapd_channel_prevent_suspend(struct hdd_adapter *adapter, + uint8_t channel) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + hdd_debug("bss_state: %d, channel: %d, dfs_ref_cnt: %d", + hostapd_state->bss_state, channel, + 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; + + if (wlan_reg_get_channel_state(hdd_ctx->pdev, channel) != + CHANNEL_STATE_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: %d)", channel); + 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); + + qdf_spinlock_destroy(&hdd_ctx->sap_update_info_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; + /* + * Check statemachine state and also stop iface change timer if running + */ + ret = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (ret) { + hdd_err("Failed to start WLAN modules return"); + return ret; + } + + ret = hdd_start_adapter(adapter); + 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 + * @dev: pointer to net device + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_open(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_hostapd_stop() - hdd stop function for hostapd interface + * This is called in response to ifconfig down + * + * @dev: pointer to net_device structure + * + * Return - 0 for success non-zero for failure + */ +static int __hdd_hostapd_stop(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) { + set_bit(DOWN_DURING_SSR, &adapter->event_flags); + 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); + + hdd_exit(); + return 0; +} + +/** + * hdd_hostapd_stop() - SSR wrapper for__hdd_hostapd_stop + * @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 *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_hostapd_uninit() - hdd uninit function + * This is called during the netdev unregister to uninitialize all data + * associated with the device. + * + * @dev: pointer to net_device structure + * + * 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 (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid magic"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (NULL == 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->dev = NULL; + adapter->magic = 0; + + hdd_exit(); +} + +/** + * hdd_hostapd_uninit() - SSR wrapper for __hdd_hostapd_uninit + * @dev: pointer to net_device + * + * Return: 0 on success, error number otherwise + */ +static void hdd_hostapd_uninit(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_hostapd_uninit(dev); + cds_ssr_unprotect(__func__); +} + +/** + * __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 + * @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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_change_mtu(dev, new_mtu); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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->session_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; +} +#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; + struct qdf_mac_addr mac_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 " MAC_ADDRESS_STR, + adapter_temp->dev->name, + MAC_ADDR_ARRAY(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 (ETHER_IS_MULTICAST(psta_mac_addr->sa_data)) { + hdd_err("MAC is Multicast"); + return -EINVAL; + } + + hdd_info("Changing MAC to " MAC_ADDRESS_STR " of interface %s ", + MAC_ADDR_ARRAY(mac_addr.bytes), + dev->name); + hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr, &mac_addr); + memcpy(&adapter->mac_addr, psta_mac_addr->sa_data, ETH_ALEN); + memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + hdd_exit(); + return 0; +} + +/** + * hdd_hostapd_set_mac_address() - set mac address + * @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 *dev, void *addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_set_mac_address(dev, addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +static void hdd_clear_sta(struct hdd_adapter *adapter, uint8_t sta_id) +{ + struct hdd_ap_ctx *ap_ctx; + struct hdd_station_info *sta_info; + struct csr_del_sta_params del_sta_params; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + + if (sta_id == ap_ctx->broadcast_sta_id) + return; + + sta_info = &adapter->sta_info[sta_id]; + if (!sta_info->in_use) + return; + + wlansap_populate_del_sta_params(sta_info->sta_mac.bytes, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + (SIR_MAC_MGMT_DISASSOC >> 4), + &del_sta_params); + + hdd_softap_sta_disassoc(adapter, &del_sta_params); +} + +static void hdd_clear_all_sta(struct hdd_adapter *adapter) +{ + uint8_t sta_id; + + hdd_enter_dev(adapter->dev); + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) + hdd_clear_sta(adapter, sta_id); +} + +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->event_flags)) { + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_debug("Deleting SAP/P2P link!!!!!!"); + + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + errno = (status == QDF_STATUS_SUCCESS) ? 0 : -EBUSY; + } + hdd_exit(); + return errno; +} + +/** + * hdd_chan_change_notify() - Function to notify hostapd about channel change + * @hostapd_adapter: hostapd adapter + * @dev: Net device structure + * @chan_change: New channel change parameters + * @legacy_phymode: is the phymode legacy + * + * This function is used to notify hostapd about the channel change + * + * Return: Success on intimating userspace + * + */ +QDF_STATUS hdd_chan_change_notify(struct hdd_adapter *adapter, + struct net_device *dev, + struct hdd_chan_change_params chan_change, + bool legacy_phymode) +{ + struct ieee80211_channel *chan; + struct cfg80211_chan_def chandef; + enum nl80211_channel_type channel_type; + uint32_t freq; + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + + if (!mac_handle) { + hdd_err("mac_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + hdd_debug("chan:%d width:%d sec_ch_offset:%d seg0:%d seg1:%d", + chan_change.chan, chan_change.chan_params.ch_width, + chan_change.chan_params.sec_ch_offset, + chan_change.chan_params.center_freq_seg0, + chan_change.chan_params.center_freq_seg1); + + freq = cds_chan_to_freq(chan_change.chan); + + chan = ieee80211_get_channel(adapter->wdev.wiphy, freq); + + if (!chan) { + hdd_err("Invalid input frequency for channel conversion"); + return QDF_STATUS_E_FAILURE; + } + + if (legacy_phymode) { + channel_type = NL80211_CHAN_NO_HT; + } else { + switch (chan_change.chan_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(&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. + */ + if (chan_change.chan_params.ch_width == CH_WIDTH_80MHZ) + chandef.width = NL80211_CHAN_WIDTH_80; + else if (chan_change.chan_params.ch_width == CH_WIDTH_80P80MHZ) + chandef.width = NL80211_CHAN_WIDTH_80P80; + else if (chan_change.chan_params.ch_width == CH_WIDTH_160MHZ) + chandef.width = NL80211_CHAN_WIDTH_160; + + if ((chan_change.chan_params.ch_width == CH_WIDTH_80MHZ) || + (chan_change.chan_params.ch_width == CH_WIDTH_80P80MHZ) || + (chan_change.chan_params.ch_width == CH_WIDTH_160MHZ)) { + if (chan_change.chan_params.center_freq_seg0) + chandef.center_freq1 = cds_chan_to_freq( + chan_change.chan_params.center_freq_seg0); + + if (chan_change.chan_params.center_freq_seg1) + chandef.center_freq2 = cds_chan_to_freq( + chan_change.chan_params.center_freq_seg1); + } + + hdd_debug("notify: chan:%d width:%d freq1:%d freq2:%d", + chandef.chan->center_freq, chandef.width, chandef.center_freq1, + chandef.center_freq2); + + cfg80211_ch_switch_notify(dev, &chandef); + + return QDF_STATUS_SUCCESS; +} + +/** + * 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 = cfg80211_vendor_event_alloc(hdd_context->wiphy, + wdev, + data_size + NLMSG_HDRLEN, + index, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("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"); + kfree_skb(vendor_event); + return QDF_STATUS_E_FAILURE; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_send_conditional_chan_switch_status() - Send conditional channel switch + * status + * @hdd_ctx: HDD context + * @wdev: Wireless device structure + * @status: Status of conditional channel switch + * (0: Success, Non-zero: Failure) + * + * Sends the status of conditional channel switch to user space. This is named + * conditional channel switch because the SAP will move to the provided channel + * after some condition (pre-cac) is met. + * + * Return: None + */ +static void hdd_send_conditional_chan_switch_status(struct hdd_context *hdd_ctx, + struct wireless_dev *wdev, + bool status) +{ + struct sk_buff *event; + + hdd_enter_dev(wdev->netdev); + + if (!hdd_ctx) { + hdd_err("Invalid HDD context pointer"); + return; + } + + event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + wdev, sizeof(uint32_t) + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX, + GFP_KERNEL); + if (!event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(event, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS, + status)) { + hdd_err("nla put failed"); + kfree_skb(event); + return; + } + + cfg80211_vendor_event(event, GFP_KERNEL); +} + +/** + * wlan_hdd_set_pre_cac_complete_status() - Set pre cac complete status + * @ap_adapter: AP adapter + * @status: Status which can be true or false + * + * Sets the status of pre cac i.e., whether it is complete or not + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_set_pre_cac_complete_status(struct hdd_adapter *ap_adapter, + bool status) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_pre_cac_complete_status( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), status); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +/** + * hdd_check_adapter() - check adapter existing or not + * @adapter: adapter + * + * Check adapter in the hdd global list or not + * + * Return: true if adapter exists. + */ +static bool hdd_check_adapter(struct hdd_adapter *adapter) +{ + struct hdd_adapter *temp; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return false; + } + hdd_for_each_adapter(hdd_ctx, temp) { + if (temp == adapter) + return true; + } + + return false; +} + +/** + * __wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure + * @data: AP adapter + * + * Deletes the pre cac adapter + * + * Return: None + */ +static void __wlan_hdd_sap_pre_cac_failure(void *data) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + + hdd_enter(); + + adapter = (struct hdd_adapter *) data; + if (!adapter || !hdd_check_adapter(adapter) || + adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("SAP Pre CAC adapter invalid"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) { + hdd_err("HDD context is null"); + return; + } + + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->mac_addr.bytes); + hdd_stop_adapter_ext(hdd_ctx, adapter, HDD_IN_CAC_WORK_TH_CONTEXT); + hdd_close_adapter(hdd_ctx, adapter, false); +} + +/** + * wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure + * @data: AP adapter + * + * Deletes the pre cac adapter + * + * Return: None + */ +void wlan_hdd_sap_pre_cac_failure(void *data) +{ + cds_ssr_protect(__func__); + __wlan_hdd_sap_pre_cac_failure(data); + cds_ssr_unprotect(__func__); +} + +/** + * wlan_hdd_sap_pre_cac_success() - Process the pre cac result + * @data: AP adapter + * + * Deletes the pre cac adapter and moves the existing SAP to the pre cac + * channel + * + * Return: None + */ +static void wlan_hdd_sap_pre_cac_success(void *data) +{ + struct hdd_adapter *adapter, *ap_adapter; + int i; + struct hdd_context *hdd_ctx; + + hdd_enter(); + + adapter = (struct hdd_adapter *) data; + if (!adapter || !hdd_check_adapter(adapter) || + adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("SAP Pre CAC adapter invalid"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + cds_ssr_protect(__func__); + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->mac_addr.bytes); + hdd_stop_adapter_ext(hdd_ctx, adapter, HDD_IN_CAC_WORK_TH_CONTEXT); + hdd_close_adapter(hdd_ctx, adapter, false); + cds_ssr_unprotect(__func__); + + /* 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. + */ + wlan_hdd_set_pre_cac_complete_status(ap_adapter, true); + + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->session_id, + CSA_REASON_PRE_CAC_SUCCESS); + i = hdd_softap_set_channel_change(ap_adapter->dev, + ap_adapter->pre_cac_chan, + CH_WIDTH_MAX, false); + if (0 != i) { + hdd_err("failed to change channel"); + wlan_hdd_set_pre_cac_complete_status(ap_adapter, false); + } +} + +#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(tpSap_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 chan_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_channel_list); + hdd_ctx->last_acs_channel_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->channellist) { + chan_list_size = comp_evt->num_of_channels * + sizeof(comp_evt->channellist[0]); + hdd_ctx->last_acs_channel_list = qdf_mem_malloc( + chan_list_size); + if (hdd_ctx->last_acs_channel_list) { + qdf_mem_copy(hdd_ctx->last_acs_channel_list, + comp_evt->channellist, + chan_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(tpSap_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_err("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() - calcuate 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 calcuate_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 (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; +} + +/** + * 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. + */ + + +static int 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 QCA_WLAN_802_11_MODE_INVALID; + } + +} + +/** + * hdd_fill_station_info() - fill stainfo once connected + * @stainfo: peer stainfo associate to SAP + * @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; + uint8_t i = 0, oldest_disassoc_sta_idx = WLAN_MAX_STA_COUNT + 1; + qdf_time_t oldest_disassoc_sta_ts = 0; + + if (event->staId >= WLAN_MAX_STA_COUNT) { + hdd_err("invalid sta id"); + return; + } + + stainfo = &adapter->sta_info[event->staId]; + + if (!stainfo) { + hdd_err("invalid stainfo"); + return; + } + + qdf_mem_copy(&stainfo->capability, &event->capability_info, + sizeof(uint16_t)); + stainfo->freq = cds_chan_to_freq(event->chan_info.chan_id); + 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->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 = + calcuate_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; + + 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_VHT_CAPS_PRESENT); + } + if (event->ht_caps.present) { + stainfo->ht_present = true; + hdd_copy_ht_caps(&stainfo->ht_caps, &event->ht_caps); + stainfo->support_mode |= + (stainfo->ht_present << HDD_HT_CAPS_PRESENT); + } + stainfo->support_mode |= + (event->he_caps_present << HDD_HE_CAPS_PRESENT); + + /* Initialize DHCP info */ + stainfo->dhcp_phase = DHCP_PHASE_ACK; + stainfo->dhcp_nego_status = DHCP_NEGO_STOP; + + while (i < WLAN_MAX_STA_COUNT) { + if (!qdf_mem_cmp(adapter->cache_sta_info[i].sta_mac.bytes, + event->staMac.bytes, + QDF_MAC_ADDR_SIZE)) + break; + i++; + } + if (i >= WLAN_MAX_STA_COUNT) { + i = 0; + while (i < WLAN_MAX_STA_COUNT) { + if (adapter->cache_sta_info[i].in_use != TRUE) + break; + + if (adapter->cache_sta_info[i].disassoc_ts && + (!oldest_disassoc_sta_ts || + (qdf_system_time_after( + oldest_disassoc_sta_ts, + adapter-> + cache_sta_info[i].disassoc_ts)))) { + oldest_disassoc_sta_ts = + adapter-> + cache_sta_info[i].disassoc_ts; + oldest_disassoc_sta_idx = i; + } + i++; + } + } + + if ((i == WLAN_MAX_STA_COUNT) && oldest_disassoc_sta_ts) { + hdd_debug("reached max cached staid, removing oldest stainfo"); + i = oldest_disassoc_sta_idx; + } + if (i < WLAN_MAX_STA_COUNT) { + qdf_mem_zero(&adapter->cache_sta_info[i], + sizeof(*stainfo)); + qdf_mem_copy(&adapter->cache_sta_info[i], + stainfo, sizeof(struct hdd_station_info)); + + } else { + hdd_debug("reached max staid, stainfo can't be cached"); + } + + 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); +} + +/** + * 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 + */ +static void +hdd_stop_sap_due_to_invalid_channel(struct work_struct *work) +{ + /* + * Extract the adapter from work structure. sap_stop_bss_work + * is part of adapter context. + */ + struct hdd_adapter *sap_adapter = container_of(work, + struct hdd_adapter, + sap_stop_bss_work); + cds_ssr_protect(__func__); + if (sap_adapter == NULL) { + cds_err("sap_adapter is NULL, no work needed"); + cds_ssr_unprotect(__func__); + return; + } + hdd_debug("work started for sap session[%d]", sap_adapter->session_id); + wlan_hdd_stop_sap(sap_adapter); + wlansap_cleanup_cac_timer(WLAN_HDD_GET_SAP_CTX_PTR(sap_adapter)); + hdd_debug("work finished for sap"); + cds_ssr_unprotect(__func__); +} + +/** + * 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 = cds_chan_to_freq(event->chan_info.chan_id); + 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->session_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to disable aggregation for peer"); +} + +QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, + void *context) +{ + struct hdd_adapter *adapter; + struct hdd_ap_ctx *ap_ctx; + struct hdd_hostapd_state *hostapd_state; + struct net_device *dev; + eSapHddEvent sapEvent; + union iwreq_data wrqu; + uint8_t *we_custom_event_generic = NULL; + int we_event = 0; + int i = 0; + uint8_t staId; + QDF_STATUS qdf_status; + bool bAuthRequired = true; + tpSap_AssocMacAddr pAssocStasArray = NULL; + char unknownSTAEvent[IW_CUSTOM_MAX + 1]; + char maxAssocExceededEvent[IW_CUSTOM_MAX + 1]; + uint8_t we_custom_start_event[64]; + char *startBssEvent; + struct hdd_context *hdd_ctx; + struct iw_michaelmicfailure msg; + uint8_t ignoreCAC = 0; + struct hdd_config *cfg = NULL; + struct wlan_dfs_info dfs_info; + uint8_t cc_len = WLAN_SVC_COUNTRY_CODE_LEN; + struct hdd_adapter *con_sap_adapter; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_chan_change_params chan_change; + tSap_StationAssocReassocCompleteEvent *event; + tSap_StationSetKeyCompleteEvent *key_complete; + int ret = 0; + struct ch_params sap_ch_param = {0}; + eCsrPhyMode phy_mode; + bool legacy_phymode; + tSap_StationDisassocCompleteEvent *disassoc_comp; + struct hdd_station_info *stainfo, *cache_stainfo; + mac_handle_t mac_handle; + tsap_config_t *sap_config; + struct wlan_objmgr_vdev *vdev; + + dev = context; + if (!dev) { + hdd_err("context is null"); + return QDF_STATUS_E_FAILURE; + } + + adapter = netdev_priv(dev); + + if ((NULL == adapter) || + (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("invalid adapter or adapter has invalid magic"); + return QDF_STATUS_E_FAILURE; + } + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + + if (!pSapEvent) { + hdd_err("pSapEvent is null"); + return QDF_STATUS_E_FAILURE; + } + + sapEvent = pSapEvent->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 = ap_ctx->operating_channel; + sme_get_country_code(mac_handle, dfs_info.country_code, &cc_len); + staId = pSapEvent->sapevt.sapStartBssCompleteEvent.staId; + sap_config = &adapter->session.ap.sap_config; + + switch (sapEvent) { + case eSAP_START_BSS_EVENT: + hdd_debug("BSS status = %s, channel = %u, bc sta Id = %d", + pSapEvent->sapevt.sapStartBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS", + pSapEvent->sapevt.sapStartBssCompleteEvent. + operatingChannel, + pSapEvent->sapevt.sapStartBssCompleteEvent.staId); + ap_ctx->operating_channel = + pSapEvent->sapevt.sapStartBssCompleteEvent + .operatingChannel; + + adapter->session_id = + pSapEvent->sapevt.sapStartBssCompleteEvent.sessionId; + + sap_config->channel = + pSapEvent->sapevt.sapStartBssCompleteEvent. + operatingChannel; + sap_config->ch_params.ch_width = + pSapEvent->sapevt.sapStartBssCompleteEvent.ch_width; + + sap_config->ch_params = ap_ctx->sap_context->ch_params; + sap_config->sec_ch = ap_ctx->sap_context->secondary_ch; + + hostapd_state->qdf_status = + pSapEvent->sapevt.sapStartBssCompleteEvent.status; + + qdf_atomic_set(&adapter->ch_switch_in_progress, 0); + + status = policy_mgr_set_chan_switch_complete_evt( + hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("set event failed"); + goto stopbss; + } + wlansap_get_dfs_ignore_cac(mac_handle, &ignoreCAC); + + /* DFS requirement: DO NOT transmit during CAC. */ + if (CHANNEL_STATE_DFS != + wlan_reg_get_channel_state(hdd_ctx->pdev, + ap_ctx->operating_channel) + || ignoreCAC + || hdd_ctx->dev_dfs_cac_status == DFS_CAC_ALREADY_DONE) + 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); + + hdd_debug("The value of dfs_cac_block_tx[%d] for ApCtx[%pK]:%d", + ap_ctx->dfs_cac_block_tx, ap_ctx, + adapter->session_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; + qdf_event_set(&hostapd_state->qdf_event); + goto stopbss; + } else { + sme_ch_avoid_update_req(mac_handle); + + ap_ctx->broadcast_sta_id = + pSapEvent->sapevt.sapStartBssCompleteEvent.staId; + + /* @@@ need wep logic here to set privacy bit */ + qdf_status = + hdd_softap_register_bc_sta(adapter, + 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 = ucfg_ipa_wlan_evt(hdd_ctx->pdev, + adapter->dev, + adapter->device_mode, + ap_ctx->broadcast_sta_id, + adapter->session_id, + WLAN_IPA_AP_CONNECT, + adapter->dev->dev_addr); + 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_channel); + + hostapd_state->bss_state = BSS_START; + + /* Set default key index */ + hdd_debug("default key index %hu", ap_ctx->wep_def_key_idx); + + sme_roam_set_default_key_index(mac_handle, + adapter->session_id, + ap_ctx->wep_def_key_idx); + + /* Set group key / WEP key every time when BSS is restarted */ + if (ap_ctx->group_key.keyLength) { + status = wlansap_set_key_sta( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + &ap_ctx->group_key); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("wlansap_set_key_sta failed"); + } else { + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + if (!ap_ctx->wep_key[i].keyLength) + continue; + + status = wlansap_set_key_sta( + WLAN_HDD_GET_SAP_CTX_PTR + (adapter), + &ap_ctx->wep_key[i]); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set_key failed idx: %d", i); + } + } + + /* Fill the params for sending IWEVCUSTOM Event + * with SOFTAP.enabled + */ + startBssEvent = "SOFTAP.enabled"; + memset(&we_custom_start_event, '\0', + sizeof(we_custom_start_event)); + 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; + hdd_ipa_set_tx_flow_info(); + + hdd_debug("check for SAP restart"); + policy_mgr_check_concurrent_intf_and_restart_sap( + hdd_ctx->psoc); + + if (policy_mgr_is_hw_mode_change_after_vdev_up( + hdd_ctx->psoc)) { + hdd_debug("check for possible hw mode change"); + status = policy_mgr_set_hw_mode_on_channel_switch( + hdd_ctx->psoc, adapter->session_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("set hw mode change not done"); + policy_mgr_set_do_hw_mode_change_flag( + hdd_ctx->psoc, false); + } + /* + * 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; + } + break; /* Event will be sent after Switch-Case stmt */ + + case eSAP_STOP_BSS_EVENT: + hdd_debug("BSS stop status = %s", + pSapEvent->sapevt.sapStopBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + + hdd_hostapd_channel_allow_suspend(adapter, + ap_ctx->operating_channel); + + /* Invalidate the channel info. */ + ap_ctx->operating_channel = 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; + } + hdd_debug("bss_stop_reason=%d", ap_ctx->bss_stop_reason); + if ((BSS_STOP_DUE_TO_MCC_SCC_SWITCH != + ap_ctx->bss_stop_reason) && + (BSS_STOP_DUE_TO_VENDOR_CONFIG_CHAN != + ap_ctx->bss_stop_reason)) { + /* + * when MCC to SCC switching or vendor subcmd + * setting sap config channel happens, key storage + * should not be cleared due to hostapd will not + * repopulate the original keys + */ + ap_ctx->group_key.keyLength = 0; + for (i = 0; i < CSR_MAX_NUM_KEY; i++) + ap_ctx->wep_key[i].keyLength = 0; + } + + /* 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; + 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(&adapter->ch_switch_in_progress, 0); + 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. + */ + 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"); + } + 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); + 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"); + } + break; + case eSAP_DFS_RADAR_DETECT: + { + int i; + tsap_config_t *sap_config = + &adapter->session.ap.sap_config; + + 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"); + } + break; + } + case eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC: + hdd_debug("notification for radar detect during pre cac:%d", + adapter->session_id); + hdd_send_conditional_chan_switch_status(hdd_ctx, + &adapter->wdev, false); + hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + qdf_create_work(0, &hdd_ctx->sap_pre_cac_work, + wlan_hdd_sap_pre_cac_failure, + (void *)adapter); + qdf_sched_work(0, &hdd_ctx->sap_pre_cac_work); + break; + case eSAP_DFS_PRE_CAC_END: + hdd_debug("pre cac end notification received:%d", + adapter->session_id); + hdd_send_conditional_chan_switch_status(hdd_ctx, + &adapter->wdev, true); + ap_ctx->dfs_cac_block_tx = false; + ucfg_ipa_set_dfs_cac_tx(hdd_ctx->pdev, + ap_ctx->dfs_cac_block_tx); + hdd_ctx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE; + + qdf_create_work(0, &hdd_ctx->sap_pre_cac_work, + wlan_hdd_sap_pre_cac_success, + (void *)adapter); + qdf_sched_work(0, &hdd_ctx->sap_pre_cac_work); + 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 = &pSapEvent->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); + } + 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, + &pSapEvent->sapevt.sapStationMICFailureEvent. + staMac, QDF_MAC_ADDR_SIZE); + hdd_debug("MIC MAC " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg.src_addr.sa_data)); + if (pSapEvent->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, + pSapEvent-> + sapevt.sapStationMICFailureEvent. + staMac.bytes, + ((pSapEvent->sapevt. + sapStationMICFailureEvent. + multicast == + true) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), + pSapEvent->sapevt. + sapStationMICFailureEvent.keyId, + pSapEvent->sapevt. + sapStationMICFailureEvent.TSC, + GFP_KERNEL); + break; + + case eSAP_STA_ASSOC_EVENT: + case eSAP_STA_REASSOC_EVENT: + event = &pSapEvent->sapevt.sapStationAssocReassocCompleteEvent; + if (eSAP_STATUS_FAILURE == event->status) { + hdd_info("assoc failure: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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; + } + + if (bAuthRequired) { + qdf_status = hdd_softap_register_sta( + adapter, + true, + ap_ctx->privacy, + event->staId, + (struct qdf_mac_addr *) + wrqu.addr.sa_data, + event->wmmEnabled); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to register STA %d " + MAC_ADDRESS_STR "", qdf_status, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + } else { + qdf_status = hdd_softap_register_sta( + adapter, + false, + ap_ctx->privacy, + event->staId, + (struct qdf_mac_addr *) + wrqu.addr.sa_data, + event->wmmEnabled); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to register STA %d " + MAC_ADDRESS_STR "", qdf_status, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + } + + staId = event->staId; + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_fill_station_info(adapter, event); + + adapter->sta_info[staId].ecsa_capable = event->ecsa_capable; + + if (ucfg_ipa_is_enabled()) { + status = ucfg_ipa_wlan_evt(hdd_ctx->pdev, + adapter->dev, + adapter->device_mode, + event->staId, + adapter->session_id, + WLAN_IPA_CLIENT_CONNECT_EX, + event->staMac.bytes); + if (status) + hdd_err("WLAN_CLIENT_CONNECT_EX event failed"); + } + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + adapter->session_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_ASSOC)); + +#ifdef MSM_PLATFORM + /* start timer in sap/p2p_go */ + if (ap_ctx->ap_active == false) { + spin_lock_bh(&hdd_ctx->bus_bw_lock); + adapter->prev_tx_packets = + adapter->stats.tx_packets; + adapter->prev_rx_packets = + adapter->stats.rx_packets; + + cdp_get_intra_bss_fwd_pkts_count( + cds_get_context(QDF_MODULE_ID_SOC), + adapter->session_id, + &adapter->prev_fwd_tx_packets, + &adapter->prev_fwd_rx_packets); + + spin_unlock_bh(&hdd_ctx->bus_bw_lock); + hdd_bus_bw_compute_timer_start(hdd_ctx); + } +#endif + ap_ctx->ap_active = true; +#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; + uint16_t iesLen = event->iesLen; + + sta_info = qdf_mem_malloc(sizeof(*sta_info)); + if (!sta_info) { + hdd_err("Failed to allocate station info"); + return QDF_STATUS_E_FAILURE; + } + if (iesLen <= MAX_ASSOC_IND_IE_LEN) { + sta_info->assoc_req_ies = + (const u8 *)&event->ies[0]; + sta_info->assoc_req_ies_len = iesLen; +#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 + cfg80211_new_sta(dev, + (const u8 *)&event->staMac.bytes[0], + sta_info, GFP_KERNEL); + } else { + hdd_err("Assoc Ie length is too long"); + } + qdf_mem_free(sta_info); + } + + vdev = hdd_objmgr_get_vdev(adapter); + /* Lets abort scan to ensure smooth authentication for client */ + if (vdev && + ucfg_scan_get_vdev_status(vdev) != SCAN_NOT_IN_PROGRESS) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_id, INVALID_SCAN_ID, + false); + } + + if (vdev) + hdd_objmgr_put_vdev(vdev); + + 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, + adapter->session_id, + &event->chan_info, + adapter->device_mode); + } + + hdd_green_ap_add_sta(hdd_ctx); + break; + + case eSAP_STA_DISASSOC_EVENT: + disassoc_comp = + &pSapEvent->sapevt.sapStationDisassocCompleteEvent; + memcpy(wrqu.addr.sa_data, + &disassoc_comp->staMac, QDF_MAC_ADDR_SIZE); + + cache_stainfo = hdd_get_stainfo(adapter->cache_sta_info, + disassoc_comp->staMac); + 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->reason_code = disassoc_comp->reason_code; + cache_stainfo->disassoc_ts = qdf_system_ticks(); + } + hdd_info(" disassociated " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + + 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 (pSapEvent->sapevt.sapStationDisassocCompleteEvent.reason == + eSAP_USR_INITATED_DISASSOC) + hdd_debug(" User initiated disassociation"); + else + hdd_debug(" MAC initiated disassociation"); + we_event = IWEVEXPIRED; + qdf_status = + hdd_softap_get_sta_id(adapter, + &pSapEvent->sapevt. + sapStationDisassocCompleteEvent.staMac, + &staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to find sta id status: %d", qdf_status); + return QDF_STATUS_E_FAILURE; + } + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + adapter->session_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); + + stainfo = hdd_get_stainfo(adapter->sta_info, + disassoc_comp->staMac); + if (stainfo) { + /* Send DHCP STOP indication to FW */ + stainfo->dhcp_phase = DHCP_PHASE_ACK; + if (stainfo->dhcp_nego_status == + DHCP_NEGO_IN_PROGRESS) + hdd_post_dhcp_ind(adapter, staId, + WMA_DHCP_STOP_IND); + stainfo->dhcp_nego_status = DHCP_NEGO_STOP; + } + hdd_softap_deregister_sta(adapter, staId); + + ap_ctx->ap_active = false; + spin_lock_bh(&adapter->sta_info_lock); + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (adapter->sta_info[i].in_use + && i != + (WLAN_HDD_GET_AP_CTX_PTR(adapter))-> + broadcast_sta_id) { + ap_ctx->ap_active = true; + break; + } + } + spin_unlock_bh(&adapter->sta_info_lock); + +#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); + cfg80211_del_sta(dev, + (const u8 *)&pSapEvent->sapevt. + sapStationDisassocCompleteEvent.staMac. + bytes[0], GFP_KERNEL); + + /* Update the beacon Interval if it is P2P GO */ + qdf_status = policy_mgr_change_mcc_go_beacon_interval( + hdd_ctx->psoc, adapter->session_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(&pSapEvent->sapevt. + sapStationDisassocCompleteEvent. + staMac, ePeerDisconnected, + 0, + adapter->session_id, + NULL, + adapter->device_mode); + } +#ifdef MSM_PLATFORM + /*stop timer in sap/p2p_go */ + if (ap_ctx->ap_active == false) { + spin_lock_bh(&hdd_ctx->bus_bw_lock); + adapter->prev_tx_packets = 0; + adapter->prev_rx_packets = 0; + adapter->prev_fwd_tx_packets = 0; + adapter->prev_fwd_rx_packets = 0; + spin_unlock_bh(&hdd_ctx->bus_bw_lock); + hdd_bus_bw_compute_timer_try_stop(hdd_ctx); + } +#endif + 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_ASSOC_STA_CALLBACK_EVENT: + pAssocStasArray = + pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas; + if (pSapEvent->sapevt.sapAssocStaListEvent.noOfAssocSta != 0) { + for (i = 0; + i < + pSapEvent->sapevt.sapAssocStaListEvent. + noOfAssocSta; i++) { + hdd_info("Associated Sta Num %d:assocId=%d, staId=%d, staMac=" + MAC_ADDRESS_STR, i + 1, + pAssocStasArray->assocId, + pAssocStasArray->staId, + MAC_ADDR_ARRAY(pAssocStasArray->staMac. + bytes)); + pAssocStasArray++; + } + } + qdf_mem_free(pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas); + pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas = NULL; + return QDF_STATUS_SUCCESS; + case eSAP_UNKNOWN_STA_JOIN: + snprintf(unknownSTAEvent, IW_CUSTOM_MAX, + "JOIN_UNKNOWN_STA-%02x:%02x:%02x:%02x:%02x:%02x", + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[0], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[1], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[2], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[3], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[4], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[5]); + 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: + snprintf(maxAssocExceededEvent, IW_CUSTOM_MAX, + "Peer %02x:%02x:%02x:%02x:%02x:%02x denied" + " assoc due to Maximum Mobile Hotspot connections reached. Please disconnect" + " one or more devices to enable the new device connection", + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[0], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[1], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[2], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[3], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[4], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr. + bytes[5]); + 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: + 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: + hdd_debug("Received eSAP_CHANNEL_CHANGE_EVENT event"); + if (hostapd_state->bss_state != BSS_STOP) { + /* Prevent suspend for new channel */ + hdd_hostapd_channel_prevent_suspend(adapter, + pSapEvent->sapevt.sap_ch_selected.pri_ch); + /* Allow suspend for old channel */ + hdd_hostapd_channel_allow_suspend(adapter, + ap_ctx->operating_channel); + } + /* 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_channel = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + ap_ctx->sap_config.acs_cfg.pri_ch = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + ap_ctx->sap_config.acs_cfg.ht_sec_ch = + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch; + ap_ctx->sap_config.acs_cfg.vht_seg0_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + ap_ctx->sap_config.acs_cfg.vht_seg1_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + ap_ctx->sap_config.acs_cfg.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + + sap_ch_param.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + sap_ch_param.center_freq_seg0 = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + sap_ch_param.center_freq_seg1 = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + wlan_reg_set_channel_params(hdd_ctx->pdev, + pSapEvent->sapevt.sap_ch_selected.pri_ch, + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch, + &sap_ch_param); + + phy_mode = wlan_sap_get_phymode( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + + 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: + legacy_phymode = false; + break; + default: + legacy_phymode = true; + break; + } + + chan_change.chan = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + chan_change.chan_params.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + chan_change.chan_params.sec_ch_offset = + sap_ch_param.sec_ch_offset; + chan_change.chan_params.center_freq_seg0 = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + chan_change.chan_params.center_freq_seg1 = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + + return hdd_chan_change_notify(adapter, dev, + chan_change, legacy_phymode); + case eSAP_ACS_SCAN_SUCCESS_EVENT: + return hdd_handle_acs_scan_event(pSapEvent, adapter); + + case eSAP_ACS_CHANNEL_SELECTED: + hdd_debug("ACS Completed for wlan%d", + adapter->dev->ifindex); + clear_bit(ACS_PENDING, &adapter->event_flags); + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + ap_ctx->sap_config.acs_cfg.pri_ch = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + ap_ctx->sap_config.acs_cfg.ht_sec_ch = + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch; + ap_ctx->sap_config.acs_cfg.vht_seg0_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + ap_ctx->sap_config.acs_cfg.vht_seg1_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + ap_ctx->sap_config.acs_cfg.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + return QDF_STATUS_SUCCESS; + case eSAP_ECSA_CHANGE_CHAN_IND: + hdd_debug("Channel change indication from peer for channel %d", + pSapEvent->sapevt.sap_chan_cng_ind.new_chan); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->session_id, + CSA_REASON_PEER_ACTION_FRAME); + if (hdd_softap_set_channel_change(dev, + pSapEvent->sapevt.sap_chan_cng_ind.new_chan, + 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]", + adapter->session_id); + INIT_WORK(&adapter->sap_stop_bss_work, + hdd_stop_sap_due_to_invalid_channel); + schedule_work(&adapter->sap_stop_bss_work); + return QDF_STATUS_SUCCESS; + + case eSAP_CHANNEL_CHANGE_RESP: + hdd_debug("Channel change rsp status = %d", + pSapEvent->sapevt.ch_change_rsp_status); + /* + * Set the ch_switch_in_progress flag to zero and also enable + * roaming once channel change process (success/failure) + * is completed + */ + qdf_atomic_set(&adapter->ch_switch_in_progress, 0); + wlan_hdd_enable_roaming(adapter); + return QDF_STATUS_SUCCESS; + + default: + hdd_debug("SAP message is not handled"); + goto stopbss; + return QDF_STATUS_SUCCESS; + } + wireless_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + + return QDF_STATUS_SUCCESS; + +stopbss: + { + uint8_t we_custom_event[64]; + char *stopBssEvent = "STOP-BSS.response"; /* 17 */ + int event_len = strlen(stopBssEvent); + + hdd_debug("BSS stop status = %s", + pSapEvent->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; + +#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_warn("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); + } + } + + /* notify userspace that the BSS has stopped */ + memset(&we_custom_event, '\0', sizeof(we_custom_event)); + 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; + wireless_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + + /* 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 == sapEvent) { + qdf_event_set(&hostapd_state->qdf_stop_bss_event); + hdd_bus_bw_compute_timer_try_stop(hdd_ctx); + } + + hdd_ipa_set_tx_flow_info(); + } + return QDF_STATUS_SUCCESS; +} + +static int hdd_softap_unpack_ie(mac_handle_t mac_handle, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, + bool *pMFPCapable, + bool *pMFPRequired, + uint16_t gen_ie_len, uint8_t *gen_ie) +{ + uint32_t ret; + uint8_t *pRsnIe; + uint16_t RSNIeLen; + tDot11fIERSN dot11RSNIE = {0}; + tDot11fIEWPA dot11WPAIE = {0}; + + if (NULL == mac_handle) { + hdd_err("Error haHandle returned NULL"); + 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 */ + pRsnIe = gen_ie + 2; + RSNIeLen = gen_ie_len - 2; + /* Unpack the RSN IE */ + memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN)); + ret = sme_unpack_rsn_ie(mac_handle, pRsnIe, RSNIeLen, + &dot11RSNIE, false); + if (DOT11F_FAILED(ret)) { + hdd_err("unpack failed, ret: 0x%x", ret); + return -EINVAL; + } + /* Copy out the encryption and authentication types */ + hdd_debug("pairwise cipher suite count: %d", + dot11RSNIE.pwise_cipher_suite_count); + hdd_debug("authentication suite count: %d", + dot11RSNIE.akm_suite_cnt); + /* + * Here we have followed the apple base code, + * but probably I suspect we can do something different + * dot11RSNIE.akm_suite_cnt + * Just translate the FIRST one + */ + *pAuthType = + hdd_translate_rsn_to_csr_auth_type(dot11RSNIE.akm_suite[0]); + /* dot11RSNIE.pwise_cipher_suite_count */ + *pEncryptType = + hdd_translate_rsn_to_csr_encryption_type(dot11RSNIE. + pwise_cipher_suites[0]); + /* dot11RSNIE.gp_cipher_suite_count */ + *mcEncryptType = + hdd_translate_rsn_to_csr_encryption_type(dot11RSNIE. + gp_cipher_suite); + /* Set the PMKSA ID Cache for this interface */ + *pMFPCapable = 0 != (dot11RSNIE.RSN_Cap[0] & 0x80); + *pMFPRequired = 0 != (dot11RSNIE.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 */ + pRsnIe = gen_ie + 2 + 4; + RSNIeLen = gen_ie_len - (2 + 4); + /* Unpack the WPA IE */ + memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA)); + ret = dot11f_unpack_ie_wpa((tpAniSirGlobal) mac_handle, + pRsnIe, RSNIeLen, &dot11WPAIE, false); + if (DOT11F_FAILED(ret)) { + hdd_err("unpack failed, ret: 0x%x", ret); + return -EINVAL; + } + /* Copy out the encryption and authentication types */ + hdd_debug("WPA unicast cipher suite count: %d", + dot11WPAIE.unicast_cipher_count); + hdd_debug("WPA authentication suite count: %d", + dot11WPAIE.auth_suite_count); + /* dot11WPAIE.auth_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_wpa_to_csr_auth_type(dot11WPAIE.auth_suites[0]); + /* dot11WPAIE.unicast_cipher_count */ + *pEncryptType = + hdd_translate_wpa_to_csr_encryption_type(dot11WPAIE. + unicast_ciphers[0]); + /* dot11WPAIE.unicast_cipher_count */ + *mcEncryptType = + hdd_translate_wpa_to_csr_encryption_type(dot11WPAIE. + multicast_cipher); + *pMFPCapable = false; + *pMFPRequired = false; + } else { + hdd_err("gen_ie[0]: %d", gen_ie[0]); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_is_any_sta_connecting() - check if any sta is connecting + * @hdd_ctx: hdd context + * + * Return: true if any sta is connecting + */ +static bool hdd_is_any_sta_connecting(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_station_ctx *sta_ctx; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return false; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE) || + (adapter->device_mode == QDF_P2P_DEVICE_MODE)) { + if (sta_ctx->conn_info.connState == + eConnectionState_Connecting) { + hdd_debug("vdev_id %d: connecting", + adapter->session_id); + return true; + } + } + } + + return false; +} + +/** + * 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_channel: target channel number. + * @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_channel, + enum phy_ch_width target_bw, bool forced) +{ + QDF_STATUS status; + int ret = 0; + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx = NULL; + struct hdd_adapter *sta_adapter; + struct hdd_station_ctx *sta_ctx; + bool is_p2p_go_session = false; + struct wlan_objmgr_vdev *vdev; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + /* + * 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; + } + + ret = hdd_validate_channel_and_bandwidth(adapter, + target_channel, target_bw); + if (ret) { + hdd_err("Invalid CH and BW combo"); + return ret; + } + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + /* + * 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 && hdd_ctx->config->conc_custom_rule1) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter); + if (hdd_conn_is_connected(sta_ctx)) { + hdd_err("Channel switch not allowed after STA connection with conc_custom_rule1 enabled"); + return -EBUSY; + } + } + + /* + * 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(&adapter->ch_switch_in_progress) > 1) { + hdd_err("Channel switch in progress!!"); + return -EBUSY; + } + + /* + * 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, + policy_mgr_convert_device_mode_to_qdf_type( + adapter->device_mode), + target_channel, + adapter->session_id)) { + hdd_err("Channel switch failed due to concurrency check failure"); + qdf_atomic_set(&adapter->ch_switch_in_progress, 0); + return -EINVAL; + } + + status = policy_mgr_reset_chan_switch_complete_evt(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("clear event failed"); + qdf_atomic_set(&adapter->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(&adapter->ch_switch_in_progress, 0); + return -EINVAL; + } + /* Disable Roaming on all adapters before doing channel change */ + wlan_hdd_disable_roaming(adapter); + + if (wlan_vdev_mlme_get_opmode(adapter->vdev) == QDF_P2P_GO_MODE) + is_p2p_go_session = true; + /* + * Post the Channel Change request to SAP. + */ + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) { + qdf_atomic_set(&adapter->ch_switch_in_progress, 0); + wlan_hdd_enable_roaming(adapter); + return -EINVAL; + } + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) + is_p2p_go_session = true; + hdd_objmgr_put_vdev(vdev); + + status = wlansap_set_channel_change_with_csa( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + (uint32_t)target_channel, + target_bw, + (forced && !(hdd_ctx->config->sta_sap_scc_on_lte_coex_chan)) || + is_p2p_go_session); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SAP set channel failed for channel: %d, bw: %d", + target_channel, target_bw); + /* + * If channel change command fails then clear the + * radar found flag and also restart the netif + * queues. + */ + qdf_atomic_set(&adapter->ch_switch_in_progress, 0); + + /* + * If Posting of the Channel Change request fails + * enable roaming on all adapters + */ + wlan_hdd_enable_roaming(adapter); + + ret = -EINVAL; + } + + return ret; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * hdd_sap_restart_with_channel_switch() - SAP channel change with E/CSA + * @ap_adapter: HDD adapter + * @target_channel: Channel 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: None + */ +void hdd_sap_restart_with_channel_switch(struct hdd_adapter *ap_adapter, + uint32_t target_channel, + 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; + } + + ret = hdd_softap_set_channel_change(dev, target_channel, + target_bw, forced); + if (ret) { + hdd_err("channel switch failed"); + return; + } +} + +void hdd_sap_restart_chan_switch_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t channel, + uint32_t channel_bw, + bool forced) +{ + struct hdd_adapter *ap_adapter = + wlan_hdd_get_adapter_from_vdev(psoc, vdev_id); + + if (!ap_adapter) { + hdd_err("Adapter is NULL"); + return; + } + hdd_sap_restart_with_channel_switch(ap_adapter, channel, + channel_bw, forced); +} + +void wlan_hdd_set_sap_csa_reason(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + struct sap_context *sap_ctx; + struct hdd_adapter *ap_adapter = wlan_hdd_get_adapter_from_vdev( + psoc, vdev_id); + if (!ap_adapter) { + hdd_err("ap adapter is NULL"); + return; + } + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter); + if (sap_ctx) + sap_ctx->csa_reason = reason; +} + +QDF_STATUS wlan_hdd_get_channel_for_sap_restart( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *channel, + uint8_t *sec_ch) +{ + mac_handle_t mac_handle; + struct hdd_ap_ctx *hdd_ap_ctx; + uint8_t intf_ch = 0; + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *hdd_sta_ctx; + struct hdd_adapter *sta_adapter; + struct ch_params ch_params; + struct hdd_adapter *ap_adapter = wlan_hdd_get_adapter_from_vdev( + psoc, vdev_id); + if (!ap_adapter) { + hdd_err("ap_adapter is NULL"); + return QDF_STATUS_E_FAILURE; + } + + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* TODO: need work for 3 port case with sta+sta */ + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (!sta_adapter) { + hdd_err("sta_adapter is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == channel || NULL == sec_ch) { + hdd_err("Null parameters"); + return QDF_STATUS_E_FAILURE; + } + + if (!test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { + hdd_err("SOFTAP_BSS_STARTED not set"); + return QDF_STATUS_E_FAILURE; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter); + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("mac_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (policy_mgr_get_connection_count(psoc) == 1) { + /* + * 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, &intf_ch)) { + hdd_debug("Move the sap to user configured channel %u", + intf_ch); + goto sap_restart; + } + } + /* + * 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 = wlansap_check_cc_intf(hdd_ap_ctx->sap_context); + hdd_info("intf_ch: %d", intf_ch); + if (QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION != + hdd_ctx->config->WlanMccToSccSwitchMode) { + if (QDF_IS_STATUS_ERROR( + policy_mgr_valid_sap_conc_channel_check( + hdd_ctx->psoc, + &intf_ch, + policy_mgr_mode_specific_get_channel( + hdd_ctx->psoc, PM_SAP_MODE)))) { + hdd_debug("can't move sap to %d", + hdd_sta_ctx->conn_info.operationChannel); + return QDF_STATUS_E_FAILURE; + } + } + +sap_restart: + if (intf_ch == 0) { + hdd_debug("interface channel is 0"); + return QDF_STATUS_E_FAILURE; + } + + hdd_info("SAP restart orig chan: %d, new chan: %d", + hdd_ap_ctx->sap_config.channel, intf_ch); + ch_params.ch_width = CH_WIDTH_MAX; + hdd_ap_ctx->bss_stop_reason = BSS_STOP_DUE_TO_MCC_SCC_SWITCH; + if (hdd_ap_ctx->sap_context) + hdd_ap_ctx->sap_context->csa_reason = + CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL; + + wlan_reg_set_channel_params(hdd_ctx->pdev, + intf_ch, + 0, + &ch_params); + + wlansap_get_sec_channel(ch_params.sec_ch_offset, intf_ch, sec_ch); + + *channel = intf_ch; + + hdd_info("SAP channel change with CSA/ECSA"); + hdd_sap_restart_chan_switch_cb(psoc, vdev_id, + intf_ch, + ch_params.ch_width, false); + + return QDF_STATUS_SUCCESS; +} +#endif + +static int __iw_softap_set_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + QDF_STATUS status; + int errno; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + char *value; + size_t len; + + 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; + + /* ensure null termination by copying into a larger, zeroed buffer */ + len = min_t(size_t, wrqu->data.length, QCSAP_IOCTL_MAX_STR_LEN); + value = qdf_mem_malloc(len + 1); + if (!value) + return -ENOMEM; + + qdf_mem_copy(value, extra, len); + hdd_debug("Received data %s", value); + status = hdd_execute_global_config_command(hdd_ctx, value); + qdf_mem_free(value); + + hdd_exit(); + + return qdf_status_to_os_return(status); +} + +int +static iw_softap_set_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_ini_cfg(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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); + + if (hostapdstate->bss_state != BSS_START) { + *value = -EINVAL; + return -EINVAL; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + + *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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_ini_cfg(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + 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) +{ + 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; + struct cdp_vdev *vdev = NULL; + struct cdp_pdev *pdev = NULL; + void *soc = NULL; + 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 (ret != 0) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case QCSAP_PARAM_SET_TXRX_STATS: + { + ret = cds_get_datapath_handles(&soc, &pdev, &vdev, + adapter->session_id); + if (ret != 0) { + hdd_err("Invalid Handles"); + break; + } + 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); + ret = cdp_txrx_stats_request(soc, vdev, &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->session_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->session_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; + + default: + hdd_err("Invalid IOCTL command: %d", sub_cmd); + break; + } + + return ret; +} + +static int iw_softap_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_two_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 - %02x:%02x:%02x:%02x:%02x:%02x\n", + i, MAC_ADDR_ARRAY(macArray)); + } +} + +static QDF_STATUS hdd_print_acl(struct hdd_adapter *adapter) +{ + eSapMacAddrACL acl_mode; + struct qdf_mac_addr maclist[MAX_ACL_MAC_ADDRESS]; + uint8_t listnum; + struct sap_context *sap_ctx; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + 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("******* WHITE 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("******* BLACK LIST ***********\n"); + if (listnum <= MAX_ACL_MAC_ADDRESS) + print_mac_list(&maclist[0], listnum); + } else { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_aid_rc() - Get AID and rate code passed from user + * @aid: pointer to AID + * @rc: pointer to rate code + * @set_value: value passed from user + * + * If target is 11ax capable, set_value will have AID left shifted 16 bits + * and 16 bits for rate code. If the target is not 11ax capable, rate code + * will only be 8 bits. + * + * Return: None + */ +static void hdd_get_aid_rc(uint8_t *aid, uint16_t *rc, int set_value) +{ + uint8_t rc_bits; + + if (sme_is_feature_supported_by_fw(DOT11AX)) + rc_bits = 16; + else + rc_bits = 8; + + *aid = set_value >> rc_bits; + *rc = set_value & ((1 << (rc_bits + 1)) - 1); +} + +/** + * hdd_set_peer_rate() - set peer rate + * @adapter: adapter being modified + * @set_value: rate code with AID + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_set_peer_rate(struct hdd_adapter *adapter, int set_value) +{ + uint8_t aid, *peer_mac; + uint16_t rc; + QDF_STATUS status; + + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Invalid devicde mode - %d", adapter->device_mode); + return -EINVAL; + } + + hdd_get_aid_rc(&aid, &rc, set_value); + + if ((adapter->sta_info[aid].in_use) && + (OL_TXRX_PEER_STATE_CONN == adapter->sta_info[aid].peer_state)) { + peer_mac = + (uint8_t *)&(adapter->sta_info[aid].sta_mac.bytes[0]); + hdd_info("Peer AID: %d MAC_ADDR: "MAC_ADDRESS_STR, + aid, MAC_ADDR_ARRAY(peer_mac)); + } else { + hdd_err("No matching peer found for AID: %d", aid); + return -EINVAL; + } + + status = sme_set_peer_param(peer_mac, WMI_PEER_PARAM_FIXED_RATE, + rc, adapter->session_id); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to set peer fixed rate - status: %d", status); + return -EIO; + } + + return 0; +} + +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; + + 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(adapter))) { + 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(adapter), + 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, + adapter->session_id, + CSA_REASON_USER_INITIATED); + hdd_debug("SET Channel Change to new channel= %d", + 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); + if (!((set_value >= CFG_CONC_SYSTEM_PREF_MIN) && + (set_value <= CFG_CONC_SYSTEM_PREF_MAX))) { + hdd_err("Invalid system preference: %d", set_value); + return -EINVAL; + } + /* hdd_ctx, hdd_ctx->config are already checked for null */ + hdd_ctx->config->conc_system_pref = set_value; + break; + case QCSAP_PARAM_MAX_ASSOC: + if (WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value) { + hdd_err("Invalid setMaxAssoc value %d", + set_value); + ret = -EINVAL; + } else { + if (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value) { + hdd_warn("setMaxAssoc %d > max allowed %d.", + set_value, + WNI_CFG_ASSOC_STA_LIMIT_STAMAX); + hdd_warn("Setting it to max allowed and continuing"); + set_value = WNI_CFG_ASSOC_STA_LIMIT_STAMAX; + } + status = sme_cfg_set_int(mac_handle, + WNI_CFG_ASSOC_STA_LIMIT, + set_value); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("setMaxAssoc failure, status: %d", + status); + 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_disable_roaming(adapter); + + status = sme_update_session_param(mac_handle, + adapter->session_id, + SIR_PARAM_SSID_HIDDEN, set_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("QCSAP_PARAM_HIDE_SSID failed"); + wlan_hdd_enable_roaming(adapter); + return -EIO; + } + break; + } + case QCSAP_PARAM_SET_MC_RATE: + { + tSirRateUpdateInd rateUpdate = {0}; + struct hdd_config *pConfig = hdd_ctx->config; + + hdd_debug("MC Target rate %d", set_value); + qdf_copy_macaddr(&rateUpdate.bssid, + &adapter->mac_addr); + rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdate.dev_mode = adapter->device_mode; + rateUpdate.mcastDataRate24GHz = set_value; + rateUpdate.mcastDataRate24GHzTxFlag = 1; + rateUpdate.mcastDataRate5GHz = set_value; + rateUpdate.bcastDataRate = -1; + status = sme_send_rate_update_ind(mac_handle, &rateUpdate); + 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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_id, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + set_value, VDEV_CMD); + break; + } + + case QCSAP_PARAM_RTSCTS: + { + ret = wma_cli_set_command(adapter->session_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; + tsap_config_t *pConfig = + &adapter->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 (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b_ONLY + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11g + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11g_ONLY + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_abg + || pConfig->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 (pConfig->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 (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b + || pConfig->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(adapter->session_id, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case QCASAP_SET_VHT_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + tsap_config_t *pConfig = + &adapter->session.ap.sap_config; + + if (pConfig->SapHw_mode != eCSR_DOT11_MODE_11ac && + pConfig->SapHw_mode != eCSR_DOT11_MODE_11ac_ONLY) { + hdd_err("SET_VHT_RATE error: SapHw_mode= 0x%x, ch: %d", + pConfig->SapHw_mode, pConfig->channel); + 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(adapter->session_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); + /* + * wma_cli_set_command should be called instead of + * sme_update_ht_config since SGI is used for HT/HE. + * This should be refactored. + * + * SGI is same for 20MHZ and 40MHZ. + */ + ret = sme_update_ht_config(mac_handle, adapter->session_id, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + 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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_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(adapter->session_id, + WMI_VDEV_PARAM_GTX_MINTPC, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_BWMASK: + { + hdd_debug("WMI_VDEV_PARAM_GTX_BWMASK %d", set_value); + ret = wma_cli_set_command(adapter->session_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, 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, adapter->session_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(adapter), + (eSapDfsNolType) set_value); + break; + + case QCASAP_SET_RADAR_CMD: + { + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + uint8_t ch = ap_ctx->operating_channel; + 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; + } + + qdf_mem_zero(&radar, sizeof(radar)); + if (wlan_reg_is_dfs_ch(pdev, ch)) + tgt_dfs_process_radar_ind(pdev, &radar); + else + hdd_err("Ignore set radar, op ch(%d) is not dfs", ch); + + break; + } + case QCASAP_TX_CHAINMASK_CMD: + { + hdd_debug("QCASAP_TX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + set_value, PDEV_CMD); + ret = hdd_set_antenna_mode(adapter, hdd_ctx, set_value); + break; + } + + case QCASAP_RX_CHAINMASK_CMD: + { + hdd_debug("QCASAP_RX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + set_value, PDEV_CMD); + ret = hdd_set_antenna_mode(adapter, hdd_ctx, set_value); + break; + } + + case QCASAP_NSS_CMD: + { + hdd_debug("QCASAP_NSS_CMD val %d", set_value); + hdd_update_nss(adapter, set_value); + ret = wma_cli_set_command(adapter->session_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 = wlan_hdd_update_phymode(dev, mac_handle, set_value, + hdd_ctx); + 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: + memset(&adapter->stats, 0, + sizeof(adapter->stats)); + memset(&adapter->hdd_stats, 0, + sizeof(adapter->hdd_stats)); + break; + case CDP_TXRX_HIST_STATS: + wlan_hdd_clear_tx_rx_histogram(hdd_ctx); + 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, set_value); + } + break; + } + case QCSAP_START_FW_PROFILING: + hdd_debug("QCSAP_START_FW_PROFILING %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + set_value, DBG_CMD); + break; + case QCASAP_PARAM_LDPC: + ret = hdd_set_ldpc(adapter, set_value); + break; + case QCASAP_PARAM_TX_STBC: + ret = hdd_set_tx_stbc(adapter, set_value); + break; + case QCASAP_PARAM_RX_STBC: + ret = hdd_set_rx_stbc(adapter, set_value); + break; + case QCASAP_SET_11AX_RATE: + ret = hdd_set_11ax_rate(adapter, set_value, + &adapter->session.ap. + sap_config); + break; + case QCASAP_SET_PEER_RATE: + ret = hdd_set_peer_rate(adapter, set_value); + break; + case QCASAP_PARAM_DCM: + hdd_debug("Set WMI_VDEV_PARAM_HE_DCM: %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_HE_DCM, 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(adapter->session_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)adapter->session_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)adapter->session_id, + (int)WMI_PDEV_PARAM_ENABLE_RTS_SIFS_BURSTING, + set_value, PDEV_CMD); + 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); + + 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, value, 3); + 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_three(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static iw_softap_setparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_setparam(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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]; + QDF_STATUS status; + 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: + status = sme_cfg_get_int(hdd_ctx->mac_handle, + WNI_CFG_ASSOC_STA_LIMIT, + (uint32_t *)value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("get WNI_CFG_ASSOC_STA_LIMIT failed status: %d", + status); + 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->session_id, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + VDEV_CMD); + break; + } + + case QCASAP_SHORT_GI: + { + *value = wma_cli_get_command(adapter->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_id, + WMI_VDEV_PARAM_HE_DCM, + VDEV_CMD); + break; + } + case QCASAP_PARAM_RANGE_EXT: + { + *value = wma_cli_get_command(adapter->session_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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getparam(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* Usage: + * BLACK_LIST = 0 + * WHITE_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 black 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 white 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 pPeerStaMac[QDF_MAC_ADDR_SIZE]; + int listType, 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++) + pPeerStaMac[i] = *(value + i); + + listType = (int)(*(value + i)); + i++; + cmd = (int)(*(value + i)); + + hdd_debug("Modify ACL mac:" MAC_ADDRESS_STR " type: %d cmd: %d", + MAC_ADDR_ARRAY(pPeerStaMac), listType, cmd); + + qdf_status = wlansap_modify_acl( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pPeerStaMac, (eSapACLType) listType, (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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_modify_acl(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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; + 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; + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) + *value = (WLAN_HDD_GET_AP_CTX_PTR( + adapter))->operating_channel; + 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getchannel(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 (NULL == 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_max_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_pktlog(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#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->session_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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define IS_BROADCAST_MAC(x) (((x[0] & x[1] & x[2] & x[3] & x[4] & x[5]) == 0xff) ? 1 : 0) + +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 *pStaInfo = adapter->sta_info; + struct hdd_context *hdd_ctx; + char *buf; + int cnt = 0; + 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) { + hdd_err("failed to allocate response buffer"); + return -ENOMEM; + } + + /* start indexing beyond where the record count will be written */ + maclist_index = sizeof(maclist_index); + left = wrqu->data.length - maclist_index; + + spin_lock_bh(&adapter->sta_info_lock); + while ((cnt < WLAN_MAX_STA_COUNT) && (left >= QDF_MAC_ADDR_SIZE)) { + if ((pStaInfo[cnt].in_use) && + (!IS_BROADCAST_MAC(pStaInfo[cnt].sta_mac.bytes))) { + memcpy(&buf[maclist_index], &(pStaInfo[cnt].sta_mac), + QDF_MAC_ADDR_SIZE); + maclist_index += QDF_MAC_ADDR_SIZE; + left -= QDF_MAC_ADDR_SIZE; + } + cnt++; + } + spin_unlock_bh(&adapter->sta_info_lock); + + *((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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getassoc_stamacaddr(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* 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 *peerMacAddr; + 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); + */ + peerMacAddr = (uint8_t *) (extra); + + hdd_debug("data " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peerMacAddr)); + wlansap_populate_del_sta_params(peerMacAddr, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + (SIR_MAC_MGMT_DISASSOC >> 4), + &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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_disassoc_sta(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + 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) +{ + 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, &(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; +} + +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_char_setnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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; + uint8_t band_start_channel = CHAN_ENUM_1; + uint8_t band_end_channel = MAX_5GHZ_CHANNEL; + struct hdd_adapter *hostapd_adapter = (netdev_priv(dev)); + struct channel_list_info *channel_list = + (struct channel_list_info *) extra; + enum band_info cur_band = BAND_ALL; + struct hdd_context *hdd_ctx; + int ret; + bool is_dfs_mode_enabled = false; + + 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; + + if (QDF_STATUS_SUCCESS != sme_get_freq_band(hdd_ctx->mac_handle, + &cur_band)) { + hdd_err("not able get the current frequency band"); + return -EIO; + } + wrqu->data.length = sizeof(struct channel_list_info); + + if (BAND_2G == cur_band) { + band_start_channel = CHAN_ENUM_1; + band_end_channel = CHAN_ENUM_14; + } else if (BAND_5G == cur_band) { + band_start_channel = CHAN_ENUM_36; + band_end_channel = MAX_5GHZ_CHANNEL; + } + + if (cur_band != BAND_2G) + band_end_channel = MAX_5GHZ_CHANNEL; + + if (hostapd_adapter->device_mode == QDF_STA_MODE && + hdd_ctx->config->enableDFSChnlScan) { + is_dfs_mode_enabled = true; + } else if (hostapd_adapter->device_mode == QDF_SAP_MODE && + hdd_ctx->config->enableDFSMasterCap) { + is_dfs_mode_enabled = true; + } + + hdd_debug("curBand = %d, StartChannel = %hu, EndChannel = %hu is_dfs_mode_enabled = %d ", + cur_band, band_start_channel, band_end_channel, + is_dfs_mode_enabled); + + for (i = band_start_channel; i <= band_end_channel; i++) { + if ((CHANNEL_STATE_ENABLE == + wlan_reg_get_channel_state(hdd_ctx->pdev, + WLAN_REG_CH_NUM(i))) || + (is_dfs_mode_enabled && CHANNEL_STATE_DFS == + wlan_reg_get_channel_state(hdd_ctx->pdev, + WLAN_REG_CH_NUM(i)))) { + channel_list->channels[num_channels] = + WLAN_REG_CH_NUM(i); + num_channels++; + } + } + + hdd_debug("number of channels %d", num_channels); + + channel_list->num_channels = num_channels; + hdd_exit(); + + return 0; +} + +int iw_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_channel_list(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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), + &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 ret; + + cds_ssr_protect(__func__); + ret = __iw_get_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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->event_flags)) { + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = + qdf_wait_for_event_completion(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_START_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->event_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + adapter->session_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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_stopbss(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_version(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int hdd_softap_get_sta_info(struct hdd_adapter *adapter, + uint8_t *buf, + int size) +{ + int i; + int written; + uint8_t bc_sta_id; + + hdd_enter(); + + bc_sta_id = WLAN_HDD_GET_AP_CTX_PTR(adapter)->broadcast_sta_id; + + written = scnprintf(buf, size, "\nstaId staAddress\n"); + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + struct hdd_station_info *sta = &adapter->sta_info[i]; + + if (written >= size - 1) + break; + + if (!sta->in_use) + continue; + + if (i == bc_sta_id) + continue; + + written += scnprintf(buf + written, size - written, + "%5d %02x:%02x:%02x:%02x:%02x:%02x ecsa=%d\n", + sta->sta_id, + sta->sta_mac.bytes[0], + sta->sta_mac.bytes[1], + sta->sta_mac.bytes[2], + sta->sta_mac.bytes[3], + sta->sta_mac.bytes[4], + sta->sta_mac.bytes[5], + sta->ecsa_capable); + } + + 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 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_sta_info(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 *pLinkSpeed = (char *)extra; + uint32_t link_speed = 0; + int len = sizeof(uint32_t) + 1; + struct qdf_mac_addr macAddress; + char pmacAddress[MAC_ADDRESS_STR_LEN + 1]; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int rc, ret, i; + + 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 only for P2P mode */ + if (adapter->device_mode != QDF_P2P_GO_MODE) { + hdd_err("Link Speed is not allowed in Device mode %s(%d)", + hdd_device_mode_to_string( + adapter->device_mode), + adapter->device_mode); + return -ENOTSUPP; + } + + if (wrqu->data.length >= MAC_ADDRESS_STR_LEN - 1) { + if (copy_from_user((void *)pmacAddress, + wrqu->data.pointer, MAC_ADDRESS_STR_LEN)) { + hdd_err("failed to copy data to user buffer"); + return -EFAULT; + } + pmacAddress[MAC_ADDRESS_STR_LEN - 1] = '\0'; + + if (!mac_pton(pmacAddress, macAddress.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)) { + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (adapter->sta_info[i].in_use && + (!qdf_is_macaddr_broadcast + (&adapter->sta_info[i].sta_mac))) { + qdf_copy_macaddr( + &macAddress, + &adapter->sta_info[i]. + sta_mac); + status = QDF_STATUS_SUCCESS; + break; + } + } + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Invalid peer macaddress"); + return -EINVAL; + } + rc = wlan_hdd_get_linkspeed_for_peermac(adapter, &macAddress, + &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(pLinkSpeed, 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_get_softap_linkspeed(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_peer_rssi() - get station's rssi + * @dev: net device + * @info: iwpriv request information + * @wrqu: iwpriv command parameter + * @extra + * + * This function will call wlan_hdd_get_peer_rssi + * to get rssi + * + * Return: 0 on success, otherwise error value + */ +#ifdef QCA_SUPPORT_CP_STATS +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; + + 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"); + } + + rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi(adapter->vdev, + macaddress.bytes, + &ret); + 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, + "[%pM] [%d]\n", + 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; +} +#else +static int +__iw_get_peer_rssi(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 *hddctx; + char macaddrarray[MAC_ADDRESS_STR_LEN]; + struct qdf_mac_addr macaddress = QDF_MAC_ADDR_BCAST_INIT; + int ret; + char *rssi_info_output = extra; + struct sir_peer_sta_info peer_sta_info; + struct sir_peer_info *rssi_info; + int i; + int buf; + int length; + + 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"); + } + + ret = wlan_hdd_get_peer_rssi(adapter, &macaddress, &peer_sta_info); + if (ret) { + hdd_err("Unable to retrieve peer rssi: %d", ret); + return ret; + } + /* + * The iwpriv tool default print is before mac addr and rssi. + * Add '\n' before first rssi item to align the first rssi item + * with others + * + * wlan getRSSI: + * [macaddr1] [rssi1] + * [macaddr2] [rssi2] + * [macaddr3] [rssi3] + */ + length = scnprintf(rssi_info_output, WE_MAX_STR_LEN, "\n"); + rssi_info = &peer_sta_info.info[0]; + for (i = 0; i < peer_sta_info.sta_num; i++) { + buf = scnprintf + ( + rssi_info_output + length, WE_MAX_STR_LEN - length, + "[%pM] [%d]\n", + rssi_info[i].peer_macaddr.bytes, + rssi_info[i].rssi + ); + length += buf; + } + wrqu->data.length = length + 1; + hdd_exit(); + + return 0; +} +#endif + +/** + * iw_get_peer_rssi() - get station's rssi + * @dev: net device + * @info: iwpriv request information + * @wrqu: iwpriv command parameter + * @extra + * + * 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_get_peer_rssi(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * 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, "set_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_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 + , + /* 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_BYTE | sizeof(struct channel_list_info), + "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" + } + , + /* Set HDD CFG Ini param */ + { + QCSAP_IOCTL_SET_INI_CFG, + IW_PRIV_TYPE_CHAR | QCSAP_IOCTL_MAX_STR_LEN, 0, "setConfig" + } + , + /* 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 + { + QCASAP_SET_11AX_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_11ax_rate" + } + , + { + QCASAP_SET_PEER_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_peer_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_get_channel_list, + [QCSAP_IOCTL_GET_STA_INFO - SIOCIWFIRSTPRIV] = + iw_softap_get_sta_info, + [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_SET_INI_CFG - SIOCIWFIRSTPRIV] = + iw_softap_set_ini_cfg, + [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, +}; + +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, + .ndo_do_ioctl = hdd_ioctl, + .ndo_change_mtu = hdd_hostapd_change_mtu, + .ndo_select_queue = hdd_select_queue, +}; + +void hdd_set_ap_ops(struct net_device *dev) +{ + dev->netdev_ops = &net_ops_struct; +} + +bool hdd_sap_create_ctx(struct hdd_adapter *adapter) +{ + hdd_debug("creating sap context"); + adapter->session.ap.sap_context = sap_create_ctx(); + if (adapter->session.ap.sap_context) + return true; + + return false; +} + +bool hdd_sap_destroy_ctx(struct hdd_adapter *adapter) +{ + hdd_debug("destroying sap context"); + sap_destroy_ctx(adapter->session.ap.sap_context); + adapter->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; + + /* 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(hdd_ctx, adapter) { + if (adapter->device_mode == QDF_SAP_MODE) + hdd_sap_destroy_ctx(adapter); + } +} + +QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, bool reinit) +{ + struct hdd_hostapd_state *phostapdBuf; + struct net_device *dev = adapter->dev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sap_context *sapContext = NULL; + int ret; + enum dfs_mode acs_dfs_mode; + + hdd_enter(); + + hdd_info("SSR in progress: %d", reinit); + qdf_atomic_init(&adapter->session.ap.acs_in_progress); + + sapContext = hdd_hostapd_init_sap_session(adapter, reinit); + if (!sapContext) { + hdd_err("Invalid sap_ctx"); + goto error_release_vdev; + } + + if (!reinit) { + adapter->session.ap.sap_config.channel = + hdd_ctx->acs_policy.acs_channel; + acs_dfs_mode = hdd_ctx->acs_policy.acs_dfs_mode; + adapter->session.ap.sap_config.acs_dfs_mode = + wlan_hdd_get_dfs_mode(acs_dfs_mode); + } + + /* Allocate the Wireless Extensions state structure */ + phostapdBuf = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + sme_set_curr_device_mode(hdd_ctx->mac_handle, adapter->device_mode); + + /* 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_release_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_release_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_release_sap_session; + } + + + /* Register as a wireless device */ + dev->wireless_handlers = (struct iw_handler_def *)&hostapd_handler_def; + + /* Initialize the data path module */ + status = hdd_softap_init_tx_rx(adapter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("hdd_softap_init_tx_rx failed"); + goto error_release_sap_session; + } + + 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_wmm; + } + + set_bit(WMM_INIT_DONE, &adapter->event_flags); + + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_BURST_ENABLE, + HDD_ENABLE_SIFS_BURST_DEFAULT, + PDEV_CMD); + + if (0 != ret) + hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed: %d", ret); + + if (!reinit) { + adapter->session.ap.sap_config.acs_cfg.acs_mode = false; + wlan_hdd_undo_acs(adapter); + qdf_mem_zero(&adapter->session.ap.sap_config.acs_cfg, + sizeof(struct sap_acs_cfg)); + } + + /* rcpi info initialization */ + qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi)); + + hdd_exit(); + + return status; + +error_release_wmm: + hdd_softap_deinit_tx_rx(adapter); +error_release_sap_session: + hdd_hostapd_deinit_sap_session(adapter); +error_release_vdev: + QDF_BUG(!hdd_vdev_destroy(adapter)); + + hdd_exit(); + return status; +} + +void hdd_deinit_ap_mode(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + hdd_enter_dev(adapter->dev); + + 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(&adapter->session.ap.acs_in_progress, 0); + wlan_hdd_undo_acs(adapter); + hdd_softap_deinit_tx_rx(adapter); + /* + * if we are being called during driver unload, + * then the dev has already been invalidated. + * if we are being called at other times, then we can + * detach the wireless device handlers + */ + if (adapter->dev) { + if (rtnl_held) { + adapter->dev->wireless_handlers = NULL; + } else { + rtnl_lock(); + adapter->dev->wireless_handlers = NULL; + rtnl_unlock(); + } + } + if (hdd_hostapd_deinit_sap_session(adapter)) + 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 + * @macAddr: 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 macAddr, + unsigned char name_assign_type, + uint8_t *iface_name) +{ + struct net_device *dev; + struct hdd_adapter *adapter; + QDF_STATUS qdf_status; + + hdd_debug("iface_name = %s", iface_name); + + dev = alloc_netdev_mq(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); + + 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->hdd_ctx = hdd_ctx; + adapter->magic = WLAN_HDD_ADAPTER_MAGIC; + adapter->session_id = HDD_SESSION_ID_INVALID; + + 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; + + if (hdd_ctx->config->enable_ip_tcp_udp_checksum_offload) + dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->features |= NETIF_F_RXCSUM; + + qdf_mem_copy(dev->dev_addr, (void *)macAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(adapter->mac_addr.bytes, + (void *)macAddr, sizeof(tSirMacAddr)); + + adapter->offloads_configured = false; + hdd_dev_setup_destructor(dev); + dev->ieee80211_ptr = &adapter->wdev; + adapter->wdev.wiphy = hdd_ctx->wiphy; + adapter->wdev.netdev = dev; + hdd_set_tso_flags(hdd_ctx, dev); + + qdf_status = qdf_event_create( + &adapter->qdf_session_open_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("failed to create session open QDF event!"); + free_netdev(adapter->dev); + return NULL; + } + + qdf_status = qdf_event_create( + &adapter->qdf_session_close_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("failed to create session close QDF event!"); + free_netdev(adapter->dev); + return NULL; + } + + 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->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 + * @adapter: Pointer to hostapd adapter + * + * Return: HT support channel width config value + */ +static bool wlan_hdd_get_sap_obss(struct hdd_adapter *adapter) +{ + uint32_t ret; + const uint8_t *ie = NULL; + uint8_t ht_cap_ie[DOT11F_IE_HTCAPS_MAX_LEN]; + tDot11fIEHTCaps dot11_ht_cap_ie = {0}; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_beacon_data *beacon = adapter->session.ap.beacon; + mac_handle_t mac_handle; + + mac_handle = hdd_ctx->mac_handle; + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_HT_CAPABILITY, + beacon->tail, beacon->tail_len); + if (ie && ie[1]) { + qdf_mem_copy(ht_cap_ie, &ie[2], DOT11F_IE_HTCAPS_MAX_LEN); + ret = dot11f_unpack_ie_ht_caps((tpAniSirGlobal)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 bool wlan_hdd_get_sap_obss(struct hdd_adapter *adapter) +{ + 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 = 0; + int channel_seg2 = 0; + struct hdd_context *hdd_ctx; + int status; + mac_handle_t mac_handle; + tSmeConfigParams *sme_config; + tsap_config_t *sap_config; + + hdd_enter(); + + if (NULL == dev) { + hdd_err("Called with dev = NULL"); + return -ENODEV; + } + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_CHANNEL, + adapter->session_id, channel_type); + + hdd_debug("Device_mode %s(%d) freq = %d", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode, chandef->chan->center_freq); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + mac_handle = hdd_ctx->mac_handle; + + /* + * Do freq to chan conversion + * TODO: for 11a + */ + + channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); + + if (NL80211_CHAN_WIDTH_80P80 == chandef->width || + NL80211_CHAN_WIDTH_160 == chandef->width) { + if (chandef->center_freq2) + channel_seg2 = ieee80211_frequency_to_channel( + chandef->center_freq2); + else + hdd_err("Invalid center_freq2"); + } + + /* Check freq range */ + if ((WNI_CFG_CURRENT_CHANNEL_STAMIN > channel) || + (WNI_CFG_CURRENT_CHANNEL_STAMAX < channel)) { + hdd_err("Channel: %d is outside valid range from %d to %d", + channel, WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + /* Check freq range */ + + if ((WNI_CFG_CURRENT_CHANNEL_STAMIN > channel_seg2) || + (WNI_CFG_CURRENT_CHANNEL_STAMAX < channel_seg2)) { + hdd_err("Channel: %d is outside valid range from %d to %d", + channel_seg2, WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + num_ch = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if ((QDF_SAP_MODE != adapter->device_mode) && + (QDF_P2P_GO_MODE != adapter->device_mode)) { + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel)) { + hdd_err("Invalid Channel: %d", channel); + return -EINVAL; + } + hdd_debug("set channel to [%d] for device mode %s(%d)", + channel, + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + } + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + struct csr_roam_profile *roam_profile; + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (eConnectionState_IbssConnected == + sta_ctx->conn_info.connState) { + /* Link is up then return cant set channel */ + hdd_err("IBSS Associated, can't set the channel"); + return -EINVAL; + } + + roam_profile = hdd_roam_profile(adapter); + num_ch = roam_profile->ChannelInfo.numOfChannels = 1; + sta_ctx->conn_info.operationChannel = channel; + roam_profile->ChannelInfo.ChannelList = + &sta_ctx->conn_info.operationChannel; + } else if ((adapter->device_mode == QDF_SAP_MODE) + || (adapter->device_mode == QDF_P2P_GO_MODE) + ) { + sap_config = &((WLAN_HDD_GET_AP_CTX_PTR(adapter))->sap_config); + if (QDF_P2P_GO_MODE == adapter->device_mode) { + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, + channel)) { + hdd_err("Invalid Channel: %d", channel); + return -EINVAL; + } + sap_config->channel = channel; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + } else { + /* set channel to what hostapd configured */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, + channel)) { + hdd_err("Invalid Channel: %d", channel); + return -EINVAL; + } + + sap_config->channel = channel; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + + if (!sme_config) { + hdd_err("Unable to allocate memory for smeconfig!"); + return -ENOMEM; + } + sme_get_config_param(mac_handle, sme_config); + switch (channel_type) { + case NL80211_CHAN_HT20: + case NL80211_CHAN_NO_HT: + sme_config->csrConfig.obssEnabled = false; + sap_config->sec_ch = 0; + break; + case NL80211_CHAN_HT40MINUS: + sap_config->sec_ch = sap_config->channel - 4; + break; + case NL80211_CHAN_HT40PLUS: + sap_config->sec_ch = sap_config->channel + 4; + break; + default: + hdd_err("Error!!! Invalid HT20/40 mode !"); + qdf_mem_free(sme_config); + return -EINVAL; + } + sme_config->csrConfig.obssEnabled = + wlan_hdd_get_sap_obss(adapter); + + sme_update_config(mac_handle, sme_config); + qdf_mem_free(sme_config); + } + } else { + hdd_err("Invalid device mode failed to set valid channel"); + return -EINVAL; + } + hdd_exit(); + return status; +} + +/** + * wlan_hdd_check_11gmode() - check for 11g mode + * @pIe: 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 *pIe, u8 *require_ht, + u8 *require_vht, u8 *pCheckRatesfor11g, + eCsrPhyMode *pSapHw_mode) +{ + u8 i, num_rates = pIe[0]; + + pIe += 1; + for (i = 0; i < num_rates; i++) { + if (*pCheckRatesfor11g + && (true == wlan_hdd_rate_is_11g(pIe[i] & RATE_MASK))) { + /* If rate set have 11g rate than change the mode + * to 11G + */ + *pSapHw_mode = eCSR_DOT11_MODE_11g; + if (pIe[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 | + WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY) == pIe[i]) + *require_ht = true; + else if ((BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY) == pIe[i]) + *require_vht = true; + } + } +} + +#ifdef WLAN_FEATURE_11AX +/** + * wlan_hdd_add_extn_ie() - add extension IE + * @adapter: Pointer to hostapd 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 hdd_adapter *adapter, 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 = adapter->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 + * @adapter: Pointer to hostapd 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 hdd_adapter *adapter, + uint8_t *genie, + uint16_t *total_ielen) +{ + struct hdd_beacon_data *pBeacon = adapter->session.ap.beacon; + int left = pBeacon->tail_len; + uint8_t *ptr = pBeacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + bool skip_ie; + + if (NULL == 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 (IE_EID_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], WHITELIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE) || + !qdf_mem_cmp(&ptr[2], BLACKLIST_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 + * @adapter: Pointer to hostapd 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 hdd_adapter *adapter, + uint8_t *genie, uint16_t *total_ielen, + uint8_t temp_ie_id) +{ + struct hdd_beacon_data *pBeacon = adapter->session.ap.beacon; + int left = pBeacon->tail_len; + uint8_t *ptr = pBeacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + + if (NULL == 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 + * @adapter: Pointer to hostapd adapter + * @ppBeacon: Pointer to pointer to 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 hdd_adapter *adapter, + struct hdd_beacon_data **ppBeacon, + 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 = adapter->session.ap.beacon; + + if (!params->head && !old) { + hdd_err("session: %d old and new heads points to NULL", + adapter->session_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 == NULL) { + hdd_err("Mem allocation for beacon failed"); + 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); + + *ppBeacon = beacon; + + adapter->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 hdd_adapter *hostapd_adapter, uint8_t *ie_buf, uint16_t *ie_len) +{ + if (QDF_SAP_MODE == hostapd_adapter->device_mode) { + if (wlan_hdd_get_sap_obss(hostapd_adapter)) + wlan_hdd_add_extra_ie(hostapd_adapter, ie_buf, ie_len, + WLAN_EID_OVERLAP_BSS_SCAN_PARAM); + } +} +#else +static void wlan_hdd_add_sap_obss_scan_ie( + struct hdd_adapter *hostapd_adapter, uint8_t *ie_buf, uint16_t *ie_len) +{ +} +#endif + +/** + * wlan_hdd_cfg80211_update_apies() - update ap mode 11ax ies + * @adapter: Pointer to hostapd 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 hdd_adapter *adapter, + uint8_t *genie, uint16_t *total_ielen) +{ + if (wlan_hdd_add_extn_ie(adapter, 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(adapter, 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 hdd_adapter *adapter, + uint8_t *genie, uint16_t *total_ielen) +{ + return 0; +} +#endif + +/** + * wlan_hdd_cfg80211_update_apies() - update ap mode ies + * @adapter: Pointer to hostapd adapter + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_update_apies(struct hdd_adapter *adapter) +{ + uint8_t *genie; + uint16_t total_ielen = 0; + int ret = 0; + tsap_config_t *pConfig; + tSirUpdateIE updateIE; + struct hdd_beacon_data *beacon = NULL; + uint16_t proberesp_ies_len; + uint8_t *proberesp_ies = NULL; + mac_handle_t mac_handle; + + pConfig = &adapter->session.ap.sap_config; + beacon = adapter->session.ap.beacon; + if (!beacon) { + hdd_err("Beacon is NULL !"); + return -EINVAL; + } + + genie = qdf_mem_malloc(MAX_GENIE_LEN); + + if (genie == NULL) + return -ENOMEM; + + mac_handle = adapter->hdd_ctx->mac_handle; + + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_VHT_TX_POWER_ENVELOPE); + + /* Extract and add the extended capabilities and interworking IE */ + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_EXT_CAPABILITY); + + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_INTERWORKING); + +#ifdef FEATURE_WLAN_WAPI + if (QDF_SAP_MODE == adapter->device_mode) { + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_WAPI); + } +#endif + + wlan_hdd_add_hostapd_conf_vsie(adapter, genie, + &total_ielen); + + ret = hdd_update_11ax_apies(adapter, genie, &total_ielen); + if (ret) + goto done; + + wlan_hdd_add_sap_obss_scan_ie(adapter, genie, &total_ielen); + + qdf_copy_macaddr(&updateIE.bssid, &adapter->mac_addr); + updateIE.smeSessionId = adapter->session_id; + + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = total_ielen; + updateIE.pAdditionIEBuffer = genie; + updateIE.append = false; + updateIE.notify = true; + if (sme_update_add_ie(mac_handle, + &updateIE, + 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(pConfig, eUPDATE_IE_PROBE_BCN); + } else { + wlansap_update_sap_config_add_ie(pConfig, + genie, + total_ielen, + eUPDATE_IE_PROBE_BCN); + } + + /* Added for Probe Response IE */ + proberesp_ies = qdf_mem_malloc(beacon->proberesp_ies_len + + MAX_GENIE_LEN); + if (proberesp_ies == NULL) { + hdd_err("mem alloc failed for probe resp ies, size: %d", + beacon->proberesp_ies_len + MAX_GENIE_LEN); + 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(adapter, proberesp_ies, + &proberesp_ies_len); + + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = proberesp_ies_len; + updateIE.pAdditionIEBuffer = proberesp_ies; + updateIE.append = false; + updateIE.notify = false; + if (sme_update_add_ie(mac_handle, + &updateIE, + 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(pConfig, eUPDATE_IE_PROBE_RESP); + } else { + wlansap_update_sap_config_add_ie(pConfig, + proberesp_ies, + proberesp_ies_len, + eUPDATE_IE_PROBE_RESP); + } + + /* Assoc resp Add ie Data */ + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = beacon->assocresp_ies_len; + updateIE.pAdditionIEBuffer = (uint8_t *) beacon->assocresp_ies; + updateIE.append = false; + updateIE.notify = false; + if (sme_update_add_ie(mac_handle, + &updateIE, + 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(pConfig, eUPDATE_IE_ASSOC_RESP); + } else { + wlansap_update_sap_config_add_ie(pConfig, + beacon->assocresp_ies, + beacon->assocresp_ies_len, + eUPDATE_IE_ASSOC_RESP); + } + +done: + qdf_mem_free(genie); + qdf_mem_free(proberesp_ies); + return ret; +} + +/** + * wlan_hdd_set_sap_hwmode() - set sap hw mode + * @adapter: Pointer to hostapd adapter + * + * Return: none + */ +static void wlan_hdd_set_sap_hwmode(struct hdd_adapter *adapter) +{ + tsap_config_t *pConfig = &adapter->session.ap.sap_config; + struct hdd_beacon_data *pBeacon = adapter->session.ap.beacon; + struct ieee80211_mgmt *pMgmt_frame = + (struct ieee80211_mgmt *)pBeacon->head; + u8 checkRatesfor11g = true; + u8 require_ht = false, require_vht = false; + const u8 *pIe = NULL; + + pConfig->SapHw_mode = eCSR_DOT11_MODE_11b; + + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_SUPP_RATES, + &pMgmt_frame->u.beacon.variable[0], + pBeacon->head_len); + if (pIe != NULL) { + pIe += 1; + wlan_hdd_check_11gmode(pIe, &require_ht, &require_vht, + &checkRatesfor11g, &pConfig->SapHw_mode); + } + + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_EXT_SUPP_RATES, + pBeacon->tail, pBeacon->tail_len); + if (pIe != NULL) { + pIe += 1; + wlan_hdd_check_11gmode(pIe, &require_ht, &require_vht, + &checkRatesfor11g, &pConfig->SapHw_mode); + } + + if (pConfig->channel > 14) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11a; + + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_HT_CAPABILITY, + pBeacon->tail, pBeacon->tail_len); + if (pIe) { + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n; + if (require_ht) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n_ONLY; + } + + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_VHT_CAPABILITY, + pBeacon->tail, pBeacon->tail_len); + if (pIe) { + pConfig->SapHw_mode = eCSR_DOT11_MODE_11ac; + if (require_vht) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11ac_ONLY; + } + + wlan_hdd_check_11ax_support(pBeacon, pConfig); + + hdd_info("SAP hw_mode: %d", pConfig->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) +{ + tsap_config_t *sap_config; + struct hdd_config *ini_config; + mac_handle_t mac_handle; + + mac_handle = hdd_ctx->mac_handle; + sap_config = &adapter->session.ap.sap_config; + ini_config = hdd_ctx->config; + + sap_config->enOverLapCh = !!hdd_ctx->config->gEnableOverLapCh; + +#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; + tsap_config_t *con_sap_config = NULL; + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, false); + + if (con_sap_adapter) + con_sap_config = + &con_sap_adapter->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) { + uint8_t con_sap_st_ch, con_sap_end_ch; + uint8_t cur_sap_st_ch, cur_sap_end_ch; + uint8_t bandStartChannel, bandEndChannel; + + con_sap_st_ch = + con_sap_config->acs_cfg.start_ch; + con_sap_end_ch = + con_sap_config->acs_cfg.end_ch; + cur_sap_st_ch = sap_config->acs_cfg.start_ch; + cur_sap_end_ch = sap_config->acs_cfg.end_ch; + + wlansap_extend_to_acs_range(mac_handle, &cur_sap_st_ch, + &cur_sap_end_ch, &bandStartChannel, + &bandEndChannel); + + wlansap_extend_to_acs_range(mac_handle, + &con_sap_st_ch, &con_sap_end_ch, + &bandStartChannel, &bandEndChannel); + + if (con_sap_st_ch <= cur_sap_st_ch && + con_sap_end_ch >= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_SKIP_ACS_SCAN; + + } else if (con_sap_st_ch >= cur_sap_st_ch && + con_sap_end_ch >= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch - 1; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch <= cur_sap_st_ch && + con_sap_end_ch <= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + con_sap_end_ch + 1; + sap_config->acs_cfg.skip_scan_range1_endch = + cur_sap_end_ch; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch >= cur_sap_st_ch && + con_sap_end_ch <= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch - 1; + sap_config->acs_cfg.skip_scan_range2_stch = + con_sap_end_ch; + sap_config->acs_cfg.skip_scan_range2_endch = + cur_sap_end_ch + 1; + + } else + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_NEW_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) +{ + tsap_config_t *sap_cfg = &ap_adapter->session.ap.sap_config; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + + /* 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 + */ + if (!hdd_ctx->config->enable_sub_20_channel_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 && + !hdd_ctx->config->sap_force_11n_for_11ac && + hdd_ctx->config->sap_11ac_override) || + (ap_adapter->device_mode == QDF_P2P_GO_MODE && + !hdd_ctx->config->go_force_11n_for_11ac && + hdd_ctx->config->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 (sap_cfg->channel >= 36) { + sap_cfg->ch_width_orig = + hdd_ctx->config->vhtChannelWidth; + } 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 + */ + if (sap_cfg->ch_width_orig >= eHT_CHANNEL_WIDTH_40MHZ && + hdd_ctx->config->nChannelBondingMode24GHz) + sap_cfg->ch_width_orig = + eHT_CHANNEL_WIDTH_40MHZ; + else + sap_cfg->ch_width_orig = + eHT_CHANNEL_WIDTH_20MHZ; + } + } + + return 0; +} + +/** + * wlan_hdd_setup_driver_overrides : Overrides SAP / P2P GO Params + * @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); + + if (!hdd_ctx->config->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) +{ + struct hdd_adapter *sta_adapter; + uint8_t sta_chan; + + sta_chan = hdd_get_operating_channel(hdd_ctx, QDF_STA_MODE); + + if (!sta_chan) { + hdd_err("STA not connected"); + return; + } + + hdd_err("STA connected on chan %d", sta_chan); + + if (sme_is_channel_valid(hdd_ctx->mac_handle, sta_chan)) { + hdd_err("STA connected on chan %d and it is valid", sta_chan); + return; + } + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + + if (!sta_adapter) { + hdd_err("STA adapter does not exist"); + return; + } + + hdd_err("chan %d not valid, issue disconnect", sta_chan); + /* Issue Disconnect request */ + wlan_hdd_disconnect(sta_adapter, eCSR_DISCONNECT_REASON_DEAUTH); +} + +#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++) { + 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, + bool notify_sap_event) +{ + struct hdd_cache_channels *cache_chann; + struct wiphy *wiphy; + int freq, status, rf_channel; + 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 = reg_chan_to_freq( + hdd_ctx->pdev, + cache_chann->channel_info[i].channel_num); + if (!freq) + continue; + + wiphy_channel = wlan_hdd_get_wiphy_channel(wiphy, freq); + if (!wiphy_channel) + continue; + rf_channel = wiphy_channel->hw_value; + /* + * Restore the orginal 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 %d reg_stat %d wiphy_stat 0x%x", + cache_chann->channel_info[i].channel_num, + cache_chann->channel_info[i].reg_status, + wiphy_channel->flags); + } + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + if (notify_sap_event) + ucfg_reg_notify_sap_event(hdd_ctx->pdev, false); + else + 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"); + 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, rf_channel; + 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 = reg_chan_to_freq(hdd_ctx->pdev, + cache_chann-> + channel_info[i].channel_num); + if (!freq) + continue; + wiphy_channel = wlan_hdd_get_wiphy_channel(wiphy, freq); + if (!wiphy_channel) + continue; + rf_channel = wiphy_channel->hw_value; + /* + * Cache the current states of + * the channels + */ + cache_chann->channel_info[i].reg_status = + reg_get_channel_state( + hdd_ctx->pdev, + rf_channel); + cache_chann->channel_info[i].wiphy_status = + wiphy_channel->flags; + hdd_debug("Disable channel %d reg_stat %d wiphy_stat 0x%x", + cache_chann->channel_info[i].channel_num, + cache_chann->channel_info[i].reg_status, + wiphy_channel->flags); + + wiphy_channel->flags |= IEEE80211_CHAN_DISABLED; + } + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + status = ucfg_reg_notify_sap_event(hdd_ctx->pdev, true); + 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, + bool notify_sap_event) +{ + return 0; +} +#endif +/** + * wlan_hdd_cfg80211_start_bss() - start bss + * @adapter: Pointer to 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 hdd_adapter *adapter, + struct cfg80211_beacon_data *params, + const u8 *ssid, size_t ssid_len, + enum nl80211_hidden_ssid hidden_ssid, + bool check_for_concurrency) +{ + tsap_config_t *pConfig; + struct hdd_beacon_data *pBeacon = NULL; + struct ieee80211_mgmt *pMgmt_frame; + struct ieee80211_mgmt mgmt; + const uint8_t *pIe = NULL; + uint16_t capab_info; + eCsrAuthType RSNAuthType; + eCsrEncryptionType RSNEncryptType; + eCsrEncryptionType mcRSNEncryptType; + int status = QDF_STATUS_SUCCESS, ret; + int qdf_status = QDF_STATUS_SUCCESS; + tpWLAN_SAPEventCB pSapEventCallback; + struct hdd_hostapd_state *hostapd_state; + mac_handle_t mac_handle; + int32_t i; + struct hdd_config *iniConfig; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tSmeConfigParams *sme_config; + bool MFPCapable = false; + bool MFPRequired = false; + uint16_t prev_rsn_length = 0; + enum dfs_mode mode; + uint8_t ignore_cac = 0; + uint8_t beacon_fixed_len; + + hdd_enter(); + + hdd_notify_teardown_tdls_links(hdd_ctx->psoc); + + 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; + } + } + + /* + * For STA+SAP concurrency support from GUI, first STA connection gets + * triggered and while it is in progress, SAP start also comes up. + * Once STA association is successful, STA connect event is sent to + * kernel which gets queued in kernel workqueue and supplicant won't + * process M1 received from AP and send M2 until this NL80211_CONNECT + * event is received. Workqueue is not scheduled as RTNL lock is already + * taken by hostapd thread which has issued start_bss command to driver. + * Driver cannot complete start_bss as the pending command at the head + * of the SME command pending list is hw_mode_update for STA session + * which cannot be processed as SME is in WAITforKey state for STA + * interface. The start_bss command for SAP interface is queued behind + * the hw_mode_update command and so it cannot be processed until + * hw_mode_update command is processed. This is causing a deadlock so + * disconnect the STA interface first if connection or key exchange is + * in progress and then start SAP interface. + */ + hdd_abort_ongoing_sta_connection(hdd_ctx); + + /* + * Reject start bss 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 + */ + mac_handle = hdd_ctx->mac_handle; + if (sme_is_any_session_in_middle_of_roaming(mac_handle) || + hdd_is_roaming_in_progress(hdd_ctx)) { + hdd_info("Reassociation in progress"); + return -EINVAL; + } + + /* Disable Roaming on all adapters before starting bss */ + wlan_hdd_disable_roaming(adapter); + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("failed to allocate memory"); + ret = -ENOMEM; + goto free; + } + + iniConfig = hdd_ctx->config; + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + clear_bit(ACS_PENDING, &adapter->event_flags); + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + + pConfig = &adapter->session.ap.sap_config; + if (!pConfig->channel) { + hdd_err("Invalid channel"); + ret = -EINVAL; + goto free; + } + + /* Mark the indoor channel (passive) to disable */ + if (iniConfig->force_ssc_disable_indoor_channel && + 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); + } + + pBeacon = adapter->session.ap.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 (pBeacon->head_len < beacon_fixed_len) { + hdd_err("Invalid beacon head len"); + ret = -EINVAL; + goto error; + } + pMgmt_frame = (struct ieee80211_mgmt *)pBeacon->head; + + pConfig->beacon_int = pMgmt_frame->u.beacon.beacon_int; + pConfig->dfs_cac_offload = hdd_ctx->dfs_cac_offload; + + pConfig->auto_channel_select_weight = + iniConfig->auto_channel_select_weight; + pConfig->disableDFSChSwitch = iniConfig->disableDFSChSwitch; + pConfig->sap_chanswitch_beacon_cnt = + iniConfig->sap_chanswitch_beacon_cnt; + pConfig->sap_chanswitch_mode = iniConfig->sap_chanswitch_mode; + + /* channel is already set in the set_channel Call back */ + /* pConfig->channel = pCommitConfig->channel; */ + + /* Protection parameter to enable or disable */ + pConfig->protEnabled = iniConfig->apProtEnabled; + + pConfig->chan_switch_hostapd_rate_enabled = + iniConfig->chan_switch_hostapd_rate_enabled; + + if (iniConfig->WlanMccToSccSwitchMode != + QDF_MCC_TO_SCC_SWITCH_DISABLE) { + pConfig->chan_switch_hostapd_rate_enabled = false; + } + + pConfig->enOverLapCh = iniConfig->gEnableOverLapCh; + pConfig->dtim_period = pBeacon->dtim_period; + pConfig->dfs_beacon_tx_enhanced = iniConfig->dfs_beacon_tx_enhanced; + pConfig->reduced_beacon_interval = + iniConfig->reduced_beacon_interval; + hdd_debug("acs_mode %d", pConfig->acs_cfg.acs_mode); + + if (pConfig->acs_cfg.acs_mode == true) { + hdd_debug("acs_channel %d, acs_dfs_mode %d", + hdd_ctx->acs_policy.acs_channel, + hdd_ctx->acs_policy.acs_dfs_mode); + + if (hdd_ctx->acs_policy.acs_channel) + pConfig->channel = hdd_ctx->acs_policy.acs_channel; + mode = hdd_ctx->acs_policy.acs_dfs_mode; + pConfig->acs_dfs_mode = wlan_hdd_get_dfs_mode(mode); + } + + policy_mgr_update_user_config_sap_chan(hdd_ctx->psoc, + pConfig->channel); + hdd_debug("pConfig->channel %d, pConfig->acs_dfs_mode %d", + pConfig->channel, pConfig->acs_dfs_mode); + + hdd_debug("****pConfig->dtim_period=%d***", + pConfig->dtim_period); + + if (adapter->device_mode == QDF_SAP_MODE) { + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_COUNTRY, + pBeacon->tail, pBeacon->tail_len); + if (pIe) { + if (pIe[1] < IEEE80211_COUNTRY_IE_MIN_LEN) { + hdd_err("Invalid Country IE len: %d", pIe[1]); + ret = -EINVAL; + goto error; + } + + if (!qdf_mem_cmp(hdd_ctx->reg.alpha2, &pIe[2], + REG_ALPHA2_LEN)) + pConfig->ieee80211d = 1; + else + pConfig->ieee80211d = 0; + } else + pConfig->ieee80211d = 0; + + pConfig->countryCode[0] = hdd_ctx->reg.alpha2[0]; + pConfig->countryCode[1] = hdd_ctx->reg.alpha2[1]; + + ret = wlan_hdd_sap_cfg_dfs_override(adapter); + if (ret < 0) + goto error; + + if (!ret && wlan_reg_is_dfs_ch(hdd_ctx->pdev, pConfig->channel)) + hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, + pConfig->channel)) { + hdd_err("Invalid Channel: %d", pConfig->channel); + ret = -EINVAL; + goto error; + } + + /* reject SAP if DFS channel scan is not allowed */ + if (!(hdd_ctx->config->enableDFSChnlScan) && + (CHANNEL_STATE_DFS == + wlan_reg_get_channel_state(hdd_ctx->pdev, + pConfig->channel))) { + hdd_err("No SAP start on DFS channel"); + ret = -EOPNOTSUPP; + goto error; + } + + if (iniConfig->ignoreCAC || + ((iniConfig->WlanMccToSccSwitchMode != + QDF_MCC_TO_SCC_SWITCH_DISABLE) && + iniConfig->sta_sap_scc_on_dfs_chan)) + ignore_cac = 1; + + wlansap_set_dfs_ignore_cac(mac_handle, ignore_cac); + wlansap_set_dfs_restrict_japan_w53(mac_handle, + iniConfig->gDisableDfsJapanW53); + wlansap_set_dfs_preferred_channel_location(mac_handle, + iniConfig->gSapPreferredChanLocation); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + wlan_sap_set_channel_avoidance(mac_handle, + iniConfig->sap_channel_avoidance); +#endif + } else if (adapter->device_mode == QDF_P2P_GO_MODE) { + pConfig->countryCode[0] = hdd_ctx->reg.alpha2[0]; + pConfig->countryCode[1] = hdd_ctx->reg.alpha2[1]; + pConfig->ieee80211d = 0; + } else { + pConfig->ieee80211d = 0; + } + + wlansap_set_tx_leakage_threshold(mac_handle, + iniConfig->sap_tx_leakage_threshold); + + capab_info = pMgmt_frame->u.beacon.capab_info; + + pConfig->privacy = (pMgmt_frame->u.beacon.capab_info & + WLAN_CAPABILITY_PRIVACY) ? true : false; + + (WLAN_HDD_GET_AP_CTX_PTR(adapter))->privacy = pConfig->privacy; + + /*Set wps station to configured */ + pIe = wlan_hdd_get_wps_ie_ptr(pBeacon->tail, pBeacon->tail_len); + + if (pIe) { + /* To acess pIe[15], length needs to be atlest 14 */ + if (pIe[1] < 14) { + hdd_err("**Wps Ie Length(%hhu) is too small***", + pIe[1]); + ret = -EINVAL; + goto error; + } else if (memcmp(&pIe[2], WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE) == + 0) { + hdd_debug("** WPS IE(len %d) ***", (pIe[1] + 2)); + /* Check 15 bit of WPS IE as it contain information for + * wps state + */ + if (SAP_WPS_ENABLED_UNCONFIGURED == pIe[15]) { + pConfig->wps_state = + SAP_WPS_ENABLED_UNCONFIGURED; + } else if (SAP_WPS_ENABLED_CONFIGURED == pIe[15]) { + pConfig->wps_state = SAP_WPS_ENABLED_CONFIGURED; + } + } + } else { + hdd_debug("WPS disabled"); + pConfig->wps_state = SAP_WPS_DISABLED; + } + /* Forward WPS PBC probe request frame up */ + pConfig->fwdWPSPBCProbeReq = 1; + + pConfig->RSNEncryptType = eCSR_ENCRYPT_TYPE_NONE; + pConfig->mcRSNEncryptType = eCSR_ENCRYPT_TYPE_NONE; + (WLAN_HDD_GET_AP_CTX_PTR(adapter))->encryption_type = + eCSR_ENCRYPT_TYPE_NONE; + + pConfig->RSNWPAReqIELength = 0; + memset(&pConfig->RSNWPAReqIE[0], 0, sizeof(pConfig->RSNWPAReqIE)); + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_RSN, pBeacon->tail, + pBeacon->tail_len); + if (pIe && pIe[1]) { + pConfig->RSNWPAReqIELength = pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hdd_err("RSNWPA IE MAX Length exceeded; length =%d", + pConfig->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), + &RSNEncryptType, &mcRSNEncryptType, + &RSNAuthType, &MFPCapable, + &MFPRequired, + pConfig->RSNWPAReqIE[1] + 2, + pConfig->RSNWPAReqIE); + + if (QDF_STATUS_SUCCESS == status) { + /* Now copy over all the security attributes you have + * parsed out. Use the cipher type in the RSN IE + */ + pConfig->RSNEncryptType = RSNEncryptType; + pConfig->mcRSNEncryptType = mcRSNEncryptType; + (WLAN_HDD_GET_AP_CTX_PTR(adapter))-> + encryption_type = RSNEncryptType; + hdd_debug("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d", + RSNAuthType, RSNEncryptType, mcRSNEncryptType); + } + } + + pIe = wlan_get_vendor_ie_ptr_from_oui(WPA_OUI_TYPE, WPA_OUI_TYPE_SIZE, + pBeacon->tail, pBeacon->tail_len); + + if (pIe && pIe[1] && (pIe[0] == DOT11F_EID_WPA)) { + if (pConfig->RSNWPAReqIE[0]) { + /*Mixed mode WPA/WPA2 */ + prev_rsn_length = pConfig->RSNWPAReqIELength; + pConfig->RSNWPAReqIELength += pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < + sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0] + + prev_rsn_length, pIe, pIe[1] + 2); + else + hdd_err("RSNWPA IE MAX Length exceeded; length: %d", + pConfig->RSNWPAReqIELength); + } else { + pConfig->RSNWPAReqIELength = pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < + sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hdd_err("RSNWPA IE MAX Length exceeded; length: %d", + pConfig->RSNWPAReqIELength); + status = hdd_softap_unpack_ie + (cds_get_context(QDF_MODULE_ID_SME), + &RSNEncryptType, + &mcRSNEncryptType, &RSNAuthType, + &MFPCapable, &MFPRequired, + pConfig->RSNWPAReqIE[1] + 2, + pConfig->RSNWPAReqIE); + + if (QDF_STATUS_SUCCESS == status) { + /* Now copy over all the security attributes + * you have parsed out. Use the cipher type + * in the RSN IE + */ + pConfig->RSNEncryptType = RSNEncryptType; + pConfig->mcRSNEncryptType = mcRSNEncryptType; + (WLAN_HDD_GET_AP_CTX_PTR(adapter))-> + encryption_type = RSNEncryptType; + hdd_debug("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d", + RSNAuthType, RSNEncryptType, + mcRSNEncryptType); + } + } + } + + if (pConfig->RSNWPAReqIELength > sizeof(pConfig->RSNWPAReqIE)) { + hdd_err("**RSNWPAReqIELength is too large***"); + ret = -EINVAL; + goto error; + } + + pConfig->SSIDinfo.ssidHidden = false; + + if (ssid != NULL) { + qdf_mem_copy(pConfig->SSIDinfo.ssid.ssId, ssid, ssid_len); + pConfig->SSIDinfo.ssid.length = ssid_len; + + switch (hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + hdd_debug("HIDDEN_SSID_NOT_IN_USE"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_NOT_IN_USE; + break; + case NL80211_HIDDEN_SSID_ZERO_LEN: + hdd_debug("HIDDEN_SSID_ZERO_LEN"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_ZERO_LEN; + break; + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hdd_debug("HIDDEN_SSID_ZERO_CONTENTS"); + pConfig->SSIDinfo.ssidHidden = + eHIDDEN_SSID_ZERO_CONTENTS; + break; + default: + hdd_err("Wrong hidden_ssid param: %d", hidden_ssid); + break; + } + } + + qdf_mem_copy(pConfig->self_macaddr.bytes, + adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + + /* default value */ + pConfig->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED; + pConfig->num_accept_mac = 0; + pConfig->num_deny_mac = 0; +#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 == hdd_ctx->config->conc_custom_rule1) || + (hdd_ctx->config->conc_custom_rule1 && + QDF_SAP_MODE == adapter->device_mode)) + pConfig->cc_switch_mode = iniConfig->WlanMccToSccSwitchMode; +#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 = pBeacon->head_len - beacon_fixed_len; + + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_SUPP_RATES, + &pMgmt_frame->u.beacon.variable[0], + beacon_data_len); + + if (pIe != NULL) { + pIe++; + if (pIe[0] > SIR_MAC_RATESET_EID_MAX) { + hdd_err("Invalid supported rates %d", + pIe[0]); + ret = -EINVAL; + goto error; + } + pConfig->supported_rates.numRates = pIe[0]; + pIe++; + for (i = 0; + i < pConfig->supported_rates.numRates; i++) { + if (pIe[i]) { + pConfig->supported_rates.rate[i] = pIe[i]; + hdd_debug("Configured Supported rate is %2x", + pConfig->supported_rates.rate[i]); + } + } + } + pIe = wlan_get_ie_ptr_from_eid(WLAN_EID_EXT_SUPP_RATES, + pBeacon->tail, + pBeacon->tail_len); + if (pIe != NULL) { + pIe++; + if (pIe[0] > SIR_MAC_RATESET_EID_MAX) { + hdd_err("Invalid supported rates %d", + pIe[0]); + ret = -EINVAL; + goto error; + } + pConfig->extended_rates.numRates = pIe[0]; + pIe++; + for (i = 0; i < pConfig->extended_rates.numRates; i++) { + if (pIe[i]) { + pConfig->extended_rates.rate[i] = pIe[i]; + hdd_debug("Configured ext Supported rate is %2x", + pConfig->extended_rates.rate[i]); + } + } + } + } + + if (!cds_is_sub_20_mhz_enabled()) + wlan_hdd_set_sap_hwmode(adapter); + + if (IS_24G_CH(pConfig->channel) && + hdd_ctx->config->enableVhtFor24GHzBand && + (pConfig->SapHw_mode == eCSR_DOT11_MODE_11n || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11n_ONLY)) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11ac; + + if (((adapter->device_mode == QDF_SAP_MODE) && + (hdd_ctx->config->sap_force_11n_for_11ac)) || + ((adapter->device_mode == QDF_P2P_GO_MODE) && + (hdd_ctx->config->go_force_11n_for_11ac))) { + if (pConfig->SapHw_mode == eCSR_DOT11_MODE_11ac || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n; + } + + 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->csrConfig.WMMSupportMode = eCsrRoamWmmAuto; + pIe = wlan_get_vendor_ie_ptr_from_oui(WMM_OUI_TYPE, WMM_OUI_TYPE_SIZE, + pBeacon->tail, pBeacon->tail_len); + if (!pIe && (pConfig->SapHw_mode == eCSR_DOT11_MODE_11a || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11g || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11b)) + sme_config->csrConfig.WMMSupportMode = eCsrRoamWmmNoQos; + sme_update_config(mac_handle, sme_config); + + if (!((adapter->device_mode == QDF_SAP_MODE) && + (hdd_ctx->config->sap_force_11n_for_11ac)) || + ((adapter->device_mode == QDF_P2P_GO_MODE) && + (hdd_ctx->config->go_force_11n_for_11ac))) { + pConfig->ch_width_orig = + hdd_map_nl_chan_width(pConfig->ch_width_orig); + } else { + if (pConfig->ch_width_orig >= NL80211_CHAN_WIDTH_40) + pConfig->ch_width_orig = CH_WIDTH_40MHZ; + else + pConfig->ch_width_orig = CH_WIDTH_20MHZ; + } + + if (wlan_hdd_setup_driver_overrides(adapter)) { + ret = -EINVAL; + goto error; + } + + pConfig->ch_params.ch_width = pConfig->ch_width_orig; + wlan_reg_set_channel_params(hdd_ctx->pdev, pConfig->channel, + pConfig->sec_ch, &pConfig->ch_params); + + /* ht_capab is not what the name conveys, + * this is used for protection bitmap + */ + pConfig->ht_capab = iniConfig->apProtection; + + if (0 != wlan_hdd_cfg80211_update_apies(adapter)) { + hdd_err("SAP Not able to set AP IEs"); + ret = -EINVAL; + goto error; + } + /* Uapsd Enabled Bit */ + pConfig->UapsdEnable = iniConfig->apUapsdEnabled; + /* Enable OBSS protection */ + pConfig->obssProtEnabled = iniConfig->apOBSSProtEnabled; + + if (adapter->device_mode == QDF_SAP_MODE) + pConfig->sap_dot11mc = + (WLAN_HDD_GET_CTX(adapter))->config->sap_dot11mc; + else /* for P2P-Go case */ + pConfig->sap_dot11mc = 1; + + hdd_debug("11MC Support Enabled : %d\n", + pConfig->sap_dot11mc); + +#ifdef WLAN_FEATURE_11W + pConfig->mfpCapable = MFPCapable; + pConfig->mfpRequired = MFPRequired; + hdd_debug("Soft AP MFP capable %d, MFP required %d", + pConfig->mfpCapable, pConfig->mfpRequired); +#endif + + hdd_debug("SOftAP macaddress : " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(adapter->mac_addr.bytes)); + hdd_debug("ssid =%s, beaconint=%d, channel=%d", + pConfig->SSIDinfo.ssid.ssId, (int)pConfig->beacon_int, + (int)pConfig->channel); + hdd_debug("hw_mode=%x, privacy=%d, authType=%d", + pConfig->SapHw_mode, pConfig->privacy, pConfig->authType); + hdd_debug("RSN/WPALen=%d, Uapsd = %d", + (int)pConfig->RSNWPAReqIELength, pConfig->UapsdEnable); + hdd_debug("ProtEnabled = %d, OBSSProtEnabled = %d", + pConfig->protEnabled, pConfig->obssProtEnabled); + hdd_debug("ChanSwitchHostapdRateEnabled = %d", + pConfig->chan_switch_hostapd_rate_enabled); + + 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, &adapter->event_flags)) { + mutex_unlock(&hdd_ctx->sap_lock); + + wlansap_reset_sap_config_add_ie(pConfig, 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; + } + + if (check_for_concurrency) { + if (!policy_mgr_allow_concurrency(hdd_ctx->psoc, + policy_mgr_convert_device_mode_to_qdf_type( + adapter->device_mode), + pConfig->channel, HW_MODE_20_MHZ)) { + 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; + } + + pConfig->persona = adapter->device_mode; + + pSapEventCallback = hdd_hostapd_sap_event_cb; + + (WLAN_HDD_GET_AP_CTX_PTR(adapter))->dfs_cac_block_tx = true; + set_bit(SOFTAP_INIT_DONE, &adapter->event_flags); + + qdf_event_reset(&hostapd_state->qdf_event); + status = wlansap_start_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pSapEventCallback, pConfig, 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; + } + + hdd_debug("Waiting for Scan to complete(auto mode) and BSS to start"); + + qdf_status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, + SME_CMD_START_STOP_BSS_TIMEOUT); + + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mutex_unlock(&hdd_ctx->sap_lock); + + hdd_err("qdf wait for single_event failed!!"); + hdd_set_connection_in_progress(false); + sme_get_command_q_status(mac_handle); + wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + QDF_ASSERT(0); + ret = -EINVAL; + goto error; + } + /* Successfully started Bss update the state bit. */ + set_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + + mutex_unlock(&hdd_ctx->sap_lock); + + /* Initialize WMM configuation */ + hdd_wmm_init(adapter); + if (hostapd_state->bss_state == BSS_START) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + adapter->device_mode, + adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + true); + } +#ifdef DHCP_SERVER_OFFLOAD + if (iniConfig->enableDHCPServerOffload) + wlan_hdd_set_dhcp_server_offload(adapter); +#endif /* DHCP_SERVER_OFFLOAD */ + + ucfg_p2p_status_start_bss(adapter->vdev); + + /* Check and restart SAP if it is on unsafe channel */ + hdd_unsafe_channel_restart_sap(hdd_ctx); + + hdd_set_connection_in_progress(false); + + ret = 0; + goto free; + +error: + + /* Revert the indoor to passive marking if START BSS fails */ + if (iniConfig->force_ssc_disable_indoor_channel && + adapter->device_mode == QDF_SAP_MODE) { + hdd_update_indoor_channel(hdd_ctx, false); + sme_update_channel_list(mac_handle); + } + clear_bit(SOFTAP_INIT_DONE, &adapter->event_flags); + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + wlan_hdd_undo_acs(adapter); + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + +free: + /* Enable Roaming after start bss in case of failure/success */ + wlan_hdd_enable_roaming(adapter); + qdf_mem_free(sme_config); + return ret; +} + +int hdd_destroy_acs_timer(struct hdd_adapter *adapter) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (!adapter->session.ap.vendor_acs_timer_initialized) + return 0; + + adapter->session.ap.vendor_acs_timer_initialized = false; + + clear_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->event_flags); + if (QDF_TIMER_STATE_RUNNING == + adapter->session.ap.vendor_acs_timer.state) { + qdf_status = + qdf_mc_timer_stop(&adapter->session.ap. + vendor_acs_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to stop ACS timer"); + } + + if (adapter->session.ap.vendor_acs_timer.user_data) + qdf_mem_free(adapter->session.ap.vendor_acs_timer.user_data); + + qdf_mc_timer_destroy(&adapter->session.ap.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 qdf_status = QDF_STATUS_E_FAILURE; + tSirUpdateIE updateIE; + int ret; + mac_handle_t mac_handle; + + hdd_enter(); + + 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 + * kernal 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) + return 0; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver module is closed; dropping request"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_STOP_AP, + adapter->session_id, adapter->device_mode); + + if (!(adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE)) { + return -EOPNOTSUPP; + } + + /* 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->event_flags); + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + /* + * If a STA connection is in progress in another adapter, disconnect + * the STA and complete the SAP operation. STA will reconnect + * after SAP stop is done. + */ + hdd_abort_ongoing_sta_connection(hdd_ctx); + + if (adapter->device_mode == QDF_SAP_MODE) + wlan_hdd_del_station(adapter); + + cds_flush_work(&adapter->sap_stop_bss_work); + /* + * When ever stop ap adapter gets called, we need to check + * whether any restart AP work is pending. If any restart is pending + * then lets finish it and go ahead from there. + */ + if (hdd_ctx->config->conc_custom_rule1 && + (QDF_SAP_MODE == adapter->device_mode)) { + cds_flush_work(&hdd_ctx->sap_start_work); + hdd_debug("Canceled the pending restart work"); + qdf_spin_lock(&hdd_ctx->sap_update_info_lock); + hdd_ctx->is_sap_restart_required = false; + qdf_spin_unlock(&hdd_ctx->sap_update_info_lock); + } + adapter->session.ap.sap_config.acs_cfg.acs_mode = false; + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + wlan_hdd_undo_acs(adapter); + qdf_mem_zero(&adapter->session.ap.sap_config.acs_cfg, + sizeof(struct sap_acs_cfg)); + 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); + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + /* Set the stop_bss_in_progress flag */ + wlansap_set_stop_bss_inprogress( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), true); + + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + status = wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_status = + qdf_wait_for_event_completion(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_START_STOP_BSS_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("qdf wait for single_event failed!!"); + QDF_ASSERT(0); + } + } + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + hdd_stop_tsf_sync(adapter); + + /* Clear the stop_bss_in_progress flag */ + wlansap_set_stop_bss_inprogress( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), false); + + /*BSS stopped, clear the active sessions for this device mode*/ + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + + if (adapter->session.ap.beacon) { + qdf_mem_free(adapter->session.ap.beacon); + adapter->session.ap.beacon = NULL; + } + } else { + hdd_debug("SAP already down"); + mutex_unlock(&hdd_ctx->sap_lock); + return 0; + } + + mutex_unlock(&hdd_ctx->sap_lock); + + mac_handle = hdd_ctx->mac_handle; + if (wlan_sap_is_pre_cac_active(mac_handle)) + hdd_clean_up_pre_cac_interface(hdd_ctx); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Stopping the BSS"); + return -EINVAL; + } + + qdf_copy_macaddr(&updateIE.bssid, &adapter->mac_addr); + updateIE.smeSessionId = adapter->session_id; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = true; + if (sme_update_add_ie(mac_handle, + &updateIE, + 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, + &updateIE, + 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); + hdd_destroy_acs_timer(adapter); + + ucfg_p2p_status_stop_bss(adapter->vdev); + + hdd_exit(); + + return ret; +} + +/** + * wlan_hdd_get_channel_bw() - get channel bandwidth + * @width: input channel width in nl80211_chan_width value + * + * Return: channel width value defined by driver + */ +static enum hw_mode_bandwidth wlan_hdd_get_channel_bw( + enum nl80211_chan_width width) +{ + enum hw_mode_bandwidth ch_bw = HW_MODE_20_MHZ; + + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + ch_bw = HW_MODE_20_MHZ; + break; + case NL80211_CHAN_WIDTH_40: + ch_bw = HW_MODE_40_MHZ; + break; + case NL80211_CHAN_WIDTH_80: + ch_bw = HW_MODE_80_MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + ch_bw = HW_MODE_80_PLUS_80_MHZ; + break; + case NL80211_CHAN_WIDTH_160: + ch_bw = HW_MODE_160_MHZ; + break; + default: + hdd_err("Invalid width: %d, using default 20MHz", width); + break; + } + + return ch_bw; +} + +/** + * wlan_hdd_cfg80211_stop_ap() - stop sap + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_stop_ap(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 == + sband_bitrates[i].hw_value) + return sband_bitrates[i].bitrate; + } + } + return 0; +} + +/** + * hdd_update_beacon_rate() - Update beacon tx rate + * @adapter: Pointer to hdd_adapter_t + * @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 hdd_adapter *adapter, + struct wiphy *wiphy, + struct cfg80211_ap_settings *params) +{ + struct cfg80211_bitrate_mask *beacon_rate_mask; + enum nl80211_band band; + + band = params->chandef.chan->band; + beacon_rate_mask = ¶ms->beacon_rate; + if (beacon_rate_mask->control[band].legacy) { + adapter->session.ap.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, + adapter->session.ap.sap_config.beacon_tx_rate); + } +} +#else +static void hdd_update_beacon_rate(struct hdd_adapter *adapter, + struct wiphy *wiphy, + struct cfg80211_ap_settings *params) +{ +} +#endif + + +/** + * __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 channel; + bool sta_sap_scc_on_dfs_chan; + uint16_t sta_cnt; + struct wireless_dev *wdev = dev->ieee80211_ptr; + + hdd_enter(); + + clear_bit(SOFTAP_INIT_DONE, &adapter->event_flags); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_START_AP, + adapter->session_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; + + hdd_debug("adapter = %pK, Device mode %s(%d) sub20 %d", + adapter, hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode, 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; + } + } + + channel_width = wlan_hdd_get_channel_bw(params->chandef.width); + channel = ieee80211_frequency_to_channel( + params->chandef.chan->center_freq); + if (!channel) { + hdd_err("Invalid channel"); + return -EINVAL; + } + + if (policy_mgr_is_sap_mandatory_chan_list_enabled(hdd_ctx->psoc)) { + if (WLAN_REG_IS_5GHZ_CH(channel)) { + hdd_debug("channel %hu, sap mandatory chan list enabled", + channel); + if (!policy_mgr_get_sap_mandatory_chan_list_len( + hdd_ctx->psoc)) + policy_mgr_init_sap_mandatory_2g_chan( + hdd_ctx->psoc); + + policy_mgr_add_sap_mandatory_chan(hdd_ctx->psoc, + channel); + } else { + policy_mgr_init_sap_mandatory_2g_chan( + hdd_ctx->psoc); + } + } + + adapter->session.ap.sap_config.ch_params.center_freq_seg0 = + cds_freq_to_chan(params->chandef.center_freq1); + adapter->session.ap.sap_config.ch_params.center_freq_seg1 = + cds_freq_to_chan(params->chandef.center_freq2); + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + hdd_ctx->psoc); + sta_cnt = + policy_mgr_mode_specific_connection_count( + hdd_ctx->psoc, PM_STA_MODE, NULL); + + hdd_debug("sta_sap_scc_on_dfs_chan %u, sta_cnt %u", + sta_sap_scc_on_dfs_chan, sta_cnt); + + /* if sta_sap_scc_on_dfs_chan ini is set, DFS master capability is + * assumed disabled in the driver. + */ + if ((reg_get_channel_state(hdd_ctx->pdev, channel) == + CHANNEL_STATE_DFS) && sta_sap_scc_on_dfs_chan && !sta_cnt) { + hdd_err("SAP not allowed on DFS channel!!"); + return -EINVAL; + } + if (!reg_is_etsi13_srd_chan_allowed_master_mode(hdd_ctx->pdev) && + reg_is_etsi13_srd_chan(hdd_ctx->pdev, channel)) { + hdd_err("SAP not allowed on SRD channel."); + 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; + tsap_config_t *sap_cfg = &adapter->session.ap.sap_config; + + if (CHANNEL_STATE_DFS == wlan_reg_get_channel_state( + hdd_ctx->pdev, channel)) { + hdd_err("Can't start SAP-DFS (channel=%d)with sub 20 MHz ch wd", + channel); + 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; + if (WLAN_REG_IS_5GHZ_CH(channel)) + ch_state = wlan_reg_get_5g_bonded_channel_state( + hdd_ctx->pdev, channel, + sub_20_ch_width); + else + ch_state = wlan_reg_get_2g_bonded_channel_state( + hdd_ctx->pdev, channel, + sub_20_ch_width, 0); + if (CHANNEL_STATE_DISABLE == ch_state) { + hdd_err("Given ch width not supported by reg domain"); + return -EINVAL; + } + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_abg; + } + + /* check if concurrency is allowed */ + if (!policy_mgr_allow_concurrency(hdd_ctx->psoc, + policy_mgr_convert_device_mode_to_qdf_type( + adapter->device_mode), + channel, + channel_width)) { + 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 stoping 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, + channel); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to stop DBS opportunistic timer"); + return -EINVAL; + } + + status = policy_mgr_current_connections_update(hdd_ctx->psoc, + adapter->session_id, channel, + POLICY_MGR_UPDATE_REASON_START_AP); + 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("ERROR: qdf wait for event failed!!"); + return -EINVAL; + } + } + + if (adapter->device_mode == QDF_P2P_GO_MODE) { + struct hdd_adapter *p2p_adapter; + + p2p_adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_DEVICE_MODE); + if (p2p_adapter) { + hdd_debug("Cancel active p2p device ROC before GO starting"); + wlan_hdd_cancel_existing_remain_on_channel( + p2p_adapter); + } + } + + 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; + tsap_config_t *sap_config = + &((WLAN_HDD_GET_AP_CTX_PTR(adapter))->sap_config); + + old = adapter->session.ap.beacon; + + if (old) + return -EALREADY; + + status = + wlan_hdd_cfg80211_alloc_new_beacon(adapter, &new, + ¶ms->beacon, + params->dtim_period); + + if (status != 0) { + hdd_err("Error!!! Allocating the new beacon"); + return -EINVAL; + } + adapter->session.ap.beacon = new; + + if (params->chandef.width < NL80211_CHAN_WIDTH_80) + channel_type = cfg80211_get_chandef_type( + &(params->chandef)); + else + channel_type = NL80211_CHAN_HT40PLUS; + + + wlan_hdd_set_channel(wiphy, dev, + ¶ms->chandef, + channel_type); + + hdd_update_beacon_rate(adapter, wiphy, params); + + /* set authentication type */ + switch (params->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + adapter->session.ap.sap_config.authType = + eSAP_OPEN_SYSTEM; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + adapter->session.ap.sap_config.authType = + eSAP_SHARED_KEY; + break; + default: + adapter->session.ap.sap_config.authType = + eSAP_AUTO_SWITCH; + } + adapter->session.ap.sap_config.ch_width_orig = + params->chandef.width; + + status = + wlan_hdd_cfg80211_start_bss(adapter, + ¶ms->beacon, + params->ssid, params->ssid_len, + params->hidden_ssid, true); + + if (status != 0) { + hdd_err("Error Start bss Failed"); + goto err_start_bss; + } + + hdd_start_tsf_sync(adapter); + + if (wdev->chandef.chan->center_freq != + params->chandef.chan->center_freq) + params->chandef = wdev->chandef; + /* + * If Do_Not_Break_Stream enabled send avoid channel list + * to application. + */ + if (policy_mgr_is_dnsc_set(adapter->vdev) && + sap_config->channel) { + wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, + sap_config->channel); + } + if (hdd_ctx->config->sap_max_inactivity_override) { + sta_inactivity_timer = qdf_mem_malloc( + sizeof(*sta_inactivity_timer)); + if (!sta_inactivity_timer) { + hdd_err("Failed to allocate Memory"); + return QDF_STATUS_E_FAILURE; + } + sta_inactivity_timer->session_id = adapter->session_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: + if (adapter->session.ap.beacon) + qdf_mem_free(adapter->session.ap.beacon); + adapter->session.ap.beacon = NULL; + +success: + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_start_ap(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BEACON, + adapter->session_id, adapter->device_mode); + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(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 = adapter->session.ap.beacon; + + if (!old) { + hdd_err("session id: %d beacon data points to NULL", + adapter->session_id); + return -EINVAL; + } + + status = wlan_hdd_cfg80211_alloc_new_beacon(adapter, &new, params, 0); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("new beacon alloc failed"); + return -EINVAL; + } + + adapter->session.ap.beacon = new; + hdd_debug("update beacon for P2P GO/SAP"); + status = wlan_hdd_cfg80211_start_bss(adapter, 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_change_beacon(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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) +{ + tSap_Event sap_event; + int sta_id; + struct sap_context *sap_ctx; + + hdd_enter(); + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + if (!sap_ctx) { + hdd_err("invalid sap context"); + return; + } + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + if (adapter->sta_info[sta_id].in_use) { + hdd_debug("sta_id: %d in_use: %d %pK", + sta_id, adapter->sta_info[sta_id].in_use, + adapter); + + if (qdf_is_macaddr_broadcast( + &adapter->sta_info[sta_id].sta_mac)) + continue; + + sap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT; + qdf_mem_copy( + &sap_event.sapevt. + sapStationDisassocCompleteEvent.staMac, + &adapter->sta_info[sta_id].sta_mac, + sizeof(struct qdf_mac_addr)); + sap_event.sapevt.sapStationDisassocCompleteEvent. + reason = + eSAP_MAC_INITATED_DISASSOC; + sap_event.sapevt.sapStationDisassocCompleteEvent. + statusCode = + QDF_STATUS_E_RESOURCES; + hdd_hostapd_sap_event_cb(&sap_event, + sap_ctx->pUsrContext); + } + } + + hdd_exit(); +} + +bool hdd_is_peer_associated(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr) +{ + uint32_t cnt; + struct hdd_station_info *sta_info; + + if (!adapter || !mac_addr) { + hdd_err("Invalid adapter or mac_addr"); + return false; + } + + sta_info = adapter->sta_info; + spin_lock_bh(&adapter->sta_info_lock); + for (cnt = 0; cnt < WLAN_MAX_STA_COUNT; cnt++) { + if ((sta_info[cnt].in_use) && + !qdf_mem_cmp(&(sta_info[cnt].sta_mac), mac_addr, + QDF_MAC_ADDR_SIZE)) + break; + } + spin_unlock_bh(&adapter->sta_info_lock); + if (cnt != WLAN_MAX_STA_COUNT) + return true; + + return false; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h new file mode 100644 index 0000000000000000000000000000000000000000..0d7af0d0675a16aac23a59555f4fd78b820f2a99 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h @@ -0,0 +1,249 @@ +/* + * 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. + */ + +#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 */ + +/* max length of command string in hostapd ioctl */ +#define HOSTAPD_IOCTL_COMMAND_STRLEN_MAX 8192 + +struct hdd_adapter *hdd_wlan_create_ap_dev(struct hdd_context *hdd_ctx, + tSirMacAddr macAddr, + unsigned char name_assign_type, + uint8_t *name); + +QDF_STATUS hdd_unregister_hostapd(struct hdd_adapter *adapter, bool rtnl_held); + +eCsrAuthType +hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]); + +int hdd_softap_set_channel_change(struct net_device *dev, + int target_channel, + enum phy_ch_width target_bw, + bool forced); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void hdd_sap_restart_with_channel_switch(struct hdd_adapter *adapter, + uint32_t target_channel, + 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 + * @channel: channel to switch + * @forced: Force to switch channel, ignore SCC/MCC check + * + * This function restarts SAP with a different channel + * + * Return: None + * + */ +void hdd_sap_restart_chan_switch_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t channel, + uint32_t channel_bw, + bool forced); +/** + * wlan_hdd_get_channel_for_sap_restart() - Function to get + * suitable channel and restart SAP + * @psoc: PSOC object information + * @vdev_id: vdev id + * @channel: channel to be returned + * @sec_ch: secondary 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, uint8_t *channel, + uint8_t *sec_ch); +#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]); + +eCsrAuthType +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 *pDelStaParams); +void hdd_softap_sta_disassoc(struct hdd_adapter *adapter, + struct csr_del_sta_params *pDelStaParams); + +QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, + void *context); +/** + * hdd_init_ap_mode() - to init the AP adaptor + * @adapter: SAP/GO adapter + * @rtnl_held: flag to indicate if RTNL lock needs to be acquired + * + * 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); +/** + * hdd_deinit_ap_mode() - to deinit the AP adaptor + * @hdd_ctx: pointer to hdd_ctx + * @adapter: SAP/GO adapter + * @rtnl_held: flag to indicate if RTNL lock needs to be acquired + * + * 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 hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool rtnl_held); +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 + * @adapter: pointer to 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 hdd_adapter *adapter); +/** + * hdd_sap_destroy_ctx_all() - Wrapper API to destroy all SAP context + * @adapter: pointer to adapter + * @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); + +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); +#endif + +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev); + +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); + +/** + * 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 + * + * 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); + +#endif /* end #if !defined(WLAN_HDD_HOSTAPD_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.c new file mode 100644 index 0000000000000000000000000000000000000000..b8c081c24c92cd868ff2d3858dbff134ca4e772a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.c @@ -0,0 +1,207 @@ +/* + * 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_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 "wlan_hdd_cfg.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; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + (sizeof(u8) + NLA_HDRLEN) + + (sizeof(u8) + NLA_HDRLEN) + + (sizeof(u8) + NLA_HDRLEN) + + (sizeof(u8) + NLA_HDRLEN) + + NLMSG_HDRLEN); + + if (!skb) { + hdd_err("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; + } + + cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + kfree_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_hw_capability(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.h new file mode 100644 index 0000000000000000000000000000000000000000..0cbdc071a54ab62c2d5ac65b287fbb1118a42ace --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.h @@ -0,0 +1,58 @@ +/* + * 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_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 \ +}, +#else /* FEATURE_HW_CAPABILITY */ +#define FEATURE_HW_CAPABILITY_COMMANDS +#endif /* FEATURE_HW_CAPABILITY */ + +#endif /* __WLAN_HDD_HW_CAPABILITY_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..cc96a8df4604e1f92088e74719becb991f1814ac --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c @@ -0,0 +1,7913 @@ +/* + * 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. + */ + +/* Include Files */ + +#include +#include +#include +#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" + +#ifdef FEATURE_WLAN_ESE +#include +#include +#endif +#include "hif.h" + +#if defined(LINUX_QCMBR) +#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13) +#endif + +/* + * Size of Driver command strings from upper layer + */ +#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */ +#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */ + +/* + * Size of GETCOUNTRYREV output = (sizeof("GETCOUNTRYREV") = 14) + one (space) + + * (sizeof("country_code") = 3) + + * one (NULL terminating character) + */ +#define SIZE_OF_GETCOUNTRYREV_OUTPUT 20 + +/* + * Ibss prop IE from command will be of size: + * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length) + * OUI_DATA should be at least 3 bytes long + */ +#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3) + +#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 + */ +#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0 +#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2 + +/* + * 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 + +#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 hdd_adapter *adapter, + 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 + +static uint16_t cesium_pid; + +/** + * 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, + const uint32_t staId, 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 (NULL == 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); + + 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.staId[0], + 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 */ + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcenable_command(uint8_t *pValue, + uint8_t *pRmcEnable) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pRmcEnable = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) + return 0; + else if (SPACE_ASCII_VALUE != *inPtr) + return 0; + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) + return 0; + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) + return -EINVAL; + + *pRmcEnable = tempInt; + + hdd_debug("ucRmcEnable: %d", *pRmcEnable); + + return 0; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue, + uint32_t *pActionPeriod) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pActionPeriod = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *inPtr) + return -EINVAL; + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) + return 0; + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) + return -EINVAL; + + if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) || + (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) + return -EINVAL; + + *pActionPeriod = tempInt; + + hdd_debug("uActionPeriod: %d", *pActionPeriod); + + return 0; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcrate_command(uint8_t *pValue, + uint32_t *pRate, + enum tx_rate_info *pTxFlags) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pRate = 0; + *pTxFlags = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *inPtr) + return -EINVAL; + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) + return 0; + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) + return -EINVAL; + + switch (tempInt) { + default: + hdd_warn("Unsupported rate: %d", tempInt); + return -EINVAL; + case 0: + case 6: + case 9: + case 12: + case 18: + case 24: + case 36: + case 48: + case 54: + *pTxFlags = TX_RATE_LEGACY; + *pRate = tempInt * 10; + break; + case 65: + *pTxFlags = TX_RATE_HT20; + *pRate = tempInt * 10; + break; + case 72: + *pTxFlags = TX_RATE_HT20 | TX_RATE_SGI; + *pRate = 722; + break; + } + + hdd_debug("Rate: %d", *pRate); + + return 0; +} + +/** + * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback + * @UserData: Adapter private data + * @pPeerInfoRsp: Peer info response + * + * This is an asynchronous callback function from SME when the peer info + * is received + * + * Return: 0 for success non-zero for failure + */ +void +hdd_get_ibss_peer_info_cb(void *pUserData, + tSirPeerInfoRspParams *pPeerInfo) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) pUserData; + struct hdd_station_ctx *pStaCtx; + uint8_t i; + + if ((NULL == adapter) || + (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("invalid adapter or adapter has invalid magic"); + return; + } + + pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) { + /* validate number of peers */ + if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) { + hdd_warn("Limiting num_peers %u to %u", + pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS); + pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS; + } + pStaCtx->ibss_peer_info.status = pPeerInfo->status; + pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers; + + for (i = 0; i < pPeerInfo->numPeers; i++) + pStaCtx->ibss_peer_info.peerInfoParams[i] = + pPeerInfo->peerInfoParams[i]; + } else { + hdd_debug("peerInfo %s: status %u, numPeers %u", + pPeerInfo ? "valid" : "null", + pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE, + pPeerInfo ? pPeerInfo->numPeers : 0); + pStaCtx->ibss_peer_info.numPeers = 0; + pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE; + } + + complete(&adapter->ibss_peer_info_comp); +} + +/** + * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info + * @adapter: Adapter context + * + * Request function to get IBSS peer info from lower layers + * + * Return: 0 for success non-zero for failure + */ +static +QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + unsigned long rc; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + + status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle, + adapter, + hdd_get_ibss_peer_info_cb, + true, 0xFF); + + if (QDF_STATUS_SUCCESS == status) { + rc = wait_for_completion_timeout + (&adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + + /* status will be 0 if timed out */ + if (!rc) { + hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT"); + status = QDF_STATUS_E_FAILURE; + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return status; +} + +/** + * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info + * @adapter: Adapter context + * @staIdx: Sta index for which the peer info is requested + * + * Request function to get IBSS peer info from lower layers + * + * Return: 0 for success non-zero for failure + */ +static QDF_STATUS +hdd_cfg80211_get_ibss_peer_info(struct hdd_adapter *adapter, uint8_t staIdx) +{ + unsigned long rc; + QDF_STATUS status; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + + status = sme_request_ibss_peer_info(adapter->hdd_ctx->mac_handle, + adapter, + hdd_get_ibss_peer_info_cb, + false, staIdx); + + if (QDF_STATUS_SUCCESS == status) { + rc = wait_for_completion_timeout( + &adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + + /* status = 0 on timeout */ + if (!rc) { + hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT"); + status = QDF_STATUS_E_FAILURE; + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return status; +} + +/* Function header is left blank intentionally */ +static QDF_STATUS +hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr) +{ + uint8_t *inPtr = pValue; + size_t in_ptr_len = strlen(pValue); + + inPtr = strnchr(pValue, in_ptr_len, SPACE_ASCII_VALUE); + + if (NULL == inPtr) + return QDF_STATUS_E_FAILURE; + else if (SPACE_ASCII_VALUE != *inPtr) + return QDF_STATUS_E_FAILURE; + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) + return QDF_STATUS_E_FAILURE; + + in_ptr_len -= (inPtr - pValue); + if (in_ptr_len < 17) + return QDF_STATUS_E_FAILURE; + + if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' || + inPtr[11] != ':' || inPtr[14] != ':') + return QDF_STATUS_E_FAILURE; + + sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x", + (unsigned int *)&pPeerMacAddr->bytes[0], + (unsigned int *)&pPeerMacAddr->bytes[1], + (unsigned int *)&pPeerMacAddr->bytes[2], + (unsigned int *)&pPeerMacAddr->bytes[3], + (unsigned int *)&pPeerMacAddr->bytes[4], + (unsigned int *)&pPeerMacAddr->bytes[5]); + + return QDF_STATUS_SUCCESS; +} + +static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band) +{ + enum band_info band = -1; + + sme_get_freq_band(hdd_ctx->mac_handle, &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_parse_bssid_and_chan() - helper function to parse bssid and channel + * @data: input data + * @target_ap_bssid: pointer to bssid (output parameter) + * @channel: pointer to channel (output parameter) + * + * Return: 0 if parsing is successful; -EINVAL otherwise + */ +static int _hdd_parse_bssid_and_chan(const uint8_t **data, + uint8_t *bssid, + uint8_t *channel) +{ + 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 (NULL == 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 (NULL == 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 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) || + (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) + return -EINVAL; + + *channel = temp_int; + *data = in_ptr; + return 0; +error: + *data = in_ptr; + return -EINVAL; +} + +/** + * hdd_parse_send_action_frame_data() - HDD Parse send action frame data + * @pValue: Pointer to input data + * @pTargetApBssid: Pointer to target Ap bssid + * @pChannel: Pointer to the Target AP channel + * @pDwellTime: Pointer to the time to stay off-channel + * after transmitting action frame + * @pBuf: Pointer to data + * @pBufLen: Pointer to data length + * + * 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 *pValue, + uint8_t *pTargetApBssid, + uint8_t *pChannel, uint8_t *pDwellTime, + uint8_t **pBuf, uint8_t *pBufLen) +{ + const uint8_t *inPtr = pValue; + const uint8_t *dataEnd; + int tempInt; + int j = 0; + int i = 0; + int v = 0; + uint8_t tempBuf[32]; + uint8_t tempByte = 0; + + if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel)) + return -EINVAL; + + /* point to the next argument */ + inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return -EINVAL; + + /* getting the next argument ie the dwell time */ + v = sscanf(inPtr, "%31s ", tempBuf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(tempBuf, 10, &tempInt); + if (v < 0 || tempInt < 0) + return -EINVAL; + + *pDwellTime = tempInt; + + /* point to the next argument */ + inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return -EINVAL; + + /* find the length of data */ + dataEnd = inPtr; + while (('\0' != *dataEnd)) + dataEnd++; + + *pBufLen = dataEnd - inPtr; + if (*pBufLen <= 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 + */ + *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2); + if (NULL == *pBuf) { + hdd_err("qdf_mem_malloc failed"); + 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 < *pBufLen; j += 2) { + if (j + 1 == *pBufLen) { + tempByte = hex_to_bin(inPtr[j]); + } else { + tempByte = + (hex_to_bin(inPtr[j]) << 4) | + (hex_to_bin(inPtr[j + 1])); + } + (*pBuf)[i++] = tempByte; + } + *pBufLen = i; + return 0; +} + +/** + * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data + * @pValue: Pointer to input data (its a NULL terminated string) + * @pTargetApBssid: Pointer to target Ap bssid + * @pChannel: Pointer to the Target AP channel + * + * This function parses the reasoc command data passed in the format + * REASSOC + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue, + uint8_t *pTargetApBssid, + uint8_t *pChannel) +{ + const uint8_t *inPtr = pValue; + + if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel)) + return -EINVAL; + + return 0; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS hdd_wma_send_fastreassoc_cmd(struct hdd_adapter *adapter, + const tSirMacAddr bssid, + int channel) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct csr_roam_profile *roam_profile; + tSirMacAddr connected_bssid; + + roam_profile = hdd_roam_profile(adapter); + qdf_mem_copy(connected_bssid, hdd_sta_ctx->conn_info.bssId.bytes, + ETH_ALEN); + return sme_fast_reassoc(adapter->hdd_ctx->mac_handle, roam_profile, + bssid, channel, adapter->session_id, + connected_bssid); +} +#endif + +/** + * hdd_reassoc() - perform a userspace-directed reassoc + * @adapter: Adapter upon which the command was received + * @bssid: BSSID with which to reassociate + * @channel: channel upon which to reassociate + * @src: The source for the trigger of this action + * + * This function performs a userspace-directed reassoc operation + * + * Return: 0 for success non-zero for failure + */ +int hdd_reassoc(struct hdd_adapter *adapter, const uint8_t *bssid, + uint8_t channel, const handoff_src src) +{ + struct hdd_station_ctx *sta_ctx; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret = 0; + QDF_STATUS status; + + if (hdd_ctx == NULL) { + hdd_err("Invalid hdd ctx"); + return -EINVAL; + } + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* + * pHddStaCtx->conn_info.connState is set to disconnected only + * after the disconnect done indication from SME. If the SME is + * in the process of disconnecting, the SME Connection state is + * set to disconnected and the pHddStaCtx->conn_info.connState + * will still be associated till the disconnect is done. + * So check both the HDD state and SME state here. + * If not associated, no need to proceed with reassoc + */ + if ((eConnectionState_Associated != sta_ctx->conn_info.connState) || + (!sme_is_conn_state_connected(hdd_ctx->mac_handle, + adapter->session_id))) { + hdd_warn("Not associated"); + ret = -EINVAL; + goto exit; + } + + /* + * if the target bssid is same as currently associated AP, + * use the current connections's channel. + */ + if (!memcmp(bssid, sta_ctx->conn_info.bssId.bytes, + QDF_MAC_ADDR_SIZE)) { + hdd_warn("Reassoc BSSID is same as currently associated AP bssid"); + channel = sta_ctx->conn_info.operationChannel; + } + + /* Check channel number is a valid channel number */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel)) { + hdd_err("Invalid Channel: %d", channel); + ret = -EINVAL; + goto exit; + } + + /* Proceed with reassoc */ + if (roaming_offload_enabled(hdd_ctx)) { + status = hdd_wma_send_fastreassoc_cmd(adapter, + bssid, (int)channel); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to send fast reassoc cmd"); + ret = -EINVAL; + } + } else { + tCsrHandoffRequest handoff; + + handoff.channel = channel; + handoff.src = src; + qdf_mem_copy(handoff.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE); + sme_handoff_request(hdd_ctx->mac_handle, adapter->session_id, + &handoff); + } +exit: + return ret; +} + +/** + * 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 + * + * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the + * BSSID and CH is the ASCII representation of the channel. For + * example + * + * REASSOC 00:0a:0b:11:22:33 48 + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command) +{ + uint8_t channel = 0; + tSirMacAddr bssid; + int ret; + + ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel); + if (ret) + hdd_err("Failed to parse reassoc command data"); + else + ret = hdd_reassoc(adapter, bssid, channel, REASSOC); + + return ret; +} + +/** + * 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; + int ret; + + 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 { + ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC); + } + 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 + * 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 + * @channel: Channel 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 uint8_t channel, 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 pVendorSpecific = + (tpSirMacVendorSpecificFrameHdr) payload; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + struct cfg80211_mgmt_tx_params params; +#endif + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* if not associated, no need to send action frame */ + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + 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 = sme_chn_to_freq(channel); + /* Check if it is specific action frame */ + if (pVendorSpecific->category == + SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) { + static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 }; + + if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) { + /* + * if the channel number is different from operating + * channel then no need to send action frame + */ + if (channel != 0) { + if (channel != + sta_ctx->conn_info.operationChannel) { + hdd_warn("channel(%d) is different from operating channel(%d)", + channel, + sta_ctx->conn_info. + operationChannel); + 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. + */ + sme_abort_roam_scan(hdd_ctx->mac_handle, + adapter->session_id); + } else { + /* + * 0 is accepted as current home channel, + * delayed transmission of action frame is ok. + */ + chan.center_freq = + sme_chn_to_freq(sta_ctx->conn_info. + operationChannel); + } + } + } + if (chan.center_freq == 0) { + hdd_err("Invalid channel number: %d", channel); + ret = -EINVAL; + goto exit; + } + + frame_len = payload_len + 24; + frame = qdf_mem_malloc(frame_len); + if (!frame) { + hdd_err("memory allocation failed"); + 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) +{ + uint8_t channel = 0; + uint8_t dwell_time = 0; + uint8_t payload_len = 0; + uint8_t *payload = NULL; + tSirMacAddr bssid; + int ret; + + ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel, + &dwell_time, &payload, + &payload_len); + if (ret) { + hdd_err("Failed to parse send action frame data"); + } else { + ret = hdd_sendactionframe(adapter, bssid, channel, + 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 + * + * 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; + + /* 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; + } + + ret = hdd_sendactionframe(adapter, bssid, params->channel, + 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 + * + * 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; +} + +/** + * hdd_parse_channellist() - HDD Parse channel list + * @pValue: Pointer to input channel list + * @ChannelList: Pointer to local output array to record + * channel list + * @pNumChannels: 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(const uint8_t *pValue, uint8_t *pChannelList, + uint8_t *pNumChannels) +{ + const uint8_t *inPtr = pValue; + int tempInt; + int j = 0; + int v = 0; + char buf[32]; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return -EINVAL; + + /* get the first argument ie the number of channels */ + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if ((v < 0) || + (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) + return -EINVAL; + + *pNumChannels = tempInt; + + hdd_debug("Number of channels are: %d", *pNumChannels); + + for (j = 0; j < (*pNumChannels); j++) { + /* + * inPtr pointing to the beginning of first space after number + * of channels + */ + inPtr = strpbrk(inPtr, " "); + /* no channel list after the number of channels argument */ + if (NULL == inPtr) { + if (0 != j) { + *pNumChannels = j; + return 0; + } else { + return -EINVAL; + } + } + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* + * no channel list after the number of channels + * argument and spaces + */ + if ('\0' == *inPtr) { + if (0 != j) { + *pNumChannels = j; + return 0; + } else { + return -EINVAL; + } + } + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if ((v < 0) || + (tempInt <= 0) || + (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + return -EINVAL; + } + pChannelList[j] = tempInt; + + hdd_debug("Channel %d added to preferred channel list", + pChannelList[j]); + } + + return 0; +} + +/** + * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 SETROAMSCANCHANNELS command with the format + * + * SETROAMSCANCHANNELS N C1 C2 ... Cn + * + * Where "N" is the ASCII representation of the number of channels and + * C1 thru Cn is the ASCII representation of the channels. For example + * + * SETROAMSCANCHANNELS 4 36 40 44 48 + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels_v1(struct hdd_adapter *adapter, + const char *command) +{ + uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t num_chan = 0; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + mac_handle_t mac_handle; + + ret = hdd_parse_channellist(command, channel_list, &num_chan); + if (ret) { + hdd_err("Failed to parse channel list information"); + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL, + adapter->session_id, num_chan); + + if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + mac_handle = hdd_ctx->mac_handle; + if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) { + hdd_err("List contains invalid channel(s)"); + ret = -EINVAL; + goto exit; + } + + status = sme_change_roam_scan_channel_list(mac_handle, + adapter->session_id, + channel_list, num_chan); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to update channel list information"); + ret = -EINVAL; + goto exit; + } +exit: + return ret; +} + +/** + * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * + * This function parses the v2 SETROAMSCANCHANNELS command with the format + * + * SETROAMSCANCHANNELS [N][C1][C2][Cn] + * + * The command begins with SETROAMSCANCHANNELS followed by a space, but + * what follows the space is an array of u08 parameters. For example + * + * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30] + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels_v2(struct hdd_adapter *adapter, + const char *command) +{ + const uint8_t *value; + uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t channel; + uint8_t num_chan; + int i; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + int ret = 0; + mac_handle_t mac_handle; + + /* array of values begins after "SETROAMSCANCHANNELS " */ + value = command + 20; + + num_chan = *value++; + if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL, + adapter->session_id, num_chan); + + + for (i = 0; i < num_chan; i++) { + channel = *value++; + if (!channel) { + hdd_err("Channels end at index %d, expected %d", + i, num_chan); + ret = -EINVAL; + goto exit; + } + + if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) { + hdd_err("index %d invalid channel %d", + i, channel); + ret = -EINVAL; + goto exit; + } + channel_list[i] = channel; + } + + mac_handle = hdd_ctx->mac_handle; + if (!sme_validate_channel_list(mac_handle, channel_list, num_chan)) { + hdd_err("List contains invalid channel(s)"); + ret = -EINVAL; + goto exit; + } + + status = sme_change_roam_scan_channel_list(mac_handle, + adapter->session_id, + channel_list, num_chan); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to update channel list information"); + ret = -EINVAL; + goto exit; + } +exit: + return ret; +} + +/** + * hdd_parse_set_roam_scan_channels() - parse the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * + * There are two different versions of the SETROAMSCANCHANNELS command. + * Version 1 of the command contains a parameter list that is ASCII + * characters whereas version 2 contains a 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_set_roam_scan_channels(struct hdd_adapter *adapter, const char *command) +{ + const char *cursor; + char ch; + bool v1; + int ret; + + /* start after "SETROAMSCANCHANNELS " */ + cursor = command + 20; + + /* assume we have a version 1 command until proven otherwise */ + v1 = true; + + /* v1 params will only contain ASCII digits and space */ + while ((ch = *cursor++) && v1) { + if (!(isdigit(ch) || isspace(ch))) + v1 = false; + } + + if (v1) + ret = hdd_parse_set_roam_scan_channels_v1(adapter, command); + else + ret = hdd_parse_set_roam_scan_channels_v2(adapter, command); + + return ret; +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_parse_plm_cmd() - HDD Parse Plm command + * @pValue: Pointer to input data + * @pPlmRequest:Pointer to output struct tpSirPlmReq + * + * 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 *pValue, tSirPlmReq *pPlmRequest) +{ + uint8_t *cmdPtr = NULL; + int count, content = 0, ret = 0; + char buf[32]; + + /* move to argument list */ + cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* START/STOP PLM req */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->enable = content; + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* Dialog token of radio meas req containing meas reqIE */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->diag_token = content; + hdd_debug("diag token %d", pPlmRequest->diag_token); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* measurement token of meas req IE */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->meas_token = content; + hdd_debug("meas token %d", pPlmRequest->meas_token); + + hdd_debug("PLM req %s", pPlmRequest->enable ? "START" : "STOP"); + if (pPlmRequest->enable) { + + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* total number of bursts after which STA stops sending */ + ret = sscanf(cmdPtr, "%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; + + pPlmRequest->numBursts = content; + hdd_debug("num burst %d", pPlmRequest->numBursts); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* burst interval in seconds */ + ret = sscanf(cmdPtr, "%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; + + pPlmRequest->burstInt = content; + hdd_debug("burst Int %d", pPlmRequest->burstInt); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */ + ret = sscanf(cmdPtr, "%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; + + pPlmRequest->measDuration = content; + hdd_debug("measDur %d", pPlmRequest->measDuration); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* burst length of PLM bursts */ + ret = sscanf(cmdPtr, "%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; + + pPlmRequest->burstLen = content; + hdd_debug("burstLen %d", pPlmRequest->burstLen); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* desired tx power for transmission of PLM bursts */ + ret = sscanf(cmdPtr, "%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; + + pPlmRequest->desiredTxPwr = content; + hdd_debug("desiredTxPwr %d", + pPlmRequest->desiredTxPwr); + + for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) { + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) + && ('\0' != *cmdPtr)) + cmdPtr++; + + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 16, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->mac_addr.bytes[count] = content; + } + + hdd_debug("MC addr " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes)); + + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* number of channels */ + ret = sscanf(cmdPtr, "%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, WNI_CFG_VALID_CHANNEL_LIST_LEN); + pPlmRequest->plmNumCh = content; + hdd_debug("numch: %d", pPlmRequest->plmNumCh); + + /* Channel numbers */ + for (count = 0; count < pPlmRequest->plmNumCh; count++) { + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) + && ('\0' != *cmdPtr)) + cmdPtr++; + + ret = sscanf(cmdPtr, "%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; + + pPlmRequest->plmChList[count] = content; + hdd_debug(" ch- %d", pPlmRequest->plmChList[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("Obselete 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 (hdd_ctx->config->extWowGotoSuspend) { + 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; + + 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; + params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber | + (hdd_ctx->config->extWowApp2WakeupPinNumber + << 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->session_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 %pM %.8s %u %.16s %u", + params.vdev_id, 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->session_id; + params.tcp_src_port = (params.tcp_src_port != 0) ? + params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort; + params.tcp_dst_port = (params.tcp_dst_port != 0) ? + params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort; + params.keepalive_init = (params.keepalive_init != 0) ? + params.keepalive_init : hdd_ctx->config-> + extWowApp2KAInitPingInterval; + params.keepalive_min = + (params.keepalive_min != 0) ? + params.keepalive_min : + hdd_ctx->config->extWowApp2KAMinPingInterval; + params.keepalive_max = + (params.keepalive_max != 0) ? + params.keepalive_max : + hdd_ctx->config->extWowApp2KAMaxPingInterval; + params.keepalive_inc = + (params.keepalive_inc != 0) ? + params.keepalive_inc : + hdd_ctx->config->extWowApp2KAIncPingInterval; + params.tcp_tx_timeout_val = + (params.tcp_tx_timeout_val != 0) ? + params.tcp_tx_timeout_val : + hdd_ctx->config->extWowApp2TcpTxTimeout; + params.tcp_rx_timeout_val = + (params.tcp_rx_timeout_val != 0) ? + params.tcp_rx_timeout_val : + hdd_ctx->config->extWowApp2TcpRxTimeout; + + hdd_debug("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u", + 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 + * @pValue: Pointer to MAXTXPOWER command + * @pDbm: 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 *pValue, int *pTxPower) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + *pTxPower = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return 0; + + v = kstrtos32(inPtr, 10, &tempInt); + + /* Range checking for passed parameter */ + if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) + return -EINVAL; + + *pTxPower = tempInt; + + hdd_debug("SETMAXTXPOWER: %d", *pTxPower); + + return 0; +} /* End of hdd_parse_setmaxtxpower_command */ + +static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command, + char *extra, uint8_t n, uint8_t *len) +{ + if (!pCfg || !command || !extra || !len) { + hdd_err("argument passed for GETDWELLTIME is incorrect"); + return -EINVAL; + } + + if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", + (int)pCfg->nActiveMaxChnTime); + return 0; + } + if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n", + (int)pCfg->nActiveMinChnTime); + return 0; + } + if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n", + (int)pCfg->nPassiveMaxChnTime); + return 0; + } + if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n", + (int)pCfg->nPassiveMinChnTime); + return 0; + } + if (strncmp(command, "GETDWELLTIME", 12) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME %u\n", + (int)pCfg->nActiveMaxChnTime); + return 0; + } + + return -EINVAL; +} + +static int hdd_set_dwell_time(struct hdd_adapter *adapter, uint8_t *command) +{ + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + struct hdd_config *pCfg; + uint8_t *value = command; + tSmeConfigParams *sme_config; + int val = 0, temp = 0; + int retval = 0; + + pCfg = (WLAN_HDD_GET_CTX(adapter))->config; + if (!pCfg || !mac_handle) { + hdd_err("argument passed for SETDWELLTIME is incorrect"); + return -EINVAL; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("failed to allocate memory for sme_config"); + return -ENOMEM; + } + qdf_mem_zero(sme_config, sizeof(*sme_config)); + sme_get_config_param(mac_handle, sme_config); + + if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) { + if (drv_cmd_validate(command, 23)) { + retval = -EINVAL; + goto free; + } + value = value + 24; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect"); + retval = -EFAULT; + goto free; + } + pCfg->nActiveMaxChnTime = val; + sme_config->csrConfig.nActiveMaxChnTime = val; + sme_update_config(mac_handle, sme_config); + } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) { + if (drv_cmd_validate(command, 23)) { + retval = -EINVAL; + goto free; + } + + value = value + 24; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect"); + retval = -EFAULT; + goto free; + } + pCfg->nActiveMinChnTime = val; + sme_config->csrConfig.nActiveMinChnTime = val; + sme_update_config(mac_handle, sme_config); + } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) { + if (drv_cmd_validate(command, 24)) { + retval = -EINVAL; + goto free; + } + + value = value + 25; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect"); + retval = -EFAULT; + goto free; + } + pCfg->nPassiveMaxChnTime = val; + sme_config->csrConfig.nPassiveMaxChnTime = val; + sme_update_config(mac_handle, sme_config); + } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) { + if (drv_cmd_validate(command, 24)) { + retval = -EINVAL; + goto free; + } + + value = value + 25; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN || + val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect"); + retval = -EFAULT; + goto free; + } + pCfg->nPassiveMinChnTime = val; + sme_config->csrConfig.nPassiveMinChnTime = val; + sme_update_config(mac_handle, sme_config); + } else if (strncmp(command, "SETDWELLTIME", 12) == 0) { + if (drv_cmd_validate(command, 12)) { + retval = -EINVAL; + goto free; + } + + value = value + 13; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME is incorrect"); + retval = -EFAULT; + goto free; + } + pCfg->nActiveMaxChnTime = val; + sme_config->csrConfig.nActiveMaxChnTime = val; + sme_update_config(mac_handle, sme_config); + } else { + retval = -EINVAL; + goto free; + } + +free: + qdf_mem_free(sme_config); + 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) +{ + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + struct hdd_config *p_cfg; + u8 *value = command; + tSmeConfigParams *sme_config; + int val = 0, temp = 0; + int retval = 0; + + p_cfg = (WLAN_HDD_GET_CTX(adapter))->config; + if (!p_cfg || !mac_handle) { + hdd_err("Argument passed for CONCSETDWELLTIME is incorrect"); + return -EINVAL; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("Failed to allocate memory for sme_config"); + return -ENOMEM; + } + + qdf_mem_zero(sme_config, sizeof(*sme_config)); + sme_get_config_param(mac_handle, sme_config); + + if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) { + if (drv_cmd_validate(command, 27)) { + hdd_err("Invalid driver command"); + retval = -EINVAL; + goto sme_config_free; + } + + value = value + 28; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN || + val > CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX) { + hdd_err("Argument passed for CONCSETDWELLTIME ACTIVE MAX is incorrect"); + retval = -EFAULT; + goto sme_config_free; + } + + p_cfg->nActiveMaxChnTimeConc = val; + sme_config->csrConfig.nActiveMaxChnTimeConc = val; + sme_update_config(mac_handle, sme_config); + } else if (strncmp(command, "CONCSETDWELLTIME ACTIVE MIN", 27) == 0) { + if (drv_cmd_validate(command, 27)) { + hdd_err("Invalid driver command"); + retval = -EINVAL; + goto sme_config_free; + } + + value = value + 28; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN || + val > CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX) { + hdd_err("argument passed for CONCSETDWELLTIME ACTIVE MIN is incorrect"); + retval = -EFAULT; + goto sme_config_free; + } + + p_cfg->nActiveMinChnTimeConc = val; + sme_config->csrConfig.nActiveMinChnTimeConc = val; + sme_update_config(mac_handle, sme_config); + } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) { + if (drv_cmd_validate(command, 28)) { + hdd_err("Invalid driver command"); + retval = -EINVAL; + goto sme_config_free; + } + + value = value + 29; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN || + val > CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX) { + hdd_err("Argument passed for CONCSETDWELLTIME PASSIVE MAX is incorrect"); + retval = -EFAULT; + goto sme_config_free; + } + + p_cfg->nPassiveMaxChnTimeConc = val; + sme_config->csrConfig.nPassiveMaxChnTimeConc = val; + sme_update_config(mac_handle, sme_config); + } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MIN", 28) == 0) { + if (drv_cmd_validate(command, 28)) { + hdd_err("Invalid driver command"); + retval = -EINVAL; + goto sme_config_free; + } + + value = value + 29; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN || + val > CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX) { + hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect"); + retval = -EFAULT; + goto sme_config_free; + } + + p_cfg->nPassiveMinChnTimeConc = val; + sme_config->csrConfig.nPassiveMinChnTimeConc = val; + sme_update_config(mac_handle, sme_config); + } else { + retval = -EINVAL; + } + +sme_config_free: + qdf_mem_free(sme_config); + return retval; +} + +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)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return 0; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + /* 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->session_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; +} + +static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo) +{ + int payload_len; + struct sk_buff *skb; + struct nlmsghdr *nlh; + uint8_t *data; + + payload_len = ETH_ALEN; + + if (0 == cesium_pid || cesium_nl_srv_sock == NULL) { + hdd_err("cesium process not registered"); + return; + } + + skb = nlmsg_new(payload_len, GFP_ATOMIC); + if (skb == NULL) { + hdd_err("nlmsg_new() failed for msg size[%d]", + NLMSG_SPACE(payload_len)); + return; + } + + nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST); + + if (NULL == nlh) { + hdd_err("nlmsg_put() failed for msg size[%d]", + NLMSG_SPACE(payload_len)); + + kfree_skb(skb); + return; + } + + data = nlmsg_data(nlh); + memcpy(data, MacAddr, ETH_ALEN); + + if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) { + hdd_err("nlmsg_unicast() failed for msg size[%d]", + NLMSG_SPACE(payload_len)); + } +} + + +/** + * hdd_ParseuserParams - return a pointer to the next argument + * @pValue: Input argument string + * @ppArg: Output pointer to the next argument + * + * This function parses argument stream and finds the pointer + * to the next argument + * + * Return: 0 if the next argument found; -EINVAL otherwise + */ +static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg) +{ + uint8_t *pVal; + + pVal = strnchr(pValue, strlen(pValue), ' '); + + if (NULL == pVal) /* no argument remains */ + return -EINVAL; + else if (SPACE_ASCII_VALUE != *pVal)/* no space after the current arg */ + return -EINVAL; + + pVal++; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) + pVal++; + + /* no argument followed by spaces */ + if ('\0' == *pVal) + return -EINVAL; + + *ppArg = pVal; + + return 0; +} + +/** + * hdd_parse_ibsstx_fail_event_params - Parse params + * for SETIBSSTXFAILEVENT + * @pValue: Input ibss tx fail event argument + * @tx_fail_count: (Output parameter) Tx fail counter + * @pid: (Output parameter) PID + * + * Return: 0 if the parsing succeeds; -EINVAL otherwise + */ +static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue, + uint8_t *tx_fail_count, + uint16_t *pid) +{ + uint8_t *param = NULL; + int ret; + + ret = hdd_parse_user_params(pValue, ¶m); + + if (0 == ret && NULL != param) { + if (1 != sscanf(param, "%hhu", tx_fail_count)) { + ret = -EINVAL; + goto done; + } + } else { + goto done; + } + + if (0 == *tx_fail_count) { + *pid = 0; + goto done; + } + + pValue = param; + pValue++; + + ret = hdd_parse_user_params(pValue, ¶m); + + if (0 == ret) { + if (1 != sscanf(param, "%hu", pid)) { + ret = -EINVAL; + goto done; + } + } else { + goto done; + } + +done: + return ret; +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_parse_ese_beacon_req() - Parse ese beacon request + * @pValue: Pointer to data + * @pEseBcnReq: 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(uint8_t *pValue, + tCsrEseBeaconReq *pEseBcnReq) +{ + uint8_t *inPtr = pValue; + uint8_t input = 0; + uint32_t tempInt = 0; + int j = 0, i = 0, v = 0; + char buf[32]; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + if (NULL == inPtr) /* no argument after the command */ + return -EINVAL; + else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return -EINVAL; + + /* Getting the first argument ie Number of IE fields */ + v = sscanf(inPtr, "%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); + pEseBcnReq->numBcnReqIe = input; + + hdd_debug("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe); + + for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) { + for (i = 0; i < 4; i++) { + /* + * inPtr pointing to the beginning of 1st space + * after number of ie fields + */ + inPtr = strpbrk(inPtr, " "); + /* no ie data after the number of ie fields argument */ + if (NULL == inPtr) + return -EINVAL; + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *inPtr) + && ('\0' != *inPtr)) + inPtr++; + + /* + * no ie data after the number of ie fields + * argument and spaces + */ + if ('\0' == *inPtr) + return -EINVAL; + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtou32(buf, 10, &tempInt); + if (v < 0) + return -EINVAL; + + switch (i) { + case 0: /* Measurement token */ + if (!tempInt) { + hdd_err("Invalid Measurement Token: %u", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].measurementToken = + tempInt; + break; + + case 1: /* Channel number */ + if (!tempInt || + (tempInt > + WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + hdd_err("Invalid Channel Number: %u", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].channel = tempInt; + break; + + case 2: /* Scan mode */ + if ((tempInt < eSIR_PASSIVE_SCAN) + || (tempInt > eSIR_BEACON_TABLE)) { + hdd_err("Invalid Scan Mode: %u Expected{0|1|2}", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].scanMode = tempInt; + break; + + case 3: /* Measurement duration */ + if ((!tempInt + && (pEseBcnReq->bcnReq[j].scanMode != + eSIR_BEACON_TABLE)) || + (pEseBcnReq->bcnReq[j].scanMode == + eSIR_BEACON_TABLE)) { + hdd_err("Invalid Measurement Duration: %u", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].measurementDuration = + tempInt; + break; + } + } + } + + for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) { + hdd_debug("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u", + j, + pEseBcnReq->bcnReq[j].measurementToken, + pEseBcnReq->bcnReq[j].channel, + pEseBcnReq->bcnReq[j].scanMode, + pEseBcnReq->bcnReq[j].measurementDuration); + } + + return 0; +} + +/** + * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE + * @pValue: Pointer to input data + * @pCckmIe: Pointer to output cckm Ie + * @pCckmIeLen: 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 *pValue, uint8_t **pCckmIe, + uint8_t *pCckmIeLen) +{ + uint8_t *inPtr = pValue; + uint8_t *dataEnd; + int j = 0; + int i = 0; + uint8_t tempByte = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *inPtr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return -EINVAL; + + /* find the length of data */ + dataEnd = inPtr; + while (('\0' != *dataEnd)) { + dataEnd++; + ++(*pCckmIeLen); + } + if (*pCckmIeLen <= 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 + */ + *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2); + if (NULL == *pCckmIe) { + hdd_err("qdf_mem_malloc failed"); + 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 < *pCckmIeLen; j += 2) { + tempByte = (hex_to_bin(inPtr[j]) << 4) | + (hex_to_bin(inPtr[j + 1])); + (*pCckmIe)[i++] = tempByte; + } + *pCckmIeLen = i; + return 0; +} +#endif /* FEATURE_WLAN_ESE */ + +int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int targetRate) +{ + tSirRateUpdateInd rateUpdate = {0}; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_config *pConfig; + + if (hdd_ctx == NULL) { + hdd_err("HDD context is null"); + return -EINVAL; + } + if ((QDF_IBSS_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode) && + (QDF_STA_MODE != adapter->device_mode)) { + hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode"); + return -EINVAL; + } + pConfig = hdd_ctx->config; + rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdate.dev_mode = adapter->device_mode; + rateUpdate.mcastDataRate24GHz = targetRate; + rateUpdate.mcastDataRate24GHzTxFlag = 1; + rateUpdate.mcastDataRate5GHz = targetRate; + rateUpdate.bcastDataRate = -1; + qdf_copy_macaddr(&rateUpdate.bssid, &adapter->mac_addr); + hdd_debug("MC Target rate %d, mac = %pM, dev_mode %s(%d)", + rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes, + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rateUpdate); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SETMCRATE failed"); + return -EFAULT; + } + return 0; +} + +static int drv_cmd_p2p_dev_addr(struct hdd_adapter *adapter, + 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, + adapter->session_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 + * @adapter: Adapter on which the command was received + * @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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_set_p2p_noa(adapter->dev, command); +} + +/** + * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command + * @adapter: Adapter on which the command was received + * @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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_set_p2p_opps(adapter->dev, command); +} + +static int drv_cmd_set_band(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int err; + uint8_t band; + + /* + * 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; + } + + return hdd_reg_set_band(adapter->dev, band); +} + +static int drv_cmd_set_wmmps(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_wmmps_helper(adapter, command); +} + +static inline int drv_cmd_country(struct hdd_adapter *adapter, + 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); +} + +/** + * drv_cmd_get_country() - Helper function to get current county code + * @adapter: pointer to adapter on which request is received + * @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 hdd_adapter *adapter, + 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 hdd_adapter *adapter, + 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 lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT; + 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_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX); + ret = -EINVAL; + goto exit; + } + + lookUpThreshold = abs(rssi); + + if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN) || + (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) { + hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)", + lookUpThreshold, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX); + ret = -EINVAL; + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL, + adapter->session_id, lookUpThreshold); + + hdd_debug("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d", + lookUpThreshold); + + hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold; + status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle, + adapter->session_id, + lookUpThreshold); + 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t lookUpThreshold = + sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->mac_handle); + int rssi = (-1) * lookUpThreshold; + char extra[32]; + uint8_t len = 0; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL, + adapter->session_id, lookUpThreshold); + + 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 hdd_adapter *adapter, + 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 roamScanPeriod = 0; + uint16_t neighborEmptyScanRefreshPeriod = + CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT; + + /* 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, &roamScanPeriod); + 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_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000), + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000)); + ret = -EINVAL; + goto exit; + } + + if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000)) + || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) { + hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)", + roamScanPeriod, + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000), + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000)); + ret = -EINVAL; + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL, + adapter->session_id, roamScanPeriod); + neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000; + + hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d", + roamScanPeriod); + + hdd_ctx->config->nEmptyScanRefreshPeriod = + neighborEmptyScanRefreshPeriod; + sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle, + adapter->session_id, + neighborEmptyScanRefreshPeriod); + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_period(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t nEmptyScanRefreshPeriod = + sme_get_empty_scan_refresh_period(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL, + adapter->session_id, + nEmptyScanRefreshPeriod); + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANPERIOD", + (nEmptyScanRefreshPeriod / 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 hdd_adapter *adapter, + 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 roamScanRefreshPeriod = 0; + uint16_t neighborScanRefreshPeriod = + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT; + + /* 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, &roamScanRefreshPeriod); + 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_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000); + ret = -EINVAL; + goto exit; + } + + if ((roamScanRefreshPeriod < + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000)) || + (roamScanRefreshPeriod > + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) { + hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)", + roamScanRefreshPeriod, + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN + / 1000), + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX + / 1000)); + ret = -EINVAL; + goto exit; + } + neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000; + + hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d", + roamScanRefreshPeriod); + + hdd_ctx->config->nNeighborResultsRefreshPeriod = + neighborScanRefreshPeriod; + sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle, + adapter->session_id, + neighborScanRefreshPeriod); + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_refresh_period(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t value = + sme_get_neighbor_scan_refresh_period(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len; + + 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 hdd_adapter *adapter, + 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 roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT; + + /* Move pointer to ahead of SETROAMMODE */ + value = value + SIZE_OF_SETROAMMODE + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamMode); + 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_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) || + (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) { + hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)", + roamMode, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set Roam Mode = %d", + roamMode); + /* + * 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 (CFG_LFR_FEATURE_ENABLED_MIN == roamMode) + roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */ + else + roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */ + + hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode; + mac_handle = hdd_ctx->mac_handle; + if (roamMode) { + hdd_ctx->config->isRoamOffloadScanEnabled = roamMode; + sme_update_roam_scan_offload_enabled(mac_handle, roamMode); + sme_update_is_fast_roam_ini_feature_enabled(mac_handle, + adapter->session_id, + roamMode); + } else { + sme_update_is_fast_roam_ini_feature_enabled(mac_handle, + adapter->session_id, + roamMode); + hdd_ctx->config->isRoamOffloadScanEnabled = roamMode; + sme_update_roam_scan_offload_enabled(mac_handle, roamMode); + } + + +exit: + return ret; +} + +static int drv_cmd_get_roam_mode(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len; + + /* + * roamMode value shall be inverted because the sementics is different. + */ + if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode) + roamMode = CFG_LFR_FEATURE_ENABLED_MAX; + else + roamMode = CFG_LFR_FEATURE_ENABLED_MIN; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode); + 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 hdd_adapter *adapter, + 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 roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT; + + /* Move pointer to ahead of SETROAMDELTA */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamRssiDiff); + 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_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX); + ret = -EINVAL; + goto exit; + } + + if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) || + (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) { + hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)", + roamRssiDiff, + CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set roam rssi diff = %d", + roamRssiDiff); + + hdd_ctx->config->RoamRssiDiff = roamRssiDiff; + sme_update_roam_rssi_diff(hdd_ctx->mac_handle, + adapter->session_id, + roamRssiDiff); + +exit: + return ret; +} + +static int drv_cmd_get_roam_delta(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t roamRssiDiff = + sme_get_roam_rssi_diff(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMDELTA_IOCTL, + adapter->session_id, roamRssiDiff); + + len = scnprintf(extra, sizeof(extra), "%s %d", + command, roamRssiDiff); + 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + int 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, + adapter->session_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; +} + +static int drv_cmd_set_roam_scan_channels(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_parse_set_roam_scan_channels(adapter, command); +} + +static int drv_cmd_get_roam_scan_channels(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t numChannels = 0; + uint8_t j = 0; + char extra[128] = { 0 }; + int len; + + if (QDF_STATUS_SUCCESS != + sme_get_roam_scan_channel_list(hdd_ctx->mac_handle, + ChannelList, + &numChannels, + adapter->session_id)) { + hdd_err("failed to get roam scan channel list"); + ret = -EFAULT; + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL, + adapter->session_id, numChannels); + + /* + * output channel list is of the format + * [Number of roam scan channels][Channel1][Channel2]... + * copy the number of channels in the 0th index + */ + len = scnprintf(extra, sizeof(extra), "%s %d", command, + numChannels); + for (j = 0; (j < numChannels) && len <= sizeof(extra); j++) + len += scnprintf(extra + len, sizeof(extra) - len, + " %d", ChannelList[j]); + + 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_ccx_mode(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + bool eseMode = sme_get_is_ese_feature_enabled(mac_handle); + 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 (eseMode && + (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) && + sme_get_is_ft_feature_enabled(mac_handle)) { + 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", eseMode); + 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 hdd_adapter *adapter, + 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; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + 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 && + sme_get_is_ese_feature_enabled(mac_handle) && + sme_get_is_ft_feature_enabled(mac_handle)) { + 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETFASTROAM", lfrMode); + 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->mac_handle); + 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 hdd_adapter *adapter, + 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 minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT; + + /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &minTime); + 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_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) || + (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) { + hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)", + minTime, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL, + adapter->session_id, minTime); + hdd_debug("Received Command to change channel min time = %d", + minTime); + + hdd_ctx->config->nNeighborScanMinChanTime = minTime; + sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle, + minTime, + adapter->session_id); + +exit: + return ret; +} + +static int drv_cmd_send_action_frame(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_parse_sendactionframe(adapter, command, + priv_data->total_len); +} + +static int drv_cmd_get_roam_scan_channel_min_time(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->mac_handle, + adapter->session_id); + char extra[32]; + uint8_t len = 0; + + /* 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, + adapter->session_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 hdd_adapter *adapter, + 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 maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT; + + /* Move pointer to ahead of SETSCANCHANNELTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &maxTime); + 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_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) || + (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) { + hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)", + maxTime, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change channel max time = %d", + maxTime); + + hdd_ctx->config->nNeighborScanMaxChanTime = maxTime; + sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle, + adapter->session_id, + maxTime); + +exit: + return ret; +} + +static int drv_cmd_get_scan_channel_time(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->mac_handle, + adapter->session_id); + char extra[32]; + uint8_t len = 0; + + /* 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 hdd_adapter *adapter, + 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_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT; + + /* 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_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX); + ret = -EINVAL; + goto exit; + } + + if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) || + (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) { + hdd_err("scan home time value %d is out of range (Min: %d Max: %d)", + val, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change scan home time = %d", + val); + + hdd_ctx->config->nNeighborScanPeriod = val; + sme_set_neighbor_scan_period(hdd_ctx->mac_handle, + adapter->session_id, val); + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_time(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->mac_handle, + adapter->session_id); + char extra[32]; + uint8_t len = 0; + + /* 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 hdd_adapter *adapter, + 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_ROAM_INTRA_BAND_DEFAULT; + + /* 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_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX); + ret = -EINVAL; + goto exit; + } + + if ((val < CFG_ROAM_INTRA_BAND_MIN) || + (val > CFG_ROAM_INTRA_BAND_MAX)) { + hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)", + val, + CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX); + ret = -EINVAL; + goto exit; + } + hdd_debug("Received Command to change intra band = %d", + val); + + hdd_ctx->config->nRoamIntraBand = val; + sme_set_roam_intra_band(hdd_ctx->mac_handle, val); + policy_mgr_set_pcl_for_existing_combo( + hdd_ctx->psoc, + PM_STA_MODE); + +exit: + return ret; +} + +static int drv_cmd_get_roam_intra_band(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_roam_intra_band(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + /* 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 hdd_adapter *adapter, + 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_ROAM_SCAN_N_PROBES_DEFAULT; + + /* 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_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX); + ret = -EINVAL; + goto exit; + } + + if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) || + (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) { + hdd_err("NProbes value %d is out of range (Min: %d Max: %d)", + nProbes, + CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set nProbes = %d", + nProbes); + + hdd_ctx->config->nProbes = nProbes; + sme_update_roam_scan_n_probes(hdd_ctx->mac_handle, + adapter->session_id, nProbes); + +exit: + return ret; +} + +static int drv_cmd_get_scan_n_probes(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + 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 hdd_adapter *adapter, + 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 homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT; + + /* 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, &homeAwayTime); + 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_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) || + (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) { + hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)", + homeAwayTime, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set scan away time = %d", + homeAwayTime); + + if (hdd_ctx->config->nRoamScanHomeAwayTime != + homeAwayTime) { + hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime; + sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle, + adapter->session_id, + homeAwayTime, + true); + } + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_away_time(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_parse_reassoc(adapter, command, priv_data->total_len); +} + +static int drv_cmd_set_wes_mode(struct hdd_adapter *adapter, + 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 wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT; + + /* Move pointer to ahead of SETWESMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &wesMode); + 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_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) || + (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) { + hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)", + wesMode, + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set WES Mode rssi diff = %d", + wesMode); + + hdd_ctx->config->isWESModeEnabled = wesMode; + sme_update_wes_mode(hdd_ctx->mac_handle, wesMode, adapter->session_id); + +exit: + return ret; +} + +static int drv_cmd_get_wes_mode(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool wesMode = sme_get_wes_mode(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode); + 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 hdd_adapter *adapter, + 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 nOpportunisticThresholdDiff = + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT; + + /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff); + 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", + nOpportunisticThresholdDiff); + + sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle, + adapter->session_id, + nOpportunisticThresholdDiff); + +exit: + return ret; +} + +static int drv_cmd_get_opportunistic_rssi_diff(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + int8_t val = sme_get_roam_opportunistic_scan_threshold_diff(mac_handle); + char extra[32]; + uint8_t len = 0; + + 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 hdd_adapter *adapter, + 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 nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT; + + /* Move pointer to ahead of SETROAMRESCANRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nRoamRescanRssiDiff); + 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", + nRoamRescanRssiDiff); + + sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle, + adapter->session_id, + nRoamRescanRssiDiff); + +exit: + return ret; +} + +static int drv_cmd_get_roam_rescan_rssi_diff(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + 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 hdd_adapter *adapter, + 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 lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT; + + /* Move pointer to ahead of SETFASTROAM */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &lfrMode); + 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_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) || + (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) { + hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)", + lfrMode, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change lfr mode = %d", + lfrMode); + + hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode; + sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle, + adapter->session_id, + lfrMode); + +exit: + return ret; +} + +static int drv_cmd_set_fast_transition(struct hdd_adapter *adapter, + 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_FAST_TRANSITION_ENABLED_NAME_DEFAULT; + + /* 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_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) || + (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) { + hdd_err("ft mode value %d is out of range (Min: %d Max: %d)", + ft, + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change ft mode = %d", ft); + + hdd_ctx->config->isFastTransitionEnabled = ft; + sme_update_fast_transition_enabled(hdd_ctx->mac_handle, ft); + +exit: + return ret; +} + +static int drv_cmd_fast_reassoc(struct hdd_adapter *adapter, + 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 channel = 0; + tSirMacAddr targetApBssid; + uint32_t roamId = INVALID_ROAM_ID; + tCsrRoamModifyProfileFields modProfileFields; + tCsrHandoffRequest handoffInfo; + struct hdd_station_ctx *sta_ctx; + mac_handle_t mac_handle; + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, no need to proceed with reassoc */ + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + hdd_warn("Not associated!"); + ret = -EINVAL; + goto exit; + } + + ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid, + &channel); + if (ret) { + hdd_err("Failed to parse reassoc command data"); + goto exit; + } + + mac_handle = hdd_ctx->mac_handle; + + /* + * if the target bssid is same as currently associated AP, + * issue reassoc to same AP + */ + if (!qdf_mem_cmp(targetApBssid, + sta_ctx->conn_info.bssId.bytes, + QDF_MAC_ADDR_SIZE)) { + hdd_warn("Reassoc BSSID is same as currently associated AP bssid"); + if (roaming_offload_enabled(hdd_ctx)) { + hdd_wma_send_fastreassoc_cmd(adapter, + targetApBssid, + sta_ctx->conn_info.operationChannel); + } else { + sme_get_modify_profile_fields(mac_handle, + adapter->session_id, + &modProfileFields); + sme_roam_reassoc(mac_handle, adapter->session_id, + NULL, modProfileFields, &roamId, 1); + } + return 0; + } + + /* Check channel number is a valid channel number */ + if (channel && (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel))) { + hdd_err("Invalid Channel [%d]", channel); + return -EINVAL; + } + + if (roaming_offload_enabled(hdd_ctx)) { + hdd_wma_send_fastreassoc_cmd(adapter, + targetApBssid, (int)channel); + goto exit; + } + /* Proceed with reassoc */ + handoffInfo.channel = channel; + handoffInfo.src = FASTREASSOC; + qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid, + sizeof(tSirMacAddr)); + sme_handoff_request(mac_handle, adapter->session_id, + &handoffInfo); +exit: + return ret; +} + +static int drv_cmd_set_roam_scan_control(struct hdd_adapter *adapter, + 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 roamScanControl = 0; + + /* Move pointer to ahead of SETROAMSCANCONTROL */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanControl); + 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 scan control = %d", + roamScanControl); + + if (0 != roamScanControl) { + ret = 0; /* return success but ignore param value "true" */ + goto exit; + } + + sme_set_roam_scan_control(hdd_ctx->mac_handle, + adapter->session_id, + roamScanControl); + +exit: + return ret; +} + +static int drv_cmd_set_okc_mode(struct hdd_adapter *adapter, + 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; + mac_handle_t mac_handle; + + 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) + */ + mac_handle = hdd_ctx->mac_handle; + if (sme_get_is_ese_feature_enabled(mac_handle) && + pmkid_modes.fw_okc && + sme_get_is_ft_feature_enabled(mac_handle)) { + 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 */ + okc_mode = hdd_ctx->config->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) + hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC; + else + hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC; + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_control(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + command, roamScanControl); + 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_bt_coex_mode(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + char *bcMode; + + bcMode = command + 11; + if ('1' == *bcMode) { + hdd_debug("BTCOEXMODE %d", *bcMode); + hdd_ctx->bt_coex_mode_set = true; + ret = wlan_hdd_scan_abort(adapter); + if (ret < 0) { + hdd_err("Failed to abort existing scan status: %d", + ret); + } + } else if ('2' == *bcMode) { + hdd_debug("BTCOEXMODE %d", *bcMode); + hdd_ctx->bt_coex_mode_set = false; + } + + return ret; +} + +static int drv_cmd_scan_active(struct hdd_adapter *adapter, + 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 hdd_adapter *adapter, + 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + struct hdd_config *pCfg = + (WLAN_HDD_GET_CTX(adapter))->config; + char extra[32]; + uint8_t len = 0; + + memset(extra, 0, sizeof(extra)); + ret = hdd_get_dwell_time(pCfg, 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_set_dwell_time(adapter, command); +} + +static int drv_cmd_conc_set_dwell_time(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + u8 *command, + u8 command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_conc_set_dwell_time(adapter, command); +} + +static int drv_cmd_miracast(struct hdd_adapter *adapter, + 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 filterType = 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, &filterType); + 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; + } + if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL) + || (filterType > + WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) { + hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink"); + ret = -EINVAL; + goto exit; + } + /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */ + hdd_ctx->miracast_value = filterType; + + ret_status = sme_set_miracast(hdd_ctx->mac_handle, filterType); + if (QDF_STATUS_SUCCESS != ret_status) { + hdd_err("Failed to set miracast"); + return -EBUSY; + } + ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc, + filterType ? 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(adapter, filterType); + +exit: + return ret; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie, + int32_t *oui_length, int32_t limit) +{ + uint8_t len; + uint8_t data; + + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) { + command++; + limit--; + } + + len = 2; + + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) { + sscanf(command, "%02x", (unsigned int *)&data); + ie[len++] = data; + command += 2; + limit -= 2; + } + + *oui_length = len - 2; + + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) { + command++; + limit--; + } + + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) { + sscanf(command, "%02x", (unsigned int *)&data); + ie[len++] = data; + command += 2; + limit -= 2; + } + + ie[0] = IE_EID_VENDOR; + ie[1] = len - 2; + + return len; +} + +/** + * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command + * @adapter: Pointer to adapter + * @hdd_ctx: Pointer to HDD context + * @command: Pointer to command string + * @command_len : Command length + * @priv_data : Pointer to priv data + * + * Return: + * int status code + */ +static int drv_cmd_set_ibss_beacon_oui_data(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int i = 0; + int status; + int ret = 0; + uint8_t *ibss_ie; + int32_t oui_length = 0; + uint32_t ibss_ie_length; + uint8_t *value = command; + tSirModifyIE ibssModifyIE; + struct csr_roam_profile *roam_profile; + mac_handle_t mac_handle; + + if (QDF_IBSS_MODE != adapter->device_mode) { + hdd_debug("Device_mode %s(%d) not IBSS", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return ret; + } + + hdd_debug("received command %s", ((char *)value)); + + /* validate argument of command */ + if (strlen(value) <= command_len) { + hdd_err("No arguments in command length %zu", + strlen(value)); + ret = -EFAULT; + goto exit; + } + + /* moving to arguments of commands */ + value = value + command_len; + command_len = strlen(value); + + /* oui_data can't be less than 3 bytes */ + if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { + hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d", + command_len); + ret = -EFAULT; + goto exit; + } + + ibss_ie = qdf_mem_malloc(command_len); + if (!ibss_ie) { + hdd_err("Could not allocate memory for command length %d", + command_len); + ret = -ENOMEM; + goto exit; + } + + ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie, + &oui_length, + command_len); + if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { + hdd_err("Could not parse command %s return length %d", + value, ibss_ie_length); + ret = -EFAULT; + qdf_mem_free(ibss_ie); + goto exit; + } + + roam_profile = hdd_roam_profile(adapter); + + qdf_copy_macaddr(&ibssModifyIE.bssid, + roam_profile->BSSIDs.bssid); + + ibssModifyIE.smeSessionId = adapter->session_id; + ibssModifyIE.notify = true; + ibssModifyIE.ieID = IE_EID_VENDOR; + ibssModifyIE.ieIDLen = ibss_ie_length; + ibssModifyIE.ieBufferlength = ibss_ie_length; + ibssModifyIE.pIEBuffer = ibss_ie; + ibssModifyIE.oui_length = oui_length; + + hdd_warn("ibss_ie length %d oui_length %d ibss_ie:", + ibss_ie_length, oui_length); + while (i < ibssModifyIE.ieBufferlength) + hdd_warn("0x%x", ibss_ie[i++]); + + /* Probe Bcn modification */ + mac_handle = hdd_ctx->mac_handle; + sme_modify_add_ie(mac_handle, &ibssModifyIE, eUPDATE_IE_PROBE_BCN); + + /* Populating probe resp frame */ + sme_modify_add_ie(mac_handle, &ibssModifyIE, eUPDATE_IE_PROBE_RESP); + + qdf_mem_free(ibss_ie); + + status = sme_send_cesium_enable_ind(mac_handle, + adapter->session_id); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Could not send cesium enable indication %d", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_rmc_enable(struct hdd_adapter *adapter, + 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 ucRmcEnable = 0; + int status; + mac_handle_t mac_handle; + + if ((QDF_IBSS_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) { + hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcenable_command(value, &ucRmcEnable); + if (status) { + hdd_err("Invalid SETRMCENABLE command"); + ret = -EINVAL; + goto exit; + } + + hdd_debug("ucRmcEnable %d", ucRmcEnable); + mac_handle = hdd_ctx->mac_handle; + + if (true == ucRmcEnable) { + status = sme_enable_rmc(mac_handle, adapter->session_id); + } else if (false == ucRmcEnable) { + status = sme_disable_rmc(mac_handle, adapter->session_id); + } else { + hdd_err("Invalid SETRMCENABLE command %d", ucRmcEnable); + ret = -EINVAL; + goto exit; + } + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SETRMC %d failed status %d", ucRmcEnable, status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_rmc_action_period(struct hdd_adapter *adapter, + 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 uActionPeriod = 0; + int status; + mac_handle_t mac_handle; + + if ((QDF_IBSS_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) { + hdd_err("Received SETRMC cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod); + if (status) { + hdd_err("Invalid SETRMCACTIONPERIOD command"); + ret = -EINVAL; + goto exit; + } + + hdd_debug("uActionPeriod %d", uActionPeriod); + mac_handle = hdd_ctx->mac_handle; + + if (sme_cfg_set_int(mac_handle, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + uActionPeriod)) { + hdd_err("Could not set SETRMCACTIONPERIOD %d", + uActionPeriod); + ret = -EINVAL; + goto exit; + } + + status = sme_send_rmc_action_period(mac_handle, + adapter->session_id); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Could not send cesium enable indication %d", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_ibss_peer_info_all(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + int status = QDF_STATUS_SUCCESS; + struct hdd_station_ctx *sta_ctx = NULL; + char *extra = NULL; + int idx = 0; + int length = 0; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t numOfBytestoPrint = 0; + + if (QDF_IBSS_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_debug("Received GETIBSSPEERINFOALL Command"); + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info_all(adapter); + if (QDF_STATUS_SUCCESS == status) { + size_t user_size = qdf_min(WLAN_MAX_BUF_SIZE, + priv_data->total_len); + + /* + * The variable extra needed to be allocated on the heap since + * amount of memory required to copy the data for 32 devices + * exceeds the size of 1024 bytes of default stack size. On + * 64 bit devices, the default max stack size of 2048 bytes + */ + extra = qdf_mem_malloc(user_size); + + if (NULL == extra) { + hdd_err("memory allocation failed"); + ret = -ENOMEM; + goto exit; + } + + /* Copy number of stations */ + length = scnprintf(extra, user_size, "%d ", + sta_ctx->ibss_peer_info.numPeers); + numOfBytestoPrint = length; + for (idx = 0; idx < sta_ctx->ibss_peer_info.numPeers; + idx++) { + int8_t rssi; + uint32_t tx_rate; + + qdf_mem_copy(mac_addr, + sta_ctx->ibss_peer_info.peerInfoParams[idx]. + mac_addr, sizeof(mac_addr)); + + tx_rate = + sta_ctx->ibss_peer_info.peerInfoParams[idx]. + txRate; + /* + * Only lower 3 bytes are rate info. Mask of the MSByte + */ + tx_rate &= 0x00FFFFFF; + + rssi = sta_ctx->ibss_peer_info.peerInfoParams[idx]. + rssi; + + length += scnprintf(extra + length, + user_size - length, + "%02x:%02x:%02x:%02x:%02x:%02x %d %d ", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5], + tx_rate, rssi); + /* + * cdf_trace_msg has limitation of 512 bytes for the + * print buffer. Hence printing the data in two chunks. + * The first chunk will have the data for 16 devices + * and the second chunk will have the rest. + */ + if (idx < NUM_OF_STA_DATA_TO_PRINT) + numOfBytestoPrint = length; + } + + /* + * Copy the data back into buffer, if the data to copy is + * more than 512 bytes than we will split the data and do + * it in two shots + */ + if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) { + hdd_err("Copy into user data buffer failed"); + ret = -EFAULT; + goto mem_free; + } + + /* This overwrites the last space, which we already copied */ + extra[numOfBytestoPrint - 1] = '\0'; + hdd_debug("%s", extra); + + if (length > numOfBytestoPrint) { + if (copy_to_user + (priv_data->buf + numOfBytestoPrint, + extra + numOfBytestoPrint, + length - numOfBytestoPrint + 1)) { + hdd_err("Copy into user data buffer failed"); + ret = -EFAULT; + goto mem_free; + } + hdd_debug("%s", &extra[numOfBytestoPrint]); + } + } else { + /* Command failed, log error */ + hdd_err("GETIBSSPEERINFOALL command failed with status code %d", + status); + ret = -EINVAL; + goto exit; + } + ret = 0; + +mem_free: + qdf_mem_free(extra); +exit: + return ret; +} + +/* Peer Info command */ +static int drv_cmd_get_ibss_peer_info(struct hdd_adapter *adapter, + 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_STATUS status; + struct hdd_station_ctx *sta_ctx = NULL; + char extra[128] = { 0 }; + uint32_t length = 0; + uint8_t staIdx = 0; + struct qdf_mac_addr peerMacAddr; + + if (QDF_IBSS_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_debug("Received GETIBSSPEERINFO Command"); + + /* if there are no peers, no need to continue with the command */ + if (eConnectionState_IbssConnected != + sta_ctx->conn_info.connState) { + hdd_err("No IBSS Peers coalesced"); + ret = -EINVAL; + goto exit; + } + + /* Parse the incoming command buffer */ + status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Invalid GETIBSSPEERINFO command"); + ret = -EINVAL; + goto exit; + } + + /* Get station index for the peer mac address and sanitize it */ + hdd_get_peer_sta_id(sta_ctx, &peerMacAddr, &staIdx); + + if (staIdx > MAX_PEERS) { + hdd_err("Invalid StaIdx %d returned", staIdx); + ret = -EINVAL; + goto exit; + } + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx); + if (QDF_STATUS_SUCCESS == status) { + uint32_t txRate = + sta_ctx->ibss_peer_info.peerInfoParams[0].txRate; + /* Only lower 3 bytes are rate info. Mask of the MSByte */ + txRate &= 0x00FFFFFF; + + length = scnprintf(extra, sizeof(extra), "%d %d", + (int)txRate, + (int)sta_ctx->ibss_peer_info. + peerInfoParams[0].rssi); + length = QDF_MIN(priv_data->total_len, length + 1); + + /* Copy the data back into buffer */ + if (copy_to_user(priv_data->buf, &extra, length)) { + hdd_err("copy data to user buffer failed GETIBSSPEERINFO command"); + ret = -EFAULT; + goto exit; + } + } else { + /* Command failed, log error */ + hdd_err("GETIBSSPEERINFO command failed with status code %d", + status); + ret = -EINVAL; + goto exit; + } + + /* Success ! */ + hdd_debug("%s", extra); + ret = 0; + +exit: + return ret; +} + +static int drv_cmd_set_rmc_tx_rate(struct hdd_adapter *adapter, + 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 uRate = 0; + enum tx_rate_info txFlags = 0; + tSirRateUpdateInd rateUpdateParams = {0}; + int status; + struct hdd_config *pConfig = hdd_ctx->config; + + if ((QDF_IBSS_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) { + hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags); + if (status) { + hdd_err("Invalid SETRMCTXRATE command"); + ret = -EINVAL; + goto exit; + } + hdd_debug("uRate %d", uRate); + /* -1 implies ignore this param */ + rateUpdateParams.ucastDataRate = -1; + + /* + * Fill the user specifieed RMC rate param + * and the derived tx flags. + */ + rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdateParams.reliableMcastDataRate = uRate; + rateUpdateParams.reliableMcastDataRateTxFlag = txFlags; + rateUpdateParams.dev_mode = adapter->device_mode; + rateUpdateParams.bcastDataRate = -1; + memcpy(rateUpdateParams.bssid.bytes, + adapter->mac_addr.bytes, + sizeof(rateUpdateParams.bssid)); + status = sme_send_rate_update_ind(hdd_ctx->mac_handle, + &rateUpdateParams); + +exit: + return ret; +} + +static int drv_cmd_set_ibss_tx_fail_event(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + char *value; + uint8_t tx_fail_count = 0; + uint16_t pid = 0; + mac_handle_t mac_handle; + + value = command; + + ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid); + + if (0 != ret) { + hdd_err("Failed to parse SETIBSSTXFAILEVENT arguments"); + goto exit; + } + + hdd_debug("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid); + mac_handle = hdd_ctx->mac_handle; + + if (0 == tx_fail_count) { + /* Disable TX Fail Indication */ + if (QDF_STATUS_SUCCESS == + sme_tx_fail_monitor_start_stop_ind(mac_handle, + tx_fail_count, + NULL)) { + cesium_pid = 0; + } else { + hdd_err("failed to disable TX Fail Event"); + ret = -EINVAL; + } + } else { + if (QDF_STATUS_SUCCESS == + sme_tx_fail_monitor_start_stop_ind(mac_handle, + tx_fail_count, + (void *)hdd_tx_fail_ind_callback)) { + cesium_pid = pid; + hdd_debug("Registered Cesium pid %u", + cesium_pid); + } else { + hdd_err("Failed to enable TX Fail Monitoring"); + ret = -EINVAL; + } + } + +exit: + return ret; +} + +#ifdef FEATURE_WLAN_ESE +static int drv_cmd_set_ccx_roam_scan_channels(struct hdd_adapter *adapter, + 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 ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t numChannels = 0; + QDF_STATUS status; + mac_handle_t mac_handle; + + ret = hdd_parse_channellist(value, ChannelList, &numChannels); + if (ret) { + hdd_err("Failed to parse channel list information"); + goto exit; + } + if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + mac_handle = hdd_ctx->mac_handle; + if (!sme_validate_channel_list(mac_handle, ChannelList, numChannels)) { + hdd_err("List contains invalid channel(s)"); + ret = -EINVAL; + goto exit; + } + + status = sme_set_ese_roam_scan_channel_list(mac_handle, + adapter->session_id, + ChannelList, + numChannels); + 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 hdd_adapter *adapter, + 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_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)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, return error */ + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + 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 hdd_adapter *adapter, + 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 *cckmIe = NULL; + uint8_t cckmIeLen = 0; + + ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen); + if (ret) { + hdd_err("Failed to parse cckm ie data"); + goto exit; + } + + if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) { + hdd_err("CCKM Ie input length is more than max[%d]", + DOT11F_IE_RSN_MAX_LEN); + if (NULL != cckmIe) { + qdf_mem_free(cckmIe); + cckmIe = NULL; + } + ret = -EINVAL; + goto exit; + } + + sme_set_cckm_ie(hdd_ctx->mac_handle, adapter->session_id, + cckmIe, cckmIeLen); + if (NULL != cckmIe) { + qdf_mem_free(cckmIe); + cckmIe = NULL; + } + +exit: + return ret; +} + +static int drv_cmd_ccx_beacon_req(struct hdd_adapter *adapter, + 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 eseBcnReq = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + ret = hdd_parse_ese_beacon_req(value, &eseBcnReq); + if (ret) { + hdd_err("Failed to parse ese beacon req"); + goto exit; + } + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_debug("Not associated"); + + if (!eseBcnReq.numBcnReqIe) + return -EINVAL; + + hdd_indicate_ese_bcn_report_no_results(adapter, + eseBcnReq.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, + adapter->session_id, + &eseBcnReq); + + 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 + * @adapter: Pointer to the 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 hdd_adapter *adapter, + 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_STATUS status = QDF_STATUS_SUCCESS; + tpSirPlmReq pPlmRequest = NULL; + + pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq)); + if (NULL == pPlmRequest) { + ret = -ENOMEM; + goto exit; + } + + status = hdd_parse_plm_cmd(value, pPlmRequest); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(pPlmRequest); + pPlmRequest = NULL; + ret = -EINVAL; + goto exit; + } + pPlmRequest->sessionId = adapter->session_id; + + status = sme_set_plm_request(hdd_ctx->mac_handle, pPlmRequest); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(pPlmRequest); + pPlmRequest = NULL; + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +/** + * drv_cmd_set_ccx_mode() - Set ESE mode + * @adapter: Pointer to the 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 hdd_adapter *adapter, + 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 eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT; + 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 (sme_get_is_ese_feature_enabled(mac_handle) && + pmkid_modes.fw_okc && + sme_get_is_ft_feature_enabled(mac_handle)) { + 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, &eseMode); + 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_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) || + (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) { + hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)", + eseMode, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + hdd_debug("Received Command to change ese mode = %d", eseMode); + + hdd_ctx->config->isEseIniFeatureEnabled = eseMode; + sme_update_is_ese_feature_enabled(mac_handle, + adapter->session_id, + eseMode); + +exit: + return ret; +} +#endif /* FEATURE_WLAN_ESE */ + +static int drv_cmd_set_mc_rate(struct hdd_adapter *adapter, + 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; + int 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(adapter, target_rate); + return ret; +} + +static int drv_cmd_max_tx_power(struct hdd_adapter *adapter, + 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; + + ret = hdd_parse_setmaxtxpower_command(value, &tx_power); + if (ret) { + hdd_err("Invalid MAXTXPOWER command"); + return ret; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + /* Assign correct self MAC address */ + qdf_copy_macaddr(&bssid, + &adapter->mac_addr); + qdf_copy_macaddr(&selfmac, + &adapter->mac_addr); + + hdd_debug("Device mode %d max tx power %d selfMac: " + MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR, + adapter->device_mode, tx_power, + MAC_ADDR_ARRAY(selfmac.bytes), + MAC_ADDR_ARRAY(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; + goto exit; + } + hdd_debug("Set max tx power success"); + } + +exit: + return ret; +} + +static int drv_cmd_set_dfs_scan_mode(struct hdd_adapter *adapter, + 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 dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT; + + /* Move pointer to ahead of SETDFSSCANMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &dfsScanMode); + 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_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX); + ret = -EINVAL; + goto exit; + } + + if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) || + (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) { + hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)", + dfsScanMode, + CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set DFS Scan Mode = %d", + dfsScanMode); + + /* 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, + dfsScanMode != CFG_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; + } + + hdd_ctx->config->allowDFSChannelRoam = dfsScanMode; + sme_update_dfs_scan_mode(hdd_ctx->mac_handle, adapter->session_id, + dfsScanMode); + +exit: + return ret; +} + +static int drv_cmd_get_dfs_scan_mode(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode); + 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 hdd_adapter *adapter, + 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(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 hdd_adapter *adapter, + 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(adapter, + adapter->session_id, + set_value); +} + +static int drv_cmd_set_app1_params(struct hdd_adapter *adapter, + 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(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 hdd_adapter *adapter, + 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(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 + * @adapter: Pointer to the 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 hdd_adapter *adapter, + 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, adapter, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode + * @adapter: Pointer to the 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 hdd_adapter *adapter, + 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, adapter, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel() - set tdls off channel number + * @adapter: Pointer to the 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 hdd_adapter *adapter, + 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; + + if (wlan_reg_is_dfs_ch(hdd_ctx->pdev, set_value)) { + hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel", + set_value); + return -EINVAL; + } + + hdd_debug("Tdls offchannel num: %d", set_value); + + ret = hdd_set_tdls_offchannel(hdd_ctx, adapter, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_scan() - set tdls scan type + * @adapter: Pointer to the 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 hdd_adapter *adapter, + 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 hdd_adapter *adapter, + 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(adapter, &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; +} + +static int drv_cmd_get_linkspeed(struct hdd_adapter *adapter, + 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(adapter, &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; +} + +/** + * 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 (!hdd_ctx->config->fEnableMCAddrList) { + 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_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + + + filter = qdf_mem_malloc(sizeof(*filter)); + if (NULL == filter) { + hdd_err("Could not allocate Memory"); + 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 =" + MAC_ADDRESS_STR, + action ? "setting" : "clearing", + MAC_ADDR_ARRAY(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->session_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_warn("Unsupported RXFILTER type %d", type); + break; + } + + return ret; +} + +/** + * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler + * @adapter: Pointer to network 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 hdd_adapter *adapter, + 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, adapter, false); +} + +/** + * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler + * @adapter: Pointer to network 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 hdd_adapter *adapter, + 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, adapter, true); +} + +/** + * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE + * command + * @value: Pointer to SETANTENNAMODE command + * @mode: Pointer to antenna mode + * @reason: Pointer to reason for set antenna mode + * + * This function parses the SETANTENNAMODE command passed in the format + * SETANTENNAMODEmode + * + * Return: 0 for success non-zero for failure + */ +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 (NULL == 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 contex + * + * Return: true if supported chain mask 2x2 else false + */ +static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx) +{ + /* + * 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 + */ + return (hdd_ctx->config->enable2x2 == 0x01) ? true : false; +} + +/** + * hdd_is_supported_chain_mask_1x1() - Verify if the supported + * chain mask is 1x1 + * @hdd_ctx: Pointer to hdd contex + * + * Return: true if supported chain mask 1x1 else false + */ +static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx) +{ + /* + * 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 + */ + return (!hdd_ctx->config->enable2x2) ? true : false; +} + +QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode) +{ + QDF_STATUS status; + uint8_t smps_mode; + uint8_t smps_enable; + mac_handle_t mac_handle; + + /* Update SME SMPS config */ + if (HDD_ANTENNA_MODE_1X1 == mode) { + smps_enable = true; + smps_mode = HDD_SMPS_MODE_STATIC; + } else { + smps_enable = false; + smps_mode = HDD_SMPS_MODE_DISABLED; + } + + hdd_debug("Update SME SMPS enable: %d mode: %d", + smps_enable, smps_mode); + mac_handle = hdd_ctx->mac_handle; + status = sme_update_mimo_power_save(mac_handle, smps_enable, + smps_mode, false); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Update SMPS config failed enable: %d mode: %d status: %d", + smps_enable, smps_mode, status); + return QDF_STATUS_E_FAILURE; + } + + 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("obselete request"); + return; + } + + /* Signal the completion of set dual mac config */ + osif_request_complete(request); + osif_request_put(request); +} + +static QDF_STATUS +hdd_populate_vdev_chains(struct 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 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; +} + +static int +hdd_set_dynamic_antenna_mode(struct hdd_adapter *adapter, + uint8_t num_rx_chains, + uint8_t num_tx_chains) +{ + enum nss_chains_band_info band; + struct mlme_nss_chains user_cfg; + QDF_STATUS status; + mac_handle_t mac_handle; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("NULL MAC handle"); + return -EINVAL; + } + + if (!hdd_is_vdev_in_conn_state(adapter)) { + hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command", + adapter->session_id); + 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_rx_chains, + num_tx_chains, band, + adapter->vdev); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + } + status = sme_nss_chains_update(mac_handle, + &user_cfg, + adapter->session_id); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return 0; +} + +int hdd_set_antenna_mode(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, int mode) +{ + + 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 = WLAN_WAIT_TIME_ANTENNA_MODE_REQ, + }; + + 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(adapter, + params.num_rx_chains, + params.num_tx_chains); + + if (hdd_ctx->current_antenna_mode == mode) { + hdd_err("System already in the requested mode"); + return 0; + } + + 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(hdd_ctx, adapter, 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 + * @adapter: Pointer to network 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 hdd_adapter *adapter, + 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(adapter, hdd_ctx, 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 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 + * @adapter: Pointer to 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 hdd_adapter *adapter, + 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; + + 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, + adapter->vdev); + 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 hdd_adapter *adapter, + 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\"", + 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->session_id, 0); + + hdd_warn("%s: Unsupported driver command \"%s\"", + adapter->dev->name, command); + + return -ENOTSUPP; +} + +/** + * drv_cmd_set_fcc_channel() - Handle fcc constraint request + * @adapter: HDD adapter + * @hdd_ctx: HDD context + * @command: command ptr, SET_FCC_CHANNEL 0/-1 is the command + * @command_len: command len + * @priv_data: private data + * + * Return: status + */ +static int drv_cmd_set_fcc_channel(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + QDF_STATUS status; + int8_t input_value; + bool fcc_constraint; + int err; + + /* + * 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. 0 means reduce power as per fcc constraint + * and -1 means remove constraint. + */ + + err = kstrtos8(command + command_len + 1, 10, &input_value); + if (err) { + hdd_err("error %d parsing userspace fcc parameter", err); + return err; + } + + fcc_constraint = input_value ? false : true; + hdd_debug("input_value = %d && fcc_constraint = %u", + input_value, fcc_constraint); + + status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev, fcc_constraint); + + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to %s tx power for channels 12/13", + fcc_constraint ? "restore" : "reduce"); + + return qdf_status_to_os_return(status); +} + +/** + * 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 (NULL == 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 + * @adapter: 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 hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + 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; + } + + 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)) { + hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw); + return -EINVAL; + } + + 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, adapter->session_id, + CSA_REASON_USER_INITIATED); + status = hdd_softap_set_channel_change(dev, chan_number, width, true); + 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) { + hdd_err("QDF_MALLOC_ERR"); + 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_err("QDF_MALLOC_ERR"); + hdd_ctx->original_channels->num_channels = 0; + qdf_mem_free(hdd_ctx->original_channels); + hdd_ctx->original_channels = NULL; + return -ENOMEM; + } + return 0; +} + +/** + * 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 received in the command. + * command should be a string having format + * SET_DISABLE_CHANNEL_LIST + * . + * If the command comes multiple times than this function will compare + * the channels received in the command with the channles cached in the + * first command, if the channel list matches with the cached channles, + * 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; + uint32_t parsed_channels[MAX_CHANNEL]; + bool is_command_repeated = false; + + if (NULL == hdd_ctx) { + hdd_err("HDD Context is NULL"); + return -EINVAL; + } + + param = strnchr(ptr, strlen(ptr), ' '); + /*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 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 > MAX_CHANNEL) { + hdd_err("Invalid Number of channel received"); + return -EINVAL; + } + + hdd_debug("Number of channel to disable are: %d", temp_int); + + if (!temp_int) { + if (!wlan_hdd_restore_channels(hdd_ctx, false)) { + /* + * Free the cache channels only when the command is + * received with num channels as 0 + */ + wlan_hdd_free_cache_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; + 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 (NULL == 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 (!IS_CHANNEL_VALID(temp_int)) { + hdd_err("Invalid channel number received"); + ret = -EINVAL; + goto parse_failed; + } + + hdd_debug("channel[%d] = %d", j, temp_int); + parsed_channels[j] = temp_int; + } + + /*extra arguments check*/ + param = strpbrk(param, " "); + if (NULL != 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 otherewise return failure. + */ + if (!is_command_repeated) { + for (j = 0; j < num_channels; j++) + hdd_ctx->original_channels-> + channel_info[j].channel_num = + parsed_channels[j]; + + /* Cache the channel list in regulatory also */ + ucfg_reg_cache_channel_state(hdd_ctx->pdev, parsed_channels, + 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].channel_num == + parsed_channels[j]) + break; + if (j == num_channels) { + ret = -EINVAL; + goto parse_failed; + } + } + ret = 0; + } +mem_alloc_failed: + + 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) { + wlan_hdd_disable_channels(hdd_ctx); + hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx); + } + + hdd_exit(); + + return ret; + +parse_failed: + if (!is_command_repeated) + wlan_hdd_free_cache_channels(hdd_ctx); + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + hdd_exit(); + + return ret; +} + +static int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_parse_disable_chan_cmd(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", ch_list[i].channel_num); + } + } + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + return len; +} + +static int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter, + 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 int drv_cmd_set_disable_chan_list(struct hdd_adapter *adapter, + 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 int drv_cmd_get_disable_chan_list(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + 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_dummy, false}, + {"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}, + {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels, true}, + {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels, 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}, + {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control, true}, + {"SETOKCMODE", drv_cmd_set_okc_mode, true}, + {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control, false}, + {"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}, + {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data, true}, + {"SETRMCENABLE", drv_cmd_set_rmc_enable, true}, + {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period, true}, + {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all, false}, + {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info, true}, + {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate, true}, + {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event, true}, +#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}, + {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true}, + {"RXFILTER-ADD", drv_cmd_rx_filter_add, true}, + {"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}, + {"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}, +}; + +/** + * hdd_drv_cmd_process() - chooses and runs the proper + * handler based on the input command + * @adapter: Pointer to the hdd 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 hdd_adapter *adapter, + uint8_t *cmd, + struct hdd_priv_data *priv_data) +{ + 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 (!adapter || !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(adapter, 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 + * @adapter: Pointer to the 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 hdd_adapter *adapter, + struct hdd_priv_data *priv_data) +{ + 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) { + hdd_err("failed to allocate memory"); + 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(adapter, command, priv_data); + +exit: + if (command) + qdf_mem_free(command); + hdd_exit(); + return ret; +} + +#ifdef CONFIG_COMPAT +static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr) +{ + 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, ifr->ifr_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(adapter, &priv_data); +exit: + return ret; +} +#else /* CONFIG_COMPAT */ +static int hdd_driver_compat_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr) +{ + /* will never be invoked */ + return 0; +} +#endif /* CONFIG_COMPAT */ + +static int hdd_driver_ioctl(struct hdd_adapter *adapter, struct ifreq *ifr) +{ + 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, ifr->ifr_data, sizeof(priv_data))) + ret = -EFAULT; + else + ret = hdd_driver_command(adapter, &priv_data); + + return ret; +} + +/** + * __hdd_ioctl() - ioctl handler for wlan network interfaces + * @dev: device upon which the ioctl was received + * @ifr: ioctl request information + * @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, struct ifreq *ifr, 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 ((!ifr) || (!ifr->ifr_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, ifr); + 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, ifr); + else + ret = hdd_driver_ioctl(adapter, ifr); + break; + default: + hdd_warn("unknown ioctl %d", cmd); + ret = -EINVAL; + break; + } +exit: + hdd_exit(); + return ret; +} + +/** + * 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ioctl(dev, ifr, cmd); + cds_ssr_unprotect(__func__); + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..27708e0f4e242d1a39525c701fc537ada492ef7c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2012-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. + */ + +#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; + +int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +int wlan_hdd_set_mc_rate(struct hdd_adapter *adapter, int targetRate); + +/** + * 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 + * @adapter: Pointer to network adapter + * @hdd_ctx: Pointer to hdd context + * @mode: new anteena mode + */ +int hdd_set_antenna_mode(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, int mode); + +#endif /* end #if !defined(WLAN_HDD_IOCTL_H) */ + diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c new file mode 100644 index 0000000000000000000000000000000000000000..0c31bbe3c4ebe4ecfc04b526b3bc16daae9627f5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c @@ -0,0 +1,477 @@ +/* + * 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: wlan_hdd_ipa.c + * + * WLAN HDD and ipa interface implementation + */ + +/* Include Files */ +#include +#include +#include "wlan_policy_mgr_api.h" +#include "wlan_ipa_ucfg_api.h" +#include +#include +#include + +void hdd_ipa_set_tx_flow_info(void) +{ + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_hostapd_state *hostapd_state; + struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INIT; + struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INIT; + struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INIT; + uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0; + const char *p2pMode = "DEV"; + struct hdd_context *hdd_ctx; + struct cds_context *cds_ctx; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + uint8_t targetChannel = 0; + uint8_t preAdapterChannel = 0; + uint8_t channel24; + uint8_t channel5; + struct hdd_adapter *preAdapterContext = NULL; + struct hdd_adapter *adapter2_4 = NULL; + struct hdd_adapter *adapter5 = NULL; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + struct wlan_objmgr_psoc *psoc; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + hdd_err("Invalid CDS Context"); + return; + } + + psoc = hdd_ctx->psoc; + + hdd_for_each_adapter(hdd_ctx, adapter) { + switch (adapter->device_mode) { + case QDF_STA_MODE: + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) { + staChannel = + sta_ctx->conn_info.operationChannel; + qdf_copy_macaddr(&staBssid, + &sta_ctx->conn_info.bssId); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = staChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case QDF_P2P_CLIENT_MODE: + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) { + p2pChannel = + sta_ctx->conn_info.operationChannel; + qdf_copy_macaddr(&p2pBssid, + &sta_ctx->conn_info.bssId); + p2pMode = "CLI"; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = p2pChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case QDF_P2P_GO_MODE: + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (hostapd_state->bss_state == BSS_START + && hostapd_state->qdf_status == + QDF_STATUS_SUCCESS) { + p2pChannel = hdd_ap_ctx->operating_channel; + qdf_copy_macaddr(&p2pBssid, + &adapter->mac_addr); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = p2pChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + p2pMode = "GO"; + break; + case QDF_SAP_MODE: + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (hostapd_state->bss_state == BSS_START + && hostapd_state->qdf_status == + QDF_STATUS_SUCCESS) { + apChannel = hdd_ap_ctx->operating_channel; + qdf_copy_macaddr(&apBssid, + &adapter->mac_addr); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = apChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case QDF_IBSS_MODE: + default: + break; + } +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + if (targetChannel) { + /* + * This is first adapter detected as active + * set as default for none concurrency case + */ + if (!preAdapterChannel) { + /* 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() && + (QDF_SAP_MODE == adapter->device_mode)) { + adapter->tx_flow_low_watermark = + hdd_ctx->config->TxFlowLowWaterMark + + WLAN_TFC_IPAUC_TX_DESC_RESERVE; + } else { + adapter->tx_flow_low_watermark = + hdd_ctx->config-> + TxFlowLowWaterMark; + } + adapter->tx_flow_high_watermark_offset = + hdd_ctx->config->TxFlowHighWaterMarkOffset; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter->session_id, + hdd_ctx->config->TxFlowMaxQueueDepth); + hdd_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d", + adapter->device_mode, + targetChannel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter->tx_flow_high_watermark_offset, + hdd_ctx->config->TxFlowMaxQueueDepth); + preAdapterChannel = targetChannel; + preAdapterContext = 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 (preAdapterChannel == targetChannel) { + /* Current adapter */ + adapter->tx_flow_low_watermark = 0; + adapter-> + tx_flow_high_watermark_offset = 0; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter->session_id, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter->device_mode), + adapter->device_mode, + targetChannel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + + if (!preAdapterContext) { + hdd_err("SCC: Previous adapter context NULL"); + continue; + } + + /* Previous adapter */ + preAdapterContext-> + tx_flow_low_watermark = 0; + preAdapterContext-> + tx_flow_high_watermark_offset = 0; + cdp_fc_ll_set_tx_pause_q_depth(soc, + preAdapterContext->session_id, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + hdd_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + preAdapterContext->device_mode + ), + preAdapterContext->device_mode, + targetChannel, + preAdapterContext-> + tx_flow_low_watermark, + preAdapterContext-> + tx_flow_low_watermark + + preAdapterContext-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + } + /* + * MCC, each adapter will have dedicated + * resource + */ + else { + /* current channel is 2.4 */ + if (targetChannel <= + WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) { + channel24 = targetChannel; + channel5 = preAdapterChannel; + adapter2_4 = adapter; + adapter5 = preAdapterContext; + } else { + /* Current channel is 5 */ + channel24 = preAdapterChannel; + channel5 = targetChannel; + adapter2_4 = preAdapterContext; + adapter5 = adapter; + } + + if (!adapter5) { + hdd_err("MCC: 5GHz adapter context NULL"); + continue; + } + adapter5->tx_flow_low_watermark = + hdd_ctx->config-> + TxHbwFlowLowWaterMark; + adapter5-> + tx_flow_high_watermark_offset = + hdd_ctx->config-> + TxHbwFlowHighWaterMarkOffset; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter5->session_id, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter5->device_mode), + adapter5->device_mode, + channel5, + adapter5->tx_flow_low_watermark, + adapter5-> + tx_flow_low_watermark + + adapter5-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + + if (!adapter2_4) { + hdd_err("MCC: 2.4GHz adapter context NULL"); + continue; + } + adapter2_4->tx_flow_low_watermark = + hdd_ctx->config-> + TxLbwFlowLowWaterMark; + adapter2_4-> + tx_flow_high_watermark_offset = + hdd_ctx->config-> + TxLbwFlowHighWaterMarkOffset; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter2_4->session_id, + hdd_ctx->config-> + TxLbwFlowMaxQueueDepth); + hdd_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + 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_high_watermark_offset, + hdd_ctx->config-> + TxLbwFlowMaxQueueDepth); + + } + } + } + targetChannel = 0; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } +} + +#if defined(QCA_CONFIG_SMP) && defined(PF_WAKE_UP_IDLE) +/** + * 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 + * + * 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 +static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb) +{ + return netif_rx_ni(skb); +} +#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 = netif_rx_ni(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 = netif_rx_ni(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); + int result; + unsigned int cpu_index; + uint8_t staid; + uint32_t enabled; + + if (hdd_validate_adapter(adapter)) { + kfree_skb(nbuf); + return; + } + + if (cds_is_driver_unloading()) { + kfree_skb(nbuf); + return; + } + + if (adapter->device_mode == QDF_SAP_MODE) { + /* Send DHCP Indication to FW */ + struct qdf_mac_addr *src_mac = + (struct qdf_mac_addr *)(nbuf->data + + QDF_NBUF_SRC_MAC_OFFSET); + if (QDF_STATUS_SUCCESS == + hdd_softap_get_sta_id(adapter, src_mac, &staid)) + hdd_inspect_dhcp_packet(adapter, staid, nbuf, 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; + + cpu_index = wlan_hdd_get_cpu(); + + ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index]; + + /* + * Update STA RX exception packet stats. + * For SAP as part of IPA HW stats are updated. + */ + if (adapter->device_mode == QDF_STA_MODE) { + ++adapter->stats.rx_packets; + adapter->stats.rx_bytes += nbuf->len; + } + + qdf_dp_trace_set_track(nbuf, QDF_RX); + + hdd_event_eapol_log(nbuf, QDF_RX); + qdf_dp_trace_log_pkt(adapter->session_id, + nbuf, QDF_RX, QDF_TRACE_DEFAULT_PDEV_ID); + 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)); + + result = hdd_ipa_aggregated_rx_ind(nbuf); + if (result == NET_RX_SUCCESS) + ++adapter->hdd_stats.tx_rx_stats.rx_delivered[cpu_index]; + else + ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index]; + + /* + * 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) { + hdd_err("HDD context is NULL"); + return; + } + + ucfg_ipa_set_mcc_mode(hdd_ctx->pdev, mcc_mode); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c new file mode 100644 index 0000000000000000000000000000000000000000..6c3b2ed8abc0c3cc83768a9325f37913a009bd33 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c @@ -0,0 +1,408 @@ +/* + * 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: 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_id: Channel ID + * + * 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_id) +{ + 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_id, + ®_info_1, ®_info_2); + if (status != QDF_STATUS_SUCCESS) + return; + + chan_info->mhz = cds_chan_to_freq(chan_id); + 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(hdd_ctx->pdev, + chan_id)) + WMI_SET_CHANNEL_FLAG(chan_info, + WMI_CHAN_FLAG_DFS); + hdd_update_channel_bw_info(hdd_ctx, chan_id, + 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 + * @adapter: Adapter whose status is to being packaged + * @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 hdd_adapter *adapter, + struct hdd_station_ctx *sta_ctx, + uint8_t is_on, uint8_t is_connected) +{ + struct hdd_context *hdd_ctx = NULL; + uint8_t buflen = WLAN_SVC_COUNTRY_CODE_LEN; + int i; + uint32_t chan_id; + struct svc_channel_info *chan_info; + + if (!data) { + hdd_err("invalid data pointer"); + return -EINVAL; + } + if (!adapter) { + 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_session_id(adapter->session_id)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx->lpss_support && hdd_ctx->config->enable_lpass_support) + data->lpss_support = 1; + else + data->lpss_support = 0; + data->numChannels = WLAN_SVC_MAX_NUM_CHAN; + sme_get_cfg_valid_channels(data->channel_list, + &data->numChannels); + + for (i = 0; i < data->numChannels; i++) { + chan_info = &data->channel_info[i]; + chan_id = data->channel_list[i]; + chan_info->chan_id = chan_id; + wlan_hdd_get_channel_info(hdd_ctx, chan_info, chan_id); + } + + sme_get_country_code(hdd_ctx->mac_handle, data->country_code, &buflen); + data->is_on = is_on; + data->vdev_id = adapter->session_id; + data->vdev_mode = adapter->device_mode; + if (sta_ctx) { + data->is_connected = is_connected; + data->rssi = adapter->rssi; + data->freq = + cds_chan_to_freq(sta_ctx->conn_info.operationChannel); + 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 + * @adapter: Adapter whose status is to be sent to lpass + * @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 hdd_adapter *adapter, + 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, adapter, 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 + * @hdd_ctx: The global HDD context + * @adapter: Adapter that supports scanning. + * + * This function indicates adapter that supports scanning to lpass. + * + * Return: none + */ +static void wlan_hdd_send_scan_intf_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + if (!hdd_ctx) { + hdd_err("NULL pointer for hdd_ctx"); + return; + } + + if (!adapter) { + hdd_err("Adapter is Null"); + return; + } + + wlan_hdd_send_status_pkg(adapter, 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) +{ + cds_config->is_lpass_enabled = hdd_ctx->config->enable_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) +{ + pmo_config->lpass_enable = hdd_ctx->config->enable_lpass_support; +} + +/* + * hdd_lpass_notify_connect() - Notify LPASS of interface connect + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_notify_connect(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + + /* only send once per connection */ + if (adapter->rssi_send) + return; + + /* don't send if driver is unloading */ + if (cds_is_driver_unloading()) + return; + + adapter->rssi_send = true; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + wlan_hdd_send_status_pkg(adapter, sta_ctx, 1, 1); +} + +/* + * hdd_lpass_notify_disconnect() - Notify LPASS of interface disconnect + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_notify_disconnect(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + + adapter->rssi_send = false; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + wlan_hdd_send_status_pkg(adapter, sta_ctx, 1, 0); +} + +void hdd_lpass_notify_mode_change(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + + if (!adapter || adapter->device_mode != QDF_STA_MODE) + return; + + hdd_debug("Sending Lpass mode change notification"); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + wlan_hdd_send_scan_intf_info(hdd_ctx, adapter); +} + +/* + * 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 hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + hdd_enter(); + + if (!adapter || adapter->device_mode != QDF_STA_MODE) + return; + + hdd_debug("Sending Start Lpass notification"); + + wlan_hdd_send_scan_intf_info(hdd_ctx, adapter); + + hdd_exit(); +} + +void hdd_lpass_notify_stop(struct hdd_context *hdd_ctx) +{ + hdd_debug("Sending Lpass stop notifcation"); + 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) +{ + return hdd_ctx->config->enable_lpass_support; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h new file mode 100644 index 0000000000000000000000000000000000000000..489624251c24942992fe5a8e9d272cfadfc7f2c0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h @@ -0,0 +1,186 @@ +/* + * 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. + */ + +#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 + * @adapter: The adapter that connected + * + * This function is used to notify the LPASS feature that an adapter + * has connected. + * + * Return: none + */ +void hdd_lpass_notify_connect(struct hdd_adapter *adapter); + +/** + * hdd_lpass_notify_disconnect() - Notify LPASS of interface disconnect + * @adapter: The adapter that connected + * + * This function is used to notify the LPASS feature that an adapter + * has disconnected. + * + * Return: none + */ +void hdd_lpass_notify_disconnect(struct hdd_adapter *adapter); + +/** + * hdd_lpass_notify_mode_change() - Notify LPASS of interface mode change + * @adapter: The adapter whose mode was changed + * + * 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 hdd_adapter *adapter); + +/** + * hdd_lpass_notify_start() - Notify LPASS of driver start + * @hdd_ctx: The global HDD context + * @adapter: adapter for which notification is send + * + * This function is used to notify the LPASS feature that the wlan + * driver has (re-)started. + * + * Return: none + */ +void hdd_lpass_notify_start(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * 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 hdd_adapter *adapter) +{ +} +static inline void hdd_lpass_notify_disconnect(struct hdd_adapter *adapter) +{ +} +static inline void hdd_lpass_notify_mode_change(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_lpass_notify_start(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ +} + +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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lro.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lro.c new file mode 100644 index 0000000000000000000000000000000000000000..30f84e3334b8f55cb858d58c83b8af2210ea6828 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lro.c @@ -0,0 +1,158 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_lro.c + * + * WLAN HDD LRO interface implementation + */ + +#include +#include +#include +#include +#include +#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) +static qdf_lro_ctx_t wlan_hdd_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 wlan_hdd_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 == NULL) { + hdd_err("hif_hdl is NULL"); + return NULL; + } + + return hif_get_lro_info(QDF_NBUF_CB_RX_CTX_ID(skb), hif_hdl); +} +#endif + +/** + * hdd_lro_rx() - LRO receive function + * @adapter: HDD adapter + * @skb: 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 hdd_lro_rx(struct hdd_adapter *adapter, struct sk_buff *skb) +{ + qdf_lro_ctx_t ctx; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct qdf_lro_info info; + struct net_lro_desc *lro_desc = NULL; + + if ((adapter->dev->features & NETIF_F_LRO) != NETIF_F_LRO) + return QDF_STATUS_E_NOSUPPORT; + + ctx = wlan_hdd_get_lro_ctx(skb); + if (!ctx) { + hdd_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 = adapter->dev; + if (qdf_lro_get_info(ctx, skb, &info, (void **)&lro_desc)) { + struct net_lro_info hdd_lro_info; + + hdd_lro_info.valid_fields = LRO_VALID_FIELDS; + + hdd_lro_info.lro_desc = lro_desc; + hdd_lro_info.lro_eligible = 1; + hdd_lro_info.tcp_ack_num = QDF_NBUF_CB_RX_TCP_ACK_NUM(skb); + hdd_lro_info.tcp_data_csum = + csum_unfold(htons(QDF_NBUF_CB_RX_TCP_CHKSUM(skb))); + hdd_lro_info.tcp_seq_num = QDF_NBUF_CB_RX_TCP_SEQ_NUM(skb); + hdd_lro_info.tcp_win = QDF_NBUF_CB_RX_TCP_WIN(skb); + + lro_receive_skb_ext(ctx->lro_mgr, skb, (void *)adapter, + &hdd_lro_info); + + if (!hdd_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; +} + +/** + * hdd_lro_display_stats() - display LRO statistics + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_lro_display_stats(struct hdd_context *hdd_ctx) +{ + hdd_debug("LRO stats is broken, will fix it"); +} + +QDF_STATUS +hdd_lro_set_reset(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, + uint8_t enable_flag) +{ + if ((hdd_ctx->ol_enable != CFG_LRO_ENABLED) || + (adapter->device_mode != QDF_STA_MODE)) { + hdd_debug("LRO is already Disabled"); + return 0; + } + + if (enable_flag) { + qdf_atomic_set(&hdd_ctx->vendor_disable_lro_flag, 0); + adapter->dev->features |= NETIF_F_LRO; + } else { + /* Disable LRO, Enable tcpdelack*/ + qdf_atomic_set(&hdd_ctx->vendor_disable_lro_flag, 1); + adapter->dev->features &= ~NETIF_F_LRO; + hdd_debug("LRO Disabled"); + + if (hdd_ctx->config->enable_tcp_delack) { + struct wlan_rx_tp_data rx_tp_data; + + hdd_debug("Enable TCP delack as LRO is disabled"); + rx_tp_data.rx_tp_flags = TCP_DEL_ACK_IND; + rx_tp_data.level = GET_CUR_RX_LVL(hdd_ctx); + wlan_hdd_update_tcp_rx_param(hdd_ctx, &rx_tp_data); + hdd_ctx->en_tcp_delack_no_lro = 1; + } + } + return 0; +} + + diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c new file mode 100644 index 0000000000000000000000000000000000000000..3bc1eaf5f9740730cc1290c08b807a3032d1511e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c @@ -0,0 +1,15611 @@ +/* + * 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: wlan_hdd_main.c + * + * WLAN Host Device Driver implementation + * + */ + +/* Include Files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#ifdef CONFIG_LEAK_DETECTION +#include "qdf_debug_domain.h" +#endif +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include +#include +#include +#include "cdp_txrx_flow_ctrl_legacy.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 +#ifdef MSM_PLATFORM +#include +#endif +#include +#include +#include +#include "cfg_api.h" +#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 "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 "wlan_reg_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 "wlan_mlme_ucfg_api.h" +#include + +#ifdef CNSS_GENL +#include +#endif +#include "wlan_reg_ucfg_api.h" +#include "wlan_ocb_ucfg_api.h" +#include +#include + +#ifdef MODULE +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#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 + +int wlan_start_ret_val; +static DECLARE_COMPLETION(wlan_start_comp); +static unsigned int dev_num = 1; +static struct cdev wlan_hdd_state_cdev; +static struct class *class; +static dev_t device; +#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 +#endif + +#define HDD_OPS_INACTIVITY_TIMEOUT (120000) +#define MAX_OPS_NAME_STRING_SIZE 20 +#define RATE_LIMIT_ERROR_LOG (256) + +static qdf_timer_t hdd_drv_ops_inactivity_timer; +static struct task_struct *hdd_drv_ops_task; +static char drv_ops_string[MAX_OPS_NAME_STRING_SIZE]; + +/* 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, +}; + +static char *country_code; +static int enable_11d = -1; +static int enable_dfs_chan_scan = -1; +static bool is_mode_change_psoc_idle_shutdown; + +/* + * spinlock for synchronizing asynchronous request/response + * (full description of use in wlan_hdd_main.h) + */ +DEFINE_SPINLOCK(hdd_context_lock); +DEFINE_MUTEX(hdd_init_deinit_lock); + +#define WLAN_NLINK_CESIUM 30 + +static qdf_wake_lock_t wlan_wake_lock; + +#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 + +/* max peer can be tdls peers + self peer + bss peer */ +#define HDD_MAX_VDEV_PEER_COUNT (HDD_MAX_NUM_TDLS_STA + 2) +#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 & 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_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_TRACE_LEVEL_ALL}, + [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_MLME] = {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_TARGET] = {QDF_TRACE_LEVEL_ALL}, +}; + +int limit_off_chan_tbl[HDD_MAX_AC][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 }, +}; + +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 + +void hdd_start_complete(int ret) +{ + wlan_start_ret_val = ret; + + complete(&wlan_start_comp); +} + +/** + * hdd_set_rps_cpu_mask - set RPS CPU mask for interfaces + * @hdd_ctx: pointer to struct hdd_context + * + * Return: none + */ +static void hdd_set_rps_cpu_mask(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) + hdd_send_rps_ind(adapter); +} + +/** + * 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; + + if (!hdd_ctx) { + hdd_err("hdd ctx is NULL"); + return; + } + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + 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 "; " BUILD_TAG; +#else +uint8_t g_wlan_driver_version[] = QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR; +#endif + +/** + * hdd_device_mode_to_string() - return string conversion of device mode + * @device_mode: device mode + * + * This utility function helps log string conversion of device mode. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_device_mode_to_string(uint8_t device_mode) +{ + switch (device_mode) { + CASE_RETURN_STRING(QDF_STA_MODE); + CASE_RETURN_STRING(QDF_SAP_MODE); + CASE_RETURN_STRING(QDF_P2P_CLIENT_MODE); + CASE_RETURN_STRING(QDF_P2P_GO_MODE); + CASE_RETURN_STRING(QDF_FTM_MODE); + CASE_RETURN_STRING(QDF_IBSS_MODE); + CASE_RETURN_STRING(QDF_P2P_DEVICE_MODE); + CASE_RETURN_STRING(QDF_OCB_MODE); + CASE_RETURN_STRING(QDF_NDI_MODE); + default: + return "Unknown"; + } +} + +/** + * hdd_get_valid_chan() - return current chan list from regulatory. + * @hdd_ctx: HDD context + * @chan_list: buf hold returned chan list + * @chan_num: input buf size and output returned chan num + * + * This function helps get current available chan list from regulatory + * module. It excludes the "disabled" and "invalid" channels. + * + * Return: 0 for success. + */ +static int hdd_get_valid_chan(struct hdd_context *hdd_ctx, + uint8_t *chan_list, + uint32_t *chan_num) +{ + int i = 0, j = 0; + struct regulatory_channel *cur_chan_list; + struct wlan_objmgr_pdev *pdev; + + if (!hdd_ctx || !hdd_ctx->pdev || !chan_list || !chan_num) + return -EINVAL; + + pdev = hdd_ctx->pdev; + cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * + sizeof(struct regulatory_channel)); + if (!cur_chan_list) + return -ENOMEM; + + if (wlan_reg_get_current_chan_list(pdev, cur_chan_list) != + QDF_STATUS_SUCCESS) { + qdf_mem_free(cur_chan_list); + return -EINVAL; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + uint32_t ch = cur_chan_list[i].chan_num; + enum channel_state state = wlan_reg_get_channel_state(pdev, + ch); + + if (state != CHANNEL_STATE_DISABLE && + state != CHANNEL_STATE_INVALID && + j < *chan_num) { + chan_list[j] = (uint8_t)ch; + j++; + } + } + *chan_num = j; + qdf_mem_free(cur_chan_list); + return 0; +} + +/** + * hdd_validate_channel_and_bandwidth() - Validate the channel-bandwidth combo + * @adapter: HDD adapter + * @chan_number: Channel number + * @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, + uint32_t chan_number, + enum phy_ch_width chan_bw) +{ + uint8_t chan[NUM_CHANNELS]; + uint32_t len = NUM_CHANNELS, i; + bool found = false; + mac_handle_t mac_handle; + int ret; + + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (!mac_handle) { + hdd_err("Invalid MAC handle"); + return -EINVAL; + } + + ret = hdd_get_valid_chan(adapter->hdd_ctx, chan, + &len); + if (ret) { + hdd_err("error %d in getting valid channel list", ret); + return ret; + } + + for (i = 0; i < len; i++) { + if (chan[i] == chan_number) { + found = true; + break; + } + } + + if (found == false) { + hdd_err("Channel not in driver's valid channel list"); + return -EOPNOTSUPP; + } + + if ((!WLAN_REG_IS_24GHZ_CH(chan_number)) && + (!WLAN_REG_IS_5GHZ_CH(chan_number))) { + hdd_err("CH %d is not in 2.4GHz or 5GHz", chan_number); + return -EINVAL; + } + + if (WLAN_REG_IS_24GHZ_CH(chan_number)) { + if (chan_bw == CH_WIDTH_80MHZ) { + hdd_err("BW80 not possible in 2.4GHz band"); + return -EINVAL; + } + if ((chan_bw != CH_WIDTH_20MHZ) && (chan_number == 14) && + (chan_bw != CH_WIDTH_MAX)) { + hdd_err("Only BW20 possible on channel 14"); + return -EINVAL; + } + } + + return 0; +} + +/** + * hdd_wait_for_recovery_completion() - Wait for cds recovery completion + * + * Block the unloading of the driver (or) interface up until the + * cds recovery is completed + * + * Return: true for recovery completion else false + */ +static bool hdd_wait_for_recovery_completion(void) +{ + int retry = 0; + + /* Wait for recovery to complete */ + while (cds_is_driver_recovering()) { + if (retry == HDD_MOD_EXIT_SSR_MAX_RETRIES/2) + hdd_err("Recovery in progress; wait here!!!"); + + msleep(1000); + if (retry++ == HDD_MOD_EXIT_SSR_MAX_RETRIES) { + hdd_err("SSR never completed, error"); + /* + * Trigger the bug_on in the internal builds, in the + * customer builds self-recovery will be enabled + * in those cases just return error. + */ + if (cds_is_self_recovery_enabled()) + return false; + QDF_BUG(0); + } + } + + hdd_info("Recovery completed successfully!"); + return true; +} + + +static int __hdd_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, void *data) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + struct netdev_notifier_info *dev_notif_info = data; + struct net_device *dev = dev_notif_info->dev; +#else + struct net_device *dev = data; +#endif + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(dev); + + if (!dev->ieee80211_ptr) { + hdd_debug("ieee80211_ptr is null"); + return NOTIFY_DONE; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD Context is Null"); + return NOTIFY_DONE; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_debug("%s: Driver module is closed", __func__); + return NOTIFY_DONE; + } + + /* Make sure that this callback corresponds to our device. */ + adapter = hdd_get_adapter_by_iface_name(hdd_ctx, dev->name); + if (!adapter) { + hdd_debug("failed to look up adapter for '%s'", dev->name); + return NOTIFY_DONE; + } + + if (adapter != WLAN_HDD_GET_PRIV_PTR(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", dev->name, state); + + 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(adapter); + if (!vdev) + break; + if (ucfg_scan_get_vdev_status(vdev) != + SCAN_NOT_IN_PROGRESS) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_id, INVALID_SCAN_ID, + true); + } + hdd_objmgr_put_vdev(vdev); + cds_flush_work(&adapter->scan_block_work); + /* Need to clean up blocked scan request */ + wlan_hdd_cfg80211_scan_block_cb(&adapter->scan_block_work); + 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, dev); + break; + + default: + break; + } + + return NOTIFY_DONE; +} + +/** + * hdd_netdev_notifier_call() - netdev notifier callback function + * @nb: pointer to notifier block + * @state: state + * @ndev: ndev pointer + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, + void *ndev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_netdev_notifier_call(nb, state, ndev); + cds_ssr_unprotect(__func__); + + return ret; +} + +struct notifier_block hdd_netdev_notifier = { + .notifier_call = hdd_netdev_notifier_call, +}; + +/* variable to hold the insmod parameters */ +static int con_mode; + +static int con_mode_ftm; +int con_mode_monitor; + +/* Variable to hold connection mode including module parameter con_mode */ +static int curr_con_mode; + +/** + * 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 (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: + hdd_err("Invalid channel width %d, setting to default", + ch_width); + return CH_WIDTH_INVALID; + } +} + +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 (hdd_ctx->start_modules_in_progress) { + hdd_debug("Start modules in progress (via %s)", func); + return -EAGAIN; + } + + if (hdd_ctx->stop_modules_in_progress) { + hdd_debug("Stop modules in progress (via %s)", func); + 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 (qdf_atomic_read(&hdd_ctx->con_mode_flag)) { + hdd_debug("Driver mode change in progress (via %s)", func); + 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_session_id(adapter->session_id, func); +} + +int __wlan_hdd_validate_session_id(uint8_t session_id, const char *func) +{ + if (session_id == CSR_SESSION_ID_INVALID) { + hdd_debug_rl("adapter is not up (via %s)", func); + return -EINVAL; + } + + if (session_id >= CSR_ROAM_SESSION_MAX) { + hdd_err("bad session Id:%u (via %s)", session_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) +{ + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_info("Modules not enabled, Present status: %d", + hdd_ctx->driver_status); + return false; + } + mutex_unlock(&hdd_ctx->iface_change_lock); + return true; +} + +/** + * hdd_set_ibss_power_save_params() - update IBSS Power Save params to WMA. + * @struct hdd_adapter Hdd adapter. + * + * This function sets the IBSS power save config parameters to WMA + * which will send it to firmware if FW supports IBSS power save + * before vdev start. + * + * Return: QDF_STATUS QDF_STATUS_SUCCESS on Success and QDF_STATUS_E_FAILURE + * on failure. + */ +QDF_STATUS hdd_set_ibss_power_save_params(struct hdd_adapter *adapter) +{ + int ret; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (hdd_ctx == NULL) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE, + hdd_ctx->config->ibssATIMWinSize, + VDEV_CMD); + if (0 != ret) { + hdd_err("atim window set failed %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED, + hdd_ctx->config->isIbssPowerSaveAllowed, + VDEV_CMD); + if (0 != ret) { + hdd_err("power save allow failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED, + hdd_ctx->config-> + isIbssPowerCollapseAllowed, VDEV_CMD); + if (0 != ret) { + hdd_err("power collapse allow failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX, + hdd_ctx->config->isIbssAwakeOnTxRx, + VDEV_CMD); + if (0 != ret) { + hdd_err("set awake on tx/rx failed %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_SET_INACTIVITY_TIME, + hdd_ctx->config->ibssInactivityCount, + VDEV_CMD); + if (0 != ret) { + hdd_err("set inactivity time failed %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME, + hdd_ctx->config->ibssTxSpEndInactivityTime, + VDEV_CMD); + if (0 != ret) { + hdd_err("set txsp end failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS, + hdd_ctx->config->ibssPsWarmupTime, + VDEV_CMD); + if (0 != ret) { + hdd_err("set ps warmup failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->session_id, + WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW, + hdd_ctx->config->ibssPs1RxChainInAtimEnable, + VDEV_CMD); + if (0 != ret) { + hdd_err("set 1rx chain atim failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#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); + + 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; + + qdf_runtime_lock_deinit(&ctx->dfs); + qdf_runtime_lock_deinit(&ctx->connect); + + 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 */ + +#define INTF_MACADDR_MASK 0x7 + +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_info("hdd_ctx->provisioned_mac_addr[0]: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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_info("hdd_ctx->derived_mac_addr[0]: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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_err("hdd_ctx->derived_mac_addr[%d]: " + MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY(hdd_ctx->derived_mac_addr[i].bytes)); + hdd_ctx->num_derived_addr++; + } +} + +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; + struct tdls_user_config *config = &tdls_cfg.config; + struct hdd_config *cfg = hdd_ctx->config; + QDF_STATUS status; + + config->tdls_tx_states_period = cfg->fTDLSTxStatsPeriod; + config->tdls_tx_pkt_threshold = cfg->fTDLSTxPacketThreshold; + config->tdls_rx_pkt_threshold = cfg->fTDLSRxFrameThreshold; + config->tdls_max_discovery_attempt = cfg->fTDLSMaxDiscoveryAttempt; + config->tdls_idle_timeout = cfg->tdls_idle_timeout; + config->tdls_idle_pkt_threshold = cfg->fTDLSIdlePacketThreshold; + config->tdls_rssi_trigger_threshold = cfg->fTDLSRSSITriggerThreshold; + config->tdls_rssi_teardown_threshold = cfg->fTDLSRSSITeardownThreshold; + config->tdls_rssi_delta = cfg->fTDLSRSSIDelta; + config->tdls_uapsd_mask = cfg->fTDLSUapsdMask; + config->tdls_uapsd_inactivity_time = cfg->fTDLSPuapsdInactivityTimer; + config->tdls_uapsd_pti_window = cfg->fTDLSPuapsdPTIWindow; + config->tdls_uapsd_ptr_timeout = cfg->fTDLSPuapsdPTRTimeout; + config->tdls_pre_off_chan_num = cfg->fTDLSPrefOffChanNum; + config->tdls_pre_off_chan_bw = cfg->fTDLSPrefOffChanBandwidth; + config->tdls_peer_kickout_threshold = cfg->tdls_peer_kickout_threshold; + config->delayed_trig_framint = cfg->DelayedTriggerFrmInt; + config->tdls_feature_flags = ((cfg->fEnableTDLSOffChannel ? + 1 << TDLS_FEATURE_OFF_CHANNEL : 0) | + (cfg->fEnableTDLSWmmMode ? 1 << TDLS_FEATURE_WMM : 0) | + (cfg->fEnableTDLSBufferSta ? 1 << TDLS_FEATURE_BUFFER_STA : 0) | + (cfg->fEnableTDLSSleepSta ? 1 << TDLS_FEATURE_SLEEP_STA : 0) | + (cfg->enable_tdls_scan ? 1 << TDLS_FEATURE_SCAN : 0) | + (cfg->fEnableTDLSSupport ? 1 << TDLS_FEATURE_ENABLE : 0) | + (cfg->fEnableTDLSImplicitTrigger ? + 1 << TDLS_FEAUTRE_IMPLICIT_TRIGGER : 0) | + (cfg->fTDLSExternalControl ? + 1 << TDLS_FEATURE_EXTERNAL_CONTROL : 0)); + config->tdls_vdev_nss_2g = GET_VDEV_NSS_CHAIN(cfg->rx_nss_2g, + QDF_TDLS_MODE); + config->tdls_vdev_nss_5g = GET_VDEV_NSS_CHAIN(cfg->rx_nss_5g, + QDF_TDLS_MODE); + + 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; + 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_dereg_peer = hdd_tdls_deregister_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; + + 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; +} + +static void hdd_update_tgt_services(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + struct hdd_config *config = hdd_ctx->config; + + /* Set up UAPSD */ + config->apUapsdEnabled &= 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; + + /* ARP offload: override user setting if invalid */ + config->fhostArpOffload &= cfg->arp_offload; + +#ifdef FEATURE_WLAN_SCAN_PNO + /* PNO offload */ + hdd_debug("PNO Capability in f/w = %d", cfg->pno_offload); + if (cfg->pno_offload) + config->PnoOffload = true; +#endif +#ifdef FEATURE_WLAN_TDLS + config->fEnableTDLSSupport &= cfg->en_tdls; + config->fEnableTDLSOffChannel = config->fEnableTDLSOffChannel && + cfg->en_tdls_offchan; + config->fEnableTDLSBufferSta = config->fEnableTDLSBufferSta && + cfg->en_tdls_uapsd_buf_sta; + if (config->fTDLSUapsdMask && cfg->en_tdls_uapsd_sleep_sta) + config->fEnableTDLSSleepSta = true; + else + config->fEnableTDLSSleepSta = false; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + config->isRoamOffloadEnabled &= cfg->en_roam_offload; +#endif + config->sap_get_peer_info &= cfg->get_peer_info_enabled; + config->MAWCEnabled &= cfg->is_fw_mawc_capable; + hdd_update_tdls_config(hdd_ctx); + sme_update_tgt_services(hdd_ctx->mac_handle, 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) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + uint8_t max_supp_nss = 1; + mac_handle_t mac_handle; + + if (cfg_ini->enable2x2 && !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, + cfg_ini->rx_nss_2g, BAND_2G); + + sme_update_vdev_type_nss(mac_handle, max_supp_nss, + cfg_ini->rx_nss_5g, BAND_5G); +} + +/** + * 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) +{ + struct ieee80211_supported_band *band_5g = + hdd_ctx->wiphy->bands[NL80211_BAND_5GHZ]; + uint32_t val; + + if (!band_5g) { + hdd_debug("5GHz band disabled, skipping capability population"); + return; + } + + val = hdd_ctx->config->txBFCsnValue; + band_5g->vht_cap.cap |= (val << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + + val = NUM_OF_SOUNDING_DIMENSIONS; + band_5g->vht_cap.cap |= + (val << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT); + + hdd_debug("Updated wiphy vhtcap:0x%x, CSNAntSupp:%d, NumSoundDim:%d", + band_5g->vht_cap.cap, hdd_ctx->config->txBFCsnValue, val); +} + +/** + * hdd_update_hw_dbs_capable() - sets the dbs capability of the device + * @hdd_ctx: HDD context + * + * Sets the DBS capability as per INI and firmware capability + * + * Return: None + */ +static void hdd_update_hw_dbs_capable(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + uint8_t hw_dbs_capable = 0; + + if (policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) && + ((cfg_ini->dual_mac_feature_disable == + ENABLE_DBS_CXN_AND_SCAN) || + (cfg_ini->dual_mac_feature_disable == + ENABLE_DBS_CXN_AND_ENABLE_SCAN_WITH_ASYNC_SCAN_OFF) || + (cfg_ini->dual_mac_feature_disable == + ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN))) + hw_dbs_capable = 1; + + sme_update_hw_dbs_capable(hdd_ctx->mac_handle, hw_dbs_capable); +} + +static void hdd_update_tgt_ht_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_ht_cap *cfg) +{ + QDF_STATUS status; + uint32_t value, val32; + uint16_t val16; + struct hdd_config *pconfig = hdd_ctx->config; + tSirMacHTCapabilityInfo *phtCapInfo; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + uint8_t enable_tx_stbc; + mac_handle_t mac_handle; + + /* check and update RX STBC */ + if (pconfig->enableRxSTBC && !cfg->ht_rx_stbc) + pconfig->enableRxSTBC = cfg->ht_rx_stbc; + + mac_handle = hdd_ctx->mac_handle; + + /* get the MPDU density */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_MPDU_DENSITY, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get MPDU DENSITY"); + value = 0; + } + + /* + * MPDU density: + * override user's setting if value is larger + * than the one supported by target + */ + if (value > cfg->mpdu_density) { + status = sme_cfg_set_int(mac_handle, WNI_CFG_MPDU_DENSITY, + cfg->mpdu_density); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set MPDU DENSITY to CCM"); + } + + /* get the HT capability info */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_HT_CAP_INFO, &val32); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("could not get HT capability info"); + return; + } + val16 = (uint16_t) val32; + phtCapInfo = (tSirMacHTCapabilityInfo *) &val16; + + /* Set the LDPC capability */ + phtCapInfo->advCodingCap = cfg->ht_rx_ldpc; + + if (pconfig->ShortGI20MhzEnable && !cfg->ht_sgi_20) + pconfig->ShortGI20MhzEnable = cfg->ht_sgi_20; + + if (pconfig->ShortGI40MhzEnable && !cfg->ht_sgi_40) + pconfig->ShortGI40MhzEnable = cfg->ht_sgi_40; + + hdd_ctx->num_rf_chains = cfg->num_rf_chains; + hdd_ctx->ht_tx_stbc_supported = cfg->ht_tx_stbc; + + enable_tx_stbc = pconfig->enableTxSTBC; + + if (pconfig->enable2x2 && (cfg->num_rf_chains == 2)) { + pconfig->enable2x2 = 1; + } else { + pconfig->enable2x2 = 0; + enable_tx_stbc = 0; + + /* 1x1 */ + /* Update Rx Highest Long GI data Rate */ + if (sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1) + == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE to CCM"); + } + + /* Update Tx Highest Long GI data Rate */ + if (sme_cfg_set_int + (mac_handle, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1) == + QDF_STATUS_E_FAILURE) { + hdd_err("VHT_TX_HIGHEST_SUPP_RATE_1_1 to CCM fail"); + } + } + if (!(cfg->ht_tx_stbc && pconfig->enable2x2)) + enable_tx_stbc = 0; + phtCapInfo->txSTBC = enable_tx_stbc; + + val32 = val16; + status = sme_cfg_set_int(mac_handle, WNI_CFG_HT_CAP_INFO, val32); + if (status != QDF_STATUS_SUCCESS) + hdd_err("could not set HT capability to CCM"); +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + value = SIZE_OF_SUPPORTED_MCS_SET; + if (sme_cfg_get_str(mac_handle, WNI_CFG_SUPPORTED_MCS_SET, mcs_set, + &value) == 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 (pconfig->enable2x2) { + for (value = 0; value < cfg->num_rf_chains; value++) + mcs_set[value] = + WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + + status = + sme_cfg_set_str(mac_handle, + WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, + SIZE_OF_SUPPORTED_MCS_SET); + if (status == QDF_STATUS_E_FAILURE) + 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; + uint32_t value = 0; + struct hdd_config *pconfig = hdd_ctx->config; + struct wiphy *wiphy = hdd_ctx->wiphy; + struct ieee80211_supported_band *band_5g = + wiphy->bands[HDD_NL80211_BAND_5GHZ]; + uint32_t temp = 0; + uint32_t ch_width = eHT_CHANNEL_WIDTH_80MHZ; + uint32_t hw_rx_ldpc_enabled; + struct wma_caps_per_phy caps_per_phy; + mac_handle_t mac_handle; + + if (!band_5g) { + hdd_debug("5GHz band disabled, skipping capability population"); + return; + } + + mac_handle = hdd_ctx->mac_handle; + + /* Get the current MPDU length */ + status = + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_MAX_MPDU_LENGTH, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get MPDU LENGTH"); + value = 0; + } + + /* + * VHT max MPDU length: + * override if user configured value is too high + * that the target cannot support + */ + if (value > cfg->vht_max_mpdu) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_MAX_MPDU_LENGTH, + cfg->vht_max_mpdu); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set VHT MAX MPDU LENGTH"); + } + + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_BASIC_MCS_SET, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtRxMCS; + + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtRxMCS2x2 << 2); + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_BASIC_MCS_SET, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass VHT_BASIC_MCS_SET to CCM"); + } + + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_RX_MCS_MAP, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtRxMCS; + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtRxMCS2x2 << 2); + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_RX_MCS_MAP, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass WNI_CFG_VHT_RX_MCS_MAP to CCM"); + } + + sme_cfg_get_int(mac_handle, WNI_CFG_VHT_TX_MCS_MAP, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtTxMCS; + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtTxMCS2x2 << 2); + + hdd_debug("vhtRxMCS2x2 - %x temp - %u enable2x2 %d", + pconfig->vhtRxMCS2x2, temp, pconfig->enable2x2); + + if (sme_cfg_set_int(mac_handle, WNI_CFG_VHT_TX_MCS_MAP, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass WNI_CFG_VHT_TX_MCS_MAP to CCM"); + } + /* Get the current RX LDPC setting */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_LDPC_CODING_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT LDPC CODING CAP"); + value = 0; + } + + /* Set HW RX LDPC capability */ + hw_rx_ldpc_enabled = !!cfg->vht_rx_ldpc; + if (hw_rx_ldpc_enabled != value) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_LDPC_CODING_CAP, + hw_rx_ldpc_enabled); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set VHT LDPC CODING CAP to CCM"); + } + + /* Get current GI 80 value */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_SHORT_GI_80MHZ, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get SHORT GI 80MHZ"); + value = 0; + } + + /* set the Guard interval 80MHz */ + if (value && !cfg->vht_short_gi_80) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SHORT_GI_80MHZ, + cfg->vht_short_gi_80); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set SHORT GI 80MHZ to CCM"); + } + + /* Get VHT TX STBC cap */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_TXSTBC, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT TX STBC"); + value = 0; + } + + /* VHT TX STBC cap */ + if (value && !cfg->vht_tx_stbc) { + status = sme_cfg_set_int(mac_handle, WNI_CFG_VHT_TXSTBC, + cfg->vht_tx_stbc); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set the VHT TX STBC to CCM"); + } + + /* Get VHT RX STBC cap */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_RXSTBC, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT RX STBC"); + value = 0; + } + + /* VHT RX STBC cap */ + if (value && !cfg->vht_rx_stbc) { + status = sme_cfg_set_int(mac_handle, WNI_CFG_VHT_RXSTBC, + cfg->vht_rx_stbc); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set the VHT RX STBC to CCM"); + } + + /* Get VHT SU Beamformer cap */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_SU_BEAMFORMER_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT SU BEAMFORMER CAP"); + value = 0; + } + + /* set VHT SU Beamformer cap */ + if (value && !cfg->vht_su_bformer) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + cfg->vht_su_bformer); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set VHT SU BEAMFORMER CAP"); + } + + /* check and update SU BEAMFORMEE capabality */ + if (pconfig->enableTxBF && !cfg->vht_su_bformee) + pconfig->enableTxBF = cfg->vht_su_bformee; + + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + pconfig->enableTxBF); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set VHT SU BEAMFORMEE CAP"); + + /* Get VHT MU Beamformer cap */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_MU_BEAMFORMER_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT MU BEAMFORMER CAP"); + value = 0; + } + + /* set VHT MU Beamformer cap */ + if (value && !cfg->vht_mu_bformer) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_MU_BEAMFORMER_CAP, + cfg->vht_mu_bformer); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set the VHT MU BEAMFORMER CAP to CCM"); + } + + /* Get VHT MU Beamformee cap */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT MU BEAMFORMEE CAP"); + value = 0; + } + + /* set VHT MU Beamformee cap */ + if (value && !cfg->vht_mu_bformee) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + cfg->vht_mu_bformee); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set VHT MU BEAMFORMER CAP"); + } + + /* Get VHT MAX AMPDU Len exp */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT AMPDU LEN"); + value = 0; + } + + /* + * 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 (value > cfg->vht_max_ampdu_len_exp) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + cfg->vht_max_ampdu_len_exp); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set the VHT AMPDU LEN EXP"); + } + + /* Get VHT TXOP PS CAP */ + status = sme_cfg_get_int(mac_handle, WNI_CFG_VHT_TXOP_PS, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT TXOP PS"); + value = 0; + } + + /* set VHT TXOP PS cap */ + if (value && !cfg->vht_txop_ps) { + status = sme_cfg_set_int(mac_handle, WNI_CFG_VHT_TXOP_PS, + cfg->vht_txop_ps); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set the VHT TXOP PS"); + } + + 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)) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + VHT_CAP_160_AND_80P80_SUPP); + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set the VHT CAP 160"); + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + ch_width = eHT_CHANNEL_WIDTH_80P80MHZ; + } else if (cfg->supp_chan_width & (1 << eHT_CHANNEL_WIDTH_160MHZ)) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + VHT_CAP_160_SUPP); + if (status == QDF_STATUS_E_FAILURE) + hdd_err("could not set the VHT CAP 160"); + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + } + pconfig->vhtChannelWidth = QDF_MIN(pconfig->vhtChannelWidth, + ch_width); + /* Get the current GI 160 value */ + status = sme_cfg_get_int(mac_handle, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + &value); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get GI 80 & 160"); + value = 0; + } + /* set the Guard interval 160MHz */ + if (value && !cfg->vht_short_gi_160) { + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + cfg->vht_short_gi_160); + + if (status == QDF_STATUS_E_FAILURE) + hdd_err("failed to set SHORT GI 160MHZ"); + } + + 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 (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 (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; + +} + +/** + * 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; +} + +#ifdef FEATURE_WLAN_APF +/** + * hdd_update_apf_support() - Update APF supported flag in hdd context + * @hdd_ctx: Pointer to hdd_ctx + * @cfg: target configuration + * + * Update the APF support flag in HDD Context using INI and target config. + * + * Return: None + */ +static void hdd_update_apf_support(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + hdd_ctx->apf_supported = (cfg->apf_enabled && + hdd_ctx->config->apf_packet_filter_enable); +} +#else +static void hdd_update_apf_support(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} +#endif + +/** + * hdd_update_ra_rate_limit() - Update RA rate limit from target + * configuration to cfg_ini in HDD + * @hdd_ctx: Pointer to hdd_ctx + * @cfg: target configuration + * + * Return: None + */ +#ifdef FEATURE_WLAN_RA_FILTERING +static void hdd_update_ra_rate_limit(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + hdd_ctx->config->IsRArateLimitEnabled = cfg->is_ra_rate_limit_enabled; +} +#else +static void hdd_update_ra_rate_limit(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} +#endif + +static void hdd_sar_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + hdd_ctx->sar_version = cfg->sar_version; +} + + +static uint8_t hdd_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: + hdd_err("Device mode %d invalid", device_mode); + return STA_NSS_CHAINS_SHIFT; + } +} + +static bool +hdd_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: + hdd_err("Unknown Band nss change not allowed"); + return false; + } + return true; +} + +static void hdd_modify_chains_in_hdd_cfg(struct hdd_context *hdd_ctx, + 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; + uint32_t *rx_chains_ini = NULL; + uint32_t *tx_chains_ini = NULL; + + if (band == NSS_CHAINS_BAND_2GHZ) { + rx_chains_ini = &hdd_ctx->config->rx_nss_2g; + tx_chains_ini = &hdd_ctx->config->tx_nss_2g; + } else if (band == NSS_CHAINS_BAND_5GHZ) { + rx_chains_ini = &hdd_ctx->config->rx_nss_5g; + tx_chains_ini = &hdd_ctx->config->tx_nss_5g; + } else { + hdd_err("wrong band passed %d, cannot modify chains", band); + return; + } + + nss_shift = hdd_get_nss_chain_shift(vdev_op_mode); + + *rx_chains_ini &= ~(nss_mask << nss_shift); + *rx_chains_ini |= (rx_chains << nss_shift); + *tx_chains_ini &= ~(nss_mask << nss_shift); + *tx_chains_ini |= (tx_chains << nss_shift); + + hdd_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 +hdd_modify_nss_in_hdd_cfg(struct hdd_context *hdd_ctx, + 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; + uint32_t *rx_nss_ini = NULL; + uint32_t *tx_nss_ini = NULL; + + if (band == NSS_CHAINS_BAND_2GHZ) { + rx_nss_ini = &hdd_ctx->config->rx_nss_2g; + tx_nss_ini = &hdd_ctx->config->tx_nss_2g; + } else if (band == NSS_CHAINS_BAND_5GHZ) { + rx_nss_ini = &hdd_ctx->config->rx_nss_5g; + tx_nss_ini = &hdd_ctx->config->tx_nss_5g; + } else + return; + + if (!hdd_is_nss_update_allowed(hdd_ctx->fw_chain_cfg, rx_nss, tx_nss, + band)) { + hdd_debug("Nss modification failed, fw doesn't support this nss %d", + rx_nss); + return; + } + + nss_shift = hdd_get_nss_chain_shift(vdev_op_mode); + + *rx_nss_ini &= ~(nss_mask << nss_shift); + *rx_nss_ini |= (rx_nss << nss_shift); + *tx_nss_ini &= ~(nss_mask << nss_shift); + *tx_nss_ini |= (tx_nss << nss_shift); + + hdd_debug("rx nss %d tx nss %d changed for vdev mode %d for band %d", + rx_nss, tx_nss, vdev_op_mode, band); +} + +static void +hdd_modify_nss_chains_tgt_cfg(struct hdd_context *hdd_ctx, + enum QDF_OPMODE vdev_op_mode, + enum nss_chains_band_info band) +{ + uint32_t ini_rx_nss; + uint32_t ini_tx_nss; + uint8_t max_supported_rx_nss = MAX_VDEV_NSS; + uint8_t max_supported_tx_nss = MAX_VDEV_NSS; + uint32_t ini_rx_chains; + uint32_t ini_tx_chains; + uint8_t max_supported_rx_chains = MAX_VDEV_CHAINS; + uint8_t max_supported_tx_chains = MAX_VDEV_CHAINS; + uint8_t nss_shift = hdd_get_nss_chain_shift(vdev_op_mode); + struct wlan_mlme_chain_cfg chain_cfg = hdd_ctx->fw_chain_cfg; + + if (band == NSS_CHAINS_BAND_2GHZ) { + ini_rx_nss = hdd_ctx->config->rx_nss_2g; + ini_tx_nss = hdd_ctx->config->tx_nss_2g; + ini_rx_chains = hdd_ctx->config->num_rx_chains_2g; + ini_tx_chains = hdd_ctx->config->num_tx_chains_2g; + } else if (band == NSS_CHAINS_BAND_5GHZ) { + ini_rx_nss = hdd_ctx->config->rx_nss_5g; + ini_tx_nss = hdd_ctx->config->tx_nss_5g; + ini_rx_chains = hdd_ctx->config->num_rx_chains_5g; + ini_tx_chains = hdd_ctx->config->num_tx_chains_5g; + } else { + hdd_err("wrong band passed %d, cannot change nss in ini", band); + return; + } + + ini_rx_nss = GET_VDEV_NSS_CHAIN(ini_rx_nss, nss_shift); + ini_tx_nss = GET_VDEV_NSS_CHAIN(ini_tx_nss, 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); + max_supported_tx_nss = QDF_MIN(ini_tx_nss, max_supported_tx_nss); + + ini_rx_chains = GET_VDEV_NSS_CHAIN(ini_rx_chains, nss_shift); + ini_tx_chains = GET_VDEV_NSS_CHAIN(ini_tx_chains, 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); + max_supported_tx_chains = QDF_MIN(ini_tx_chains, + max_supported_tx_chains); + + hdd_modify_nss_in_hdd_cfg(hdd_ctx, max_supported_rx_chains, + max_supported_tx_chains, vdev_op_mode, + band); + hdd_modify_chains_in_hdd_cfg(hdd_ctx, max_supported_rx_nss, + max_supported_tx_nss, vdev_op_mode, band); +} + +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); +} + +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); + uint8_t temp_band_cap; + struct cds_config_info *cds_cfg = cds_get_ini_config(); + uint8_t antenna_mode; + QDF_STATUS status; + mac_handle_t mac_handle; + enum nss_chains_band_info band; + + 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; + } + + hdd_objmgr_update_tgt_max_vdev_psoc(hdd_ctx, cfg->max_intf_count); + + ret = hdd_green_ap_update_config(hdd_ctx); + + ucfg_ipa_set_dp_handle(hdd_ctx->psoc, + cds_get_context(QDF_MODULE_ID_SOC)); + ucfg_ipa_set_txrx_handle(hdd_ctx->psoc, + cds_get_context(QDF_MODULE_ID_TXRX)); + 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); + + if (cds_cfg) { + if (hdd_ctx->config->enable_sub_20_channel_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 = + hdd_ctx->config->enable_sub_20_channel_width; + } + } + + /* first store the INI band capability */ + temp_band_cap = hdd_ctx->config->nBandCapability; + + hdd_ctx->config->nBandCapability = 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; + + /* + * now overwrite the target band capability with INI + * setting if INI setting is a subset + */ + + if ((hdd_ctx->config->nBandCapability == BAND_ALL) && + (temp_band_cap != BAND_ALL)) + hdd_ctx->config->nBandCapability = temp_band_cap; + else if ((hdd_ctx->config->nBandCapability != BAND_ALL) && + (temp_band_cap != BAND_ALL) && + (hdd_ctx->config->nBandCapability != temp_band_cap)) { + hdd_warn("ini BandCapability not supported by the target"); + } + + hdd_ctx->curr_band = hdd_ctx->config->nBandCapability; + + 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... */ + + if (!qdf_is_macaddr_zero(&cfg->hw_macaddr)) + qdf_mem_copy(&hdd_ctx->hw_macaddr, &cfg->hw_macaddr, + QDF_MAC_ADDR_SIZE); + else + hdd_info("hw_mac is zero"); + + 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 > CSR_ROAM_SESSION_MAX) { + hdd_err("fw max vdevs (%u) > host max vdevs (%u); using %u", + cfg->max_intf_count, CSR_ROAM_SESSION_MAX, + CSR_ROAM_SESSION_MAX); + hdd_ctx->max_intf_count = CSR_ROAM_SESSION_MAX; + } 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); + + hdd_update_tgt_vht_cap(hdd_ctx, &cfg->vht_cap); + if (cfg->services.en_11ax) { + hdd_info("11AX: 11ax is enabled - update HDD config"); + hdd_update_tgt_he_cap(hdd_ctx, cfg); + } + hdd_update_tgt_twt_cap(hdd_ctx, cfg); + + hdd_ctx->fw_chain_cfg = cfg->chain_cfg; + + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) { + hdd_modify_nss_chains_tgt_cfg(hdd_ctx, QDF_STA_MODE, band); + hdd_modify_nss_chains_tgt_cfg(hdd_ctx, QDF_SAP_MODE, band); + hdd_modify_nss_chains_tgt_cfg(hdd_ctx, QDF_TDLS_MODE, band); + hdd_modify_nss_chains_tgt_cfg(hdd_ctx, QDF_P2P_DEVICE_MODE, + band); + hdd_modify_nss_chains_tgt_cfg(hdd_ctx, QDF_OCB_MODE, band); + hdd_modify_nss_chains_tgt_cfg(hdd_ctx, QDF_TDLS_MODE, band); + } + + hdd_update_vdev_nss(hdd_ctx); + + hdd_update_hw_dbs_capable(hdd_ctx); + hdd_ctx->dynamic_nss_chains_support = cfg->dynamic_nss_chains_support; + + hdd_ctx->config->fine_time_meas_cap &= cfg->fine_time_measurement_cap; + hdd_ctx->fine_time_meas_cap_target = cfg->fine_time_measurement_cap; + hdd_debug("fine_time_meas_cap: 0x%x", + hdd_ctx->config->fine_time_meas_cap); + + antenna_mode = (hdd_ctx->config->enable2x2 == 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; + hdd_update_ra_rate_limit(hdd_ctx, cfg); + + if ((hdd_ctx->config->txBFCsnValue > + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF) && + !cfg->tx_bfee_8ss_enabled) + hdd_ctx->config->txBFCsnValue = + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF; + + mac_handle = hdd_ctx->mac_handle; + status = sme_cfg_set_int(mac_handle, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + hdd_ctx->config->txBFCsnValue); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("fw update WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED to CFG fails"); + + hdd_update_apf_support(hdd_ctx, cfg); + + hdd_debug("Target APF %d Host APF %d 8ss fw support %d txBFCsnValue %d", + cfg->apf_enabled, hdd_ctx->config->apf_packet_filter_enable, + cfg->tx_bfee_8ss_enabled, hdd_ctx->config->txBFCsnValue); + + /* + * Update txBFCsnValue and NumSoundingDim values to vhtcap in wiphy + */ + hdd_update_wiphy_vhtcap(hdd_ctx); + + hdd_ctx->wmi_max_len = cfg->wmi_max_len; + + /* + * 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); + hdd_ctx->dfs_cac_offload = cfg->dfs_cac_offload; + hdd_ctx->lte_coex_ant_share = cfg->services.lte_coex_ant_share; + status = sme_cfg_set_int(mac_handle, WNI_CFG_OBSS_DETECTION_OFFLOAD, + cfg->obss_detection_offloaded); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Couldn't pass WNI_CFG_OBSS_DETECTION_OFFLOAD to CFG"); + + status = sme_cfg_set_int(mac_handle, + WNI_CFG_OBSS_COLOR_COLLISION_OFFLOAD, + cfg->obss_color_collision_offloaded); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set WNI_CFG_OBSS_COLOR_COLLISION_OFFLOAD"); + + return 0; + +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; + struct hdd_ap_ctx *ap_ctx; + + if (!hdd_ctx) { + hdd_info("Couldn't get hdd_ctx"); + return true; + } + + if (hdd_ctx->config->disableDFSChSwitch) { + hdd_info("skip tx block hdd_ctx=%pK, disableDFSChSwitch=%d", + hdd_ctx, hdd_ctx->config->disableDFSChSwitch); + return true; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + + if ((QDF_SAP_MODE == adapter->device_mode || + QDF_P2P_GO_MODE == adapter->device_mode) && + (wlan_reg_is_passive_or_disable_ch(hdd_ctx->pdev, + ap_ctx->operating_channel))) { + WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx = + true; + hdd_info("tx blocked for session: %d", + adapter->session_id); + if (adapter->txrx_vdev) + cdp_fc_vdev_flush( + cds_get_context(QDF_MODULE_ID_SOC), + adapter->txrx_vdev); + } + } + + return true; +} + +/** + * hdd_is_valid_mac_address() - validate MAC address + * @pMacAddr: 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: 1 for valid and 0 for invalid + */ +bool hdd_is_valid_mac_address(const uint8_t *pMacAddr) +{ + int xdigit = 0; + int separator = 0; + + while (*pMacAddr) { + if (isxdigit(*pMacAddr)) { + xdigit++; + } else if (':' == *pMacAddr) { + if (0 == xdigit || ((xdigit / 2) - 1) != separator) + break; + + ++separator; + } else { + /* Invalid MAC found */ + return 0; + } + ++pMacAddr; + } + 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_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); + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_mon_mode_ether_setup(dev); + + if (con_mode == QDF_GLOBAL_MONITOR_MODE) { + 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->event_flags)) { + ret = hdd_start_adapter(adapter); + if (ret) { + hdd_err("Failed to start adapter :%d", + adapter->device_mode); + return ret; + } + hdd_err("hdd_start_adapters() successful !"); + } + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + } + + ret = hdd_set_mon_rx_cb(dev); + + if (!ret) + ret = hdd_enable_monitor_mode(dev); + + return ret; +} + +/** + * hdd_mon_open() - Wrapper function for __hdd_mon_open to protect it from SSR + * @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; + + cds_ssr_protect(__func__); + ret = __hdd_mon_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#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 channel_select_logic_conc = 0; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + 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; + + 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)) + channel_select_logic_conc = + hdd_ctx->config->channel_select_logic_conc; + + if (hdd_ctx->config->dual_mac_feature_disable != + 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, + hdd_ctx->config->dual_mac_feature_disable, + channel_select_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 (status != QDF_STATUS_SUCCESS) { + hdd_err("sme_soc_set_dual_mac_config failed %d", status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_start_adapter() - Wrapper function for device specific adapter + * @adapter: pointer to HDD adapter + * + * 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) +{ + + int ret; + enum QDF_OPMODE device_mode = adapter->device_mode; + + hdd_enter_dev(adapter->dev); + hdd_debug("Start_adapter for mode : %d", adapter->device_mode); + + switch (device_mode) { + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_OCB_MODE: + case QDF_STA_MODE: + case QDF_MONITOR_MODE: + ret = hdd_start_station_adapter(adapter); + if (ret) + goto err_start_adapter; + + hdd_nud_ignore_tracking(adapter, false); + break; + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + ret = hdd_start_ap_adapter(adapter); + if (ret) + goto err_start_adapter; + break; + case QDF_IBSS_MODE: + /* + * For IBSS interface is initialized as part of + * hdd_init_station_mode() + */ + goto exit_with_success; + case QDF_FTM_MODE: + /* vdevs are dynamically managed by firmware in FTM */ + 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->session_id != HDD_SESSION_ID_INVALID) { + 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_exit(); + + return 0; + +err_start_adapter: + return -EINVAL; +} + +/** + * hdd_enable_power_management() - API to Enable Power Management + * + * API invokes Bus Interface Layer power management functionality + * + * Return: None + */ +static void hdd_enable_power_management(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) { + hdd_err("Bus Interface Context is Invalid"); + return; + } + + hif_enable_power_management(hif_ctx, cds_is_packet_log_enabled()); +} + +/** + * hdd_disable_power_management() - API to disable Power Management + * + * API disable Bus Interface Layer Power management functionality + * + * Return: None + */ +static void hdd_disable_power_management(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) { + hdd_err("Bus Interface Context is Invalid"); + return; + } + + hif_disable_power_management(hif_ctx); +} + +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) { + hdd_err("HIF context is NULL"); + return; + } + + hif_get_hw_info(hif_sc, &hdd_ctx->target_hw_version, + &hdd_ctx->target_hw_revision, + &target_hw_name); + + if (hdd_ctx->target_hw_name) + qdf_mem_free(hdd_ctx->target_hw_name); + + target_hw_name_len = strlen(target_hw_name) + 1; + hdd_ctx->target_hw_name = qdf_mem_malloc(target_hw_name_len); + if (hdd_ctx->target_hw_name) + qdf_mem_copy(hdd_ctx->target_hw_name, target_hw_name, + target_hw_name_len); + + buf = qdf_mem_malloc(WE_MAX_STR_LEN); + if (buf) { + buf_len = hdd_wlan_get_version(hdd_ctx, WE_MAX_STR_LEN, buf); + hdd_info("%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 num_entries = 0; + uint8_t tx_sched_wrr_param[TX_SCHED_WRR_PARAMS_NUM]; + uint8_t *tx_sched_wrr_ac; + int i; + struct cds_context *cds_ctx; + + if (NULL == hdd_ctx) + return; + + if (NULL == hdd_ctx->config) { + /* Do nothing if hdd_ctx is invalid */ + hdd_err("%s: Warning: hdd_ctx->cfg_ini is NULL", __func__); + return; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + hdd_err("Invalid CDS Context"); + return; + } + + for (i = 0; i < OL_TX_NUM_WMM_AC; i++) { + switch (i) { + case OL_TX_WMM_AC_BE: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_be; + break; + case OL_TX_WMM_AC_BK: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_bk; + break; + case OL_TX_WMM_AC_VI: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_vi; + break; + case OL_TX_WMM_AC_VO: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_vo; + break; + default: + tx_sched_wrr_ac = NULL; + break; + } + + hdd_string_to_u8_array(tx_sched_wrr_ac, + tx_sched_wrr_param, + &num_entries, + sizeof(tx_sched_wrr_param)); + + if (num_entries == 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]; + } + + num_entries = 0; + } +} + +uint32_t hdd_wlan_get_version(struct hdd_context *hdd_ctx, + const size_t version_len, uint8_t *version) +{ + uint32_t size; + + 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; + } + + 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", + 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); + + return size; +} + +#ifdef IPA_OFFLOAD +/** + * hdd_update_ipa_component_config() - update ipa config + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static void hdd_update_ipa_component_config(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg = hdd_ctx->config; + struct wlan_ipa_config ipa_cfg; + + ipa_cfg.ipa_config = cfg->IpaConfig; + ipa_cfg.desc_size = cfg->IpaDescSize; + ipa_cfg.txbuf_count = cfg->IpaUcTxBufCount; + ipa_cfg.bus_bw_high = cfg->busBandwidthHighThreshold; + ipa_cfg.bus_bw_medium = cfg->busBandwidthMediumThreshold; + ipa_cfg.bus_bw_low = cfg->busBandwidthLowThreshold; + ipa_cfg.ipa_bw_high = cfg->IpaHighBandwidthMbps; + ipa_cfg.ipa_bw_medium = cfg->IpaMediumBandwidthMbps; + ipa_cfg.ipa_bw_low = cfg->IpaLowBandwidthMbps; + + ucfg_ipa_update_config(&ipa_cfg); +} +#else +static void hdd_update_ipa_component_config(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef FEATURE_WLAN_WAPI +/** + * hdd_wapi_security_sta_exist() - return wapi security sta exist or not + * + * This API returns the wapi security station exist or not + * + * Return: true - wapi security station exist + */ +static bool hdd_wapi_security_sta_exist(void) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + hdd_for_each_adapter(hdd_ctx, adapter) { + if ((adapter->device_mode == QDF_STA_MODE) && + adapter->wapi_info.wapi_mode && + (adapter->wapi_info.wapi_auth_mode != WAPI_AUTH_MODE_OPEN)) + return true; + } + return false; +} +#else +static bool hdd_wapi_security_sta_exist(void) +{ + return false; +} +#endif + +#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_adapter *adapter = NULL; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err("Adapter is NULL"); + return PM_MAX_NUM_OF_MODE; + } + + return policy_mgr_convert_device_mode_to_qdf_type( + adapter->device_mode); +} + +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_wapi_security_sta_exist = + hdd_wapi_security_sta_exist; + + 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_FEATURE_NAN_CONVERGENCE +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_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.get_peer_idx = hdd_ndp_get_peer_idx; + cb_obj.peer_departed_ind = hdd_ndp_peer_departed_handler; + + os_if_nan_register_hdd_callbacks(hdd_ctx->psoc, &cb_obj); +} +#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_peer_leaks(hdd_ctx->psoc); + wlan_objmgr_psoc_check_for_vdev_leaks(hdd_ctx->psoc); + wlan_objmgr_psoc_check_for_pdev_leaks(hdd_ctx->psoc); + + /* many adapter resources are not freed by design during SSR */ + if (is_ssr) + return; + + qdf_mc_timer_check_for_leaks(); + qdf_nbuf_map_check_for_leaks(); + qdf_mem_check_for_leaks(); +} + +#define hdd_debug_domain_set(domain) qdf_debug_domain_set(domain) +#else +static inline void hdd_check_for_leaks(struct hdd_context *hdd_ctx, bool is_ssr) +{ } + +#define hdd_debug_domain_set(domain) +#endif /* CONFIG_LEAK_DETECTION */ + +/** + * 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 + */ +static int hdd_update_country_code(struct hdd_context *hdd_ctx) +{ + if (!country_code) + return 0; + + return hdd_reg_set_country(hdd_ctx, country_code); +} + +/** + * 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: 0 for success; non-zero for failure + */ +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; + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) { + hdd_err("QDF Device Context is Invalid return"); + return -EINVAL; + } + + hdd_psoc_idle_timer_stop(hdd_ctx); + + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status == DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_debug("Driver modules already Enabled"); + hdd_exit(); + return 0; + } + + hdd_ctx->start_modules_in_progress = true; + + switch (hdd_ctx->driver_status) { + case DRIVER_MODULES_UNINITIALIZED: + hdd_info("Wlan transitioning (UNINITIALIZED -> CLOSED)"); + unint = true; + /* Fall through dont add break here */ + case DRIVER_MODULES_CLOSED: + hdd_info("Wlan transitioning (CLOSED -> ENABLED)"); + + hdd_debug_domain_set(QDF_DEBUG_DOMAIN_ACTIVE); + + 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; + } + } + + 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) { + hdd_err("hif context is null!!"); + 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; + } + + hdd_update_ipa_component_config(hdd_ctx); + + ret = hdd_update_config(hdd_ctx); + if (ret) { + hdd_err("Failed to update configuration; errno: %d", + ret); + goto cds_free; + } + + hdd_update_cds_ac_specs_params(hdd_ctx); + + 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 deinit_config; + } + + hdd_ctx->mac_handle = cds_get_context(QDF_MODULE_ID_SME); + + if (hdd_ctx->config->rx_thread_affinity_mask) + cds_set_rx_thread_cpu_mask( + hdd_ctx->config->rx_thread_affinity_mask); + + /* 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; + } + + 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; + } + + ret = hdd_register_cb(hdd_ctx); + if (ret) { + hdd_err("Failed to register HDD callbacks!"); + goto cds_txrx_free; + } + + /* + * NAN compoenet requires certian operations like, open adapter, + * close adapter, etc. to be initiated by HDD, for those + * register HDD callbacks with UMAC's NAN componenet. + */ +#ifdef WLAN_FEATURE_NAN_CONVERGENCE + hdd_nan_register_callbacks(hdd_ctx); +#endif + + 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 deregister_cb; + } + + hdd_register_policy_manager_callback( + hdd_ctx->psoc); + + hdd_sysfs_create_driver_root_obj(); + hdd_sysfs_create_version_interface(hdd_ctx->psoc); + hdd_sysfs_create_powerstats_interface(); + hdd_update_hw_sw_info(hdd_ctx); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("in ftm mode, no need to configure cds modules"); + ret = -EINVAL; + break; + } + + ret = hdd_configure_cds(hdd_ctx); + if (ret) { + hdd_err("Failed to Enable cds modules; errno: %d", ret); + goto destroy_driver_sysfs; + } + + hdd_enable_power_management(); + + 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_info("Wlan transitioned (now ENABLED)"); + + hdd_ctx->start_modules_in_progress = false; + + mutex_unlock(&hdd_ctx->iface_change_lock); + + hdd_exit(); + + return 0; + +destroy_driver_sysfs: + hdd_sysfs_destroy_powerstats_interface(); + hdd_sysfs_destroy_version_interface(); + hdd_sysfs_destroy_driver_root_obj(); + cds_post_disable(); + +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); + dispatcher_pdev_close(hdd_ctx->pdev); + hdd_objmgr_release_and_destroy_pdev(hdd_ctx); + } + + cds_dp_close(hdd_ctx->psoc); + +close: + hdd_ctx->driver_status = DRIVER_MODULES_CLOSED; + hdd_info("Wlan transition aborted (now CLOSED)"); + + cds_close(hdd_ctx->psoc); + +deinit_config: + cds_deinit_ini_config(); + +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: + if (!reinit && !unint) + pld_power_off(qdf_dev->dev); +release_lock: + hdd_ctx->start_modules_in_progress = false; + mutex_unlock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->target_hw_name) { + qdf_mem_free(hdd_ctx->target_hw_name); + hdd_ctx->target_hw_name = NULL; + } + + hdd_check_for_leaks(hdd_ctx, reinit); + hdd_debug_domain_set(QDF_DEBUG_DOMAIN_INIT); + + 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; + struct hdd_config *cfg = hdd_ctx->config; + + 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); + wifi_pos_set_dwell_time_min(psoc, cfg->nNeighborScanMinChanTime); + wifi_pos_set_dwell_time_max(psoc, cfg->nNeighborScanMaxChanTime); +} +#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; + + hdd_enter_dev(dev); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_OPEN_REQUEST, + adapter->session_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; + } + + if (qdf_atomic_read(&hdd_ctx->con_mode_flag)) { + hdd_err("con_mode_handler is in progress; Please try again."); + return -EBUSY; + } + + mutex_lock(&hdd_init_deinit_lock); + hdd_start_driver_ops_timer(eHDD_DRV_OP_IFF_UP); + + /* + * 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!!"); + ret = -EIO; + goto err_hdd_hdd_init_deinit_lock; + } + + + ret = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (ret) { + hdd_err("Failed to start WLAN modules return"); + goto err_hdd_hdd_init_deinit_lock; + } + + + if (!test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + ret = hdd_start_adapter(adapter); + if (ret) { + hdd_err("Failed to start adapter :%d", + adapter->device_mode); + goto err_hdd_hdd_init_deinit_lock; + } + } + + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + if (hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + 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(hdd_ctx, adapter); + +err_hdd_hdd_init_deinit_lock: + hdd_stop_driver_ops_timer(); + mutex_unlock(&hdd_init_deinit_lock); + return ret; +} + + +/** + * hdd_open() - Wrapper function for __hdd_open to protect it from SSR + * @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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_stop() - HDD stop function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig down + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_stop(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->session_id, adapter->device_mode); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + set_bit(DOWN_DURING_SSR, &adapter->event_flags); + 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; + } + + /* Make sure the interface is marked as closed */ + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + mac_handle = hdd_ctx->mac_handle; + + hdd_debug("Disabling Auto Power save timer"); + sme_ps_disable_auto_ps_timer( + mac_handle, + adapter->session_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)", + hdd_device_mode_to_string(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)) + return 0; + + /* + * 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); + + 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 + * @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 *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 + * + * 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); + + do { + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid magic"); + break; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("NULL hdd_ctx"); + break; + } + + 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->dev = NULL; + adapter->magic = 0; + } while (0); + + hdd_exit(); +} + +/** + * hdd_uninit() - Wrapper function to protect __hdd_uninit from SSR + * @dev: pointer to net_device structure + * + * This is called during the netdev unregister to uninitialize all data + * associated with the device + * + * Return: none + */ +static void hdd_uninit(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_uninit(dev); + cds_ssr_unprotect(__func__); +} + +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 == NULL) { + hdd_err("NLINK: cesium netlink_kernel_create failed"); + ret = -ECONNREFUSED; + } + + return ret; +} + +static void hdd_close_cesium_nl_sock(void) +{ + if (NULL != 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(); +} + +/** + * __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; + + hdd_enter_dev(dev); + + if (netif_running(dev)) { + hdd_err("On iface up, set mac address change isn't supported"); + return -EBUSY; + } + + 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 " MAC_ADDRESS_STR, + adapter_temp->dev->name, + MAC_ADDR_ARRAY(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_info("Changing MAC to " MAC_ADDRESS_STR " of the interface %s ", + MAC_ADDR_ARRAY(mac_addr.bytes), dev->name); + + hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr, &mac_addr); + memcpy(&adapter->mac_addr, psta_mac_addr->sa_data, ETH_ALEN); + memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + + hdd_exit(); + return qdf_ret_status; +} + +/** + * hdd_set_mac_address() - Wrapper function to protect __hdd_set_mac_address() + * function from SSR + * @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 *dev, void *addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_set_mac_address(dev, addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +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_info("Assigning MAC from derived list" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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_info("Assigning MAC from provisioned list" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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_info("Releasing MAC from provisioned list"); + hdd_info( + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(releaseAddr)); + } else { + qdf_atomic_clear_bit( + mac_pos_in_mask, &hdd_ctx-> + derived_intf_addr_mask); + hdd_info("Releasing MAC from derived list"); + hdd_info(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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_err("Releasing non existing MAC" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(releaseAddr)); +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * __hdd_set_multicast_list() - set the multicast address list + * @dev: Pointer to the WLAN device. + * @skb: Pointer to OS packet (sk_buff). + * + * This funciton 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; + + hdd_enter_dev(dev); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + goto out; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto out; + + errno = hdd_validate_adapter(adapter); + if (errno) + goto out; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("%s: Driver module is closed", __func__); + goto out; + } + + mc_list_request = qdf_mem_malloc(sizeof(*mc_list_request)); + if (!mc_list_request) { + hdd_err("Cannot allocate mc_list_request"); + goto out; + } + + /* Delete already configured multicast address list */ + if (adapter->mc_addr_list.mc_cnt > 0) { + hdd_debug("clear previously configured MC address list"); + 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 > pmo_ucfg_max_mc_addr_supported(psoc)) { + hdd_debug("Exceeded max MC filter addresses (%d). Allowing all MC frames by disabling MC address filtering", + pmo_ucfg_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) { + hdd_debug("ha_addr[%d] "MAC_ADDRESS_STR, + i, MAC_ADDR_ARRAY(ha->addr)); + 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] = %pM", i, + mc_list_request->mc_addr[i].bytes); + i++; + } + } + + adapter->mc_addr_list.mc_cnt = mc_count; + mc_list_request->psoc = psoc; + mc_list_request->vdev_id = adapter->session_id; + mc_list_request->count = mc_count; + + errno = hdd_cache_mc_addr_list(mc_list_request); + if (errno) { + hdd_err("Failed to cache MC address list for vdev %u; errno:%d", + adapter->session_id, errno); + goto free_req; + } + + hdd_enable_mc_addr_filtering(adapter, pmo_mc_list_change_notify); + +free_req: + qdf_mem_free(mc_list_request); + +out: + hdd_exit(); +} + + +/** + * hdd_set_multicast_list() - SSR wrapper function for __hdd_set_multicast_list + * @dev: pointer to net_device + * + * Return: none + */ +static void hdd_set_multicast_list(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_set_multicast_list(dev); + cds_ssr_unprotect(__func__); +} +#endif + +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_tx_timeout = hdd_tx_timeout, + .ndo_get_stats = hdd_get_stats, + .ndo_do_ioctl = hdd_ioctl, + .ndo_set_mac_address = hdd_set_mac_address, + .ndo_select_queue = hdd_select_queue, +#ifdef WLAN_FEATURE_PACKET_FILTERING + .ndo_set_rx_mode = hdd_set_multicast_list, +#endif +}; + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/* Monitor mode net_device_ops, doesnot 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_station_ops() - update net_device ops for monitor mode + * @dev: Handle to struct net_device to be updated. + * Return: None + */ +void hdd_set_station_ops(struct net_device *dev) +{ + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + dev->netdev_ops = &wlan_mon_drv_ops; + else + dev->netdev_ops = &wlan_drv_ops; +} +#else +void hdd_set_station_ops(struct net_device *dev) +{ + dev->netdev_ops = &wlan_drv_ops; +} +#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: User-visible name of the interface + * + * 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) +{ + struct net_device *dev; + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + QDF_STATUS qdf_status; + + /* cfg80211 initialization and registration */ + dev = alloc_netdev_mq(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 ? + hdd_mon_mode_ether_setup : ether_setup), + NUM_TX_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)); + sta_ctx = &adapter->session.station; + qdf_mem_set(sta_ctx->conn_info.staId, sizeof(sta_ctx->conn_info.staId), + HDD_WLAN_INVALID_STA_ID); + adapter->dev = dev; + adapter->hdd_ctx = hdd_ctx; + adapter->magic = WLAN_HDD_ADAPTER_MAGIC; + adapter->session_id = HDD_SESSION_ID_INVALID; + + qdf_status = qdf_event_create(&adapter->qdf_session_open_event); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto free_net_dev; + + qdf_status = qdf_event_create(&adapter->qdf_session_close_event); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto free_net_dev; + + adapter->offloads_configured = false; + adapter->is_link_up_service_needed = false; + adapter->disconnection_in_progress = false; + adapter->send_mode_change = true; + + /* Init the net_device structure */ + strlcpy(dev->name, name, IFNAMSIZ); + + qdf_mem_copy(dev->dev_addr, mac_addr, sizeof(tSirMacAddr)); + qdf_mem_copy(adapter->mac_addr.bytes, mac_addr, sizeof(tSirMacAddr)); + dev->watchdog_timeo = HDD_TX_TIMEOUT; + + if (hdd_ctx->config->enable_ip_tcp_udp_checksum_offload) + dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + dev->features |= NETIF_F_RXCSUM; + + hdd_set_tso_flags(hdd_ctx, dev); + 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; + + /* set dev's parent to underlying device */ + SET_NETDEV_DEV(dev, hdd_ctx->parent_dev); + hdd_wmm_init(adapter); + spin_lock_init(&adapter->pause_map_lock); + adapter->start_time = qdf_system_ticks(); + adapter->last_time = adapter->start_time; + + return adapter; + +free_net_dev: + free_netdev(adapter->dev); + + return NULL; +} + +static QDF_STATUS hdd_register_interface(struct hdd_adapter *adapter, bool rtnl_held) +{ + 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; + } + } + + ret = register_netdevice(dev); + if (ret) { + hdd_err("register_netdevice(%s) failed, err = 0x%x", + dev->name, ret); + return QDF_STATUS_E_FAILURE; + } + } else { + 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_open_session_callback(uint8_t session_id, + QDF_STATUS qdf_status) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD_CTX"); + return QDF_STATUS_E_FAILURE; + } + + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, session_id); + if (NULL == adapter) { + hdd_err("NULL adapter for %d", session_id); + return QDF_STATUS_E_INVAL; + } + + if (qdf_status == QDF_STATUS_SUCCESS) + set_bit(SME_SESSION_OPENED, &adapter->event_flags); + + qdf_event_set(&adapter->qdf_session_open_event); + hdd_debug("session %d opened", adapter->session_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_sme_close_session_callback(uint8_t session_id) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD_CTX"); + return QDF_STATUS_E_FAILURE; + } + + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, session_id); + if (NULL == adapter) { + hdd_err("NULL adapter"); + return QDF_STATUS_E_INVAL; + } + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid magic"); + return QDF_STATUS_NOT_INITIALIZED; + } + + /* + * 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); + + clear_bit(SME_SESSION_OPENED, &adapter->event_flags); + + /* + * 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) + qdf_event_set(&adapter->qdf_session_close_event); + + return QDF_STATUS_SUCCESS; +} + +int hdd_vdev_ready(struct hdd_adapter *adapter) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + + status = pmo_vdev_ready(vdev); + 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 = pmo_ucfg_enhanced_mc_filter_enable(vdev); + else + status = pmo_ucfg_enhanced_mc_filter_disable(vdev); + + hdd_objmgr_put_vdev(vdev); + + return qdf_status_to_os_return(status); +} + +int hdd_vdev_destroy(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + int errno; + struct hdd_context *hdd_ctx; + uint8_t vdev_id; + struct wlan_objmgr_vdev *vdev; + + vdev_id = adapter->session_id; + hdd_info("destroying vdev %d", vdev_id); + + /* vdev created sanity check */ + if (!test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + hdd_err("vdev %u does not exist", vdev_id); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + + ucfg_pmo_del_wow_pattern(vdev); + + status = ucfg_reg_11d_vdev_delete_update(vdev); + + /* Disable Scan and abort any pending scans for this vdev */ + ucfg_scan_set_vdev_del_in_progress(vdev); + hdd_objmgr_put_vdev(vdev); + wlan_hdd_scan_abort(adapter); + + /* close sme session (destroy vdev in firmware via legacy API) */ + qdf_event_reset(&adapter->qdf_session_close_event); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = sme_close_session(hdd_ctx->mac_handle, adapter->session_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to close sme session; status:%d", status); + goto release_vdev; + } + + /* block on a completion variable until sme session is closed */ + status = qdf_wait_for_event_completion( + &adapter->qdf_session_close_event, + SME_CMD_VDEV_CREATE_DELETE_TIMEOUT); + + if (QDF_IS_STATUS_ERROR(status)) { + clear_bit(SME_SESSION_OPENED, &adapter->event_flags); + + if (adapter->device_mode == QDF_NDI_MODE) + hdd_ndp_session_end_handler(adapter); + + if (status == QDF_STATUS_E_TIMEOUT) + hdd_err("timed out waiting for sme close session"); + else if (adapter->qdf_session_close_event.force_set) { + ucfg_mlme_force_objmgr_vdev_peer_cleanup(vdev_id); + hdd_info("SSR occurred during sme close session"); + } + else + hdd_err("failed to wait for sme close session; status:%u", + status); + } + +release_vdev: + + /* do vdev logical destroy via objmgr */ + errno = hdd_objmgr_release_and_destroy_vdev(adapter); + if (errno) { + hdd_err("failed to destroy objmgr vdev; errno:%d", errno); + return errno; + } + + hdd_info("vdev %d destroyed successfully", vdev_id); + + return 0; +} + +static int hdd_set_sme_session_param(struct hdd_adapter *adapter, + struct sme_session_params *session_param, + csr_roam_complete_cb callback, + void *callback_ctx) +{ + uint32_t type; + uint32_t sub_type; + QDF_STATUS status; + + /* determine vdev (sub)type */ + status = cds_get_vdev_types(adapter->device_mode, &type, &sub_type); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to get vdev type: %d", status); + return qdf_status_to_os_return(status); + } + session_param->sme_session_id = adapter->session_id; + session_param->self_mac_addr = (uint8_t *)&adapter->mac_addr; + session_param->type_of_persona = type; + session_param->subtype_of_persona = sub_type; + session_param->session_open_cb = hdd_sme_open_session_callback; + session_param->session_close_cb = hdd_sme_close_session_callback; + session_param->callback = callback; + session_param->callback_ctx = callback_ctx; + + return 0; +} + +static void +hdd_check_nss_chains_ini_params(struct mlme_nss_chains *vdev_ini_cfg, + uint8_t rf_chains_supported) +{ + enum nss_chains_band_info band; + + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; 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); + } +} + +void hdd_fill_nss_chain_params(struct hdd_context *hdd_ctx, + struct mlme_nss_chains *vdev_ini_cfg, + uint8_t device_mode) +{ + uint8_t nss_chain_shift; + uint8_t max_supported_nss; + struct hdd_config *config = hdd_ctx->config; + uint8_t rf_chains_supported = hdd_ctx->num_rf_chains; + + nss_chain_shift = hdd_get_nss_chain_shift(device_mode); + max_supported_nss = config->enable2x2 ? MAX_VDEV_NSS : 1; + + /* If the fw doesn't support two chains, num rf chains can max be 1 */ + vdev_ini_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->num_rx_chains_2g, + nss_chain_shift), + rf_chains_supported); + + vdev_ini_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->num_tx_chains_2g, + nss_chain_shift), + rf_chains_supported); + + /* If 2x2 mode is disabled, then max rx, tx nss can be 1 */ + vdev_ini_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->rx_nss_2g, + nss_chain_shift), + max_supported_nss); + + vdev_ini_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->tx_nss_2g, + nss_chain_shift), + max_supported_nss); + + vdev_ini_cfg->num_tx_chains_11a = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->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(config->num_tx_chains_11b, + nss_chain_shift), + rf_chains_supported); + + vdev_ini_cfg->num_tx_chains_11g = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->num_tx_chains_11g, + nss_chain_shift), + rf_chains_supported); + + vdev_ini_cfg->disable_rx_mrc[NSS_CHAINS_BAND_2GHZ] = + config->disable_rx_mrc_2g; + + vdev_ini_cfg->disable_tx_mrc[NSS_CHAINS_BAND_2GHZ] = + config->disable_tx_mrc_2g; + + /* config for 5ghz ini values */ + + vdev_ini_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->num_rx_chains_2g, + nss_chain_shift), + rf_chains_supported); + + vdev_ini_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->num_tx_chains_2g, + nss_chain_shift), + rf_chains_supported); + + /* If 2x2 mode is disabled, then max rx, tx nss can be 1 */ + vdev_ini_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->rx_nss_2g, + nss_chain_shift), + max_supported_nss); + + vdev_ini_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ] = + QDF_MIN(GET_VDEV_NSS_CHAIN(config->tx_nss_2g, + nss_chain_shift), + max_supported_nss); + + vdev_ini_cfg->disable_rx_mrc[NSS_CHAINS_BAND_5GHZ] = + config->disable_rx_mrc_2g; + + vdev_ini_cfg->disable_tx_mrc[NSS_CHAINS_BAND_5GHZ] = + config->disable_tx_mrc_2g; + hdd_check_nss_chains_ini_params(vdev_ini_cfg, rf_chains_supported); +} + +static void +hdd_store_nss_chains_cfg_in_vdev(struct hdd_adapter *adapter) +{ + struct mlme_nss_chains vdev_ini_cfg; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* Populate the nss chain params from ini for this vdev type */ + hdd_fill_nss_chain_params(hdd_ctx, &vdev_ini_cfg, adapter->device_mode); + + /* Store the nss chain config into the vdev */ + sme_store_nss_chains_cfg_in_vdev(adapter->vdev, &vdev_ini_cfg); +} + +int hdd_vdev_create(struct hdd_adapter *adapter, + csr_roam_complete_cb callback, void *ctx) +{ + QDF_STATUS status; + int errno; + struct hdd_context *hdd_ctx; + struct sme_session_params sme_session_params = {0}; + struct wlan_objmgr_vdev *vdev; + + hdd_info("creating new vdev"); + + /* do vdev create via objmgr */ + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = hdd_objmgr_create_and_store_vdev(hdd_ctx->pdev, adapter); + if (errno) { + hdd_err("failed to create objmgr vdev: %d", errno); + return errno; + } + + /* Open a SME session (prepare vdev in firmware via legacy API) */ + status = qdf_event_reset(&adapter->qdf_session_open_event); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to reinit session open event"); + return -EINVAL; + } + errno = hdd_set_sme_session_param(adapter, &sme_session_params, + callback, ctx); + if (errno) { + hdd_err("failed to populating SME params"); + goto objmgr_vdev_destroy_procedure; + } + + status = sme_open_session(hdd_ctx->mac_handle, &sme_session_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to open sme session: %d", status); + errno = qdf_status_to_os_return(status); + goto objmgr_vdev_destroy_procedure; + } + + /* block on a completion variable until sme session is opened */ + status = qdf_wait_for_event_completion(&adapter->qdf_session_open_event, + SME_CMD_VDEV_CREATE_DELETE_TIMEOUT); + if (QDF_STATUS_SUCCESS != status) { + if (adapter->qdf_session_open_event.force_set) { + /* + * SSR/PDR has caused shutdown, which has forcefully + * set the event. Return without the closing session. + */ + adapter->session_id = HDD_SESSION_ID_INVALID; + hdd_err("Session open event forcefully set"); + return -EINVAL; + } + + if (QDF_STATUS_E_TIMEOUT == status) + hdd_err("Session failed to open within timeout period"); + else + hdd_err("Failed to wait for session open event(status-%d)", + status); + errno = -ETIMEDOUT; + set_bit(SME_SESSION_OPENED, &adapter->event_flags); + goto hdd_vdev_destroy_procedure; + } + + if (!test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + hdd_err("Session failed to open due to vdev create failure"); + errno = -EINVAL; + goto objmgr_vdev_destroy_procedure; + } + + /* firmware ready for component communication, raise vdev_ready event */ + errno = hdd_vdev_ready(adapter); + if (errno) { + hdd_err("failed to dispatch vdev ready event: %d", errno); + goto hdd_vdev_destroy_procedure; + } + + if (adapter->device_mode == QDF_STA_MODE) { + hdd_debug("setting RTT mac randomization param: %d", + hdd_ctx->config->enable_rtt_mac_randomization); + errno = sme_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_ENABLE_DISABLE_RTT_INITIATOR_RANDOM_MAC, + hdd_ctx->config->enable_rtt_mac_randomization, + VDEV_CMD); + if (0 != errno) + hdd_err("RTT mac randomization param set failed %d", + errno); + } + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + goto hdd_vdev_destroy_procedure; + wlan_vdev_set_max_peer_count(vdev, + HDD_MAX_VDEV_PEER_COUNT); + hdd_objmgr_put_vdev(vdev); + } + + /* store the ini and dynamic nss chain params to the vdev object */ + hdd_store_nss_chains_cfg_in_vdev(adapter); + + hdd_info("vdev %d created successfully", adapter->session_id); + + return 0; + + /* + * Due to legacy constraints, we need to destroy in the same order as + * create. So, split error handling into 2 cases to accommodate. + */ + +objmgr_vdev_destroy_procedure: + QDF_BUG(!hdd_objmgr_release_and_destroy_vdev(adapter)); + + return errno; + +hdd_vdev_destroy_procedure: + QDF_BUG(!hdd_vdev_destroy(adapter)); + + return errno; +} + +QDF_STATUS hdd_init_station_mode(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx = &adapter->session.station; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + int ret_val; + mac_handle_t mac_handle; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + mac_handle = hdd_ctx->mac_handle; + sme_set_curr_device_mode(mac_handle, adapter->device_mode); + sme_set_pdev_ht_vht_ies(mac_handle, hdd_ctx->config->enable2x2); + sme_set_vdev_ies_per_band(mac_handle, adapter->session_id); + + hdd_roam_profile_init(adapter); + hdd_register_wext(adapter->dev); + + hdd_conn_set_connection_state(adapter, eConnectionState_NotConnected); + + qdf_mem_set(sta_ctx->conn_info.staId, + sizeof(sta_ctx->conn_info.staId), HDD_WLAN_INVALID_STA_ID); + + /* set fast roaming capability in sme session */ + status = sme_config_fast_roaming(mac_handle, adapter->session_id, + true); + /* Set the default operation channel */ + sta_ctx->conn_info.operationChannel = + hdd_ctx->config->OperatingChannel; + + /* Make the default Auth Type as OPEN */ + sta_ctx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + status = hdd_init_tx_rx(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("hdd_init_tx_rx() failed, status code %08d [x%08x]", + status, status); + goto error_init_txrx; + } + + set_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + + 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); + + ret_val = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_BURST_ENABLE, + HDD_ENABLE_SIFS_BURST_DEFAULT, + PDEV_CMD); + if (ret_val) + hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", ret_val); + + /* + * 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 (hdd_ctx->config->lro_enable && + !(qdf_atomic_read(&hdd_ctx->vendor_disable_lro_flag))) + adapter->dev->features |= NETIF_F_LRO; + + /* rcpi info initialization */ + qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi)); + + return QDF_STATUS_SUCCESS; + +error_wmm_init: + clear_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + hdd_deinit_tx_rx(adapter); +error_init_txrx: + hdd_unregister_wext(adapter->dev); + QDF_BUG(!hdd_vdev_destroy(adapter)); + + return status; +} + +/** + * hdd_deinit_station_mode() - De-initialize the station adapter + * @hdd_ctx: global hdd context + * @adapter: HDD adapter + * @rtnl_held: Used to indicate whether or not the caller is holding + * the kernel rtnl_mutex + * + * This function De-initializes the STA/P2P/OCB adapter. + * + * Return: None. + */ +static void hdd_deinit_station_mode(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + hdd_enter_dev(adapter->dev); + + if (adapter->dev) { + if (rtnl_held) + adapter->dev->wireless_handlers = NULL; + else { + rtnl_lock(); + adapter->dev->wireless_handlers = NULL; + rtnl_unlock(); + } + } + + if (test_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags)) { + hdd_deinit_tx_rx(adapter); + clear_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + } + + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + + + hdd_exit(); +} + +void hdd_deinit_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + hdd_enter(); + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_IBSS_MODE: + case QDF_NDI_MODE: + { + hdd_deinit_station_mode(hdd_ctx, adapter, rtnl_held); + break; + } + + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + { + hdd_deinit_ap_mode(hdd_ctx, adapter, rtnl_held); + break; + } + + default: + break; + } + + hdd_exit(); +} + +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_nud_deinit_tracking(adapter); + qdf_mutex_destroy(&adapter->disconnection_status_lock); + hdd_apf_context_destroy(adapter); + qdf_spinlock_destroy(&adapter->vdev_lock); + + wlan_hdd_debugfs_csr_deinit(adapter); + if (adapter->device_mode == QDF_STA_MODE) + hdd_sysfs_destroy_adapter_root_obj(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) + unregister_netdevice(dev); + else + 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 macAddr) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (!qdf_mem_cmp(adapter->mac_addr.bytes, + macAddr, sizeof(tSirMacAddr))) { + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef CONFIG_FW_LOGS_BASED_ON_INI +/** + * hdd_set_fw_log_params() - Set log parameters to FW + * @hdd_ctx: HDD Context + * @adapter: HDD Adapter + * + * 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, + struct hdd_adapter *adapter) +{ + uint8_t count = 0, numentries = 0, + moduleloglevel[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + uint32_t value = 0; + int ret; + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam() || + (!hdd_ctx->config->enable_fw_log)) { + hdd_debug("enable_fw_log not enabled in INI or in FTM mode return"); + return; + } + + /* Enable FW logs based on INI configuration */ + hdd_ctx->fw_log_settings.dl_type = + hdd_ctx->config->enableFwLogType; + ret = sme_cli_set_command(adapter->session_id, + WMI_DBGLOG_TYPE, + hdd_ctx->config->enableFwLogType, + DBG_CMD); + if (ret != 0) + hdd_err("Failed to enable FW log type ret %d", + ret); + + hdd_ctx->fw_log_settings.dl_loglevel = + hdd_ctx->config->enableFwLogLevel; + ret = sme_cli_set_command(adapter->session_id, + WMI_DBGLOG_LOG_LEVEL, + hdd_ctx->config->enableFwLogLevel, + DBG_CMD); + if (ret != 0) + hdd_err("Failed to enable FW log level ret %d", + ret); + + hdd_string_to_u8_array( + hdd_ctx->config->enableFwModuleLogLevel, + moduleloglevel, + &numentries, + FW_MODULE_LOG_LEVEL_STRING_LENGTH); + + while (count < numentries) { + /* + * FW module log level input string looks like + * below: + * gFwDebugModuleLoglevel=, + * ,... + * For example: + * gFwDebugModuleLoglevel= + * 1,0,2,1,3,2,4,3,5,4,6,5,7,6 + * 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 + */ + + if ((moduleloglevel[count] > WLAN_MODULE_ID_MAX) + || (moduleloglevel[count + 1] > DBGLOG_LVL_MAX)) { + hdd_err("Module id %d and dbglog level %d input length is more than max", + moduleloglevel[count], + moduleloglevel[count + 1]); + return; + } + + value = moduleloglevel[count] << 16; + value |= moduleloglevel[count + 1]; + ret = sme_cli_set_command(adapter->session_id, + WMI_DBGLOG_MOD_LOG_LEVEL, + value, DBG_CMD); + if (ret != 0) + hdd_err("Failed to enable FW module log level %d ret %d", + value, ret); + + count += 2; + } + +} +#else +static void hdd_set_fw_log_params(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ +} + +#endif + +/** + * 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) +{ + int ret_val; + QDF_STATUS status; + struct wma_caps_per_phy non_dbs_phy_cap; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_debug("enable2x2: %d, lte_coex: %d, ChainMask1x1: tx: %d rx: %d", + hdd_ctx->config->enable2x2, hdd_ctx->lte_coex_ant_share, + hdd_ctx->config->txchainmask1x1, + hdd_ctx->config->rxchainmask1x1); + hdd_debug("disable_DBS: %d, tx_chain_mask_2g: %d, rx_chain_mask_2g: %d", + hdd_ctx->config->dual_mac_feature_disable, + hdd_ctx->config->tx_chain_mask_2g, + hdd_ctx->config->rx_chain_mask_2g); + hdd_debug("tx_chain_mask_5g: %d, rx_chain_mask_5g: %d", + hdd_ctx->config->tx_chain_mask_5g, + hdd_ctx->config->rx_chain_mask_5g); + hdd_debug("enable_bt_chain_separation %d", + hdd_ctx->config->enable_bt_chain_separation); + + status = wma_get_caps_for_phyidx_hwmode(&non_dbs_phy_cap, + HW_MODE_DBS_NONE, + CDS_BAND_ALL); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("couldn't get phy caps. skip chain mask programming"); + return qdf_status_to_os_return(status); + } + + 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) { + hdd_debug("firmware not capable. skip chain mask programming"); + return 0; + } + + if (hdd_ctx->config->enable2x2 && + !hdd_ctx->config->enable_bt_chain_separation) { + hdd_debug("2x2 enabled. skip chain mask programming"); + return 0; + } + + if (hdd_ctx->config->dual_mac_feature_disable != + DISABLE_DBS_CXN_AND_SCAN) { + hdd_debug("DBS enabled(%d). skip chain mask programming", + hdd_ctx->config->dual_mac_feature_disable); + return 0; + } + + if (hdd_ctx->lte_coex_ant_share) { + hdd_debug("lte ant sharing enabled. skip chainmask programming"); + return 0; + } + + if (hdd_ctx->config->txchainmask1x1) { + ret_val = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + hdd_ctx->config->txchainmask1x1, + PDEV_CMD); + if (ret_val) + goto error; + } + + if (hdd_ctx->config->rxchainmask1x1) { + ret_val = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + hdd_ctx->config->rxchainmask1x1, + PDEV_CMD); + if (ret_val) + goto error; + } + + if (hdd_ctx->config->txchainmask1x1 || + hdd_ctx->config->rxchainmask1x1) { + hdd_debug("band agnostic tx/rx chain mask set. skip per band chain mask"); + return 0; + } + + if (hdd_ctx->config->tx_chain_mask_2g) { + ret_val = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_TX_CHAIN_MASK_2G, + hdd_ctx->config->tx_chain_mask_2g, PDEV_CMD); + if (0 != ret_val) + goto error; + } + + if (hdd_ctx->config->rx_chain_mask_2g) { + ret_val = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_RX_CHAIN_MASK_2G, + hdd_ctx->config->rx_chain_mask_2g, PDEV_CMD); + if (0 != ret_val) + goto error; + } + + if (hdd_ctx->config->tx_chain_mask_5g) { + ret_val = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_TX_CHAIN_MASK_5G, + hdd_ctx->config->tx_chain_mask_5g, PDEV_CMD); + if (0 != ret_val) + goto error; + } + + if (hdd_ctx->config->rx_chain_mask_5g) { + ret_val = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_RX_CHAIN_MASK_5G, + hdd_ctx->config->rx_chain_mask_5g, PDEV_CMD); + if (0 != ret_val) + goto error; + } + + return 0; + +error: + hdd_err("WMI PDEV set param failed %d", ret_val); + return -EINVAL; +} + +/** + * hdd_send_coex_config_params() - Send coex config params to FW + * @hdd_ctx: HDD context + * + * This function is used to send all coex config related params to FW + * + * Return: 0 on success, -EINVAL on failure + */ +static int hdd_send_coex_config_params(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct coex_config_params coex_cfg_params = {0}; + struct hdd_config *config; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is invalid"); + goto err; + } + + if (!adapter) { + hdd_err("adapter is invalid"); + goto err; + } + + config = hdd_ctx->config; + if (!config) { + hdd_err("hdd config got NULL"); + goto err; + } + + coex_cfg_params.vdev_id = adapter->session_id; + coex_cfg_params.config_type = WMI_COEX_CONFIG_TX_POWER; + coex_cfg_params.config_arg1 = config->set_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->set_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; + coex_cfg_params.config_arg1 = config->set_btc_mode; + + 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->set_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->set_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->set_bt_interference_low_ll; + coex_cfg_params.config_arg2 = config->set_bt_interference_low_ul; + coex_cfg_params.config_arg3 = config->set_bt_interference_medium_ll; + coex_cfg_params.config_arg4 = config->set_bt_interference_medium_ul; + coex_cfg_params.config_arg5 = config->set_bt_interference_high_ll; + coex_cfg_params.config_arg6 = config->set_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(config)) + goto err; + + return 0; +err: + return -EINVAL; +} + +/** + * 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; + struct hdd_context *hdd_ctx; + + 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; + } + + ret = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_DTIM_SYNTH, + hdd_ctx->config->enable_lprx, PDEV_CMD); + if (ret) { + hdd_err("Failed to set LPRx"); + goto error; + } + + + ret = sme_cli_set_command( + adapter->session_id, + WMI_PDEV_PARAM_1CH_DTIM_OPTIMIZED_CHAIN_SELECTION, + hdd_ctx->config->enable_dtim_selection_diversity, + PDEV_CMD); + if (ret) { + hdd_err("Failed to set DTIM_OPTIMIZED_CHAIN_SELECTION"); + goto error; + } + + ret = sme_cli_set_command( + adapter->session_id, + WMI_PDEV_PARAM_TX_SCH_DELAY, + hdd_ctx->config->enable_tx_sch_delay, + PDEV_CMD); + if (ret) { + hdd_err("Failed to set WMI_PDEV_PARAM_TX_SCH_DELAY"); + goto error; + } + + ret = sme_cli_set_command( + adapter->session_id, + WMI_PDEV_PARAM_SECONDARY_RETRY_ENABLE, + hdd_ctx->config->enable_secondary_rate, + PDEV_CMD); + if (ret) { + hdd_err("Failed to set WMI_PDEV_PARAM_SECONDARY_RETRY_ENABLE"); + goto error; + } + + if (adapter->device_mode == QDF_STA_MODE) { + sme_set_smps_cfg(adapter->session_id, + HDD_STA_SMPS_PARAM_UPPER_BRSSI_THRESH, + hdd_ctx->config->upper_brssi_thresh); + + sme_set_smps_cfg(adapter->session_id, + HDD_STA_SMPS_PARAM_LOWER_BRSSI_THRESH, + hdd_ctx->config->lower_brssi_thresh); + + sme_set_smps_cfg(adapter->session_id, + HDD_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE, + hdd_ctx->config->enable_dtim_1chrx); + } + + if (hdd_ctx->config->enable2x2) { + hdd_debug("configuring 2x2 mode fw params"); + + ret = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_ENABLE_CCK_TXFIR_OVERRIDE, + hdd_ctx->config->enable_cck_tx_fir_override, + PDEV_CMD); + if (ret) { + hdd_err("WMI_PDEV_PARAM_ENABLE_CCK_TXFIR_OVERRIDE set failed %d", + ret); + goto error; + } + + if (hdd_configure_chain_mask(adapter)) + goto error; + } 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->session_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 + + if (hdd_configure_chain_mask(adapter)) + goto error; + } + + ret = sme_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_HYST_EN, + hdd_ctx->config->enableMemDeepSleep, + PDEV_CMD); + if (ret) { + hdd_err("WMI_PDEV_PARAM_HYST_EN set failed %d", ret); + goto error; + } + + ret = sme_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + hdd_ctx->config->rts_profile, + VDEV_CMD); + if (ret) { + hdd_err("FAILED TO SET RTSCTS Profile ret:%d", ret); + goto error; + } + + hdd_debug("SET AMSDU num %d", hdd_ctx->config->max_amsdu_num); + + ret = wma_cli_set_command(adapter->session_id, + GEN_VDEV_PARAM_AMSDU, + hdd_ctx->config->max_amsdu_num, + GEN_CMD); + if (ret != 0) { + hdd_err("GEN_VDEV_PARAM_AMSDU set failed %d", ret); + goto error; + } + + hdd_set_fw_log_params(hdd_ctx, adapter); + + 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->roaming_comp_var); + init_completion(&adapter->linkup_event_var); + init_completion(&adapter->cancel_rem_on_chan_var); + init_completion(&adapter->rem_on_chan_ready_event); + init_completion(&adapter->sta_authorized_event); + init_completion(&adapter->offchannel_tx_event); + init_completion(&adapter->tx_action_cnf_event); + init_completion(&adapter->ibss_peer_info_comp); + init_completion(&adapter->lfr_fw_status.disable_lfr_event); +} + +static void hdd_reset_locally_admin_bit(struct hdd_context *hdd_ctx, + tSirMacAddr macAddr) +{ + 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( + macAddr, + &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(macAddr); + hdd_debug("locally administered bit reset in sta mode: " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(macAddr)); +} + +/** + * hdd_open_adapter() - open and setup the hdd adatper + * @hdd_ctx: global hdd context + * @session_type: type of the interface to be created + * @iface_name: User-visible name of the interface + * @macAddr: 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 + * + * This function open and setup the hdd adpater 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 macAddr, + unsigned char name_assign_type, + bool rtnl_held) +{ + struct hdd_adapter *adapter = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (hdd_ctx->current_intf_count >= hdd_ctx->max_intf_count) { + /* + * Max limit reached on the number of vdevs configured by the + * host. Return error + */ + hdd_err("Unable to add virtual intf: currentVdevCnt=%d,hostConfiguredVdevCnt=%d", + hdd_ctx->current_intf_count, hdd_ctx->max_intf_count); + return NULL; + } + + status = wlan_hdd_validate_mac_address((struct qdf_mac_addr *)macAddr); + if (QDF_IS_STATUS_ERROR(status)) { + /* Not received valid macAddr */ + hdd_err("Unable to add virtual intf: Not able to get valid mac address"); + return NULL; + } + + status = hdd_check_for_existing_macaddr(hdd_ctx, macAddr); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("Duplicate MAC addr: " MAC_ADDRESS_STR + " already exists", + MAC_ADDR_ARRAY(macAddr)); + return NULL; + } + + switch (session_type) { + case QDF_STA_MODE: + if (!hdd_ctx->config->mac_provision) { + hdd_reset_locally_admin_bit(hdd_ctx, macAddr); + /* + * After resetting locally administered bit + * again check if the new mac address is already + * exists. + */ + status = hdd_check_for_existing_macaddr(hdd_ctx, + macAddr); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("Duplicate MAC addr: " MAC_ADDRESS_STR + " already exists", + MAC_ADDR_ARRAY(macAddr)); + return NULL; + } + } + + /* fall through */ + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_OCB_MODE: + case QDF_NDI_MODE: + case QDF_MONITOR_MODE: + adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr, + name_assign_type, + iface_name); + + if (NULL == adapter) { + hdd_err("failed to allocate adapter for session %d", + session_type); + return NULL; + } + + 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 + 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 + status = hdd_register_interface(adapter, rtnl_held); + if (QDF_STATUS_SUCCESS != status) + goto err_free_netdev; + + /* 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); + + hdd_nud_init_tracking(adapter); + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE) + hdd_sysfs_create_adapter_root_obj(adapter); + qdf_mutex_create(&adapter->disconnection_status_lock); + + break; + + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + adapter = hdd_wlan_create_ap_dev(hdd_ctx, macAddr, + name_assign_type, + (uint8_t *) iface_name); + if (NULL == adapter) { + hdd_err("failed to allocate adapter for session %d", + session_type); + return NULL; + } + + 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); + if (QDF_STATUS_SUCCESS != status) + goto err_free_netdev; + + 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 + break; + case QDF_FTM_MODE: + adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr, + name_assign_type, + iface_name); + if (NULL == adapter) { + hdd_err("Failed to allocate adapter for FTM mode"); + return NULL; + } + adapter->wdev.iftype = NL80211_IFTYPE_STATION; + adapter->device_mode = session_type; + status = hdd_register_interface(adapter, rtnl_held); + if (QDF_STATUS_SUCCESS != status) + goto err_free_netdev; + + /* 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; + } + + qdf_spinlock_create(&adapter->vdev_lock); + + hdd_init_completion(adapter); + INIT_WORK(&adapter->scan_block_work, wlan_hdd_cfg80211_scan_block_cb); + qdf_list_create(&adapter->blocked_scan_request_q, WLAN_MAX_SCAN_COUNT); + qdf_mutex_create(&adapter->blocked_scan_request_q_lock); + + if (QDF_STATUS_SUCCESS == status) { + /* Add it to the hdd's session list. */ + status = hdd_add_adapter_back(hdd_ctx, adapter); + } + + if (QDF_STATUS_SUCCESS != status) { + if (NULL != adapter) { + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); + adapter = NULL; + } + + return NULL; + } + hdd_apf_context_init(adapter); + + if (QDF_STATUS_SUCCESS == status) { + policy_mgr_set_concurrency_mode(hdd_ctx->psoc, + session_type); + + /* Adapter successfully added. Increment the vdev count */ + hdd_ctx->current_intf_count++; + + hdd_debug("current_intf_count=%d", + hdd_ctx->current_intf_count); + + hdd_check_and_restart_sap_with_non_dfs_acs(); + } + + if (QDF_STATUS_SUCCESS != hdd_debugfs_init(adapter)) + hdd_err("Interface %s wow debug_fs init failed", + netdev_name(adapter->dev)); + + hdd_info("%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_free_netdev: + wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); + free_netdev(adapter->dev); + + return NULL; +} + +QDF_STATUS hdd_close_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter, + bool rtnl_held) +{ + /* + * Here we are stopping global bus_bw timer & work per adapter. + * + * The reason is to fix one race condition between + * bus bandwidth work and cleaning up an adapter. + * Under some conditions, it is possible for the bus bandwidth + * work to access a particularly destroyed adapter, leading to + * use-after-free. + */ + hdd_bus_bw_compute_timer_stop(hdd_ctx); + + qdf_list_destroy(&adapter->blocked_scan_request_q); + qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); + + /* cleanup adapter */ + policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, + adapter->device_mode); + hdd_remove_adapter(hdd_ctx, adapter); + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); + + /* conditionally restart the bw timer */ + hdd_bus_bw_compute_timer_try_start(hdd_ctx); + + /* Adapter removed. Decrement vdev count */ + if (hdd_ctx->current_intf_count != 0) + hdd_ctx->current_intf_count--; + + /* Fw will take care incase of concurrency */ + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_close_all_adapters - Close all open adapters + * @hdd_ctx: Hdd context + * rtnl_held: True if RTNL lock held + * + * Close all open adapters. + * + * Return: QDF status code + */ +QDF_STATUS hdd_close_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held) +{ + struct hdd_adapter *adapter; + QDF_STATUS status; + + hdd_enter(); + + do { + status = hdd_remove_front_adapter(hdd_ctx, &adapter); + if (QDF_IS_STATUS_SUCCESS(status)) { + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->mac_addr.bytes); + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); + + /* Adapter removed. Decrement vdev count */ + if (hdd_ctx->current_intf_count != 0) + hdd_ctx->current_intf_count--; + } + } while (QDF_IS_STATUS_SUCCESS(status)); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +void wlan_hdd_reset_prob_rspies(struct hdd_adapter *adapter) +{ + struct qdf_mac_addr *bssid = NULL; + tSirUpdateIE updateIE; + mac_handle_t mac_handle; + + 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(adapter); + bssid = &sta_ctx->conn_info.bssId; + break; + } + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + case QDF_IBSS_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(&updateIE.bssid, bssid); + updateIE.smeSessionId = adapter->session_id; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = false; + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (sme_update_add_ie(mac_handle, + &updateIE, + eUPDATE_IE_PROBE_RESP) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } +} + +QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + return hdd_stop_adapter_ext(hdd_ctx, adapter, 0); +} + +QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + enum hdd_adapter_stop_flag_t flag) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + struct csr_roam_profile *roam_profile; + union iwreq_data wrqu; + tSirUpdateIE updateIE; + unsigned long rc; + tsap_config_t *sap_config; + mac_handle_t mac_handle; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + if (adapter->session_id != HDD_SESSION_ID_INVALID) + wlan_hdd_cfg80211_deregister_frames(adapter); + + hdd_nud_ignore_tracking(adapter, true); + hdd_nud_reset_tracking(adapter); + hdd_nud_flush_work(adapter); + hdd_stop_tsf_sync(adapter); + + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + /* + * if this is the last active connection check & stop the + * opportunistic timer first + */ + if (((policy_mgr_get_connection_count(hdd_ctx->psoc) == 1) && + (policy_mgr_mode_specific_connection_count(hdd_ctx->psoc, + policy_mgr_convert_device_mode_to_qdf_type( + adapter->device_mode), NULL) == 1)) || + !policy_mgr_get_connection_count(hdd_ctx->psoc)) + policy_mgr_check_and_stop_opportunistic_timer( + hdd_ctx->psoc, adapter->session_id); + + mac_handle = hdd_ctx->mac_handle; + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_IBSS_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_NDI_MODE: + if ((QDF_NDI_MODE == adapter->device_mode) || + hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter)) || + hdd_is_connecting( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + INIT_COMPLETION(adapter->disconnect_comp_var); + roam_profile = hdd_roam_profile(adapter); + /* For NDI do not use roam_profile */ + if (QDF_NDI_MODE == adapter->device_mode) + qdf_ret_status = sme_roam_disconnect( + mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_NDI_DELETE); + else if (roam_profile->BSSType == + eCSR_BSS_TYPE_START_IBSS) + qdf_ret_status = sme_roam_disconnect( + mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + else if (QDF_STA_MODE == adapter->device_mode) { + rc = wlan_hdd_disconnect( + adapter, + eCSR_DISCONNECT_REASON_DEAUTH); + if (rc != 0 && ucfg_ipa_is_enabled()) { + hdd_err("STA disconnect failed"); + ucfg_ipa_uc_cleanup_sta(hdd_ctx->pdev, + adapter->dev); + } + } else { + qdf_ret_status = sme_roam_disconnect( + mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + /* success implies disconnect command got + * queued up successfully + */ + if (qdf_ret_status == QDF_STATUS_SUCCESS && + QDF_STA_MODE != adapter->device_mode) { + rc = wait_for_completion_timeout( + &adapter->disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hdd_warn("disconn_comp_var wait fail"); + } + if (qdf_ret_status != QDF_STATUS_SUCCESS) + hdd_warn("failed to post disconnect"); + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wireless_send_event(adapter->dev, SIOCGIWAP, &wrqu, + NULL); + } + wlan_hdd_scan_abort(adapter); + + wlan_hdd_cleanup_actionframe(adapter); + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + hdd_clear_fils_connection_info(adapter); + qdf_ret_status = sme_roam_del_pmkid_from_cache( + mac_handle, + adapter->session_id, + NULL, true); + if (QDF_IS_STATUS_ERROR(qdf_ret_status)) + hdd_err("Cannot flush PMKIDCache"); + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv4_notifier_work); +#endif + + hdd_deregister_tx_flow_control(adapter); + +#ifdef WLAN_NS_OFFLOAD +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv6_notifier_work); +#endif +#endif + + if (adapter->device_mode == QDF_STA_MODE) { + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + wlan_cfg80211_sched_scan_stop(vdev); + hdd_objmgr_put_vdev(vdev); + } + } + + /* + * During vdev destroy, if any STA is in connecting state the + * roam command will be in active queue and thus vdev destroy is + * queued in pending queue. In case STA tries to connect to + * multiple BSSID and fails to connect, due to auth/assoc + * timeouts it may take more than vdev destroy time to get + * completed. On vdev destroy timeout vdev is moved to logically + * deleted state. Once connection is completed, vdev destroy is + * activated and to release the self-peer ref count it try to + * get the ref of the vdev, which fails as vdev is logically + * deleted and this leads to peer ref leak. So before vdev + * destroy is queued abort any STA ongoing connection to avoid + * vdev destroy timeout. + */ + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) + hdd_abort_ongoing_sta_connection(hdd_ctx); + + hdd_vdev_destroy(adapter); + break; + + case QDF_MONITOR_MODE: + wlan_hdd_scan_abort(adapter); + hdd_deregister_tx_flow_control(adapter); + hdd_vdev_destroy(adapter); + break; + + case QDF_SAP_MODE: + if (test_bit(ACS_PENDING, &adapter->event_flags)) { + cds_flush_delayed_work(&adapter->acs_pending_work); + clear_bit(ACS_PENDING, &adapter->event_flags); + } + wlan_hdd_scan_abort(adapter); + /* Diassociate with all the peers before stop ap post */ + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) + wlan_hdd_del_station(adapter); + /* Flush IPA exception path packets */ + sap_config = &adapter->session.ap.sap_config; + if (sap_config) + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + ucfg_ipa_flush(hdd_ctx->pdev); + if (!(flag & HDD_IN_CAC_WORK_TH_CONTEXT)) + cds_flush_work(&hdd_ctx->sap_pre_cac_work); + /* fallthrough */ + + case QDF_P2P_GO_MODE: + cds_flush_work(&adapter->sap_stop_bss_work); + + /* Any softap specific cleanup here... */ + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + wlan_hdd_undo_acs(adapter); + if (adapter->device_mode == QDF_P2P_GO_MODE) + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + + hdd_deregister_tx_flow_control(adapter); + + hdd_destroy_acs_timer(adapter); + /** + * During vdev destroy, If any STA is in connecting state the + * roam command will be in active queue and thus vdev destroy is + * queued in pending queue. In case STA is tries to connected to + * multiple BSSID and fails to connect, due to auth/assoc + * timeouts it may take more than vdev destroy time to get + * completes. If vdev destroy timeout vdev is moved to logically + * deleted state. Once connection is completed, vdev destroy is + * activated and to release the self-peer ref count it try to + * get the ref of the vdev, which fails as vdev is logically + * deleted and this leads to peer ref leak. So before vdev + * destroy is queued abort any STA ongoing connection to avoid + * vdev destroy timeout. + */ + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) + hdd_abort_ongoing_sta_connection(hdd_ctx); + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + QDF_STATUS status; + QDF_STATUS qdf_status; + + /* Stop Bss. */ + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + + if (QDF_IS_STATUS_SUCCESS(status)) { + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + qdf_event_reset(&hostapd_state-> + qdf_stop_bss_event); + qdf_status = + qdf_wait_for_event_completion( + &hostapd_state->qdf_stop_bss_event, + SME_CMD_START_STOP_BSS_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("failure waiting for wlansap_stop_bss %d", + qdf_status); + } + } else { + hdd_err("failure in wlansap_stop_bss"); + } + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, + adapter->device_mode, + false); + + qdf_copy_macaddr(&updateIE.bssid, + &adapter->mac_addr); + updateIE.smeSessionId = adapter->session_id; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = false; + updateIE.notify = false; + /* Probe bcn reset */ + if (sme_update_add_ie(mac_handle, + &updateIE, eUPDATE_IE_PROBE_BCN) + == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } + /* Assoc resp reset */ + if (sme_update_add_ie(mac_handle, + &updateIE, + 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); + } + clear_bit(SOFTAP_INIT_DONE, &adapter->event_flags); + qdf_mem_free(adapter->session.ap.beacon); + adapter->session.ap.beacon = NULL; + + /* + * If Do_Not_Break_Stream was enabled clear avoid channel list. + */ + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + if (policy_mgr_is_dnsc_set(vdev)) + wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, 0); + hdd_objmgr_put_vdev(vdev); + } + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv4_notifier_work); +#endif + +#ifdef WLAN_NS_OFFLOAD +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv6_notifier_work); +#endif +#endif + + hdd_vdev_destroy(adapter); + + mutex_unlock(&hdd_ctx->sap_lock); + break; + case QDF_OCB_MODE: + cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_pdev *)cds_get_context(QDF_MODULE_ID_TXRX), + WLAN_HDD_GET_STATION_CTX_PTR(adapter)->conn_info.staId[0]); + hdd_deregister_tx_flow_control(adapter); + hdd_vdev_destroy(adapter); + 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; + } + + hdd_exit(); + return QDF_STATUS_SUCCESS; +} + +/** + * 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; + + hdd_enter(); + + hdd_for_each_adapter(hdd_ctx, adapter) + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + + hdd_exit(); +} + +QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + + hdd_enter(); + + cds_flush_work(&hdd_ctx->sap_pre_cac_work); + + hdd_for_each_adapter(hdd_ctx, adapter) + hdd_stop_adapter(hdd_ctx, adapter); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +static void hdd_reset_scan_operation(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_IBSS_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_NDI_MODE: + wlan_hdd_scan_abort(adapter); + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + if (adapter->device_mode == QDF_STA_MODE) { + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + wlan_cfg80211_sched_scan_stop(vdev); + hdd_objmgr_put_vdev(vdev); + } + } + break; + case QDF_P2P_GO_MODE: + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + break; + case QDF_SAP_MODE: + qdf_atomic_set(&adapter->session.ap.acs_in_progress, 0); + wlan_hdd_undo_acs(adapter); + break; + default: + break; + } +} + +QDF_STATUS hdd_reset_all_adapters(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + struct qdf_mac_addr peerMacAddr; + int sta_id; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + cds_flush_work(&hdd_ctx->sap_pre_cac_work); + + hdd_for_each_adapter(hdd_ctx, adapter) { + hdd_info("[SSR] reset adapter with device mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + /* Stop tdls timers */ + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + hdd_notify_tdls_reset_adapter(vdev); + hdd_objmgr_put_vdev(vdev); + } + adapter->session.station.hdd_reassoc_scenario = false; + } + + if (hdd_ctx->config->sap_internal_restart && + adapter->device_mode == QDF_SAP_MODE) { + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + if (test_bit(ACS_PENDING, &adapter->event_flags)) { + cds_flush_delayed_work( + &adapter->acs_pending_work); + clear_bit(ACS_PENDING, &adapter->event_flags); + } + + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)) { + hdd_sap_indicate_disconnect_for_sta(adapter); + clear_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags); + } + + } else { + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + + hdd_reset_scan_operation(hdd_ctx, adapter); + + hdd_deinit_tx_rx(adapter); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + + if (adapter->device_mode == QDF_STA_MODE) + hdd_clear_fils_connection_info(adapter); + + if (adapter->device_mode == QDF_SAP_MODE) { + wlansap_cleanup_cac_timer( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + /* + * If adapter is SAP, set session ID to invalid + * since SAP session will be cleanup during SSR. + */ + wlansap_set_invalid_session( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + } + + /* Delete connection peers if any to avoid peer object leaks */ + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + qdf_copy_macaddr(&peerMacAddr, + &sta_ctx->conn_info.bssId); + + } else if (adapter->device_mode == QDF_P2P_GO_MODE) { + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + if (adapter->sta_info[sta_id].in_use) { + hdd_debug("[SSR] deregister STA with ID %d", + sta_id); + hdd_softap_deregister_sta(adapter, + sta_id); + adapter->sta_info[sta_id].in_use = 0; + } + } + } + + hdd_nud_ignore_tracking(adapter, true); + hdd_nud_reset_tracking(adapter); + hdd_nud_flush_work(adapter); + + if (adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_GO_MODE && + adapter->device_mode != QDF_FTM_MODE) + hdd_set_disconnect_status(adapter, false); + + hdd_stop_tsf_sync(adapter); + + hdd_softap_deinit_tx_rx(adapter); + hdd_deregister_tx_flow_control(adapter); + + /* Destroy vdev which will be recreated during reinit. */ + hdd_vdev_destroy(adapter); + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +bool hdd_is_vdev_in_conn_state(struct hdd_adapter *adapter) +{ + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + return hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter)); + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + return (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)); + default: + hdd_err("Device mode %d invalid", adapter->device_mode); + return 0; + } + + return 0; +} + +bool hdd_is_any_interface_open(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + bool close_modules = true; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_info("FTM mode, don't close the module"); + return false; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags) || + test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + hdd_debug("Still other ifaces are up cannot close modules"); + close_modules = false; + break; + } + } + + return close_modules; +} + +bool hdd_is_interface_up(struct hdd_adapter *adapter) +{ + if (test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) + return true; + else + return false; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) \ + && !defined(WITH_BACKPORTS) && !defined(IEEE80211_PRIVACY) +struct cfg80211_bss *hdd_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, const u8 *ssid, + size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); +} +#else +struct cfg80211_bss *hdd_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, const u8 *ssid, + size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); +} +#endif + +#if defined CFG80211_CONNECT_BSS || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +#if defined CFG80211_CONNECT_TIMEOUT_REASON_CODE || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) +/** + * hdd_convert_timeout_reason() - Convert to kernel specific enum + * @timeout_reason: reason for connect timeout + * + * This function is used to convert host timeout + * reason enum to kernel specific enum. + * + * Return: nl timeout enum + */ +static enum nl80211_timeout_reason hdd_convert_timeout_reason( + tSirResultCodes timeout_reason) +{ + switch (timeout_reason) { + case eSIR_SME_JOIN_TIMEOUT_RESULT_CODE: + return NL80211_TIMEOUT_SCAN; + case eSIR_SME_AUTH_TIMEOUT_RESULT_CODE: + return NL80211_TIMEOUT_AUTH; + case eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE: + return NL80211_TIMEOUT_ASSOC; + default: + return NL80211_TIMEOUT_UNSPECIFIED; + } +} + +/** + * hdd_cfg80211_connect_timeout() - API to send connection timeout reason + * @dev: network device + * @bssid: bssid to which we want to associate + * @timeout_reason: reason for connect timeout + * + * This API is used to send connection timeout reason to supplicant + * + * Return: void + */ +static void hdd_cfg80211_connect_timeout(struct net_device *dev, + const u8 *bssid, + tSirResultCodes timeout_reason) +{ + enum nl80211_timeout_reason nl_timeout_reason; + + nl_timeout_reason = hdd_convert_timeout_reason(timeout_reason); + + cfg80211_connect_timeout(dev, bssid, NULL, 0, GFP_KERNEL, + nl_timeout_reason); +} + +/** + * __hdd_connect_bss() - API to send connection status to supplicant + * @dev: network device + * @bssid: bssid to which we want to associate + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: Kernel Flag + * @timeout_reason: reason for connect timeout + * + * Return: void + */ +static void __hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + tSirResultCodes timeout_reason) +{ + enum nl80211_timeout_reason nl_timeout_reason; + + nl_timeout_reason = hdd_convert_timeout_reason(timeout_reason); + + cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp, + nl_timeout_reason); +} +#else +#if defined CFG80211_CONNECT_TIMEOUT || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) +static void hdd_cfg80211_connect_timeout(struct net_device *dev, + const u8 *bssid, + tSirResultCodes timeout_reason) +{ + cfg80211_connect_timeout(dev, bssid, NULL, 0, GFP_KERNEL); +} +#endif + +static void __hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + tSirResultCodes timeout_reason) +{ + cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp); +} +#endif + +/** + * hdd_connect_bss() - API to send connection status to supplicant + * @dev: network device + * @bssid: bssid to which we want to associate + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: Kernel Flag + * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp + * @timeout_reason: reason for connect timeout + * + * The API is a wrapper to send connection status to supplicant + * + * Return: Void + */ +#if defined CFG80211_CONNECT_TIMEOUT || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) +static void hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + if (connect_timeout) + hdd_cfg80211_connect_timeout(dev, bssid, timeout_reason); + else + __hdd_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, + resp_ie_len, status, gfp, timeout_reason); +} +#else +static void hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + __hdd_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, + resp_ie_len, status, gfp, timeout_reason); +} +#endif + +#if defined(WLAN_FEATURE_FILS_SK) +#if (defined(CFG80211_CONNECT_DONE) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)) +#if defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) +/** + * hdd_populate_fils_params() - Populate FILS keys to connect response + * @fils_params: connect response to supplicant + * @fils_kek: FILS kek + * @fils_kek_len: FILS kek length + * @pmk: FILS PMK + * @pmk_len: FILS PMK length + * @pmkid: PMKID + * @fils_seq_num: FILS Seq number + * + * Return: None + */ +static void hdd_populate_fils_params(struct cfg80211_connect_resp_params + *fils_params, const uint8_t *fils_kek, + size_t fils_kek_len, const uint8_t *pmk, + size_t pmk_len, const uint8_t *pmkid, + uint16_t fils_seq_num) +{ + /* Increament seq number to be used for next FILS */ + fils_params->fils_erp_next_seq_num = fils_seq_num + 1; + fils_params->update_erp_next_seq_num = true; + fils_params->fils_kek = fils_kek; + fils_params->fils_kek_len = fils_kek_len; + fils_params->pmk = pmk; + fils_params->pmk_len = pmk_len; + fils_params->pmkid = pmkid; + hdd_debug("FILS erp_next_seq_num:%d", + fils_params->fils_erp_next_seq_num); +} +#else +static inline void hdd_populate_fils_params(struct cfg80211_connect_resp_params + *fils_params, const uint8_t + *fils_kek, size_t fils_kek_len, + const uint8_t *pmk, size_t pmk_len, + const uint8_t *pmkid, + uint16_t fils_seq_num) +{ } +#endif + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +/** + * hdd_populate_fils_params() - Populate FILS keys to connect response + * @fils_params: connect response to supplicant + * @fils_kek: FILS kek + * @fils_kek_len: FILS kek length + * @pmk: FILS PMK + * @pmk_len: FILS PMK length + * @pmkid: PMKID + * @fils_seq_num: FILS Seq number + * + * Return: None + */ +static void hdd_populate_fils_params(struct cfg80211_connect_resp_params + *fils_params, const uint8_t *fils_kek, + size_t fils_kek_len, const uint8_t *pmk, + size_t pmk_len, const uint8_t *pmkid, + uint16_t fils_seq_num) +{ + /* Increament seq number to be used for next FILS */ + fils_params->fils.erp_next_seq_num = fils_seq_num + 1; + fils_params->fils.update_erp_next_seq_num = true; + fils_params->fils.kek = fils_kek; + fils_params->fils.kek_len = fils_kek_len; + fils_params->fils.pmk = pmk; + fils_params->fils.pmk_len = pmk_len; + fils_params->fils.pmkid = pmkid; + hdd_debug("FILS erp_next_seq_num:%d", + fils_params->fils.erp_next_seq_num); +} +#endif /* CFG80211_CONNECT_DONE */ + +#if defined(CFG80211_CONNECT_DONE) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) + +void hdd_update_hlp_info(struct net_device *dev, + struct csr_roam_info *roam_info) +{ + 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 fils_join_rsp_params *roam_fils_params + = roam_info->fils_join_rsp; + struct hdd_adapter *padapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (!roam_fils_params) { + hdd_err("FILS Roam Param NULL"); + return; + } + + if (!roam_fils_params->hlp_data_len) { + hdd_err("FILS HLP Data NULL, len %d", + roam_fils_params->hlp_data_len); + return; + } + + hlp_data = roam_fils_params->hlp_data; + hlp_data_len = roam_fils_params->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 == NULL) { + hdd_err("HLP packet nbuf alloc fails"); + return; + } + + qdf_mem_copy(skb_put(skb, ETH_ALEN), roam_fils_params->dst_mac.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(skb_put(skb, ETH_ALEN), roam_fils_params->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; + + status = hdd_rx_packet_cbk(padapter, skb); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Sending HLP packet fails"); + return; + } + hdd_debug("send HLP packet to netif successfully"); +} + +/** + * hdd_connect_done() - Wrapper API to call cfg80211_connect_done + * @dev: network device + * @bssid: bssid to which we want to associate + * @bss: cfg80211 bss info + * @roam_info: information about connected bss + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: allocation flags + * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp + * @timeout_reason: reason for connect timeout + * + * This API is used as wrapper to send FILS key/sequence number + * params etc. to supplicant in case of FILS connection + * + * Return: None + */ +static void hdd_connect_done(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, + struct csr_roam_info *roam_info, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, u16 status, + gfp_t gfp, bool connect_timeout, + tSirResultCodes timeout_reason) +{ + struct cfg80211_connect_resp_params fils_params; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct fils_join_rsp_params *roam_fils_params = + roam_info->fils_join_rsp; + + qdf_mem_zero(&fils_params, sizeof(fils_params)); + + if (!roam_fils_params) { + fils_params.status = WLAN_STATUS_UNSPECIFIED_FAILURE; + } else { + fils_params.status = status; + fils_params.bssid = bssid; + fils_params.timeout_reason = + hdd_convert_timeout_reason(timeout_reason); + fils_params.req_ie = req_ie; + fils_params.req_ie_len = req_ie_len; + fils_params.resp_ie = resp_ie; + fils_params.resp_ie_len = resp_ie_len; + fils_params.bss = bss; + hdd_populate_fils_params(&fils_params, roam_fils_params->kek, + roam_fils_params->kek_len, + roam_fils_params->fils_pmk, + roam_fils_params->fils_pmk_len, + roam_fils_params->fils_pmkid, + roam_info->fils_seq_num); + hdd_save_gtk_params(adapter, roam_info, false); + } + hdd_debug("FILS indicate connect status %d", fils_params.status); + + cfg80211_connect_done(dev, &fils_params, gfp); + + if (roam_fils_params && roam_fils_params->hlp_data_len) + hdd_update_hlp_info(dev, roam_info); + + /* Clear all the FILS key info */ + if (roam_fils_params && roam_fils_params->fils_pmk) + qdf_mem_free(roam_fils_params->fils_pmk); + if (roam_fils_params) + qdf_mem_free(roam_fils_params); + roam_info->fils_join_rsp = NULL; +} +#else /* CFG80211_CONNECT_DONE */ +static inline void +hdd_connect_done(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, struct csr_roam_info *roam_info, + const u8 *req_ie, size_t req_ie_len, + const u8 *resp_ie, size_t resp_ie_len, u16 status, + gfp_t gfp, bool connect_timeout, + tSirResultCodes timeout_reason) +{ } +#endif +#endif /* WLAN_FEATURE_FILS_SK */ + +#if defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_CONNECT_DONE) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0))) +/** + * hdd_fils_update_connect_results() - API to send fils connection status to + * supplicant. + * @dev: network device + * @bssid: bssid to which we want to associate + * @bss: cfg80211 bss info + * @roam_info: information about connected bss + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: allocation flags + * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp + * @timeout_reason: reason for connect timeout + * + * The API is a wrapper to send connection status to supplicant + * + * Return: 0 if success else failure + */ +static int hdd_fils_update_connect_results(struct net_device *dev, + const u8 *bssid, + struct cfg80211_bss *bss, + struct csr_roam_info *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + hdd_enter(); + if (!roam_info || !roam_info->is_fils_connection) + return -EINVAL; + + hdd_connect_done(dev, bssid, bss, roam_info, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp, connect_timeout, + timeout_reason); + return 0; +} +#else +static inline int hdd_fils_update_connect_results(struct net_device *dev, + const u8 *bssid, + struct cfg80211_bss *bss, + struct csr_roam_info *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + return -EINVAL; +} +#endif + +/** + * hdd_connect_result() - API to send connection status to supplicant + * @dev: network device + * @bssid: bssid to which we want to associate + * @roam_info: information about connected bss + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: Kernel Flag + * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp + * @timeout_reason: reason for connect timeout + * + * The API is a wrapper to send connection status to supplicant + * and allow runtime suspend + * + * Return: Void + */ +void hdd_connect_result(struct net_device *dev, const u8 *bssid, + struct csr_roam_info *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + struct hdd_adapter *padapter = (struct hdd_adapter *) netdev_priv(dev); + struct cfg80211_bss *bss = NULL; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(padapter); + + if (WLAN_STATUS_SUCCESS == status) { + struct ieee80211_channel *chan; + int freq; + int chan_no = roam_info->pBssDesc->channelId; + + if (chan_no <= 14) + freq = ieee80211_channel_to_frequency(chan_no, + HDD_NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(chan_no, + HDD_NL80211_BAND_5GHZ); + + chan = ieee80211_get_channel(padapter->wdev.wiphy, freq); + bss = hdd_cfg80211_get_bss(padapter->wdev.wiphy, chan, bssid, + roam_info->u.pConnectedProfile->SSID.ssId, + roam_info->u.pConnectedProfile->SSID.length); + } + + if (hdd_fils_update_connect_results(dev, bssid, bss, + roam_info, req_ie, req_ie_len, resp_ie, + resp_ie_len, status, gfp, connect_timeout, + timeout_reason) != 0) { + hdd_connect_bss(dev, bssid, bss, req_ie, + req_ie_len, resp_ie, resp_ie_len, + status, gfp, connect_timeout, timeout_reason); + } + + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT); +} +#else +void hdd_connect_result(struct net_device *dev, const u8 *bssid, + struct csr_roam_info *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + struct hdd_adapter *padapter = (struct hdd_adapter *) netdev_priv(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(padapter); + + cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp); + + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT); +} +#endif + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, uint32_t chan, + uint32_t bandwidth) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_mon_set_ch_info *ch_info = &sta_ctx->ch_info; + QDF_STATUS status; + struct qdf_mac_addr bssid; + struct csr_roam_profile roam_profile; + struct ch_params ch_params; + + if (QDF_GLOBAL_MONITOR_MODE != hdd_get_conparam()) { + hdd_err("Not supported, device is not in monitor mode"); + return -EINVAL; + } + + /* Validate Channel */ + if (!WLAN_REG_IS_24GHZ_CH(chan) && !WLAN_REG_IS_5GHZ_CH(chan)) { + hdd_err("Channel %d Not supported", chan); + return -EINVAL; + } + + if (WLAN_REG_IS_24GHZ_CH(chan)) { + if (bandwidth == CH_WIDTH_80MHZ) { + hdd_err("BW80 not possible in 2.4GHz band"); + return -EINVAL; + } + if ((bandwidth != CH_WIDTH_20MHZ) && (chan == 14) && + (bandwidth != CH_WIDTH_MAX)) { + hdd_err("Only BW20 possible on channel 14"); + return -EINVAL; + } + } + + if (WLAN_REG_IS_5GHZ_CH(chan)) { + if ((bandwidth != CH_WIDTH_20MHZ) && (chan == 165) && + (bandwidth != CH_WIDTH_MAX)) { + hdd_err("Only BW20 possible on channel 165"); + return -EINVAL; + } + } + + hdd_debug("Set monitor mode Channel %d", chan); + qdf_mem_zero(&roam_profile, sizeof(roam_profile)); + roam_profile.ChannelInfo.ChannelList = &ch_info->channel; + roam_profile.ChannelInfo.numOfChannels = 1; + roam_profile.phyMode = ch_info->phy_mode; + roam_profile.ch_params.ch_width = bandwidth; + hdd_select_cbmode(adapter, chan, &roam_profile.ch_params); + + qdf_mem_copy(bssid.bytes, adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = bandwidth; + wlan_reg_set_channel_params(hdd_ctx->pdev, chan, 0, &ch_params); + 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, chan, + POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN)) { + hdd_err("Failed to change hw mode"); + return -EINVAL; + } + + status = sme_roam_channel_change_req(hdd_ctx->mac_handle, + bssid, &ch_params, + &roam_profile); + if (status) { + hdd_err("Status: %d Failed to set sme_roam Channel for monitor mode", + status); + } + + adapter->mon_chan = chan; + adapter->mon_bandwidth = bandwidth; + return qdf_status_to_os_return(status); +} +#endif + +#ifdef MSM_PLATFORM +/** + * 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 inline void hdd_stop_p2p_go(struct hdd_adapter *adapter) +{ +} + +/** + * 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) +{ + struct hdd_adapter *adapter; + eConnectionState connState; + + hdd_enter(); + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (!hdd_is_interface_up(adapter)) + continue; + + hdd_debug("[SSR] start adapter with device mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + hdd_wmm_init(adapter); + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + + connState = (WLAN_HDD_GET_STATION_CTX_PTR(adapter)) + ->conn_info.connState; + + hdd_start_station_adapter(adapter); + /* Open the gates for HDD to receive Wext commands */ + adapter->is_link_up_service_needed = false; + + /* Indicate disconnect event to supplicant + * if associated previously + */ + if (eConnectionState_Associated == connState || + eConnectionState_IbssConnected == connState || + eConnectionState_NotConnected == connState || + eConnectionState_IbssDisconnected == connState || + eConnectionState_Disconnecting == connState) { + union iwreq_data wrqu; + + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wireless_send_event(adapter->dev, SIOCGIWAP, + &wrqu, NULL); + adapter->session.station. + hdd_reassoc_scenario = false; + + /* indicate disconnected event to nl80211 */ + wlan_hdd_cfg80211_indicate_disconnect( + adapter->dev, false, + WLAN_REASON_UNSPECIFIED); + } else if (eConnectionState_Connecting == connState) { + /* + * Indicate connect failure to supplicant if we + * were in the process of connecting + */ + hdd_connect_result(adapter->dev, NULL, NULL, + NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL, false, 0); + } + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb, + hdd_tx_flow_control_is_pause); + + hdd_lpass_notify_start(hdd_ctx, adapter); + hdd_nud_ignore_tracking(adapter, false); + break; + + case QDF_SAP_MODE: + if (hdd_ctx->config->sap_internal_restart) + hdd_start_ap_adapter(adapter); + + break; + + case QDF_P2P_GO_MODE: + hdd_delete_sta(adapter); + break; + case QDF_MONITOR_MODE: + hdd_start_station_adapter(adapter); + hdd_set_mon_rx_cb(adapter->dev); + wlan_hdd_set_mon_chan(adapter, adapter->mon_chan, + adapter->mon_bandwidth); + break; + default: + break; + } + /* + * Action frame registered in one adapter which will + * applicable to all interfaces + */ + wlan_hdd_cfg80211_register_frames(adapter); + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (!hdd_is_interface_up(adapter)) + continue; + + if (adapter->device_mode == QDF_P2P_GO_MODE) + hdd_stop_p2p_go(adapter); + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +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_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; +} + +struct hdd_adapter *hdd_get_adapter_by_rand_macaddr( + struct hdd_context *hdd_ctx, tSirMacAddr mac_addr) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE) && + ucfg_p2p_check_random_mac(hdd_ctx->psoc, + adapter->session_id, mac_addr)) + return adapter; + } + + return NULL; +} + +struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx, + tSirMacAddr macAddr) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (!qdf_mem_cmp(adapter->mac_addr.bytes, + macAddr, sizeof(tSirMacAddr))) + return adapter; + } + + return NULL; +} + +struct hdd_adapter *hdd_get_adapter_by_vdev(struct hdd_context *hdd_ctx, + uint32_t vdev_id) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->session_id == vdev_id) + return adapter; + } + + return NULL; +} + +/** + * hdd_get_adapter_by_sme_session_id() - Return adapter with + * the sessionid + * @hdd_ctx: hdd context. + * @sme_session_id: sme session is for the adapter to get. + * + * This function is used to get the adapter with provided session id + * + * Return: adapter pointer if found + * + */ +struct hdd_adapter * +hdd_get_adapter_by_sme_session_id(struct hdd_context *hdd_ctx, + uint32_t sme_session_id) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->session_id == sme_session_id) + return adapter; + } + + return NULL; +} + +struct hdd_adapter *hdd_get_adapter_by_iface_name(struct hdd_context *hdd_ctx, + const char *iface_name) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (!qdf_str_cmp(adapter->dev->name, iface_name)) + return adapter; + } + + 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; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode == mode) + return adapter; + } + + return NULL; +} + +enum QDF_OPMODE hdd_get_device_mode(uint32_t session_id) +{ + 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 QDF_MAX_NO_OF_MODE; + } + + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, session_id); + if (!adapter) { + hdd_err("Invalid HDD adapter"); + return QDF_MAX_NO_OF_MODE; + } + + return adapter->device_mode; +} + +/** + * hdd_get_operating_channel() - 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 number. "0" id the requested device is not found OR it is + * not connected. + */ +uint8_t hdd_get_operating_channel(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode) +{ + struct hdd_adapter *adapter; + uint8_t operatingChannel = 0; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (mode == adapter->device_mode) { + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (hdd_conn_is_connected + (WLAN_HDD_GET_STATION_CTX_PTR + (adapter))) { + operatingChannel = + (WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info. + operationChannel; + } + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + /* softap connection info */ + if (test_bit + (SOFTAP_BSS_STARTED, + &adapter->event_flags)) + operatingChannel = + (WLAN_HDD_GET_AP_CTX_PTR + (adapter))->operating_channel; + break; + default: + break; + } + + /* Found the device of interest. break the loop */ + break; + } + } + + return operatingChannel; +} + +static inline QDF_STATUS hdd_unregister_wext_all_adapters(struct hdd_context * + hdd_ctx) +{ + struct hdd_adapter *adapter; + + hdd_enter(); + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_IBSS_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE || + adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + hdd_unregister_wext(adapter->dev); + } + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_abort_mac_scan_all_adapters(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + + hdd_enter(); + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_IBSS_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE || + adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_id, INVALID_SCAN_ID, + true); + } + } + + 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; + int err; + + hdd_enter(); + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_IBSS_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_exit(); + + return QDF_STATUS_SUCCESS; +} + +#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 + +void hdd_set_disconnect_status(struct hdd_adapter *adapter, bool status) +{ + qdf_mutex_acquire(&adapter->disconnection_status_lock); + adapter->disconnection_in_progress = status; + qdf_mutex_release(&adapter->disconnection_status_lock); + hdd_debug("setting disconnection status: %d", status); +} + +/** + * 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 = hdd_nud_register_netevent_notifier(hdd_ctx); + 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; + +} + +/** + * 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) +{ + hdd_nud_unregister_netevent_notifier(hdd_ctx); + 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(); + + 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; +} + +/** + * hdd_rx_wake_lock_destroy() - Destroy RX wakelock + * @hdd_ctx: HDD context. + * + * Destroy RX wakelock. + * + * Return: None. + */ +static void hdd_rx_wake_lock_destroy(struct hdd_context *hdd_ctx) +{ + qdf_wake_lock_destroy(&hdd_ctx->rx_wake_lock); +} + +/** + * hdd_rx_wake_lock_create() - Create RX wakelock + * @hdd_ctx: HDD context. + * + * Create RX wakelock. + * + * Return: None. + */ +static void hdd_rx_wake_lock_create(struct hdd_context *hdd_ctx) +{ + qdf_wake_lock_create(&hdd_ctx->rx_wake_lock, "qcom_rx_wakelock"); +} + +/** + * 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) +{ + qdf_wake_lock_destroy(&hdd_ctx->monitor_mode_wakelock); + + wlan_hdd_cfg80211_deinit(hdd_ctx->wiphy); + + hdd_sap_context_destroy(hdd_ctx); + + hdd_rx_wake_lock_destroy(hdd_ctx); + + hdd_scan_context_destroy(hdd_ctx); + + qdf_list_destroy(&hdd_ctx->hdd_adapters); + + return 0; +} + +/** + * 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 + */ +static void hdd_context_destroy(struct hdd_context *hdd_ctx) +{ + cds_set_context(QDF_MODULE_ID_HDD, NULL); + + wlan_hdd_deinit_tx_rx_histogram(hdd_ctx); + + hdd_context_deinit(hdd_ctx); + + qdf_mem_free(hdd_ctx->config); + hdd_ctx->config = NULL; + + 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 + +/** + * hdd_wlan_exit() - HDD WLAN exit function + * @hdd_ctx: Pointer to the HDD Context + * + * This is the driver exit point (invoked during rmmod) + * + * Return: None + */ +static void hdd_wlan_exit(struct hdd_context *hdd_ctx) +{ + struct wiphy *wiphy = hdd_ctx->wiphy; + int driver_status; + + hdd_enter(); + + hdd_debugfs_mws_coex_info_deinit(hdd_ctx); + hdd_psoc_idle_timer_stop(hdd_ctx); + + hdd_unregister_notifiers(hdd_ctx); + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + 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_channel_list); + hdd_ctx->last_acs_channel_list = NULL; + hdd_ctx->num_of_channels = 0; + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); +#endif + + mutex_lock(&hdd_ctx->iface_change_lock); + driver_status = hdd_ctx->driver_status; + mutex_unlock(&hdd_ctx->iface_change_lock); + + /* + * 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 (driver_status != DRIVER_MODULES_CLOSED) { + hdd_unregister_wext_all_adapters(hdd_ctx); + /* + * 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); + + hdd_wlan_stop_modules(hdd_ctx, false); + + hdd_bus_bandwidth_deinit(hdd_ctx); + 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->sta_update_info_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_exit_netlink_services(hdd_ctx); + mutex_destroy(&hdd_ctx->iface_change_lock); +#ifdef FEATURE_WLAN_CH_AVOID + mutex_destroy(&hdd_ctx->avoid_freq_lock); +#endif + + driver_status = hdd_objmgr_release_and_destroy_psoc(hdd_ctx); + if (driver_status) + hdd_err("Psoc delete failed"); + + hdd_context_destroy(hdd_ctx); +} + +void __hdd_wlan_exit(void) +{ + struct hdd_context *hdd_ctx; + + hdd_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD Context"); + hdd_exit(); + return; + } + + /* Do all the cleanup before deregistering the driver */ + hdd_wlan_exit(hdd_ctx); + + hdd_exit(); +} + +#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 = (struct hdd_context *) 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_channel_list); + hdd_ctx->last_acs_channel_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; + sme_scan_flush_result(mac_handle); +} +#endif + +#ifdef QCA_HT_2040_COEX +int hdd_wlan_set_ht2040_mode(struct hdd_adapter *adapter, uint16_t sta_id, + struct qdf_mac_addr sta_mac, int channel_type) +{ + int status; + QDF_STATUS qdf_status; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + 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_ht2040_mode(mac_handle, sta_id, sta_mac, + adapter->session_id, channel_type); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Fail to send notification with ht2040 mode"); + return -EINVAL; + } + + return 0; +} +#endif + +/** + * 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 + * @adapter - 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; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC) + return adapter; + } + + 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.alpha2, + 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; +} + +static int hdd_wiphy_init(struct hdd_context *hdd_ctx) +{ + struct wiphy *wiphy; + int ret_val; + + 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 (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 + + /* 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 MSM_PLATFORM +/** + * hdd_display_periodic_stats() - Function to display periodic stats + * @hdd_ctx - handle to hdd context + * @bool data_in_interval - true, if data detected in bw time interval + * + * The periodicity is determined by hdd_ctx->config->periodic_stats_disp_time. + * Stats show up in wlan driver logs. + * + * Returns: None + */ +static inline +void hdd_display_periodic_stats(struct hdd_context *hdd_ctx, + bool data_in_interval) +{ + static u32 counter; + static bool data_in_time_period; + ol_txrx_pdev_handle pdev; + + if (hdd_ctx->config->periodic_stats_disp_time == 0) + return; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + hdd_err("pdev is NULL"); + return; + } + + counter++; + if (data_in_interval) + data_in_time_period = data_in_interval; + + if (counter * hdd_ctx->config->busBandwidthComputeInterval >= + hdd_ctx->config->periodic_stats_disp_time * 1000) { + if (data_in_time_period) { + wlan_hdd_display_txrx_stats(hdd_ctx); + cdp_display_stats(cds_get_context(QDF_MODULE_ID_SOC), + CDP_TXRX_PATH_STATS, + QDF_STATS_VERBOSITY_LEVEL_LOW); + wlan_hdd_display_netif_queue_history + (hdd_ctx, QDF_STATS_VERBOSITY_LEVEL_LOW); + qdf_dp_trace_dump_stats(); + } + counter = 0; + data_in_time_period = false; + } +} + +/** + * hdd_clear_rps_cpu_mask - clear RPS CPU mask for interfaces + * @hdd_ctx: pointer to struct hdd_context + * + * Return: none + */ +static void hdd_clear_rps_cpu_mask(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) + hdd_send_rps_disable_ind(adapter); +} + +/** + * hdd_pld_request_bus_bandwidth() - Function to control bus bandwidth + * @hdd_ctx - handle to hdd context + * @tx_packets - transmit packet count + * @rx_packets - receive packet count + * + * The function controls the bus bandwidth and dynamic control of + * tcp delayed ack configuration + * + * Returns: None + */ + +static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx, + const uint64_t tx_packets, + const uint64_t rx_packets) +{ + u64 total_pkts = tx_packets + rx_packets; + uint64_t temp_tx = 0, avg_rx = 0; + uint64_t no_rx_offload_pkts = 0, avg_no_rx_offload_pkts = 0; + uint64_t rx_offload_pkts = 0, avg_rx_offload_pkts = 0; + enum pld_bus_width_type next_vote_level = PLD_BUS_WIDTH_NONE; + static enum wlan_tp_level next_rx_level = WLAN_SVC_TP_NONE; + enum wlan_tp_level next_tx_level = WLAN_SVC_TP_NONE; + uint32_t delack_timer_cnt = hdd_ctx->config->tcp_delack_timer_count; + uint16_t index = 0; + bool vote_level_change = false; + bool rx_level_change = false; + bool tx_level_change = false; + bool rxthread_high_tput_req = false; + bool dptrace_high_tput_req; + if (total_pkts > hdd_ctx->config->busBandwidthHighThreshold) + next_vote_level = PLD_BUS_WIDTH_HIGH; + else if (total_pkts > hdd_ctx->config->busBandwidthMediumThreshold) + next_vote_level = PLD_BUS_WIDTH_MEDIUM; + else if (total_pkts > hdd_ctx->config->busBandwidthLowThreshold) + next_vote_level = PLD_BUS_WIDTH_LOW; + else + next_vote_level = PLD_BUS_WIDTH_NONE; + + dptrace_high_tput_req = + next_vote_level > PLD_BUS_WIDTH_NONE ? true : false; + + if (hdd_ctx->cur_vote_level != next_vote_level) { + hdd_debug("trigger level %d, tx_packets: %lld, rx_packets: %lld", + next_vote_level, tx_packets, rx_packets); + hdd_ctx->cur_vote_level = next_vote_level; + vote_level_change = true; + pld_request_bus_bandwidth(hdd_ctx->parent_dev, next_vote_level); + if ((next_vote_level == PLD_BUS_WIDTH_LOW) || + (next_vote_level == PLD_BUS_WIDTH_NONE)) { + if (hdd_ctx->hbw_requested) { + pld_remove_pm_qos(hdd_ctx->parent_dev); + hdd_ctx->hbw_requested = false; + } + if (hdd_ctx->dynamic_rps) + hdd_clear_rps_cpu_mask(hdd_ctx); + } else { + if (!hdd_ctx->hbw_requested) { + pld_request_pm_qos(hdd_ctx->parent_dev, 1); + hdd_ctx->hbw_requested = true; + } + if (hdd_ctx->dynamic_rps) + hdd_set_rps_cpu_mask(hdd_ctx); + } + + if (hdd_ctx->config->napi_cpu_affinity_mask) + hdd_napi_apply_throughput_policy(hdd_ctx, + tx_packets, + rx_packets); + + if (rx_packets < hdd_ctx->config->busBandwidthLowThreshold) + hdd_disable_rx_ol_for_low_tput(hdd_ctx, true); + else + hdd_disable_rx_ol_for_low_tput(hdd_ctx, false); + } + +#ifdef CONFIG_DP_TRACE + qdf_dp_trace_apply_tput_policy(dptrace_high_tput_req); +#endif + + /* + * Includes tcp+udp, if perf core is required for tcp, then + * perf core is also required for udp. + */ + no_rx_offload_pkts = hdd_ctx->no_rx_offload_pkt_cnt; + hdd_ctx->no_rx_offload_pkt_cnt = 0; + rx_offload_pkts = rx_packets - no_rx_offload_pkts; + + avg_no_rx_offload_pkts = (no_rx_offload_pkts + + hdd_ctx->prev_no_rx_offload_pkts) / 2; + hdd_ctx->prev_no_rx_offload_pkts = no_rx_offload_pkts; + + avg_rx_offload_pkts = (rx_offload_pkts + + hdd_ctx->prev_rx_offload_pkts) / 2; + hdd_ctx->prev_rx_offload_pkts = rx_offload_pkts; + + avg_rx = avg_no_rx_offload_pkts + avg_rx_offload_pkts; + /* + * 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 (avg_no_rx_offload_pkts > + hdd_ctx->config->busBandwidthHighThreshold) + rxthread_high_tput_req = true; + else + rxthread_high_tput_req = false; + + if (cds_sched_handle_throughput_req(rxthread_high_tput_req)) + hdd_warn("Rx thread high_tput(%d) affinity request failed", + rxthread_high_tput_req); + + /* fine-tuning parameters for RX Flows */ + if (avg_rx > hdd_ctx->config->tcpDelackThresholdHigh) { + if ((hdd_ctx->cur_rx_level != WLAN_SVC_TP_HIGH) && + (++hdd_ctx->rx_high_ind_cnt == delack_timer_cnt)) { + next_rx_level = WLAN_SVC_TP_HIGH; + } + } else { + hdd_ctx->rx_high_ind_cnt = 0; + next_rx_level = WLAN_SVC_TP_LOW; + } + + if (hdd_ctx->cur_rx_level != next_rx_level) { + struct wlan_rx_tp_data rx_tp_data = {0}; + + hdd_debug("TCP DELACK trigger level %d, average_rx: %llu", + next_rx_level, avg_rx); + hdd_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 (hdd_ctx->en_tcp_delack_no_lro) + rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND; + + if (hdd_ctx->config->enable_tcp_adv_win_scale) + rx_tp_data.rx_tp_flags |= TCP_ADV_WIN_SCL; + + rx_tp_data.level = next_rx_level; + wlan_hdd_update_tcp_rx_param(hdd_ctx, &rx_tp_data); + } + + /* fine-tuning parameters for TX Flows */ + temp_tx = (tx_packets + hdd_ctx->prev_tx) / 2; + hdd_ctx->prev_tx = tx_packets; + if (temp_tx > hdd_ctx->config->tcp_tx_high_tput_thres) + next_tx_level = WLAN_SVC_TP_HIGH; + else + next_tx_level = WLAN_SVC_TP_LOW; + + if ((hdd_ctx->config->enable_tcp_limit_output) && + (hdd_ctx->cur_tx_level != next_tx_level)) { + struct wlan_tx_tp_data tx_tp_data = {0}; + + hdd_debug("change TCP TX trigger level %d, average_tx: %llu", + next_tx_level, temp_tx); + hdd_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_hdd_update_tcp_tx_param(hdd_ctx, &tx_tp_data); + } + + index = hdd_ctx->hdd_txrx_hist_idx; + if (vote_level_change || tx_level_change || rx_level_change) { + hdd_ctx->hdd_txrx_hist[index].next_tx_level = next_tx_level; + hdd_ctx->hdd_txrx_hist[index].next_rx_level = next_rx_level; + hdd_ctx->hdd_txrx_hist[index].next_vote_level = next_vote_level; + hdd_ctx->hdd_txrx_hist[index].interval_rx = rx_packets; + hdd_ctx->hdd_txrx_hist[index].interval_tx = tx_packets; + hdd_ctx->hdd_txrx_hist[index].qtime = qdf_get_log_timestamp(); + hdd_ctx->hdd_txrx_hist_idx++; + hdd_ctx->hdd_txrx_hist_idx &= NUM_TX_RX_HISTOGRAM_MASK; + } + + hdd_display_periodic_stats(hdd_ctx, (total_pkts > 0) ? true : false); +} + +#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) +static void __hdd_bus_bw_work_handler(struct work_struct *work) +{ + struct hdd_context *hdd_ctx = container_of(work, struct hdd_context, + bus_bw_work); + struct hdd_adapter *adapter = NULL, *con_sap_adapter = NULL; + uint64_t tx_packets = 0, rx_packets = 0; + uint64_t fwd_tx_packets = 0, fwd_rx_packets = 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; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (hdd_ctx->is_wiphy_suspended) + goto restart_timer; + + hdd_for_each_adapter(hdd_ctx, adapter) { + /* + * Validate magic so we don't end up accessing + * an invalid adapter. + */ + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) + continue; + + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) && + WLAN_HDD_GET_STATION_CTX_PTR(adapter)->conn_info.connState + != eConnectionState_Associated) { + + continue; + } + + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + WLAN_HDD_GET_AP_CTX_PTR(adapter)->ap_active == false) { + + continue; + } + + tx_packets += HDD_BW_GET_DIFF(adapter->stats.tx_packets, + adapter->prev_tx_packets); + rx_packets += HDD_BW_GET_DIFF(adapter->stats.rx_packets, + adapter->prev_rx_packets); + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_IBSS_MODE) { + + ret = cdp_get_intra_bss_fwd_pkts_count( + cds_get_context(QDF_MODULE_ID_SOC), + adapter->session_id, + &fwd_tx_packets, &fwd_rx_packets); + if (ret == A_OK) { + fwd_tx_packets_diff += HDD_BW_GET_DIFF( + fwd_tx_packets, + adapter->prev_fwd_tx_packets); + fwd_rx_packets_diff += HDD_BW_GET_DIFF( + fwd_tx_packets, + adapter->prev_fwd_rx_packets); + } + } + + if (adapter->device_mode == QDF_SAP_MODE) + con_sap_adapter = adapter; + + total_rx += adapter->stats.rx_packets; + total_tx += adapter->stats.tx_packets; + + spin_lock_bh(&hdd_ctx->bus_bw_lock); + adapter->prev_tx_packets = adapter->stats.tx_packets; + adapter->prev_rx_packets = adapter->stats.rx_packets; + adapter->prev_fwd_tx_packets = fwd_tx_packets; + adapter->prev_fwd_rx_packets = fwd_rx_packets; + spin_unlock_bh(&hdd_ctx->bus_bw_lock); + connected = true; + } + + if (!connected) { + hdd_err("bus bandwidth timer running in disconnected state"); + return; + } + + /* add intra bss forwarded tx and rx packets */ + tx_packets += fwd_tx_packets_diff; + rx_packets += fwd_rx_packets_diff; + + if (ucfg_ipa_is_fw_wdi_activated(hdd_ctx->pdev)) { + ucfg_ipa_uc_stat_query(hdd_ctx->pdev, &ipa_tx_packets, + &ipa_rx_packets); + tx_packets += (uint64_t)ipa_tx_packets; + rx_packets += (uint64_t)ipa_rx_packets; + + if (con_sap_adapter) { + con_sap_adapter->stats.tx_packets += ipa_tx_packets; + con_sap_adapter->stats.rx_packets += ipa_rx_packets; + } + + ucfg_ipa_set_perf_level(hdd_ctx->pdev, tx_packets, rx_packets); + ucfg_ipa_uc_stat_request(hdd_ctx->pdev, 2); + } + + hdd_pld_request_bus_bandwidth(hdd_ctx, tx_packets, rx_packets); + +restart_timer: + /* ensure periodic timer should still be running before restarting it */ + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + if (hdd_ctx->bus_bw_timer_running) + qdf_timer_mod(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); +} + +static void hdd_bus_bw_work_handler(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_bus_bw_work_handler(work); + cds_ssr_unprotect(__func__); +} + +/** + * __hdd_bus_bw_cbk() - Bus bandwidth data structure callback. + * @arg: Argument of timer function + * + * Schedule a workqueue in this function where all the processing is done. + * + * Return: None. + */ +static void __hdd_bus_bw_cbk(void *arg) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) arg; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + schedule_work(&hdd_ctx->bus_bw_work); +} + +/** + * hdd_bus_bw_cbk() - Wrapper for bus bw callback for SSR protection. + * @arg: Argument of timer function + * + * Return: None. + */ +static void hdd_bus_bw_cbk(void *arg) +{ + cds_ssr_protect(__func__); + __hdd_bus_bw_cbk(arg); + cds_ssr_unprotect(__func__); +} + +int hdd_bus_bandwidth_init(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + spin_lock_init(&hdd_ctx->bus_bw_lock); + INIT_WORK(&hdd_ctx->bus_bw_work, hdd_bus_bw_work_handler); + hdd_ctx->bus_bw_timer_running = false; + qdf_spinlock_create(&hdd_ctx->bus_bw_timer_lock); + qdf_timer_init(NULL, &hdd_ctx->bus_bw_timer, hdd_bus_bw_cbk, + (void *)hdd_ctx, QDF_TIMER_TYPE_SW); + + hdd_exit(); + + return 0; +} + +void hdd_bus_bandwidth_deinit(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + QDF_BUG(!hdd_ctx->bus_bw_timer_running); + + qdf_timer_free(&hdd_ctx->bus_bw_timer); + qdf_spinlock_destroy(&hdd_ctx->bus_bw_timer_lock); + + hdd_exit(); +} + +#endif /* MSM_PLATFORM */ + +/** + * wlan_hdd_init_tx_rx_histogram() - init tx/rx histogram stats + * @hdd_ctx: hdd context + * + * Return: 0 for success or error code + */ +static int wlan_hdd_init_tx_rx_histogram(struct hdd_context *hdd_ctx) +{ + hdd_ctx->hdd_txrx_hist = qdf_mem_malloc( + (sizeof(struct hdd_tx_rx_histogram) * NUM_TX_RX_HISTOGRAM)); + if (hdd_ctx->hdd_txrx_hist == NULL) { + hdd_err("Failed malloc for hdd_txrx_hist"); + return -ENOMEM; + } + return 0; +} + +/** + * wlan_hdd_deinit_tx_rx_histogram() - deinit tx/rx histogram stats + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_deinit_tx_rx_histogram(struct hdd_context *hdd_ctx) +{ + if (!hdd_ctx || hdd_ctx->hdd_txrx_hist == NULL) + return; + + qdf_mem_free(hdd_ctx->hdd_txrx_hist); + hdd_ctx->hdd_txrx_hist = NULL; +} + +#ifdef WLAN_DEBUG +static uint8_t *convert_level_to_string(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"; + } +} +#endif + + +/** + * wlan_hdd_display_tx_rx_histogram() - display tx rx histogram + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_display_tx_rx_histogram(struct hdd_context *hdd_ctx) +{ + int i; + +#ifdef MSM_PLATFORM + hdd_debug("BW compute Interval: %dms", + hdd_ctx->config->busBandwidthComputeInterval); + hdd_debug("BW High TH: %d BW Med TH: %d BW Low TH: %d", + hdd_ctx->config->busBandwidthHighThreshold, + hdd_ctx->config->busBandwidthMediumThreshold, + hdd_ctx->config->busBandwidthLowThreshold); + hdd_debug("Enable TCP DEL ACK: %d", + hdd_ctx->en_tcp_delack_no_lro); + hdd_debug("TCP DEL High TH: %d TCP DEL Low TH: %d", + hdd_ctx->config->tcpDelackThresholdHigh, + hdd_ctx->config->tcpDelackThresholdLow); + hdd_debug("TCP TX HIGH TP TH: %d (Use to set tcp_output_bytes_limit)", + hdd_ctx->config->tcp_tx_high_tput_thres); +#endif + + hdd_debug("Total entries: %d Current index: %d", + NUM_TX_RX_HISTOGRAM, hdd_ctx->hdd_txrx_hist_idx); + + hdd_debug("[index][timestamp]: interval_rx, interval_tx, bus_bw_level, RX TP Level, TX TP Level"); + + for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) { + /* using hdd_log to avoid printing function name */ + if (hdd_ctx->hdd_txrx_hist[i].qtime > 0) + hdd_debug("[%3d][%15llu]: %6llu, %6llu, %s, %s, %s", + i, hdd_ctx->hdd_txrx_hist[i].qtime, + hdd_ctx->hdd_txrx_hist[i].interval_rx, + hdd_ctx->hdd_txrx_hist[i].interval_tx, + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i]. + next_vote_level), + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i]. + next_rx_level), + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i]. + next_tx_level)); + } +} + +/** + * wlan_hdd_clear_tx_rx_histogram() - clear tx rx histogram + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_clear_tx_rx_histogram(struct hdd_context *hdd_ctx) +{ + hdd_ctx->hdd_txrx_hist_idx = 0; + qdf_mem_zero(hdd_ctx->hdd_txrx_hist, + (sizeof(struct hdd_tx_rx_histogram) * NUM_TX_RX_HISTOGRAM)); +} + +/* 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; + + comb_log_str_size = (ADAP_NETIFQ_LOG_LEN * CSR_ROAM_SESSION_MAX) + 1; + comb_log_str = qdf_mem_malloc(comb_log_str_size); + if (!comb_log_str) { + hdd_err("failed to alloc comb_log_str"); + return; + } + + bytes_written = 0; + + hdd_for_each_adapter(hdd_ctx, adapter) { + 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->session_id, adapter->device_mode, + adapter->pause_map, + qdf_system_ticks_to_msecs(pause), + qdf_system_ticks_to_msecs(total), + temp_str); + + adapter_num++; + } + + /* 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); +} + +/** + * wlan_hdd_display_netif_queue_history() - display netif queue history + * @hdd_ctx: hdd context + * + * Return: none + */ +void +wlan_hdd_display_netif_queue_history(struct hdd_context *hdd_ctx, + enum qdf_stats_verbosity_level verb_lvl) +{ + + struct hdd_adapter *adapter = NULL; + int i; + qdf_time_t total, pause, unpause, curr_time, delta; + + if (verb_lvl == QDF_STATS_VERBOSITY_LEVEL_LOW) { + hdd_display_netif_queue_history_compact(hdd_ctx); + return; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + hdd_debug("Netif queue operation statistics:"); + hdd_debug("Session_id %d device mode %d", + adapter->session_id, adapter->device_mode); + hdd_debug("Current pause_map value %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_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_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_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_debug("Netif queue operation history:"); + hdd_debug("Total entries: %d current index %d", + WLAN_HDD_MAX_HISTORY_ENTRY, adapter->history_index); + + hdd_debug("index: time: action_type: reason_type: pause_map"); + + 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; + hdd_debug("%d: %u: %s: %s: %x", + 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); + } + } +} + +/** + * 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; + + hdd_for_each_adapter(hdd_ctx, adapter) { + 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; + } +} + +#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 + * @phddctx: struct hdd_context structure pointer + * @enable: enable or disable this behaviour + * + * Return: int + */ +static int wlan_hdd_set_wow_pulse(struct hdd_context *phddctx, bool enable) +{ + struct hdd_config *pcfg_ini = phddctx->config; + struct wow_pulse_mode wow_pulse_set_info; + QDF_STATUS status; + + hdd_debug("wow pulse enable flag is %d", enable); + + if (false == phddctx->config->wow_pulse_support) + 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 = + pcfg_ini->wow_pulse_pin; + wow_pulse_set_info.wow_pulse_interval_low = + pcfg_ini->wow_pulse_interval_low; + wow_pulse_set_info.wow_pulse_interval_high = + pcfg_ini->wow_pulse_interval_high; + } 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; + } + hdd_debug("enable %d pin %d low %d high %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); + + 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 *phddctx, bool enable) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_FASTPATH +/** + * hdd_enable_fastpath() - Enable fastpath if enabled in config INI + * @hdd_cfg: hdd config + * @context: lower layer context + * + * Return: none + */ +void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + void *context) +{ + if (hdd_cfg->fastpath_enable) + 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 + +/** + * hdd_switch_sap_channel() - Move SAP to the given channel + * @adapter: AP 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: None + */ +void hdd_switch_sap_channel(struct hdd_adapter *adapter, uint8_t channel, + bool forced) +{ + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + + if (!adapter) { + hdd_err("invalid adapter"); + return; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (!mac_handle) { + hdd_err("invalid MAC handle"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_debug("chan:%d width:%d", + channel, hdd_ap_ctx->sap_config.ch_width_orig); + + policy_mgr_change_sap_channel_with_csa(hdd_ctx->psoc, + adapter->session_id, channel, + hdd_ap_ctx->sap_config.ch_width_orig, 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; + + set_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->event_flags); + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&adapter->session. + ap.vendor_acs_timer)) { + qdf_mc_timer_stop(&adapter->session.ap.vendor_acs_timer); + } + timer_context = (struct hdd_external_acs_timer_context *) + adapter->session.ap.vendor_acs_timer.user_data; + timer_context->reason = reason; + qdf_status = + qdf_mc_timer_start(&adapter->session.ap.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; +} + +#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(uint8_t restart_chan, uint8_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_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 + */ +void hdd_unsafe_channel_restart_sap(struct hdd_context *hdd_ctxt) +{ + struct hdd_adapter *adapter; + uint32_t i; + bool found = false; + uint8_t restart_chan_store[SAP_MAX_NUM_SESSION] = {0}; + uint8_t restart_chan; + + hdd_for_each_adapter(hdd_ctxt, adapter) { + if (!(adapter->device_mode == QDF_SAP_MODE && + adapter->session.ap.sap_config.acs_cfg.acs_mode)) { + hdd_debug("skip device mode:%d acs:%d", + adapter->device_mode, + adapter->session.ap.sap_config. + acs_cfg.acs_mode); + continue; + } + + found = false; + /* + * 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_ctxt->psoc, + adapter->session.ap.operating_channel) && + hdd_ctxt->config->sta_sap_scc_on_lte_coex_chan) + hdd_debug("SAP is allowed on SCC channel, no need to move SAP"); + else { + for (i = 0; i < hdd_ctxt->unsafe_channel_count; i++) { + if (adapter->session.ap.operating_channel == + hdd_ctxt->unsafe_channel_list[i]) { + found = true; + hdd_debug("operating ch:%d is unsafe", + adapter->session.ap.operating_channel); + break; + } + } + } + if (!found) { + hdd_store_sap_restart_channel( + adapter->session.ap.operating_channel, + restart_chan_store); + hdd_debug("ch:%d is safe. no need to change channel", + adapter->session.ap.operating_channel); + continue; + } + + if (hdd_ctxt->config->vendor_acs_support && + hdd_ctxt->config->acs_support_for_dfs_ltecoex) { + hdd_update_acs_timer_reason(adapter, + QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX); + continue; + } + + restart_chan = 0; + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (!restart_chan_store[i]) + continue; + + if (policy_mgr_is_force_scc(hdd_ctxt->psoc) && + WLAN_REG_IS_SAME_BAND_CHANNELS( + restart_chan_store[i], + adapter->session.ap. + operating_channel)) { + restart_chan = restart_chan_store[i]; + break; + } + } + if (!restart_chan) + restart_chan = + wlansap_get_safe_channel_from_pcl_and_acs_range( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + + if (!restart_chan) { + hdd_err("fail to restart SAP"); + } else { + /* + * 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_ctxt->acs_policy.acs_channel = AUTO_CHANNEL_SELECT; + hdd_debug("sending coex indication"); + wlan_hdd_send_svc_nlink_msg(hdd_ctxt->radio_index, + WLAN_SVC_LTE_COEX_IND, NULL, 0); + hdd_debug("driver to start sap: %d", + hdd_ctxt->config->sap_internal_restart); + if (hdd_ctxt->config->sap_internal_restart) { + wlan_hdd_set_sap_csa_reason(hdd_ctxt->psoc, + adapter->session_id, + CSA_REASON_UNSAFE_CHANNEL); + hdd_switch_sap_channel(adapter, restart_chan, + true); + hdd_store_sap_restart_channel( + restart_chan, + restart_chan_store); + } else { + return; + } + } + } +} + +/** + * 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; + + 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); + + for (index = 0; index < unsafe_channel_count; index++) { + hdd_debug("channel %d is not safe", + hdd_ctx->unsafe_channel_list[index]); + + } + +} + +static void hdd_lte_coex_restart_sap(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx) +{ + uint8_t restart_chan; + + restart_chan = wlansap_get_safe_channel_from_pcl_and_acs_range( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + 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_channel = 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->session_id, + CSA_REASON_LTE_COEX); + hdd_switch_sap_channel(adapter, 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) { + hdd_err("No memory for unsafe chan list size%d", + size); + 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) +{ + 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 (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) */ + +/** + * 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; + int i; + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *)frame_ind->frameBuf; + + 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 < CSR_ROAM_SESSION_MAX; i++) { + adapter = + hdd_get_adapter_by_sme_session_id(hdd_ctx, i); + if (adapter) + break; + } + } else if (SME_SESSION_ID_BROADCAST == frame_ind->sessionId) { + hdd_for_each_adapter(hdd_ctx, adapter) { + if ((NULL != adapter) && + (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)) { + __hdd_indicate_mgmt_frame(adapter, + frame_ind->frame_len, + frame_ind->frameBuf, + frame_ind->frameType, + frame_ind->rxChan, + frame_ind->rxRssi); + } + } + adapter = NULL; + } else { + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, + frame_ind->sessionId); + } + + if ((NULL != adapter) && + (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)) + __hdd_indicate_mgmt_frame(adapter, + frame_ind->frame_len, + frame_ind->frameBuf, + frame_ind->frameType, + frame_ind->rxChan, + frame_ind->rxRssi); +} + +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; + + hdd_enter(); + if (!timer_context) { + hdd_err("invlaid 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; + + if (test_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->event_flags)) + clear_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->event_flags); + else + return; + + hdd_err("ACS timeout happened for %s reason %d", + adapter->dev->name, reason); + + switch (reason) { + /* SAP init case */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_INIT: + wlan_sap_set_vendor_acs(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + false); + wlan_hdd_cfg80211_start_acs(adapter); + break; + /* DFS detected on current channel */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS: + wlan_sap_update_next_channel( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), 0, 0); + sme_update_new_channel_event(hdd_ctx->mac_handle, + adapter->session_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) +{ + + if (0 == enable_dfs_chan_scan || 1 == enable_dfs_chan_scan) { + hdd_ctx->config->enableDFSChnlScan = 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) { + hdd_ctx->config->Is11dSupportEnabled = enable_11d; + hdd_debug("Module enable_11d set to %d", enable_11d); + } + + if (!ucfg_ipa_is_present()) { + hdd_ctx->config->IpaConfig = 0; + hdd_debug("IpaConfig override to %d", + hdd_ctx->config->IpaConfig); + } + + if (!hdd_ctx->config->rssi_assoc_reject_enabled || + !hdd_ctx->config->enable_bcast_probe_rsp) { + hdd_debug("OCE disabled, rssi_assoc_reject_enabled: %d enable_bcast_probe_rsp: %d", + hdd_ctx->config->rssi_assoc_reject_enabled, + hdd_ctx->config->enable_bcast_probe_rsp); + hdd_ctx->config->oce_sta_enabled = 0; + } + + if (hdd_ctx->config->action_oui_enable && !ucfg_action_oui_enabled()) { + hdd_ctx->config->action_oui_enable = 0; + hdd_err("Ignore ini: %s, since no action_oui component", + CFG_ENABLE_ACTION_OUI); + } +} + +#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_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) +{ + hdd_qdf_trace_enable(QDF_MODULE_ID_WMI, + hdd_ctx->config->qdf_trace_enable_wdi); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD, + hdd_ctx->config->qdf_trace_enable_hdd); + hdd_qdf_trace_enable(QDF_MODULE_ID_SME, + hdd_ctx->config->qdf_trace_enable_sme); + hdd_qdf_trace_enable(QDF_MODULE_ID_PE, + hdd_ctx->config->qdf_trace_enable_pe); + hdd_qdf_trace_enable(QDF_MODULE_ID_WMA, + hdd_ctx->config->qdf_trace_enable_wma); + hdd_qdf_trace_enable(QDF_MODULE_ID_SYS, + hdd_ctx->config->qdf_trace_enable_sys); + hdd_qdf_trace_enable(QDF_MODULE_ID_QDF, + hdd_ctx->config->qdf_trace_enable_qdf); + hdd_qdf_trace_enable(QDF_MODULE_ID_SAP, + hdd_ctx->config->qdf_trace_enable_sap); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD_SOFTAP, + hdd_ctx->config->qdf_trace_enable_hdd_sap); + hdd_qdf_trace_enable(QDF_MODULE_ID_BMI, + hdd_ctx->config->qdf_trace_enable_bmi); + hdd_qdf_trace_enable(QDF_MODULE_ID_CFG, + hdd_ctx->config->qdf_trace_enable_cfg); + hdd_qdf_trace_enable(QDF_MODULE_ID_EPPING, + hdd_ctx->config->qdf_trace_enable_epping); + hdd_qdf_trace_enable(QDF_MODULE_ID_QDF_DEVICE, + hdd_ctx->config->qdf_trace_enable_qdf_devices); + hdd_qdf_trace_enable(QDF_MODULE_ID_TXRX, + hdd_ctx->config->qdf_trace_enable_txrx); + hdd_qdf_trace_enable(QDF_MODULE_ID_DP, + hdd_ctx->config->qdf_trace_enable_dp); + hdd_qdf_trace_enable(QDF_MODULE_ID_HTC, + hdd_ctx->config->qdf_trace_enable_htc); + hdd_qdf_trace_enable(QDF_MODULE_ID_HIF, + hdd_ctx->config->qdf_trace_enable_hif); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD_SAP_DATA, + hdd_ctx->config->qdf_trace_enable_hdd_sap_data); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD_DATA, + hdd_ctx->config->qdf_trace_enable_hdd_data); + hdd_qdf_trace_enable(QDF_MODULE_ID_WIFIPOS, + hdd_ctx->config->qdf_trace_enable_wifi_pos); + hdd_qdf_trace_enable(QDF_MODULE_ID_NAN, + hdd_ctx->config->qdf_trace_enable_nan); + hdd_qdf_trace_enable(QDF_MODULE_ID_REGULATORY, + hdd_ctx->config->qdf_trace_enable_regulatory); + hdd_qdf_trace_enable(QDF_MODULE_ID_CP_STATS, + hdd_ctx->config->qdf_trace_enable_cp_stats); + + hdd_set_mtrace_for_each(hdd_ctx); + + hdd_cfg_print(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 = CSR_ROAM_SESSION_MAX; + + init_completion(&hdd_ctx->mc_sus_event_var); + init_completion(&hdd_ctx->ready_to_suspend); + init_completion(&hdd_ctx->pdev_cmd_flushed_var); + + qdf_spinlock_create(&hdd_ctx->connection_status_lock); + qdf_spinlock_create(&hdd_ctx->sta_update_info_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; + + hdd_rx_wake_lock_create(hdd_ctx); + + ret = hdd_sap_context_init(hdd_ctx); + if (ret) + goto scan_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 sap_destroy; + + qdf_wake_lock_create(&hdd_ctx->monitor_mode_wakelock, + "monitor_mode_wakelock"); + + return 0; + +sap_destroy: + hdd_sap_context_destroy(hdd_ctx); + +scan_destroy: + hdd_scan_context_destroy(hdd_ctx); + hdd_rx_wake_lock_destroy(hdd_ctx); +list_destroy: + qdf_list_destroy(&hdd_ctx->hdd_adapters); + + return ret; +} + +/* + * enum hdd_block_shutdown - Control if driver allows modem shutdown + * @HDD_UNBLOCK_MODEM_SHUTDOWN: Unblock shutdown + * @HDD_BLOCK_MODEM_SHUTDOWN: Block shutdown + * + * On calling pld_block_shutdown API with the given values, modem + * graceful shutdown is blocked/unblocked. + */ +enum hdd_block_shutdown { + HDD_UNBLOCK_MODEM_SHUTDOWN, + HDD_BLOCK_MODEM_SHUTDOWN, +}; + +/** + * ie_whitelist_attrs_init() - initialize ie whitelisting attributes + * @hdd_ctx: pointer to hdd context + * + * Return: status of initialization + * 0 - success + * negative value - failure + */ +static int ie_whitelist_attrs_init(struct hdd_context *hdd_ctx) +{ + int ret; + + if (!hdd_ctx->config->probe_req_ie_whitelist) + return 0; + + if (!hdd_validate_prb_req_ie_bitmap(hdd_ctx)) { + hdd_err("invalid ie bitmap and ouis: disable ie whitelisting"); + hdd_ctx->config->probe_req_ie_whitelist = false; + return -EINVAL; + } + + /* parse ini string probe req oui */ + ret = hdd_parse_probe_req_ouis(hdd_ctx); + if (ret) { + hdd_err("parsing error: disable ie whitelisting"); + hdd_ctx->config->probe_req_ie_whitelist = false; + } + + return ret; +} + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +static void hdd_set_wlan_logging(struct hdd_context *hdd_ctx) +{ + wlan_logging_set_log_to_console(hdd_ctx->config-> + wlan_logging_to_console); + wlan_logging_set_active(hdd_ctx->config->wlan_logging_enable); +} +#else +static void hdd_set_wlan_logging(struct hdd_context *hdd_ctx) +{ } +#endif + + +static int hdd_mode_change_psoc_idle_shutdown(struct device *dev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + int ret; + + if (!hdd_ctx) + return -EINVAL; + + ret = hdd_wlan_stop_modules(hdd_ctx, true); + if (ret) + hdd_err("Failed to stop modules"); + + is_mode_change_psoc_idle_shutdown = false; + + return ret; +} + +static int hdd_mode_change_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_wlan_start_modules(hdd_ctx, false); +} + +/** + * 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) +{ + struct hdd_context *hdd_ctx = priv; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_info("Psoc idle timeout elapsed; starting psoc shutdown"); + + pld_idle_shutdown(hdd_ctx->parent_dev, hdd_psoc_idle_shutdown); +} + + +static int __hdd_psoc_idle_restart(struct hdd_context *hdd_ctx) +{ + return hdd_wlan_start_modules(hdd_ctx, false); +} + +int hdd_psoc_idle_restart(struct device *dev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) { + hdd_err_rl("hdd ctx is null"); + 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()); + + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status == DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_psoc_idle_timer_stop(hdd_ctx); + hdd_info("Driver modules already Enabled"); + return 0; + } + + mutex_unlock(&hdd_ctx->iface_change_lock); + ret = pld_idle_restart(hdd_ctx->parent_dev, hdd_psoc_idle_restart); + return ret; +} + +int hdd_psoc_idle_shutdown(struct device *dev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + int ret; + + if (is_mode_change_psoc_idle_shutdown) + return hdd_mode_change_psoc_idle_shutdown(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_enter(); + + ret = hdd_wlan_stop_modules(hdd_ctx, false); + if (ret) { + hdd_err("Failed to start modules"); + return ret; + } + + hdd_exit(); + + return 0; +} + +void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx) +{ + uint32_t timeout_ms = hdd_ctx->config->iface_change_wait_time; + enum wake_lock_reason reason = + WIFI_POWER_EVENT_WAKELOCK_IFACE_CHANGE_TIMER; + + if (!timeout_ms) { + hdd_info("psoc idle timer is disabled"); + return; + } + + hdd_debug("Starting psoc idle timer"); + qdf_sched_delayed_work(&hdd_ctx->psoc_idle_timeout_work, timeout_ms); + hdd_prevent_suspend_timeout(timeout_ms, reason); +} + +void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx) +{ + qdf_cancel_delayed_work(&hdd_ctx->psoc_idle_timeout_work); + hdd_debug("Stopped psoc idle timer"); +} + + +/** + * 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 + */ +static 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(sizeof(struct hdd_context)); + if (hdd_ctx == NULL) { + ret = -ENOMEM; + goto err_out; + } + + qdf_create_delayed_work(&hdd_ctx->psoc_idle_timeout_work, + hdd_psoc_idle_timeout_callback, + (void *)hdd_ctx); + + mutex_init(&hdd_ctx->iface_change_lock); + + hdd_ctx->parent_dev = dev; + hdd_ctx->last_scan_reject_session_id = 0xFF; + + hdd_ctx->config = qdf_mem_malloc(sizeof(struct hdd_config)); + if (hdd_ctx->config == NULL) { + hdd_err("Failed to alloc memory for HDD config!"); + ret = -ENOMEM; + goto err_free_hdd_context; + } + + /* Read and parse the qcom_cfg.ini file */ + status = hdd_parse_config_ini(hdd_ctx); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error (status: %d) parsing INI file: %s", status, + WLAN_INI_FILE); + ret = -EINVAL; + goto err_free_config; + } + + ie_whitelist_attrs_init(hdd_ctx); + + hdd_debug("setting timer multiplier: %u", + hdd_ctx->config->timer_multiplier); + qdf_timer_set_multiplier(hdd_ctx->config->timer_multiplier); + + + if (hdd_ctx->config->fhostNSOffload) + hdd_ctx->ns_offload_enable = true; + + cds_set_fatal_event(hdd_ctx->config->enable_fatal_event); + + hdd_override_ini_config(hdd_ctx); + + ret = hdd_context_init(hdd_ctx); + + if (ret) + goto err_free_config; + + /* Uses to enabled logging after SSR */ + hdd_ctx->fw_log_settings.enable = hdd_ctx->config->enable_fw_log; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + goto skip_multicast_logging; + + cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs); + + ret = wlan_hdd_init_tx_rx_histogram(hdd_ctx); + if (ret) + goto err_deinit_hdd_context; + + ret = hdd_init_netlink_services(hdd_ctx); + if (ret) + goto err_deinit_txrx_histogram; + + hdd_set_wlan_logging(hdd_ctx); + +skip_multicast_logging: + hdd_set_trace_level_for_each(hdd_ctx); + + cds_set_context(QDF_MODULE_ID_HDD, hdd_ctx); + + hdd_exit(); + + return hdd_ctx; + +err_deinit_txrx_histogram: + wlan_hdd_deinit_tx_rx_histogram(hdd_ctx); + +err_deinit_hdd_context: + hdd_context_deinit(hdd_ctx); + +err_free_config: + qdf_mem_free(hdd_ctx->config); + +err_free_hdd_context: + mutex_destroy(&hdd_ctx->iface_change_lock); + wiphy_free(hdd_ctx->wiphy); + +err_out: + return ERR_PTR(ret); +} + +#ifdef WLAN_OPEN_P2P_INTERFACE +/** + * hdd_open_p2p_interface - Open P2P interface + * @hdd_ctx: HDD context + * @rtnl_held: True if RTNL lock held + * + * Open P2P interface during probe. This function called to open the P2P + * interface at probe along with STA interface. + * + * Return: 0 on success and errno on failure + */ +static int hdd_open_p2p_interface(struct hdd_context *hdd_ctx, bool rtnl_held) +{ + struct hdd_adapter *adapter; + uint8_t *p2p_dev_addr; + bool is_p2p_locally_administered = false; + + if (hdd_ctx->config->isP2pDeviceAddrAdministrated) { + if (hdd_ctx->num_provisioned_addr && + !(hdd_ctx->provisioned_mac_addr[0].bytes[0] & 0x02)) { + qdf_mem_copy(hdd_ctx->p2p_device_address.bytes, + hdd_ctx->provisioned_mac_addr[0].bytes, + sizeof(tSirMacAddr)); + + /* + * 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)) { + qdf_mem_copy(hdd_ctx->p2p_device_address.bytes, + hdd_ctx->derived_mac_addr[0].bytes, + sizeof(tSirMacAddr)); + /* + * 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) { + p2p_dev_addr = wlan_hdd_get_intf_addr(hdd_ctx, + QDF_P2P_DEVICE_MODE); + if (!p2p_dev_addr) { + hdd_err("Failed to allocate mac_address for p2p_device"); + return -ENOSPC; + } + + qdf_mem_copy(&hdd_ctx->p2p_device_address.bytes[0], + p2p_dev_addr, QDF_MAC_ADDR_SIZE); + } + + adapter = hdd_open_adapter(hdd_ctx, QDF_P2P_DEVICE_MODE, "p2p%d", + &hdd_ctx->p2p_device_address.bytes[0], + NET_NAME_UNKNOWN, rtnl_held); + + if (NULL == adapter) { + hdd_err("Failed to do hdd_open_adapter for P2P Device Interface"); + return -ENOSPC; + } + + return 0; +} +#else +static inline int hdd_open_p2p_interface(struct hdd_context *hdd_ctx, + bool rtnl_held) +{ + return 0; +} +#endif + +static int hdd_open_ocb_interface(struct hdd_context *hdd_ctx, bool rtnl_held) +{ + struct hdd_adapter *adapter; + int ret = 0; + + adapter = hdd_open_adapter(hdd_ctx, QDF_OCB_MODE, "wlanocb%d", + wlan_hdd_get_intf_addr(hdd_ctx, + QDF_OCB_MODE), + NET_NAME_UNKNOWN, rtnl_held); + if (adapter == NULL) { + hdd_err("Failed to open 802.11p interface"); + ret = -ENOSPC; + } + + return ret; +} + +/** + * 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) +{ + QDF_STATUS status; + int ret; + + hdd_enter_dev(adapter->dev); + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + hdd_err("session is already opened, %d", + adapter->session_id); + return qdf_status_to_os_return(QDF_STATUS_SUCCESS); + } + + ret = hdd_vdev_create(adapter, hdd_sme_roam_callback, adapter); + if (ret) { + hdd_err("failed to create vdev: %d", ret); + return ret; + } + status = hdd_init_station_mode(adapter); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error Initializing station mode: %d", status); + return qdf_status_to_os_return(status); + } + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb, + hdd_tx_flow_control_is_pause); + + hdd_exit(); + + return 0; +} + +/** + * hdd_start_ap_adapter()- Start AP Adapter + * @adapter: HDD adapter + * + * 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) +{ + QDF_STATUS status; + bool is_ssr = false; + int ret; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + hdd_err("session is already opened, %d", + adapter->session_id); + return qdf_status_to_os_return(QDF_STATUS_SUCCESS); + } + /* + * 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 (adapter->session.ap.sap_context) { + 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(adapter, wlansap_roam_callback, + adapter->session.ap.sap_context); + if (ret) { + hdd_err("failed to create vdev, status:%d", ret); + hdd_sap_destroy_ctx(adapter); + return ret; + } + + if (adapter->device_mode == QDF_SAP_MODE) + sme_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_ENABLE_DISABLE_RTT_RESPONDER_ROLE, + (bool)(hdd_ctx->config->fine_time_meas_cap & + WMI_FW_AP_RTT_RESPR), + VDEV_CMD); + + status = hdd_init_ap_mode(adapter, is_ssr); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error Initializing the AP mode: %d", status); + return qdf_status_to_os_return(status); + } + + 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_exit(); + return 0; +} + +static int hdd_open_concurrent_interface(struct hdd_context *hdd_ctx, + bool rtnl_held) +{ + struct hdd_adapter *adapter; + + adapter = hdd_open_adapter(hdd_ctx, QDF_STA_MODE, + hdd_ctx->config->enableConcurrentSTA, + wlan_hdd_get_intf_addr(hdd_ctx, + QDF_STA_MODE), + NET_NAME_UNKNOWN, rtnl_held); + + if (!adapter) + return -ENOSPC; + + return 0; +} + +/** + * hdd_open_interfaces - Open all required interfaces + * hdd_ctx: HDD context + * rtnl_held: True if RTNL lock is held + * + * Open all the interfaces like STA, P2P and OCB based on the configuration. + * + * Return: 0 if all interfaces were created, otherwise negative errno + */ +static int hdd_open_interfaces(struct hdd_context *hdd_ctx, bool rtnl_held) +{ + struct hdd_adapter *adapter; + enum QDF_GLOBAL_MODE curr_mode; + int ret; + + curr_mode = hdd_get_conparam(); + /* open monitor mode adapter if con_mode is monitor mode */ + if (curr_mode == QDF_GLOBAL_MONITOR_MODE || + curr_mode == QDF_GLOBAL_FTM_MODE) { + uint8_t session_type = (curr_mode == QDF_GLOBAL_MONITOR_MODE) ? + QDF_MONITOR_MODE : QDF_FTM_MODE; + + adapter = hdd_open_adapter(hdd_ctx, session_type, "wlan%d", + wlan_hdd_get_intf_addr( + hdd_ctx, + session_type), + NET_NAME_UNKNOWN, rtnl_held); + if (!adapter) { + hdd_err("open adapter failed"); + return -ENOSPC; + } + + return 0; + } + + if (hdd_ctx->config->dot11p_mode == WLAN_HDD_11P_STANDALONE) + /* Create only 802.11p interface */ + return hdd_open_ocb_interface(hdd_ctx, rtnl_held); + + adapter = hdd_open_adapter(hdd_ctx, QDF_STA_MODE, "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx, + QDF_STA_MODE), + NET_NAME_UNKNOWN, rtnl_held); + + if (adapter == NULL) + return -ENOSPC; + + if (strlen(hdd_ctx->config->enableConcurrentSTA) != 0) { + ret = hdd_open_concurrent_interface(hdd_ctx, rtnl_held); + if (ret) + hdd_err("Cannot create concurrent STA interface"); + } + + ret = hdd_open_p2p_interface(hdd_ctx, rtnl_held); + if (ret) + goto err_close_adapters; + + /* Open 802.11p Interface */ + if (hdd_ctx->config->dot11p_mode == WLAN_HDD_11P_CONCURRENT) { + ret = hdd_open_ocb_interface(hdd_ctx, rtnl_held); + if (ret) + goto err_close_adapters; + } + + return 0; + +err_close_adapters: + hdd_close_all_adapters(hdd_ctx, rtnl_held); + 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 = + hdd_ctx->config->TxFlowStopQueueThreshold; + cds_cfg->tx_flow_start_queue_offset = + hdd_ctx->config->TxFlowStartQueueOffset; +} +#else +static inline void hdd_txrx_populate_cds_config(struct cds_config_info + *cds_cfg, + struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * hdd_ra_populate_cds_config() - Populate RA filtering cds configuration + * @cds_cfg: CDS Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_ra_populate_cds_config(struct cds_config_info *cds_cfg, + struct hdd_context *hdd_ctx) +{ + cds_cfg->ra_ratelimit_interval = + hdd_ctx->config->RArateLimitInterval; + cds_cfg->is_ra_ratelimit_enabled = + hdd_ctx->config->IsRArateLimitEnabled; +} +#else +static inline void hdd_ra_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; + + cds_cfg = (struct cds_config_info *)qdf_mem_malloc(sizeof(*cds_cfg)); + if (!cds_cfg) { + hdd_err("failed to allocate cds config"); + return -ENOMEM; + } + + cds_cfg->driver_type = QDF_DRIVER_TYPE_PRODUCTION; + if (!hdd_ctx->config->nMaxPsPoll || + !hdd_ctx->config->enablePowersaveOffload) { + cds_cfg->powersave_offload_enabled = + hdd_ctx->config->enablePowersaveOffload; + } else { + if ((hdd_ctx->config->enablePowersaveOffload == + PS_QPOWER_NODEEPSLEEP) || + (hdd_ctx->config->enablePowersaveOffload == + PS_LEGACY_NODEEPSLEEP)) + cds_cfg->powersave_offload_enabled = + PS_LEGACY_NODEEPSLEEP; + else + cds_cfg->powersave_offload_enabled = + PS_LEGACY_DEEPSLEEP; + hdd_info("Qpower disabled in cds config, %d", + cds_cfg->powersave_offload_enabled); + } + cds_cfg->sta_dynamic_dtim = hdd_ctx->config->enableDynamicDTIM; + cds_cfg->sta_mod_dtim = hdd_ctx->config->enableModulatedDTIM; + cds_cfg->sta_maxlimod_dtim = hdd_ctx->config->fMaxLIModulatedDTIM; + cds_cfg->wow_enable = hdd_ctx->config->wowEnable; + + /* + * Copy the DFS Phyerr Filtering Offload status. + * This parameter reflects the value of the + * dfs_phyerr_filter_offload flag as set in the ini. + */ + cds_cfg->dfs_phyerr_filter_offload = + hdd_ctx->config->fDfsPhyerrFilterOffload; + if (hdd_ctx->config->ssdp) + cds_cfg->ssdp = hdd_ctx->config->ssdp; + + cds_cfg->force_target_assert_enabled = + hdd_ctx->config->crash_inject_enabled; + + cds_cfg->enable_mc_list = hdd_ctx->config->fEnableMCAddrList; + cds_cfg->ap_maxoffload_peers = hdd_ctx->config->apMaxOffloadPeers; + + cds_cfg->ap_maxoffload_reorderbuffs = + hdd_ctx->config->apMaxOffloadReorderBuffs; + + cds_cfg->ap_disable_intrabss_fwd = + hdd_ctx->config->apDisableIntraBssFwd; + + cds_cfg->dfs_pri_multiplier = + hdd_ctx->config->dfsRadarPriMultiplier; + cds_cfg->reorder_offload = + hdd_ctx->config->reorderOffloadSupport; + + /* IPA micro controller data path offload resource config item */ + cds_cfg->uc_offload_enabled = ucfg_ipa_uc_is_enabled(); + if (!is_power_of_2(hdd_ctx->config->IpaUcTxBufCount)) { + /* IpaUcTxBufCount should be power of 2 */ + hdd_debug("Round down IpaUcTxBufCount %d to nearest power of 2", + hdd_ctx->config->IpaUcTxBufCount); + hdd_ctx->config->IpaUcTxBufCount = + rounddown_pow_of_two( + hdd_ctx->config->IpaUcTxBufCount); + if (!hdd_ctx->config->IpaUcTxBufCount) { + hdd_err("Failed to round down IpaUcTxBufCount"); + goto exit; + } + hdd_debug("IpaUcTxBufCount rounded down to %d", + hdd_ctx->config->IpaUcTxBufCount); + } + cds_cfg->uc_txbuf_count = hdd_ctx->config->IpaUcTxBufCount; + cds_cfg->uc_txbuf_size = hdd_ctx->config->IpaUcTxBufSize; + if (!is_power_of_2(hdd_ctx->config->IpaUcRxIndRingCount)) { + /* IpaUcRxIndRingCount should be power of 2 */ + hdd_debug("Round down IpaUcRxIndRingCount %d to nearest power of 2", + hdd_ctx->config->IpaUcRxIndRingCount); + hdd_ctx->config->IpaUcRxIndRingCount = + rounddown_pow_of_two( + hdd_ctx->config->IpaUcRxIndRingCount); + if (!hdd_ctx->config->IpaUcRxIndRingCount) { + hdd_err("Failed to round down IpaUcRxIndRingCount"); + goto exit; + } + hdd_debug("IpaUcRxIndRingCount rounded down to %d", + hdd_ctx->config->IpaUcRxIndRingCount); + } + cds_cfg->uc_rxind_ringcount = + hdd_ctx->config->IpaUcRxIndRingCount; + cds_cfg->uc_tx_partition_base = + hdd_ctx->config->IpaUcTxPartitionBase; + cds_cfg->max_scan = hdd_ctx->config->max_scan_count; + + cds_cfg->ip_tcp_udp_checksum_offload = + hdd_ctx->config->enable_ip_tcp_udp_checksum_offload; + cds_cfg->enable_rxthread = hdd_ctx->enable_rxthread; + cds_cfg->ce_classify_enabled = + hdd_ctx->config->ce_classify_enabled; + cds_cfg->apf_packet_filter_enable = + hdd_ctx->config->apf_packet_filter_enable; + cds_cfg->tx_chain_mask_cck = hdd_ctx->config->tx_chain_mask_cck; + cds_cfg->self_gen_frm_pwr = hdd_ctx->config->self_gen_frm_pwr; + cds_cfg->max_station = hdd_ctx->config->maxNumberOfPeers; + cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE; + cds_cfg->flow_steering_enabled = hdd_ctx->config->flow_steering_enable; + cds_cfg->max_msdus_per_rxinorderind = + hdd_ctx->config->max_msdus_per_rxinorderind; + cds_cfg->self_recovery_enabled = hdd_ctx->config->enableSelfRecovery; + cds_cfg->fw_timeout_crash = hdd_ctx->config->fw_timeout_crash; + cds_cfg->active_uc_apf_mode = hdd_ctx->config->active_uc_apf_mode; + cds_cfg->active_mc_bc_apf_mode = hdd_ctx->config->active_mc_bc_apf_mode; + cds_cfg->auto_power_save_fail_mode = + hdd_ctx->config->auto_pwr_save_fail_mode; + + cds_cfg->ito_repeat_count = hdd_ctx->config->ito_repeat_count; + cds_cfg->bandcapability = hdd_ctx->config->nBandCapability; + cds_cfg->delay_before_vdev_stop = + hdd_ctx->config->delay_before_vdev_stop; + + cds_cfg->enable_peer_unmap_conf_support = + hdd_ctx->config->enable_peer_unmap_conf_support; + + hdd_ra_populate_cds_config(cds_cfg, hdd_ctx); + cds_cfg->enable_tx_compl_tsf64 = + hdd_tsf_is_tsf64_tx_set(hdd_ctx); + cds_cfg->enable_three_way_coex_config_legacy = + hdd_ctx->config->enable_three_way_coex_config_legacy; + hdd_txrx_populate_cds_config(cds_cfg, hdd_ctx); + hdd_nan_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; + + user_config = qdf_mem_malloc(sizeof(*user_config)); + if (user_config == NULL) { + hdd_alert("Failed to alloc memory for user_config!"); + return -ENOMEM; + } + + user_config->dot11_mode = hdd_ctx->config->dot11Mode; + user_config->dual_mac_feature_disable = + hdd_ctx->config->dual_mac_feature_disable; + user_config->indoor_channel_support = + hdd_ctx->config->indoor_channel_support; + user_config->is_11d_support_enabled = + hdd_ctx->config->Is11dSupportEnabled; + user_config->is_11h_support_enabled = + hdd_ctx->config->Is11hSupportEnabled; + user_config->optimize_chan_avoid_event = + hdd_ctx->config->goptimize_chan_avoid_event; + user_config->skip_dfs_chnl_in_p2p_search = + hdd_ctx->config->skipDfsChnlInP2pSearch; + user_config->band_capability = hdd_ctx->config->nBandCapability; + 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) +{ + tSmeThermalParams thermal_param; + QDF_STATUS status; + mac_handle_t mac_handle; + + thermal_param.smeThermalMgmtEnabled = + hdd_ctx->config->thermalMitigationEnable; + thermal_param.smeThrottlePeriod = hdd_ctx->config->throttlePeriod; + + thermal_param.sme_throttle_duty_cycle_tbl[0] = + hdd_ctx->config->throttle_dutycycle_level0; + thermal_param.sme_throttle_duty_cycle_tbl[1] = + hdd_ctx->config->throttle_dutycycle_level1; + thermal_param.sme_throttle_duty_cycle_tbl[2] = + hdd_ctx->config->throttle_dutycycle_level2; + thermal_param.sme_throttle_duty_cycle_tbl[3] = + hdd_ctx->config->throttle_dutycycle_level3; + + thermal_param.smeThermalLevels[0].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel0; + thermal_param.smeThermalLevels[0].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel0; + thermal_param.smeThermalLevels[1].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel1; + thermal_param.smeThermalLevels[1].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel1; + thermal_param.smeThermalLevels[2].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel2; + thermal_param.smeThermalLevels[2].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel2; + thermal_param.smeThermalLevels[3].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel3; + thermal_param.smeThermalLevels[3].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel3; + + mac_handle = hdd_ctx->mac_handle; + status = sme_init_thermal_info(mac_handle, thermal_param); + + 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 +#define MAX_PKTLOG_SIZE 16 + +/** + * 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("Pktlog buff size is too large. max value is 16MB.\n"); + 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_vlaue = 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: 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, + uint8_t user_triggered, int size) +{ + struct sir_wifi_start_log start_log; + QDF_STATUS status; + + start_log.ring_id = RING_ID_PER_PACKET_STATS; + start_log.verbose_level = + enable ? 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; + } + + if (enable == true) + hdd_ctx->is_pktlog_enabled = 1; + else + hdd_ctx->is_pktlog_enabled = 0; + + 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(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(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]" MAC_ADDRESS_STR, iter, + MAC_ADDR_ARRAY(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]" MAC_ADDRESS_STR, iter, + MAC_ADDR_ARRAY(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 customMacAddr; + QDF_STATUS status; + + if (hdd_ctx->num_provisioned_addr) + qdf_mem_copy(&customMacAddr, + &hdd_ctx->provisioned_mac_addr[0].bytes[0], + sizeof(tSirMacAddr)); + else + qdf_mem_copy(&customMacAddr, + &hdd_ctx->derived_mac_addr[0].bytes[0], + sizeof(tSirMacAddr)); + status = sme_set_custom_mac_addr(customMacAddr); + 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; + bool update_mac_addr_to_fw = true; + + ret = hdd_platform_wlan_mac(hdd_ctx); + if (hdd_ctx->config->mac_provision || !ret) { + hdd_info("using MAC address from platform driver"); + 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); + update_mac_addr_to_fw = 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."); + cds_rand_get_bytes(0, (uint8_t *)(&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); + } + + if (update_mac_addr_to_fw) { + ret = hdd_update_mac_addr_to_fw(hdd_ctx); + if (ret) + hdd_err("MAC address out-of-sync, ret:%d", ret); + } + return ret; +} + +static int hdd_set_smart_chainmask_enabled(struct hdd_context *hdd_ctx) +{ + int vdev_id = 0; + int param_id = WMI_PDEV_PARAM_SMART_CHAINMASK_SCHEME; + int value = hdd_ctx->config->smart_chainmask_enabled; + int vpdev = PDEV_CMD; + int ret; + + ret = sme_cli_set_command(vdev_id, param_id, value, vpdev); + if (ret) + hdd_err("WMI_PDEV_PARAM_SMART_CHAINMASK_SCHEME failed %d", ret); + + return ret; +} + +static int hdd_set_alternative_chainmask_enabled(struct hdd_context *hdd_ctx) +{ + int vdev_id = 0; + int param_id = WMI_PDEV_PARAM_ALTERNATIVE_CHAINMASK_SCHEME; + int value = hdd_ctx->config->alternative_chainmask_enabled; + int vpdev = PDEV_CMD; + int ret; + + ret = sme_cli_set_command(vdev_id, param_id, value, vpdev); + if (ret) + hdd_err("WMI_PDEV_PARAM_ALTERNATIVE_CHAINMASK_SCHEME failed %d", + ret); + + return ret; +} + +static int hdd_set_ani_enabled(struct hdd_context *hdd_ctx) +{ + int vdev_id = 0; + int param_id = WMI_PDEV_PARAM_ANI_ENABLE; + int value = hdd_ctx->config->ani_enabled; + int vpdev = PDEV_CMD; + int ret; + + ret = sme_cli_set_command(vdev_id, param_id, value, vpdev); + if (ret) + hdd_err("WMI_PDEV_PARAM_ANI_ENABLE failed %d", ret); + + return ret; +} + +/** + * 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; + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + cdp_register_pause_cb(soc, wlan_hdd_txrx_pause_cb); + /* + * Set 802.11p config + * TODO-OCB: This has been temporarily added here to ensure this + * parameter is set in CSR when we init the channel list. This should + * be removed once the 5.9 GHz channels are added to the regulatory + * domain. + */ + hdd_set_dot11p_config(hdd_ctx); + + /* + * 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; + } + + ret = sme_cli_set_command(0, WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS, + hdd_ctx->config->tx_chain_mask_1ss, + PDEV_CMD); + if (0 != ret) { + hdd_err("WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS failed %d", ret); + goto out; + } + + ret = hdd_set_smart_chainmask_enabled(hdd_ctx); + if (ret) + goto out; + + ret = hdd_set_alternative_chainmask_enabled(hdd_ctx); + if (ret) + goto out; + + ret = hdd_set_ani_enabled(hdd_ctx); + if (ret) + goto out; + + ret = sme_cli_set_command(0, WMI_PDEV_PARAM_ARP_AC_OVERRIDE, + hdd_ctx->config->arp_ac_category, + PDEV_CMD); + if (0 != ret) { + hdd_err("WMI_PDEV_PARAM_ARP_AC_OVERRIDE ac: %d ret: %d", + hdd_ctx->config->arp_ac_category, 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; + } + + /* Apply the cfg.ini to cfg.dat */ + if (!hdd_update_config_cfg(hdd_ctx)) { + hdd_err("config update failed"); + ret = -EINVAL; + goto out; + } + + + hdd_init_channel_avoidance(hdd_ctx); + + /* update enable sap mandatory chan list */ + policy_mgr_enable_disable_sap_mandatory_chan_list(hdd_ctx->psoc, + hdd_ctx->config->enable_sap_mandatory_chan_list); +out: + return ret; +} + +/** + * 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; + struct hdd_adapter *adapter; + + hdd_enter(); + + if (hdd_ctx == NULL) { + hdd_err("Invalid HDD context pointer"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, evt->vdev_id); + if (!adapter) { + hdd_err("Cannot find adapter by vdev_id = %d", + evt->vdev_id); + return; + } + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &(adapter->wdev), sizeof(uint32_t) + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("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"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + hdd_debug("Sent P2P_LISTEN_OFFLOAD_STOP event for vdev_id = %d", + evt->vdev_id); +} + +/** + * 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; + + dwelltime_params.is_enabled = + hdd_ctx->config->adaptive_dwell_mode_enabled; + dwelltime_params.dwelltime_mode = + hdd_ctx->config->global_adapt_dwelltime_mode; + dwelltime_params.lpf_weight = + hdd_ctx->config->adapt_dwell_lpf_weight; + dwelltime_params.passive_mon_intval = + hdd_ctx->config->adapt_dwell_passive_mon_intval; + dwelltime_params.wifi_act_threshold = + hdd_ctx->config->adapt_dwell_wifi_act_threshold; + + status = sme_set_adaptive_dwelltime_config(hdd_ctx->mac_handle, + &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 dbs_scan_config[CDS_DBS_SCAN_PARAM_PER_CLIENT + * CDS_DBS_SCAN_CLIENTS_MAX]; + + /* check if DBS is enabled or supported */ + if ((hdd_ctx->config->dual_mac_feature_disable == + DISABLE_DBS_CXN_AND_SCAN) || + (hdd_ctx->config->dual_mac_feature_disable == + 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->WlanAutoShutdown) + 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 +/** + * hdd_set_mws_coex() - Set 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; + + ret = sme_cli_set_command(0, WMI_PDEV_PARAM_MWSCOEX_4G_ALLOW_QUICK_FTDM, + hdd_ctx->config->mws_coex_4g_quick_tdm, + PDEV_CMD); + if (ret) { + hdd_warn("Unable to send MWS-COEX 4G quick FTDM policy"); + return ret; + } + + ret = sme_cli_set_command(0, WMI_PDEV_PARAM_MWSCOEX_SET_5GNR_PWR_LIMIT, + hdd_ctx->config->mws_coex_5g_nr_pwr_limit, + PDEV_CMD); + if (ret) { + hdd_warn("Unable to send MWS-COEX 4G quick FTDM policy"); + return ret; + } + return ret; +} +#else +static int hdd_init_mws_coex(struct hdd_context *hdd_ctx) +{ + return 0; +} +#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) +{ + tSirTxPowerLimit hddtxlimit; + QDF_STATUS status; + struct sme_5g_band_pref_params band_pref_params; + int ret; + mac_handle_t mac_handle; + struct hdd_config *cfg; + + hdd_enter(); + + ret = hdd_update_country_code(hdd_ctx); + if (ret) { + hdd_err("Failed to update country code; errno:%d", ret); + return -EINVAL; + } + + ret = hdd_init_mws_coex(hdd_ctx); + if (ret) + hdd_warn("Error initializing mws-coex"); + + cfg = hdd_ctx->config; + /* FW capabilities received, Set the Dot11 mode */ + mac_handle = hdd_ctx->mac_handle; + sme_setdef_dot11mode(mac_handle); + sme_set_prefer_80MHz_over_160MHz(mac_handle, + hdd_ctx->config->sta_prefer_80MHz_over_160MHz); + sme_set_etsi13_srd_ch_in_master_mode(mac_handle, + cfg-> + etsi13_srd_chan_in_master_mode); + + if (hdd_ctx->config->fIsImpsEnabled) + hdd_set_idle_ps_config(hdd_ctx, true); + else + hdd_set_idle_ps_config(hdd_ctx, false); + + /* Send Enable/Disable data stall detection cmd to FW */ + sme_cli_set_command(0, WMI_PDEV_PARAM_DATA_STALL_DETECT_ENABLE, + hdd_ctx->config->enable_data_stall_det, PDEV_CMD); + + if (hdd_ctx->config->enable_go_cts2self_for_sta) + sme_set_cts2self_for_p2p_go(mac_handle); + + if (sme_set_vc_mode_config(hdd_ctx->config->vc_mode_cfg_bitmap)) + hdd_warn("Error in setting Voltage Corner mode config to FW"); + + if (hdd_rx_ol_init(hdd_ctx)) + 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 (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 = hdd_ctx->config->TxPower2g; + hddtxlimit.txPower5g = hdd_ctx->config->TxPower5g; + 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); + + if (hdd_ctx->config->goptimize_chan_avoid_event) { + status = sme_enable_disable_chanavoidind_event( + mac_handle, 0); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to disable Chan Avoidance Indication"); + return -EINVAL; + } + } + + if (hdd_ctx->config->enable_5g_band_pref) { + band_pref_params.rssi_boost_threshold_5g = + hdd_ctx->config->rssi_boost_threshold_5g; + band_pref_params.rssi_boost_factor_5g = + hdd_ctx->config->rssi_boost_factor_5g; + band_pref_params.max_rssi_boost_5g = + hdd_ctx->config->max_rssi_boost_5g; + band_pref_params.rssi_penalize_threshold_5g = + hdd_ctx->config->rssi_penalize_threshold_5g; + band_pref_params.rssi_penalize_factor_5g = + hdd_ctx->config->rssi_penalize_factor_5g; + band_pref_params.max_rssi_penalize_5g = + hdd_ctx->config->max_rssi_penalize_5g; + sme_set_5g_band_pref(mac_handle, &band_pref_params); + } + + /* 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); + + 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); + + hdd_exit(); + return 0; +} + +/** + * 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_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_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; + + status = cdp_flow_pool_map(cds_get_context(QDF_MODULE_ID_SOC), + cds_get_context(QDF_MODULE_ID_TXRX), + 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); + } +} + +/** + * 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) +{ + cdp_flow_pool_unmap(cds_get_context(QDF_MODULE_ID_SOC), + cds_get_context(QDF_MODULE_ID_TXRX), vdev_id); +} + +/** + * hdd_action_oui_config() - Configure action_oui strings + * @hdd_ctx: pointer to hdd context + * + * This is a HDD wrapper function which invokes ucfg api + * of action_oui component to parse action oui strings. + * + * Return: None + */ +static void hdd_action_oui_config(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint32_t id; + uint8_t *str; + + if (!hdd_ctx->config->action_oui_enable) + return; + + for (id = 0; id < ACTION_OUI_MAXIMUM_ID; id++) { + str = hdd_ctx->config->action_oui_str[id]; + if (!qdf_str_len(str)) + continue; + + status = ucfg_action_oui_parse(hdd_ctx->psoc, str, id); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to parse action_oui str: %u", id); + } +} + +/** + * hdd_action_oui_send() - Send action_oui extensions to firmware + * @hdd_ctx: pointer to hdd context + * + * This is a HDD wrapper function which invokes ucfg api + * of action_oui component to send action oui extensions to firmware. + * + * Return: None + */ +static void hdd_action_oui_send(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!hdd_ctx->config->action_oui_enable) + return; + + status = ucfg_action_oui_send(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to send one or all action_ouis"); +} + +/** + * hdd_configure_cds() - Configure cds modules + * @hdd_ctx: HDD context + * @adapter: Primary adapter 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; + uint32_t num_abg_tx_chains = 0; + uint32_t num_11b_tx_chains = 0; + uint32_t num_11ag_tx_chains = 0; + struct policy_mgr_dp_cbacks dp_cbs = {0}; + qdf_device_t qdf_ctx; + + mac_handle = hdd_ctx->mac_handle; + + hdd_action_oui_send(hdd_ctx); + + if (hdd_ctx->config->is_force_1x1_enable) + sme_cli_set_command(0, (int)WMI_PDEV_PARAM_SET_IOT_PATTERN, + 1, PDEV_CMD); + /* set chip power save failure detected callback */ + sme_set_chip_pwr_save_fail_cb(mac_handle, + hdd_chip_pwr_save_fail_detected_cb); + + if (hdd_ctx->config->max_mpdus_inampdu) { + set_value = hdd_ctx->config->max_mpdus_inampdu; + sme_cli_set_command(0, (int)WMI_PDEV_PARAM_MAX_MPDUS_IN_AMPDU, + set_value, PDEV_CMD); + } + + if (hdd_ctx->config->enable_rts_sifsbursting) { + set_value = hdd_ctx->config->enable_rts_sifsbursting; + sme_cli_set_command(0, + (int)WMI_PDEV_PARAM_ENABLE_RTS_SIFS_BURSTING, + set_value, PDEV_CMD); + } + + if (hdd_ctx->config->sap_get_peer_info) { + set_value = hdd_ctx->config->sap_get_peer_info; + sme_cli_set_command(0, + (int)WMI_PDEV_PARAM_PEER_STATS_INFO_ENABLE, + set_value, PDEV_CMD); + } + + num_11b_tx_chains = hdd_ctx->config->num_11b_tx_chains; + num_11ag_tx_chains = hdd_ctx->config->num_11ag_tx_chains; + if (!hdd_ctx->config->enable2x2) { + 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); + sme_cli_set_command(0, (int)WMI_PDEV_PARAM_ABG_MODE_TX_CHAIN_NUM, + num_abg_tx_chains, PDEV_CMD); + + 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. + */ + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) { + hdd_err("QDF device context is NULL"); + goto out; + } + + if (ucfg_ipa_uc_ol_init(hdd_ctx->pdev, qdf_ctx)) { + hdd_err("Failed to setup pipes"); + 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; + + if (hdd_ctx->ol_enable) + dp_cbs.hdd_disable_rx_ol_in_concurrency = + hdd_disable_rx_ol_in_concurrency; + dp_cbs.hdd_set_rx_mode_rps_cb = hdd_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; + 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"); + + if (0 != wlan_hdd_set_wow_pulse(hdd_ctx, true)) + hdd_debug("Failed to set wow pulse"); + + sme_cli_set_command(0, WMI_PDEV_PARAM_GCMP_SUPPORT_ENABLE, + hdd_ctx->config->gcmp_enabled, PDEV_CMD); + sme_cli_set_command(0, WMI_PDEV_AUTO_DETECT_POWER_FAILURE, + hdd_ctx->config->auto_pwr_save_fail_mode, PDEV_CMD); + + + if (hdd_ctx->config->enable_phy_reg_retention) + wma_cli_set_command(0, WMI_PDEV_PARAM_FAST_PWR_TRANSITION, + hdd_ctx->config->enable_phy_reg_retention, PDEV_CMD); + + return 0; + +cds_disable: + cds_disable(hdd_ctx->psoc); + +out: + return -EINVAL; +} + +/** + * 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(); + + /* 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; +} + +#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 + +/** + * hdd_wlan_stop_modules - Single driver state machine for stoping 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: 0 for success; non-zero for failure + */ +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 active_threads; + int debugfs_threads; + struct target_psoc_info *tgt_hdl; + + hdd_enter(); + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) { + hdd_err("QDF device context NULL"); + return -EINVAL; + } + + mutex_lock(&hdd_ctx->iface_change_lock); + hdd_ctx->stop_modules_in_progress = true; + cds_set_module_stop_in_progress(true); + + active_threads = cds_return_external_threads_count(); + debugfs_threads = hdd_return_debugfs_threads_count(); + + if (active_threads > 0 || debugfs_threads > 0 || + hdd_ctx->is_wiphy_suspended) { + hdd_warn("External threads %d, Debugfs threads %d, wiphy suspend %d", + active_threads, debugfs_threads, + hdd_ctx->is_wiphy_suspended); + + if (active_threads) + cds_print_external_threads(); + + if (IS_IDLE_STOP && !ftm_mode) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_psoc_idle_timer_start(hdd_ctx); + hdd_ctx->stop_modules_in_progress = false; + cds_set_module_stop_in_progress(false); + + return 0; + } + } + + 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_info("Wlan transitioning (CLOSED <- ENABLED)"); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) + break; + + hdd_disable_power_management(); + 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_sysfs_destroy_powerstats_interface(); + hdd_sysfs_destroy_version_interface(); + hdd_sysfs_destroy_driver_root_obj(); + hdd_debug("Closing CDS modules!"); + + qdf_status = cds_post_disable(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to process post CDS disable Modules! :%d", + qdf_status); + ret = -EINVAL; + QDF_ASSERT(0); + } + + /* 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); + } + + 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); + + 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); + } + + /* + * 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) { + hdd_err("Hif context is Null"); + ret = -EINVAL; + } + + if (hdd_ctx->target_hw_name) { + qdf_mem_free(hdd_ctx->target_hw_name); + hdd_ctx->target_hw_name = NULL; + } + + hdd_hif_close(hdd_ctx, hif_ctx); + + ol_cds_free(); + + if (IS_IDLE_STOP && cds_is_target_ready()) { + 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_check_for_leaks(hdd_ctx, is_recovery_stop); + hdd_debug_domain_set(QDF_DEBUG_DOMAIN_INIT); + + /* Once the firmware sequence is completed reset this flag */ + hdd_ctx->imps_enabled = false; + hdd_ctx->driver_status = DRIVER_MODULES_CLOSED; + hdd_info("Wlan transitioned (now CLOSED)"); + +done: + hdd_ctx->stop_modules_in_progress = false; + cds_set_module_stop_in_progress(false); + mutex_unlock(&hdd_ctx->iface_change_lock); + + hdd_exit(); + + return ret; +} + + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +/** + * hdd_state_info_dump() - prints state information of hdd layer + * @buf: 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 *hdd_sta_ctx; + struct hdd_adapter *adapter; + uint16_t len = 0; + char *buf = *buf_ptr; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Failed to get hdd context "); + 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(hdd_ctx, adapter) { + if (adapter->dev) + 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: + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + len += scnprintf(buf + len, *size - len, + "\n connState: %d", + hdd_sta_ctx->conn_info.connState); + break; + + default: + break; + } + } + + *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 CONFIG_DP_TRACE +void hdd_dp_trace_init(struct hdd_config *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; + uint8_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; + + if (!config->enable_dp_trace) { + hdd_err("dp trace is disabled from ini"); + return; + } + + hdd_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 = GET_BW_COMPUTE_INTV(config); + if (bw_compute_interval <= 1000 && bw_compute_interval > 0) + thresh_time_limit = 1000 / bw_compute_interval; + else if (bw_compute_interval > 1000) { + hdd_err("busBandwidthComputeInterval > 1000, using 1000"); + thresh_time_limit = 1; + } else + hdd_err("busBandwidthComputeInterval is 0, using defaults"); + + switch (num_entries) { + case 4: + proto_bitmap = config_params[3]; + /* fall through */ + case 3: + verbosity = config_params[2]; + /* fall through */ + case 2: + thresh = config_params[1]; + /* fall through */ + case 1: + live_mode = config_params[0]; + /* fall through */ + default: + hdd_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); + +} +#endif + +#ifdef DISABLE_CHANNEL_LIST +static int wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) +{ + return qdf_mutex_create(&hdd_ctx->cache_channel_lock); +} +#else +static int wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +/** + * hdd_wlan_startup() - HDD init function + * @dev: Pointer to the underlying device + * + * This is the driver startup code executed once a WLAN device has been detected + * + * Return: 0 for success, < 0 for failure + */ +int hdd_wlan_startup(struct device *dev) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx; + int ret; + bool rtnl_held; + mac_handle_t mac_handle; + + hdd_enter(); + + hdd_ctx = hdd_context_create(dev); + + if (IS_ERR(hdd_ctx)) + return PTR_ERR(hdd_ctx); + + ret = hdd_objmgr_create_and_store_psoc(hdd_ctx, + DEFAULT_PSOC_ID); + if (ret) { + hdd_err("Psoc creation fails!"); + QDF_BUG(0); + goto err_hdd_free_context; + } + + hdd_action_oui_config(hdd_ctx); + + qdf_nbuf_init_replenish_timer(); + + ret = wlan_hdd_cache_chann_mutex_create(hdd_ctx); + if (QDF_IS_STATUS_ERROR(ret)) + goto err_hdd_free_context; + +#ifdef FEATURE_WLAN_CH_AVOID + mutex_init(&hdd_ctx->avoid_freq_lock); +#endif + + osif_request_manager_init(); + qdf_atomic_init(&hdd_ctx->con_mode_flag); + hdd_driver_memdump_init(); + hdd_bus_bandwidth_init(hdd_ctx); + + ret = hdd_wlan_start_modules(hdd_ctx, false); + if (ret) { + hdd_err("Failed to start modules: %d", ret); + goto err_memdump_deinit; + } + + wlan_hdd_update_wiphy(hdd_ctx); + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + hdd_ctx->mac_handle = mac_handle; + if (!mac_handle) { + hdd_err("Mac Handle is null"); + goto err_stop_modules; + } + + ret = hdd_wiphy_init(hdd_ctx); + if (ret) { + hdd_err("Failed to initialize wiphy: %d", ret); + goto err_stop_modules; + } + + hdd_dp_trace_init(hdd_ctx->config); + + ret = hdd_initialize_mac_address(hdd_ctx); + if (ret) { + hdd_err("MAC initializtion failed: %d", ret); + goto err_wiphy_unregister; + } + + ret = register_netdevice_notifier(&hdd_netdev_notifier); + if (ret) { + hdd_err("register_netdevice_notifier failed: %d", ret); + goto err_wiphy_unregister; + } + + rtnl_held = hdd_hold_rtnl_lock(); + + ret = hdd_open_interfaces(hdd_ctx, rtnl_held); + if (ret) { + hdd_err("Failed to open interfaces: %d", ret); + goto err_release_rtnl_lock; + } + + hdd_release_rtnl_lock(); + rtnl_held = false; + + wlan_hdd_update_11n_mode(hdd_ctx->config); + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + status = qdf_mc_timer_init(&hdd_ctx->skip_acs_scan_timer, + QDF_TIMER_TYPE_SW, + hdd_skip_acs_scan_timer_handler, + (void *)hdd_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to init ACS Skip timer"); + qdf_spinlock_create(&hdd_ctx->acs_skip_lock); +#endif + + hdd_lpass_notify_wlan_version(hdd_ctx); + + if (hdd_ctx->rps) + hdd_set_rps_cpu_mask(hdd_ctx); + + ret = hdd_register_notifiers(hdd_ctx); + if (ret) + goto err_close_adapters; + + status = wlansap_global_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_unregister_notifiers(hdd_ctx); + goto err_close_adapters; + } + + if (hdd_ctx->config->fIsImpsEnabled) + hdd_set_idle_ps_config(hdd_ctx, true); + else + hdd_set_idle_ps_config(hdd_ctx, false); + + if (QDF_GLOBAL_FTM_MODE != hdd_get_conparam()) + hdd_psoc_idle_timer_start(hdd_ctx); + + hdd_debugfs_mws_coex_info_init(hdd_ctx); + goto success; + +err_close_adapters: + hdd_close_all_adapters(hdd_ctx, rtnl_held); + +err_release_rtnl_lock: + if (rtnl_held) + hdd_release_rtnl_lock(); + + unregister_netdevice_notifier(&hdd_netdev_notifier); + +err_wiphy_unregister: + wiphy_unregister(hdd_ctx->wiphy); + +err_stop_modules: + hdd_wlan_stop_modules(hdd_ctx, false); + +err_memdump_deinit: + hdd_bus_bandwidth_deinit(hdd_ctx); + hdd_driver_memdump_deinit(); + + osif_request_manager_deinit(); + hdd_exit_netlink_services(hdd_ctx); + + hdd_objmgr_release_and_destroy_psoc(hdd_ctx); + +err_hdd_free_context: + if (cds_is_fw_down()) + hdd_err("Not setting the complete event as fw is down"); + else + hdd_start_complete(ret); + + qdf_nbuf_deinit_replenish_timer(); + hdd_context_destroy(hdd_ctx); + return ret; + +success: + hdd_exit(); + return 0; +} + +/** + * 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; +} + +void hdd_get_nud_stats_cb(void *data, struct rsp_stats *rsp, void *context) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)data; + int status; + struct hdd_adapter *adapter = NULL; + struct osif_request *request = NULL; + + hdd_enter(); + + if (!rsp) { + hdd_err("data is null"); + return; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + return; + + request = osif_request_get(context); + if (!request) { + hdd_err("obselete request"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, rsp->vdev_id); + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("Invalid adapter or adapter has invalid magic"); + osif_request_put(request); + return; + } + + hdd_debug("rsp->arp_req_enqueue :%x", rsp->arp_req_enqueue); + hdd_debug("rsp->arp_req_tx_success :%x", rsp->arp_req_tx_success); + hdd_debug("rsp->arp_req_tx_failure :%x", rsp->arp_req_tx_failure); + hdd_debug("rsp->arp_rsp_recvd :%x", rsp->arp_rsp_recvd); + hdd_debug("rsp->out_of_order_arp_rsp_drop_cnt :%x", + rsp->out_of_order_arp_rsp_drop_cnt); + hdd_debug("rsp->dad_detected :%x", rsp->dad_detected); + hdd_debug("rsp->connect_status :%x", rsp->connect_status); + hdd_debug("rsp->ba_session_establishment_status :%x", + rsp->ba_session_establishment_status); + + adapter->hdd_stats.hdd_arp_stats.rx_fw_cnt = rsp->arp_rsp_recvd; + adapter->dad |= rsp->dad_detected; + adapter->con_status = rsp->connect_status; + + /* Flag true indicates connectivity check stats present. */ + if (rsp->connect_stats_present) { + hdd_debug("rsp->tcp_ack_recvd :%x", rsp->tcp_ack_recvd); + hdd_debug("rsp->icmpv4_rsp_recvd :%x", rsp->icmpv4_rsp_recvd); + adapter->hdd_stats.hdd_tcp_stats.rx_fw_cnt = rsp->tcp_ack_recvd; + adapter->hdd_stats.hdd_icmpv4_stats.rx_fw_cnt = + rsp->icmpv4_rsp_recvd; + } + + osif_request_complete(request); + osif_request_put(request); + + hdd_exit(); +} + +/** + * 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_nan_register_callback(mac_handle, + wlan_hdd_cfg80211_nan_callback); + 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_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); + /* print error and not block the startup process */ + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set lost link info callback failed"); + + wlan_hdd_register_cp_stats_cb(hdd_ctx); + + 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_congestion_register_callback(mac_handle, + hdd_update_cca_info_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set congestion callback failed"); + + 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"); + + 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_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_register_callback(mac_handle, + wlan_hdd_cfg80211_stats_ext_callback); + + sme_nan_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"); + + sme_deregister_oem_data_rsp_callback(mac_handle); + + hdd_exit(); +} + +/** + * hdd_softap_sta_deauth() - handle deauth req from HDD + * @adapter: Pointer to the HDD + * @enable: bool value + * + * 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 *pDelStaParams) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + + hdd_enter(); + + /* Ignore request to deauth bcmc station */ + if (pDelStaParams->peerMacAddr.bytes[0] & 0x1) + return qdf_status; + + qdf_status = + wlansap_deauth_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pDelStaParams); + + hdd_exit(); + return qdf_status; +} + +/** + * hdd_softap_sta_disassoc() - take counter measure to handle deauth req from HDD + * @adapter: Pointer to the HDD + * @p_del_sta_params: 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 *pDelStaParams) +{ + hdd_enter(); + + /* Ignore request to disassoc bcmc station */ + if (pDelStaParams->peerMacAddr.bytes[0] & 0x1) + return; + + wlansap_disassoc_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pDelStaParams); +} + +/** + * hdd_issta_p2p_clientconnected() - check if sta or p2p client is connected + * @hdd_ctx: HDD Context + * + * API to find if there is any STA or P2P-Client is connected + * + * Return: true if connected; false otherwise + */ +QDF_STATUS hdd_issta_p2p_clientconnected(struct hdd_context *hdd_ctx) +{ + return sme_is_sta_p2p_client_connected(hdd_ctx->mac_handle); +} + +void wlan_hdd_disable_roaming(struct hdd_adapter *cur_adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(cur_adapter); + struct hdd_adapter *adapter = NULL; + struct csr_roam_profile *roam_profile; + struct hdd_station_ctx *sta_ctx; + + if (!policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) { + hdd_debug("No active sta session"); + return; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + roam_profile = hdd_roam_profile(adapter); + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (cur_adapter->session_id != adapter->session_id && + adapter->device_mode == QDF_STA_MODE && + hdd_conn_is_connected(sta_ctx)) { + hdd_debug("%d Disable roaming", adapter->session_id); + sme_stop_roaming(hdd_ctx->mac_handle, + adapter->session_id, + ecsr_driver_disabled); + } + } +} + +void wlan_hdd_enable_roaming(struct hdd_adapter *cur_adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(cur_adapter); + struct hdd_adapter *adapter = NULL; + struct csr_roam_profile *roam_profile; + struct hdd_station_ctx *sta_ctx; + + if (!policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) { + hdd_debug("No active sta session"); + return; + } + + hdd_for_each_adapter(hdd_ctx, adapter) { + roam_profile = hdd_roam_profile(adapter); + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (cur_adapter->session_id != adapter->session_id && + adapter->device_mode == QDF_STA_MODE && + hdd_conn_is_connected(sta_ctx)) { + hdd_debug("%d Enable roaming", adapter->session_id); + sme_start_roaming(hdd_ctx->mac_handle, + adapter->session_id, + REASON_DRIVER_ENABLED); + } + } +} + +/** + * 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 == NULL) + 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; + bool ap_connected = false, sta_connected = false; + mac_handle_t mac_handle; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) + return; + + if (hdd_ctx->config->WlanAutoShutdown == 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)) { + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode == QDF_STA_MODE) { + if (WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState == + eConnectionState_Associated) { + sta_connected = true; + break; + } + } + + if (adapter->device_mode == QDF_SAP_MODE) { + if (WLAN_HDD_GET_AP_CTX_PTR(adapter)-> + ap_active == true) { + ap_connected = true; + break; + } + } + } + } + + 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->WlanAutoShutdown) + != 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->WlanAutoShutdown); +} +#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, *con_sap_adapter; + + con_sap_adapter = NULL; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter && ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) && + adapter != this_sap_adapter) { + if (check_start_bss) { + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)) { + con_sap_adapter = adapter; + break; + } + } else { + con_sap_adapter = adapter; + break; + } + } + } + + return con_sap_adapter; +} + +#ifdef MSM_PLATFORM +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; +} + +static inline bool hdd_adapter_is_ap(struct hdd_adapter *adapter) +{ + return adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE; +} + +static bool hdd_any_adapter_is_assoc(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (hdd_adapter_is_sta(adapter) && + WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState == eConnectionState_Associated) { + return true; + } + + if (hdd_adapter_is_ap(adapter) && + WLAN_HDD_GET_AP_CTX_PTR(adapter)->ap_active) { + return true; + } + } + + return false; +} + +static bool hdd_bus_bw_compute_timer_is_running(struct hdd_context *hdd_ctx) +{ + bool is_running; + + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + is_running = hdd_ctx->bus_bw_timer_running; + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); + + return is_running; +} + +static void __hdd_bus_bw_compute_timer_start(struct hdd_context *hdd_ctx) +{ + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + hdd_ctx->bus_bw_timer_running = true; + qdf_timer_start(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); +} + +void hdd_bus_bw_compute_timer_start(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hdd_exit(); + return; + } + + if (hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already started"); + return; + } + + __hdd_bus_bw_compute_timer_start(hdd_ctx); + + hdd_exit(); +} + +void hdd_bus_bw_compute_timer_try_start(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + if (hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already started"); + return; + } + + if (hdd_any_adapter_is_assoc(hdd_ctx)) + __hdd_bus_bw_compute_timer_start(hdd_ctx); + + hdd_exit(); +} + +static void __hdd_bus_bw_compute_timer_stop(struct hdd_context *hdd_ctx) +{ + ucfg_ipa_set_perf_level(hdd_ctx->pdev, 0, 0); + + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + hdd_ctx->bus_bw_timer_running = false; + qdf_timer_sync_cancel(&hdd_ctx->bus_bw_timer); + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); + + /* work callback is long running; flush outside of lock */ + cancel_work_sync(&hdd_ctx->bus_bw_work); + hdd_reset_tcp_delack(hdd_ctx); +} + +void hdd_bus_bw_compute_timer_stop(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + if (!hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already stopped"); + return; + } + + __hdd_bus_bw_compute_timer_stop(hdd_ctx); + + hdd_exit(); +} + +void hdd_bus_bw_compute_timer_try_stop(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + if (!hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already stopped"); + return; + } + + if (!hdd_any_adapter_is_assoc(hdd_ctx)) + __hdd_bus_bw_compute_timer_stop(hdd_ctx); + + hdd_exit(); +} +#endif + +/** + * wlan_hdd_check_custom_con_channel_rules() - This function checks the sap's + * and sta's operating channel. + * @sta_adapter: Describe the first argument to foobar. + * @ap_adapter: Describe the second argument to foobar. + * @roam_profile: Roam profile of AP to which STA wants to connect. + * @concurrent_chnl_same: If both SAP and STA channels are same then + * set this flag to true else false. + * + * This function checks the sap's operating channel and sta's operating channel. + * if both are same then it will return false else it will restart the sap in + * sta's channel and return true. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + */ +QDF_STATUS +wlan_hdd_check_custom_con_channel_rules(struct hdd_adapter *sta_adapter, + struct hdd_adapter *ap_adapter, + struct csr_roam_profile *roam_profile, + tScanResultHandle *scan_cache, + bool *concurrent_chnl_same) +{ + struct hdd_ap_ctx *hdd_ap_ctx; + uint8_t channel_id; + QDF_STATUS status; + enum QDF_OPMODE device_mode = ap_adapter->device_mode; + *concurrent_chnl_same = true; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + status = + sme_get_ap_channel_from_scan_cache(roam_profile, + scan_cache, + &channel_id); + if (QDF_STATUS_SUCCESS == status) { + if ((QDF_SAP_MODE == device_mode) && + (channel_id < SIR_11A_CHANNEL_BEGIN)) { + if (hdd_ap_ctx->operating_channel != channel_id) { + *concurrent_chnl_same = false; + hdd_debug("channels are different"); + } + } else if ((QDF_P2P_GO_MODE == device_mode) && + (channel_id >= SIR_11A_CHANNEL_BEGIN)) { + if (hdd_ap_ctx->operating_channel != channel_id) { + *concurrent_chnl_same = false; + hdd_debug("channels are different"); + } + } + } else { + /* + * Lets handle worst case scenario here, Scan cache lookup is + * failed so we have to stop the SAP to avoid any channel + * discrepancy between SAP's channel and STA's channel. + * Return the status as failure so caller function could know + * that scan look up is failed. + */ + hdd_err("Finding AP from scan cache failed"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * 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 (NULL == ap_adapter) { + hdd_err("ap_adapter is NULL here"); + return; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + 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->event_flags)) { + wlan_hdd_del_station(ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + 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_for_event_completion(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_START_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->event_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + ap_adapter->device_mode, + ap_adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, ap_adapter->device_mode, + false); + hdd_debug("SAP Stop Success"); + } else { + hdd_err("Can't stop ap because its not started"); + } + mutex_unlock(&hdd_ctx->sap_lock); +} + +/** + * wlan_hdd_start_sap() - this function starts bss of SAP. + * @ap_adapter: SAP adapter + * + * This function will process the starting of sap adapter. + * + * Return: None + */ +void wlan_hdd_start_sap(struct hdd_adapter *ap_adapter, bool reinit) +{ + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_hostapd_state *hostapd_state; + QDF_STATUS qdf_status; + struct hdd_context *hdd_ctx; + tsap_config_t *sap_config; + + if (NULL == ap_adapter) { + hdd_err("ap_adapter is NULL here"); + return; + } + + 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); + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + sap_config = &ap_adapter->session.ap.sap_config; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) + goto end; + + if (0 != wlan_hdd_cfg80211_update_apies(ap_adapter)) { + hdd_err("SAP Not able to set AP IEs"); + goto end; + } + wlan_reg_set_channel_params(hdd_ctx->pdev, + hdd_ap_ctx->sap_config.channel, 0, + &hdd_ap_ctx->sap_config.ch_params); + + qdf_event_reset(&hostapd_state->qdf_event); + if (wlansap_start_bss(hdd_ap_ctx->sap_context, hdd_hostapd_sap_event_cb, + &hdd_ap_ctx->sap_config, + ap_adapter->dev) + != QDF_STATUS_SUCCESS) + goto end; + + hdd_debug("Waiting for SAP to start"); + qdf_status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, + SME_CMD_START_STOP_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, &ap_adapter->event_flags); + if (hostapd_state->bss_state == BSS_START) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + ap_adapter->device_mode, + ap_adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, ap_adapter->device_mode, + true); + } + mutex_unlock(&hdd_ctx->sap_lock); + + return; +end: + 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"); + +} + +#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 int hdd_qdf_print_init(void) +{ + int qdf_print_idx; + QDF_STATUS status; + + status = qdf_print_setup(); + if (status != QDF_STATUS_SUCCESS) { + pr_err("qdf_print_setup failed\n"); + return -EINVAL; + } + + qdf_print_idx = qdf_print_ctrl_register(cinfo, NULL, NULL, "MCL_WLAN"); + + if (qdf_print_idx < 0) { + pr_err("qdf_print_ctrl_register failed, ret = %d\n", + qdf_print_idx); + return -EINVAL; + } + + qdf_set_pidx(qdf_print_idx); + + return 0; +} + +static void hdd_qdf_print_deinit(void) +{ + int qdf_print_idx; + + qdf_print_idx = qdf_get_pidx(); + qdf_print_ctrl_cleanup(qdf_print_idx); +} + +static inline int hdd_state_query_cb(void) +{ + return !!wlan_hdd_validate_context(cds_get_context(QDF_MODULE_ID_HDD)); +} + +/** + * hdd_init() - Initialize Driver + * + * This function initilizes 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; + int ret = 0; + + status = cds_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to allocate CDS context"); + ret = -ENOMEM; + goto err_out; + } + qdf_register_module_state_query_callback(hdd_state_query_cb); + + wlan_init_bug_report_lock(); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_init_svc(); +#endif + + qdf_timer_init(NULL, &hdd_drv_ops_inactivity_timer, + (void *)hdd_drv_ops_inactivity_handler, NULL, + QDF_TIMER_TYPE_SW); + + hdd_trace_init(); + + hdd_register_debug_callback(); + +err_out: + return ret; +} + +/** + * 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) +{ + qdf_timer_free(&hdd_drv_ops_inactivity_timer); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_deinit_svc(); +#endif + + wlan_destroy_bug_report_lock(); + cds_deinit(); +} + +#ifdef QCA_WIFI_NAPIER_EMULATION +#define HDD_WLAN_START_WAIT_TIME ((CDS_WMA_TIMEOUT + 5000) * 100) +#else +#define HDD_WLAN_START_WAIT_TIME (CDS_WMA_TIMEOUT + 5000) +#endif + +static int wlan_hdd_state_ctrl_param_open(struct inode *inode, + struct file *file) +{ + return 0; +} + +static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, + const char __user *user_buf, + size_t count, + loff_t *f_pos) +{ + char buf[3]; + static const char wlan_off_str[] = "OFF"; + static const char wlan_on_str[] = "ON"; + int ret; + unsigned long rc; + + if (copy_from_user(buf, user_buf, 3)) { + pr_err("Failed to read buffer\n"); + return -EINVAL; + } + + if (strncmp(buf, wlan_off_str, strlen(wlan_off_str)) == 0) { + pr_debug("Wifi turning off from UI\n"); + goto exit; + } + + if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) == 0) { + pr_info("Wifi Turning On from UI\n"); + } + + if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) != 0) { + pr_err("Invalid value received from framework"); + goto exit; + } + + if (!cds_is_driver_loaded()) { + init_completion(&wlan_start_comp); + rc = wait_for_completion_timeout(&wlan_start_comp, + msecs_to_jiffies(HDD_WLAN_START_WAIT_TIME)); + if (!rc) { + hdd_alert("Timed-out waiting in wlan_hdd_state_ctrl_param_write"); + ret = -EINVAL; + return ret; + } + + hdd_start_complete(0); + } + +exit: + return count; +} + + +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, +}; + +static int wlan_hdd_state_ctrl_param_create(void) +{ + unsigned int wlan_hdd_state_major = 0; + int ret; + struct device *dev; + + 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 = class_create(THIS_MODULE, WLAN_MODULE_NAME); + if (IS_ERR(class)) { + pr_err("wlan_hdd_state class_create error"); + goto class_err; + } + + dev = device_create(class, NULL, device, NULL, WLAN_MODULE_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); + 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_MODULE_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; +} + +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"); +} + +/** + * hdd_component_init() - Initialize all components + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_component_init(void) +{ + QDF_STATUS status; + + /* initialize converged components */ + status = dispatcher_init(); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* initialize non-converged components */ + status = disa_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto dispatcher_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 = ucfg_mlme_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto oui_deinit; + + return QDF_STATUS_SUCCESS; + +oui_deinit: + ucfg_action_oui_deinit(); +ipa_deinit: + ipa_deinit(); +ocb_deinit: + ucfg_ocb_deinit(); +pmo_deinit: + pmo_deinit(); +disa_deinit: + disa_deinit(); +dispatcher_deinit: + dispatcher_deinit(); + + return status; +} + +/** + * hdd_component_deinit() - Deinitialize all components + * + * Return: None + */ +static void hdd_component_deinit(void) +{ + /* deinitialize non-converged components */ + ucfg_mlme_deinit(); + ucfg_action_oui_deinit(); + ipa_deinit(); + ucfg_ocb_deinit(); + pmo_deinit(); + disa_deinit(); + + /* deinitialize converged components */ + dispatcher_deinit(); +} + +void hdd_component_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + ocb_psoc_enable(psoc); + disa_psoc_enable(psoc); +} + +void hdd_component_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + disa_psoc_disable(psoc); + ocb_psoc_disable(psoc); +} + +/** + * hdd_fln() - logging macro for before/after qdf logging is initialized + * @fmt: printk compatible format string + * @args: arguments to be logged + * + * Note: To be used only in module insmod and rmmod code paths + * + * Return: None + */ +#define hdd_fln(fmt, args...) __hdd_fln(FL(fmt "\n"), ##args) +#define __hdd_fln(fmt, args...) pr_err(fmt, ##args) + +/** + * hdd_driver_load() - Perform the driver-level load operation + * + * Note: this is used in both static and DLKM driver builds + * + * Return: Errno + */ +static int hdd_driver_load(void) +{ + QDF_STATUS status; + int errno; + + pr_err("%s: Loading driver v%s (%s)\n", + WLAN_MODULE_NAME, + g_wlan_driver_version, + TIMER_MANAGER_STR MEMORY_DEBUG_STR PANIC_ON_BUG_STR); + + hdd_qdf_print_init(); + errno = hdd_init(); + if (errno) { + hdd_fln("Failed to init HDD; errno:%d", errno); + goto exit; + } + + status = hdd_component_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_fln("Failed to init components; status:%u", status); + errno = qdf_status_to_os_return(status); + goto hdd_deinit; + } + + status = qdf_wake_lock_create(&wlan_wake_lock, "wlan"); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_fln("Failed to create wake lock; status:%u", status); + errno = qdf_status_to_os_return(status); + goto comp_deinit; + } + + hdd_set_conparam(con_mode); + + errno = wlan_hdd_state_ctrl_param_create(); + if (errno) { + hdd_fln("Failed to create ctrl param; errno:%d", errno); + goto wakelock_destroy; + } + + errno = pld_init(); + if (errno) { + hdd_fln("Failed to init PLD; errno:%d", errno); + goto param_destroy; + } + + errno = wlan_hdd_register_driver(); + if (errno) { + hdd_fln("Failed to register driver; errno:%d", errno); + goto pld_deinit; + } + + pr_info("%s: driver loaded\n", WLAN_MODULE_NAME); + + return 0; + +pld_deinit: + pld_deinit(); +param_destroy: + wlan_hdd_state_ctrl_param_destroy(); +wakelock_destroy: + qdf_wake_lock_destroy(&wlan_wake_lock); +comp_deinit: + hdd_component_deinit(); +hdd_deinit: + hdd_deinit(); + +exit: + return errno; +} + +/** + * hdd_driver_unload() - Performs the driver-level unload operation + * + * Note: this is used in both static and DLKM driver builds + * + * Return: None + */ +static void hdd_driver_unload(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + pr_info("%s: Unloading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + + if (!hdd_wait_for_recovery_completion()) + return; + + cds_set_driver_loaded(false); + cds_set_unload_in_progress(true); + + if (!cds_wait_for_external_threads_completion(__func__)) + hdd_warn("External threads are still active attempting " + "driver unload anyway"); + + if (hdd_ctx) + hdd_psoc_idle_timer_stop(hdd_ctx); + + wlan_hdd_unregister_driver(); + pld_deinit(); + wlan_hdd_state_ctrl_param_destroy(); + hdd_set_conparam(0); + qdf_wake_lock_destroy(&wlan_wake_lock); + hdd_component_deinit(); + hdd_deinit(); + hdd_qdf_print_deinit(); +} + +#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 + * @buff: 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_fln("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("boot_wlan", + kernel_kobj); + if (!wlan_loader->boot_wlan_obj) { + hdd_fln("sysfs create and add failed"); + goto error_return; + } + + ret = sysfs_create_group(wlan_loader->boot_wlan_obj, + wlan_loader->attr_group); + if (ret) { + hdd_fln("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_fln("wlan loader context 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 + */ +static int hdd_module_init(void) +{ + if (hdd_driver_load()) + return -EINVAL; + + return 0; +} +#else +static int __init hdd_module_init(void) +{ + int ret = -EINVAL; + + ret = wlan_init_sysfs(); + if (ret) + hdd_fln("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 + */ +static void __exit hdd_module_exit(void) +{ + hdd_driver_unload(); +} +#else +static void __exit hdd_module_exit(void) +{ + hdd_driver_unload(); + wlan_deinit_sysfs(); +} +#endif + +#undef hdd_fln + +static int fwpath_changed_handler(const char *kmessage, + const struct kernel_param *kp) +{ + return param_set_copystring(kmessage, kp); +} + +#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 + +/** + * 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: + case QDF_GLOBAL_MISSION_MODE: + return true; + default: + return false; + } +} + +/** + * hdd_get_adpter_mode() - returns adapter mode based on global con mode + * @mode: global con mode + * + * Return: adapter mode + */ +static enum QDF_OPMODE hdd_get_adpter_mode( + enum QDF_GLOBAL_MODE mode) +{ + + switch (mode) { + case QDF_GLOBAL_MISSION_MODE: + return QDF_STA_MODE; + case QDF_GLOBAL_MONITOR_MODE: + return QDF_MONITOR_MODE; + case QDF_GLOBAL_EPPING_MODE: + return QDF_EPPING_MODE; + case QDF_GLOBAL_FTM_MODE: + return QDF_FTM_MODE; + case QDF_GLOBAL_QVIT_MODE: + return QDF_QVIT_MODE; + default: + return QDF_MAX_NO_OF_MODE; + } +} + +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) +{ + int driver_status; + + driver_status = hdd_ctx->driver_status; + + 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_register_req_mode(struct hdd_context *hdd_ctx, + enum QDF_GLOBAL_MODE mode) +{ + struct hdd_adapter *adapter; + int ret = 0; + bool rtnl_held; + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + QDF_STATUS status; + + if (!qdf_dev) { + hdd_err("qdf device context is Null return!"); + return -EINVAL; + } + + rtnl_held = hdd_hold_rtnl_lock(); + switch (mode) { + case QDF_GLOBAL_MISSION_MODE: + ret = hdd_open_interfaces(hdd_ctx, rtnl_held); + if (ret) + hdd_err("Failed to open interfaces: %d", ret); + break; + case QDF_GLOBAL_FTM_MODE: + adapter = hdd_open_adapter(hdd_ctx, QDF_FTM_MODE, "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx, + QDF_FTM_MODE), + NET_NAME_UNKNOWN, rtnl_held); + if (adapter == NULL) + ret = -EINVAL; + break; + case QDF_GLOBAL_MONITOR_MODE: + adapter = hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, "wlan%d", + wlan_hdd_get_intf_addr( + hdd_ctx, + QDF_MONITOR_MODE), + NET_NAME_UNKNOWN, rtnl_held); + if (adapter == NULL) + ret = -EINVAL; + break; + case QDF_GLOBAL_EPPING_MODE: + status = epping_open(); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to open in eeping mode: %d", status); + ret = -EINVAL; + break; + } + ret = epping_enable(qdf_dev->dev); + if (ret) { + hdd_err("Failed to enable in epping mode : %d", ret); + epping_close(); + } + break; + default: + hdd_err("Mode not supported"); + ret = -ENOTSUPP; + break; + } + hdd_release_rtnl_lock(); + rtnl_held = false; + return ret; +} + +/** + * __con_mode_handler() - Handles module param con_mode change + * @kmessage: con mode name on which driver to be bring up + * @kp: The associated kernel parameter + * @hdd_ctx: Pointer to the global HDD context + * + * This function is invoked when user updates con mode using sys entry, + * to initialize and bring-up driver in that specific mode. + * + * Return - 0 on success and failure code on failure + */ +static int __con_mode_handler(const char *kmessage, + const struct kernel_param *kp, + struct hdd_context *hdd_ctx) +{ + int ret; + enum QDF_GLOBAL_MODE curr_mode; + enum QDF_OPMODE adapter_mode; + int new_con_mode; + + hdd_info("con_mode handler: %s", kmessage); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + qdf_atomic_set(&hdd_ctx->con_mode_flag, 1); + + ret = kstrtoint(kmessage, 0, &new_con_mode); + if (ret) { + hdd_err("Failed to parse con_mode '%s'", kmessage); + goto reset_flags; + } + mutex_lock(&hdd_init_deinit_lock); + + if (!is_con_mode_valid(new_con_mode)) { + hdd_err("invalid con_mode %d", new_con_mode); + ret = -EINVAL; + goto reset_flags; + } + + curr_mode = hdd_get_conparam(); + if (curr_mode == new_con_mode) { + hdd_err("curr mode: %d is same as user triggered mode %d", + curr_mode, new_con_mode); + ret = 0; + goto reset_flags; + } + + /* ensure adapters are stopped */ + hdd_stop_present_mode(hdd_ctx, curr_mode); + + is_mode_change_psoc_idle_shutdown = true; + ret = pld_idle_shutdown(hdd_ctx->parent_dev, + hdd_mode_change_psoc_idle_shutdown); + if (ret) { + is_mode_change_psoc_idle_shutdown = false; + hdd_err("Failed to change the mode because of idle shutdown"); + goto reset_flags; + } + + /* Cleanup present mode before switching to new mode */ + hdd_cleanup_present_mode(hdd_ctx, curr_mode); + + hdd_set_conparam(new_con_mode); + + /* Register for new con_mode & then kick_start modules again */ + ret = hdd_register_req_mode(hdd_ctx, new_con_mode); + if (ret) { + hdd_err("Failed to register for new mode"); + goto reset_flags; + } + + adapter_mode = hdd_get_adpter_mode(new_con_mode); + if (adapter_mode == QDF_MAX_NO_OF_MODE) { + hdd_err("invalid adapter"); + ret = -EINVAL; + goto reset_flags; + } + + ret = pld_idle_restart(hdd_ctx->parent_dev, + hdd_mode_change_psoc_idle_restart); + if (ret) { + is_mode_change_psoc_idle_shutdown = false; + hdd_err("Start wlan modules failed: %d", ret); + goto reset_flags; + } + + if (new_con_mode == QDF_GLOBAL_MONITOR_MODE) { + struct hdd_adapter *adapter = + hdd_get_adapter(hdd_ctx, adapter_mode); + + if (!adapter) { + hdd_err("Failed to get adapter:%d", adapter_mode); + goto reset_flags; + } + + if (hdd_start_adapter(adapter)) { + hdd_err("Failed to start %s adapter", kmessage); + ret = -EINVAL; + goto reset_flags; + } + + 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 = new_con_mode; + hdd_info("Mode successfully changed to %s", kmessage); + ret = 0; + +reset_flags: + mutex_unlock(&hdd_init_deinit_lock); + qdf_atomic_set(&hdd_ctx->con_mode_flag, 0); + return ret; +} + + +static int con_mode_handler(const char *kmessage, const struct kernel_param *kp) +{ + int ret; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!cds_wait_for_external_threads_completion(__func__)) { + hdd_warn("External threads are still active, can not change mode"); + return -EAGAIN; + } + + cds_ssr_protect(__func__); + ret = __con_mode_handler(kmessage, kp, hdd_ctx); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int con_mode_handler_ftm(const char *kmessage, + const struct kernel_param *kp) +{ + int ret; + + ret = param_set_int(kmessage, kp); + + 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 FEATURE_MONITOR_MODE_SUPPORT +static int con_mode_handler_monitor(const char *kmessage, + const struct kernel_param *kp) +{ + int ret; + + ret = param_set_int(kmessage, kp); + + if (con_mode_monitor != QDF_GLOBAL_MONITOR_MODE) { + pr_err("Only Monitor mode supported!"); + return -ENOTSUPP; + } + + hdd_set_conparam(con_mode_monitor); + con_mode = con_mode_monitor; + + 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_clean_up_pre_cac_interface() - Clean up the pre cac interface + * @hdd_ctx: HDD context + * + * Cleans up the pre cac interface, if it exists + * + * Return: None + */ +void hdd_clean_up_pre_cac_interface(struct hdd_context *hdd_ctx) +{ + uint8_t session_id; + QDF_STATUS status; + struct hdd_adapter *precac_adapter; + + status = wlan_sap_get_pre_cac_vdev_id(hdd_ctx->mac_handle, &session_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get pre cac vdev id"); + return; + } + + precac_adapter = hdd_get_adapter_by_vdev(hdd_ctx, session_id); + if (!precac_adapter) { + hdd_err("invalid pre cac adapter"); + return; + } + + qdf_create_work(0, &hdd_ctx->sap_pre_cac_work, + wlan_hdd_sap_pre_cac_failure, + (void *)precac_adapter); + qdf_sched_work(0, &hdd_ctx->sap_pre_cac_work); + +} + +/** + * 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); + + if (!ol_ctx) + return; + + cfg.enable_self_recovery = hdd_ctx->config->enableSelfRecovery; + 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); +} + +#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 = hdd_ctx->config->runtime_pm_delay; +} +#else +static void hdd_populate_runtime_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}; + + if (!scn) + return; + + cfg.enable_self_recovery = hdd_ctx->config->enableSelfRecovery; + hdd_populate_runtime_cfg(hdd_ctx, &cfg); + hif_init_ini_config(scn, &cfg); + + if (hdd_ctx->config->prevent_link_down) + hif_vote_link_up(scn); +} + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +static void +hdd_update_dp_config_queue_threshold(struct hdd_context *hdd_ctx, + struct cdp_config_params *params) +{ + params->tx_flow_stop_queue_threshold = + hdd_ctx->config->TxFlowStopQueueThreshold; + params->tx_flow_start_queue_offset = + hdd_ctx->config->TxFlowStartQueueOffset; +} +#else +static inline void +hdd_update_dp_config_queue_threshold(struct hdd_context *hdd_ctx, + struct cdp_config_params *params) +{ +} +#endif + +/** + * 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 cdp_config_params params = {0}; + QDF_STATUS status; + + params.tso_enable = hdd_ctx->config->tso_enable; + params.lro_enable = hdd_ctx->config->lro_enable; + hdd_update_dp_config_queue_threshold(hdd_ctx, ¶ms); + params.flow_steering_enable = hdd_ctx->config->flow_steering_enable; + params.napi_enable = hdd_ctx->napi_enable; + params.tcp_udp_checksumoffload = + hdd_ctx->config->enable_ip_tcp_udp_checksum_offload; + + status = cdp_update_config_parameters( + cds_get_context(QDF_MODULE_ID_SOC), + ¶ms); + if (status) { + hdd_err("Failed to attach config parameters"); + return status; + } + + 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; + + 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); + + return ret; +} + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * hdd_ra_populate_cds_config() - Populate RA filtering cds configuration + * @psoc_cfg: pmo psoc Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_ra_populate_pmo_config( + struct pmo_psoc_cfg *psoc_cfg, + struct hdd_context *hdd_ctx) +{ + psoc_cfg->ra_ratelimit_interval = + hdd_ctx->config->RArateLimitInterval; + psoc_cfg->ra_ratelimit_enable = + hdd_ctx->config->IsRArateLimitEnabled; +} +#else +static inline void hdd_ra_populate_pmo_config( + struct cds_config_info *cds_cfg, + struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * 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; + + /* + * 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 patter and pattern byte match on + * all interfaces. + */ + psoc_cfg.magic_ptrn_enable = + (hdd_ctx->config->wowEnable & 0x01) ? true : false; + psoc_cfg.ptrn_match_enable_all_vdev = + (hdd_ctx->config->wowEnable & 0x02) ? true : false; + psoc_cfg.apf_enable = hdd_ctx->config->apf_packet_filter_enable; + psoc_cfg.arp_offload_enable = hdd_ctx->config->fhostArpOffload; + psoc_cfg.hw_filter_mode_bitmap = hdd_ctx->config->hw_filter_mode_bitmap; + psoc_cfg.ns_offload_enable_dynamic = hdd_ctx->config->fhostNSOffload; + psoc_cfg.ns_offload_enable_static = hdd_ctx->config->fhostNSOffload; + psoc_cfg.packet_filter_enabled = !hdd_ctx->config->disablePacketFilter; + psoc_cfg.ssdp = hdd_ctx->config->ssdp; + psoc_cfg.enable_mc_list = hdd_ctx->config->fEnableMCAddrList; + psoc_cfg.active_mode_offload = hdd_ctx->config->active_mode_offload; + psoc_cfg.ap_arpns_support = hdd_ctx->ap_arpns_support; + psoc_cfg.d0_wow_supported = wma_d0_wow_is_supported(); + psoc_cfg.sta_dynamic_dtim = hdd_ctx->config->enableDynamicDTIM; + psoc_cfg.sta_mod_dtim = hdd_ctx->config->enableModulatedDTIM; + psoc_cfg.sta_max_li_mod_dtim = hdd_ctx->config->fMaxLIModulatedDTIM; + psoc_cfg.power_save_mode = hdd_ctx->config->enablePowersaveOffload; + psoc_cfg.auto_power_save_fail_mode = + hdd_ctx->config->auto_pwr_save_fail_mode; + psoc_cfg.wow_data_inactivity_timeout = + hdd_ctx->config->wow_data_inactivity_timeout; + psoc_cfg.ps_data_inactivity_timeout = + hdd_ctx->config->nDataInactivityTimeout; + psoc_cfg.ito_repeat_count = hdd_ctx->config->ito_repeat_count; + + hdd_ra_populate_pmo_config(&psoc_cfg, hdd_ctx); + hdd_nan_populate_pmo_config(&psoc_cfg, hdd_ctx); + 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); +} + +#ifdef FEATURE_WLAN_SCAN_PNO +static inline void hdd_update_pno_config(struct pno_user_cfg *pno_cfg, + struct hdd_config *cfg) +{ + struct nlo_mawc_params *mawc_cfg = &pno_cfg->mawc_params; + + pno_cfg->channel_prediction = cfg->pno_channel_prediction; + pno_cfg->top_k_num_of_channels = cfg->top_k_num_of_channels; + pno_cfg->stationary_thresh = cfg->stationary_thresh; + pno_cfg->scan_timer_repeat_value = cfg->configPNOScanTimerRepeatValue; + pno_cfg->slow_scan_multiplier = cfg->pno_slow_scan_multiplier; + pno_cfg->dfs_chnl_scan_enabled = cfg->enable_dfs_pno_chnl_scan; + pno_cfg->adaptive_dwell_mode = cfg->pnoscan_adaptive_dwell_mode; + pno_cfg->channel_prediction_full_scan = + cfg->channel_prediction_full_scan; + mawc_cfg->enable = cfg->MAWCEnabled && cfg->mawc_nlo_enabled; + mawc_cfg->exp_backoff_ratio = cfg->mawc_nlo_exp_backoff_ratio; + mawc_cfg->init_scan_interval = cfg->mawc_nlo_init_scan_interval; + mawc_cfg->max_scan_interval = cfg->mawc_nlo_max_scan_interval; +} +#else +static inline void +hdd_update_pno_config(struct pno_user_cfg *pno_cfg, + struct hdd_config *cfg) +{ +} +#endif + +void hdd_update_ie_whitelist_attr(struct probe_req_whitelist_attr *ie_whitelist, + struct hdd_config *cfg) +{ + uint8_t i = 0; + + ie_whitelist->white_list = cfg->probe_req_ie_whitelist; + if (!ie_whitelist->white_list) + return; + + ie_whitelist->ie_bitmap[0] = cfg->probe_req_ie_bitmap_0; + ie_whitelist->ie_bitmap[1] = cfg->probe_req_ie_bitmap_1; + ie_whitelist->ie_bitmap[2] = cfg->probe_req_ie_bitmap_2; + ie_whitelist->ie_bitmap[3] = cfg->probe_req_ie_bitmap_3; + ie_whitelist->ie_bitmap[4] = cfg->probe_req_ie_bitmap_4; + ie_whitelist->ie_bitmap[5] = cfg->probe_req_ie_bitmap_5; + ie_whitelist->ie_bitmap[6] = cfg->probe_req_ie_bitmap_6; + ie_whitelist->ie_bitmap[7] = cfg->probe_req_ie_bitmap_7; + + ie_whitelist->num_vendor_oui = cfg->no_of_probe_req_ouis; + for (i = 0; i < ie_whitelist->num_vendor_oui; i++) + ie_whitelist->voui[i] = cfg->probe_req_voui[i]; +} + +uint32_t hdd_limit_max_per_index_score(uint32_t per_index_score) +{ + uint8_t i, score; + + for (i = 0; i < MAX_INDEX_PER_INI; i++) { + score = WLAN_GET_SCORE_PERCENTAGE(per_index_score, i); + if (score > MAX_INDEX_SCORE) + WLAN_SET_SCORE_PERCENTAGE(per_index_score, + MAX_INDEX_SCORE, i); + } + + return per_index_score; +} + +/** + * hdd_update_score_config - API to update candidate scoring related params + * configuration parameters + * @score_config: score config to update + * @cfg: config params + * + * Return: 0 if success else err + */ +static void hdd_update_score_config( + struct scoring_config *score_config, struct hdd_config *cfg) +{ + int total_weight; + + score_config->weight_cfg.rssi_weightage = cfg->rssi_weightage; + score_config->weight_cfg.ht_caps_weightage = cfg->ht_caps_weightage; + score_config->weight_cfg.vht_caps_weightage = + cfg->vht_caps_weightage; + score_config->weight_cfg.he_caps_weightage = + cfg->he_caps_weightage; + score_config->weight_cfg.chan_width_weightage = + cfg->chan_width_weightage; + score_config->weight_cfg.chan_band_weightage = + cfg->chan_band_weightage; + score_config->weight_cfg.nss_weightage = cfg->nss_weightage; + score_config->weight_cfg.beamforming_cap_weightage = + cfg->beamforming_cap_weightage; + score_config->weight_cfg.pcl_weightage = cfg->pcl_weightage; + score_config->weight_cfg.channel_congestion_weightage = + cfg->channel_congestion_weightage; + score_config->weight_cfg.oce_wan_weightage = cfg->oce_wan_weightage; + + total_weight = score_config->weight_cfg.rssi_weightage + + score_config->weight_cfg.ht_caps_weightage + + score_config->weight_cfg.vht_caps_weightage + + score_config->weight_cfg.he_caps_weightage + + score_config->weight_cfg.chan_width_weightage + + score_config->weight_cfg.chan_band_weightage + + score_config->weight_cfg.nss_weightage + + score_config->weight_cfg.beamforming_cap_weightage + + score_config->weight_cfg.pcl_weightage + + score_config->weight_cfg.channel_congestion_weightage + + score_config->weight_cfg.oce_wan_weightage; + + if (total_weight > BEST_CANDIDATE_MAX_WEIGHT) { + hdd_err("total weight is greater than %d fallback to default values", + BEST_CANDIDATE_MAX_WEIGHT); + + score_config->weight_cfg.rssi_weightage = RSSI_WEIGHTAGE; + score_config->weight_cfg.ht_caps_weightage = + HT_CAPABILITY_WEIGHTAGE; + score_config->weight_cfg.vht_caps_weightage = VHT_CAP_WEIGHTAGE; + score_config->weight_cfg.he_caps_weightage = HE_CAP_WEIGHTAGE; + score_config->weight_cfg.chan_width_weightage = + CHAN_WIDTH_WEIGHTAGE; + score_config->weight_cfg.chan_band_weightage = + CHAN_BAND_WEIGHTAGE; + score_config->weight_cfg.nss_weightage = NSS_WEIGHTAGE; + score_config->weight_cfg.beamforming_cap_weightage = + BEAMFORMING_CAP_WEIGHTAGE; + score_config->weight_cfg.pcl_weightage = PCL_WEIGHT; + score_config->weight_cfg.channel_congestion_weightage = + CHANNEL_CONGESTION_WEIGHTAGE; + score_config->weight_cfg.oce_wan_weightage = OCE_WAN_WEIGHTAGE; + } + + score_config->bandwidth_weight_per_index = + hdd_limit_max_per_index_score( + cfg->bandwidth_weight_per_index); + score_config->nss_weight_per_index = + hdd_limit_max_per_index_score(cfg->nss_weight_per_index); + score_config->band_weight_per_index = + hdd_limit_max_per_index_score(cfg->band_weight_per_index); + + score_config->rssi_score.best_rssi_threshold = + cfg->best_rssi_threshold; + score_config->rssi_score.good_rssi_threshold = + cfg->good_rssi_threshold; + score_config->rssi_score.bad_rssi_threshold = + cfg->bad_rssi_threshold; + score_config->rssi_score.good_rssi_pcnt = cfg->good_rssi_pcnt; + score_config->rssi_score.bad_rssi_pcnt = cfg->bad_rssi_pcnt; + score_config->rssi_score.good_rssi_bucket_size = + cfg->good_rssi_bucket_size; + score_config->rssi_score.bad_rssi_bucket_size = + cfg->bad_rssi_bucket_size; + score_config->rssi_score.rssi_pref_5g_rssi_thresh = + cfg->rssi_pref_5g_rssi_thresh; + + score_config->esp_qbss_scoring.num_slot = cfg->num_esp_qbss_slots; + score_config->esp_qbss_scoring.score_pcnt3_to_0 = + hdd_limit_max_per_index_score( + cfg->esp_qbss_score_slots3_to_0); + score_config->esp_qbss_scoring.score_pcnt7_to_4 = + hdd_limit_max_per_index_score( + cfg->esp_qbss_score_slots7_to_4); + score_config->esp_qbss_scoring.score_pcnt11_to_8 = + hdd_limit_max_per_index_score( + cfg->esp_qbss_score_slots11_to_8); + score_config->esp_qbss_scoring.score_pcnt15_to_12 = + hdd_limit_max_per_index_score( + cfg->esp_qbss_score_slots15_to_12); + + score_config->oce_wan_scoring.num_slot = cfg->num_oce_wan_slots; + score_config->oce_wan_scoring.score_pcnt3_to_0 = + hdd_limit_max_per_index_score( + cfg->oce_wan_score_slots3_to_0); + score_config->oce_wan_scoring.score_pcnt7_to_4 = + hdd_limit_max_per_index_score( + cfg->oce_wan_score_slots7_to_4); + score_config->oce_wan_scoring.score_pcnt11_to_8 = + hdd_limit_max_per_index_score( + cfg->oce_wan_score_slots11_to_8); + score_config->oce_wan_scoring.score_pcnt15_to_12 = + hdd_limit_max_per_index_score( + cfg->oce_wan_score_slots15_to_12); + + + score_config->cb_mode_24G = cfg->nChannelBondingMode24GHz; + score_config->cb_mode_5G = cfg->nChannelBondingMode5GHz; + score_config->vdev_nss_24g = + cfg->enable2x2 ? + GET_VDEV_NSS_CHAIN(cfg->rx_nss_2g, + STA_NSS_CHAINS_SHIFT) : + 1; + score_config->vdev_nss_5g = + cfg->enable2x2 ? + GET_VDEV_NSS_CHAIN(cfg->rx_nss_5g, + STA_NSS_CHAINS_SHIFT) : + 1; + + if (cfg->dot11Mode == eHDD_DOT11_MODE_AUTO || + cfg->dot11Mode == eHDD_DOT11_MODE_11ax || + cfg->dot11Mode == eHDD_DOT11_MODE_11ax_ONLY) + score_config->he_cap = 1; + + if (score_config->he_cap || + cfg->dot11Mode == eHDD_DOT11_MODE_11ac || + cfg->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) + score_config->vht_cap = 1; + + if (score_config->vht_cap || cfg->dot11Mode == eHDD_DOT11_MODE_11n || + cfg->dot11Mode == eHDD_DOT11_MODE_11n_ONLY) + score_config->ht_cap = 1; + + if (score_config->vht_cap && cfg->enableVhtFor24GHzBand) + score_config->vht_24G_cap = 1; + + if (cfg->enableTxBF) + score_config->beamformee_cap = 1; + +} + +/** + * 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 hdd_config *cfg = hdd_ctx->config; + struct dfs_user_config dfs_cfg = {0}; + QDF_STATUS status; + + dfs_cfg.dfs_is_phyerr_filter_offload = !!cfg->fDfsPhyerrFilterOffload; + 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 + */ +static int hdd_update_scan_config(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct scan_user_cfg scan_cfg = {0}; + struct hdd_config *cfg = hdd_ctx->config; + QDF_STATUS status; + + /* The ini is disallow DFS channel scan if ini is 1, so negate that */ + scan_cfg.allow_dfs_chan_in_first_scan = !cfg->initial_scan_no_dfs_chnl; + scan_cfg.allow_dfs_chan_in_scan = cfg->enableDFSChnlScan; + scan_cfg.use_wake_lock_in_user_scan = cfg->wake_lock_in_user_scan; + scan_cfg.active_dwell = cfg->nActiveMaxChnTime; + scan_cfg.active_dwell_2g = cfg->active_dwell_2g; + scan_cfg.passive_dwell = cfg->nPassiveMaxChnTime; + scan_cfg.conc_active_dwell = cfg->nActiveMaxChnTimeConc; + scan_cfg.conc_passive_dwell = cfg->nPassiveMaxChnTimeConc; + scan_cfg.conc_max_rest_time = cfg->nRestTimeConc; + scan_cfg.conc_min_rest_time = cfg->min_rest_time_conc; + scan_cfg.conc_idle_time = cfg->idle_time_conc; + /* convert to ms */ + scan_cfg.scan_cache_aging_time = + cfg->scanAgingTimeout * 1000; + scan_cfg.prefer_5ghz = cfg->nRoamPrefer5GHz; + scan_cfg.select_5ghz_margin = cfg->nSelect5GHzMargin; + scan_cfg.scan_bucket_threshold = cfg->first_scan_bucket_threshold; + scan_cfg.rssi_cat_gap = cfg->nRssiCatGap; + scan_cfg.scan_dwell_time_mode = cfg->scan_adaptive_dwell_mode; + scan_cfg.scan_dwell_time_mode_nc = + cfg->scan_adaptive_dwell_mode_nc; + scan_cfg.honour_nl_scan_policy_flags = + cfg->honour_nl_scan_policy_flags; + scan_cfg.is_snr_monitoring_enabled = cfg->fEnableSNRMonitoring; + scan_cfg.usr_cfg_probe_rpt_time = cfg->scan_probe_repeat_time; + scan_cfg.usr_cfg_num_probes = cfg->scan_num_probes; + scan_cfg.is_bssid_hint_priority = cfg->is_bssid_hint_priority; + scan_cfg.enable_mac_spoofing = cfg->enable_mac_spoofing; + scan_cfg.sta_miracast_mcc_rest_time = + cfg->sta_miracast_mcc_rest_time_val; + scan_cfg.sta_scan_burst_duration = cfg->sta_scan_burst_duration; + scan_cfg.p2p_scan_burst_duration = cfg->p2p_scan_burst_duration; + scan_cfg.go_scan_burst_duration = cfg->go_scan_burst_duration; + scan_cfg.ap_scan_burst_duration = cfg->ap_scan_burst_duration; + scan_cfg.skip_dfs_chan_in_p2p_search = cfg->skipDfsChnlInP2pSearch; + + hdd_update_pno_config(&scan_cfg.pno_cfg, cfg); + hdd_update_ie_whitelist_attr(&scan_cfg.ie_whitelist, cfg); + hdd_update_score_config(&scan_cfg.score_config, cfg); + + status = ucfg_scan_update_user_config(psoc, &scan_cfg); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed pmo psoc configuration"); + return -EINVAL; + } + ucfg_scan_set_global_config( + psoc, SCAN_CFG_DROP_BCN_ON_CHANNEL_MISMATCH, + cfg->drop_bcn_on_chan_mismatch); + + 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); + + 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 + * @hddctx: 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; + + if (!hdd_ctx->config->goptimize_chan_avoid_event) { + hdd_warn("goptimize_chan_avoid_event ini param disabled"); + return -EINVAL; + } + + 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; +} + +/** + * hdd_set_roaming_in_progress() - to set the roaming in progress flag + * @value: value to set + * + * This function will set the passed value to roaming in progress flag. + * + * Return: None + */ +void hdd_set_roaming_in_progress(bool value) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return; + } + + hdd_ctx->roaming_in_progress = value; + hdd_debug("Roaming in Progress set to %d", value); + if (!hdd_ctx->roaming_in_progress) { + /* Reset scan reject params on successful roam complete */ + hdd_debug("Reset scan reject params"); + hdd_init_scan_reject_params(hdd_ctx); + } +} + +bool hdd_is_roaming_in_progress(struct hdd_context *hdd_ctx) +{ + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return false; + } + + hdd_debug("roaming_in_progress = %d", hdd_ctx->roaming_in_progress); + + return hdd_ctx->roaming_in_progress; +} + +/** + * hdd_is_connection_in_progress() - check if connection is in + * progress + * @session_id: session id + * @reason: scan reject reason + * + * Go through each adapter and check if Connection is in progress + * + * Return: true if connection is in progress else false + */ +bool hdd_is_connection_in_progress(uint8_t *session_id, + enum scan_reject_states *reason) +{ + struct hdd_station_ctx *hdd_sta_ctx = NULL; + struct hdd_adapter *adapter = NULL; + uint8_t sta_id = 0; + uint8_t *sta_mac = NULL; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return false; + } + + mac_handle = hdd_ctx->mac_handle; + + hdd_for_each_adapter(hdd_ctx, adapter) { + hdd_debug("Adapter with device mode %s(%d) exists", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + if (((QDF_STA_MODE == adapter->device_mode) + || (QDF_P2P_CLIENT_MODE == adapter->device_mode) + || (QDF_P2P_DEVICE_MODE == adapter->device_mode)) + && (eConnectionState_Connecting == + (WLAN_HDD_GET_STATION_CTX_PTR(adapter))-> + conn_info.connState)) { + hdd_debug("%pK(%d) Connection is in progress", + WLAN_HDD_GET_STATION_CTX_PTR(adapter), + adapter->session_id); + if (session_id && reason) { + *session_id = adapter->session_id; + *reason = CONNECTION_IN_PROGRESS; + } + return true; + } + /* + * sme_neighbor_middle_of_roaming is for LFR2 + * hdd_is_roaming_in_progress is for LFR3 + */ + if (((QDF_STA_MODE == adapter->device_mode) && + sme_neighbor_middle_of_roaming( + mac_handle, + adapter->session_id)) || + hdd_is_roaming_in_progress(hdd_ctx)) { + hdd_debug("%pK(%d) Reassociation in progress", + WLAN_HDD_GET_STATION_CTX_PTR(adapter), + adapter->session_id); + if (session_id && reason) { + *session_id = adapter->session_id; + *reason = REASSOC_IN_PROGRESS; + } + return true; + } + 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(adapter); + if ((eConnectionState_Associated == + hdd_sta_ctx->conn_info.connState) + && sme_is_sta_key_exchange_in_progress( + mac_handle, adapter->session_id)) { + sta_mac = (uint8_t *) + &(adapter->mac_addr.bytes[0]); + hdd_debug("client " MAC_ADDRESS_STR + " is in middle of WPS/EAPOL exchange.", + MAC_ADDR_ARRAY(sta_mac)); + if (session_id && reason) { + *session_id = adapter->session_id; + *reason = EAPOL_IN_PROGRESS; + } + return true; + } + } else if ((QDF_SAP_MODE == adapter->device_mode) || + (QDF_P2P_GO_MODE == adapter->device_mode)) { + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; + sta_id++) { + if (!((adapter->sta_info[sta_id].in_use) + && (OL_TXRX_PEER_STATE_CONN == + adapter->sta_info[sta_id].peer_state))) + continue; + + sta_mac = (uint8_t *) + &(adapter->sta_info[sta_id]. + sta_mac.bytes[0]); + hdd_debug("client " MAC_ADDRESS_STR + " of SAP/GO is in middle of WPS/EAPOL exchange", + MAC_ADDR_ARRAY(sta_mac)); + if (session_id && reason) { + *session_id = adapter->session_id; + *reason = SAP_EAPOL_IN_PROGRESS; + } + return true; + } + if (hdd_ctx->connection_in_progress) { + hdd_debug("AP/GO: connection is in progress"); + *reason = SAP_CONNECTION_IN_PROGRESS; + *session_id = adapter->session_id; + return true; + } + } + } + + return false; +} + +/** + * hdd_restart_sap() - to restart SAP in driver internally + * @ap_adapter: Pointer to SAP struct hdd_adapter structure + * + * Return: None + */ +void hdd_restart_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 = WLAN_HDD_GET_CTX(ap_adapter); + tsap_config_t *sap_config; + void *sap_ctx; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + sap_config = &hdd_ap_ctx->sap_config; + sap_ctx = hdd_ap_ctx->sap_context; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { + wlan_hdd_del_station(ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + if (QDF_STATUS_SUCCESS == wlansap_stop_bss(sap_ctx)) { + qdf_status = + qdf_wait_for_event_completion(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_START_STOP_BSS_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SAP Stop Failed"); + goto end; + } + } + clear_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + ap_adapter->device_mode, ap_adapter->session_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(ap_adapter)) { + hdd_err("SAP Not able to set AP IEs"); + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + goto end; + } + + qdf_event_reset(&hostapd_state->qdf_event); + if (wlansap_start_bss(sap_ctx, hdd_hostapd_sap_event_cb, + sap_config, + ap_adapter->dev) != QDF_STATUS_SUCCESS) { + hdd_err("SAP Start Bss fail"); + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + goto end; + } + + hdd_info("Waiting for SAP to start"); + qdf_status = + qdf_wait_for_event_completion(&hostapd_state->qdf_event, + SME_CMD_START_STOP_BSS_TIMEOUT); + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SAP Start failed"); + goto end; + } + hdd_err("SAP Start Success"); + set_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + if (hostapd_state->bss_state == BSS_START) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + ap_adapter->device_mode, + ap_adapter->session_id); + hdd_green_ap_start_state_mc(hdd_ctx, + ap_adapter->device_mode, + true); + } + } +end: + mutex_unlock(&hdd_ctx->sap_lock); +} + +/** + * hdd_check_and_restart_sap_with_non_dfs_acs() - Restart SAP + * with non dfs acs + * + * Restarts SAP in non-DFS ACS mode when STA-AP mode DFS is not supported + * + * Return: None + */ +void hdd_check_and_restart_sap_with_non_dfs_acs(void) +{ + struct hdd_adapter *ap_adapter; + struct hdd_context *hdd_ctx; + struct cds_context *cds_ctx; + uint8_t restart_chan; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + hdd_err("Invalid CDS Context"); + return; + } + + if (policy_mgr_get_concurrency_mode(hdd_ctx->psoc) + != (QDF_STA_MASK | QDF_SAP_MASK)) { + hdd_debug("Concurrency mode is not SAP"); + return; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (ap_adapter && + test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags) && + wlan_reg_is_dfs_ch(hdd_ctx->pdev, + ap_adapter->session.ap.operating_channel)) { + + hdd_warn("STA-AP Mode DFS not supported, Switch SAP channel to Non DFS"); + + restart_chan = + wlansap_get_safe_channel_from_pcl_and_acs_range( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter)); + if (!restart_chan || + wlan_reg_is_dfs_ch(hdd_ctx->pdev, restart_chan)) + restart_chan = SAP_DEFAULT_5GHZ_CHANNEL; + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + ap_adapter->session_id, + CSA_REASON_STA_CONNECT_DFS_TO_NON_DFS); + hdd_switch_sap_channel(ap_adapter, restart_chan, true); + } +} + +/** + * 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) { + hdd_err("HDD context is NULL"); + 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_p2p_quota(struct hdd_adapter *adapter, int set_value) +{ + if (!adapter) { + hdd_err("Invalid adapter"); + return -EINVAL; + } + hdd_info("Send MCC P2P QUOTA to WMA: %d", set_value); + sme_cli_set_command(adapter->session_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->session_id, + WMA_VDEV_MCC_SET_TIME_LATENCY, + set_value, VDEV_CMD); + return 0; +} + +struct hdd_adapter *wlan_hdd_get_adapter_from_vdev(struct wlan_objmgr_psoc + *psoc, uint8_t vdev_id) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + /* + * 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. + */ + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) + hdd_err("Get adapter by vdev id failed"); + + return adapter; +} + +int hdd_get_rssi_snr_by_bssid(struct hdd_adapter *adapter, const uint8_t *bssid, + int8_t *rssi, int8_t *snr) +{ + QDF_STATUS status; + mac_handle_t mac_handle; + struct csr_roam_profile *roam_profile; + + roam_profile = hdd_roam_profile(adapter); + mac_handle = hdd_adapter_get_mac_handle(adapter); + status = sme_get_rssi_snr_by_bssid(mac_handle, + roam_profile, bssid, rssi, snr); + if (QDF_STATUS_SUCCESS != status) { + hdd_warn("sme_get_rssi_snr_by_bssid failed"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_set_limit_off_chan_for_tos() - set limit off-channel command parameters + * @adapter - HDD adapter + * @tos - type of service + * @status - status of the traffic + * + * Return: 0 on success and non zero value on failure + */ + +int hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, enum tos 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; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + + if (ret < 0) { + hdd_err("failed to set limit off chan params"); + return ret; + } + + 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[TOS_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[TOS_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, + hdd_ctx->config->conc_system_pref); + } + } else { + /* No active tos */ + policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc, + hdd_ctx->config->conc_system_pref); + } + + status = sme_send_limit_off_channel_params(hdd_ctx->mac_handle, + adapter->session_id, + is_tos_active, + max_off_chan_time, + hdd_ctx->config->nRestTimeConc, + true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to set limit off chan params"); + ret = -EINVAL; + } + + return ret; +} + +/** + * 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; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret < 0) + return ret; + + /* set the system preferece to default */ + policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc, + hdd_ctx->config->conc_system_pref); + + /* clear the bitmap */ + adapter->active_ac = 0; + + hdd_debug("reset ac_bitmap for session %hu active_ac %0x", + adapter->session_id, adapter->active_ac); + + status = sme_send_limit_off_channel_params(hdd_ctx->mac_handle, + adapter->session_id, + false, 0, 0, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to reset limit off chan params"); + ret = -EINVAL; + } + + return ret; +} + +/** + * hdd_start_driver_ops_timer() - Starts driver ops inactivity timer + * @drv_op: Enum indicating driver op + * + * Return: none + */ +void hdd_start_driver_ops_timer(int drv_op) +{ + memset(drv_ops_string, 0, MAX_OPS_NAME_STRING_SIZE); + switch (drv_op) { + case eHDD_DRV_OP_PROBE: + memcpy(drv_ops_string, "probe", sizeof("probe")); + break; + case eHDD_DRV_OP_REMOVE: + memcpy(drv_ops_string, "remove", sizeof("remove")); + break; + case eHDD_DRV_OP_SHUTDOWN: + memcpy(drv_ops_string, "shutdown", sizeof("shutdown")); + break; + case eHDD_DRV_OP_REINIT: + memcpy(drv_ops_string, "reinit", sizeof("reinit")); + break; + case eHDD_DRV_OP_IFF_UP: + memcpy(drv_ops_string, "iff_up", sizeof("iff_up")); + break; + } + + hdd_drv_ops_task = current; + qdf_timer_start(&hdd_drv_ops_inactivity_timer, + HDD_OPS_INACTIVITY_TIMEOUT * qdf_timer_get_multiplier()); +} + +/** + * hdd_stop_driver_ops_timer() - Stops driver ops inactivity timer + * + * Return: none + */ +void hdd_stop_driver_ops_timer(void) +{ + qdf_timer_sync_cancel(&hdd_drv_ops_inactivity_timer); +} + +/** + * hdd_drv_ops_inactivity_handler() - Timeout handler for driver ops + * inactivity timer + * + * Return: None + */ +void hdd_drv_ops_inactivity_handler(void *context) +{ + hdd_err("WLAN_BUG_RCA %s: %d Sec timer expired while in .%s", + __func__, HDD_OPS_INACTIVITY_TIMEOUT/1000, drv_ops_string); + + if (hdd_drv_ops_task) { + printk("Call stack for \"%s\"\n", hdd_drv_ops_task->comm); + qdf_print_thread_trace(hdd_drv_ops_task); + } else { + hdd_err("hdd_drv_ops_task is null"); + } + + /* Driver shutdown is stuck, no recovery possible at this point */ + if (0 == qdf_mem_cmp(&drv_ops_string[0], "shutdown", + sizeof("shutdown"))) + QDF_BUG(0); + + if (cds_is_fw_down()) { + hdd_err("FW is down"); + return; + } + + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); +} + +void hdd_pld_ipa_uc_shutdown_pipes(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + ucfg_ipa_uc_force_pipe_shutdown(hdd_ctx->pdev); +} + +/** + * hdd_set_rx_mode_rps() - Enable/disable RPS in SAP mode + * @struct hdd_context *hdd_ctx + * @struct hdd_adapter *padapter + * @bool enble + * + * Return: none + */ +void hdd_set_rx_mode_rps(bool enable) +{ + struct cds_config_info *cds_cfg = cds_get_ini_config(); + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + + if (!cds_cfg) + return; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!adapter) + return; + + if (!hdd_ctx->rps && cds_cfg->uc_offload_enabled) { + if (enable && !cds_cfg->rps_enabled) + hdd_send_rps_ind(adapter); + else if (!enable && cds_cfg->rps_enabled) + hdd_send_rps_disable_ind(adapter); + } +} + +#ifdef MSM_PLATFORM +void wlan_hdd_update_tcp_rx_param(struct hdd_context *hdd_ctx, void *data) +{ + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + if (!data) { + hdd_err("Data is null"); + return; + } + if (hdd_ctx->config->enable_tcp_param_update) + wlan_hdd_send_tcp_param_update_event(hdd_ctx, data, 1); + else + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_TP_IND, + data, + sizeof(struct wlan_rx_tp_data)); +} + +void wlan_hdd_update_tcp_tx_param(struct hdd_context *hdd_ctx, void *data) +{ + enum wlan_tp_level next_tx_level; + struct wlan_tx_tp_data *tx_tp_data; + + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + if (!data) { + hdd_err("Data is null"); + return; + } + + tx_tp_data = (struct wlan_tx_tp_data *)data; + next_tx_level = tx_tp_data->level; + + if (hdd_ctx->config->enable_tcp_param_update) + wlan_hdd_send_tcp_param_update_event(hdd_ctx, data, 0); + else + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_TP_TX_IND, + &next_tx_level, + sizeof(next_tx_level)); +} + +/** + * wlan_hdd_send_tcp_param_update_event() - Send vendor event to update + * TCP parameter through Wi-Fi HAL + * @hdd_ctx: Pointer to HDD context + * @data: Parameters to update + * @dir: Direction(tx/rx) to update + * + * Return: None + */ +void wlan_hdd_send_tcp_param_update_event(struct hdd_context *hdd_ctx, + void *data, + uint8_t dir) +{ + struct sk_buff *vendor_event; + 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; + + event_len = sizeof(uint8_t) + sizeof(uint8_t) + NLMSG_HDRLEN; + + 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 { + hdd_err("Invalid Direction [%d]", dir); + return; + } + + vendor_event = + cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, + NULL, event_len, + QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + 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; + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + return; + +tcp_param_change_nla_failed: + hdd_err("nla_put api failed"); + kfree_skb(vendor_event); +} +#endif /* MSM_PLATFORM */ + +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 hdd_adapter *adapter; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + if (!adapter) { + hdd_err("Adapter is null"); + return; + } + /* enable roaming on all adapters once hdd get hidden ssid rsp */ + wlan_hdd_enable_roaming(adapter); +} + +/* 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"); + +static const struct kernel_param_ops con_mode_ops = { + .set = con_mode_handler, + .get = param_get_int, +}; + +static const struct kernel_param_ops con_mode_ftm_ops = { + .set = con_mode_handler_ftm, + .get = param_get_int, +}; + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +static const struct kernel_param_ops con_mode_monitor_ops = { + .set = con_mode_handler_monitor, + .get = param_get_int, +}; +#endif + +static const struct kernel_param_ops fwpath_ops = { + .set = fwpath_changed_handler, + .get = param_get_string, +}; + +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); + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +module_param_cb(con_mode_monitor, &con_mode_monitor_ops, &con_mode_monitor, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +#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); diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c new file mode 100644 index 0000000000000000000000000000000000000000..9156d2b3de98a50b4714396349117730a74fcb28 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 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. + */ + +/** + * DOC : wlan_hdd_memdump.c + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#include +#include +#include +#include +#include +#include /* Necessary because we use the proc fs */ +#include /* for copy_to_user */ + + +#ifdef MULTI_IF_NAME +#define PROCFS_DRIVER_DUMP_DIR "debugdriver" MULTI_IF_NAME +#else +#define PROCFS_DRIVER_DUMP_DIR "debugdriver" +#endif +#define PROCFS_DRIVER_DUMP_NAME "driverdump" +#define PROCFS_DRIVER_DUMP_PERM 0444 + +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) { + hdd_err("Invalid HDD context"); + 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; + } else 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; + } else if ((*pos == 0) || (hdd_ctx->driver_dump_mem == NULL)) { + /* + * 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) { + hdd_err("qdf_mem_malloc failed"); + 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) +{ + ssize_t len; + + cds_ssr_protect(__func__); + len = __hdd_driver_memdump_read(file, buf, count, pos); + cds_ssr_unprotect(__func__); + + return len; +} + +/** + * struct driver_dump_fops - file operations for driver dump feature + * @read - read function for driver dump operation. + * + * This structure initialize the file operation handle for memory + * dump feature + */ +static const struct file_operations driver_dump_fops = { +read: hdd_driver_memdump_read +}; + +/** + * 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 == NULL) { + 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 == NULL) { + 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) +{ + 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() - Intialization 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) { + hdd_err("Invalid HDD context"); + 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_mpta_helper.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_mpta_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..2119767112a6e2e2a1b87613e7a42f1a1e0354ad --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_mpta_helper.c @@ -0,0 +1,251 @@ +/* + * 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_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 "wlan_hdd_cfg.h" + +static 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_mpta_helper_config( + wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_mpta_helper_enable() - enable/disable mpta helper + * according to cfg from INI + * @config: pointer of BTC config items + * + * Return: 0 on success; error number otherwise. + * + */ +int +wlan_hdd_mpta_helper_enable(struct hdd_config *config) +{ + QDF_STATUS status; + struct coex_config_params coex_cfg_params = {0}; + + coex_cfg_params.config_type = WMI_COEX_CONFIG_MPTA_HELPER_ENABLE; + coex_cfg_params.config_arg1 = config->set_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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c new file mode 100644 index 0000000000000000000000000000000000000000..a1f3ba02a14a034e52607398588d9d59f5a25365 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c @@ -0,0 +1,146 @@ +/* + * 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: wlan_hdd_nan.c + * + * WLAN Host Device Driver NAN API implementation + */ + +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "nan_api.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_nan.h" +#include + +/** + * __wlan_hdd_cfg80211_nan_request() - cfg80211 NAN 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 + * + * This is called when userspace needs to send a nan request to + * firmware. The wlan host driver simply de-encapsulates the + * request from the netlink payload and then forwards it to + * firmware via SME. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tNanRequestReq nan_req; + QDF_STATUS status; + 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_rl("Command not allowed in FTM mode"); + return -EPERM; + } + + if (!hdd_ctx->config->enable_nan_support) { + hdd_err_rl("NaN support is not enabled in INI"); + return -EPERM; + } + + nan_req.request_data_len = data_len; + nan_req.request_data = data; + + status = sme_nan_request(&nan_req); + if (QDF_STATUS_SUCCESS != status) + ret_val = -EINVAL; + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_nan_request() - handle NAN 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_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) + +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_nan_request(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +void wlan_hdd_cfg80211_nan_callback(hdd_handle_t hdd_handle, tSirNanEvent *msg) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct sk_buff *vendor_event; + int status; + + if (!msg) { + hdd_err("msg received here is null"); + return; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + msg->event_data_len + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NAN, + msg->event_data_len, msg->event_data)) { + hdd_err("QCA_WLAN_VENDOR_ATTR_NAN put fail"); + kfree_skb(vendor_event); + return; + } + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c new file mode 100644 index 0000000000000000000000000000000000000000..185b13fac512a722dd6436537f726f0dc7687ae8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c @@ -0,0 +1,896 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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 "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" + +/** + * hdd_ndp_print_ini_config()- Print nan datapath specific INI configuration + * @hdd_ctx: handle to hdd context + * + * Return: None + */ +void hdd_ndp_print_ini_config(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] Value = [%u]", CFG_ENABLE_NAN_DATAPATH_NAME, + hdd_ctx->config->enable_nan_datapath); + hdd_debug("Name = [%s] Value = [%u]", CFG_ENABLE_NAN_NDI_CHANNEL_NAME, + hdd_ctx->config->nan_datapath_ndi_channel); +} + +/** + * hdd_nan_datapath_target_config() - Configure NAN datapath features + * @hdd_ctx: Pointer to HDD context + * @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 *cfg) +{ + hdd_ctx->nan_datapath_enabled = + hdd_ctx->config->enable_nan_datapath && + cfg->nan_datapath_enabled; + hdd_debug("final: %d, host: %d, fw: %d", + hdd_ctx->nan_datapath_enabled, + hdd_ctx->config->enable_nan_datapath, + cfg->nan_datapath_enabled); +} + +/** + * 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); + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv4_notifier_work); +#endif + hdd_deregister_tx_flow_control(adapter); + +#ifdef WLAN_NS_OFFLOAD +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv6_notifier_work); +#endif +#endif + errno = hdd_vdev_destroy(adapter); + if (errno) + hdd_err("failed to destroy vdev: %d", errno); + + /* We are good to close the adapter */ + hdd_close_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 + */ +static bool hdd_is_ndp_allowed(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + + hdd_for_each_adapter(hdd_ctx, adapter) { + switch (adapter->device_mode) { + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)) + return false; + break; + case QDF_P2P_CLIENT_MODE: + case QDF_IBSS_MODE: + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (hdd_conn_is_connected(sta_ctx) || + hdd_is_connecting(sta_ctx)) + return false; + break; + default: + break; + } + } + + return true; +} + +/** + * hdd_ndi_start_bss() - Start BSS on NAN data interface + * @adapter: adapter context + * @operating_channel: channel on which the BSS to be started + * + * Return: 0 on success, error value on failure + */ +static int hdd_ndi_start_bss(struct hdd_adapter *adapter, + uint8_t operating_channel) +{ + QDF_STATUS status; + uint32_t roam_id; + struct csr_roam_profile *roam_profile; + mac_handle_t mac_handle; + + hdd_enter(); + + roam_profile = hdd_roam_profile(adapter); + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(adapter))->config->WmmMode) { + /* QoS not enabled in cfg file*/ + roam_profile->uapsd_mask = 0; + } else { + /* QoS enabled, update uapsd mask from cfg file*/ + roam_profile->uapsd_mask = + (WLAN_HDD_GET_CTX(adapter))->config->UapsdMask; + } + + roam_profile->csrPersona = adapter->device_mode; + + if (!operating_channel) + operating_channel = NAN_SOCIAL_CHANNEL_2_4GHZ; + + roam_profile->ChannelInfo.numOfChannels = 1; + roam_profile->ChannelInfo.ChannelList = &operating_channel; + + roam_profile->SSIDs.numOfSSIDs = 1; + roam_profile->SSIDs.SSIDList->SSID.length = 0; + + roam_profile->phyMode = eCSR_DOT11_MODE_11ac; + roam_profile->BSSType = eCSR_BSS_TYPE_NDI; + roam_profile->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy((void *)(roam_profile->BSSIDs.bssid), + &adapter->mac_addr.bytes[0], + QDF_MAC_ADDR_SIZE); + + roam_profile->AuthType.numEntries = 1; + roam_profile->AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + roam_profile->EncryptionType.numEntries = 1; + roam_profile->EncryptionType.encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE; + + mac_handle = hdd_adapter_get_mac_handle(adapter); + status = sme_roam_connect(mac_handle, adapter->session_id, + roam_profile, &roam_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("NDI sme_RoamConnect session %d failed with status %d -> NotConnected", + adapter->session_id, status); + /* change back to NotConnected */ + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + } else { + hdd_info("sme_RoamConnect issued successfully for NDI"); + } + + roam_profile->ChannelInfo.ChannelList = NULL; + roam_profile->ChannelInfo.numOfChannels = 0; + + 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)); + cds_rand_get_bytes(0, &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 { + cds_rand_get_bytes(0, (uint8_t *)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 hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roam_id, eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + bool success; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(adapter->vdev); + + 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 to umac", + success); + os_if_nan_post_ndi_create_rsp(psoc, adapter->session_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 to umac", + success); + os_if_nan_post_ndi_delete_rsp(psoc, adapter->session_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_cmds() - 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); + + 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_rl("Command not allowed in FTM mode"); + return -EPERM; + } + + if (!WLAN_HDD_IS_NDP_ENABLED(hdd_ctx)) { + hdd_err_rl("NAN datapath is not enabled"); + return -EPERM; + } + /* NAN data path coexists only with STA interface */ + if (false == hdd_is_ndp_allowed(hdd_ctx)) { + hdd_err_rl("Unsupported concurrency for NAN datapath"); + return -EPERM; + } + + /* NAN data path coexists only with STA interface */ + if (false == hdd_is_ndp_allowed(hdd_ctx)) { + hdd_err_rl("Unsupported concurrency for NAN datapath"); + return -EPERM; + } + + return os_if_nan_process_ndp_cmd(hdd_ctx->psoc, + data, data_len); +} + +/** + * 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_process_ndp_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int update_ndi_state(struct hdd_adapter *adapter, uint32_t state) +{ + return os_if_nan_set_ndi_state(adapter->vdev, state); +} + +/** + * 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; + + ret_val = hdd_vdev_create(adapter, hdd_sme_roam_callback, adapter); + 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 */ + sme_set_curr_device_mode(mac_handle, adapter->device_mode); + sme_set_pdev_ht_vht_ies(mac_handle, hdd_ctx->config->enable2x2); + sme_set_vdev_ies_per_band(mac_handle, adapter->session_id); + + hdd_roam_profile_init(adapter); + hdd_register_wext(wlan_dev); + + status = hdd_init_tx_rx(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("hdd_init_tx_rx() init failed, status %d", status); + ret_val = -EAGAIN; + goto error_init_txrx; + } + + set_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + + 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); + + ret_val = wma_cli_set_command((int)adapter->session_id, + (int)WMI_PDEV_PARAM_BURST_ENABLE, + (int)HDD_ENABLE_SIFS_BURST_DEFAULT, + PDEV_CMD); + if (0 != ret_val) + hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", ret_val); + + + update_ndi_state(adapter, NAN_DATA_NDI_CREATING_STATE); + return ret_val; + +error_wmm_init: + clear_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + hdd_deinit_tx_rx(adapter); + +error_init_txrx: + hdd_unregister_wext(wlan_dev); + + QDF_BUG(!hdd_vdev_destroy(adapter)); + + return ret_val; +} + +int hdd_ndi_open(char *iface_name) +{ + 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; + + hdd_enter(); + if (!hdd_ctx) { + hdd_err("hdd_ctx null"); + return -EINVAL; + } + + if (hdd_ctx->config->is_ndi_mac_randomized) { + 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; + } + } + + adapter = hdd_open_adapter(hdd_ctx, QDF_NDI_MODE, iface_name, + ndi_mac_addr, NET_NAME_UNKNOWN, true); + if (!adapter) { + hdd_err("hdd_open_adapter failed"); + return -EINVAL; + } + + hdd_exit(); + return 0; +} + +int hdd_ndi_start(char *iface_name, uint16_t transaction_id) +{ + int ret; + uint8_t op_channel; + QDF_STATUS status; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + hdd_enter(); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return -EINVAL; + } + + op_channel = hdd_ctx->config->nan_datapath_ndi_channel; + 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; + } + + /* + * 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(adapter->vdev, + transaction_id); + ucfg_nan_set_ndi_state(adapter->vdev, + NAN_DATA_NDI_CREATING_STATE); + + /* + * The NAN data interface has been created at this point. + * 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. + */ + if (op_channel != NAN_SOCIAL_CHANNEL_2_4GHZ && + op_channel != NAN_SOCIAL_CHANNEL_5GHZ_LOWER_BAND && + op_channel != NAN_SOCIAL_CHANNEL_5GHZ_UPPER_BAND) { + /* start NDI on the default 2.4 GHz social channel */ + op_channel = NAN_SOCIAL_CHANNEL_2_4GHZ; + } + + if (hdd_ndi_start_bss(adapter, op_channel)) { + hdd_err("NDI start bss failed"); + ret = -EFAULT; + goto err_handler; + } + + hdd_exit(); + return 0; + +err_handler: + + /* Start BSS failed, delete the interface */ + hdd_close_ndi(adapter); + return ret; +} + +int hdd_ndi_delete(uint8_t vdev_id, char *iface_name, uint16_t transaction_id) +{ + int ret; + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + uint8_t sta_id; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return -EINVAL; + } + + /* check if adapter by vdev_id is valid NDI */ + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter || !WLAN_HDD_IS_NDI(adapter)) { + hdd_err("NAN data interface %s is not available", iface_name); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (!sta_ctx) { + hdd_err("sta_ctx is NULL"); + return -EINVAL; + } + + sta_id = sta_ctx->broadcast_staid; + if (sta_id >= HDD_MAX_ADAPTERS) { + hdd_err("Error: Invalid sta id %u", sta_id); + return -EINVAL; + } + + /* Since, the interface is being deleted, remove the broadcast id. */ + hdd_ctx->sta_to_adapter[sta_id] = NULL; + + os_if_nan_set_ndp_delete_transaction_id(adapter->vdev, + transaction_id); + os_if_nan_set_ndi_state(adapter->vdev, NAN_DATA_NDI_DELETING_STATE); + + /* Delete the interface */ + ret = __wlan_hdd_del_virtual_intf(hdd_ctx->wiphy, &adapter->wdev); + if (ret) + hdd_err("NDI delete request failed"); + else + hdd_err("NDI delete request successfully issued"); + + return ret; +} + +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 hdd_station_ctx *sta_ctx; + struct csr_roam_info roam_info = {0}; + struct bss_description tmp_bss_descp = {0}; + struct qdf_mac_addr bc_mac_addr = QDF_MAC_ADDR_BCAST_INIT; + uint8_t sta_id; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err("adapter is null"); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (!sta_ctx) { + hdd_err("sta_ctx is null"); + return; + } + + sta_id = ndi_rsp->sta_id; + if (sta_id >= HDD_MAX_ADAPTERS) { + hdd_err("Error: Invalid sta id %u", sta_id); + return; + } + + if (ndi_rsp->status == QDF_STATUS_SUCCESS) { + hdd_alert("NDI interface successfully created"); + os_if_nan_set_ndp_create_transaction_id(adapter->vdev, 0); + os_if_nan_set_ndi_state(adapter->vdev, + NAN_DATA_NDI_CREATED_STATE); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } else { + hdd_alert("NDI interface creation failed with reason %d", + ndi_rsp->reason /* create_reason */); + } + + sta_ctx->broadcast_staid = sta_id; + hdd_save_peer(sta_ctx, sta_id, &bc_mac_addr); + hdd_roam_register_sta(adapter, &roam_info, sta_id, + &bc_mac_addr, &tmp_bss_descp); + hdd_ctx->sta_to_adapter[sta_id] = adapter; +} + +void hdd_ndi_close(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err("adapter is null"); + return; + } + + hdd_close_ndi(adapter); +} + +void hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + uint8_t sta_id; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err("adapter is null"); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (!sta_ctx) { + hdd_err("sta_ctx is null"); + return; + } + + sta_id = sta_ctx->broadcast_staid; + if (sta_id < HDD_MAX_ADAPTERS) { + hdd_ctx->sta_to_adapter[sta_id] = NULL; + hdd_roam_deregister_sta(adapter, sta_id); + hdd_delete_peer(sta_ctx, sta_id); + sta_ctx->broadcast_staid = HDD_WLAN_INVALID_STA_ID; + } + + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + complete(&adapter->disconnect_comp_var); +} + +void hdd_ndp_session_end_handler(struct hdd_adapter *adapter) +{ + os_if_nan_ndi_session_end(adapter->vdev); +} + +int hdd_ndp_get_peer_idx(uint8_t vdev_id, struct qdf_mac_addr *addr) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + return hdd_get_peer_idx(sta_ctx, addr); +} + +/** + * hdd_ndp_new_peer_handler() - NDP new peer indication handler + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Return: none + */ +int hdd_ndp_new_peer_handler(uint8_t vdev_id, uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, bool fist_peer) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + struct bss_description tmp_bss_descp = {0}; + struct csr_roam_info roam_info = {0}; + + hdd_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return -EINVAL; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (!sta_ctx) { + hdd_err("sta_ctx is null"); + return -EINVAL; + } + + if (sta_id >= HDD_MAX_ADAPTERS) { + hdd_err("Error: Invalid sta_id: %u", sta_id); + return -EINVAL; + } + + /* save peer in ndp ctx */ + if (false == hdd_save_peer(sta_ctx, sta_id, peer_mac_addr)) { + hdd_err("Ndp peer table full. cannot save new peer"); + return -EPERM; + } + + /* this function is called for each new peer */ + hdd_roam_register_sta(adapter, &roam_info, sta_id, + peer_mac_addr, &tmp_bss_descp); + hdd_ctx->sta_to_adapter[sta_id] = adapter; + /* perform following steps for first new peer ind */ + if (fist_peer) { + hdd_info("Set ctx connection state to connected"); + sta_ctx->conn_info.connState = eConnectionState_NdiConnected; + hdd_wmm_connect(adapter, &roam_info, eCSR_BSS_TYPE_NDI); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, WLAN_CONTROL_PATH); + } + hdd_exit(); + return 0; +} + + +/** + * hdd_ndp_peer_departed_handler() - Handle NDP peer departed indication + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * 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) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + + hdd_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) { + hdd_err("adapter is null"); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (!sta_ctx) { + hdd_err("sta_ctx is null"); + return; + } + + if (sta_id >= HDD_MAX_ADAPTERS) { + hdd_err("Error: Invalid sta_id: %u", sta_id); + return; + } + + hdd_roam_deregister_sta(adapter, sta_id); + hdd_delete_peer(sta_ctx, sta_id); + hdd_ctx->sta_to_adapter[sta_id] = NULL; + + if (last_peer) { + hdd_info("No more ndp peers."); + sta_ctx->conn_info.connState = eConnectionState_NdiDisconnected; + hdd_conn_set_connection_state(adapter, + eConnectionState_NdiDisconnected); + hdd_info("Stop netif tx queues."); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + + hdd_exit(); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..89583619a9c3b42d4d5ce86545f3fb3e20cec07b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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_tgt_cfg; +struct hdd_config; +struct hdd_adapter; +struct wireless_dev; + +/* NAN Social channels */ +#define NAN_SOCIAL_CHANNEL_2_4GHZ 6 +#define NAN_SOCIAL_CHANNEL_5GHZ_LOWER_BAND 44 +#define NAN_SOCIAL_CHANNEL_5GHZ_UPPER_BAND 149 + +#define NDP_BROADCAST_STAID (0) + +#ifdef WLAN_FEATURE_NAN_DATAPATH +#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.connState) +#else +#define WLAN_HDD_IS_NDI(adapter) (false) +#define WLAN_HDD_IS_NDI_CONNECTED(adapter) (false) +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +#ifdef WLAN_FEATURE_NAN_DATAPATH +void hdd_ndp_print_ini_config(struct hdd_context *hdd_ctx); +void hdd_nan_datapath_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg); +void hdd_ndp_event_handler(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roam_id, 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); +#else +static inline void hdd_ndp_print_ini_config(struct hdd_context *hdd_ctx) +{ +} +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 hdd_adapter *adapter, + struct csr_roam_info *roam_info, + uint32_t roam_id, + 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) +{ +} +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +enum nan_datapath_state; +struct nan_datapath_inf_create_rsp; + +int hdd_ndi_open(char *iface_name); +int hdd_ndi_start(char *iface_name, uint16_t transaction_id); +int hdd_ndi_delete(uint8_t vdev_id, char *iface_name, uint16_t transaction_id); +void hdd_ndi_close(uint8_t vdev_id); +void hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id, + struct nan_datapath_inf_create_rsp *ndi_rsp); +void hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id); +int hdd_ndp_get_peer_idx(uint8_t vdev_id, struct qdf_mac_addr *addr); +int hdd_ndp_new_peer_handler(uint8_t vdev_id, uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, bool fist_peer); +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_HDD_NAN_DATAPATH_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c new file mode 100644 index 0000000000000000000000000000000000000000..793edf8fd3a99a5d339f906eff67373e129f66a7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c @@ -0,0 +1,557 @@ +/* + * 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. + */ + +/** + * 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" + +/* 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(NULL == hif)) + QDF_ASSERT(NULL != 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 == NULL) + hdd_napi_ctx = hdd_napi_get_all(); + if (hdd_napi_ctx != NULL) + 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 (NULL == napid) { + hdd_err("unable to retrieve napi structure"); + rc = -EFAULT; + goto exit; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(NULL == hif_ctx)) { + QDF_ASSERT(NULL != 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(NULL == hdd_ctx)) { + QDF_ASSERT(0); + rc = -EFAULT; + goto exit; + } + + rc = hdd_napi_event(NAPI_EVT_INI_FILE, + (void *)hdd_ctx->napi_enable); + 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(NULL == hif_ctx)) + QDF_ASSERT(NULL != 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(NULL == hif_ctx)) + QDF_ASSERT(NULL != 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(NULL == hif)) + QDF_ASSERT(hif != NULL); /* 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(NULL == hif)) + QDF_ASSERT(hif != NULL); + else + rc = hif_napi_event(hif, event, data); + + NAPI_DEBUG("<--[rc=%d]", rc); + return rc; +} + +#if defined HELIUMPLUS && defined MSM_PLATFORM +/** + * 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 == NULL)) { + hdd_err("cannot get hdd_context"); + 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 + */ +static int napi_tput_policy_delay; +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("-->%s(tx=%lld, rx=%lld)", __func__, tx_packets, rx_packets); + + if (unlikely(napi_tput_policy_delay < 0)) + napi_tput_policy_delay = 0; + if (napi_tput_policy_delay > 0) { + NAPI_DEBUG("%s: delaying policy; delay-count=%d", + __func__, napi_tput_policy_delay); + napi_tput_policy_delay--; + + /* make sure the next timer call calls us */ + hddctx->cur_vote_level = -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 > hddctx->config->busBandwidthHighThreshold) + 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); + /* blacklist/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 != NULL) + hdd_ctx->cur_vote_level = -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" arrary for end of string char. + */ + char buf[6 * QCA_NAPI_NUM_BUCKETS + 1] = {'\0'}; + + napid = hdd_napi_get_all(); + if (NULL == napid) { + hdd_err("%s unable to retrieve napi structure", __func__); + return -EFAULT; + } + hdd_debug("[NAPI %u][BL %d]: scheds polls comps done t-lim p-lim corr max_time napi-buckets(%d)", + napid->napi_mode, + hif_napi_cpu_blacklist(napid, BLACKLIST_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_debug("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 (NULL == napid) { + hdd_err("%s unable to retrieve napi structure", __func__); + 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.c new file mode 100644 index 0000000000000000000000000000000000000000..ca589861543ae6e1a9f916ffc3d1ef89de078a65 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.c @@ -0,0 +1,503 @@ +/* + * 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. + */ + +/** + * DOC: contains nud event tracking main function definitions + */ + +#include "wlan_hdd_main.h" + +void hdd_nud_set_gateway_addr(struct hdd_adapter *adapter, + struct qdf_mac_addr gw_mac_addr) +{ + qdf_mem_copy(adapter->nud_tracking.gw_mac_addr.bytes, + gw_mac_addr.bytes, + sizeof(struct qdf_mac_addr)); + adapter->nud_tracking.is_gw_updated = true; +} + +void hdd_nud_cfg_print(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] value = [0x%x]", + CFG_ENABLE_NUD_TRACKING_NAME, + hdd_ctx->config->enable_nud_tracking); +} + +void hdd_nud_incr_gw_rx_pkt_cnt(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr) +{ + if (!adapter->nud_tracking.is_gw_rx_pkt_track_enabled) + return; + + if (!adapter->nud_tracking.is_gw_updated) + return; + + if (qdf_is_macaddr_equal(&adapter->nud_tracking.gw_mac_addr, + mac_addr)) + qdf_atomic_inc(&adapter + ->nud_tracking.tx_rx_stats.gw_rx_packets); +} + +void hdd_nud_flush_work(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (adapter->device_mode == QDF_STA_MODE && + hdd_ctx->config->enable_nud_tracking) { + hdd_debug("Flush the NUD work"); + qdf_disable_work(&adapter->nud_tracking.nud_event_work); + } +} + +void hdd_nud_deinit_tracking(struct hdd_adapter *adapter) +{ + hdd_debug("DeInitialize the NUD tracking"); + qdf_destroy_work(NULL, &adapter->nud_tracking.nud_event_work); +} + +void hdd_nud_ignore_tracking(struct hdd_adapter *adapter, bool ignoring) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (adapter->device_mode == QDF_STA_MODE && + hdd_ctx->config->enable_nud_tracking) + adapter->nud_tracking.ignore_nud_tracking = ignoring; +} + +void hdd_nud_reset_tracking(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (adapter->device_mode == QDF_STA_MODE && + hdd_ctx->config->enable_nud_tracking) { + hdd_debug("Reset the NUD tracking"); + + qdf_zero_macaddr(&adapter->nud_tracking.gw_mac_addr); + adapter->nud_tracking.is_gw_updated = false; + qdf_mem_zero(&adapter->nud_tracking.tx_rx_stats, + sizeof(struct hdd_nud_tx_rx_stats)); + + adapter->nud_tracking.curr_state = NUD_NONE; + qdf_atomic_set(&adapter + ->nud_tracking.tx_rx_stats.gw_rx_packets, 0); + } +} + +/** + * hdd_nud_stats_info() - display wlan NUD stats info + * @hdd_adapter: Pointer to hdd adapter + * + * Return: None + */ +static void hdd_nud_stats_info(struct hdd_adapter *adapter) +{ + struct netdev_queue *txq; + int i = 0; + + hdd_debug("**** NUD STATS: ****"); + hdd_debug("NUD Probe Tx : %d", + adapter->nud_tracking.tx_rx_stats.pre_tx_packets); + hdd_debug("NUD Probe Ack : %d", + adapter->nud_tracking.tx_rx_stats.pre_tx_acked); + hdd_debug("NUD Probe Rx : %d", + adapter->nud_tracking.tx_rx_stats.pre_rx_packets); + hdd_debug("NUD Failure Tx : %d", + adapter->nud_tracking.tx_rx_stats.post_tx_packets); + hdd_debug("NUD Failure Ack : %d", + adapter->nud_tracking.tx_rx_stats.post_tx_acked); + hdd_debug("NUD Failure Rx : %d", + adapter->nud_tracking.tx_rx_stats.post_rx_packets); + hdd_debug("NUD Gateway Rx : %d", + qdf_atomic_read(&adapter + ->nud_tracking.tx_rx_stats.gw_rx_packets)); + + hdd_debug("carrier state: %d", netif_carrier_ok(adapter->dev)); + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(adapter->dev, i); + hdd_debug("Queue: %d status: %d txq->trans_start: %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } + + hdd_debug("Current pause_map value %x", adapter->pause_map); +} + +/** + * hdd_nud_capture_stats() - capture wlan NUD stats + * @hdd_adapter: Pointer to hdd adapter + * @nud_state: NUD state for which stats to capture + * + * Return: None + */ +static void hdd_nud_capture_stats(struct hdd_adapter *adapter, + uint8_t nud_state) +{ + switch (nud_state) { + case NUD_INCOMPLETE: + case NUD_PROBE: + adapter->nud_tracking.tx_rx_stats.pre_tx_packets = + adapter->stats.tx_packets; + adapter->nud_tracking.tx_rx_stats.pre_rx_packets = + adapter->stats.rx_packets; + adapter->nud_tracking.tx_rx_stats.pre_tx_acked = + hdd_txrx_get_tx_ack_count(adapter); + break; + case NUD_FAILED: + adapter->nud_tracking.tx_rx_stats.post_tx_packets = + adapter->stats.tx_packets; + adapter->nud_tracking.tx_rx_stats.post_rx_packets = + adapter->stats.rx_packets; + adapter->nud_tracking.tx_rx_stats.post_tx_acked = + hdd_txrx_get_tx_ack_count(adapter); + break; + default: + break; + } +} + +/** + * hdd_nud_honour_failure() - check if nud failure to be honored + * @hdd_adapter: Pointer to hdd_adapter + * + * Return: true if nud failure to be honored, else false. + */ +static bool hdd_nud_honour_failure(struct hdd_adapter *adapter) +{ + uint32_t tx_transmitted; + uint32_t tx_acked; + uint32_t gw_rx_pkt; + + tx_transmitted = adapter->nud_tracking.tx_rx_stats.post_tx_packets - + adapter->nud_tracking.tx_rx_stats.pre_tx_packets; + tx_acked = adapter->nud_tracking.tx_rx_stats.post_tx_acked - + adapter->nud_tracking.tx_rx_stats.pre_tx_acked; + gw_rx_pkt = qdf_atomic_read(&adapter + ->nud_tracking.tx_rx_stats.gw_rx_packets); + + if (!tx_transmitted || !tx_acked || !gw_rx_pkt) { + hdd_debug("NUD_FAILURE_HONORED [mac:%pM]", + adapter->nud_tracking.gw_mac_addr.bytes); + hdd_nud_stats_info(adapter); + return true; + } + hdd_debug("NUD_FAILURE_NOT_HONORED [mac:%pM]", + adapter->nud_tracking.gw_mac_addr.bytes); + hdd_nud_stats_info(adapter); + return false; +} + +/** + * hdd_nud_set_tracking() - set the NUD tracking info + * @hdd_adapter: Pointer to hdd_adapter + * @nud_state: Current NUD state to set + * @capture_enabled: GW Rx packet to be capture or not + * + * Return: None + */ +static void hdd_nud_set_tracking(struct hdd_adapter *adapter, + uint8_t nud_state, + bool capture_enabled) +{ + adapter->nud_tracking.curr_state = nud_state; + qdf_atomic_set(&adapter->nud_tracking.tx_rx_stats.gw_rx_packets, 0); + adapter->nud_tracking.is_gw_rx_pkt_track_enabled = capture_enabled; +} + +/** + * __hdd_nud_failure_work() - work for nud event + * @data: Pointer to hdd_adapter + * + * Return: None + */ +static void __hdd_nud_failure_work(void *data) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + eConnectionState conn_state; + int status; + + hdd_enter(); + + if (!data) + return; + + adapter = (struct hdd_adapter *)data; + + 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; + + conn_state = (WLAN_HDD_GET_STATION_CTX_PTR(adapter)) + ->conn_info.connState; + + if (eConnectionState_Associated != conn_state) { + hdd_debug("Not in Connected State"); + return; + } + if (adapter->nud_tracking.curr_state != NUD_FAILED) { + hdd_debug("Not in NUD_FAILED state"); + return; + } + + qdf_mutex_acquire(&adapter->disconnection_status_lock); + if (adapter->disconnection_in_progress) { + qdf_mutex_release(&adapter->disconnection_status_lock); + hdd_debug("Disconnect is already in progress"); + return; + } + adapter->disconnection_in_progress = true; + qdf_mutex_release(&adapter->disconnection_status_lock); + + hdd_debug("Disconnecting STA with session id: %d", + adapter->session_id); + /* Issue Disconnect */ + status = wlan_hdd_disconnect(adapter, eCSR_DISCONNECT_REASON_DEAUTH); + if (0 != status) { + hdd_err("wlan_hdd_disconnect failed, status: %d", status); + hdd_set_disconnect_status(adapter, false); + } + + hdd_exit(); +} + +/** + * hdd_nud_failure_work() - work for nud event + * @data: Pointer to hdd_adapter + * + * Return: None + */ +static void hdd_nud_failure_work(void *data) +{ + cds_ssr_protect(__func__); + __hdd_nud_failure_work(data); + cds_ssr_unprotect(__func__); +} + +void hdd_nud_init_tracking(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (adapter->device_mode == QDF_STA_MODE && + hdd_ctx->config->enable_nud_tracking) { + hdd_debug("Initialize the NUD tracking"); + + qdf_zero_macaddr(&adapter->nud_tracking.gw_mac_addr); + qdf_mem_zero(&adapter->nud_tracking.tx_rx_stats, + sizeof(struct hdd_nud_tx_rx_stats)); + + adapter->nud_tracking.curr_state = NUD_NONE; + adapter->nud_tracking.ignore_nud_tracking = false; + adapter->nud_tracking.is_gw_updated = false; + + qdf_atomic_init(&adapter + ->nud_tracking.tx_rx_stats.gw_rx_packets); + qdf_create_work(0, &adapter->nud_tracking.nud_event_work, + hdd_nud_failure_work, + (void *)adapter); + } +} + +/** + * hdd_nud_process_failure_event() - processing NUD_FAILED event + * @hdd_adapter: Pointer to hdd_adapter + * + * Return: None + */ +static void hdd_nud_process_failure_event(struct hdd_adapter *adapter) +{ + uint8_t curr_state; + + curr_state = adapter->nud_tracking.curr_state; + if (curr_state == NUD_PROBE || curr_state == NUD_INCOMPLETE) { + hdd_nud_capture_stats(adapter, NUD_FAILED); + if (hdd_nud_honour_failure(adapter)) { + adapter->nud_tracking.curr_state = NUD_FAILED; + qdf_sched_work(0, &adapter + ->nud_tracking.nud_event_work); + } else { + hdd_nud_set_tracking(adapter, NUD_NONE, false); + } + } else { + hdd_debug("NUD FAILED -> Current State [0x%x]", curr_state); + } +} + +/** + * hdd_nud_filter_netevent() - filter netevents for STA interface + * @neighbour: Pointer to neighbour + * + * Return: None + */ +static void hdd_nud_filter_netevent(struct neighbour *neigh) +{ + int status; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + eConnectionState conn_state; + const struct net_device *netdev = neigh->dev; + + hdd_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + adapter = hdd_get_adapter_by_macaddr(hdd_ctx, netdev->dev_addr); + + if (!adapter) + return; + + status = hdd_validate_adapter(adapter); + if (status) + return; + + if (adapter->nud_tracking.ignore_nud_tracking) { + hdd_debug("NUD Tracking is Disabled"); + return; + } + + if (!adapter->nud_tracking.is_gw_updated) + return; + + if (adapter->device_mode != QDF_STA_MODE) + return; + + conn_state = (WLAN_HDD_GET_STATION_CTX_PTR(adapter)) + ->conn_info.connState; + + if (eConnectionState_Associated != conn_state) { + hdd_debug("Not in Connected State"); + return; + } + + if (!qdf_is_macaddr_equal(&adapter->nud_tracking.gw_mac_addr, + (struct qdf_mac_addr *)&neigh->ha[0])) + return; + + switch (neigh->nud_state) { + case NUD_PROBE: + case NUD_INCOMPLETE: + hdd_debug("NUD_START [0x%x]", neigh->nud_state); + hdd_nud_capture_stats(adapter, neigh->nud_state); + hdd_nud_set_tracking(adapter, + neigh->nud_state, + true); + break; + + case NUD_REACHABLE: + hdd_debug("NUD_REACHABLE [0x%x]", neigh->nud_state); + hdd_nud_set_tracking(adapter, NUD_NONE, false); + break; + + case NUD_FAILED: + hdd_debug("NUD_FAILED [0x%x]", neigh->nud_state); + hdd_nud_process_failure_event(adapter); + break; + default: + hdd_debug("NUD Event For Other State [0x%x]", + neigh->nud_state); + break; + } + hdd_exit(); +} + +/** + * __hdd_nud_netevent_cb() - netevent callback + * @nb: Pointer to notifier block + * @event: Net Event triggered + * @data: Pointer to neighbour struct + * + * Callback for netevent + * + * Return: None + */ +static void __hdd_nud_netevent_cb(struct notifier_block *nb, + unsigned long event, + void *data) +{ + hdd_enter(); + hdd_nud_filter_netevent(data); + hdd_exit(); +} + +/** + * hdd_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 hdd_nud_netevent_cb(struct notifier_block *nb, unsigned long event, + void *data) +{ + switch (event) { + case NETEVENT_NEIGH_UPDATE: + cds_ssr_protect(__func__); + __hdd_nud_netevent_cb(nb, event, data); + cds_ssr_unprotect(__func__); + break; + case NETEVENT_REDIRECT: + default: + break; + } + return 0; +} + +static struct notifier_block wlan_netevent_nb = { + .notifier_call = hdd_nud_netevent_cb +}; + +int hdd_nud_register_netevent_notifier(struct hdd_context *hdd_ctx) +{ + int ret = 0; + + if (hdd_ctx->config->enable_nud_tracking) { + ret = register_netevent_notifier(&wlan_netevent_nb); + if (!ret) + hdd_debug("Registered netevent notifier"); + } + return ret; +} + +void hdd_nud_unregister_netevent_notifier(struct hdd_context *hdd_ctx) +{ + int ret; + + if (hdd_ctx->config->enable_nud_tracking) { + ret = unregister_netevent_notifier(&wlan_netevent_nb); + if (!ret) + hdd_debug("Unregistered netevent notifier"); + } +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.h new file mode 100644 index 0000000000000000000000000000000000000000..3bd741169ba4bcc44b22da69c8a7eac70a3800ca --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.h @@ -0,0 +1,208 @@ + /* + * 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. + */ + +/** + * DOC: contains nud event tracking function declarations + */ + +#ifndef _WLAN_NUD_TRACKING_H_ +#define _WLAN_NUD_TRACKING_H_ + +#ifdef WLAN_NUD_TRACKING + +/** + * struct hdd_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 hdd_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 hdd_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 hdd_nud_tracking_info { + uint8_t curr_state; + bool ignore_nud_tracking; + struct hdd_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; +}; + +/** + * hdd_nud_set_gateway_addr() - set gateway mac address + * @adapter: Pointer to adapter + * @gw_mac_addr: mac address to be set + * + * Return: none + */ +void hdd_nud_set_gateway_addr(struct hdd_adapter *adapter, + struct qdf_mac_addr gw_mac_addr); + +/** +* hdd_nud_cfg_print() - Print nud tracking related parameters +* @hdd_ctx: Pointer to HDD context +* +* Return: None +*/ +void hdd_nud_cfg_print(struct hdd_context *hdd_ctx); + +/** + * hdd_nud_incr_gw_rx_pkt_cnt() - Increment rx count for gateway + * @adapter: Pointer to adapter + * @mac_addr: Gateway mac address + * + * Return: None + */ +void hdd_nud_incr_gw_rx_pkt_cnt(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr); + +/** + * hdd_nud_init_tracking() - initialize NUD tracking + * @hdd_adapter: Pointer to hdd adapter + * + * Return: None + */ +void hdd_nud_init_tracking(struct hdd_adapter *adapter); + +/** + * hdd_nud_reset_tracking() - reset NUD tracking + * @hdd_adapter: Pointer to hdd adapter + * + * Return: None + */ +void hdd_nud_reset_tracking(struct hdd_adapter *adapter); + +/** + * hdd_nud_deinit_tracking() - deinitialize NUD tracking + * @hdd_adapter: Pointer to hdd adapter + * + * Return: None + */ +void hdd_nud_deinit_tracking(struct hdd_adapter *adapter); + +/** + * hdd_nud_ignore_tracking() - set/reset nud trackig status + * @data: Pointer to hdd_adapter + * @ignoring: Ignore status to set + * + * Return: None + */ +void hdd_nud_ignore_tracking(struct hdd_adapter *adapter, + bool ignoring); + +/** + * hdd_nud_register_netevent_notifier - Register netevent notifiers. + * @hdd_ctx: HDD context + * + * Register netevent notifiers. + * + * Return: 0 on success and errno on failure + */ +int hdd_nud_register_netevent_notifier(struct hdd_context *hdd_ctx); + +/** + * hdd_nud_unregister_netevent_notifier - Unregister netevent notifiers. + * @hdd_ctx: HDD context + * + * Unregister netevent notifiers. + * + * Return: None + */ +void hdd_nud_unregister_netevent_notifier(struct hdd_context *hdd_ctx); + +/** + * hdd_nud_flush_work() - flush pending nud work + * @adapter: Pointer to hdd adapter + * + * Return: None + */ +void hdd_nud_flush_work(struct hdd_adapter *adapter); + +#else +static inline void hdd_nud_set_gateway_addr(struct hdd_adapter *adapter, + struct qdf_mac_addr gw_mac_addr) +{ +} + +static inline void hdd_nud_cfg_print(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_nud_incr_gw_rx_pkt_cnt(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr) +{ +} + +static inline void hdd_nud_init_tracking(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_nud_reset_tracking(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_nud_deinit_tracking(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_nud_ignore_tracking(struct hdd_adapter *adapter, + bool status) +{ +} + +static inline int +hdd_nud_register_netevent_notifier(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline void +hdd_nud_unregister_netevent_notifier(struct hdd_context *hdd_ctx) +{ +} + +static inline void +hdd_nud_flush_work(struct hdd_adapter *adapter) +{ +} +#endif /* WLAN_NUD_TRACKING */ +#endif /* end of _WLAN_NUD_TRACKING_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.c new file mode 100644 index 0000000000000000000000000000000000000000..8e52a0dc965383f669e1f39d76ff1d3249d66064 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.c @@ -0,0 +1,393 @@ +/* + * 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: HDD object manager API source file to create/destroy PSOC, + * PDEV, VDEV and PEER objects. + */ + +#include +#include +#include +#include +#include + +#define LOW_2GHZ_FREQ 2312 +#define HIGH_2GHZ_FREQ 2732 +#define LOW_5GHZ_FREQ 4912 +#define HIGH_5GHZ_FREQ 6100 + +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 struct vdev_osif_priv * +hdd_init_vdev_os_priv(struct hdd_adapter *adapter) +{ + struct vdev_osif_priv *os_priv; + + os_priv = qdf_mem_malloc(sizeof(*os_priv)); + if (!os_priv) + return NULL; + + /* Initialize the vdev OS private structure*/ + os_priv->wdev = adapter->dev->ieee80211_ptr; + os_priv->legacy_osif_priv = adapter; + + return os_priv; +} + +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) { + hdd_err("qdf ctx is null, can't set to soc object"); + 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); +} + +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; + + if (!psoc) { + hdd_err("Psoc NULL"); + return -EINVAL; + } + + priv = qdf_mem_malloc(sizeof(*priv)); + if (priv == NULL) { + hdd_err("pdev os obj create failed"); + 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; + } + reg_cap_ptr->phy_id = 0; + reg_cap_ptr->low_2ghz_chan = LOW_2GHZ_FREQ; + reg_cap_ptr->high_2ghz_chan = HIGH_2GHZ_FREQ; + reg_cap_ptr->low_5ghz_chan = LOW_5GHZ_FREQ; + reg_cap_ptr->high_5ghz_chan = HIGH_5GHZ_FREQ; + + 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_create_and_store_vdev(struct wlan_objmgr_pdev *pdev, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + int errno = 0; + struct wlan_objmgr_vdev *vdev; + struct vdev_osif_priv *osif_priv; + struct wlan_vdev_create_params vdev_params = {0}; + + QDF_BUG(pdev); + if (!pdev) { + hdd_err("pdev is null"); + return -EINVAL; + } + + osif_priv = hdd_init_vdev_os_priv(adapter); + if (!osif_priv) { + hdd_err("Failed to allocate osif_priv; out of memory"); + return -ENOMEM; + } + + vdev_params.opmode = adapter->device_mode; + vdev_params.osifp = osif_priv; + qdf_mem_copy(vdev_params.macaddr, + adapter->mac_addr.bytes, + QDF_NET_MAC_ADDR_MAX_LEN); + + vdev = wlan_objmgr_vdev_obj_create(pdev, &vdev_params); + if (!vdev) { + hdd_err("Failed to create vdev object"); + errno = -ENOMEM; + qdf_mem_free(osif_priv); + return errno; + } + + /* + * To enable legacy use cases, we need to delay physical vdev destroy + * until after the sme session has been closed. We accomplish this by + * getting a reference here. + */ + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to acquire vdev ref; status:%d", status); + errno = qdf_status_to_os_return(status); + goto vdev_destroy; + } + + qdf_spin_lock_bh(&adapter->vdev_lock); + adapter->vdev = vdev; + adapter->session_id = wlan_vdev_get_id(vdev); + qdf_spin_unlock_bh(&adapter->vdev_lock); + + return 0; + +vdev_destroy: + wlan_objmgr_vdev_obj_delete(vdev); + return errno; +} + +int hdd_objmgr_release_and_destroy_vdev(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + qdf_spin_lock_bh(&adapter->vdev_lock); + vdev = adapter->vdev; + adapter->vdev = NULL; + adapter->session_id = HDD_SESSION_ID_INVALID; + qdf_spin_unlock_bh(&adapter->vdev_lock); + + QDF_BUG(vdev); + if (!vdev) + return -EINVAL; + + status = wlan_objmgr_vdev_obj_delete(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + + return qdf_status_to_os_return(status); +} + +struct wlan_objmgr_vdev *__hdd_objmgr_get_vdev(struct hdd_adapter *adapter, + const char *func) +{ + struct wlan_objmgr_vdev *vdev = NULL; + QDF_STATUS status; + + if (!adapter) { + hdd_err("Adapter is NULL (via %s)", func); + return NULL; + } + + qdf_spin_lock_bh(&adapter->vdev_lock); + vdev = adapter->vdev; + if (vdev) { + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_OSIF_ID); + if (QDF_IS_STATUS_ERROR(status)) + vdev = NULL; + } + qdf_spin_unlock_bh(&adapter->vdev_lock); + + if (!vdev) + hdd_err("VDEV is NULL (via %s)", func); + + return vdev; +} + +void __hdd_objmgr_put_vdev(struct wlan_objmgr_vdev *vdev, const char *func) +{ + if (!vdev) { + hdd_err("VDEV is NULL (via %s)", func); + return; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); +} + +int hdd_objmgr_set_peer_mlme_auth_state(struct wlan_objmgr_vdev *vdev, + bool is_authenticated) +{ + struct wlan_objmgr_peer *peer; + QDF_STATUS status; + + wlan_vdev_obj_lock(vdev); + peer = wlan_vdev_get_bsspeer(vdev); + wlan_vdev_obj_unlock(vdev); + + if (!peer) { + hdd_err("peer is null"); + + return -EINVAL; + } + status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_NB_ID); + if (status != QDF_STATUS_SUCCESS) + 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_TDLS_NB_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; + + wlan_vdev_obj_lock(vdev); + peer = wlan_vdev_get_bsspeer(vdev); + wlan_vdev_obj_unlock(vdev); + + 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); + + return 0; +} + diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..d11e09076bd4cec99d19b2d37748860eab290cc7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.h @@ -0,0 +1,185 @@ +/* + * 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. + */ + +#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 + * + * 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_create_and_store_vdev() - Create vdev and store in hdd adapter + * @pdev: pdev pointer + * @adapter: hdd adapter + * + * This API creates the vdev object and store the vdev reference to the + * given @adapter. Also, creates a self peer for the vdev. + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_create_and_store_vdev(struct wlan_objmgr_pdev *pdev, + struct hdd_adapter *adapter); + +/** + * hdd_objmgr_release_and_destroy_vdev() - Delete vdev and remove from adapter + * @adapter: hdd adapter + * + * This API deletes vdev object and release its reference from hdd adapter + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_release_and_destroy_vdev(struct hdd_adapter *adapter); + +/** + * hdd_objmgr_get_vdev() - Get reference of vdev from adapter + * @adapter: hdd adapter + * + * This API gets vdev object reference from hdd adapter + * + * Return: pointer to vdev object for success, NULL for failure + */ +#define hdd_objmgr_get_vdev(adapter) \ + __hdd_objmgr_get_vdev(adapter, __func__) +struct wlan_objmgr_vdev *__hdd_objmgr_get_vdev(struct hdd_adapter *adapter, + const char *func); + +/** + * hdd_objmgr_put_vdev() - Release reference of vdev object + * @vdev: pointer to vdev object + * + * This API releases vdev object reference which was acquired using + * hdd_objmgr_get_vdev(). + * + * Return: void + */ +#define hdd_objmgr_put_vdev(vdev) \ + __hdd_objmgr_put_vdev(vdev, __func__) +void __hdd_objmgr_put_vdev(struct wlan_objmgr_vdev *vdev, const char *func); + +/** + * 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); + +#endif /* end #if !defined(WLAN_HDD_OBJECT_MANAGER_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c new file mode 100644 index 0000000000000000000000000000000000000000..a352b3b04e97e171af82d4012f602bfa8cfbfabe --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c @@ -0,0 +1,2060 @@ +/* + * 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: wlan_hdd_ocb.c + * + * WLAN Host Device Driver 802.11p OCB implementation + */ + +#include "cds_sched.h" +#include "wlan_hdd_assoc.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 + +/* 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 + +/** + * hdd_set_dot11p_config() - Set 802.11p config flag + * @hdd_ctx: HDD Context pointer + * + * TODO-OCB: This has been temporarily added to ensure this parameter + * is set in CSR when we init the channel list. This should be removed + * once the 5.9 GHz channels are added to the regulatory domain. + */ +void hdd_set_dot11p_config(struct hdd_context *hdd_ctx) +{ + sme_set_dot11p_config(hdd_ctx->mac_handle, + hdd_ctx->config->dot11p_mode != + WLAN_HDD_11P_DISABLED); +} + +/** + * 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 < MAX_NUM_AC; 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 + * @center_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 + * @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_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + uint8_t peer_id; + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + qdf_status = cdp_peer_register_ocb_peer(soc, + adapter->mac_addr.bytes, + &peer_id); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Error registering OCB Self Peer!"); + return -EINVAL; + } + + if (peer_id >= HDD_MAX_ADAPTERS) { + hdd_err("Error: Invalid peer_id: %u", peer_id); + return -EINVAL; + } + + hdd_ctx->sta_to_adapter[peer_id] = adapter; + + sta_desc.sta_id = peer_id; + sta_desc.is_qos_enabled = 1; + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_rx_packet_cbk; + cdp_vdev_register(soc, + (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, adapter->session_id), + adapter, &txrx_ops); + txrx_ops.rx.stats_rx = hdd_tx_rx_collect_connectivity_stats_info; + adapter->tx_fn = txrx_ops.tx.tx; + + qdf_status = cdp_peer_register(soc, + (struct cdp_pdev *)pdev, &sta_desc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + return -EINVAL; + } + + if (sta_ctx->conn_info.staId[0] != HDD_WLAN_INVALID_STA_ID && + sta_ctx->conn_info.staId[0] != peer_id) { + hdd_err("The ID for the OCB station has changed."); + } + + sta_ctx->conn_info.staId[0] = peer_id; + qdf_copy_macaddr(&sta_ctx->conn_info.peerMacAddress[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, + }; + + 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); + + 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(adapter->vdev, config, + hdd_ocb_set_config_callback, + cookie); + 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); + + /* fall through */ +end: + osif_request_put(request); + + return rc; +} + +/** + * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED + * ioctl + * @dev: Pointer to net_device structure + * @iw_request_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 == NULL) { + hdd_err("Failed to allocate memory!"); + return -ENOMEM; + } + + /* Identify the vdev interface */ + config->vdev_id = adapter->session_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 == NULL) { + 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 < MAX_NUM_AC; 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 + * @iw_request_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 ret; + + cds_ssr_protect(__func__); + ret = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static 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 + }, +}; + +static 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 + }, +}; + +static 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 + }, +}; + +static 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 + }, +}; + +static 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 + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = { + .type = NLA_U32 + }, +}; + +static 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 + * @mac_address: MAC address assigned to this channel + * @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[MAX_NUM_AC]; + 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 (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 == NULL) { + 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->session_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 == NULL) { + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_set_config(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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; + int rc = -EINVAL; + + hdd_enter_dev(dev); + + 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->session_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) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + utc->vdev_id = adapter->session_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); + + if (ucfg_ocb_set_utc_time(adapter->vdev, utc) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while setting UTC time"); + rc = -EINVAL; + } else { + rc = 0; + } + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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; + int rc = -EINVAL; + + hdd_enter_dev(dev); + + 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->session_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + timing_advert = qdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + timing_advert->vdev_id = adapter->session_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; + } + + if (ucfg_ocb_start_timing_advert(adapter->vdev, timing_advert) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while starting timing advert"); + rc = -EINVAL; + } else { + rc = 0; + } + +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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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; + int rc = -EINVAL; + + hdd_enter_dev(dev); + + 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->session_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + timing_advert = qdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + timing_advert->vdev_id = adapter->session_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]); + + if (ucfg_ocb_stop_timing_advert(adapter->vdev, timing_advert) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while stopping timing advert"); + rc = -EINVAL; + } else { + rc = 0; + } + +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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len); + if (!nl_resp) { + hdd_err("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 = cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc); + goto end; + } +end: + if (nl_resp) + kfree_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, + }; + + hdd_enter_dev(dev); + + 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->session_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); + + tsf_request.vdev_id = adapter->session_id; + status = ucfg_ocb_get_tsf_timer(adapter->vdev, &tsf_request, + hdd_ocb_get_tsf_timer_callback, + cookie); + 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; + } + + /* fall through */ +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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len); + if (!nl_resp) { + hdd_err("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 = cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc); + goto end; + } +end: + if (nl_resp) + kfree_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, + }; + + hdd_enter_dev(dev); + + 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->session_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->session_id; + dcc_request.channel_count = channel_count; + dcc_request.request_array_len = request_array_len; + dcc_request.request_array = request_array; + + status = ucfg_ocb_dcc_get_stats(adapter->vdev, &dcc_request, + hdd_dcc_get_stats_callback, + cookie); + 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; + } + + /* fall through */ +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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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]; + + hdd_enter_dev(dev); + + 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->session_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; + } + + if (ucfg_ocb_dcc_clear_stats(adapter->vdev, adapter->session_id, + nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) != + QDF_STATUS_SUCCESS) { + hdd_err("Failed to clear DCC stats."); + return -EINVAL; + } + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +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, + }; + + hdd_enter_dev(dev); + + 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->session_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 > 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->session_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; + + status = ucfg_ocb_dcc_update_ndl(adapter->vdev, &dcc_request, + hdd_dcc_update_ndl_callback, + cookie); + 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; + } + + /* fall through */ +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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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; + + hdd_enter(); + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, sizeof(uint32_t) + resp->channel_stats_array_len + + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("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"); + kfree_skb(vendor_event); + return; + } + + 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h new file mode 100644 index 0000000000000000000000000000000000000000..43470370d38ff679c535191637128e316dbdda7e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h @@ -0,0 +1,372 @@ +/* + * Copyright (c) 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 __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[MAX_NUM_AC]; + 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_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 + */ +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_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 + */ +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_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 + */ +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_CHANNEL_FREQ: + * the channel frequency on which to stop the timing advert + */ +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_dcc_get_tsf_response - vendor subcmd to get TSF + * timer 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 + */ +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_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 + */ +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_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 + */ +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_BITMAP: + * mask of the type of stats to be cleared + */ +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_ocb_set_config - vendor subcmd to update dcc + * @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 + */ +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_FEATURE_DSRC +void hdd_set_dot11p_config(struct hdd_context *hdd_ctx); + +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +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 void hdd_set_dot11p_config(struct hdd_context *hdd_ctx) +{ +} + +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; +} + +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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c new file mode 100644 index 0000000000000000000000000000000000000000..40f32e20f382e6b94d64a5e2acda1c10f47b56a8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c @@ -0,0 +1,1129 @@ +/* + * 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. + */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * DOC: wlan_hdd_oemdata.c + * + * Support for generic OEM Data Request handling + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "qwlan_version.h" +#include "cds_utils.h" +#include "wma.h" +#include "sme_api.h" +#include "wlan_nlink_srv.h" + +#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; + uint8_t *chan_list; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + config = hdd_ctx->config; + if (!config) { + hdd_err("HDD configuration is null"); + return -EINVAL; + } + chan_list = qdf_mem_malloc(sizeof(uint8_t) * OEM_CAP_MAX_NUM_CHANNELS); + if (NULL == chan_list) { + hdd_err("Memory allocation failed"); + 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; + data_cap->allowed_dwell_time_min = config->nNeighborScanMinChanTime; + data_cap->allowed_dwell_time_max = config->nNeighborScanMaxChanTime; + data_cap->curr_dwell_time_min = + sme_get_neighbor_scan_min_chan_time(hdd_ctx->mac_handle, + adapter->session_id); + data_cap->curr_dwell_time_max = + sme_get_neighbor_scan_max_chan_time(hdd_ctx->mac_handle, + adapter->session_id); + data_cap->supported_bands = config->nBandCapability; + + /* request for max num of channels */ + num_chan = OEM_CAP_MAX_NUM_CHANNELS; + status = sme_get_cfg_valid_channels( + &chan_list[0], &num_chan); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to get valid channel list, status: %d", status); + qdf_mem_free(chan_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_list", + num_chan, OEM_CAP_MAX_NUM_CHANNELS); + qdf_mem_free(chan_list); + return -ENOMEM; + } + + data_cap->num_channels = num_chan; + qdf_mem_copy(data_cap->channel_list, chan_list, + sizeof(uint8_t) * num_chan); + + qdf_mem_free(chan_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) +{ + int status; + struct oem_data_cap oemDataCap = { {0} }; + struct oem_data_cap *pHddOemDataCap; + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *pHddContext; + int ret; + + hdd_enter(); + + pHddContext = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(pHddContext); + if (0 != ret) + return ret; + + status = populate_oem_data_cap(adapter, &oemDataCap); + if (0 != status) { + hdd_err("Failed to populate oem data capabilities"); + return status; + } + + pHddOemDataCap = (struct oem_data_cap *) (extra); + *pHddOemDataCap = oemDataCap; + + 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 *aniHdr; + uint8_t *buf; + uint8_t *numInterfaces; + uint8_t *deviceMode; + uint8_t *vdevId; + struct hdd_adapter *adapter; + + /* 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 == NULL) + 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; + aniHdr = NLMSG_DATA(nlh); + aniHdr->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 *)aniHdr + sizeof(tAniMsgHdr)); + numInterfaces = buf++; + *numInterfaces = 0; + + /* Iterate through each adapter and fill device mode and vdev id */ + hdd_for_each_adapter(p_hdd_ctx, adapter) { + deviceMode = buf++; + vdevId = buf++; + *deviceMode = adapter->device_mode; + *vdevId = adapter->session_id; + (*numInterfaces)++; + hdd_debug("numInterfaces: %d, deviceMode: %d, vdevId: %d", + *numInterfaces, *deviceMode, + *vdevId); + } + + aniHdr->length = + sizeof(uint8_t) + (*numInterfaces) * 2 * sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + hdd_debug("sending App Reg Response length: %d to pid: %d", + aniHdr->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 *aniHdr; + uint8_t *buf; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) + 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; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_OEM_ERROR; + aniHdr->length = sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length); + + /* message body will contain one byte of error code */ + buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr)); + *buf = error_code; + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->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 == NULL) + 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) { + hdd_err("malloc failed for data req buffer"); + 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_data_req(p_hdd_ctx->mac_handle, &oem_data_req); + + qdf_mem_free(oem_data_req.data); + oem_data_req.data = NULL; + + return status; +} + +/** + * update_channel_bw_info() - set bandwidth info for the chan + * @hdd_ctx: hdd context + * @chan: channel for which info are required + * @chan_info: struct where the bandwidth info is filled + * + * This function find the maximum bandwidth allowed, secondary + * channel offset and center freq for the channel as per regulatory + * domain and using these info calculate the phy mode for the + * channel. + * + * Return: void + */ +void hdd_update_channel_bw_info(struct hdd_context *hdd_ctx, + uint16_t chan, void *chan_info) +{ + struct ch_params ch_params = {0}; + uint16_t sec_ch_2g = 0; + WLAN_PHY_MODE phy_mode; + uint32_t wni_dot11_mode; + tHddChannelInfo *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(hdd_ctx->pdev, chan, sec_ch_2g, &ch_params); + 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, 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 = MODE_UNKNOWN; + + hdd_debug("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d phy_mode %d", + chan, wni_dot11_mode, ch_params.ch_width, + ch_params.sec_ch_offset, + hdd_chan_info->band_center_freq1, phy_mode); + + WMI_SET_CHANNEL_MODE(hdd_chan_info, 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 *aniHdr; + struct hdd_channel_info *pHddChanInfo; + struct hdd_channel_info hddChanInfo; + uint8_t chanId; + uint32_t reg_info_1; + uint32_t reg_info_2; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i; + uint8_t *buf; + + /* 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 == NULL) + 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; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP; + + aniHdr->length = + sizeof(uint8_t) + numOfChannels * sizeof(*pHddChanInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + /* First byte of message body will have num of channels */ + buf = (char *)((char *)aniHdr + 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)); + + chanId = chanList[i]; + status = sme_get_reg_info(p_hdd_ctx->mac_handle, chanId, + ®_info_1, ®_info_2); + if (QDF_STATUS_SUCCESS == status) { + /* copy into hdd chan info struct */ + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = cds_chan_to_freq(chanId); + hddChanInfo.band_center_freq1 = hddChanInfo.mhz; + hddChanInfo.band_center_freq2 = 0; + + hddChanInfo.info = 0; + if (CHANNEL_STATE_DFS == + wlan_reg_get_channel_state(p_hdd_ctx->pdev, chanId)) + WMI_SET_CHANNEL_FLAG(&hddChanInfo, + WMI_CHAN_FLAG_DFS); + + hdd_update_channel_bw_info(p_hdd_ctx, + chanId, &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", + chanId); + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = 0; + 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) + aniHdr->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 == NULL) + 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 == NULL) + 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; +} + +/** + * hdd_send_peer_status_ind_to_oem_app() - + * Function to send peer status to a registered application + * @peerMac: MAC address of peer + * @peerStatus: ePeerConnected or ePeerDisconnected + * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @sessionId: SME session id, i.e. 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 *peerMac, + uint8_t peerStatus, + uint8_t peerTimingMeasCap, + uint8_t sessionId, + tSirSmeChanInfo *chan_info, + enum QDF_OPMODE dev_mode) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + struct peer_status_info *pPeerInfo; + + 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(*pPeerInfo)), + GFP_KERNEL); + if (skb == NULL) + 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; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_PEER_STATUS_IND; + + aniHdr->length = sizeof(*pPeerInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + pPeerInfo = (struct peer_status_info *) ((char *)aniHdr + sizeof(tAniMsgHdr)); + + qdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes, + sizeof(peerMac->bytes)); + pPeerInfo->peer_status = peerStatus; + pPeerInfo->vdev_id = sessionId; + pPeerInfo->peer_capability = peerTimingMeasCap; + pPeerInfo->reserved0 = 0; + /* Set 0th bit of reserved0 for STA mode */ + if (QDF_STA_MODE == dev_mode) + pPeerInfo->reserved0 |= 0x01; + + if (chan_info) { + pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id; + pPeerInfo->peer_chan_info.reserved0 = 0; + pPeerInfo->peer_chan_info.mhz = chan_info->mhz; + pPeerInfo->peer_chan_info.band_center_freq1 = + chan_info->band_center_freq1; + pPeerInfo->peer_chan_info.band_center_freq2 = + chan_info->band_center_freq2; + pPeerInfo->peer_chan_info.info = chan_info->info; + pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1; + pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2; + } else { + pPeerInfo->peer_chan_info.chan_id = 0; + pPeerInfo->peer_chan_info.reserved0 = 0; + pPeerInfo->peer_chan_info.mhz = 0; + pPeerInfo->peer_chan_info.band_center_freq1 = 0; + pPeerInfo->peer_chan_info.band_center_freq2 = 0; + pPeerInfo->peer_chan_info.info = 0; + pPeerInfo->peer_chan_info.reg_info_1 = 0; + pPeerInfo->peer_chan_info.reg_info_2 = 0; + } + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + hdd_info("sending peer " MAC_ADDRESS_STR + " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%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)", + MAC_ADDR_ARRAY(peerMac->bytes), + peerStatus, peerTimingMeasCap, + sessionId, pPeerInfo->peer_chan_info.chan_id, + p_hdd_ctx->oem_pid, + pPeerInfo->peer_chan_info.band_center_freq1, + pPeerInfo->peer_chan_info.band_center_freq2, + pPeerInfo->peer_chan_info.info, + pPeerInfo->peer_chan_info.mhz, + pPeerInfo->peer_chan_info.reg_info_1, + pPeerInfo->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) || + (WNI_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) { + hdd_err("hdd ctx validate fails"); + 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = oem_msg_callback(skb); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c new file mode 100644 index 0000000000000000000000000000000000000000..d1e3cbbcc44d90e820f6da91019e3a1580effbca --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c @@ -0,0 +1,1418 @@ +/* + * 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 wlan_hdd_p2p.c + * + * @brief WLAN Host Device Driver implementation for P2P commands interface + * + */ + +#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_hdd_object_manager.h" + +/* Ms to Time Unit Micro Sec */ +#define MS_TO_TU_MUS(x) ((x) * 1024) +#define MAX_MUS_VAL (INT_MAX / 1024) + +#ifdef WLAN_FEATURE_P2P_DEBUG +#define MAX_P2P_ACTION_FRAME_TYPE 9 +const char *p2p_action_frame_type[] = { "GO Negotiation Request", + "GO Negotiation Response", + "GO Negotiation Confirmation", + "P2P Invitation Request", + "P2P Invitation Response", + "Device Discoverability Request", + "Device Discoverability Response", + "Provision Discovery Request", + "Provision Discovery Response"}; + +#endif +#define MAX_TDLS_ACTION_FRAME_TYPE 11 +const char *tdls_action_frame_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"}; + +void wlan_hdd_cancel_existing_remain_on_channel(struct hdd_adapter *adapter) +{ + if (!adapter) { + hdd_err("null adapter"); + return; + } + + ucfg_p2p_cleanup_roc_by_vdev(adapter->vdev); +} + +int wlan_hdd_check_remain_on_channel(struct hdd_adapter *adapter) +{ + if (QDF_P2P_GO_MODE != adapter->device_mode) + wlan_hdd_cancel_existing_remain_on_channel(adapter); + + return 0; +} + +/* Clean up RoC context at hdd_stop_adapter*/ +void wlan_hdd_cleanup_remain_on_channel_ctx(struct hdd_adapter *adapter) +{ + if (!adapter) { + hdd_err("null adapter"); + return; + } + + ucfg_p2p_cleanup_roc_by_vdev(adapter->vdev); +} + +void wlan_hdd_cleanup_actionframe(struct hdd_adapter *adapter) +{ + if (!adapter) { + hdd_err("null adapter"); + return; + } + + ucfg_p2p_cleanup_tx_by_vdev(adapter->vdev); +} + +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; + 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; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + status = wlan_cfg80211_roc(adapter->vdev, chan, duration, cookie); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_remain_on_channel(wiphy, + wdev, + chan, + duration, cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +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); + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + status = wlan_cfg80211_cancel_roc(adapter->vdev, cookie); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, + wdev, + cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +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); + uint8_t type; + uint8_t sub_type; + QDF_STATUS qdf_status; + int ret; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + hdd_err("wlan_hdd_validate_context return:%d", ret); + return ret; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]); + sub_type = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]); + + /* 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) && + (type == SIR_MAC_MGMT_FRAME && + sub_type == SIR_MAC_MGMT_AUTH)) { + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_SME, + TRACE_CODE_HDD_SEND_MGMT_TX, + wlan_vdev_get_id(adapter->vdev), 0); + + qdf_status = sme_send_mgmt_tx(hdd_ctx->mac_handle, + adapter->session_id, buf, len); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + return 0; + else + return -EINVAL; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_OS_IF, + TRACE_CODE_HDD_SEND_MGMT_TX, + wlan_vdev_get_id(adapter->vdev), 0); + + status = wlan_cfg80211_mgmt_tx(adapter->vdev, chan, offchan, wait, buf, + len, no_cck, dont_wait_for_ack, cookie); + hdd_debug("mgmt tx, status:%d, cookie:0x%llx", 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 ret; + + cds_ssr_protect(__func__); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + ret = __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 + ret = __wlan_hdd_mgmt_tx(wiphy, wdev, chan, offchan, + wait, buf, len, no_cck, + dont_wait_for_ack, cookie); +#endif /* LINUX_VERSION_CODE */ + cds_ssr_unprotect(__func__); + + return ret; +} + +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); + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + status = wlan_cfg80211_mgmt_tx_cancel(adapter->vdev, cookie); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev, cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_set_p2p_noa + * + ***FUNCTION: + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_NOA command from wpa_supplicant using private ioctl + * + ***LOGIC: + * Fill noa Struct According to P2P Power save Option and Pass it to SME layer + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param dev Pointer to net device structure + * @param command Pointer to command + * + * @return Status + */ + +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; + char *param; + int ret; + + param = strnchr(command, strlen(command), ' '); + if (param == NULL) { + hdd_err("strnchr failed to find delimeter"); + return -EINVAL; + } + param++; + ret = sscanf(param, "%d %d %d", &count, &interval, &duration); + if (ret != 3) { + hdd_err("P2P_SET GO noa: fail to read params, ret=%d", + ret); + return -EINVAL; + } + if (count < 0 || interval < 0 || duration < 0 || + 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", + count, interval, duration); + duration = MS_TO_TU_MUS(duration); + /* PS Selection + * Periodic noa (2) + * Single NOA (4) + */ + noa.opp_ps = 0; + noa.ct_window = 0; + if (count == 1) { + noa.duration = 0; + noa.single_noa_duration = duration; + noa.ps_selection = P2P_POWER_SAVE_TYPE_SINGLE_NOA; + } else { + noa.duration = duration; + noa.single_noa_duration = 0; + noa.ps_selection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA; + } + noa.interval = MS_TO_TU_MUS(interval); + noa.count = count; + noa.vdev_id = adapter->session_id; + + hdd_debug("P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " + "interval %d count %d single noa duration %d " + "PsSelection %x", noa.opp_ps, + noa.ct_window, noa.duration, noa.interval, + noa.count, noa.single_noa_duration, noa.ps_selection); + + return wlan_hdd_set_power_save(adapter, &noa); +} + +/** + * hdd_set_p2p_opps + * + ***FUNCTION: + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_PS command from wpa_supplicant using private ioctl + * + ***LOGIC: + * Fill noa Struct According to P2P Power save Option and Pass it to SME layer + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param dev Pointer to net device structure + * @param command Pointer to command + * + * @return Status + */ + +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 == NULL) { + 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 ctWindow and + * Opps when user want to set ctWindow during that time other parameters + * values are coming from wpa_supplicant as -1. + * Example : User want to set ctWindow 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)/disbaled(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->session_id; + + hdd_debug("P2P_PS_ATTR: oppPS %d ctWindow %d duration %d interval %d count %d single noa duration %d PsSelection %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->ctWindow; + noa.duration = pappnoa->duration; + noa.interval = pappnoa->interval; + noa.count = pappnoa->count; + noa.single_noa_duration = pappnoa->single_noa_duration; + noa.ps_selection = pappnoa->psSelection; + noa.vdev_id = adapter->session_id; + + return wlan_hdd_set_power_save(adapter, &noa); +} + +static uint8_t wlan_hdd_get_session_type(enum nl80211_iftype type) +{ + switch (type) { + case NL80211_IFTYPE_AP: + return QDF_SAP_MODE; + case NL80211_IFTYPE_P2P_GO: + return QDF_P2P_GO_MODE; + case NL80211_IFTYPE_P2P_CLIENT: + return QDF_P2P_CLIENT_MODE; + case NL80211_IFTYPE_STATION: + return QDF_STA_MODE; + default: + return QDF_STA_MODE; + } +} + +/** + * wlan_hdd_allow_sap_add() - check to add new sap interface + * @hdd_ctx: pointer to hdd context + * @name: name of the new interface + * @sap_dev: output pointer to hold existing interface + * + * Return: If able to add interface return true else false + */ +static bool +wlan_hdd_allow_sap_add(struct hdd_context *hdd_ctx, const char *name, + struct wireless_dev **sap_dev) +{ + struct hdd_adapter *adapter; + + *sap_dev = NULL; + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode == QDF_SAP_MODE && + test_bit(NET_DEVICE_REGISTERED, &adapter->event_flags) && + adapter->dev && + !strncmp(adapter->dev->name, name, IFNAMSIZ)) { + struct hdd_beacon_data *beacon = + adapter->session.ap.beacon; + + hdd_debug("iface already registered"); + if (beacon) { + adapter->session.ap.beacon = NULL; + qdf_mem_free(beacon); + } + if (adapter->dev->ieee80211_ptr) { + *sap_dev = adapter->dev->ieee80211_ptr; + return false; + } + + hdd_err("ieee80211_ptr points to NULL"); + return false; + } + } + + return true; +} + +/** + * __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 + * @nl80211_iftype: (virtual) interface types + * @flags: moniter configuraiton flags (not used) + * @vif_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 = (struct hdd_context *) wiphy_priv(wiphy); + struct hdd_adapter *adapter = NULL; + struct wlan_objmgr_vdev *vdev; + int ret; + uint8_t session_type; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return ERR_PTR(-EINVAL); + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ERR_PTR(ret); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ADD_VIRTUAL_INTF, NO_SESSION, type); + /* + * Allow addition multiple interfaces for QDF_P2P_GO_MODE, + * QDF_SAP_MODE, QDF_P2P_CLIENT_MODE and QDF_STA_MODE + * session type. + */ + session_type = wlan_hdd_get_session_type(type); + if (hdd_get_adapter(hdd_ctx, session_type) != NULL + && QDF_SAP_MODE != session_type + && QDF_P2P_GO_MODE != session_type + && QDF_P2P_CLIENT_MODE != session_type + && QDF_STA_MODE != session_type) { + hdd_err("Interface type %d already exists. Two interfaces of same type are not supported currently.", + type); + return ERR_PTR(-EINVAL); + } + + adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (adapter && !wlan_hdd_validate_session_id(adapter->session_id)) { + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev && + ucfg_scan_get_vdev_status(vdev) != SCAN_NOT_IN_PROGRESS) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_id, INVALID_SCAN_ID, + false); + hdd_debug("Abort Scan while adding virtual interface"); + } + + if (vdev) + hdd_objmgr_put_vdev(vdev); + } + + if (session_type == QDF_SAP_MODE) { + struct wireless_dev *sap_dev; + bool allow_add_sap = wlan_hdd_allow_sap_add(hdd_ctx, name, + &sap_dev); + if (!allow_add_sap) { + if (sap_dev) + return sap_dev; + + return ERR_PTR(-EINVAL); + } + } + + adapter = NULL; + if (hdd_ctx->config->isP2pDeviceAddrAdministrated && + ((NL80211_IFTYPE_P2P_GO == type) || + (NL80211_IFTYPE_P2P_CLIENT == type))) { + /* + * 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, + session_type, + name, p2p_device_address.bytes, + name_assign_type, + true); + } else { + adapter = hdd_open_adapter(hdd_ctx, + session_type, + name, + wlan_hdd_get_intf_addr( + hdd_ctx, + session_type), + name_assign_type, + true); + } + + if (NULL == adapter) { + hdd_err("hdd_open_adapter failed"); + return ERR_PTR(-ENOSPC); + } + + /* + * Add interface can be requested from the upper layer at any time + * check the statemachine for modules state and if they are closed + * open the modules. + */ + ret = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (ret) { + hdd_err("Failed to start the wlan_modules"); + goto close_adapter; + } + + if (hdd_ctx->rps) + hdd_send_rps_ind(adapter); + + hdd_exit(); + return adapter->dev->ieee80211_ptr; + +close_adapter: + hdd_close_adapter(hdd_ctx, adapter, true); + + return ERR_PTR(-EINVAL); +} + +#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) +{ + struct wireless_dev *wdev; + + cds_ssr_protect(__func__); + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, ¶ms->flags, params); + cds_ssr_unprotect(__func__); + + return wdev; +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || defined(WITH_BACKPORTS) +/** + * wlan_hdd_add_virtual_intf() - Add virtual interface wrapper + * @wiphy: wiphy pointer + * @name: User-visible name of the interface + * @name_assign_type: the name of assign type of the netdev + * @nl80211_iftype: (virtual) interface types + * @flags: monitor mode configuration flags (not used) + * @vif_params: virtual interface parameters (not used) + * + * Return: the pointer of wireless dev, otherwise ERR_PTR. + */ +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; + + cds_ssr_protect(__func__); + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, flags, params); + cds_ssr_unprotect(__func__); + return wdev; + +} +#else +/** + * wlan_hdd_add_virtual_intf() - Add virtual interface wrapper + * @wiphy: wiphy pointer + * @name: User-visible name of the interface + * @nl80211_iftype: (virtual) interface types + * @flags: monitor mode configuration flags (not used) + * @vif_params: virtual interface parameters (not used) + * + * Return: the pointer of wireless dev, otherwise ERR_PTR. + */ +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + unsigned char name_assign_type = 0; + + cds_ssr_protect(__func__); + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, flags, params); + cds_ssr_unprotect(__func__); + return wdev; + +} +#endif + +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->event_flags); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_DEL_VIRTUAL_INTF, + adapter->session_id, adapter->device_mode); + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + /* check state machine state and kickstart modules if they are closed */ + errno = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (errno) + return errno; + + if (adapter->device_mode == QDF_SAP_MODE && + wlan_sap_is_pre_cac_active(hdd_ctx->mac_handle)) { + hdd_clean_up_pre_cac_interface(hdd_ctx); + } else { + 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_close_adapter(hdd_ctx, adapter, true); + } + + hdd_exit(); + + return 0; +} + +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_del_virtual_intf(wiphy, wdev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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)); +} + +void __hdd_indicate_mgmt_frame(struct hdd_adapter *adapter, + uint32_t frm_len, + uint8_t *pb_frames, + uint8_t frameType, uint32_t rxChan, int8_t rxRssi) +{ + uint16_t freq; + uint8_t type = 0; + uint8_t subType = 0; + struct hdd_context *hdd_ctx; + uint8_t *dest_addr; + + hdd_debug("Frame Type = %d Frame Length = %d", + frameType, frm_len); + + if (NULL == 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]); + subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pb_frames[0]); + + /* Get adapter from Destination mac address of the frame */ + if ((type == SIR_MAC_MGMT_FRAME) && + (subType != SIR_MAC_MGMT_PROBE_REQ) && + !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 (NULL == adapter) { + /* + * Under assumtion 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 = " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(dest_addr)); + hdd_debug("Frame Type = %d Frame Length = %d subType = %d", + frameType, frm_len, subType); + /* + * We will receive broadcast management frames + * in OCB mode + */ + adapter = hdd_get_adapter(hdd_ctx, QDF_OCB_MODE); + if (NULL == adapter || !qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *)dest_addr)) { + /* + * Under assumtion that we don't + * receive any action frame with BCST + * as destination, we are dropping + * action frame + */ + return; + } + } + } + + if (NULL == 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 (rxChan <= MAX_NO_OF_2_4_CHANNELS) + freq = ieee80211_channel_to_frequency(rxChan, + NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(rxChan, + NL80211_BAND_5GHZ); + + 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->session_id); + + /* Indicate Frame Over Normal Interface */ + hdd_debug("Indicate Frame over NL80211 sessionid : %d, idx :%d", + adapter->session_id, adapter->dev->ifindex); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(adapter->dev->ieee80211_ptr, + freq, rxRssi * 100, pb_frames, + frm_len, NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(adapter->dev->ieee80211_ptr, + freq, rxRssi * 100, pb_frames, + frm_len, NL80211_RXMGMT_FLAG_ANSWERED, + GFP_ATOMIC); +#else + cfg80211_rx_mgmt(adapter->dev->ieee80211_ptr, freq, + rxRssi * 100, + pb_frames, frm_len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ +} + +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, 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->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); + + return qdf_status_to_os_return(status); +} + +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); +} + +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->session_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_update_mcc_adaptive_scheduler() - Function to update + * MAS value to FW + * @adapter: adapter object data + * @is_enable: 0-Disable, 1-Enable MAS + * + * This function passes down the value of MAS to UMAC + * + * Return: 0 for success else non zero + * + */ +static int32_t wlan_hdd_update_mcc_adaptive_scheduler( + struct hdd_adapter *adapter, bool is_enable) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (hdd_ctx == NULL) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + hdd_info("enable/disable MAS :%d", is_enable); + if (hdd_ctx->config && + hdd_ctx->config->enableMCCAdaptiveScheduler) { + /* Todo check where to set the MCC apative SCHED for read */ + + if (QDF_STATUS_SUCCESS != sme_set_mas(is_enable)) { + hdd_err("Failed to enable/disable MAS"); + return -EAGAIN; + } + } + + return 0; +} + +/** + * 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) +{ + int32_t ret = 0; + + if (!adapter) { + hdd_err("Adapter is NULL"); + return -EINVAL; + } + + if (mas_value) { + hdd_info("Miracast is ON. Disable MAS and configure P2P quota"); + ret = wlan_hdd_update_mcc_adaptive_scheduler( + adapter, false); + if (0 != ret) { + hdd_err("Failed to disable MAS"); + goto done; + } + + /* 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); + + ret = wlan_hdd_update_mcc_adaptive_scheduler( + adapter, true); + if (0 != ret) { + hdd_err("Failed to enable MAS"); + goto done; + } + } + +done: + return ret; +} + +/** + * set_first_connection_operating_channel() - Function to set + * first connection oerating channel + * @adapter: adapter data + * @set_value: Quota value for the interface + * @dev_mode: Device 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; + + operating_channel = hdd_get_operating_channel( + hdd_ctx, dev_mode); + if (!operating_channel) { + hdd_err(" First adpter operating channel is invalid"); + return -EINVAL; + } + + 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 + * @adapter: adapter data + * @set_value: Quota value for the interface + * @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 = policy_mgr_get_mcc_operating_channel( + hdd_ctx->psoc, vdev_id); + + if (operating_channel == 0) { + hdd_err("Second adapter operating channel is invalid"); + return -EINVAL; + } + + 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 + * @psoc: PSOC object information + * @set_value: Qouta value for the interface + * @operating_channel First adapter operating channel + * @vdev_id vdev id + * + * 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; + + if (!adapter) { + hdd_err("Invalid adapter"); + return -EFAULT; + } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx == NULL) { + 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 == + (QDF_STA_MASK | QDF_P2P_CLIENT_MASK)) || + (concurrent_state == (QDF_STA_MASK | QDF_P2P_GO_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->session_id); + + + ret = wlan_hdd_send_p2p_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; + + if (!adapter) { + hdd_err("Invalid adapter"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx == NULL) { + 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 == + (QDF_STA_MASK | QDF_P2P_CLIENT_MASK)) || + (concurrent_state == (QDF_STA_MASK | QDF_P2P_GO_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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..cb704ce6a64a4a03fb6394f74213c298738a2ae7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c @@ -0,0 +1,261 @@ +/* + * 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: 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_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + uint8_t filters = 0, i = 0, filter_id = 1; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx == NULL) { + hdd_err("HDD context is Null!!!"); + return -EINVAL; + } + 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 = hdd_ctx->config->packet_filters_bitmap; + + 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], + adapter->session_id); + filter_id++; + } + filters = filters >> 1; + i++; + } + + return 0; +} + +int hdd_disable_default_pkt_filters(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + uint8_t filters = 0, i = 0, filter_id = 1; + + struct pkt_filter_cfg packet_filter_default_rules = {0}; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx == NULL) { + hdd_err("HDD context is Null!!!"); + return -EINVAL; + } + + 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 = hdd_ctx->config->packet_filters_bitmap; + + 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, + adapter->session_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 sessionId) +{ + 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 (hdd_ctx->config->disablePacketFilter) { + 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) { + hdd_err("unable to allocate 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]); + } + + if (QDF_STATUS_SUCCESS != + pmo_ucfg_set_pkt_filter(hdd_ctx->psoc, + pmo_set_pkt_fltr_req, + sessionId)) { + 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) { + hdd_err("unable to allocate pmo_clr_pkt_fltr_param"); + return QDF_STATUS_E_NOMEM; + } + + pmo_clr_pkt_fltr_param->filter_id = request->filter_id; + if (QDF_STATUS_SUCCESS != + pmo_ucfg_clear_pkt_filter(hdd_ctx->psoc, + pmo_clr_pkt_fltr_param, + sessionId)) { + 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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_power.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_power.c new file mode 100644 index 0000000000000000000000000000000000000000..fb515990780109e09cf55f66b484a73a716696e5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_power.c @@ -0,0 +1,2516 @@ +/* + * 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: wlan_hdd_power.c + * + * WLAN power management functions + * + */ + +/* Include files */ + +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && 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 "cfg_api.h" + +#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" + +/* Preprocessor definitions and constants */ +#ifdef QCA_WIFI_NAPIER_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 + +/** + * hdd_enable_gtk_offload() - enable GTK offload + * @adapter: pointer to the adapter + * + * Central function to enable GTK offload. + * + * Return: nothing + */ +static void hdd_enable_gtk_offload(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + status = pmo_ucfg_enable_gtk_offload_in_fwr(adapter->vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_info("Failed to enable gtk offload"); +} + +/** + * hdd_disable_gtk_offload() - disable GTK offload + * @adapter: pointer to the adapter + * + * Central function to disable GTK offload. + * + * Return: nothing + */ +static void hdd_disable_gtk_offload(struct hdd_adapter *adapter) +{ + 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 = pmo_ucfg_get_gtk_rsp(adapter->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 = pmo_ucfg_disable_gtk_offload_in_fwr(adapter->vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_info("Failed to disable gtk offload"); +} + + +/** + * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function + * @nb: notifier block that was registered with the kernel + * @data: (unused) generic data that was registered with the kernel + * @arg: (unused) generic argument that was registered with the kernel + * + * 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: NOTIFY_DONE to indicate we don't care what happens with + * other callbacks + */ +static int __wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg; + struct net_device *ndev = ifa->idev->dev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(ndev); + + errno = hdd_validate_adapter(adapter); + if (errno) + goto exit; + + if (adapter->dev == ndev && + (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_NDI_MODE)) { + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto exit; + + /* Ignore if the interface is down */ + if (!(ndev->flags & IFF_UP)) { + hdd_err("Rcvd change addr request on %s(flags 0x%X)", + ndev->name, ndev->flags); + hdd_err("NETDEV Interface is down, ignoring..."); + goto exit; + } + + hdd_debug("invoking sme_dhcp_done_ind"); + sme_dhcp_done_ind(hdd_ctx->mac_handle, adapter->session_id); + schedule_work(&adapter->ipv6_notifier_work); + } + +exit: + hdd_exit(); + + return NOTIFY_DONE; +} + +int wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_ipv6_changed(nb, data, arg); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses + * @idev: pointer to net device + * @ipv6addr: 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[][SIR_MAC_IPV6_ADDR_LEN], + 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] = pmo_ucfg_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 + * @ipv6addr: 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[][SIR_MAC_IPV6_ADDR_LEN], + 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] = pmo_ucfg_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, + 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; + + hdd_enter(); + + if (!psoc) { + hdd_err("psoc is NULL"); + goto out; + } + + in6_dev = __in6_dev_get(adapter->dev); + if (NULL == 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) { + hdd_err("fail to allocate ns_req"); + goto out; + } + + ns_req->psoc = psoc; + ns_req->vdev_id = adapter->session_id; + ns_req->trigger = trigger; + 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_disable_ns_offload(adapter, 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, trigger); + hdd_debug("Max supported addresses: disabling NS offload"); + goto free_req; + } + + /* cache ns request */ + status = pmo_ucfg_cache_ns_offload_req(ns_req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to cache ns request; status:%d", status); + goto free_req; + } + + /* enable ns request */ + status = pmo_ucfg_enable_ns_offload_in_fwr(adapter->vdev, trigger); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("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, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + + hdd_enter(); + status = pmo_ucfg_flush_ns_offload_req(adapter->vdev); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to flush NS Offload"); + goto out; + } + + status = pmo_ucfg_disable_ns_offload_in_fwr(adapter->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(); + +} + +/** + * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function + * @work: registered work item + * + * This function performs the work initially trigged 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 work_struct *work) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + int errno; + + hdd_enter(); + + adapter = container_of(work, struct hdd_adapter, ipv6_notifier_work); + 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; + + hdd_enable_ns_offload(adapter, pmo_ipv6_change_notify); + +exit: + hdd_exit(); +} + +void hdd_ipv6_notifier_work_queue(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_ipv6_notifier_work_queue(work); + cds_ssr_unprotect(__func__); +} + +static void hdd_enable_hw_filter(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + hdd_enter(); + + status = pmo_ucfg_enable_hw_filter_in_fwr(adapter->vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_info("Failed to enable hardware filter"); + + hdd_exit(); +} + +static void hdd_disable_hw_filter(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + hdd_enter(); + + status = pmo_ucfg_disable_hw_filter_in_fwr(adapter->vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_info("Failed to disable hardware filter"); + + hdd_exit(); +} + +void hdd_enable_host_offloads(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + hdd_enter(); + + if (!ucfg_pmo_is_vdev_supports_offload(adapter->vdev)) { + hdd_debug("offload is not supported on vdev opmode %d", + adapter->device_mode); + goto out; + } + + if (!ucfg_pmo_is_vdev_connected(adapter->vdev)) { + hdd_debug("offload is not supported on disconnected vdevs"); + goto out; + } + + hdd_debug("enable offloads"); + hdd_enable_gtk_offload(adapter); + hdd_enable_arp_offload(adapter, trigger); + hdd_enable_ns_offload(adapter, trigger); + hdd_enable_mc_addr_filtering(adapter, trigger); + hdd_enable_hw_filter(adapter); +out: + hdd_exit(); + +} + +void hdd_disable_host_offloads(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + hdd_enter(); + + if (!ucfg_pmo_is_vdev_supports_offload(adapter->vdev)) { + hdd_info("offload is not supported on this vdev opmode: %d", + adapter->device_mode); + goto out; + } + + if (!ucfg_pmo_is_vdev_connected(adapter->vdev)) { + hdd_info("vdev is not connected"); + goto out; + } + + hdd_debug("disable offloads"); + hdd_disable_gtk_offload(adapter); + hdd_disable_arp_offload(adapter, trigger); + hdd_disable_ns_offload(adapter, trigger); + hdd_disable_mc_addr_filtering(adapter, trigger); + hdd_disable_hw_filter(adapter); +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; +} + +/** + * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive + * @adapter: the HDD adapter to configure + * + * This configures gratuitous APR keepalive based on the adapter's current + * connection information, specifically IPv4 address and BSSID + * + * return: zero for success, non-zero for failure + */ +static 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; + tSirKeepAliveReq 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); + 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); + req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod; + req.sessionId = adapter->session_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 + * @work: registered work item + * + * This function performs the work initially trigged 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 work_struct *work) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + int errno; + struct csr_roam_profile *roam_profile; + struct in_ifaddr *ifa; + + hdd_enter(); + + adapter = container_of(work, struct hdd_adapter, ipv4_notifier_work); + 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; + + hdd_enable_arp_offload(adapter, pmo_ipv4_change_notify); + + if (hdd_ctx->config->sta_keepalive_method == HDD_STA_KEEPALIVE_GRAT_ARP) + hdd_set_grat_arp_keepalive(adapter); + + hdd_debug("FILS Roaming support: %d", + hdd_ctx->is_fils_roaming_supported); + roam_profile = hdd_roam_profile(adapter); + + ifa = hdd_lookup_ifaddr(adapter); + if (ifa && hdd_ctx->is_fils_roaming_supported) + sme_send_hlp_ie_info(hdd_ctx->mac_handle, adapter->session_id, + roam_profile, ifa->ifa_local); +exit: + hdd_exit(); +} + +void hdd_ipv4_notifier_work_queue(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_ipv4_notifier_work_queue(work); + cds_ssr_unprotect(__func__); +} + +/** + * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function + * @nb: notifier block that was registered with the kernel + * @data: (unused) generic data that was registered with the kernel + * @arg: (unused) generic argument that was registered with the kernel + * + * 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: NOTIFY_DONE to indicate we don't care what happens with + * other callbacks + */ +static int __wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)arg; + struct net_device *ndev = ifa->ifa_dev->dev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(ndev); + + errno = hdd_validate_adapter(adapter); + if (errno) + goto exit; + + if (adapter->dev == ndev && + (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_NDI_MODE)) { + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto exit; + + /* Ignore if the interface is down */ + if (!(ndev->flags & IFF_UP)) { + hdd_err("Rcvd change addr request on %s(flags 0x%X)", + ndev->name, ndev->flags); + hdd_err("NETDEV Interface is down, ignoring..."); + goto exit; + } + hdd_debug("invoking sme_dhcp_done_ind"); + sme_dhcp_done_ind(hdd_ctx->mac_handle, adapter->session_id); + + if (!hdd_ctx->config->fhostArpOffload) { + hdd_debug("Offload not enabled ARPOffload=%d", + hdd_ctx->config->fhostArpOffload); + goto exit; + } + + ifa = hdd_lookup_ifaddr(adapter); + if (ifa && ifa->ifa_local) + schedule_work(&adapter->ipv4_notifier_work); + } + +exit: + hdd_exit(); + + return NOTIFY_DONE; +} + +int wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_ipv4_changed(nb, data, arg); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_get_ipv4_local_interface() - get ipv4 local interafce 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, + 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; + + hdd_enter(); + + arp_req = qdf_mem_malloc(sizeof(*arp_req)); + if (!arp_req) { + hdd_err("cannot allocate arp_req"); + goto out; + } + + arp_req->psoc = psoc; + arp_req->vdev_id = adapter->session_id; + arp_req->trigger = trigger; + + 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 = pmo_ucfg_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; + } + + status = pmo_ucfg_enable_arp_offload_in_fwr(adapter->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); + +out: + hdd_exit(); +} + +void hdd_disable_arp_offload(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + + hdd_enter(); + status = pmo_ucfg_flush_arp_offload_req(adapter->vdev); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to flush arp Offload"); + goto out; + } + + status = pmo_ucfg_disable_arp_offload_in_fwr(adapter->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"); +out: + hdd_exit(); +} + +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; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + goto out; + + if (!hdd_adapter_is_connected_sta(adapter)) + goto out; + + status = pmo_ucfg_enable_mc_addr_filtering_in_fwr(hdd_ctx->psoc, + adapter->session_id, + trigger); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to enable mc list; status:%d", status); + +out: + hdd_exit(); +} + +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; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + goto out; + + if (!hdd_adapter_is_connected_sta(adapter)) + goto out; + + status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(hdd_ctx->psoc, + adapter->session_id, + trigger); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to disable mc list; status:%d", status); + +out: + hdd_exit(); +} + +int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config) +{ + QDF_STATUS status; + + hdd_enter(); + status = pmo_ucfg_cache_mc_addr_list(mc_list_config); + hdd_exit(); + + 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; + + hdd_enter(); + + if (!hdd_adapter_is_connected_sta(adapter)) + goto flush_mc_list; + + /* disable mc list first because the mc list is cached in PMO */ + status = pmo_ucfg_disable_mc_addr_filtering_in_fwr(hdd_ctx->psoc, + adapter->session_id, + trigger); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to disable mc list; status:%d", status); + +flush_mc_list: + status = pmo_ucfg_flush_mc_addr_list(hdd_ctx->psoc, + adapter->session_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to flush mc list; status:%d", status); + + hdd_exit(); + + return; +} + +/** + * 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) +{ + + eConnectionState connState; + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + connState = sta_ctx->conn_info.connState; + + if (connState == eConnectionState_Associated || + connState == eConnectionState_IbssConnected) + *conn_state_mask |= (1 << adapter->session_id); +} + +/** + * hdd_suspend_wlan() - Driver suspend function + * @callback: Callback function to invoke when driver is ready to suspend + * @callbackContext: Context to pass back to @callback 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; + uint32_t conn_state_mask = 0; + + hdd_info("WLAN being suspended by OS"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is Null"); + 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(hdd_ctx, adapter) { + if (wlan_hdd_validate_session_id(adapter->session_id)) + continue; + + /* stop all TX queues before suspend */ + hdd_debug("Disabling queues for dev mode %s", + hdd_device_mode_to_string(adapter->device_mode)); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + if (adapter->device_mode == QDF_STA_MODE) + status = hdd_enable_default_pkt_filters(adapter); + + /* Configure supported OffLoads */ + hdd_enable_host_offloads(adapter, pmo_apps_suspend); + hdd_update_conn_state_mask(adapter, &conn_state_mask); + } + + status = pmo_ucfg_psoc_user_space_suspend_req(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + if (status != QDF_STATUS_SUCCESS) + return -EAGAIN; + + hdd_ctx->hdd_wlan_suspended = true; + 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; + QDF_STATUS status; + + hdd_info("WLAN being resumed by OS"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is Null"); + 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(hdd_ctx, adapter) { + if (wlan_hdd_validate_session_id(adapter->session_id)) + continue; + + /* Disable supported OffLoads */ + hdd_disable_host_offloads(adapter, pmo_apps_resume); + + /* wake the tx queues */ + hdd_debug("Enabling queues for dev mode %s", + hdd_device_mode_to_string(adapter->device_mode)); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + if (adapter->device_mode == QDF_STA_MODE) + status = hdd_disable_default_pkt_filters(adapter); + } + + ucfg_ipa_resume(hdd_ctx->pdev); + status = pmo_ucfg_psoc_user_space_resume_req(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + 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; +} + +/** + * 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; + + hdd_enter(); + + hdd_for_each_adapter(hdd_ctx, adapter) { + if (adapter->device_mode == QDF_SAP_MODE) { + if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) { + hdd_debug("Restart prev SAP session"); + wlan_hdd_start_sap(adapter, true); + } + } + } + + hdd_exit(); +} + +/** + * hdd_purge_all_pdev_cmd_cb() - cb for pdev purge cmd sync + * @hdd_handle: hdd handle + * + * Return : void + */ +static void hdd_purge_all_pdev_cmd_cb(hdd_handle_t hdd_handle) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + + if (!hdd_ctx) + return; + + /* Unblock threads waiting for pdev command to get flushed */ + complete(&hdd_ctx->pdev_cmd_flushed_var); + hdd_debug("All pdev commands flushed"); +} + +/** + * hdd_purge_all_pdev_cmd() - purge pdev commands and wait for complete + * @hdd_ctx: hdd context + * + * Return : void + */ +static void hdd_purge_all_pdev_cmd(struct hdd_context *hdd_ctx) +{ + int rc; + QDF_STATUS status; + +#define WLAN_WAIT_PURGE_PDEV_CMDS 1000 + + INIT_COMPLETION(hdd_ctx->pdev_cmd_flushed_var); + + status = + sme_purge_pdev_all_ser_cmd_list_sync(hdd_ctx->mac_handle, + hdd_purge_all_pdev_cmd_cb); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to post purge pdev cmd"); + return; + } + + rc = wait_for_completion_timeout(&hdd_ctx->pdev_cmd_flushed_var, + msecs_to_jiffies( + WLAN_WAIT_PURGE_PDEV_CMDS)); + + if (!rc) + hdd_err("Failed to flush pdev cmds, timed out"); +} + +QDF_STATUS hdd_wlan_shutdown(void) +{ + struct hdd_context *hdd_ctx; + 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) { + hdd_err("HDD context is Null"); + return QDF_STATUS_E_FAILURE; + } + + hdd_bus_bw_compute_timer_stop(hdd_ctx); + hdd_set_connection_in_progress(false); + policy_mgr_clear_concurrent_session_count(hdd_ctx->psoc); + + hdd_debug("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + + /* 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; + } + +#ifdef QCA_CONFIG_SMP + if (hdd_ctx->is_ol_rx_thread_suspended) { + cds_resume_rx_thread(); + hdd_ctx->is_ol_rx_thread_suspended = false; + } +#endif + + /* + * After SSR, FW clear its txrx stats. In host, + * as adapter is intact so those counts are still + * available. Now if agains Set stats command comes, + * then host will increment its counts start from its + * last saved value, i.e., count before SSR, and FW will + * increment its count from 0. This will finally sends a + * mismatch of packet counts b/w host and FW to framework + * that will create ambiquity. Therfore, Resetting the host + * counts here so that after SSR both FW and host start + * increment their counts from 0. + */ + hdd_reset_all_adapters_connectivity_stats(hdd_ctx); + + /* Disable scan and abort all pending scan commands. */ + ucfg_scan_set_enable(hdd_ctx->psoc, false); + wlan_abort_scan(hdd_ctx->pdev, + wlan_objmgr_pdev_get_pdev_id(hdd_ctx->pdev), + INVAL_VDEV_ID, INVAL_SCAN_ID, true); + /* + * Purge all active and pending list to avoid vdev destroy timeout and + * thus avoid peer/vdev refcount leak. + */ + hdd_purge_all_pdev_cmd(hdd_ctx); + + 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_bus_bandwidth_deinit(hdd_ctx); + hdd_lpass_notify_stop(hdd_ctx); + + 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 + +/** + * hdd_send_default_scan_ies - send default scan ies to fw + * + * 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; + + hdd_for_each_adapter(hdd_ctx, adapter) { + 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->session_id, + adapter->scan_info.default_scan_ies, + adapter->scan_info.default_scan_ies_len); + } + } +} + +/** + * hdd_is_interface_down_during_ssr - Check if the interface went down during + * SSR + * @hdd_ctx: HDD context + * + * Check if any of the interface went down while the device is recovering. + * If the interface went down close the session. + */ +static void hdd_is_interface_down_during_ssr(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *pnext = NULL; + QDF_STATUS status; + + hdd_enter(); + + status = hdd_get_front_adapter(hdd_ctx, &adapter); + while (adapter && status == QDF_STATUS_SUCCESS) { + if (test_bit(DOWN_DURING_SSR, &adapter->event_flags)) { + clear_bit(DOWN_DURING_SSR, &adapter->event_flags); + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + } + status = hdd_get_next_adapter(hdd_ctx, adapter, &pnext); + adapter = pnext; + } + + hdd_exit(); +} + +/** + * 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"); +} + +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; + + 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) { + hdd_err("HDD context is Null"); + 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"); + + hdd_dp_trace_init(hdd_ctx->config); + hdd_bus_bandwidth_init(hdd_ctx); + + 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); + + hdd_init_scan_reject_params(hdd_ctx); + + hdd_set_roaming_in_progress(false); + complete(&adapter->roaming_comp_var); + 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_sar_config(hdd_ctx); + + hdd_send_default_scan_ies(hdd_ctx); + hdd_info("WLAN host driver reinitiation completed!"); + + if (hdd_ctx->config->sap_internal_restart) + hdd_ssr_restart_sap(hdd_ctx); + hdd_is_interface_down_during_ssr(hdd_ctx); + hdd_wlan_ssr_reinit_event(); + return QDF_STATUS_SUCCESS; + +err_re_init: + hdd_bus_bandwidth_deinit(hdd_ctx); + +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 hdd_adapter *adapter, + bool allow_power_save, uint32_t timeout) +{ + mac_handle_t mac_handle; + struct hdd_context *hdd_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == adapter) { + hdd_err("Adapter NULL"); + return -ENODEV; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return -EINVAL; + } + + hdd_debug("Allow power save: %d", allow_power_save); + mac_handle = hdd_ctx->mac_handle; + + /* + * 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. + */ + if (allow_power_save && + adapter->device_mode == QDF_STA_MODE && + !adapter->session.station.ap_supports_immediate_power_save) { + timeout = AUTO_PS_DEFER_TIMEOUT_MS; + hdd_debug("Defer power-save due to AP spec non-conformance"); + } + + if (allow_power_save) { + if (QDF_STA_MODE == adapter->device_mode || + QDF_P2P_CLIENT_MODE == adapter->device_mode) { + hdd_debug("Disabling Auto Power save timer"); + status = sme_ps_disable_auto_ps_timer(mac_handle, + adapter->session_id); + if (status != QDF_STATUS_SUCCESS) + goto end; + } + + if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) { + hdd_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, + adapter->session_id, + timeout); + if (status != QDF_STATUS_SUCCESS) + goto end; + } else { + status = sme_ps_enable_disable(mac_handle, + adapter->session_id, + SME_PS_ENABLE); + if (status != QDF_STATUS_SUCCESS) + goto end; + } + } else { + hdd_debug("Power Save is not enabled in the cfg"); + } + } else { + hdd_debug("Wlan driver Entering Full Power"); + + /* + * Enter Full power command received from GUI + * this means we are disconnected + */ + status = sme_ps_disable_auto_ps_timer(mac_handle, + adapter->session_id); + + if (status != QDF_STATUS_SUCCESS) + goto end; + + if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) + status = sme_ps_enable_disable(mac_handle, + adapter->session_id, + SME_PS_DISABLE); + } + +end: + return qdf_status_to_os_return(status); +} + +static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx) +{ +#ifdef WLAN_DEBUG + struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats; +#endif + + 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; + int exit_code; + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + + 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()) { + hdd_err("Command not allowed in FTM mode"); + exit_code = -EINVAL; + goto exit_with_code; + } + + exit_code = wlan_hdd_validate_context(hdd_ctx); + if (exit_code) { + hdd_err("Invalid HDD context"); + goto exit_with_code; + } + + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_debug("Driver is not enabled; Skipping resume"); + exit_code = 0; + goto exit_with_code; + } + mutex_unlock(&hdd_ctx->iface_change_lock); + + pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_MEDIUM); + + 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; + } +#ifdef QCA_CONFIG_SMP + /* Resume tlshim Rx thread */ + if (hdd_ctx->is_ol_rx_thread_suspended) { + complete(&cds_sched_context->ol_resume_rx_event); + hdd_ctx->is_ol_rx_thread_suspended = false; + } +#endif + + 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; +} + +int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_resume_wlan(wiphy); + cds_ssr_unprotect(__func__); + + return ret; +} + +static void hdd_suspend_cb(void) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + 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) +{ +#ifdef QCA_CONFIG_SMP +#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */ +#endif + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + struct hdd_adapter *adapter; + struct hdd_scan_info *scan_info; + mac_handle_t mac_handle; + int rc; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + rc = wlan_hdd_validate_context(hdd_ctx); + if (0 != rc) + return rc; + + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_debug("Driver Modules not Enabled "); + return 0; + } + mutex_unlock(&hdd_ctx->iface_change_lock); + + 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(hdd_ctx, adapter) { + if (wlan_hdd_validate_session_id(adapter->session_id)) + continue; + + if (QDF_SAP_MODE == adapter->device_mode) { + if (BSS_START == + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter)->bss_state && + true == + WLAN_HDD_GET_AP_CTX_PTR(adapter)-> + dfs_cac_block_tx) { + hdd_err("RADAR detection in progress, do not allow suspend"); + wlan_hdd_inc_suspend_stats(hdd_ctx, + SUSPEND_FAIL_RADAR); + return -EAGAIN; + } else if (!hdd_ctx->config->enable_sap_suspend) { + /* return -EOPNOTSUPP if SAP does not support + * suspend + */ + hdd_err("SAP does not support suspend!!"); + return -EOPNOTSUPP; + } + } else if (QDF_P2P_GO_MODE == adapter->device_mode) { + if (!hdd_ctx->config->enable_sap_suspend) { + /* return -EOPNOTSUPP if GO does not support + * suspend + */ + hdd_err("GO does not support suspend!!"); + return -EOPNOTSUPP; + } + } + } + /* p2p cleanup task based on scheduler */ + ucfg_p2p_cleanup_tx_by_psoc(hdd_ctx->psoc); + ucfg_p2p_cleanup_roc_by_psoc(hdd_ctx->psoc); + + /* Stop ongoing scan on each interface */ + hdd_for_each_adapter(hdd_ctx, adapter) { + scan_info = &adapter->scan_info; + + if (sme_neighbor_middle_of_roaming(mac_handle, + adapter->session_id) || + hdd_is_roaming_in_progress(hdd_ctx)) { + hdd_err("Roaming in progress, do not allow suspend"); + wlan_hdd_inc_suspend_stats(hdd_ctx, + SUSPEND_FAIL_ROAM); + return -EAGAIN; + } + + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_id, INVALID_SCAN_ID, false); + } + + /* flush any pending powersave timers */ + hdd_for_each_adapter(hdd_ctx, adapter) { + if (wlan_hdd_validate_session_id(adapter->session_id)) + continue; + + sme_ps_timer_flush_sync(mac_handle, adapter->session_id); + } + + /* + * 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); + return -EAGAIN; + } + + /* 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; + +#ifdef QCA_CONFIG_SMP + /* 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 + (RX_TLSHIM_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"); + goto resume_all; + } + hdd_ctx->is_ol_rx_thread_suspended = true; +#endif + + 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_all; + } + + hdd_ctx->is_wiphy_suspended = true; + + pld_request_bus_bandwidth(hdd_ctx->parent_dev, PLD_BUS_WIDTH_NONE); + + hdd_exit(); + return 0; + +#ifdef QCA_CONFIG_SMP +resume_all: + /* Resume tlshim Rx thread */ + if (hdd_ctx->is_ol_rx_thread_suspended) { + cds_resume_rx_thread(); + hdd_ctx->is_ol_rx_thread_suspended = false; + } + scheduler_resume(); + hdd_ctx->is_scheduler_suspended = false; +#endif + +resume_tx: + + hdd_resume_wlan(); + return -ETIME; + +} + +int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_stop_dhcp_ind() - API to stop DHCP sequence + * @adapter: Adapter on which DHCP needs to be stopped + * + * Release the wakelock held for DHCP process and allow + * the runtime pm to continue + * + * Return: None + */ +static void hdd_stop_dhcp_ind(struct hdd_adapter *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, + adapter->mac_addr.bytes, + adapter->session_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 + * @adapter: Adapter on which DHCP needs to be stopped + * + * Prevent APPS suspend and the runtime suspend during + * DHCP sequence + * + * Return: None + */ +static void hdd_start_dhcp_ind(struct hdd_adapter *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, + adapter->mac_addr.bytes, + adapter->session_id); +} + +/** + * __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; + + hdd_enter(); + + if (timeout < 0) { + hdd_debug("User space timeout: %d; Enter full power or power save", + timeout); + timeout = 0; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT, + adapter->session_id, timeout); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_debug("Driver Module not enabled return success"); + return 0; + } + mutex_unlock(&hdd_ctx->iface_change_lock); + + status = wlan_hdd_set_powersave(adapter, allow_power_save, timeout); + + allow_power_save ? hdd_stop_dhcp_ind(adapter) : + hdd_start_dhcp_ind(adapter); + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev, + allow_power_save, timeout); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 (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); + + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) + 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 = sme_cfg_set_int(mac_handle, WNI_CFG_CURRENT_TX_POWER_LEVEL, + dbm); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("sme_cfg_set_int failed for tx power %hu, %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: + /* Fall through */ + 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 */ + hdd_err("NL80211_TX_POWER_FIXED not supported"); + return -EOPNOTSUPP; + + 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_txpower(wiphy, + wdev, + type, mbm); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef QCA_SUPPORT_CP_STATS +static void wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm) +{ + wlan_cfg80211_mc_cp_stats_get_tx_power(adapter->vdev, dbm); +} +#else +static void wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm) +{ + wlan_hdd_get_class_astats(adapter); + *dbm = adapter->hdd_stats.class_a_stat.max_pwr; +} +#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); + int status; + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_enter_dev(ndev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + *dbm = 0; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + /* Validate adapter sessionId */ + status = wlan_hdd_validate_session_id(adapter->session_id); + if (status) + return status; + + if (sta_ctx->hdd_reassoc_scenario) { + hdd_debug("Roaming is in progress, rej this req"); + return -EINVAL; + } + + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_debug("Driver Module not enabled return success"); + /* Send cached data to upperlayer*/ + *dbm = adapter->hdd_stats.class_a_stat.max_pwr; + return 0; + } + mutex_unlock(&hdd_ctx->iface_change_lock); + + if (sta_ctx->conn_info.connState != eConnectionState_Associated) { + hdd_debug("Not associated"); + return 0; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_TXPOWER, + adapter->session_id, adapter->device_mode); + + wlan_hdd_get_tx_power(adapter, dbm); + hdd_debug("power: %d", *dbm); + + return 0; +} + +int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm); + cds_ssr_unprotect(__func__); + + return ret; +} + +int hdd_set_qpower_config(struct hdd_context *hddctx, + struct hdd_adapter *adapter, + u8 qpower) +{ + QDF_STATUS status; + + if (!hddctx->config->enablePowersaveOffload) { + hdd_err("qpower is disabled in configuration"); + return -EINVAL; + } + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_info("QPOWER only allowed in STA/P2P-Client modes:%d", + adapter->device_mode); + return -EINVAL; + } + + if (qpower > PS_DUTY_CYCLING_QPOWER || + qpower < PS_LEGACY_NODEEPSLEEP) { + hdd_err("invalid qpower value: %d", qpower); + return -EINVAL; + } + + if (hddctx->config->nMaxPsPoll) { + if ((qpower == PS_QPOWER_NODEEPSLEEP) || + (qpower == PS_LEGACY_NODEEPSLEEP)) + qpower = PS_LEGACY_NODEEPSLEEP; + else + qpower = PS_LEGACY_DEEPSLEEP; + hdd_info("Qpower disabled, %d", qpower); + } + status = wma_set_qpower_config(adapter->session_id, qpower); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed to configure qpower: %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; + qdf_device_t qdf_dev; + + hdd_info("Unit-test resume WLAN"); + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) { + hdd_err("Failed to get QDF device context"); + QDF_BUG(0); + return; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("Failed to get HIF context"); + 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_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_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("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("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) { + hdd_err("Failed to get QDF device context"); + return -EINVAL; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("Failed to get HIF context"); + 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; + } + + /* 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()); + +cfg80211_resume: + QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy)); + +link_down: + hif_vote_link_down(hif_ctx); + + clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state); + hdd_err("Unit-test suspend failed: %d", errno); + + 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) { + hdd_err("Failed to get HIF context"); + return -EINVAL; + } + + hif_ut_apps_resume(hif_ctx); + __hdd_wlan_fake_apps_resume(wiphy, dev); + + return 0; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c new file mode 100644 index 0000000000000000000000000000000000000000..da19b19f88779bc0677d3d2f88d567e0c4018e2c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c @@ -0,0 +1,1416 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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 + +#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, + } +}; + +/** + * 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; +} + +static void reg_program_config_vars(struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ + config_vars->enable_11d_support = hdd_ctx->config->Is11dSupportEnabled; + config_vars->scan_11d_interval = hdd_ctx->config->scan_11d_interval; + config_vars->userspace_ctry_priority = + hdd_ctx->config->fSupplicantCountryCodeHasPriority; + config_vars->dfs_enabled = hdd_ctx->config->enableDFSChnlScan; + config_vars->indoor_chan_enabled = + hdd_ctx->config->indoor_channel_support; + config_vars->force_ssc_disable_indoor_channel = + hdd_ctx->config->force_ssc_disable_indoor_channel; + config_vars->band_capability = hdd_ctx->config->nBandCapability; + config_vars->restart_beaconing = hdd_ctx->config-> + restart_beaconing_on_chan_avoid_event; + config_vars->enable_srd_chan_in_master_mode = + hdd_ctx->config->etsi13_srd_chan_in_master_mode; + config_vars->enable_11d_in_world_mode = + hdd_ctx->config->enable_11d_in_world_mode; +} + + +/** + * 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 if (hdd_ctx->config->fRegChangeDefCountry) { + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + reg_rules = &hdd_world_regrules_60_61_62; + } 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 if (hdd_ctx->config->fRegChangeDefCountry) { + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + reg_rules = &hdd_world_regrules_60_61_62; + } 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 + * @dfs_region: 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; + + band_capability = hdd_ctx->curr_band; + + for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) { + + if (wiphy->bands[band_num] == NULL) + 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 (hdd_ctx->config->force_ssc_disable_indoor_channel && + (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; + if (hdd_ctx->config->indoor_channel_support + == false) { + cds_chan->state = CHANNEL_STATE_DFS; + wiphy_chan->flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + 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 (NULL != 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_REG); + + 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 + * @wiphy_chan: wiphy channel number + * @cds_chan: cds channel structure + * @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 = hdd_ctx->config->indoor_channel_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_1; + 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] == NULL) + 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_144) + 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 + +int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code) +{ + QDF_STATUS status; + uint8_t cc[REG_ALPHA2_LEN + 1]; + + if (!country_code) { + hdd_err("country_code is null"); + return -EINVAL; + } + + qdf_mem_copy(cc, country_code, REG_ALPHA2_LEN); + cc[REG_ALPHA2_LEN] = '\0'; + + status = ucfg_reg_set_country(hdd_ctx->pdev, cc); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set country"); + + return qdf_status_to_os_return(status); +} + +int hdd_reg_set_band(struct net_device *dev, u8 ui_band) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + mac_handle_t mac_handle; + enum band_info band; + QDF_STATUS status; + struct hdd_context *hdd_ctx; + enum band_info currBand; + enum band_info connectedBand; + long lrc; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + switch (ui_band) { + case WLAN_HDD_UI_BAND_AUTO: + band = BAND_ALL; + break; + case WLAN_HDD_UI_BAND_5_GHZ: + band = BAND_5G; + break; + case WLAN_HDD_UI_BAND_2_4_GHZ: + band = BAND_2G; + break; + default: + hdd_err("Invalid band value %u", ui_band); + return -EINVAL; + } + + hdd_debug("change band to %u", band); + + if ((band == BAND_2G && hdd_ctx->config->nBandCapability == 2) || + (band == BAND_5G && hdd_ctx->config->nBandCapability == 1) || + (band == BAND_ALL && hdd_ctx->config->nBandCapability != 0)) { + hdd_err("band value %u violate INI settings %u", + band, hdd_ctx->config->nBandCapability); + return -EIO; + } + + if (band == BAND_ALL) { + hdd_debug("Auto band received. Setting band same as ini value %d", + hdd_ctx->config->nBandCapability); + band = hdd_ctx->config->nBandCapability; + } + + if (ucfg_reg_get_curr_band(hdd_ctx->pdev, &currBand) != + QDF_STATUS_SUCCESS) { + hdd_debug("Failed to get current band config"); + return -EIO; + } + + if (currBand == band) + return 0; + + hdd_ctx->curr_band = band; + + /* Change band request received. + * Abort pending scan requests, flush the existing scan results, + * and change the band capability + */ + hdd_debug("Current band value = %u, new setting %u ", + currBand, band); + + mac_handle = hdd_ctx->mac_handle; + hdd_for_each_adapter(hdd_ctx, adapter) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_id, INVALID_SCAN_ID, false); + connectedBand = hdd_conn_get_connected_band( + WLAN_HDD_GET_STATION_CTX_PTR(adapter)); + + /* Handling is done only for STA and P2P */ + if (band != BAND_ALL && + ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) && + (hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) + && (connectedBand != band)) { + status = QDF_STATUS_SUCCESS; + + /* STA already connected on current + * band, So issue disconnect first, + * then change the band + */ + + hdd_debug("STA (Device mode %s(%d)) connected in band %u, Changing band to %u, Issuing Disconnect", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode, currBand, band); + INIT_COMPLETION(adapter->disconnect_comp_var); + + status = sme_roam_disconnect( + mac_handle, + adapter->session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_roam_disconnect failure, status: %d", + (int)status); + return -EINVAL; + } + + lrc = wait_for_completion_timeout( + &adapter->disconnect_comp_var, + msecs_to_jiffies( + WLAN_WAIT_TIME_DISCONNECT)); + + if (lrc == 0) { + hdd_err("Timeout while waiting for csr_roam_disconnect"); + return -ETIMEDOUT; + } + } + + sme_scan_flush_result(mac_handle); + } + + if (QDF_IS_STATUS_ERROR(ucfg_reg_set_band(hdd_ctx->pdev, band))) { + hdd_err("Failed to set the band value to %u", band); + return -EINVAL; + } + + 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 + * @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}; + + 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: + 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)) + hdd_err("Failed to set country"); +} +#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 (NULL == 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("%s: unloading or ssr in progress, ignore", + __func__); + 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("%s: system/cfg80211 is already suspend", __func__); + return; + } + + if (('K' == request->alpha2[0]) && + ('R' == request->alpha2[1])) + request->dfs_region = (enum nl80211_dfs_regions) DFS_KR_REG; + + if (('C' == request->alpha2[0]) && + ('N' == request->alpha2[1])) + request->dfs_region = (enum nl80211_dfs_regions) DFS_CN_REG; + + /* 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; + sme_set_cc_src(hdd_ctx->mac_handle, 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)) +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; + + 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] == NULL) + 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 + * @adapter: HDD adapter pointer + * @indParam: Channel avoid notification parameter + * + * 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; + + /* 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); + + 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->ch_cnt; + + qdf_mem_copy(hdd_ctxt->unsafe_channel_list, unsafe_chan_list->ch_list, + sizeof(hdd_ctxt->unsafe_channel_list)); + 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)) + 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; +} + +/** + * 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_REG: + return NL80211_DFS_UNSET; + case DFS_FCC_REG: + return NL80211_DFS_FCC; + case DFS_ETSI_REG: + return NL80211_DFS_ETSI; + case DFS_MKK_REG: + return NL80211_DFS_JP; + default: + return NL80211_DFS_UNSET; + } +} + +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) { + hdd_err("mem alloc failed for reg rules"); + 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); + 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 + +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]; + + pdev_priv = wlan_pdev_get_ospriv(pdev); + wiphy = pdev_priv->wiphy; + hdd_ctx = wiphy_priv(wiphy); + + hdd_debug("process channel list update from regulatory"); + + fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_2GHZ); + fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_5GHZ); + + cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->psoc, alpha2); + qdf_mem_copy(hdd_ctx->reg.alpha2, alpha2, REG_ALPHA2_LEN + 1); + sme_set_cc_src(hdd_ctx->mac_handle, cc_src); + + /* 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 + + if (avoid_freq_ind) + hdd_ch_avoid_ind(hdd_ctx, &avoid_freq_ind->chan_list, + &avoid_freq_ind->freq_list); + else + sme_generic_change_country_code(hdd_ctx->mac_handle, + hdd_ctx->reg.alpha2); +} + +int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy) +{ + bool offload_enabled; + struct reg_config_vars config_vars; + struct regulatory_channel cur_chan_list[NUM_CHANNELS]; + enum country_src cc_src; + uint8_t alpha2[REG_ALPHA2_LEN + 1]; + + reg_program_config_vars(hdd_ctx, &config_vars); + ucfg_reg_register_chan_change_callback(hdd_ctx->psoc, + hdd_regulatory_dyn_cbk, + NULL); + + ucfg_reg_set_config_vars(hdd_ctx->psoc, config_vars); + + 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; + ucfg_reg_get_current_chan_list(hdd_ctx->pdev, + 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); + + cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->psoc, alpha2); + qdf_mem_copy(hdd_ctx->reg.alpha2, alpha2, REG_ALPHA2_LEN + 1); + sme_set_cc_src(hdd_ctx->mac_handle, cc_src); + } else { + hdd_ctx->reg_offload = false; + } + + 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 diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.c new file mode 100644 index 0000000000000000000000000000000000000000..ff88f7accf260e18c528db037273f25fcaa2c161 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.c @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#include "wlan_hdd_includes.h" +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_rx_monitor.h" + +/** + * hdd_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 hdd_rx_monitor_callback(ol_osif_vdev_handle context, + qdf_nbuf_t rxbuf, + void *rx_status) +{ + struct hdd_adapter *adapter; + int rxstat; + struct sk_buff *skb; + struct sk_buff *skb_next; + unsigned int cpu_index; + + qdf_assert(context); + qdf_assert(rxbuf); + + adapter = (struct hdd_adapter *)context; + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "invalid adapter %pK", adapter); + return; + } + + cpu_index = wlan_hdd_get_cpu(); + + /* walk the chain until all are processed */ + skb = (struct sk_buff *)rxbuf; + while (NULL != skb) { + skb_next = skb->next; + skb->dev = adapter->dev; + + ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index]; + ++adapter->stats.rx_packets; + adapter->stats.rx_bytes += skb->len; + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(skb); + + /* + * If this is not a last packet on the chain + * Just put packet into backlog queue, not scheduling RX sirq + */ + if (skb->next) { + rxstat = netif_rx(skb); + } else { + /* + * This is the last packet on the chain + * Scheduling rx sirq + */ + rxstat = netif_rx_ni(skb); + } + + if (NET_RX_SUCCESS == rxstat) + ++adapter-> + hdd_stats.tx_rx_stats.rx_delivered[cpu_index]; + else + ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index]; + + skb = skb_next; + } +} + +/** + * hdd_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 hdd_monitor_set_rx_monitor_cb(struct ol_txrx_ops *txrx, + ol_txrx_rx_mon_fp rx_monitor_cb) +{ + txrx->rx.mon = rx_monitor_cb; +} + +/** + * hdd_enable_monitor_mode() - Enable monitor mode + * @dev: Pointer to the net_device structure + * + * This function invokes cdp interface API to enable + * monitor mode configuration on the hardware. In this + * case sends HTT messages to FW to setup hardware rings + * + * Return: 0 for success; non-zero for failure + */ +int hdd_enable_monitor_mode(struct net_device *dev) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_enter_dev(dev); + + return cdp_set_monitor_mode(soc, + (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, adapter->session_id), false); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.h new file mode 100644 index 0000000000000000000000000000000000000000..9747a2096370374d24b04dada690dca63c438549 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.h @@ -0,0 +1,46 @@ +/* + * 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_RX_MONITOR_H +#define __WLAN_HDD_RX_MONITOR_H + +struct ol_txrx_ops; + +#if defined(QCA_WIFI_QCA6290) +void hdd_monitor_set_rx_monitor_cb(struct ol_txrx_ops *txrx, + ol_txrx_rx_mon_fp rx_monitor_cb); + +void hdd_rx_monitor_callback(ol_osif_vdev_handle vdev, + qdf_nbuf_t mpdu, + void *rx_status); + +int hdd_enable_monitor_mode(struct net_device *dev); +#else +static inline void hdd_monitor_set_rx_monitor_cb(struct ol_txrx_ops *txrx, + ol_txrx_rx_mon_fp rx_monitor_cb){ } +static inline void hdd_rx_monitor_callback(ol_osif_vdev_handle vdev, + qdf_nbuf_t mpdu, + void *rx_status){ } +static inline int hdd_enable_monitor_mode(struct net_device *dev) +{ + return 0; +} +#endif /* CONFIG_LITHIUM */ + +#endif /* __WLAN_HDD_RX_MONITOR_H */ + diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c new file mode 100644 index 0000000000000000000000000000000000000000..b7d93cd436722bec1303097987b77868fd9e3495 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c @@ -0,0 +1,1572 @@ +/* + * 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: 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 "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" + +#ifdef WLAN_UMAC_CONVERGENCE +#include "wlan_cfg80211.h" +#endif +#include +#include + +#include "wlan_utility.h" +#include "wlan_hdd_object_manager.h" + +#define MAX_RATES 12 +#define HDD_WAKE_LOCK_SCAN_DURATION (5 * 1000) /* in msec */ + +#define SCAN_DONE_EVENT_BUF_SIZE 4096 +#define RATE_MASK 0x7f + +/** + * enum essid_bcast_type - SSID broadcast type + * @eBCAST_UNKNOWN: Broadcast unknown + * @eBCAST_NORMAL: Broadcast normal + * @eBCAST_HIDDEN: Broadcast hidden + */ +enum essid_bcast_type { + eBCAST_UNKNOWN = 0, + eBCAST_NORMAL = 1, + eBCAST_HIDDEN = 2, +}; + +/** + * hdd_vendor_scan_callback() - Scan completed callback event + * @hddctx: HDD context + * @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; + + hdd_enter(); + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid adapter magic"); + qdf_mem_free(req); + return; + } + skb = cfg80211_vendor_event_alloc(hddctx->wiphy, &(adapter->wdev), + SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_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 staus"); + goto nla_put_failure; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + hdd_info("scan complete event sent to NL"); + qdf_mem_free(req); + return; + +nla_put_failure: + kfree_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_channel_list == NULL || + 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_channel_list[j] == + request->channels[i]->hw_value) { + find = true; + break; + } + } + if (!find) { + skip = false; + hdd_debug("Chan %d isn't in ACS chan list", + request->channels[i]->hw_value); + 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 + +static void __wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work) +{ + struct hdd_adapter *adapter; + struct cfg80211_scan_request *request; + struct scan_req *blocked_scan_req; + qdf_list_node_t *node = NULL; + + adapter = container_of(work, struct hdd_adapter, scan_block_work); + if (WLAN_HDD_ADAPTER_MAGIC != 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 wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __wlan_hdd_cfg80211_scan_block_cb(work); + cds_ssr_unprotect(__func__); +} + +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_session_id = 0xFF; + hdd_ctx->last_scan_reject_reason = 0; + hdd_ctx->scan_reject_cnt = 0; + } +} + +void hdd_reset_scan_reject_params(struct hdd_context *hdd_ctx, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + if ((roam_status == eCSR_ROAM_ASSOCIATION_FAILURE) || + (roam_status == eCSR_ROAM_CANCELLED) || + (roam_result == eCSR_ROAM_RESULT_ASSOCIATED)) { + hdd_debug("Reset scan reject params"); + hdd_init_scan_reject_params(hdd_ctx); + } +} + +/* + * 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; + 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; + + while (rem_len >= 2) { + current_ie = temp_ie; + elem_id = *temp_ie++; + elem_len = *temp_ie++; + rem_len -= 2; + + 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 IE_EID_VENDOR: + if ((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) { + hdd_err("Failed to allocate 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 + * @dev: Pointer to net device + * @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); + struct hdd_config *cfg_param = NULL; + int status; + struct hdd_scan_info *scan_info = NULL; + struct hdd_adapter *con_sap_adapter; + uint16_t con_dfs_ch; + uint8_t curr_session_id; + enum scan_reject_states curr_reason; + static uint32_t scan_ebusy_cnt; + struct scan_params params = {0}; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + 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_session_id(adapter->session_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->session_id, request->n_channels); + + if (!sme_is_session_id_valid(hdd_ctx->mac_handle, adapter->session_id)) + return -EINVAL; + + if ((eConnectionState_Associated == + WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState) && + (!hdd_ctx->config->enable_connected_scan)) { + 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; + } + + hdd_debug("Device_mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + + /* + * IBSS vdev does not need to scan to establish + * IBSS connection. If IBSS vdev need to support scan, + * Firmware need to make the change to add self peer + * per mac for IBSS vdev. + * NDI does not need scan from userspace to establish connection + * and it does not support scan request either. + */ + if (QDF_IBSS_MODE == adapter->device_mode || + QDF_NDI_MODE == adapter->device_mode) { + hdd_err("Scan not supported for %s", + hdd_device_mode_to_string(adapter->device_mode)); + return -EINVAL; + } + + cfg_param = hdd_ctx->config; + 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) { + con_dfs_ch = con_sap_adapter->session.ap.sap_config.channel; + if (con_dfs_ch == AUTO_CHANNEL_SELECT) + con_dfs_ch = + con_sap_adapter->session.ap.operating_channel; + + if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) && + wlan_reg_is_dfs_ch(hdd_ctx->pdev, con_dfs_ch) && + !policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + hdd_ctx->psoc)) { + /* 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_session_id, &curr_reason)) { + scan_ebusy_cnt++; + hdd_err_rl("Scan not allowed. scan_ebusy_cnt: %d Session %d Reason %d", + scan_ebusy_cnt, curr_session_id, curr_reason); + if (hdd_ctx->last_scan_reject_session_id != curr_session_id || + hdd_ctx->last_scan_reject_reason != curr_reason || + !hdd_ctx->last_scan_reject_timestamp) { + hdd_ctx->last_scan_reject_session_id = curr_session_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_session_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 (hdd_ctx->config->enable_fatal_event) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, + false, + hdd_ctx->config->enableSelfRecovery); + } 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 != NULL) { + 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_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode) || + (QDF_P2P_DEVICE_MODE == adapter->device_mode)) { + struct csr_roam_profile *roam_profile = + hdd_roam_profile(adapter); + + roam_profile->pAddIEScan = + scan_info->scan_add_ie.addIEdata; + roam_profile->nAddIEScanLength = + scan_info->scan_add_ie.length; + } + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) { + status = -EINVAL; + goto error; + } + + if ((request->n_ssids == 1) && (request->ssids != NULL) && + (request->ssids[0].ssid_len > 7) && + !qdf_mem_cmp(&request->ssids[0], "DIRECT-", 7)) + ucfg_p2p_status_scan(vdev); + + status = wlan_cfg80211_scan(vdev, request, ¶ms); + hdd_objmgr_put_vdev(vdev); +error: + if (params.default_ie.ptr) + qdf_mem_free(params.default_ie.ptr); + hdd_exit(); + return status; +} + +#undef SCAN_FAILURE + +/** + * wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @dev: Pointer to net device + * @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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_scan(wiphy, + request, NL_SCAN); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * wlan_hdd_cfg80211_tdls_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. This + * function gets called when tdls module queues the scan request. + * + * Return: 0 for success, non zero for failure. + */ +int wlan_hdd_cfg80211_tdls_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_scan(wiphy, + request, source); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * 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; + + skb = 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"); + kfree_skb(skb); + return -EINVAL; + } + + ret = cfg80211_vendor_cmd_reply(skb); + + /* Send a scan started event to supplicant */ + skb = cfg80211_vendor_event_alloc(wiphy, wdev, + sizeof(u64) + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SCAN_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)) { + kfree_skb(skb); + return -EINVAL; + } + 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) +{ + if (test_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->event_flags)) { + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&adapter->session. + ap.vendor_acs_timer)) { + qdf_mc_timer_stop(&adapter->session. + ap.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 + * @wdev: Pointer to wireless device + * @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 wireless_dev *wdev, + 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) || + (wdev->current_bss)) { + 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 wireless_dev *wdev, + struct nlattr **tb) +{ + return 0; +} +#endif + +static 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] = {.type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK] = {.type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, +}; + +/** + * __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 tmp, count, j; + 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); + + 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 (MAX_CHANNEL < n_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 > SIR_MAC_MAX_SSID_LENGTH) || + (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, wdev, 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 + * @dev: Pointer to net 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + 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 + * + * 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) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_vendor_abort_scan(wiphy, + data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_scan_abort() - abort ongoing scan + * @adapter: Pointer to interface adapter + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_scan_abort(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->session_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; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_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; + + if (!hdd_ctx->config->PnoOffload) { + hdd_debug("PnoOffload is not enabled!!!"); + return -EINVAL; + } + + if ((eConnectionState_Associated == + WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState) && + (!hdd_ctx->config->enable_connected_scan)) { + hdd_info("enable_connected_scan is false, Aborting scan"); + return -EBUSY; + } + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + ret = wlan_cfg80211_sched_scan_start(vdev, request, + hdd_ctx->config->scan_backoff_multiplier); + hdd_objmgr_put_vdev(vdev); + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request); + cds_ssr_unprotect(__func__); + + return ret; +} + +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; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (NULL == hdd_ctx) { + hdd_err("HDD context is Null"); + return -EINVAL; + } + if (!hdd_ctx->config->PnoOffload) { + hdd_debug("PnoOffload is not enabled!!!"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + ret = wlan_cfg80211_sched_scan_stop(vdev); + hdd_objmgr_put_vdev(vdev); + + 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; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err_rl("Command not allowed in FTM 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); + + hdd_exit(); + + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sched_scan_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#else +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev, + uint64_t reqid) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sched_scan_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#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_session_id(adapter->session_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) +{ + cds_ssr_protect(__func__); + __wlan_hdd_cfg80211_abort_scan(wiphy, wdev); + cds_ssr_unprotect(__func__); +} +#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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h new file mode 100644 index 0000000000000000000000000000000000000000..bcc874b43be376facea453990fdbfe62ed17742f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h @@ -0,0 +1,148 @@ +/* + * 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 : 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 + +#define MAX_PENDING_LOG 5 + +/* (30 Mins) */ +#define MIN_TIME_REQUIRED_FOR_NEXT_BUG_REPORT (30 * 60 * 1000) + +/* HDD Scan inactivity timeout set to double + * of the CSR CMD Timeout. + */ +#define HDD_SCAN_INACTIVITY_TIMEOUT \ + (CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT * 2) + +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); + +/** + * hdd_reset_scan_reject_params() - reset scan reject params per roam stats + * @hdd_ctx: hdd contxt + * @roam_status: roam status + * @roam_result: roam result + * + * Return: None + */ +void hdd_reset_scan_reject_params(struct hdd_context *hdd_ctx, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); + +/** + * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler + * @work: Pointer to work + * + * This function is used to do scan block work handler + * + * Return: none + */ +void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work); +#endif /* end #if !defined(WLAN_HDD_SCAN_H) */ + diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..2d3abbea9114fd07449f0fa1bf9a35bb6d64e561 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -0,0 +1,1321 @@ +/* + * 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. + */ + +/* denote that this file does not allow legacy hddLog */ +#define HDD_DISALLOW_LEGACY_HDDLOG 1 + +/* Include files */ +#include +#include +#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 +#include "wlan_mlme_ucfg_api.h" + +/* Preprocessor definitions and constants */ +#undef QCA_HDD_SAP_DUMP_SK_BUFF + +/* Type declarations */ + +/* Function definitions and documenation */ +#ifdef QCA_HDD_SAP_DUMP_SK_BUFF +/** + * hdd_softap_dump_sk_buff() - Dump an skb + * @skb: skb to dump + * + * Return: None + */ +static void hdd_softap_dump_sk_buff(struct sk_buff *skb) +{ + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: head = %pK ", __func__, skb->head); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "%s: tail = %pK ", __func__, skb->tail); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: end = %pK ", __func__, skb->end); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: len = %d ", __func__, skb->len); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: data_len = %d ", __func__, skb->data_len); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: mac_len = %d", __func__, skb->mac_len); + + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", skb->data[0], + skb->data[1], skb->data[2], skb->data[3], skb->data[4], + skb->data[5], skb->data[6], skb->data[7]); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", skb->data[8], + skb->data[9], skb->data[10], skb->data[11], skb->data[12], + skb->data[13], skb->data[14], skb->data[15]); +} +#else +static void hdd_softap_dump_sk_buff(struct sk_buff *skb) +{ +} +#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); +} + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * 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) +{ + if (true == tx_resume) + return; + + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&adapter-> + tx_flow_control_timer)) { + QDF_STATUS status; + + status = qdf_mc_timer_start(&adapter->tx_flow_control_timer, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + adapter->hdd_stats.tx_rx_stats.txflow_timer_cnt++; + } +} +#else + +static inline void +hdd_softap_tx_resume_false(struct hdd_adapter *adapter, bool tx_resume) +{ +} +#endif + +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); +} + +static inline struct sk_buff *hdd_skb_orphan(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int need_orphan = 0; + + if (adapter->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 (hdd_ctx->config->tx_orphan_enable) + need_orphan = 1; +#endif + } else if (hdd_ctx->config->tx_orphan_enable) { + if (qdf_nbuf_is_ipv4_tcp_pkt(skb) || + qdf_nbuf_is_ipv6_tcp_pkt(skb)) + need_orphan = 1; + } + + if (need_orphan) { + skb_orphan(skb); + ++adapter->hdd_stats.tx_rx_stats.tx_orphaned; + } else + skb = skb_unshare(skb, GFP_ATOMIC); + + return skb; +} + +#else +/** + * hdd_skb_orphan() - skb_unshare a cloned packed else skb_orphan + * @adapter: pointer to HDD adapter + * @skb: pointer to skb data packet + * + * Return: pointer to skb structure + */ +static inline struct sk_buff *hdd_skb_orphan(struct hdd_adapter *adapter, + struct sk_buff *skb) { + + struct sk_buff *nskb; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); +#endif + + hdd_skb_fill_gso_size(adapter->dev, skb); + + nskb = skb_unshare(skb, GFP_ATOMIC); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) + if (unlikely(hdd_ctx->config->tx_orphan_enable) && (nskb == skb)) { + /* + * 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. + */ + ++adapter->hdd_stats.tx_rx_stats.tx_orphaned; + skb_orphan(skb); + } +#endif + return nskb; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * hdd_post_dhcp_ind() - Send DHCP START/STOP indication to FW + * @adapter: pointer to hdd adapter + * @sta_id: peer station ID + * @type: WMA message type + * + * Return: error number + */ +int hdd_post_dhcp_ind(struct hdd_adapter *adapter, + uint8_t sta_id, uint16_t type) +{ + tAniDHCPInd pmsg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + hdd_debug("Post DHCP indication,sta_id=%d, type=%d", sta_id, type); + + if (!adapter) { + hdd_err("NULL adapter"); + return -EINVAL; + } + + pmsg.msgType = type; + pmsg.msgLen = (uint16_t) sizeof(tAniDHCPInd); + pmsg.device_mode = adapter->device_mode; + qdf_mem_copy(pmsg.adapterMacAddr.bytes, + adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pmsg.peerMacAddr.bytes, + adapter->sta_info[sta_id].sta_mac.bytes, + QDF_MAC_ADDR_SIZE); + + status = wma_process_dhcp_ind(cds_get_context(QDF_MODULE_ID_WMA), + &pmsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Post DHCP Ind MSG fail", __func__); + return -EFAULT; + } + + return 0; +} + +/** + * hdd_softap_notify_dhcp_ind() - Notify SAP for DHCP indication for tx desc + * @context: pointer to HDD context + * @netbuf: pointer to OS packet (sk_buff) + * + * Return: None + */ +static void hdd_softap_notify_dhcp_ind(void *context, struct sk_buff *netbuf) +{ + struct hdd_ap_ctx *hdd_ap_ctx; + struct qdf_mac_addr *dest_mac_addr; + uint8_t sta_id; + struct hdd_adapter *adapter = context; + + if (hdd_validate_adapter(adapter)) + return; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + if (!hdd_ap_ctx) { + hdd_err("HDD sap context is NULL"); + return; + } + + dest_mac_addr = (struct qdf_mac_addr *)netbuf->data; + + if (QDF_NBUF_CB_GET_IS_BCAST(netbuf) || + QDF_NBUF_CB_GET_IS_MCAST(netbuf)) { + /* The BC/MC station ID is assigned during BSS + * starting phase. SAP will return the station ID + * used for BC/MC traffic. + */ + sta_id = hdd_ap_ctx->broadcast_sta_id; + } else { + if (QDF_STATUS_SUCCESS != + hdd_softap_get_sta_id(adapter, + dest_mac_addr, &sta_id)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to find right station", __func__); + return; + } + } + hdd_post_dhcp_ind(adapter, sta_id, WMA_DHCP_STOP_IND); +} + +/** + * hdd_inspect_dhcp_packet() - Inspect DHCP packet + * @adapter: pointer to hdd adapter + * @sta_id: peer station ID + * @skb: 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 hdd_inspect_dhcp_packet(struct hdd_adapter *adapter, + uint8_t sta_id, + struct sk_buff *skb, + enum qdf_proto_dir dir) +{ + enum qdf_proto_subtype subtype = QDF_PROTO_INVALID; + struct hdd_station_info *hdd_sta_info; + int errno = 0; + + if (sta_id >= WLAN_MAX_STA_COUNT) { + hdd_err("Invalid sta id: %d", sta_id); + return -EINVAL; + } + + if (((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) && + ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP == + QDF_NBUF_CB_GET_PACKET_TYPE(skb)) || + (dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(skb) == true))) { + + subtype = qdf_nbuf_get_dhcp_subtype(skb); + hdd_sta_info = &adapter->sta_info[sta_id]; + + hdd_debug("ENTER: type=%d, phase=%d, nego_status=%d", + subtype, + hdd_sta_info->dhcp_phase, + hdd_sta_info->dhcp_nego_status); + + switch (subtype) { + case QDF_PROTO_DHCP_DISCOVER: + if (dir != QDF_RX) + break; + if (hdd_sta_info->dhcp_nego_status == DHCP_NEGO_STOP) + errno = hdd_post_dhcp_ind(adapter, sta_id, + WMA_DHCP_START_IND); + hdd_sta_info->dhcp_phase = DHCP_PHASE_DISCOVER; + hdd_sta_info->dhcp_nego_status = DHCP_NEGO_IN_PROGRESS; + break; + case QDF_PROTO_DHCP_OFFER: + hdd_sta_info->dhcp_phase = DHCP_PHASE_OFFER; + break; + case QDF_PROTO_DHCP_REQUEST: + if (dir != QDF_RX) + break; + if (hdd_sta_info->dhcp_nego_status == DHCP_NEGO_STOP) + errno = hdd_post_dhcp_ind(adapter, sta_id, + WMA_DHCP_START_IND); + hdd_sta_info->dhcp_nego_status = DHCP_NEGO_IN_PROGRESS; + case QDF_PROTO_DHCP_DECLINE: + if (dir == QDF_RX) + hdd_sta_info->dhcp_phase = DHCP_PHASE_REQUEST; + break; + case QDF_PROTO_DHCP_ACK: + case QDF_PROTO_DHCP_NACK: + hdd_sta_info->dhcp_phase = DHCP_PHASE_ACK; + if (hdd_sta_info->dhcp_nego_status == + DHCP_NEGO_IN_PROGRESS) { + hdd_debug("Setting NOTIFY_COMP Flag"); + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(skb) + = 1; + } + hdd_sta_info->dhcp_nego_status = DHCP_NEGO_STOP; + break; + default: + break; + } + + hdd_debug("EXIT: phase=%d, nego_status=%d", + hdd_sta_info->dhcp_phase, + hdd_sta_info->dhcp_nego_status); + } + + return errno; +} + +/** + * __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 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: Always returns NETDEV_TX_OK + */ +static netdev_tx_t __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_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + struct qdf_mac_addr *dest_mac_addr; + uint8_t sta_id; + uint32_t num_seg; + + ++adapter->hdd_stats.tx_rx_stats.tx_called; + adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + + /* Prevent this function from being called during SSR since TL + * context may not be reinitialized at this time which may + * lead to a crash. + */ + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() || + cds_is_load_or_unload_in_progress()) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Recovery/(Un)load in Progress. Ignore!!!", + __func__); + goto drop_pkt; + } + + /* + * If the device is operating on a DFS Channel + * then check if SAP is in CAC WAIT state and + * drop the packets. In CAC WAIT state device + * is expected not to transmit any frames. + * SAP starts Tx only after the BSS START is + * done. + */ + if (ap_ctx->dfs_cac_block_tx) + goto drop_pkt; + + /* + * If a transmit function is not registered, drop packet + */ + if (!adapter->tx_fn) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: TX function not registered by the data path", + __func__); + goto drop_pkt; + } + + wlan_hdd_classify_pkt(skb); + + dest_mac_addr = (struct qdf_mac_addr *)skb->data; + + if (QDF_NBUF_CB_GET_IS_BCAST(skb) || + QDF_NBUF_CB_GET_IS_MCAST(skb)) { + /* The BC/MC station ID is assigned during BSS + * starting phase. SAP will return the station ID + * used for BC/MC traffic. + */ + sta_id = ap_ctx->broadcast_sta_id; + } else { + if (QDF_STATUS_SUCCESS != + hdd_softap_get_sta_id(adapter, + dest_mac_addr, &sta_id)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to find right station", __func__); + goto drop_pkt; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to find right station", __func__); + goto drop_pkt; + } else if (!adapter->sta_info[sta_id].in_use) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: STA %d is unregistered", __func__, + sta_id); + goto drop_pkt; + } else if (adapter->sta_info[sta_id]. + is_deauth_in_progress) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: STA %d deauth in progress", __func__, + sta_id); + goto drop_pkt; + } + + if ((OL_TXRX_PEER_STATE_CONN != + adapter->sta_info[sta_id].peer_state) + && (OL_TXRX_PEER_STATE_AUTH != + adapter->sta_info[sta_id].peer_state)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Station not connected yet", __func__); + goto drop_pkt; + } else if (OL_TXRX_PEER_STATE_CONN == + adapter->sta_info[sta_id].peer_state) { + if (ntohs(skb->protocol) != HDD_ETHERTYPE_802_1_X) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: NON-EAPOL packet in non-Authenticated state", + __func__); + goto drop_pkt; + } + } + } + + hdd_get_tx_resource(adapter, sta_id, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + ++adapter->hdd_stats.tx_rx_stats.tx_classified_ac[ac]; + +#if defined(IPA_OFFLOAD) + if (!qdf_nbuf_ipa_owned_get(skb)) { +#endif + + skb = hdd_skb_orphan(adapter, skb); + if (!skb) + goto drop_pkt_accounting; + +#if defined(IPA_OFFLOAD) + } 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(skb); + } +#endif + + /* + * Add SKB to internal tracking table before further processing + * in WLAN driver. + */ + qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__); + + adapter->stats.tx_bytes += skb->len; + adapter->sta_info[sta_id].tx_bytes += skb->len; + + if (qdf_nbuf_is_tso(skb)) { + num_seg = qdf_nbuf_get_tso_num_seg(skb); + adapter->stats.tx_packets += num_seg; + adapter->sta_info[sta_id].tx_packets += num_seg; + } else { + ++adapter->stats.tx_packets; + adapter->sta_info[sta_id].tx_packets++; + } + adapter->sta_info[sta_id].last_tx_rx_ts = qdf_system_ticks(); + + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(skb) = 0; + + if (sta_id != ap_ctx->broadcast_sta_id) + hdd_inspect_dhcp_packet(adapter, sta_id, skb, QDF_TX); + + hdd_event_eapol_log(skb, QDF_TX); + QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, QDF_NBUF_TX_PKT_HDD); + qdf_dp_trace_set_track(skb, QDF_TX); + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(skb), + sizeof(qdf_nbuf_data(skb)), + QDF_TX)); + + /* check whether need to linearize skb, like non-linear udp data */ + if (hdd_skb_nontso_linearize(skb) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: skb %pK linearize failed. drop the pkt", + __func__, skb); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + + if (adapter->tx_fn(adapter->txrx_vdev, + (qdf_nbuf_t)skb) != NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to send packet to txrx for staid:%d", + __func__, sta_id); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + netif_trans_update(dev); + + return NETDEV_TX_OK; + +drop_pkt_and_release_skb: + qdf_net_buf_debug_release_skb(skb); +drop_pkt: + + qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_DROP_PACKET_RECORD, 0, + QDF_TX); + kfree_skb(skb); + +drop_pkt_accounting: + ++adapter->stats.tx_dropped; + ++adapter->hdd_stats.tx_rx_stats.tx_dropped; + + return NETDEV_TX_OK; +} + +netdev_tx_t hdd_softap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + netdev_tx_t ret; + + cds_ssr_protect(__func__); + ret = __hdd_softap_hard_start_xmit(skb, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 netdev_queue *txq; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + 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; + } + + 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_netif_queue_history(hdd_ctx, + QDF_STATS_VERBOSITY_LEVEL_HIGH); + cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "carrier state: %d", netif_carrier_ok(dev)); + + ++adapter->hdd_stats.tx_rx_stats.tx_timeout_cnt; + ++adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt; + + if (adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt > + HDD_TX_STALL_THRESHOLD) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Detected data stall due to continuous TX timeouts"); + adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + if (hdd_ctx->config->enable_data_stall_det) + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_HOST_DRIVER, + DATA_STALL_LOG_HOST_SOFTAP_TX_TIMEOUT, + 0xFF, 0xFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } +} + +void hdd_softap_tx_timeout(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_softap_tx_timeout(dev); + cds_ssr_unprotect(__func__); +} + +QDF_STATUS hdd_softap_init_tx_rx(struct hdd_adapter *adapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + uint8_t STAId = 0; + + qdf_mem_zero(&adapter->stats, sizeof(struct net_device_stats)); + + spin_lock_init(&adapter->sta_info_lock); + + for (STAId = 0; STAId < WLAN_MAX_STA_COUNT; STAId++) { + qdf_mem_zero(&adapter->sta_info[STAId], + sizeof(struct hdd_station_info)); + } + + return status; +} + +QDF_STATUS hdd_softap_deinit_tx_rx(struct hdd_adapter *adapter) +{ + QDF_BUG(adapter); + if (!adapter) + return QDF_STATUS_E_FAILURE; + + adapter->txrx_vdev = NULL; + adapter->tx_fn = NULL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_softap_init_tx_rx_sta(struct hdd_adapter *adapter, + uint8_t sta_id, + struct qdf_mac_addr *sta_mac) +{ + spin_lock_bh(&adapter->sta_info_lock); + if (adapter->sta_info[sta_id].in_use) { + spin_unlock_bh(&adapter->sta_info_lock); + hdd_err("Reinit of in use station %d", sta_id); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&adapter->sta_info[sta_id], + sizeof(struct hdd_station_info)); + + adapter->sta_info[sta_id].in_use = true; + adapter->sta_info[sta_id].is_deauth_in_progress = false; + qdf_copy_macaddr(&adapter->sta_info[sta_id].sta_mac, sta_mac); + + spin_unlock_bh(&adapter->sta_info_lock); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_softap_deinit_tx_rx_sta(struct hdd_adapter *adapter, + uint8_t sta_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_hostapd_state *hostapd_state; + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + spin_lock_bh(&adapter->sta_info_lock); + + if (false == adapter->sta_info[sta_id].in_use) { + spin_unlock_bh(&adapter->sta_info_lock); + hdd_err("Deinit station not inited %d", sta_id); + return QDF_STATUS_E_FAILURE; + } + + adapter->sta_info[sta_id].in_use = false; + adapter->sta_info[sta_id].is_deauth_in_progress = false; + + spin_unlock_bh(&adapter->sta_info_lock); + return status; +} + +/** + * hdd_softap_tsf_timestamp_rx() - time stamp Rx netbuf + * @context: pointer to HDD context + * @netbuf: pointer to a Rx netbuf + * + * Return: None + */ +#ifdef WLAN_FEATURE_TSF_PLUS +static inline void hdd_softap_tsf_timestamp_rx(struct hdd_context *hdd_ctx, + qdf_nbuf_t netbuf) +{ + uint64_t target_time; + + if (!hdd_tsf_is_rx_set(hdd_ctx)) + return; + + target_time = ktime_to_us(netbuf->tstamp); + hdd_rx_timestamp(netbuf, target_time); +} +#else +static inline void hdd_softap_tsf_timestamp_rx(struct hdd_context *hdd_ctx, + qdf_nbuf_t netbuf) +{ +} +#endif + +/** + * hdd_softap_notify_tx_compl_cbk() - callback to notify tx completion + * @skb: pointer to skb data + * @adapter: pointer to vdev apdapter + * + * Return: None + */ +static void hdd_softap_notify_tx_compl_cbk(struct sk_buff *skb, + void *context) +{ + int errno; + struct hdd_adapter *adapter = context; + + errno = hdd_validate_adapter(adapter); + if (errno) + return; + + if (QDF_NBUF_CB_PACKET_TYPE_DHCP == QDF_NBUF_CB_GET_PACKET_TYPE(skb)) { + hdd_debug("sending DHCP indication"); + hdd_softap_notify_dhcp_ind(context, skb); + } +} + +QDF_STATUS hdd_softap_rx_packet_cbk(void *context, qdf_nbuf_t rx_buf) +{ + struct hdd_adapter *adapter = NULL; + int rxstat; + unsigned int cpu_index; + struct sk_buff *skb = NULL; + struct sk_buff *next = NULL; + struct hdd_context *hdd_ctx = NULL; + struct qdf_mac_addr *src_mac; + uint8_t staid; + + /* Sanity check on inputs */ + if (unlikely((NULL == context) || (NULL == rx_buf))) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + adapter = (struct hdd_adapter *)context; + if (unlikely(WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); + return QDF_STATUS_E_FAILURE; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (unlikely(NULL == hdd_ctx)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: HDD context is Null", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* walk the chain until all are processed */ + next = (struct sk_buff *)rx_buf; + + while (next) { + skb = next; + next = skb->next; + skb->next = NULL; + +#ifdef QCA_WIFI_QCA6290 /* Debug code, remove later */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: skb %pK skb->len %d\n", __func__, skb, skb->len); +#endif + + hdd_softap_dump_sk_buff(skb); + + skb->dev = adapter->dev; + + if (unlikely(skb->dev == NULL)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_ERROR, + "%s: ERROR!!Invalid netdevice", __func__); + continue; + } + cpu_index = wlan_hdd_get_cpu(); + ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index]; + ++adapter->stats.rx_packets; + adapter->stats.rx_bytes += skb->len; + + /* Send DHCP Indication to FW */ + src_mac = (struct qdf_mac_addr *)(skb->data + + QDF_NBUF_SRC_MAC_OFFSET); + if (QDF_STATUS_SUCCESS == + hdd_softap_get_sta_id(adapter, src_mac, &staid)) { + if (staid < WLAN_MAX_STA_COUNT) { + adapter->sta_info[staid].rx_packets++; + adapter->sta_info[staid].rx_bytes += skb->len; + adapter->sta_info[staid].last_tx_rx_ts = + qdf_system_ticks(); + hdd_inspect_dhcp_packet(adapter, staid, + skb, QDF_RX); + } + } + + hdd_event_eapol_log(skb, QDF_RX); + qdf_dp_trace_log_pkt(adapter->session_id, + skb, QDF_RX, QDF_TRACE_DEFAULT_PDEV_ID); + DPTRACE(qdf_dp_trace(skb, + QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(skb), + sizeof(qdf_nbuf_data(skb)), QDF_RX)); + DPTRACE(qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_RX_PACKET_RECORD, 0, QDF_RX)); + + skb->protocol = eth_type_trans(skb, skb->dev); + + /* hold configurable wakelock for unicast traffic */ + if (!hdd_is_current_high_throughput(hdd_ctx) && + hdd_ctx->config->rx_wakelock_timeout && + skb->pkt_type != PACKET_BROADCAST && + skb->pkt_type != PACKET_MULTICAST) { + cds_host_diag_log_work(&hdd_ctx->rx_wake_lock, + hdd_ctx->config->rx_wakelock_timeout, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); + qdf_wake_lock_timeout_acquire(&hdd_ctx->rx_wake_lock, + hdd_ctx->config-> + rx_wakelock_timeout); + } + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(skb); + + hdd_softap_tsf_timestamp_rx(hdd_ctx, skb); + + if (qdf_likely(hdd_ctx->enable_rxthread)) { + local_bh_disable(); + rxstat = netif_receive_skb(skb); + local_bh_enable(); + } else { + rxstat = netif_receive_skb(skb); + } + + hdd_ctx->no_rx_offload_pkt_cnt++; + + if (NET_RX_SUCCESS == rxstat) + ++adapter->hdd_stats.tx_rx_stats.rx_delivered[cpu_index]; + else + ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index]; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_softap_deregister_sta(struct hdd_adapter *adapter, + uint8_t sta_id) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct hdd_context *hdd_ctx; + tSmeConfigParams *sme_config; + + if (NULL == 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; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (sta_id >= WLAN_MAX_STA_COUNT) { + hdd_err("Error: Invalid sta_id: %u", sta_id); + return QDF_STATUS_E_INVAL; + } + + /* Clear station in TL and then update HDD data + * structures. This helps to block RX frames from other + * station to this station. + */ + qdf_status = cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_pdev *)cds_get_context(QDF_MODULE_ID_TXRX), + sta_id); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("cdp_clear_peer failed for staID %d, Status=%d [0x%08X]", + sta_id, qdf_status, qdf_status); + } + + if (adapter->sta_info[sta_id].in_use) { + if (ucfg_ipa_is_enabled()) { + if (ucfg_ipa_wlan_evt(hdd_ctx->pdev, adapter->dev, + adapter->device_mode, + adapter->sta_info[sta_id].sta_id, + adapter->session_id, + WLAN_IPA_CLIENT_DISCONNECT, + adapter->sta_info[sta_id].sta_mac. + bytes) != QDF_STATUS_SUCCESS) + hdd_err("WLAN_CLIENT_DISCONNECT event failed"); + } + spin_lock_bh(&adapter->sta_info_lock); + qdf_mem_zero(&adapter->sta_info[sta_id], + sizeof(struct hdd_station_info)); + spin_unlock_bh(&adapter->sta_info_lock); + } + + hdd_ctx->sta_to_adapter[sta_id] = NULL; + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + + if (!sme_config) { + hdd_err("Unable to allocate memory for smeconfig!"); + return 0; + } + sme_get_config_param(hdd_ctx->mac_handle, sme_config); + ucfg_mlme_update_oce_flags(hdd_ctx->pdev, + sme_config->csrConfig.oce_feature_bitmap); + qdf_mem_free(sme_config); + + return qdf_status; +} + +QDF_STATUS hdd_softap_register_sta(struct hdd_adapter *adapter, + bool auth_required, + bool privacy_required, + uint8_t sta_id, + struct qdf_mac_addr *sta_mac, + bool wmm_enabled) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + 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); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + tSmeConfigParams *sme_config; + + hdd_info("STA:%u, Auth:%u, Priv:%u, WMM:%u", + sta_id, auth_required, privacy_required, wmm_enabled); + + if (sta_id >= WLAN_MAX_STA_COUNT) { + hdd_err("Error: Invalid sta_id: %u", sta_id); + return qdf_status; + } + + /* + * Clean up old entry if it is not cleaned up properly + */ + if (adapter->sta_info[sta_id].in_use) { + hdd_info("clean up old entry for STA %d", sta_id); + hdd_softap_deregister_sta(adapter, sta_id); + } + + /* Get the Station ID from the one saved during the association. */ + staDesc.sta_id = sta_id; + + /* Save the adapter Pointer for this sta_id */ + hdd_ctx->sta_to_adapter[sta_id] = adapter; + + qdf_status = hdd_softap_init_tx_rx_sta(adapter, sta_id, sta_mac); + + staDesc.is_qos_enabled = wmm_enabled; + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_softap_rx_packet_cbk; + txrx_ops.tx.tx_comp = hdd_softap_notify_tx_compl_cbk; + cdp_vdev_register(soc, + (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, adapter->session_id), + adapter, &txrx_ops); + adapter->txrx_vdev = (void *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, + adapter->session_id); + adapter->tx_fn = txrx_ops.tx.tx; + + qdf_status = cdp_peer_register(soc, + (struct cdp_pdev *)pdev, &staDesc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("cdp_peer_register() failed to register. Status = %d [0x%08X]", + qdf_status, qdf_status); + 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 + */ + + adapter->sta_info[sta_id].sta_id = sta_id; + adapter->sta_info[sta_id].is_qos_enabled = wmm_enabled; + + if (!auth_required) { + hdd_info("open/shared auth StaId= %d. Changing TL state to AUTHENTICATED at Join time", + adapter->sta_info[sta_id].sta_id); + + /* Connections that do not need Upper layer auth, + * transition TL directly to 'Authenticated' state. + */ + qdf_status = hdd_change_peer_state(adapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_AUTH, false); + + adapter->sta_info[sta_id].peer_state = OL_TXRX_PEER_STATE_AUTH; + } else { + + hdd_info("ULA auth StaId= %d. Changing TL state to CONNECTED at Join time", + adapter->sta_info[sta_id].sta_id); + + qdf_status = hdd_change_peer_state(adapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_CONN, false); + adapter->sta_info[sta_id].peer_state = OL_TXRX_PEER_STATE_CONN; + } + + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + + if (!sme_config) { + hdd_err("Unable to allocate memory for smeconfig!"); + return 0; + } + sme_get_config_param(hdd_ctx->mac_handle, sme_config); + ucfg_mlme_update_oce_flags(hdd_ctx->pdev, + sme_config->csrConfig.oce_feature_bitmap); + qdf_mem_free(sme_config); + return qdf_status; +} + +/** + * hdd_softap_register_bc_sta() - Register the SoftAP broadcast STA + * @adapter: pointer to adapter context + * @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 hdd_adapter *adapter, + bool privacy_required) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct qdf_mac_addr broadcastMacAddr = QDF_MAC_ADDR_BCAST_INIT; + struct hdd_ap_ctx *ap_ctx; + uint8_t sta_id; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + 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; + } + + hdd_ctx->sta_to_adapter[sta_id] = adapter; + qdf_status = hdd_softap_register_sta(adapter, false, + privacy_required, sta_id, + &broadcastMacAddr, 0); + + return qdf_status; +} + +/** + * hdd_softap_deregister_bc_sta() - Deregister the SoftAP broadcast STA + * @adapter: pointer to adapter context + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +static QDF_STATUS hdd_softap_deregister_bc_sta(struct hdd_adapter *adapter) +{ + struct hdd_ap_ctx *ap_ctx; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + return hdd_softap_deregister_sta(adapter, ap_ctx->broadcast_sta_id); +} + +QDF_STATUS hdd_softap_stop_bss(struct hdd_adapter *adapter) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint8_t sta_id = 0; + struct hdd_context *hdd_ctx; + struct hdd_ap_ctx *ap_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + + /* 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 + */ + qdf_status = hdd_softap_deregister_bc_sta(adapter); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to deregister BC sta Id %d", + ap_ctx->broadcast_sta_id); + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + /* This excludes BC sta as it is already deregistered */ + if (adapter->sta_info[sta_id].in_use) { + qdf_status = hdd_softap_deregister_sta(adapter, sta_id); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to deregister sta Id %d", + sta_id); + } + } + } + if (adapter->device_mode == QDF_SAP_MODE) + wlan_hdd_restore_channels(hdd_ctx, true); + + /* Mark the indoor channel (passive) to enable */ + if (hdd_ctx->config->force_ssc_disable_indoor_channel && + 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, + ap_ctx->broadcast_sta_id, + adapter->session_id, + WLAN_IPA_AP_DISCONNECT, + adapter->dev->dev_addr) != + QDF_STATUS_SUCCESS) + hdd_err("WLAN_AP_DISCONNECT event failed"); + } + + 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) +{ + uint8_t sta_id = WLAN_MAX_STA_COUNT; + QDF_STATUS qdf_status; + + hdd_enter_dev(adapter->dev); + + qdf_status = hdd_softap_get_sta_id(adapter, sta_mac, &sta_id); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Failed to find right station"); + return qdf_status; + } + + if (false == + qdf_is_macaddr_equal(&adapter->sta_info[sta_id].sta_mac, + sta_mac)) { + hdd_err("Station %u MAC address not matching", sta_id); + return QDF_STATUS_E_FAILURE; + } + + qdf_status = + hdd_change_peer_state(adapter, sta_id, state, false); + hdd_info("Station %u changed to state %d", sta_id, state); + + if (QDF_STATUS_SUCCESS == qdf_status) { + adapter->sta_info[sta_id].peer_state = + OL_TXRX_PEER_STATE_AUTH; + p2p_peer_authorized(adapter->vdev, sta_mac->bytes); + } + + hdd_exit(); + return qdf_status; +} + +QDF_STATUS hdd_softap_get_sta_id(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac, + uint8_t *sta_id) +{ + uint8_t i; + + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (!qdf_mem_cmp + (&adapter->sta_info[i].sta_mac, sta_mac, + QDF_MAC_ADDR_SIZE) && adapter->sta_info[i].in_use) { + *sta_id = i; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_spectralscan.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_spectralscan.c new file mode 100644 index 0000000000000000000000000000000000000000..f9f9f41e7d171a499d007ed7e3531902c50e486a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_spectralscan.c @@ -0,0 +1,492 @@ +/* + * 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: wlan_hdd_spectral_scan.c + * + * WLAN Host Device Driver Spectral Scan Implementation + */ + +#include +#include +#include +#include +#include "wlan_hdd_includes.h" +#include "cds_api.h" +#include "ani_global.h" +#include "wlan_cfg80211_spectral.h" +#include "wlan_hdd_spectralscan.h" +#include +#ifdef CNSS_GENL +#include +#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; + + 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_session_id(adapter->session_id)) + return -EINVAL; + + ret = wlan_cfg80211_spectral_scan_config_and_start(wiphy, + hdd_ctx->pdev, + data, data_len); + 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); + + 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; + } + + ret = wlan_cfg80211_spectral_scan_stop(wiphy, hdd_ctx->pdev, + data, data_len); + 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); + + 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; + } + + ret = wlan_cfg80211_spectral_scan_get_config(wiphy, hdd_ctx->pdev, + data, data_len); + 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); + + 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; + } + + ret = wlan_cfg80211_spectral_scan_get_diag_stats(wiphy, + hdd_ctx->pdev, + data, data_len); + 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); + + 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; + } + + ret = wlan_cfg80211_spectral_scan_get_cap(wiphy, hdd_ctx->pdev, + data, data_len); + 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); + + 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; + } + + ret = wlan_cfg80211_spectral_scan_get_status(wiphy, hdd_ctx->pdev, + data, data_len); + hdd_exit(); + + return ret; +} + +int wlan_hdd_cfg80211_spectral_scan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_spectral_scan_start( + wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +int wlan_hdd_cfg80211_spectral_scan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_spectral_scan_stop( + wiphy, wdev, data, data_len); + + cds_ssr_unprotect(__func__); + + return ret; +} + +int wlan_hdd_cfg80211_spectral_scam_get_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_spectral_scan_get_config( + wiphy, wdev, data, data_len); + + cds_ssr_unprotect(__func__); + + return ret; +} + +int wlan_hdd_cfg80211_spectral_scan_get_diag_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_spectral_scan_get_diag_stats( + wiphy, wdev, data, data_len); + + cds_ssr_unprotect(__func__); + + return ret; +} + +int wlan_hdd_cfg80211_spectral_scan_get_cap_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_spectral_scan_get_cap_info( + wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +int wlan_hdd_cfg80211_spectral_scan_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_spectral_scan_get_status( + wiphy, wdev, data, data_len); + + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 *rsp_msg; + int err; + + skb = alloc_skb(NLMSG_SPACE(sizeof(struct spectral_scan_msg)), + GFP_KERNEL); + if (skb == NULL) { + 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; + + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct spectral_scan_msg)); + skb_put(skb, NLMSG_SPACE(sizeof(struct spectral_scan_msg))); + + 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 (0 != 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) +{ + cds_ssr_protect(__func__); + __spectral_scan_msg_handler(data, data_len, ctx, pid); + cds_ssr_unprotect(__func__); +} + +void spectral_scan_activate_service(void) +{ + register_cld_cmd_cb(WLAN_NL_MSG_SPECTRAL_SCAN, + spectral_scan_msg_handler, NULL); +} + +void spectral_scan_deactivate_service(void) +{ + deregister_cld_cmd_cb(WLAN_NL_MSG_SPECTRAL_SCAN); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..b975446e576f389bbd14bd0404b0b6b025d96b77 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c @@ -0,0 +1,6263 @@ +/* + * 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 : 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 "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_reg_services_api.h" +#include +#include "wlan_cp_stats_mc_ucfg_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_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 +#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_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) +#endif /* kernel version less than 4.0.0 && no_backport */ + +/* 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 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 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 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} } +}; + +/*MCS parameters with Nss = 2*/ +static 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}, {1560, 1733} } +}; + +/*array index ponints to MCS and array value points respective rssi*/ +static int rssi_mcs_tbl[][10] = { +/*MCS 0 1 2 3 4 5 6 7 8 9*/ + {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */ + {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */ + {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */ +}; + + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * struct hdd_ll_stats_priv - hdd link layer stats private + * @request_id: userspace-assigned link layer stats request id + * @request_bitmap: userspace-assigned link layer stats request bitmap + */ +struct hdd_ll_stats_priv { + uint32_t request_id; + uint32_t request_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(tpSirWifiRateStat 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.rateMcsIdx) || + 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->txMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU, + stats->rxMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST, + stats->mpduLost) || + 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->retriesShort) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG, + stats->retriesLong)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +/** + * 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(tpSirWifiPeerInfo stats, + struct sk_buff *vendor_event) +{ + u32 i = 0; + tpSirWifiRateStat pRateStats; + + 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->peerMacAddress.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->numRate)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + goto error; + } + + if (stats->numRate) { + struct nlattr *rateInfo; + struct nlattr *rates; + + rateInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO); + if (rateInfo == NULL) + goto error; + + for (i = 0; i < stats->numRate; i++) { + pRateStats = (tpSirWifiRateStat) ((uint8_t *) + stats->rateStats + + (i * + sizeof + (tSirWifiRateStat))); + rates = nla_nest_start(vendor_event, i); + if (rates == NULL) + goto error; + + if (false == + put_wifi_rate_stat(pRateStats, vendor_event)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + nla_nest_end(vendor_event, rates); + } + nla_nest_end(vendor_event, rateInfo); + } + + return true; +error: + return false; +} + +/** + * 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 + * + * Return: bool + */ +static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats, + struct sk_buff *vendor_event) +{ + 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_STATE, + stats->state) || + 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, + WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR, + WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +/** + * put_wifi_iface_stats() - put wifi interface stats + * @pWifiIfaceStat: Pointer to interface stats context + * @num_peer: Number of peers + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat, + u32 num_peers, struct sk_buff *vendor_event) +{ + int i = 0; + struct nlattr *wmmInfo; + struct nlattr *wmmStats; + u64 average_tsf_offset; + wmi_iface_link_stats *link_stats = &pWifiIfaceStat->link_stats; + + if (false == put_wifi_interface_info(&pWifiIfaceStat->info, + vendor_event)) { + 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_WLAN_VENDOR_ATTR_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) || + 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, + pWifiIfaceStat->rts_succ_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT, + pWifiIfaceStat->rts_fail_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT, + pWifiIfaceStat->ppdu_succ_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT, + pWifiIfaceStat->ppdu_fail_cnt)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + wmmInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO); + if (wmmInfo == NULL) + return false; + + for (i = 0; i < WIFI_AC_MAX; i++) { + wmmStats = nla_nest_start(vendor_event, i); + if (wmmStats == NULL) + return false; + + if (false == + put_wifi_wmm_ac_stat(&pWifiIfaceStat->ac_stats[i], + vendor_event)) { + hdd_err("put_wifi_wmm_ac_stat Fail"); + return false; + } + + nla_nest_end(vendor_event, wmmStats); + } + nla_nest_end(vendor_event, wmmInfo); + return true; +} + +/** + * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode + * @deviceMode: Device mode + * + * Return: interface mode + */ +static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode) +{ + switch (deviceMode) { + 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; + case QDF_IBSS_MODE: + return WIFI_INTERFACE_IBSS; + default: + /* Return Interface Mode as STA for all the unsupported modes */ + return WIFI_INTERFACE_STA; + } +} + +bool hdd_get_interface_info(struct hdd_adapter *adapter, + tpSirWifiInterfaceInfo pInfo) +{ + uint8_t *staMac = NULL; + struct hdd_station_ctx *sta_ctx; + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + /* pre-existing layering violation */ + tpAniSirGlobal pMac = MAC_CONTEXT(mac_handle); + + pInfo->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode); + + qdf_copy_macaddr(&pInfo->macAddr, &adapter->mac_addr); + + 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(adapter); + if (eConnectionState_NotConnected == + sta_ctx->conn_info.connState) { + pInfo->state = WIFI_DISCONNECTED; + } + if (eConnectionState_Connecting == + sta_ctx->conn_info.connState) { + hdd_err("Session ID %d, Connection is in progress", + adapter->session_id); + pInfo->state = WIFI_ASSOCIATING; + } + if ((eConnectionState_Associated == + sta_ctx->conn_info.connState) + && (false == sta_ctx->conn_info.uIsAuthenticated)) { + staMac = + (uint8_t *) &(adapter->mac_addr. + bytes[0]); + hdd_err("client " MAC_ADDRESS_STR + " is in the middle of WPS/EAPOL exchange.", + MAC_ADDR_ARRAY(staMac)); + pInfo->state = WIFI_AUTHENTICATING; + } + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) { + pInfo->state = WIFI_ASSOCIATED; + qdf_copy_macaddr(&pInfo->bssid, + &sta_ctx->conn_info.bssId); + qdf_mem_copy(pInfo->ssid, + sta_ctx->conn_info.SSID.SSID.ssId, + sta_ctx->conn_info.SSID.SSID.length); + /* + * NULL Terminate the string + */ + pInfo->ssid[sta_ctx->conn_info.SSID.SSID.length] = 0; + } + } + + qdf_mem_copy(pInfo->countryStr, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + qdf_mem_copy(pInfo->apCountryStr, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + return true; +} + +/** + * hdd_link_layer_process_peer_stats() - This function is called after + * @adapter: Pointer to device adapter + * @more_data: More data + * @pData: 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, + tpSirWifiPeerStat pData) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tpSirWifiPeerStat pWifiPeerStat; + tpSirWifiPeerInfo pWifiPeerInfo; + struct sk_buff *vendor_event; + int status, i; + struct nlattr *peers; + int numRate; + + hdd_enter(); + + pWifiPeerStat = pData; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + hdd_debug("LL_STATS_PEER_ALL : numPeers %u, more data = %u", + pWifiPeerStat->numPeers, more_data); + + /* + * Allocate a size of 4096 for the peer stats comprising + * each of size = sizeof (tSirWifiPeerInfo) + numRate * + * sizeof (tSirWifiRateStat).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 (tSirWifiRateStat) being 32. + */ + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) || + 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_IFACE_NUM_PEERS, + pWifiPeerStat->numPeers)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + + kfree_skb(vendor_event); + return; + } + + pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *) + pWifiPeerStat->peerInfo); + + if (pWifiPeerStat->numPeers) { + struct nlattr *peerInfo; + + peerInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO); + if (peerInfo == NULL) { + hdd_err("nla_nest_start failed"); + kfree_skb(vendor_event); + return; + } + + for (i = 1; i <= pWifiPeerStat->numPeers; i++) { + peers = nla_nest_start(vendor_event, i); + if (peers == NULL) { + hdd_err("nla_nest_start failed"); + kfree_skb(vendor_event); + return; + } + + numRate = pWifiPeerInfo->numRate; + + if (false == + put_wifi_peer_info(pWifiPeerInfo, vendor_event)) { + hdd_err("put_wifi_peer_info fail"); + kfree_skb(vendor_event); + return; + } + + pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *) + pWifiPeerStat-> + peerInfo + + (i * + sizeof + (tSirWifiPeerInfo)) + + + (numRate * + sizeof + (tSirWifiRateStat))); + nla_nest_end(vendor_event, peers); + } + nla_nest_end(vendor_event, peerInfo); + } + + cfg80211_vendor_cmd_reply(vendor_event); + hdd_exit(); +} + +/** + * hdd_link_layer_process_iface_stats() - This function is called after + * @adapter: Pointer to device adapter + * @pData: 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 hdd_adapter *adapter, + tpSirWifiIfaceStat pData, + u32 num_peers) +{ + tpSirWifiIfaceStat pWifiIfaceStat; + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int status; + + hdd_enter(); + + pWifiIfaceStat = pData; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + /* + * Allocate a size of 4096 for the interface stats comprising + * sizeof (tpSirWifiIfaceStat).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. + */ + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + hdd_debug("WMI_LINK_STATS_IFACE Data"); + + if (false == hdd_get_interface_info(adapter, &pWifiIfaceStat->info)) { + hdd_err("hdd_get_interface_info get fail"); + kfree_skb(vendor_event); + return; + } + + if (false == + put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) { + hdd_err("put_wifi_iface_stats fail"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_cmd_reply(vendor_event); + hdd_exit(); +} + +/** + * 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, + tSirWifiRadioStat *radiostat, + struct sk_buff *vendor_event) +{ + tSirWifiChannelStats *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 == NULL) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < radiostat->numChannels; i++) { + channel_stats = (tSirWifiChannelStats *) ((uint8_t *) + radiostat->channels + + (i * sizeof(tSirWifiChannelStats))); + + chinfo = nla_nest_start(vendor_event, i); + if (chinfo == NULL) { + hdd_err("nla_nest_start failed"); + 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.centerFreq) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0, + channel_stats->channel.centerFreq0) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1, + channel_stats->channel.centerFreq1) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME, + channel_stats->onTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME, + channel_stats->ccaBusyTime)) { + hdd_err("nla_put failed"); + return -EINVAL; + } + nla_nest_end(vendor_event, chinfo); + } + nla_nest_end(vendor_event, chlist); + + return 0; +} + +/** + * 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: 0 on success; errno on failure + */ +static int hdd_llstats_post_radio_stats(struct hdd_adapter *adapter, + u32 more_data, + tSirWifiRadioStat *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 (tSirWifiRadioStat) + numChannels * sizeof + * (tSirWifiChannelStats).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 (tSirWifiChannelStats) being 24 bytes. + */ + + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb( + hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_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->onTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME, + radiostat->txTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME, + radiostat->rxTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN, + radiostat->onTimeScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD, + radiostat->onTimeNbd) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN, + radiostat->onTimeGscan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN, + radiostat->onTimeRoamScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN, + radiostat->onTimePnoScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20, + radiostat->onTimeHs20) || + 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->numChannels)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + goto failure; + } + + if (radiostat->total_num_tx_power_levels) { + if (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)) { + hdd_err("nla_put fail"); + goto failure; + } + } + + if (radiostat->numChannels) { + ret = hdd_llstats_radio_fill_channels(adapter, radiostat, + vendor_event); + if (ret) + goto failure; + } + + cfg80211_vendor_cmd_reply(vendor_event); + return 0; + +failure: + kfree_skb(vendor_event); + return -EINVAL; +} + +/** + * hdd_link_layer_process_radio_stats() - This function is called after + * @adapter: Pointer to device adapter + * @more_data: More data + * @pData: Pointer to stats data + * @num_radios: 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, + tpSirWifiRadioStat pData, + u32 num_radio) +{ + int status, i, nr, ret; + tSirWifiRadioStat *pWifiRadioStat = pData; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + hdd_debug("LL_STATS_RADIO: number of radios: %u", num_radio); + + for (i = 0; i < num_radio; i++) { + hdd_debug("LL_STATS_RADIO" + " radio: %u onTime: %u txTime: %u rxTime: %u" + " onTimeScan: %u onTimeNbd: %u" + " onTimeGscan: %u onTimeRoamScan: %u" + " onTimePnoScan: %u onTimeHs20: %u" + " numChannels: %u total_num_tx_pwr_levels: %u" + " on_time_host_scan: %u, on_time_lpi_scan: %u", + pWifiRadioStat->radio, pWifiRadioStat->onTime, + pWifiRadioStat->txTime, pWifiRadioStat->rxTime, + pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd, + pWifiRadioStat->onTimeGscan, + pWifiRadioStat->onTimeRoamScan, + pWifiRadioStat->onTimePnoScan, + pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels, + pWifiRadioStat->total_num_tx_power_levels, + pWifiRadioStat->on_time_host_scan, + pWifiRadioStat->on_time_lpi_scan); + pWifiRadioStat++; + } + + pWifiRadioStat = pData; + for (nr = 0; nr < num_radio; nr++) { + ret = hdd_llstats_post_radio_stats(adapter, more_data, + pWifiRadioStat, num_radio); + if (ret) + return; + + pWifiRadioStat++; + } + + hdd_exit(); +} + +/** + * hdd_ll_process_radio_stats() - Wrapper function for cfg80211/debugfs + * @adapter: Pointer to device adapter + * @more_data: More data + * @data: Pointer to stats data + * @num_radios: Number of radios + * @resp_id: Response ID from FW + * + * Receiving Link Layer Radio statistics from FW. This function is a wrapper + * function which calls cfg80211/debugfs functions based on the response ID. + * + * Return: None + */ +static void hdd_ll_process_radio_stats(struct hdd_adapter *adapter, + uint32_t more_data, void *data, uint32_t num_radio, + uint32_t resp_id) +{ + if (DEBUGFS_LLSTATS_REQID == resp_id) + hdd_debugfs_process_radio_stats(adapter, more_data, + (tpSirWifiRadioStat)data, num_radio); + else + hdd_link_layer_process_radio_stats(adapter, more_data, + (tpSirWifiRadioStat)data, num_radio); +} + +/** + * hdd_ll_process_iface_stats() - Wrapper function for cfg80211/debugfs + * @adapter: Pointer to device adapter + * @data: Pointer to stats data + * @num_peers: Number of peers + * @resp_id: Response ID from FW + * + * Receiving Link Layer Radio statistics from FW. This function is a wrapper + * function which calls cfg80211/debugfs functions based on the response ID. + * + * Return: None + */ +static void hdd_ll_process_iface_stats(struct hdd_adapter *adapter, + void *data, uint32_t num_peers, uint32_t resp_id) +{ + if (DEBUGFS_LLSTATS_REQID == resp_id) + hdd_debugfs_process_iface_stats(adapter, + (tpSirWifiIfaceStat) data, num_peers); + else + hdd_link_layer_process_iface_stats(adapter, + (tpSirWifiIfaceStat) data, num_peers); +} + +/** + * hdd_ll_process_peer_stats() - Wrapper function for cfg80211/debugfs + * @adapter: Pointer to device adapter + * @more_data: More data + * @data: Pointer to stats data + * @resp_id: Response ID from FW + * + * Receiving Link Layer Radio statistics from FW. This function is a wrapper + * function which calls cfg80211/debugfs functions based on the response ID. + * + * Return: None + */ +static void hdd_ll_process_peer_stats(struct hdd_adapter *adapter, + uint32_t more_data, void *data, uint32_t resp_id) +{ + if (DEBUGFS_LLSTATS_REQID == resp_id) + hdd_debugfs_process_peer_stats(adapter, data); + else + hdd_link_layer_process_peer_stats(adapter, more_data, + (tpSirWifiPeerStat) data); +} + +/** + * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called + * @ctx: Pointer to hdd context + * @indType: Indication type + * @pRsp: Pointer to response + * @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(void *ctx, int indType, + void *pRsp, void *cookie) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) ctx; + struct hdd_adapter *adapter = NULL; + struct hdd_ll_stats_priv *priv; + tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp; + int status; + struct osif_request *request; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, + linkLayerStatsResults->ifaceId); + + if (!adapter) { + hdd_err("vdev_id %d does not exist with host", + linkLayerStatsResults->ifaceId); + return; + } + + hdd_debug("Link Layer Indication indType: %d", indType); + + switch (indType) { + case SIR_HAL_LL_STATS_RESULTS_RSP: + { + hdd_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %pK", + linkLayerStatsResults->paramId, + linkLayerStatsResults->ifaceId, + linkLayerStatsResults->rspId, + linkLayerStatsResults->moreResultToFollow, + linkLayerStatsResults->num_radio, + linkLayerStatsResults->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 != linkLayerStatsResults->rspId) || + !(priv->request_bitmap & linkLayerStatsResults->paramId)) { + hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x", + priv->request_id, linkLayerStatsResults->rspId, + priv->request_bitmap, + linkLayerStatsResults->paramId); + osif_request_put(request); + return; + } + + if (linkLayerStatsResults->paramId & WMI_LINK_STATS_RADIO) { + hdd_ll_process_radio_stats(adapter, + linkLayerStatsResults->moreResultToFollow, + linkLayerStatsResults->results, + linkLayerStatsResults->num_radio, + linkLayerStatsResults->rspId); + + if (!linkLayerStatsResults->moreResultToFollow) + priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO); + + } else if (linkLayerStatsResults->paramId & + WMI_LINK_STATS_IFACE) { + hdd_ll_process_iface_stats(adapter, + linkLayerStatsResults->results, + linkLayerStatsResults->num_peers, + linkLayerStatsResults->rspId); + + /* 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 (!linkLayerStatsResults->num_peers) + priv->request_bitmap &= + ~(WMI_LINK_STATS_ALL_PEER); + priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE); + + } else if (linkLayerStatsResults-> + paramId & WMI_LINK_STATS_ALL_PEER) { + hdd_ll_process_peer_stats(adapter, + linkLayerStatsResults->moreResultToFollow, + linkLayerStatsResults->results, + linkLayerStatsResults->rspId); + + if (!linkLayerStatsResults->moreResultToFollow) + priv->request_bitmap &= + ~(WMI_LINK_STATS_ALL_PEER); + + } else { + hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); + } + + /* complete response event if all requests are completed */ + if (!priv->request_bitmap) + osif_request_complete(request); + + osif_request_put(request); + break; + } + default: + hdd_warn("invalid event type %d", indType); + 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 hdd_adapter *adapter; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + if (!lost_link_info) { + hdd_err("lost_link_info is NULL"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id); + if (!adapter) { + hdd_err("invalid adapter"); + return; + } + + adapter->rssi_on_disconnect = lost_link_info->rssi; + hdd_debug("rssi on disconnect %d", adapter->rssi_on_disconnect); +} + +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 LinkLayerStatsSetReq; + 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) { + 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. */ + LinkLayerStatsSetReq.reqId = 1; + + LinkLayerStatsSetReq.mpduSizeThreshold = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]); + + LinkLayerStatsSetReq.aggressiveStatisticsGathering = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]); + + LinkLayerStatsSetReq.staId = adapter->session_id; + + hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d", + LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId, + LinkLayerStatsSetReq.mpduSizeThreshold, + LinkLayerStatsSetReq.aggressiveStatisticsGathering); + + if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->mac_handle, + &LinkLayerStatsSetReq)) { + 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 int wlan_hdd_send_ll_stats_req(struct hdd_context *hdd_ctx, + tSirLLStatsGetReq *req) +{ + int ret; + struct hdd_ll_stats_priv *priv; + struct osif_request *request; + void *cookie; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_LL_STATS, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request Allocation Failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + + priv = osif_request_priv(request); + + priv->request_id = req->reqId; + priv->request_bitmap = req->paramIdMask; + + if (QDF_STATUS_SUCCESS != + sme_ll_stats_get_req(hdd_ctx->mac_handle, req, cookie)) { + hdd_err("sme_ll_stats_get_req Failed"); + ret = -EINVAL; + goto exit; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Target response timed out request id %d request bitmap 0x%x", + priv->request_id, priv->request_bitmap); + ret = -ETIMEDOUT; + goto exit; + } + hdd_exit(); + +exit: + osif_request_put(request); + return ret; +} + +int wlan_hdd_ll_stats_get(struct hdd_adapter *adapter, uint32_t req_id, + uint32_t req_mask) +{ + int errno; + tSirLLStatsGetReq get_req; + struct hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (hddstactx->hdd_reassoc_scenario) { + hdd_err("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 = adapter->session_id; + + rtnl_lock(); + errno = wlan_hdd_send_ll_stats_req(hdd_ctx, &get_req); + rtnl_unlock(); + if (errno) + hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d", + req_id, req_mask, adapter->session_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 hdd_station_ctx *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* ENTER() 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 (!adapter->is_link_layer_stats_set) { + hdd_warn("is_link_layer_stats_set: %d", + adapter->is_link_layer_stats_set); + return -EINVAL; + } + + if (hddstactx->hdd_reassoc_scenario) { + hdd_err("Roaming in progress, cannot 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 = adapter->session_id; + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + ret = wlan_hdd_send_ll_stats_req(hdd_ctx, &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) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +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->session_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 = 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"); + kfree_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 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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(tSirWifiPeerInfo *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->peerMacAddress)) { + 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(tSirWifiPeerStat *data, + struct sk_buff *vendor_event) +{ + uint32_t peer_num, i; + tSirWifiPeerInfo *wifi_peer_info; + struct nlattr *peer_info, *peers; + + if (!data) { + hdd_err("Invalid pointer to Wifi peer stat."); + return -EINVAL; + } + + peer_num = data->numPeers; + 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 == NULL) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < peer_num; i++) { + wifi_peer_info = &data->peerInfo[i]; + peers = nla_nest_start(vendor_event, i); + + if (peers == NULL) { + 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 == NULL || skb == NULL) + 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 + * @info: 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 + * @info: 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 + * @info: 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 + * @info: 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 + * @info: 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 + * @info: 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 + * @info: 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 = NULL; + uint32_t param_id, index; + struct hdd_adapter *adapter = NULL; + tSirLLStatsResults *linkLayer_stats_results; + tSirWifiPeerStat *peer_stats; + uint8_t *results; + int status; + + hdd_enter(); + + if (!rsp) { + hdd_err("Invalid result."); + return; + } + + hdd_ctx = hdd_handle_to_context(ctx); + linkLayer_stats_results = rsp; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, + linkLayer_stats_results->ifaceId); + + if (!adapter) { + hdd_err("vdev_id %d does not exist with host.", + linkLayer_stats_results->ifaceId); + return; + } + + index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX; + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, LL_STATS_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed."); + return; + } + + results = linkLayer_stats_results->results; + param_id = linkLayer_stats_results->paramId; + hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK", + linkLayer_stats_results->paramId, + linkLayer_stats_results->ifaceId, + linkLayer_stats_results->results); + if (param_id & WMI_LL_STATS_EXT_PS_CHG) { + peer_stats = (tSirWifiPeerStat *)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) + cfg80211_vendor_event(skb, GFP_KERNEL); + else + kfree_skb(skb); + hdd_exit(); +} + +static 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_EXT_GLOBAL] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = { + .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_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] = { + .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_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_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_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_ANT_SNR] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = { + .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/disbale 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->session_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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /* 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 + */ +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); + + 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; + } + + stats_ext_req.request_data_len = data_len; + stats_ext_req.request_data = (void *)data; + + status = sme_stats_ext_request(adapter->session_id, &stats_ext_req); + + if (QDF_STATUS_SUCCESS != 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback + * @ctx: Pointer to HDD context + * @msg: Message received + * + * Return: nothing + */ +void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, + tStatsExtEvent *msg) +{ + + struct hdd_context *hdd_ctx = (struct hdd_context *) ctx; + struct sk_buff *vendor_event; + int status; + int ret_val; + tStatsExtEvent *data = msg; + struct hdd_adapter *adapter = NULL; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, data->vdev_id); + + if (NULL == adapter) { + hdd_err("vdev_id %d does not exist with host", data->vdev_id); + return; + } + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + data->event_data_len + + sizeof(uint32_t) + + NLMSG_HDRLEN + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX, + adapter->dev->ifindex); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail"); + kfree_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"); + kfree_skb(vendor_event); + + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + +} + +void wlan_hdd_cfg80211_stats_ext2_callback(void *ctx, + struct sir_sme_rx_aggr_hole_ind *pmsg) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)ctx; + int status; + uint32_t data_size, hole_info_size; + struct sk_buff *vendor_event; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (NULL == 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 = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + data_size + NLMSG_HDRLEN + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_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"); + kfree_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"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +#endif /* End of WLAN_FEATURE_STATS_EXT */ + +#ifdef LINKSPEED_DEBUG_ENABLED +#define linkspeed_dbg(format, args...) pr_info(format, ## args) +#else +#define linkspeed_dbg(format, args...) +#endif /* LINKSPEED_DEBUG_ENABLED */ + +/** + * 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 + * + * Return: None + */ +static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats, + struct station_info *info) +{ + int i; + + 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]; + } + + info->filled |= HDD_INFO_TX_PACKETS | + HDD_INFO_TX_RETRIES | + HDD_INFO_TX_FAILED | + HDD_INFO_RX_PACKETS; +} + +/** + * wlan_hdd_get_sap_stats() - get aggregate SAP stats + * @adapter: sap adapter to get stats for + * @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 hdd_adapter *adapter, struct station_info *info) +{ + int ret; + + ret = wlan_hdd_get_station_stats(adapter); + if (ret) { + hdd_err("Failed to get SAP stats; status:%d", ret); + return ret; + } + + wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, info); + + 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 < mcsidx; i++) { + if (rssi <= rssi_mcs_tbl[mode][i]) { + mcsidx = i; + break; + } + } + if (mcsidx < stats->tx_rate.mcs) + mcsidx = stats->tx_rate.mcs; + } + + 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++) { + 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)) +/** + * hdd_fill_bw_mcs() - fill ch width and mcs flags + * @stainfo: stainfo pointer + * @rate_flags: HDD rate flags + * @mcsidx: mcs index + * @nss: number of streams + * @vht: vht mode or not + * + * This function will fill ch width and mcs flags + * + * Return: None + */ +static void hdd_fill_bw_mcs(struct station_info *sinfo, + uint8_t rate_flags, + uint8_t mcsidx, + uint8_t nss, + bool vht) +{ + if (vht) { + sinfo->txrate.nss = nss; + sinfo->txrate.mcs = mcsidx; + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + if (rate_flags & TX_RATE_VHT80) + sinfo->txrate.bw = RATE_INFO_BW_80; + else if (rate_flags & TX_RATE_VHT40) + sinfo->txrate.bw = RATE_INFO_BW_40; + else if (rate_flags & TX_RATE_VHT20) + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + } else { + sinfo->txrate.mcs = (nss - 1) << 3; + sinfo->txrate.mcs |= mcsidx; + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & TX_RATE_HT40) + sinfo->txrate.bw = RATE_INFO_BW_40; + } +} +#else +/** + * hdd_fill_bw_mcs() - fill ch width and mcs flags + * @stainfo: stainfo pointer + * @rate_flags: HDD rate flags + * @mcsidx: mcs index + * @nss: number of streams + * @vht: vht mode or not + * + * This function will fill ch width and mcs flags + * + * Return: None + */ +static void hdd_fill_bw_mcs(struct station_info *sinfo, + uint8_t rate_flags, + uint8_t mcsidx, + uint8_t nss, + bool vht) +{ + if (vht) { + sinfo->txrate.nss = nss; + sinfo->txrate.mcs = mcsidx; + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + if (rate_flags & TX_RATE_VHT80) + sinfo->txrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + else if (rate_flags & TX_RATE_VHT40) + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + else if (rate_flags & TX_RATE_VHT20) + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + } else { + sinfo->txrate.mcs = (nss - 1) << 3; + sinfo->txrate.mcs |= mcsidx; + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & TX_RATE_HT40) + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + } +} +#endif + +/** + * hdd_fill_bw_mcs_vht() - fill ch width and mcs flags for VHT mode + * @stainfo: stainfo pointer + * @rate_flags: HDD rate flags + * @mcsidx: mcs index + * @nss: number of streams + * + * This function will fill ch width and mcs flags for VHT mode + * + * Return: None + */ +static void hdd_fill_bw_mcs_vht(struct station_info *sinfo, + uint8_t rate_flags, + uint8_t mcsidx, + uint8_t nss) +{ + hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, true); +} + +/** + * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct + * @sinfo: station_info struct pointer + * @rate_flags: HDD rate flags + * @mcsidx: mcs index + * @nss: number of streams + * @maxrate: data rate (kbps) + * + * 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 maxrate) +{ + if (rate_flags & TX_RATE_LEGACY) { + /* provide to the UI in units of 100kbps */ + sinfo->txrate.legacy = maxrate; + } else { + /* must be MCS */ + if (rate_flags & + (TX_RATE_VHT80 | + TX_RATE_VHT40 | + TX_RATE_VHT20)) + hdd_fill_bw_mcs_vht(sinfo, rate_flags, mcsidx, nss); + + if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) + hdd_fill_bw_mcs(sinfo, rate_flags, mcsidx, nss, false); + + if (rate_flags & TX_RATE_SGI) { + if (!(sinfo->txrate.flags & RATE_INFO_FLAGS_VHT_MCS)) + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } + } + + hdd_info("flag %x mcs %d legacy %d nss %d", + sinfo->txrate.flags, + sinfo->txrate.mcs, + sinfo->txrate.legacy, + sinfo->txrate.nss); +} + +/** + * hdd_fill_station_info_flags() - fill flags of sinfo struct + * @sinfo: station_info struct pointer + * + * This function will fill flags of sinfo struct + * + * Return: None + */ +static void hdd_fill_station_info_flags(struct station_info *sinfo) +{ + sinfo->filled |= HDD_INFO_SIGNAL | + HDD_INFO_TX_BYTES | + HDD_INFO_TX_BYTES64 | + HDD_INFO_TX_BITRATE | + HDD_INFO_TX_PACKETS | + HDD_INFO_TX_RETRIES | + HDD_INFO_TX_FAILED | + HDD_INFO_RX_BYTES | + HDD_INFO_RX_BYTES64 | + HDD_INFO_RX_PACKETS | + HDD_INFO_INACTIVE_TIME | + HDD_INFO_CONNECTED_TIME; +} + +/** + * hdd_fill_rate_info() - fill rate info of sinfo + * @sinfo: station_info struct pointer + * @stainfo: stainfo pointer + * @stats: fw txrx status pointer + * @cfg: hdd config pointer + * + * This function will fill rate info of sinfo + * + * Return: None + */ +static void hdd_fill_rate_info(struct station_info *sinfo, + struct hdd_station_info *stainfo, + struct hdd_fw_txrx_stats *stats, + struct hdd_config *cfg) +{ + uint8_t rate_flags; + uint8_t mcsidx = 0xff; + uint32_t myrate, maxrate, tmprate; + int rssidx; + int nss = 1; + + hdd_info("reportMaxLinkSpeed %d", cfg->reportMaxLinkSpeed); + + /* convert to 100kbps expected in rate table */ + myrate = stats->tx_rate.rate / 100; + rate_flags = stainfo->rate_flags; + if (!(rate_flags & TX_RATE_LEGACY)) { + nss = stainfo->nss; + if (eHDD_LINK_SPEED_REPORT_ACTUAL == cfg->reportMaxLinkSpeed) { + /* 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 (eHDD_LINK_SPEED_REPORT_ACTUAL != cfg->reportMaxLinkSpeed) { + /* we do not want to necessarily report the current speed */ + if (eHDD_LINK_SPEED_REPORT_MAX == cfg->reportMaxLinkSpeed) { + /* report the max possible speed */ + rssidx = 0; + } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED == + cfg->reportMaxLinkSpeed) { + /* report the max possible speed with RSSI scaling */ + if (stats->rssi >= cfg->linkSpeedRssiHigh) { + /* report the max possible speed */ + rssidx = 0; + } else if (stats->rssi >= + cfg->linkSpeedRssiMid) { + /* report middle speed */ + rssidx = 1; + } else if (stats->rssi >= + cfg->linkSpeedRssiLow) { + /* report middle 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", + cfg->reportMaxLinkSpeed); + 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 = myrate; + mcsidx = stats->tx_rate.mcs; + } + + /* + * make sure we report a value at least as big as our + * current rate + */ + if ((maxrate < myrate) || (maxrate == 0)) { + maxrate = myrate; + 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 = myrate; + if (!(rate_flags & TX_RATE_LEGACY)) + mcsidx = stats->tx_rate.mcs; + } + + hdd_fill_sinfo_rate_info(sinfo, + rate_flags, + mcsidx, + nss, + maxrate); +} + +/** + * wlan_hdd_fill_station_info() - fill station_info struct + * @sinfo: station_info struct pointer + * @stainfo: stainfo pointer + * @stats: fw txrx status pointer + * @cfg: hdd config pointer + * + * This function will fill station_info struct + * + * Return: None + */ +static void wlan_hdd_fill_station_info(struct station_info *sinfo, + struct hdd_station_info *stainfo, + struct hdd_fw_txrx_stats *stats, + struct hdd_config *cfg) +{ + qdf_time_t curr_time, dur; + + curr_time = qdf_system_ticks(); + dur = curr_time - stainfo->assoc_ts; + sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000; + dur = curr_time - stainfo->last_tx_rx_ts; + sinfo->inactive_time = qdf_system_ticks_to_msecs(dur); + sinfo->signal = stats->rssi; + sinfo->tx_bytes = stats->tx_bytes; + sinfo->tx_packets = stats->tx_packets; + sinfo->rx_bytes = stats->rx_bytes; + sinfo->rx_packets = stats->rx_packets; + sinfo->tx_failed = stats->tx_failed; + sinfo->tx_retries = stats->tx_retries; + + /* tx rate info */ + hdd_fill_rate_info(sinfo, stainfo, stats, cfg); + + hdd_fill_station_info_flags(sinfo); + + /* dump sta info*/ + hdd_info("dump stainfo"); + hdd_info("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_info("failed %d retries %d tx_bytes %lld rx_bytes %lld", + sinfo->tx_failed, sinfo->tx_retries, + sinfo->tx_bytes, sinfo->rx_bytes); + hdd_info("rssi %d mcs %d legacy %d nss %d flags %x", + sinfo->signal, sinfo->txrate.mcs, + sinfo->txrate.legacy, sinfo->txrate.nss, + sinfo->txrate.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; + + 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_err("invalid mode param %d", mode); + + return flags; +} + +/** + * wlan_hdd_fill_rate_info() - fill HDD rate info from SIR peer info + * @ap_ctx: AP Context + * @peer_info: SIR peer info pointer + * + * This function is used to fill HDD rate info rom SIR peer info + * + * Return: None + */ +static void wlan_hdd_fill_rate_info(struct hdd_ap_ctx *ap_ctx, + struct sir_peer_info_ext *peer_info) +{ + uint8_t flags; + uint32_t rate_code; + + /* tx rate info */ + ap_ctx->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) + ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_HT; + else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) == + WMI_RATE_PREAMBLE_VHT) + ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_VHT; + else + ap_ctx->txrx_stats.tx_rate.mode = SIR_SME_PHY_MODE_LEGACY; + + ap_ctx->txrx_stats.tx_rate.nss = + WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1; + ap_ctx->txrx_stats.tx_rate.mcs = + WMI_GET_HW_RATECODE_RATE_V1(rate_code); + + flags = hdd_get_rate_flags(ap_ctx->txrx_stats.tx_rate.rate / 100, + ap_ctx->txrx_stats.tx_rate.mode, + ap_ctx->txrx_stats.tx_rate.nss, + ap_ctx->txrx_stats.tx_rate.mcs); + + ap_ctx->txrx_stats.tx_rate.rate_flags = flags; + + hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x", + ap_ctx->txrx_stats.tx_rate.mode, + ap_ctx->txrx_stats.tx_rate.nss, + ap_ctx->txrx_stats.tx_rate.mcs, + ap_ctx->txrx_stats.tx_rate.rate_flags, + flags); + + /* rx rate info */ + ap_ctx->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) + ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_HT; + else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) == + WMI_RATE_PREAMBLE_VHT) + ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_VHT; + else + ap_ctx->txrx_stats.rx_rate.mode = SIR_SME_PHY_MODE_LEGACY; + + ap_ctx->txrx_stats.rx_rate.nss = + WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1; + ap_ctx->txrx_stats.rx_rate.mcs = + WMI_GET_HW_RATECODE_RATE_V1(rate_code); + + flags = hdd_get_rate_flags(ap_ctx->txrx_stats.rx_rate.rate / 100, + ap_ctx->txrx_stats.rx_rate.mode, + ap_ctx->txrx_stats.rx_rate.nss, + ap_ctx->txrx_stats.rx_rate.mcs); + + ap_ctx->txrx_stats.rx_rate.rate_flags = flags; + + hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x", + ap_ctx->txrx_stats.rx_rate.mode, + ap_ctx->txrx_stats.rx_rate.nss, + ap_ctx->txrx_stats.rx_rate.mcs, + ap_ctx->txrx_stats.rx_rate.rate_flags, + flags); +} + +int wlan_hdd_get_station_remote(struct wiphy *wiphy, + struct net_device *dev, + const u8 *mac, + struct station_info *sinfo); + +/** + * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP + * @wiphy: pointer to wiphy + * @dev: pointer to net_device structure + * @mac: request peer mac address + * @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 + */ +int wlan_hdd_get_station_remote(struct wiphy *wiphy, + struct net_device *dev, + const u8 *mac, + struct station_info *sinfo) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hddctx = wiphy_priv(wiphy); + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + struct hdd_station_info *stainfo = NULL; + struct hdd_config *cfg; + struct qdf_mac_addr macaddr; + struct sir_peer_info_ext peer_info; + int status; + int i; + + status = wlan_hdd_validate_context(hddctx); + if (status != 0) + return status; + + cfg = hddctx->config; + + hdd_debug("get peer %pM info", mac); + + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (!qdf_mem_cmp(adapter->sta_info[i].sta_mac.bytes, + mac, + QDF_MAC_ADDR_SIZE)) { + stainfo = &adapter->sta_info[i]; + break; + } + } + + if (!stainfo) { + hdd_err("peer %pM not found", mac); + return -EINVAL; + } + + qdf_mem_copy(macaddr.bytes, mac, QDF_MAC_ADDR_SIZE); + status = wlan_hdd_get_peer_info(adapter, macaddr, &peer_info); + if (status) { + hdd_err("fail to get peer info from fw"); + return -EPERM; + } + + qdf_mem_zero(&ap_ctx->txrx_stats, sizeof(ap_ctx->txrx_stats)); + ap_ctx->txrx_stats.tx_packets = peer_info.tx_packets; + ap_ctx->txrx_stats.tx_bytes = peer_info.tx_bytes; + ap_ctx->txrx_stats.rx_packets = peer_info.rx_packets; + ap_ctx->txrx_stats.rx_bytes = peer_info.rx_bytes; + ap_ctx->txrx_stats.tx_retries = peer_info.tx_retries; + ap_ctx->txrx_stats.tx_failed = peer_info.tx_failed; + ap_ctx->txrx_stats.rssi = + peer_info.rssi + WLAN_HDD_TGT_NOISE_FLOOR_DBM; + wlan_hdd_fill_rate_info(ap_ctx, &peer_info); + + wlan_hdd_fill_station_info(sinfo, stainfo, &ap_ctx->txrx_stats, cfg); + + return status; +} + +/** + * hdd_report_max_rate() - Fill the max rate stats in the station info structure + * to be sent to the userspace. + * + * @mac_handle: The mac handle + * @config: The HDD config structure + * @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 + */ +static bool hdd_report_max_rate(mac_handle_t mac_handle, + struct hdd_config *config, + struct rate_info *rate, + int8_t signal, + uint8_t rate_flags, + uint8_t mcs_index, + uint16_t fw_rate, uint8_t nss) + +{ + uint8_t i, j, rssidx; + uint16_t max_rate = 0; + uint32_t vht_mcs_map; + uint16_t current_rate = 0; + uint32_t or_leng = CSR_DOT11_SUPPORTED_RATES_MAX; + uint8_t operational_rates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint8_t extended_rates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + uint32_t er_leng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX; + uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET]; + uint32_t mcs_leng = SIZE_OF_BASIC_MCS_SET; + struct index_vht_data_rate_type *supported_vht_mcs_rate; + struct index_data_rate_type *supported_mcs_rate; + enum data_rate_11ac_max_mcs vht_max_mcs; + uint8_t max_speed_mcs = 0; + uint8_t max_mcs_idx = 0; + uint8_t rate_flag = 1; + int mode = 0, max_ht_idx; + + /* we do not want to necessarily report the current speed */ + if (eHDD_LINK_SPEED_REPORT_MAX == config->reportMaxLinkSpeed) { + /* report the max possible speed */ + rssidx = 0; + } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED == + config->reportMaxLinkSpeed) { + /* report the max possible speed with RSSI scaling */ + if (signal >= config->linkSpeedRssiHigh) { + /* report the max possible speed */ + rssidx = 0; + } else if (signal >= config->linkSpeedRssiMid) { + /* report middle speed */ + rssidx = 1; + } else if (signal >= config->linkSpeedRssiLow) { + /* report middle 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", + config->reportMaxLinkSpeed); + rssidx = 0; + } + + max_rate = 0; + + /* Get Basic Rate Set */ + if (0 != sme_cfg_get_str(mac_handle, + WNI_CFG_OPERATIONAL_RATE_SET, + operational_rates, + &or_leng)) { + hdd_err("cfg get returned failure"); + /*To keep GUI happy */ + return false; + } + + 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 */ + if (0 != sme_cfg_get_str(mac_handle, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + extended_rates, &er_leng)) { + hdd_err("cfg get returned failure"); + /*To keep GUI happy */ + return false; + } + + 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)) { + if (0 != sme_cfg_get_str(mac_handle, + WNI_CFG_CURRENT_MCS_SET, mcs_rates, + &mcs_leng)) { + hdd_err("cfg get returned failure"); + /*To keep GUI happy */ + return false; + } + rate_flag = 0; + 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) || + (rate_flags & TX_RATE_HT40)) + mode = 1; + else + mode = 0; + + /* VHT80 rate has separate rate table */ + if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 | + TX_RATE_VHT80)) { + sme_cfg_get_int(mac_handle, + WNI_CFG_VHT_TX_MCS_MAP, + &vht_mcs_map); + 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 (!config->enable_vht20_mcs9 && + (rate_flags & TX_RATE_VHT20)) + max_mcs_idx = 8; + else + max_mcs_idx = 9; + } + + if (rssidx != 0) { + for (i = 0; i <= max_mcs_idx; i++) { + if (signal <= rssi_mcs_tbl[mode][i]) { + max_mcs_idx = i; + break; + } + } + } + + if (rate_flags & TX_RATE_VHT80) { + current_rate = + supported_vht_mcs_rate[mcs_index]. + supported_VHT80_rate[rate_flag]; + max_rate = + supported_vht_mcs_rate[max_mcs_idx]. + supported_VHT80_rate[rate_flag]; + } else if (rate_flags & TX_RATE_VHT40) { + current_rate = + supported_vht_mcs_rate[mcs_index]. + supported_VHT40_rate[rate_flag]; + max_rate = + supported_vht_mcs_rate[max_mcs_idx]. + supported_VHT40_rate[rate_flag]; + } else if (rate_flags & TX_RATE_VHT20) { + current_rate = + supported_vht_mcs_rate[mcs_index]. + supported_VHT20_rate[rate_flag]; + max_rate = + supported_vht_mcs_rate[max_mcs_idx]. + supported_VHT20_rate[rate_flag]; + } + + max_speed_mcs = 1; + if (current_rate > max_rate) + max_rate = current_rate; + + } else { + 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_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_leng; 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; + } + max_speed_mcs = 1; + } + if (nss == 2) + max_mcs_idx += MAX_HT_MCS_IDX; + } + } + + else if (!(rate_flags & TX_RATE_LEGACY)) { + max_rate = fw_rate; + max_speed_mcs = 1; + 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; + if (rate_flags & TX_RATE_LEGACY) { + max_speed_mcs = 0; + } else { + max_speed_mcs = 1; + max_mcs_idx = mcs_index; + } + } + + if (rate_flags & TX_RATE_LEGACY) { + rate->legacy = max_rate; + + hdd_info("Reporting legacy rate %d", rate->legacy); + } else { + rate->mcs = max_mcs_idx; + rate->nss = nss; + if (rate_flags & TX_RATE_VHT80) + hdd_set_rate_bw(rate, HDD_RATE_BW_80); + else if (rate_flags & TX_RATE_VHT40) + hdd_set_rate_bw(rate, HDD_RATE_BW_40); + else if (rate_flags & TX_RATE_VHT20) + hdd_set_rate_bw(rate, HDD_RATE_BW_20); + + if (rate_flags & + (TX_RATE_HT20 | TX_RATE_HT40)) { + rate->flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & TX_RATE_HT40) + hdd_set_rate_bw(rate, + HDD_RATE_BW_40); + else if (rate_flags & TX_RATE_HT20) + hdd_set_rate_bw(rate, + HDD_RATE_BW_20); + } else { + rate->flags |= RATE_INFO_FLAGS_VHT_MCS; + } + + if (rate_flags & TX_RATE_SGI) { + if (!(rate->flags & RATE_INFO_FLAGS_VHT_MCS)) + rate->flags |= RATE_INFO_FLAGS_MCS; + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + } + linkspeed_dbg("Reporting MCS rate %d flags %x\n", + rate->mcs, rate->flags); + } + + 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 strust rate_info to be filled + * @mcs_index; The mcs index computed from rate + * @nss: The NSS from fw stats + * + * Return: None + */ +static void hdd_report_actual_rate(uint8_t rate_flags, uint16_t my_rate, + struct rate_info *rate, uint8_t mcs_index, + uint8_t nss) +{ + /* report current rate instead of max rate */ + + if (rate_flags & TX_RATE_LEGACY) { + /* provide to the UI in units of 100kbps */ + rate->legacy = my_rate; + linkspeed_dbg("Reporting actual legacy rate %d", + rate->legacy); + } else { + /* must be MCS */ + rate->mcs = mcs_index; + rate->nss = nss; + + if (rate_flags & TX_RATE_VHT80) + hdd_set_rate_bw(rate, HDD_RATE_BW_80); + else if (rate_flags & TX_RATE_VHT40) + hdd_set_rate_bw(rate, HDD_RATE_BW_40); + + if (rate_flags & + (TX_RATE_HT20 | TX_RATE_HT40)) { + rate->flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & TX_RATE_HT40) + hdd_set_rate_bw(rate, HDD_RATE_BW_40); + } else { + rate->flags |= RATE_INFO_FLAGS_VHT_MCS; + } + + if (rate_flags & TX_RATE_SGI) { + rate->flags |= RATE_INFO_FLAGS_SHORT_GI; + } + + linkspeed_dbg("Reporting actual MCS rate %d flags %x\n", + rate->mcs, rate->flags); + } +} + +/** + * hdd_wlan_fill_per_chain_rssi_stats() - Fill per chain rssi stats + * + * @sinfo: The station_info structure to be filled. + * @adapter: The HDD adapter structure + * + * Return: None + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +static inline +void hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo, + struct hdd_adapter *adapter) +{ + 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] = + adapter->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, adapter->session_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 hdd_adapter *adapter) +{ +} + +#endif + +#if defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT) +static void hdd_fill_fcs_and_mpdu_count(struct hdd_adapter *adapter, + struct station_info *sinfo) +{ + sinfo->rx_mpdu_count = adapter->hdd_stats.peer_stats.rx_count; + sinfo->fcs_err_count = adapter->hdd_stats.peer_stats.fcs_count; + hdd_debug("RX mpdu count %d fcs_err_count %d", + sinfo->rx_mpdu_count, sinfo->fcs_err_count); +} +#else +static void hdd_fill_fcs_and_mpdu_count(struct hdd_adapter *adapter, + struct station_info *sinfo) +{ +} +#endif + +/** + * wlan_hdd_get_sta_stats() - get aggregate STA stats + * @wiphy: wireless phy + * @adapter: 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 wiphy *wiphy, + struct hdd_adapter *adapter, + const uint8_t *mac, + struct station_info *sinfo) +{ + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + uint8_t rate_flags, tx_rate_flags, rx_rate_flags; + uint8_t tx_mcs_index, rx_mcs_index; + struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy); + struct hdd_config *pCfg = hdd_ctx->config; + mac_handle_t mac_handle; + int8_t snr = 0; + uint16_t my_tx_rate, my_rx_rate; + uint8_t tx_nss = 1, rx_nss = 1; + int32_t rcpi_value; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_STA, + adapter->session_id, 0); + + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + hdd_debug("Not associated"); + /*To keep GUI happy */ + return 0; + } + + if (sta_ctx->hdd_reassoc_scenario) { + hdd_debug("Roaming 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 = adapter->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(adapter); + + adapter->rssi = adapter->hdd_stats.summary_stat.rssi; + snr = adapter->hdd_stats.summary_stat.snr; + + /* for new connection there might be no valid previous RSSI */ + if (!adapter->rssi) { + hdd_get_rssi_snr_by_bssid(adapter, + sta_ctx->conn_info.bssId.bytes, + &adapter->rssi, &snr); + } + + sinfo->signal = adapter->rssi; + hdd_debug("snr: %d, rssi: %d", + adapter->hdd_stats.summary_stat.snr, + adapter->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; + + /* + * 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(adapter); + + rate_flags = adapter->hdd_stats.class_a_stat.tx_rx_rate_flags; + tx_rate_flags = rx_rate_flags = rate_flags; + + tx_mcs_index = adapter->hdd_stats.class_a_stat.tx_mcs_index; + rx_mcs_index = adapter->hdd_stats.class_a_stat.rx_mcs_index; + mac_handle = hdd_ctx->mac_handle; + + /* convert to the UI units of 100kbps */ + my_tx_rate = adapter->hdd_stats.class_a_stat.tx_rate; + my_rx_rate = adapter->hdd_stats.class_a_stat.rx_rate; + + if (!(rate_flags & TX_RATE_LEGACY)) { + tx_nss = adapter->hdd_stats.class_a_stat.tx_nss; + rx_nss = adapter->hdd_stats.class_a_stat.rx_nss; + + if ((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 nss(%d) to 1", + tx_nss); + tx_nss--; + } + + if ((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 nss(%d) to 1", + rx_nss); + rx_nss--; + } + + if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) { + /* 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 = + adapter->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 = + adapter->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", + sinfo->signal, pCfg->reportMaxLinkSpeed, + (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid, + (int)pCfg->linkSpeedRssiLow); + hdd_debug("Rate info: TX: %d, RX: %d", my_tx_rate, my_rx_rate); + hdd_debug("Rate flags: TX: 0x%x, RX: 0x%x", (int)tx_rate_flags, + (int)rx_rate_flags); + hdd_debug("MCS Index: TX: %d, RX: %d", (int)tx_mcs_index, + (int)rx_mcs_index); + hdd_debug("NSS: TX: %d, RX: %d", (int)tx_nss, (int)rx_nss); + + /* assume basic BW. anything else will override this later */ + hdd_set_rate_bw(&sinfo->txrate, HDD_RATE_BW_20); + + if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) { + bool tx_rate_calc; + bool rx_rate_calc; + + tx_rate_calc = hdd_report_max_rate(mac_handle, pCfg, + &sinfo->txrate, + sinfo->signal, + tx_rate_flags, + tx_mcs_index, + my_tx_rate, + tx_nss); + + rx_rate_calc = hdd_report_max_rate(mac_handle, pCfg, + &sinfo->rxrate, + sinfo->signal, + rx_rate_flags, + rx_mcs_index, + my_rx_rate, + rx_nss); + + if (!tx_rate_calc || !rx_rate_calc) + /* Keep GUI happy */ + return 0; + } else { + + /* Fill TX stats */ + hdd_report_actual_rate(tx_rate_flags, my_tx_rate, + &sinfo->txrate, tx_mcs_index, tx_nss); + + /* Fill RX stats */ + hdd_report_actual_rate(rx_rate_flags, my_rx_rate, + &sinfo->rxrate, rx_mcs_index, rx_nss); + } + + wlan_hdd_fill_summary_stats(&adapter->hdd_stats.summary_stat, sinfo); + sinfo->tx_bytes = adapter->stats.tx_bytes; + sinfo->rx_bytes = adapter->stats.rx_bytes; + sinfo->rx_packets = adapter->stats.rx_packets; + + hdd_fill_fcs_and_mpdu_count(adapter, sinfo); + + 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("Reporting legacy rate %d pkt cnt tx %d rx %d", + sinfo->txrate.legacy, sinfo->tx_packets, + sinfo->rx_packets); + else + hdd_debug("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d", + sinfo->txrate.mcs, sinfo->txrate.flags, + sinfo->tx_packets, sinfo->rx_packets); + + hdd_wlan_fill_per_chain_rssi_stats(sinfo, adapter); + + hdd_exit(); + + return 0; +} + +/** + * __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 status; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy); + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + if (adapter->device_mode == QDF_SAP_MODE) + return wlan_hdd_get_sap_stats(adapter, sinfo); + else + return wlan_hdd_get_sta_stats(wiphy, adapter, 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 + */ +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + struct station_info *sinfo) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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 + */ +static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo) +{ + hdd_debug("%s: idx %d", __func__, idx); + if (idx != 0) + return -ENOENT; + qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE); + return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * 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) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_enter_dev(dev); + return &adapter->stats; +} + + +/* + * time = cycle_count * cycle + * cycle = 1 / clock_freq + * Since the unit of clock_freq reported from + * FW is MHZ, and we want to calculate time in + * ms level, the result is + * time = cycle / (clock_freq * 1000) + */ +#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) +{ + uint64_t clock_freq = chan_info->clock_freq * 1000; + + if (channels->center_freq != (uint16_t)chan_info->freq) + return false; + + survey->channel = channels; + survey->noise = chan_info->noise_floor; + survey->filled = SURVEY_INFO_NOISE_DBM; + + if (opfreq == chan_info->freq) + survey->filled |= SURVEY_INFO_IN_USE; + + if (clock_freq == 0) + return true; + + survey->time = qdf_do_div(chan_info->cycle_count, clock_freq); + + survey->time_busy = qdf_do_div(chan_info->rx_clear_count, clock_freq); + + survey->time_tx = qdf_do_div(chan_info->tx_frame_count, clock_freq); + + 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) +{ + uint64_t clock_freq = chan_info->clock_freq * 1000; + + if (channels->center_freq != (uint16_t)chan_info->freq) + return false; + + survey->channel = channels; + survey->noise = chan_info->noise_floor; + survey->filled = SURVEY_INFO_NOISE_DBM; + + if (opfreq == chan_info->freq) + survey->filled |= SURVEY_INFO_IN_USE; + + if (clock_freq == 0) + return true; + + survey->channel_time = qdf_do_div(chan_info->cycle_count, clock_freq); + + survey->channel_time_busy = qdf_do_div(chan_info->rx_clear_count, + clock_freq); + + survey->channel_time_tx = qdf_do_div(chan_info->tx_frame_count, + clock_freq); + + 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 channel = 0, opfreq; /* Initialization Required */ + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + sme_get_operation_channel(hdd_ctx->mac_handle, &channel, + adapter->session_id); + opfreq = wlan_reg_chan_to_freq(hdd_ctx->pdev, channel); + + mutex_lock(&hdd_ctx->chan_info_lock); + + for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) { + if (wiphy->bands[i] == NULL) + 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; + struct hdd_station_ctx *sta_ctx; + int status; + bool filled = false; + + hdd_enter_dev(dev); + + hdd_debug("dump survey index: %d", idx); + if (idx > QDF_MAX_NUM_CHAN - 1) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (hdd_ctx->chan_info == NULL) { + 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; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (hdd_ctx->config->fEnableSNRMonitoring == 0) + return -ENONET; + + if (sta_ctx->hdd_reassoc_scenario) { + hdd_info("Roaming in progress, hence return"); + return -ENONET; + } + + filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx); + + if (!filled) + return -ENONET; + hdd_exit(); + 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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); + if (hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) + return false; + + if (hdd_sta_ctx->hdd_reassoc_scenario) { + /* 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->event_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 + * @rcpi_req: Pointer to rcpi response + * + * 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 + */ +static 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) { + hdd_err("unable to allocate memory for 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->session_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; +} + +int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac, + int32_t *rcpi_value, + enum rcpi_measurement_type measurement_type) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_get_rcpi(adapter, mac, rcpi_value, measurement_type); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef QCA_SUPPORT_CP_STATS +QDF_STATUS wlan_hdd_get_rssi(struct hdd_adapter *adapter, int8_t *rssi_value) +{ + int ret = 0, i; + struct hdd_station_ctx *sta_ctx; + struct stats_event *rssi_info; + + if (NULL == adapter) { + hdd_err("Invalid context, adapter"); + return QDF_STATUS_E_FAULT; + } + 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 = adapter->rssi; + return QDF_STATUS_SUCCESS; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + hdd_debug("Not associated!, rssi on disconnect %d", + adapter->rssi_on_disconnect); + *rssi_value = adapter->rssi_on_disconnect; + return QDF_STATUS_SUCCESS; + } + + if (sta_ctx->hdd_reassoc_scenario) { + hdd_debug("Roaming in progress, return cached RSSI"); + *rssi_value = adapter->rssi; + return QDF_STATUS_SUCCESS; + } + + rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi( + adapter->vdev, + sta_ctx->conn_info.bssId.bytes, + &ret); + 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, + WLAN_MACADDR_LEN)) { + *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; +} +#else /* QCA_SUPPORT_CP_STATS */ +struct rssi_priv { + int8_t rssi; +}; + +/** + * hdd_get_rssi_cb() - "Get RSSI" callback function + * @rssi: Current RSSI of the station + * @sta_id: ID 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_rssi_cb(int8_t rssi, uint32_t sta_id, void *context) +{ + struct osif_request *request; + struct rssi_priv *priv; + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->rssi = rssi; + osif_request_complete(request); + osif_request_put(request); +} + +QDF_STATUS wlan_hdd_get_rssi(struct hdd_adapter *adapter, int8_t *rssi_value) +{ + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *sta_ctx; + QDF_STATUS status; + int ret; + void *cookie; + struct osif_request *request; + struct rssi_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (NULL == adapter) { + hdd_err("Invalid context, adapter"); + return QDF_STATUS_E_FAULT; + } + 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 = adapter->rssi; + return QDF_STATUS_SUCCESS; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + hdd_debug("Not associated!, rssi on disconnect %d", + adapter->rssi_on_disconnect); + *rssi_value = adapter->rssi_on_disconnect; + return QDF_STATUS_SUCCESS; + } + + if (sta_ctx->hdd_reassoc_scenario) { + hdd_debug("Roaming in progress, return cached RSSI"); + *rssi_value = adapter->rssi; + return QDF_STATUS_SUCCESS; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure, return cached RSSI"); + *rssi_value = adapter->rssi; + return QDF_STATUS_SUCCESS; + } + cookie = osif_request_cookie(request); + + status = sme_get_rssi(hdd_ctx->mac_handle, hdd_get_rssi_cb, + sta_ctx->conn_info.staId[0], + sta_ctx->conn_info.bssId, adapter->rssi, + 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_warn("SME timed out while retrieving RSSI"); + /* we'll returned a cached value below */ + } else { + /* update the adapter with the fresh results */ + priv = osif_request_priv(request); + + adapter->rssi = priv->rssi; + + /* + * for new connection there might be no valid previous + * RSSI. + */ + if (!adapter->rssi) { + hdd_get_rssi_snr_by_bssid(adapter, + sta_ctx->conn_info.bssId.bytes, + &adapter->rssi, 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. + */ + osif_request_put(request); + + *rssi_value = adapter->rssi; + hdd_debug("RSSI = %d", *rssi_value); + + return QDF_STATUS_SUCCESS; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +struct snr_priv { + int8_t snr; +}; + +/** + * hdd_get_snr_cb() - "Get SNR" callback function + * @snr: Current SNR of the station + * @sta_id: ID 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, uint32_t sta_id, 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 hdd_adapter *adapter, int8_t *snr) +{ + struct hdd_context *hdd_ctx; + 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(); + + if (NULL == adapter) { + hdd_err("Invalid context, adapter"); + return QDF_STATUS_E_FAULT; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return QDF_STATUS_E_FAULT; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + 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.staId[0], + 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); + adapter->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 = adapter->snr; + hdd_exit(); + return QDF_STATUS_SUCCESS; +} + +struct linkspeed_priv { + tSirLinkSpeedInfo linkspeed_info; +}; + +static void +hdd_get_link_speed_cb(tSirLinkSpeedInfo *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 hdd_adapter *adapter, + struct qdf_mac_addr *mac_address, + uint32_t *linkspeed) +{ + int ret; + QDF_STATUS status; + void *cookie; + tSirLinkSpeedInfo *linkspeed_info; + struct osif_request *request; + struct linkspeed_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if ((!adapter) || (!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; + } + adapter->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 = adapter->estimated_linkspeed; + + return ret; +} + +int wlan_hdd_get_link_speed(struct hdd_adapter *adapter, uint32_t *link_speed) +{ + struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *hdd_stactx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + int ret; + + ret = wlan_hdd_validate_context(hddctx); + if (ret) + return ret; + + /* Linkspeed is allowed only for P2P mode */ + if (adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_err("Link Speed is not allowed in Device mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -ENOTSUPP; + } + + if (eConnectionState_Associated != hdd_stactx->conn_info.connState) { + /* we are not connected so we don't have a classAstats */ + *link_speed = 0; + } else { + struct qdf_mac_addr bssid; + + qdf_copy_macaddr(&bssid, &hdd_stactx->conn_info.bssId); + + ret = wlan_hdd_get_linkspeed_for_peermac(adapter, &bssid, + link_speed); + if (ret) { + hdd_err("Unable to retrieve SME linkspeed"); + return ret; + } + /* linkspeed in units of 500 kbps */ + *link_speed = (*link_speed) / 500; + } + return 0; +} + +struct peer_rssi_priv { + struct sir_peer_sta_info peer_sta_info; +}; + +/** + * hdd_get_peer_rssi_cb() - get peer station's rssi callback + * @sta_rssi: pointer of peer information + * @context: get rssi callback context + * + * This function will fill rssi information to rssi priv + * adapter + * + */ +static void hdd_get_peer_rssi_cb(struct sir_peer_info_resp *sta_rssi, + void *context) +{ + struct osif_request *request; + struct peer_rssi_priv *priv; + struct sir_peer_info *rssi_info; + uint8_t peer_num; + + if ((!sta_rssi)) { + hdd_err("Bad param, sta_rssi [%pK]", sta_rssi); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + peer_num = sta_rssi->count; + rssi_info = sta_rssi->info; + + hdd_debug("%d peers", peer_num); + + if (peer_num > MAX_PEER_STA) { + hdd_warn("Exceed max peer sta to handle one time %d", peer_num); + peer_num = MAX_PEER_STA; + } + + qdf_mem_copy(priv->peer_sta_info.info, rssi_info, + peer_num * sizeof(*rssi_info)); + priv->peer_sta_info.sta_num = peer_num; + + osif_request_complete(request); + osif_request_put(request); + +} + +int wlan_hdd_get_peer_rssi(struct hdd_adapter *adapter, + struct qdf_mac_addr *macaddress, + struct sir_peer_sta_info *peer_sta_info) +{ + QDF_STATUS status; + void *cookie; + int ret; + struct sir_peer_info_req rssi_req; + struct osif_request *request; + struct peer_rssi_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (!adapter || !macaddress || !peer_sta_info) { + hdd_err("adapter [%pK], macaddress [%pK], peer_sta_info[%pK]", + adapter, macaddress, peer_sta_info); + return -EFAULT; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + + qdf_mem_copy(&rssi_req.peer_macaddr, macaddress, + QDF_MAC_ADDR_SIZE); + rssi_req.sessionid = adapter->session_id; + status = sme_get_peer_info(adapter->hdd_ctx->mac_handle, + rssi_req, + cookie, + hdd_get_peer_rssi_cb); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Unable to retrieve statistics for rssi"); + ret = -EFAULT; + } else { + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving rssi"); + ret = -EFAULT; + } else { + *peer_sta_info = priv->peer_sta_info; + ret = 0; + } + } + + osif_request_put(request); + + return ret; +} + +struct peer_info_priv { + struct sir_peer_sta_ext_info peer_sta_ext_info; +}; + +/** + * wlan_hdd_get_peer_info_cb() - get peer info callback + * @sta_info: pointer of peer information + * @context: get peer info callback context + * + * This function will fill stats info to peer info priv + * + */ +static void wlan_hdd_get_peer_info_cb(struct sir_peer_info_ext_resp *sta_info, + void *context) +{ + struct osif_request *request; + struct peer_info_priv *priv; + uint8_t sta_num; + + if ((!sta_info) || (!context)) { + hdd_err("Bad param, sta_info [%pK] context [%pK]", + sta_info, context); + return; + } + + if (!sta_info->count) { + hdd_err("Fail to get remote peer info"); + return; + } + + if (sta_info->count > MAX_PEER_STA) { + hdd_warn("Exceed max peer number %d", sta_info->count); + sta_num = MAX_PEER_STA; + } else { + sta_num = sta_info->count; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + priv->peer_sta_ext_info.sta_num = sta_num; + qdf_mem_copy(&priv->peer_sta_ext_info.info, + sta_info->info, + sta_num * sizeof(sta_info->info[0])); + + osif_request_complete(request); + osif_request_put(request); +} + +int wlan_hdd_get_peer_info(struct hdd_adapter *adapter, + struct qdf_mac_addr macaddress, + struct sir_peer_info_ext *peer_info_ext) +{ + QDF_STATUS status; + void *cookie; + int ret; + struct sir_peer_info_ext_req peer_info_req; + struct osif_request *request; + struct peer_info_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 -EFAULT; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + + qdf_mem_copy(&peer_info_req.peer_macaddr, &macaddress, + QDF_MAC_ADDR_SIZE); + peer_info_req.sessionid = adapter->session_id; + peer_info_req.reset_after_request = 0; + status = sme_get_peer_info_ext(adapter->hdd_ctx->mac_handle, + &peer_info_req, + cookie, + wlan_hdd_get_peer_info_cb); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Unable to retrieve statistics for peer info"); + ret = -EFAULT; + } else { + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving peer info"); + ret = -EFAULT; + } else { + /* only support one peer by now */ + *peer_info_ext = priv->peer_sta_ext_info.info[0]; + ret = 0; + } + } + + osif_request_put(request); + + return ret; +} + +#ifndef QCA_SUPPORT_CP_STATS +struct class_a_stats { + tCsrGlobalClassAStatsInfo class_a_stats; +}; + +/** + * hdd_get_class_a_statistics_cb() - Get Class A stats callback function + * @stats: pointer to Class A stats + * @context: user context originally registered with SME (always the + * cookie from the request context) + * + * Return: None + */ +static void hdd_get_class_a_statistics_cb(void *stats, void *context) +{ + struct osif_request *request; + struct class_a_stats *priv; + tCsrGlobalClassAStatsInfo *returned_stats; + + hdd_enter(); + if (NULL == stats) { + hdd_err("Bad param, stats"); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + returned_stats = stats; + priv = osif_request_priv(request); + priv->class_a_stats = *returned_stats; + osif_request_complete(request); + osif_request_put(request); + hdd_exit(); +} + +QDF_STATUS wlan_hdd_get_class_astats(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + QDF_STATUS status; + int ret; + void *cookie; + struct osif_request *request; + struct class_a_stats *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (NULL == adapter) { + hdd_err("adapter is NULL"); + return QDF_STATUS_E_FAULT; + } + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_debug("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + 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); + + /* query only for Class A statistics (which include link speed) */ + status = sme_get_statistics(adapter->hdd_ctx->mac_handle, + eCSR_HDD, SME_GLOBAL_CLASSA_STATS, + hdd_get_class_a_statistics_cb, + sta_ctx->conn_info.staId[0], + cookie, adapter->session_id); + if (QDF_STATUS_SUCCESS != status) { + hdd_warn("Unable to retrieve Class A statistics"); + goto return_cached_results; + } + + /* request was sent -- wait for the response */ + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_warn("SME timed out while retrieving Class A statistics"); + goto return_cached_results; + } + + /* update the adapter with the fresh results */ + priv = osif_request_priv(request); + adapter->hdd_stats.class_a_stat = priv->class_a_stats; + +return_cached_results: + /* + * 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 QDF_STATUS_SUCCESS; +} +#endif + +#ifdef QCA_SUPPORT_CP_STATS +int wlan_hdd_get_station_stats(struct hdd_adapter *adapter) +{ + int ret = 0; + uint8_t mcs_rate_flags; + struct stats_event *stats; + + stats = wlan_cfg80211_mc_cp_stats_get_station_stats(adapter->vdev, + &ret); + if (ret || !stats) { + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + return ret; + } + + /* save summary stats to legacy location */ + qdf_mem_copy(adapter->hdd_stats.summary_stat.retry_cnt, + stats->vdev_summary_stats[0].stats.retry_cnt, + sizeof(adapter->hdd_stats.summary_stat.retry_cnt)); + qdf_mem_copy(adapter->hdd_stats.summary_stat.multiple_retry_cnt, + stats->vdev_summary_stats[0].stats.multiple_retry_cnt, + sizeof(adapter->hdd_stats.summary_stat.multiple_retry_cnt)); + qdf_mem_copy(adapter->hdd_stats.summary_stat.tx_frm_cnt, + stats->vdev_summary_stats[0].stats.tx_frm_cnt, + sizeof(adapter->hdd_stats.summary_stat.tx_frm_cnt)); + qdf_mem_copy(adapter->hdd_stats.summary_stat.fail_cnt, + stats->vdev_summary_stats[0].stats.fail_cnt, + sizeof(adapter->hdd_stats.summary_stat.fail_cnt)); + adapter->hdd_stats.summary_stat.snr = + stats->vdev_summary_stats[0].stats.snr; + adapter->hdd_stats.summary_stat.rssi = + stats->vdev_summary_stats[0].stats.rssi; + adapter->hdd_stats.summary_stat.rx_frm_cnt = + stats->vdev_summary_stats[0].stats.rx_frm_cnt; + adapter->hdd_stats.summary_stat.frm_dup_cnt = + stats->vdev_summary_stats[0].stats.frm_dup_cnt; + adapter->hdd_stats.summary_stat.rts_fail_cnt = + stats->vdev_summary_stats[0].stats.rts_fail_cnt; + adapter->hdd_stats.summary_stat.ack_fail_cnt = + stats->vdev_summary_stats[0].stats.ack_fail_cnt; + adapter->hdd_stats.summary_stat.rts_succ_cnt = + stats->vdev_summary_stats[0].stats.rts_succ_cnt; + adapter->hdd_stats.summary_stat.rx_discard_cnt = + stats->vdev_summary_stats[0].stats.rx_discard_cnt; + adapter->hdd_stats.summary_stat.rx_error_cnt = + stats->vdev_summary_stats[0].stats.rx_error_cnt; + adapter->hdd_stats.peer_stats.rx_count = + stats->peer_adv_stats->rx_count; + adapter->hdd_stats.peer_stats.rx_bytes = + stats->peer_adv_stats->rx_bytes; + adapter->hdd_stats.peer_stats.fcs_count = + stats->peer_adv_stats->fcs_count; + + /* save class a stats to legacy location */ + adapter->hdd_stats.class_a_stat.tx_nss = + wlan_vdev_mlme_get_nss(adapter->vdev); + adapter->hdd_stats.class_a_stat.rx_nss = + wlan_vdev_mlme_get_nss(adapter->vdev); + adapter->hdd_stats.class_a_stat.tx_rate = stats->tx_rate; + adapter->hdd_stats.class_a_stat.rx_rate = stats->rx_rate; + adapter->hdd_stats.class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags; + adapter->hdd_stats.class_a_stat.tx_mcs_index = + sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags, + &adapter->hdd_stats.class_a_stat.tx_nss, + &mcs_rate_flags); + adapter->hdd_stats.class_a_stat.tx_mcs_rate_flags = mcs_rate_flags; + adapter->hdd_stats.class_a_stat.rx_mcs_index = + sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags, + &adapter->hdd_stats.class_a_stat.rx_nss, + &mcs_rate_flags); + adapter->hdd_stats.class_a_stat.rx_mcs_rate_flags = mcs_rate_flags; + + /* save per chain rssi to legacy location */ + qdf_mem_copy(adapter->hdd_stats.per_chain_rssi_stats.rssi, + stats->vdev_chain_rssi[0].chain_rssi, + sizeof(stats->vdev_chain_rssi[0].chain_rssi)); + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + + return 0; +} +#else /* QCA_SUPPORT_CP_STATS */ +struct station_stats { + tCsrSummaryStatsInfo summary_stats; + tCsrGlobalClassAStatsInfo class_a_stats; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; +}; + +/** + * hdd_get_station_statistics_cb() - Get stats callback function + * @stats: pointer to combined station stats + * @context: user context originally registered with SME (always the + * cookie from the request context) + * + * Return: None + */ +static void hdd_get_station_statistics_cb(void *stats, void *context) +{ + struct osif_request *request; + struct station_stats *priv; + tCsrSummaryStatsInfo *summary_stats; + tCsrGlobalClassAStatsInfo *class_a_stats; + struct csr_per_chain_rssi_stats_info *per_chain_rssi_stats; + + if ((NULL == stats) || (NULL == context)) { + hdd_err("Bad param, pStats [%pK] pContext [%pK]", + stats, context); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + summary_stats = (tCsrSummaryStatsInfo *) stats; + class_a_stats = (tCsrGlobalClassAStatsInfo *) (summary_stats + 1); + per_chain_rssi_stats = (struct csr_per_chain_rssi_stats_info *) + (class_a_stats + 1); + priv = osif_request_priv(request); + + /* copy over the stats. do so as a struct copy */ + priv->summary_stats = *summary_stats; + priv->class_a_stats = *class_a_stats; + priv->per_chain_rssi_stats = *per_chain_rssi_stats; + + osif_request_complete(request); + osif_request_put(request); +} + +int wlan_hdd_get_station_stats(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + QDF_STATUS status; + int errno; + void *cookie; + struct osif_request *request; + struct station_stats *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (NULL == adapter) { + hdd_err("adapter is NULL"); + return 0; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + /* query only for Summary & Class A statistics */ + status = sme_get_statistics(adapter->hdd_ctx->mac_handle, + eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_PER_CHAIN_RSSI_STATS, + hdd_get_station_statistics_cb, + sta_ctx->conn_info.staId[0], + cookie, + adapter->session_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to retrieve statistics, status %d", status); + goto put_request; + } + + /* request was sent -- wait for the response */ + errno = osif_request_wait_for_response(request); + if (errno) { + hdd_err("Failed to wait for statistics, errno %d", errno); + goto put_request; + } + + /* update the adapter with the fresh results */ + priv = osif_request_priv(request); + adapter->hdd_stats.summary_stat = priv->summary_stats; + adapter->hdd_stats.class_a_stat = priv->class_a_stats; + adapter->hdd_stats.per_chain_rssi_stats = priv->per_chain_rssi_stats; + +put_request: + /* + * 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 0; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +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 (NULL == adapter) { + hdd_err("adapter is NULL"); + return -EPERM; + } + + 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; +} + +void wlan_hdd_display_txrx_stats(struct hdd_context *ctx) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_tx_rx_stats *stats; + int i = 0; + uint32_t total_rx_pkt, total_rx_dropped, + total_rx_delv, total_rx_refused; + + hdd_for_each_adapter(ctx, adapter) { + total_rx_pkt = 0; + total_rx_dropped = 0; + total_rx_delv = 0; + total_rx_refused = 0; + stats = &adapter->hdd_stats.tx_rx_stats; + hdd_debug("adapter: %u", adapter->session_id); + for (; i < NUM_CPUS; i++) { + total_rx_pkt += stats->rx_packets[i]; + total_rx_dropped += stats->rx_dropped[i]; + total_rx_delv += stats->rx_delivered[i]; + total_rx_refused += stats->rx_refused[i]; + } + + hdd_debug("TX - called %u, dropped %u orphan %u", + stats->tx_called, stats->tx_dropped, + stats->tx_orphaned); + + for (i = 0; i < NUM_CPUS; i++) { + if (stats->rx_packets[i] == 0) + continue; + hdd_debug("Rx CPU[%d]: packets %u, dropped %u, delivered %u, refused %u", + i, stats->rx_packets[i], stats->rx_dropped[i], + stats->rx_delivered[i], stats->rx_refused[i]); + } + hdd_debug("RX - packets %u, dropped %u, unsolict_arp_n_mcast_drp %u, delivered %u, refused %u", + total_rx_pkt, total_rx_dropped, + qdf_atomic_read(&stats->rx_usolict_arp_n_mcast_drp), + total_rx_delv, + total_rx_refused); + } +} + +#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 hdd_adapter *adapter; + struct stats_event *ev = stats_ev; + uint8_t i; + struct hdd_station_ctx *sta_ctx; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + for (i = 0; i < ev->num_summary_stats; i++) { + adapter = hdd_get_adapter_by_vdev( + hdd_ctx, + ev->vdev_summary_stats[i].vdev_id); + if (!adapter) { + hdd_debug("invalid adapter"); + continue; + } + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((sta_ctx) && + (eConnectionState_Associated != + sta_ctx->conn_info.connState)) { + adapter->rssi_on_disconnect = + ev->vdev_summary_stats[i].stats.rssi; + hdd_debug("rssi on disconnect %d for " QDF_MAC_ADDR_STR, + adapter->rssi_on_disconnect, + QDF_MAC_ADDR_ARRAY(adapter->mac_addr.bytes)); + } + } +} + +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 + diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..0ad9c34b7f0de7c74b590c6d708ed2c1e9a32839 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h @@ -0,0 +1,430 @@ +/* + * 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 : 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" + +#define INVALID_MCS_IDX 255 +#define MAX_HT_MCS_IDX 8 +#define MAX_VHT_MCS_IDX 10 + +#define DATA_RATE_11AC_MCS_MASK 0x03 + +/* LL stats get request time out value */ +#define WLAN_WAIT_TIME_LL_STATS 800 + +#define WLAN_HDD_TGT_NOISE_FLOOR_DBM (-96) + +/** + * 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 + * @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:i 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); + +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 + * @adapter: Pointer to device adapter + * @info: Pointer to interface info + * + * Return: bool + */ +bool hdd_get_interface_info(struct hdd_adapter *adapter, + tpSirWifiInterfaceInfo info); + +/** + * wlan_hdd_ll_stats_get() - Get Link Layer statistics from FW + * @adapter: Pointer to device 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 hdd_adapter *adapter, uint32_t req_id, + uint32_t req_mask); + +#else + +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(hdd_adapter_t *adapter, uint32_t req_id, + uint32_t req_mask) +{ + return -EINVAL; +} + +#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_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); + +void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, + tStatsExtEvent *msg); + +/** + * wlan_hdd_cfg80211_stats_ext2_callback - stats_ext2_callback + * @ctx: hdd context + * @pmsg: sir_sme_rx_aggr_hole_ind + * + * Return: void + */ +void wlan_hdd_cfg80211_stats_ext2_callback(void *ctx, + struct sir_sme_rx_aggr_hole_ind *pmsg); + +void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, int indType, + void *pRsp, void *context); +/** + * 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); + +/** + * 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); + +/** + * wlan_hdd_get_rssi() - Get the current RSSI + * @adapter: adapter upon which the measurement is requested + * @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 hdd_adapter *adapter, int8_t *rssi_value); + +/** + * wlan_hdd_get_snr() - Get the current SNR + * @adapter: adapter upon which the measurement is requested + * @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 hdd_adapter *adapter, int8_t *snr); + +/** + * wlan_hdd_get_linkspeed_for_peermac() - Get link speed for a peer + * @adapter: adapter upon which the peer is active + * @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 hdd_adapter *adapter, + struct qdf_mac_addr *mac_address, + uint32_t *linkspeed); + +/** + * wlan_hdd_get_link_speed() - get link speed + * @adapter: pointer to the 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 hdd_adapter *adapter, uint32_t *link_speed); + +/** + * wlan_hdd_get_peer_rssi() - get station's rssi + * @adapter: hostapd interface + * @macaddress: peer sta mac address or ff:ff:ff:ff:ff:ff to query all peer + * @peer_sta_info: output pointer which will fill by peer sta info + * + * This function will call sme_get_peer_info to get rssi + * + * Return: 0 on success, otherwise error value + */ +int wlan_hdd_get_peer_rssi(struct hdd_adapter *adapter, + struct qdf_mac_addr *macaddress, + struct sir_peer_sta_info *peer_sta_info); + +/** + * wlan_hdd_get_peer_info() - get peer info + * @adapter: hostapd interface + * @macaddress: request peer mac address + * @peer_info_ext: one peer extended info retrieved + * + * This function will call sme_get_peer_info_ext to get peer info + * + * Return: 0 on success, otherwise error value + */ +int wlan_hdd_get_peer_info(struct hdd_adapter *adapter, + struct qdf_mac_addr macaddress, + struct sir_peer_info_ext *peer_info_ext); + +#ifndef QCA_SUPPORT_CP_STATS +/** + * wlan_hdd_get_class_astats() - Get Class A statistics + * @adapter: adapter for which statistics are desired + * + * Return: QDF_STATUS_SUCCESS if adapter's Class A statistics were updated + */ +QDF_STATUS wlan_hdd_get_class_astats(struct hdd_adapter *adapter); +#endif + +/** + * wlan_hdd_get_station_stats() - Get station statistics + * @adapter: adapter for which statistics are desired + * + * Return: status of operation + */ +int wlan_hdd_get_station_stats(struct hdd_adapter *adapter); + +/** + * 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); + +/** + * wlan_hdd_request_station_stats() - Get station statistics + * @adapter: adapter for which statistics are desired + * + * Return: QDF_STATUS_SUCCESS if adapter's statistics were updated + */ +int wlan_hdd_request_station_stats(struct hdd_adapter *adapter); + +/** + * wlan_hdd_display_txrx_stats() - display HDD txrx stats summary + * @hdd_ctx: hdd context + * + * Display TXRX Stats for all adapters + * + * Return: none + */ +void wlan_hdd_display_txrx_stats(struct hdd_context *hdd_ctx); + +#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 + +#endif /* end #if !defined(WLAN_HDD_STATS_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c new file mode 100644 index 0000000000000000000000000000000000000000..ae2d2b8b4721239dda5c5f5130169db357bf4ea4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c @@ -0,0 +1,194 @@ +/* + * 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. + */ + +/** + * DOC: wlan_hdd_subnet_detect.c + * + * WLAN Host Device Driver subnet detect API implementation + */ + +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_subnet_detect.h" +#include + +/* + * 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 + +static const struct nla_policy + policy[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1] = { + [PARAM_MAC_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE + }, + [PARAM_IPV4_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_IPV4_ADDR_SIZE + }, + [PARAM_IPV6_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_IPV6_ADDR_SIZE + } +}; + +/** + * __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_param_update_req req = { 0 }; + int ret; + QDF_STATUS status; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* user may have disabled the feature in INI */ + if (!hdd_ctx->config->enable_lfr_subnet_detection) { + hdd_info("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_err("Received GW param update for non-STA mode adapter"); + return -ENOTSUPP; + } + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("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, 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.session_id = adapter->session_id; + + hdd_debug("Configuring gateway for session %d", req.session_id); + hdd_debug("mac:%pM, ipv4:%pI4 (type %d), ipv6:%pI6c (type %d)", + req.gw_mac_addr.bytes, + req.ipv4_addr, req.ipv4_addr_type, + req.ipv6_addr, req.ipv6_addr_type); + + hdd_nud_set_gateway_addr(adapter, req.gw_mac_addr); + + 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 ret; + + cds_ssr_protect(__func__); + + ret = __wlan_hdd_cfg80211_set_gateway_params( + wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + return ret; +} +#undef PARAM_MAC_ADDR +#undef PARAM_IPV4_ADDR +#undef PARAM_IPV6_ADDR diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h new file mode 100644 index 0000000000000000000000000000000000000000..2d832009bdc17e510c72fdcbc772cc765c00fbef --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015 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; + +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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs.c new file mode 100644 index 0000000000000000000000000000000000000000..a665b16b556bd6714e1315fc2d9bbcd12c6c7d5e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs.c @@ -0,0 +1,555 @@ +/* + * 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: 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 +#include + +#define MAX_PSOC_ID_SIZE 10 + +#ifdef MULTI_IF_NAME +#define DRIVER_NAME MULTI_IF_NAME +#else +#define DRIVER_NAME "wlan" +#endif + +static struct kobject *wlan_kobject; +static struct kobject *driver_kobject; +static struct kobject *fw_kobject; +static struct kobject *psoc_kobject; + +static ssize_t __show_driver_version(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, QWLAN_VERSIONSTR); +} + +static ssize_t show_driver_version(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + ssize_t ret_val; + + cds_ssr_protect(__func__); + ret_val = __show_driver_version(kobj, attr, buf); + cds_ssr_unprotect(__func__); + + return ret_val; +} + +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); + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + hdd_err("hdd ctx is invalid"); + return ret; + } + + 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) +{ + ssize_t ret_val; + + cds_ssr_protect(__func__); + ret_val = __show_fw_version(kobj, attr, buf); + cds_ssr_unprotect(__func__); + + return ret_val; +}; + +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 kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + 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(); + + ret_cnt = wlan_hdd_validate_context(hdd_ctx); + if (ret_cnt) + return ret_cnt; + + 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"); + 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) +{ + ssize_t ret_val; + + cds_ssr_protect(__func__); + ret_val = __show_device_power_stats(kobj, attr, buf); + cds_ssr_unprotect(__func__); + + return ret_val; +} + +#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 device *dev, char *buf) +{ + struct net_device *netdev = + qdf_container_of(dev, struct net_device, dev); + struct hdd_adapter *adapter = (netdev_priv(netdev)); + 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) { + hdd_err("hdd ctx is invalid"); + 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_adapter_is_connected_sta(adapter)) { + 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->session_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) +{ + ssize_t ret_val; + + cds_ssr_protect(__func__); + ret_val = __show_beacon_reception_stats(dev, buf); + cds_ssr_unprotect(__func__); + + return ret_val; +} + +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); +static struct kobj_attribute power_stats_attribute = + __ATTR(power_stats, 0444, show_device_power_stats, NULL); + +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", driver_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; +} + +void hdd_sysfs_destroy_version_interface(void) +{ + if (psoc_kobject) { + kobject_put(psoc_kobject); + psoc_kobject = NULL; + kobject_put(fw_kobject); + fw_kobject = NULL; + } +} + +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"); +} + +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); +} + +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; + } +} + +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; + kobject_put(wlan_kobject); + wlan_kobject = NULL; + } +} + +#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; +} + +void hdd_sysfs_create_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_create_bcn_reception_interface(adapter); +} + +static void hdd_sysfs_destroy_bcn_reception_interface(struct hdd_adapter + *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_beacon_stats); +} + +void hdd_sysfs_destroy_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_destroy_bcn_reception_interface(adapter); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c new file mode 100644 index 0000000000000000000000000000000000000000..1e40ac960572b08edacd95de094381ce0c408583 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c @@ -0,0 +1,918 @@ +/* + * 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: wlan_hdd_tdls.c + * + * WLAN Host Device Driver implementation for TDLS + */ + +#include +#include +#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_hdd_object_manager.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; + 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(adapter); + if (!vdev) { + len = scnprintf(buf, buflen, "\nVDEV is NULL\n"); + return len; + } + ret = wlan_cfg80211_tdls_get_all_peers(vdev, buf, buflen); + hdd_objmgr_put_vdev(vdev); + + 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] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [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] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, +}; +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] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_TDLS_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] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [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}, +}; + +static 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}, +}; + +/** + * __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) +{ + /* TODO */ + return 0; +} + +/** + * __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; + + 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 (NULL == 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) { + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + ret = wlan_cfg80211_tdls_configure_mode(vdev, + trigger_mode); + hdd_objmgr_put_vdev(vdev); + return ret; + } + + return -EINVAL; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_configure_tdls_mode(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_get_status(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_exttdls_enable() - enable an externally controllable + * TDLS peer and set parameters + * wiphy: wiphy + * @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) +{ + /* TODO */ + return 0; +} + +/** + * 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_enable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __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) +{ + /* TODO */ + return 0; +} + +/** + * 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 ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_disable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#if TDLS_MGMT_VERSION2 +/** + * __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 + * @buf: additional IE to include + * @len: length of buf in bytes + * + * Return: 0 if success; negative errno otherwise + */ +static 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 +/** + * __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 + * @buf: additional IE to include + * @len: length of buf in bytes + * + * Return: 0 if success; negative errno otherwise + */ +#if (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)) +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 +#endif +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); +#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_session_id(adapter->session_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TDLS_MGMT, + adapter->session_id, action_code); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (false == hdd_ctx->config->fEnableTDLSSupport) { + hdd_debug("TDLS Disabled in INI OR not enabled in FW. " + "Cannot process TDLS commands"); + return -ENOTSUPP; + } + + if (hdd_ctx->tdls_umac_comp_active) { + struct wlan_objmgr_vdev *vdev; + int ret; + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + ret = wlan_cfg80211_tdls_mgmt(vdev, peer, + action_code, dialog_token, + status_code, peer_capability, + buf, len); + hdd_objmgr_put_vdev(vdev); + return ret; + } + + return -EINVAL; +} + +/** + * 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 + * @buf: buffer + * @len: Length of @buf + * + * 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. + */ +#if 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 /* TDLS_MGMT_VERSION2 */ +#if (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)) +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 +#endif +{ + int ret; + + cds_ssr_protect(__func__); +#if TDLS_MGMT_VERSION2 + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#else /* TDLS_MGMT_VERSION2 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + ret = __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)) + ret = __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)) + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#else + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, buf, len); +#endif +#endif + + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_tdls_extctrl_config_peer() - configure an externally controllable + * TDLS peer + * @adapter: HDD adapter + * @peer: MAC address of the TDLS peer + * @callback: Callback to set on the peer + * @chan: Channel + * @max_latency: Maximum latency + * @op_class: Operation class + * @min_bandwidth: Minimal bandwidth + * + * Return: 0 on success; negative otherwise + */ +int wlan_hdd_tdls_extctrl_config_peer(struct hdd_adapter *adapter, + const uint8_t *peer, + cfg80211_exttdls_callback callback, + u32 chan, + u32 max_latency, + u32 op_class, u32 min_bandwidth) +{ + /* TODO */ + return 0; +} + +/** + * wlan_hdd_tdls_extctrl_deconfig_peer() - de-configure an externally + * controllable TDLS peer + * @adapter: HDD adapter + * @peer: MAC address of the tdls peer + * + * Return: 0 if success; negative errno otherwisw + */ +int wlan_hdd_tdls_extctrl_deconfig_peer(struct hdd_adapter *adapter, + const uint8_t *peer) +{ + /* TODO */ + return 0; +} + +/** + * __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; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->session_id)) + return -EINVAL; + + if (false == hdd_ctx->config->fEnableTDLSSupport) { + 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->session_id, oper); + + if (NULL == 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) { + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + status = wlan_cfg80211_tdls_oper(vdev, + peer, oper); + hdd_objmgr_put_vdev(vdev); + hdd_exit(); + return status; + } + + hdd_exit(); + return -EINVAL; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_tdls_oper(wiphy, dev, peer, oper); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_send_tdls_discover_req() - send out TDLS discovery for + * a TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the peer + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, + struct net_device *dev, u8 *peer) +{ + hdd_debug("tdls send discover req: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer)); +#if TDLS_MGMT_VERSION2 + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, 0, + NULL, 0); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, 0, NULL, 0); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, NULL, 0); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, NULL, 0); +#else + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + NULL, 0); +#endif +#endif +} + + +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) { + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + status = ucfg_set_tdls_offchannel(vdev, + offchannel); + hdd_objmgr_put_vdev(vdev); + } + } + 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) { + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + status = ucfg_set_tdls_secoffchanneloffset(vdev, + offchanoffset); + hdd_objmgr_put_vdev(vdev); + } + } + 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; + + if (hdd_ctx->tdls_umac_comp_active) { + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + status = ucfg_set_tdls_offchan_mode(vdev, + offchanmode); + hdd_objmgr_put_vdev(vdev); + } + } + 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; + } + + hdd_ctx->config->enable_tdls_scan = val; + return 0; +} + +/** + * wlan_hdd_tdls_antenna_switch() - Dynamic TDLS antenna switch 1x1 <-> 2x2 + * antenna mode in standalone station + * @hdd_ctx: Pointer to hdd contex + * @adapter: Pointer to hdd adapter + * + * Return: 0 if success else non zero + */ +int wlan_hdd_tdls_antenna_switch(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint32_t mode) +{ + if (hdd_ctx->tdls_umac_comp_active) { + struct wlan_objmgr_vdev *vdev; + int ret; + + vdev = hdd_objmgr_get_vdev(adapter); + if (!vdev) + return -EINVAL; + ret = wlan_tdls_antenna_switch(vdev, mode); + hdd_objmgr_put_vdev(vdev); + return ret; + } + + return 0; +} + +QDF_STATUS hdd_tdls_register_peer(void *userdata, uint32_t vdev_id, + const uint8_t *mac, uint16_t sta_id, + uint8_t qos) +{ + struct hdd_adapter *adapter; + struct hdd_context *hddctx; + + hddctx = userdata; + if (!hddctx) { + hdd_err("Invalid hddctx"); + return QDF_STATUS_E_INVAL; + } + adapter = hdd_get_adapter_by_vdev(hddctx, vdev_id); + if (!adapter) { + hdd_err("Invalid adapter"); + return QDF_STATUS_E_FAILURE; + } + + return hdd_roam_register_tdlssta(adapter, mac, sta_id, qos); +} + +QDF_STATUS hdd_tdls_deregister_peer(void *userdata, uint32_t vdev_id, + uint8_t sta_id) +{ + struct hdd_adapter *adapter; + struct hdd_context *hddctx; + + hddctx = userdata; + if (!hddctx) { + hdd_err("Invalid hddctx"); + return QDF_STATUS_E_INVAL; + } + adapter = hdd_get_adapter_by_vdev(hddctx, vdev_id); + if (!adapter) { + hdd_err("Invalid adapter"); + return QDF_STATUS_E_FAILURE; + } + + return hdd_roam_deregister_tdlssta(adapter, sta_id); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..22a2438499f6e2936f9fb6a4333661d3b09225a1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c @@ -0,0 +1,68 @@ +/* + * 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. + */ + +#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_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_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/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c new file mode 100644 index 0000000000000000000000000000000000000000..9fd26ad9bd709f06fbb22fb9dcc523d561ea5bc7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c @@ -0,0 +1,1788 @@ +/* + * Copyright (c) 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. + */ + +/** + * wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_tsf.h" +#include "wma_api.h" +#include +#include +#include "ol_txrx_api.h" +static struct completion 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 +#define WLAN_HDD_SOFTAP_INTERVEL_TIMES 100 + +/** + * 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 +#define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 9 + +static inline void hdd_set_th_sync_status(struct hdd_adapter *adapter, + bool initialized) +{ + qdf_atomic_set(&adapter->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_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 hdd_tsf_get_state ret = TSF_RETURN; + 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); + if (hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) { + hdd_err("failed to cap tsf, not connect with ap"); + ret = TSF_STA_NOT_CONNECTED_NO_TSF; + } + } else if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + !(test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags))) { + hdd_err("Soft AP / P2p GO not beaconing"); + ret = TSF_SAP_NOT_STARTED_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_ready_flag) || + !hdd_get_th_sync_status(adapter)) { + hdd_err("TSF is not initialized"); + return false; + } + + return true; +} + +/** + * 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 + */ +#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && defined(WLAN_FEATURE_TSF_PLUS) +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; +} + +bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd) +{ + return (hdd && (hdd->config) && + (hdd->config->tsf_ptp_options)); +} + +bool hdd_tsf_is_tx_set(struct hdd_context *hdd) +{ + return (hdd && (hdd->config) && + ((hdd->config->tsf_ptp_options) + & CFG_SET_TSF_PTP_OPT_TX)); +} + +bool hdd_tsf_is_rx_set(struct hdd_context *hdd) +{ + return (hdd && (hdd->config) && + ((hdd->config->tsf_ptp_options) + & CFG_SET_TSF_PTP_OPT_RX)); +} + +bool hdd_tsf_is_raw_set(struct hdd_context *hdd) +{ + return (hdd && (hdd->config) && + ((hdd->config->tsf_ptp_options) + & CFG_SET_TSF_PTP_OPT_RAW)); +} + +bool hdd_tsf_is_dbg_fs_set(struct hdd_context *hdd) +{ + return (hdd && (hdd->config) && + ((hdd->config->tsf_ptp_options) + & CFG_SET_TSF_DBG_FS)); +} + +bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd) +{ + return (hdd && (hdd->config) && + ((hdd->config->tsf_ptp_options) + & CFG_SET_TSF_PTP_OPT_TSF64_TX)); +} + +#else +static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) +{ + int ret; + + ret = wma_cli_set_command((int)adapter->session_id, + (int)GEN_PARAM_RESET_TSF_GPIO, adapter->session_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 = hdd_ctx->config->tsf_gpio_pin; + + 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 + +static enum hdd_tsf_op_result hdd_capture_tsf_internal( + struct hdd_adapter *adapter, uint32_t *buf, int len) +{ + int ret; + struct hdd_context *hddctx; + qdf_mc_timer_t *cap_timer; + + if (adapter == NULL || buf == NULL) { + 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 (!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->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->cap_tsf_context = adapter; + + hdd_debug("+ioctl issue cap tsf cmd"); + cap_timer = &adapter->host_capture_req_timer; + qdf_mc_timer_init(cap_timer, QDF_TIMER_TYPE_SW, + hdd_capture_req_timer_expired_handler, + (void *)adapter); + qdf_mc_timer_start(cap_timer, WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS); + + /* Reset TSF value for new capture */ + adapter->cur_target_time = 0; + + buf[0] = TSF_RETURN; + init_completion(&tsf_sync_get_completion_evt); + ret = wma_cli_set_command((int)adapter->session_id, + (int)GEN_PARAM_CAPTURE_TSF, + adapter->session_id, GEN_CMD); + if (QDF_STATUS_SUCCESS != ret) { + hdd_err("cap tsf fail"); + buf[0] = TSF_CAPTURE_FAIL; + hddctx->cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->cap_tsf_flag, 0); + qdf_mc_timer_stop(&adapter->host_capture_req_timer); + qdf_mc_timer_destroy(&adapter->host_capture_req_timer); + + return HDD_TSF_OP_SUCC; + } + hdd_debug("-ioctl return cap tsf cmd"); + return HDD_TSF_OP_SUCC; +} + +static enum hdd_tsf_op_result hdd_indicate_tsf_internal( + struct hdd_adapter *adapter, uint32_t *buf, int len) +{ + int ret; + struct hdd_context *hddctx; + + if (!adapter || !buf) { + hdd_err("invalid pointer"); + return HDD_TSF_OP_FAIL; + } + + if (len != 3) + return HDD_TSF_OP_FAIL; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return HDD_TSF_OP_FAIL; + } + + buf[1] = 0; + buf[2] = 0; + + 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 (adapter->cur_target_time == 0) { + hdd_info("TSF value not received"); + buf[0] = TSF_NOT_RETURNED_BY_FW; + return HDD_TSF_OP_SUCC; + } + + buf[0] = TSF_RETURN; + buf[1] = (uint32_t)(adapter->cur_target_time & 0xffffffff); + buf[2] = (uint32_t)((adapter->cur_target_time >> 32) & + 0xffffffff); + + if (!qdf_atomic_read(&hddctx->cap_tsf_flag)) { + hdd_info("old: status=%u, tsf_low=%u, tsf_high=%u", + buf[0], buf[1], buf[2]); + return HDD_TSF_OP_SUCC; + } + + ret = hdd_tsf_reset_gpio(adapter); + if (0 != ret) { + hdd_err("reset tsf gpio fail"); + buf[0] = TSF_RESET_GPIO_FAIL; + return HDD_TSF_OP_SUCC; + } + hddctx->cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->cap_tsf_flag, 0); + hdd_debug("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u", + buf[0], buf[1], buf[2]); + + 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 inverval should: + * equal or less than (1/2 * OVERFLOW_INDICATOR32 us) + */ +#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 10 +#define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32) +#define CAP_TSF_TIMER_FIX_SEC 1 + +/** + * 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; + } + + ret = qdf_mc_timer_start(&adapter->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; + + if (!hdd_get_th_sync_status(adapter)) { + hdd_err("Host Target sync has not initialized"); + return HDD_TSF_OP_SUCC; + } + + ret = qdf_mc_timer_stop(&adapter->host_target_sync_timer); + if (ret != QDF_STATUS_SUCCESS) { + hdd_err("Failed to stop timer, ret: %d", ret); + return HDD_TSF_OP_FAIL; + } + return HDD_TSF_OP_SUCC; +} + +static inline void hdd_reset_timestamps(struct hdd_adapter *adapter) +{ + qdf_spin_lock_bh(&adapter->host_target_sync_lock); + adapter->cur_host_time = 0; + adapter->cur_target_time = 0; + adapter->last_host_time = 0; + adapter->last_target_time = 0; + qdf_spin_unlock_bh(&adapter->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 + * + * 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) +{ + 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_warn("timestamps deviation - delta: %llu ns", delta_ns); + /* the deviation should be smaller than a threshold */ + if (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->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) +{ + 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); + + /* + * 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(&adapter->host_target_sync_lock); + + /* at present, target_time is only 32bit in fact */ + delta32_target = (int64_t)((target_time & U32_MAX) - + (adapter->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(adapter->last_host_time, + HOST_TO_TARGET_TIME_RATIO * delta32_target, + host_time); + + if (in_cap_state) + qdf_spin_unlock_bh(&adapter->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) +{ + int32_t ret = -EINVAL; + bool in_cap_state; + + if (!adapter || host_time == 0) + return ret; + + in_cap_state = hdd_tsf_is_in_cap(adapter); + if (in_cap_state) + qdf_spin_lock_bh(&adapter->host_target_sync_lock); + + if (host_time < adapter->last_host_time) + ret = hdd_uint64_minus(adapter->last_target_time, + qdf_do_div(adapter->last_host_time - + host_time, + HOST_TO_TARGET_TIME_RATIO), + target_time); + else + ret = hdd_uint64_plus(adapter->last_target_time, + qdf_do_div(host_time - + adapter->last_host_time, + HOST_TO_TARGET_TIME_RATIO), + target_time); + + if (in_cap_state) + qdf_spin_unlock_bh(&adapter->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) +{ + 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); + + /* + * 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(&adapter->host_target_sync_lock); + + /* at present, target_time is 64bit (g_tsf64), us*/ + if (tsf64_time > adapter->last_target_global_tsf_time) { + delta64_tsf64time = tsf64_time - + adapter->last_target_global_tsf_time; + delta64_soctime = delta64_tsf64time * NSEC_PER_USEC; + + /* soc_time (ns)*/ + ret = hdd_uint64_plus(adapter->last_tsf_sync_soc_time, + delta64_soctime, soc_time); + } else { + delta64_tsf64time = adapter->last_target_global_tsf_time - + tsf64_time; + delta64_soctime = delta64_tsf64time * NSEC_PER_USEC; + + /* soc_time (ns)*/ + ret = hdd_uint64_minus(adapter->last_tsf_sync_soc_time, + delta64_soctime, soc_time); + } + + if (in_cap_state) + qdf_spin_unlock_bh(&adapter->host_target_sync_lock); + + return ret; +} + +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(); +} + +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); +} + +#ifndef WLAN_FEATURE_TSF_PLUS_NOIRQ +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; + + hdd_ctx = (struct hdd_context *)arg; + host_time = hdd_get_monotonic_host_time(hdd_ctx); + + adapter = hdd_ctx->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_info("irq: %d - iface: %s - host_time: %llu", + irq, (!name ? "none" : name), host_time); + + return IRQ_HANDLED; +} +#endif + +void hdd_capture_req_timer_expired_handler(void *arg) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + 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; + } + + if (!hdd_tsf_is_initialized(adapter)) { + qdf_mc_timer_destroy(&adapter->host_capture_req_timer); + hdd_warn("tsf not init"); + return; + } + + qdf_spin_lock_bh(&adapter->host_target_sync_lock); + adapter->cur_host_time = 0; + adapter->cur_target_time = 0; + qdf_spin_unlock_bh(&adapter->host_target_sync_lock); + + ret = hdd_tsf_reset_gpio(adapter); + if (0 != ret) + hdd_info("reset tsf gpio fail"); + + hdd_ctx->cap_tsf_context = NULL; + qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0); + qdf_mc_timer_destroy(&adapter->host_capture_req_timer); + + sync_timer = &adapter->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); +} + +#ifdef WLAN_FEATURE_TSF_PLUS_NOIRQ +static void hdd_update_timestamp(struct hdd_adapter *adapter) +{ + int interval = 0; + enum hdd_ts_status sync_status; + + if (!adapter) + return; + + /* 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(&adapter->host_target_sync_lock); + sync_status = + hdd_check_timestamp_status(adapter->last_target_time, + adapter->last_tsf_sync_soc_time, + adapter->cur_target_time, + adapter->cur_tsf_sync_soc_time); + hdd_info("sync_status %d", sync_status); + switch (sync_status) { + case HDD_TS_STATUS_INVALID: + if (++adapter->continuous_error_count < + MAX_CONTINUOUS_ERROR_CNT) { + interval = + WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS; + adapter->cur_target_time = 0; + adapter->cur_tsf_sync_soc_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: + adapter->last_target_time = adapter->cur_target_time; + adapter->last_target_global_tsf_time = + adapter->cur_target_global_tsf_time; + adapter->last_tsf_sync_soc_time = + adapter->cur_tsf_sync_soc_time; + adapter->cur_target_time = 0; + adapter->cur_target_global_tsf_time = 0; + adapter->cur_tsf_sync_soc_time = 0; + hdd_info("ts-pair updated: target: %llu; g_target:%llu, Qtime: %llu", + adapter->last_target_time, + adapter->last_target_global_tsf_time, + adapter->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. + */ + 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_INTERVEL_TIMES; + } + + adapter->continuous_error_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(&adapter->host_target_sync_lock); + + if (interval > 0) + qdf_mc_timer_start(&adapter->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; + ssize_t size; + + 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); + if (eConnectionState_Associated != hdd_sta_ctx->conn_info.connState && + (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"); + + tsf_sync_qtime = adapter->last_tsf_sync_soc_time; + do_div(tsf_sync_qtime, NSEC_PER_USEC); + + 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); + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM %llu %llu\n", + buf, adapter->last_target_time, + tsf_sync_qtime, + hdd_sta_ctx->conn_info.bssId.bytes, + qtime, host_time); + } else { + size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM %llu %llu\n", + buf, adapter->last_target_time, + tsf_sync_qtime, + adapter->mac_addr.bytes, + qtime, host_time); + } + + return size; +} + +static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) +{ + uint32_t tsf_op_resp[3]; + struct hdd_context *hddctx; + + hddctx = WLAN_HDD_GET_CTX(adapter); + hdd_indicate_tsf_internal(adapter, tsf_op_resp, 3); + 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; + + if (!adapter) + return; + + /* 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) + adapter->cur_host_time = host_time; + + qdf_spin_lock_bh(&adapter->host_target_sync_lock); + if (target_time > 0) + adapter->cur_target_time = target_time; + + sync_status = hdd_check_timestamp_status(adapter->last_target_time, + adapter->last_host_time, + adapter->cur_target_time, + adapter->cur_host_time); + hdd_info("sync_status %d", sync_status); + switch (sync_status) { + case HDD_TS_STATUS_INVALID: + if (++adapter->continuous_error_count < + MAX_CONTINUOUS_ERROR_CNT) { + interval = + WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS; + adapter->cur_target_time = 0; + adapter->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: + adapter->last_target_time = adapter->cur_target_time; + adapter->last_host_time = adapter->cur_host_time; + adapter->cur_target_time = 0; + adapter->cur_host_time = 0; + hdd_info("ts-pair updated: target: %llu; host: %llu", + adapter->last_target_time, + adapter->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_INTERVEL_TIMES; + } + + adapter->continuous_error_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(&adapter->host_target_sync_lock); + + if (interval > 0) + qdf_mc_timer_start(&adapter->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; + + 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); + if (eConnectionState_Associated != hdd_sta_ctx->conn_info.connState && + (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) { + size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n", + buf, target_time, host_time, + hdd_sta_ctx->conn_info.bssId.bytes); + } else { + size = scnprintf(buf, PAGE_SIZE, "%s%llu %llu %pM\n", + buf, target_time, host_time, + adapter->mac_addr.bytes); + } + } + + return size; +} + +static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) +{ + uint32_t tsf_op_resp[3]; + + hdd_indicate_tsf_internal(adapter, tsf_op_resp, 3); + hdd_update_timestamp(adapter, tsf, 0); +} +#endif + +static ssize_t hdd_wlan_tsf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __hdd_wlan_tsf_show(dev, attr, buf); + cds_ssr_unprotect(__func__); + + return ret; +} + +static DEVICE_ATTR(tsf, 0400, 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; + + 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_ready_flag)) { + hdd_err("TSF feature has NOT been initialized"); + 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->host_target_sync_lock); + + hdd_reset_timestamps(adapter); + + ret = qdf_mc_timer_init(&adapter->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 timer, ret: %d", ret); + goto fail; + } + + 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); + + 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)) { + hdd_err("Host Target sync has not been initialized!!"); + return HDD_TSF_OP_SUCC; + } + + hdd_set_th_sync_status(adapter, false); + ret = qdf_mc_timer_destroy(&adapter->host_target_sync_timer); + if (ret != QDF_STATUS_SUCCESS) + hdd_err("Failed to destroy 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->cap_tsf_flag) && + hddctx->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->cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->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; +} + +#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; + + 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) { + netbuf->tstamp = soc_time; + return HDD_TSF_OP_SUCC; + } + } + + return HDD_TSF_OP_FAIL; +} +#endif + +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) { + hdd_err("Failed to init tsf sync, ret: %d", ret); + return -EINVAL; + } + + return (__hdd_start_tsf_sync(adapter) == + HDD_TSF_OP_SUCC) ? 0 : -EINVAL; +} + +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; +} + +int hdd_tx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time) +{ + struct sock *sk = netbuf->sk; + + if (!sk) + return -EINVAL; + + if ((skb_shinfo(netbuf)->tx_flags & SKBTX_SW_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)); + serr->ee.ee_errno = ENOMSG; + 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 = ns_to_ktime(0); + return -EINVAL; +} + +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; +} + +static inline int __hdd_indicate_tsf(struct hdd_adapter *adapter, + uint32_t *buf, int len) +{ + if (!adapter || !buf) { + hdd_err("invalid pointer"); + return -EINVAL; + } + + if (len != 3) + return -EINVAL; + + buf[0] = TSF_DISABLED_BY_TSFPLUS; + buf[1] = 0; + buf[2] = 0; + + return 0; +} + +#ifdef WLAN_FEATURE_TSF_PLUS_NOIRQ +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + if (!hdd_tsf_is_ptp_enabled(hdd_ctx)) { + hdd_info("To enable TSF_PLUS, set gtsf_ptp_options in ini"); + return HDD_TSF_OP_FAIL; + } + + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_register_timestamp_callback(hdd_tx_timestamp); + return HDD_TSF_OP_SUCC; +} + +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + QDF_TIMER_STATE capture_req_timer_status; + qdf_mc_timer_t *cap_timer; + struct hdd_adapter *adapter, *adapternode_ptr, *next_ptr; + + if (!hdd_tsf_is_ptp_enabled(hdd_ctx)) + return HDD_TSF_OP_SUCC; + + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_deregister_timestamp_callback(); + + status = hdd_get_front_adapter(hdd_ctx, &adapternode_ptr); + + while (NULL != adapternode_ptr && QDF_STATUS_SUCCESS == status) { + adapter = adapternode_ptr; + status = + hdd_get_next_adapter(hdd_ctx, adapternode_ptr, &next_ptr); + adapternode_ptr = next_ptr; + if (adapter->host_capture_req_timer.state == 0) + continue; + cap_timer = &adapter->host_capture_req_timer; + capture_req_timer_status = + qdf_mc_timer_get_current_state(cap_timer); + + if (capture_req_timer_status != QDF_TIMER_STATE_UNUSED) { + qdf_mc_timer_stop(cap_timer); + status = + qdf_mc_timer_destroy(cap_timer); + if (status != QDF_STATUS_SUCCESS) + hdd_err("remove timer failed: %d", status); + } + } + + 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; + + if (!hdd_tsf_is_ptp_enabled(hdd_ctx)) { + hdd_info("To enable TSF_PLUS, set gtsf_ptp_options in ini"); + return HDD_TSF_OP_FAIL; + } + + 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; + } + + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_register_timestamp_callback(hdd_tx_timestamp); + return HDD_TSF_OP_SUCC; +} + +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + int ret; + + if (!hdd_tsf_is_ptp_enabled(hdd_ctx)) + return HDD_TSF_OP_SUCC; + + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_deregister_timestamp_callback(); + + 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 + +void hdd_tsf_notify_wlan_state_change(struct hdd_adapter *adapter, + eConnectionState old_state, + eConnectionState new_state) +{ + if (!adapter) + return; + + if (old_state != eConnectionState_Associated && + new_state == eConnectionState_Associated) + hdd_start_tsf_sync(adapter); + else if (old_state == eConnectionState_Associated && + new_state != eConnectionState_Associated) + hdd_stop_tsf_sync(adapter); +} +#else +static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) +{ +} + +static inline int __hdd_indicate_tsf(struct hdd_adapter *adapter, + uint32_t *buf, int len) +{ + return (hdd_indicate_tsf_internal(adapter, buf, len) == + HDD_TSF_OP_SUCC) ? 0 : -EINVAL; +} + +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; +} +#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, uint32_t *buf, int len) +{ + return __hdd_indicate_tsf(adapter, buf, len); +} + +/** + * 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 varaible 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; + int ret; + uint64_t tsf_sync_soc_time; + QDF_STATUS status; + QDF_TIMER_STATE capture_req_timer_status; + qdf_mc_timer_t *capture_timer; + + if (pcb_cxt == NULL || ptsf == NULL) { + 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; + + adapter = hdd_get_adapter_by_vdev(hddctx, ptsf->vdev_id); + + if (NULL == adapter) { + hdd_err("failed to find adapter"); + return -EINVAL; + } + + 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); + + capture_timer = &adapter->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); + status = qdf_mc_timer_destroy(capture_timer); + if (status != QDF_STATUS_SUCCESS) + hdd_warn("destroy cap req timer fail, ret: %d", status); + + adapter->cur_target_time = ((uint64_t)ptsf->tsf_high << 32 | + ptsf->tsf_low); + + adapter->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); + adapter->cur_tsf_sync_soc_time = + qdf_log_timestamp_to_usecs(tsf_sync_soc_time) * NSEC_PER_USEC; + complete(&tsf_sync_get_completion_evt); + hdd_update_tsf(adapter, adapter->cur_target_time); + hdd_info("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; +} + +static const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.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]; + int status, ret; + struct sk_buff *reply_skb; + uint32_t tsf_op_resp[3], tsf_cmd; + + hdd_enter_dev(wdev->netdev); + + 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]); + + if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) { + hdd_capture_tsf(adapter, tsf_op_resp, 1); + switch (tsf_op_resp[0]) { + 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; + } + } + if (status < 0) + goto end; + + if (tsf_cmd == QCA_TSF_SYNC_GET) { + ret = wait_for_completion_timeout(&tsf_sync_get_completion_evt, + msecs_to_jiffies(WLAN_TSF_SYNC_GET_TIMEOUT)); + if (ret == 0) { + status = -ETIMEDOUT; + goto end; + } + } + + if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) { + hdd_indicate_tsf(adapter, tsf_op_resp, 3); + switch (tsf_op_resp[0]) { + case TSF_RETURN: + status = 0; + break; + case TSF_NOT_RETURNED_BY_FW: + status = -EINPROGRESS; + break; + case TSF_STA_NOT_CONNECTED_NO_TSF: + case TSF_SAP_NOT_STARTED_NO_TSF: + status = -EPERM; + break; + default: + status = -EINVAL; + break; + } + if (status != 0) + goto end; + + reply_skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + sizeof(uint64_t) * 2 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX, + GFP_KERNEL); + if (!reply_skb) { + hdd_err("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, + adapter->cur_target_time) || + hdd_wlan_nla_put_u64(reply_skb, + QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, + adapter->cur_tsf_sync_soc_time)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + status = -EINVAL; + goto end; + } + status = 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 ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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_ready_flag) > 1) + return; + + qdf_atomic_init(&hdd_ctx->cap_tsf_flag); + + 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) + goto fail; + + return; + +fail: + qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0); +} + +void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx) +{ + if (!hdd_ctx) + return; + + if (!qdf_atomic_read(&hdd_ctx->tsf_ready_flag)) + return; + + wlan_hdd_tsf_plus_deinit(hdd_ctx); + qdf_atomic_set(&hdd_ctx->tsf_ready_flag, 0); + qdf_atomic_set(&hdd_ctx->cap_tsf_flag, 0); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_twt.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_twt.c new file mode 100644 index 0000000000000000000000000000000000000000..8d5cf4b3ab4c763d9a30ae2d1c01bd27a6df4b06 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_twt.c @@ -0,0 +1,169 @@ +/* + * 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 : wlan_hdd_twt.c + * + * WLAN Host Device Driver file for TWT (Target Wake Time) support. + * + */ + +#include "wlan_hdd_twt.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_cfg.h" +#include "cfg_api.h" +#include "sme_api.h" +#include "wma_twt.h" + +void hdd_twt_print_ini_config(struct hdd_context *hdd_ctx) +{ + hdd_debug("Name = [%s] Value = [%d]", CFG_ENABLE_TWT_NAME, + hdd_ctx->config->enable_twt); + hdd_debug("Name = [%s] Value = [%d]", CFG_TWT_CONGESTION_TIMEOUT_NAME, + hdd_ctx->config->twt_congestion_timeout); +} + +void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + struct wma_tgt_services *services = &cfg->services; + + hdd_debug("TWT: enable_twt=%d, tgt Req=%d, Res=%d", + hdd_ctx->config->enable_twt, services->twt_requestor, + services->twt_responder); + + sme_cfg_set_int(hdd_ctx->mac_handle, WNI_CFG_TWT_REQUESTOR, + QDF_MIN(services->twt_requestor, + hdd_ctx->config->enable_twt)); + + sme_cfg_set_int(hdd_ctx->mac_handle, WNI_CFG_TWT_RESPONDER, + QDF_MIN(services->twt_responder, + hdd_ctx->config->enable_twt)); + + /* + * Currently broadcast TWT is not supported + */ + sme_cfg_set_int(hdd_ctx->mac_handle, WNI_CFG_BCAST_TWT, + QDF_MIN(0, hdd_ctx->config->enable_twt)); +} + +void hdd_send_twt_enable_cmd(struct hdd_context *hdd_ctx) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + uint32_t req_val = 0, resp_val = 0, bcast_val = 0; + uint32_t congestion_timeout = hdd_ctx->config->twt_congestion_timeout; + + sme_cfg_get_int(hdd_ctx->mac_handle, WNI_CFG_TWT_REQUESTOR, &req_val); + sme_cfg_get_int(hdd_ctx->mac_handle, WNI_CFG_TWT_RESPONDER, &resp_val); + sme_cfg_get_int(hdd_ctx->mac_handle, WNI_CFG_BCAST_TWT, &bcast_val); + + hdd_debug("TWT cfg req:%d, responder:%d, bcast:%d, pdev:%d, cong:%d", + req_val, resp_val, bcast_val, pdev_id, congestion_timeout); + + if (req_val || resp_val || bcast_val) + wma_send_twt_enable_cmd(pdev_id, congestion_timeout); +} + +void hdd_twt_enable_comp_cb(void *hddctx, + struct wmi_twt_enable_complete_event_param *params) +{ + struct hdd_context *hdd_ctx = hddctx; + enum twt_status prev_state; + + if (!hdd_ctx) { + hdd_err("TWT: Invalid HDD Context"); + return; + } + 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); +} + +void hdd_twt_disable_comp_cb(void *hddctx) +{ + struct hdd_context *hdd_ctx = hddctx; + enum twt_status prev_state; + + if (!hdd_ctx) { + hdd_err("TWT: Invalid HDD Context"); + return; + } + prev_state = hdd_ctx->twt_state; + hdd_ctx->twt_state = TWT_DISABLED; + + hdd_debug("TWT: State transitioned from %d to %d", + prev_state, hdd_ctx->twt_state); +} + +void wlan_hdd_twt_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + hdd_ctx->twt_state = TWT_INIT; + status = sme_register_twt_enable_complete_cb(hdd_ctx->mac_handle, + hdd_twt_enable_comp_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Register twt enable complete failed"); + return; + } + + status = sme_register_twt_disable_complete_cb(hdd_ctx->mac_handle, + hdd_twt_disable_comp_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Register twt disable complete failed"); + goto twt_init_fail; + } + hdd_send_twt_enable_cmd(hdd_ctx); + return; + +twt_init_fail: + + sme_deregister_twt_enable_complete_cb(hdd_ctx->mac_handle); +} + +void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = sme_deregister_twt_disable_complete_cb(hdd_ctx->mac_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("De-register of twt disable cb failed: %d", status); + status = sme_deregister_twt_enable_complete_cb(hdd_ctx->mac_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("De-register of twt enable cb failed: %d", status); + + hdd_ctx->twt_state = TWT_CLOSED; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..f4c7d9f325cafa9ef30d52273ef9ab28ef61eae4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c @@ -0,0 +1,2566 @@ +/* + * 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: 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "sap_api.h" +#include "wlan_hdd_wmm.h" +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_lro.h" +#include +#include +#include +#include "wlan_hdd_nan_datapath.h" +#include "pld_common.h" +#include +#include "wlan_hdd_rx_monitor.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_cfg80211.h" +#include +#include +#include "wma_api.h" +#include "wlan_hdd_object_manager.h" + +#include "wlan_hdd_nud_tracking.h" + +#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 + +#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); +} +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * 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) +{ + 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); + + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&adapter-> + tx_flow_control_timer)) { + QDF_STATUS 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 + adapter->hdd_stats.tx_rx_stats.txflow_timer_cnt++; + } + + adapter->hdd_stats.tx_rx_stats.txflow_pause_cnt++; + adapter->hdd_stats.tx_rx_stats.is_txflow_paused = true; +} +#else + +static inline void +hdd_tx_resume_false(struct hdd_adapter *adapter, bool tx_resume) +{ +} +#endif + +static inline struct sk_buff *hdd_skb_orphan(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int need_orphan = 0; + + if (adapter->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 (hdd_ctx->config->tx_orphan_enable) + need_orphan = 1; +#endif + } else if (hdd_ctx->config->tx_orphan_enable) { + if (qdf_nbuf_is_ipv4_tcp_pkt(skb) || + qdf_nbuf_is_ipv6_tcp_pkt(skb)) + need_orphan = 1; + } + + if (need_orphan) { + skb_orphan(skb); + ++adapter->hdd_stats.tx_rx_stats.tx_orphaned; + } else + skb = skb_unshare(skb, GFP_ATOMIC); + + return skb; +} + +/** + * 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); + + /* 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_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 ((NULL == 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->session_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->session_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; + } +} + +/** + * hdd_get_tx_resource() - check tx resources and take action + * @adapter: adapter handle + * @STAId: station id + * @timer_value: timer value + * + * Return: none + */ +void hdd_get_tx_resource(struct hdd_adapter *adapter, + uint8_t STAId, uint16_t timer_value) +{ + if (false == + cdp_fc_get_tx_resource(cds_get_context(QDF_MODULE_ID_SOC), STAId, + adapter->tx_flow_low_watermark, + adapter->tx_flow_high_watermark_offset)) { + hdd_debug("Disabling queues lwm %d hwm offset %d", + adapter->tx_flow_low_watermark, + adapter->tx_flow_high_watermark_offset); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + if ((adapter->tx_flow_timer_initialized == true) && + (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&adapter-> + tx_flow_control_timer))) { + qdf_mc_timer_start(&adapter->tx_flow_control_timer, + timer_value); + adapter->hdd_stats.tx_rx_stats.txflow_timer_cnt++; + adapter->hdd_stats.tx_rx_stats.txflow_pause_cnt++; + adapter->hdd_stats.tx_rx_stats.is_txflow_paused = true; + } + } +} + +#else +/** + * hdd_skb_orphan() - skb_unshare a cloned packed else skb_orphan + * @adapter: pointer to HDD adapter + * @skb: pointer to skb data packet + * + * Return: pointer to skb structure + */ +static inline struct sk_buff *hdd_skb_orphan(struct hdd_adapter *adapter, + struct sk_buff *skb) { + + struct sk_buff *nskb; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); +#endif + + hdd_skb_fill_gso_size(adapter->dev, skb); + + nskb = skb_unshare(skb, GFP_ATOMIC); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) + if (unlikely(hdd_ctx->config->tx_orphan_enable) && (nskb == skb)) { + /* + * 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. + */ + ++adapter->hdd_stats.tx_rx_stats.tx_orphaned; + skb_orphan(skb); + } +#endif + return nskb; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +uint32_t hdd_txrx_get_tx_ack_count(struct hdd_adapter *adapter) +{ + return cdp_get_tx_ack_stats(cds_get_context(QDF_MODULE_ID_SOC), + adapter->session_id); +} + +/** + * qdf_event_eapol_log() - send event to wlan diag + * @skb: skb ptr + * @dir: direction + * @eapol_key_info: eapol key info + * + * Return: None + */ +void hdd_event_eapol_log(struct sk_buff *skb, 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(skb)))) + return; + else if (!qdf_nbuf_is_ipv4_eapol_pkt(skb)) + return; + + eapol_key_info = (uint16_t)(*(uint16_t *) + (skb->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 *) + (skb->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, + (skb->data + QDF_NBUF_DEST_MAC_OFFSET), + sizeof(wlan_diag_event.dest_addr)); + qdf_mem_copy(wlan_diag_event.src_addr, + (skb->data + QDF_NBUF_SRC_MAC_OFFSET), + sizeof(wlan_diag_event.src_addr)); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL); +} + + +/** + * wlan_hdd_classify_pkt() - classify packet + * @skb - sk buff + * + * Return: none + */ +void wlan_hdd_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; +} + +/** + * hdd_get_transmit_sta_id() - function to retrieve station id to be used for + * sending traffic towards a particular destination address. The destination + * address can be unicast, multicast or broadcast + * + * @adapter: Handle to adapter context + * @dst_addr: Destination address + * @station_id: station id + * + * Returns: None + */ +static void hdd_get_transmit_sta_id(struct hdd_adapter *adapter, + struct sk_buff *skb, uint8_t *station_id) +{ + bool mcbc_addr = false; + QDF_STATUS status; + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct qdf_mac_addr *dst_addr = NULL; + + dst_addr = (struct qdf_mac_addr *)skb->data; + status = hdd_get_peer_sta_id(sta_ctx, dst_addr, station_id); + if (QDF_IS_STATUS_ERROR(status)) { + if (QDF_NBUF_CB_GET_IS_BCAST(skb) || + QDF_NBUF_CB_GET_IS_MCAST(skb)) { + hdd_debug("Received MC/BC packet for transmission"); + mcbc_addr = true; + } + } + + if (adapter->device_mode == QDF_IBSS_MODE || + adapter->device_mode == QDF_NDI_MODE) { + /* + * This check is necessary to make sure station id is not + * overwritten for UC traffic in IBSS or NDI mode + */ + if (mcbc_addr) + *station_id = sta_ctx->broadcast_staid; + } else { + /* For the rest, traffic is directed to AP/P2P GO */ + if (eConnectionState_Associated == sta_ctx->conn_info.connState) + *station_id = sta_ctx->conn_info.staId[0]; + } +} + +/** + * hdd_clear_tx_rx_connectivity_stats() - clear connectivity stats + * @hdd_ctx: pointer to HDD Station Context + * + * Return: None + */ +static void hdd_clear_tx_rx_connectivity_stats(struct hdd_adapter *adapter) +{ + hdd_info("Clear txrx connectivity stats"); + qdf_mem_zero(&adapter->hdd_stats.hdd_arp_stats, + sizeof(adapter->hdd_stats.hdd_arp_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_dns_stats, + sizeof(adapter->hdd_stats.hdd_dns_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_tcp_stats, + sizeof(adapter->hdd_stats.hdd_tcp_stats)); + qdf_mem_zero(&adapter->hdd_stats.hdd_icmpv4_stats, + sizeof(adapter->hdd_stats.hdd_icmpv4_stats)); + adapter->pkt_type_bitmap = 0; + adapter->track_arp_ip = 0; + qdf_mem_zero(adapter->dns_payload, adapter->track_dns_domain_len); + adapter->track_dns_domain_len = 0; + adapter->track_src_port = 0; + adapter->track_dest_port = 0; + adapter->track_dest_ipv4 = 0; +} + +void hdd_reset_all_adapters_connectivity_stats(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *pNext = NULL; + QDF_STATUS status; + + hdd_enter(); + + status = hdd_get_front_adapter(hdd_ctx, &adapter); + + while (NULL != adapter && QDF_STATUS_SUCCESS == status) { + hdd_clear_tx_rx_connectivity_stats(adapter); + status = hdd_get_next_adapter(hdd_ctx, adapter, &pNext); + adapter = pNext; + } + + hdd_exit(); +} + +/** + * hdd_is_tx_allowed() - check if Tx is allowed based on current peer state + * @skb: pointer to OS packet (sk_buff) + * @peer_id: Peer STA ID in peer table + * + * This function gets the peer state from DP and check if it is either + * in OL_TXRX_PEER_STATE_CONN or OL_TXRX_PEER_STATE_AUTH. Only EAP packets + * are allowed when peer_state is OL_TXRX_PEER_STATE_CONN. All packets + * allowed when peer_state is OL_TXRX_PEER_STATE_AUTH. + * + * Return: true if Tx is allowed and false otherwise. + */ +static inline bool hdd_is_tx_allowed(struct sk_buff *skb, uint8_t peer_id) +{ + enum ol_txrx_peer_state peer_state; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + void *peer; + + QDF_BUG(soc); + QDF_BUG(pdev); + + peer = cdp_peer_find_by_local_id(soc, pdev, peer_id); + + if (peer == NULL) { + hdd_err_rl("Unable to find peer entry for staid: %d", peer_id); + return false; + } + + peer_state = cdp_peer_state_get(soc, peer); + if (likely(OL_TXRX_PEER_STATE_AUTH == peer_state)) + return true; + if (OL_TXRX_PEER_STATE_CONN == peer_state && + (ntohs(skb->protocol) == HDD_ETHERTYPE_802_1_X + || IS_HDD_ETHERTYPE_WAI(skb))) + return true; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Invalid peer state for Tx: %d"), peer_state); + return false; +} + +/** + * hdd_tx_rx_is_dns_domain_name_match() - function to check whether dns + * domain name in the received skb matches with the tracking dns domain + * name or not + * + * @skb: pointer to skb + * @adapter: pointer to adapter + * + * Returns: true if matches else false + */ +static bool hdd_tx_rx_is_dns_domain_name_match(struct sk_buff *skb, + struct hdd_adapter *adapter) +{ + uint8_t *domain_name; + + if (adapter->track_dns_domain_len == 0) + return false; + + /* check OOB , is strncmp accessing data more than skb->len */ + if ((adapter->track_dns_domain_len + + QDF_NBUF_PKT_DNS_NAME_OVER_UDP_OFFSET) > qdf_nbuf_len(skb)) + return false; + + domain_name = qdf_nbuf_get_dns_domain_name(skb, + adapter->track_dns_domain_len); + if (strncmp(domain_name, adapter->dns_payload, + adapter->track_dns_domain_len) == 0) + return true; + else + return false; +} + +void hdd_tx_rx_collect_connectivity_stats_info(struct sk_buff *skb, + void *context, + enum connectivity_stats_pkt_status action, + uint8_t *pkt_type) +{ + uint32_t pkt_type_bitmap; + struct hdd_adapter *adapter = NULL; + + adapter = (struct hdd_adapter *)context; + if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); + return; + } + + /* ARP tracking is done already. */ + pkt_type_bitmap = adapter->pkt_type_bitmap; + pkt_type_bitmap &= ~CONNECTIVITY_CHECK_SET_ARP; + + if (!pkt_type_bitmap) + return; + + switch (action) { + case PKT_TYPE_REQ: + case PKT_TYPE_TX_HOST_FW_SENT: + if (qdf_nbuf_is_icmp_pkt(skb)) { + if (qdf_nbuf_data_is_icmpv4_req(skb) && + (adapter->track_dest_ipv4 == + qdf_nbuf_get_icmpv4_tgt_ip(skb))) { + *pkt_type = CONNECTIVITY_CHECK_SET_ICMPV4; + if (action == PKT_TYPE_REQ) { + ++adapter->hdd_stats.hdd_icmpv4_stats. + tx_icmpv4_req_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ICMPv4 Req packet", + __func__); + } else + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_icmpv4_stats. + tx_host_fw_sent; + } + } else if (qdf_nbuf_is_ipv4_tcp_pkt(skb)) { + if (qdf_nbuf_data_is_tcp_syn(skb) && + (adapter->track_dest_port == + qdf_nbuf_data_get_tcp_dst_port(skb))) { + *pkt_type = CONNECTIVITY_CHECK_SET_TCP_SYN; + if (action == PKT_TYPE_REQ) { + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP Syn packet", + __func__); + } else + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_syn_host_fw_sent; + } else if ((adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv || adapter->hdd_stats. + hdd_tcp_stats.is_tcp_ack_sent) && + qdf_nbuf_data_is_tcp_ack(skb) && + (adapter->track_dest_port == + qdf_nbuf_data_get_tcp_dst_port(skb))) { + *pkt_type = CONNECTIVITY_CHECK_SET_TCP_ACK; + if (action == PKT_TYPE_REQ && + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv) { + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_count; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv = false; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_ack_sent = true; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP Ack packet", + __func__); + } else if (action == PKT_TYPE_TX_HOST_FW_SENT && + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_ack_sent) { + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_tcp_stats. + tx_tcp_ack_host_fw_sent; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_ack_sent = false; + } + } + } else if (qdf_nbuf_is_ipv4_udp_pkt(skb)) { + if (qdf_nbuf_data_is_dns_query(skb) && + hdd_tx_rx_is_dns_domain_name_match(skb, adapter)) { + *pkt_type = CONNECTIVITY_CHECK_SET_DNS; + if (action == PKT_TYPE_REQ) { + ++adapter->hdd_stats.hdd_dns_stats. + tx_dns_req_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : DNS query packet", + __func__); + } else + /* host receives tx completion */ + ++adapter->hdd_stats.hdd_dns_stats. + tx_host_fw_sent; + } + } + break; + + case PKT_TYPE_RSP: + if (qdf_nbuf_is_icmp_pkt(skb)) { + if (qdf_nbuf_data_is_icmpv4_rsp(skb) && + (adapter->track_dest_ipv4 == + qdf_nbuf_get_icmpv4_src_ip(skb))) { + ++adapter->hdd_stats.hdd_icmpv4_stats. + rx_icmpv4_rsp_count; + *pkt_type = + CONNECTIVITY_CHECK_SET_ICMPV4; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ICMPv4 Res packet", __func__); + } + } else if (qdf_nbuf_is_ipv4_tcp_pkt(skb)) { + if (qdf_nbuf_data_is_tcp_syn_ack(skb) && + (adapter->track_dest_port == + qdf_nbuf_data_get_tcp_src_port(skb))) { + ++adapter->hdd_stats.hdd_tcp_stats. + rx_tcp_syn_ack_count; + adapter->hdd_stats.hdd_tcp_stats. + is_tcp_syn_ack_rcv = true; + *pkt_type = + CONNECTIVITY_CHECK_SET_TCP_SYN_ACK; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP Syn ack packet", __func__); + } + } else if (qdf_nbuf_is_ipv4_udp_pkt(skb)) { + if (qdf_nbuf_data_is_dns_response(skb) && + hdd_tx_rx_is_dns_domain_name_match(skb, adapter)) { + ++adapter->hdd_stats.hdd_dns_stats. + rx_dns_rsp_count; + *pkt_type = CONNECTIVITY_CHECK_SET_DNS; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : DNS response packet", __func__); + } + } + break; + + case PKT_TYPE_TX_DROPPED: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.tx_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ICMPv4 Req packet dropped", __func__); + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP syn packet dropped", __func__); + break; + case CONNECTIVITY_CHECK_SET_TCP_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : TCP ack packet dropped", __func__); + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.tx_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : DNS query packet dropped", __func__); + break; + default: + break; + } + break; + case PKT_TYPE_RX_DELIVERED: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.rx_delivered; + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.rx_delivered; + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.rx_delivered; + break; + default: + break; + } + break; + case PKT_TYPE_RX_REFUSED: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.rx_refused; + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.rx_refused; + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.rx_refused; + break; + default: + break; + } + break; + case PKT_TYPE_TX_ACK_CNT: + switch (*pkt_type) { + case CONNECTIVITY_CHECK_SET_ICMPV4: + ++adapter->hdd_stats.hdd_icmpv4_stats.tx_ack_cnt; + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_syn_ack_cnt; + break; + case CONNECTIVITY_CHECK_SET_TCP_ACK: + ++adapter->hdd_stats.hdd_tcp_stats.tx_tcp_ack_ack_cnt; + break; + case CONNECTIVITY_CHECK_SET_DNS: + ++adapter->hdd_stats.hdd_dns_stats.tx_ack_cnt; + break; + default: + break; + } + break; + default: + break; + } +} + +/** + * __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: Always returns NETDEV_TX_OK + */ +static netdev_tx_t __hdd_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + QDF_STATUS status; + sme_ac_enum_type ac; + enum sme_qos_wmmuptype up; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + bool granted; + uint8_t STAId; + struct hdd_station_ctx *sta_ctx = &adapter->session.station; + struct qdf_mac_addr *mac_addr; + uint8_t pkt_type = 0; + bool is_arp = false; + struct wlan_objmgr_vdev *vdev; + +#ifdef QCA_WIFI_FTM + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + kfree_skb(skb); + return NETDEV_TX_OK; + } +#endif + + ++adapter->hdd_stats.tx_rx_stats.tx_called; + adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() || + cds_is_load_or_unload_in_progress()) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "Recovery/(Un)load in progress, dropping the packet"); + goto drop_pkt; + } + + wlan_hdd_classify_pkt(skb); + if (QDF_NBUF_CB_GET_PACKET_TYPE(skb) == QDF_NBUF_CB_PACKET_TYPE_ARP) { + is_arp = true; + if (qdf_nbuf_data_is_arp_req(skb) && + (adapter->track_arp_ip == qdf_nbuf_get_arp_tgt_ip(skb))) { + ++adapter->hdd_stats.hdd_arp_stats.tx_arp_req_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ARP packet", __func__); + } + } + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info(skb, adapter, + PKT_TYPE_REQ, &pkt_type); + + if (cds_is_driver_recovering()) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_WARN, + "Recovery in progress, dropping the packet"); + goto drop_pkt; + } + + STAId = HDD_WLAN_INVALID_STA_ID; + + hdd_get_transmit_sta_id(adapter, skb, &STAId); + if (STAId >= WLAN_MAX_STA_COUNT) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "Invalid station id, transmit operation suspended"); + goto drop_pkt; + } + + hdd_get_tx_resource(adapter, STAId, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + + if (!qdf_nbuf_ipa_owned_get(skb)) { + skb = hdd_skb_orphan(adapter, skb); + if (!skb) + goto drop_pkt_accounting; + } + + /* + * Add SKB to internal tracking table before further processing + * in WLAN driver. + */ + qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__); + + /* + * user priority from IP header, which is already extracted and set from + * select_queue call back function + */ + up = skb->priority; + + ++adapter->hdd_stats.tx_rx_stats.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 artifically boosted higher qos priority. + */ + + if (((adapter->psb_changed & (1 << ac)) && + likely(adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessAllowed)) || + ((sta_ctx->conn_info.uIsAuthenticated == false) && + (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 isDefaultAc = 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.wmmAcStatus[ac]. + wmmAcAccessAllowed)) { + 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; + isDefaultAc = true; + break; + } + if (isDefaultAc) + break; + } + skb->priority = up; + skb->queue_mapping = hdd_linux_up_to_ac_map[up]; + } + + adapter->stats.tx_bytes += skb->len; + + mac_addr = (struct qdf_mac_addr *)skb->data; + + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + ucfg_tdls_update_tx_pkt_cnt(vdev, mac_addr); + hdd_objmgr_put_vdev(vdev); + } + + if (qdf_nbuf_is_tso(skb)) + adapter->stats.tx_packets += qdf_nbuf_get_tso_num_seg(skb); + else + ++adapter->stats.tx_packets; + + hdd_event_eapol_log(skb, QDF_TX); + QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, QDF_NBUF_TX_PKT_HDD); + + qdf_dp_trace_set_track(skb, QDF_TX); + + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, qdf_nbuf_data_addr(skb), + sizeof(qdf_nbuf_data(skb)), + QDF_TX)); + + if (!hdd_is_tx_allowed(skb, STAId)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Tx not allowed for sta_id: %d"), STAId); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + + /* check whether need to linearize skb, like non-linear udp data */ + if (hdd_skb_nontso_linearize(skb) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: skb %pK linearize failed. drop the pkt", + __func__, skb); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + + /* + * If a transmit function is not registered, drop packet + */ + if (!adapter->tx_fn) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: TX function not registered by the data path", + __func__); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + + if (adapter->tx_fn(adapter->txrx_vdev, + (qdf_nbuf_t)skb) != NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to send packet to txrx for staid: %d", + __func__, STAId); + ++adapter->hdd_stats.tx_rx_stats.tx_dropped_ac[ac]; + goto drop_pkt_and_release_skb; + } + + netif_trans_update(dev); + + return NETDEV_TX_OK; + +drop_pkt_and_release_skb: + qdf_net_buf_debug_release_skb(skb); +drop_pkt: + + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info(skb, adapter, + PKT_TYPE_TX_DROPPED, + &pkt_type); + qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_DROP_PACKET_RECORD, 0, + QDF_TX); + kfree_skb(skb); + +drop_pkt_accounting: + + ++adapter->stats.tx_dropped; + ++adapter->hdd_stats.tx_rx_stats.tx_dropped; + if (is_arp) { + ++adapter->hdd_stats.hdd_arp_stats.tx_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ARP packet dropped", __func__); + } + + return NETDEV_TX_OK; +} + +/** + * hdd_hard_start_xmit() - Wrapper function to protect + * __hdd_hard_start_xmit from SSR + * @skb: pointer to OS packet + * @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 *dev) +{ + netdev_tx_t ret; + + cds_ssr_protect(__func__); + ret = __hdd_hard_start_xmit(skb, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_get_peer_sta_id() - Get the StationID using the Peer Mac address + * @sta_ctx: pointer to HDD Station Context + * @pMacAddress: pointer to Peer Mac address + * @staID: pointer to returned Station Index + * + * Return: QDF_STATUS_SUCCESS/QDF_STATUS_E_FAILURE + */ + +QDF_STATUS hdd_get_peer_sta_id(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *pMacAddress, uint8_t *staId) +{ + uint8_t idx; + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (!qdf_mem_cmp(&sta_ctx->conn_info.peerMacAddress[idx], + pMacAddress, QDF_MAC_ADDR_SIZE)) { + *staId = sta_ctx->conn_info.staId[idx]; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} + +/** + * __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; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + u64 diff_jiffies; + 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_info("Queue: %d status: %d txq->trans_start: %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } + + hdd_info("carrier state: %d", netif_carrier_ok(dev)); + + wlan_hdd_display_netif_queue_history(hdd_ctx, + QDF_STATS_VERBOSITY_LEVEL_HIGH); + cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); + + ++adapter->hdd_stats.tx_rx_stats.tx_timeout_cnt; + ++adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt; + + diff_jiffies = jiffies - + adapter->hdd_stats.tx_rx_stats.jiffies_last_txtimeout; + + if ((adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt > 1) && + (diff_jiffies > (HDD_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 kernel will call the tx time-out back to back + * at interval of HDD_TX_TIMEOUT. Here now check if previous + * TX TIME out has occurred more than twice of HDD_TX_TIMEOUT + * back then host may recovered here from data stall. + */ + adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "Reset continuous tx timeout stat"); + } + + adapter->hdd_stats.tx_rx_stats.jiffies_last_txtimeout = jiffies; + + if (adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt > + HDD_TX_STALL_THRESHOLD) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Data stall due to continuous TX timeouts"); + adapter->hdd_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + if (hdd_ctx->config->enable_data_stall_det) + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_HOST_DRIVER, + DATA_STALL_LOG_HOST_STA_TX_TIMEOUT, + 0xFF, 0xFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } +} + +/** + * hdd_tx_timeout() - Wrapper function to protect __hdd_tx_timeout from SSR + * @dev: pointer to net_device structure + * + * 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 + */ +void hdd_tx_timeout(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_tx_timeout(dev); + cds_ssr_unprotect(__func__); +} + +/** + * @hdd_init_tx_rx() - Initialize Tx/RX module + * @adapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_init_tx_rx(struct hdd_adapter *adapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == adapter) { + hdd_err("adapter is NULL"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * @hdd_deinit_tx_rx() - Deinitialize Tx/RX module + * @adapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_deinit_tx_rx(struct hdd_adapter *adapter) +{ + QDF_BUG(adapter); + if (!adapter) + return QDF_STATUS_E_FAILURE; + + adapter->txrx_vdev = NULL; + adapter->tx_fn = NULL; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * hdd_mon_rx_packet_cbk() - Receive callback registered with OL layer. + * @context: [in] pointer to qdf context + * @rxBuf: [in] 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_E_FAILURE if any errors encountered, QDF_STATUS_SUCCESS + * otherwise + */ +static QDF_STATUS hdd_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf) +{ + struct hdd_adapter *adapter; + int rxstat; + struct sk_buff *skb; + struct sk_buff *skb_next; + unsigned int cpu_index; + + /* Sanity check on inputs */ + if ((NULL == context) || (NULL == rxbuf)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + adapter = (struct hdd_adapter *)context; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "invalid adapter %pK", adapter); + return QDF_STATUS_E_FAILURE; + } + + cpu_index = wlan_hdd_get_cpu(); + + /* walk the chain until all are processed */ + skb = (struct sk_buff *) rxbuf; + while (NULL != skb) { + skb_next = skb->next; + skb->dev = adapter->dev; + + ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index]; + ++adapter->stats.rx_packets; + adapter->stats.rx_bytes += skb->len; + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(skb); + + /* + * If this is not a last packet on the chain + * Just put packet into backlog queue, not scheduling RX sirq + */ + if (skb->next) { + rxstat = netif_rx(skb); + } else { + /* + * This is the last packet on the chain + * Scheduling rx sirq + */ + rxstat = netif_rx_ni(skb); + } + + if (NET_RX_SUCCESS == rxstat) + ++adapter-> + hdd_stats.tx_rx_stats.rx_delivered[cpu_index]; + else + ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index]; + + skb = skb_next; + } + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_get_peer_idx() - Get the idx for given address in peer table + * @sta_ctx: pointer to HDD Station Context + * @addr: pointer to Peer Mac address + * + * Return: index when success else INVALID_PEER_IDX + */ +int hdd_get_peer_idx(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *addr) +{ + uint8_t idx; + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (sta_ctx->conn_info.staId[idx] == HDD_WLAN_INVALID_STA_ID) + continue; + if (qdf_mem_cmp(&sta_ctx->conn_info.peerMacAddress[idx], + addr, sizeof(struct qdf_mac_addr))) + continue; + return idx; + } + + return INVALID_PEER_IDX; +} + +/* + * hdd_is_mcast_replay() - checks if pkt is multicast replay + * @skb: packet skb + * + * Return: true if replayed multicast pkt, false otherwise + */ +static bool hdd_is_mcast_replay(struct sk_buff *skb) +{ + struct ethhdr *eth; + + eth = eth_hdr(skb); + if (unlikely(skb->pkt_type == PACKET_MULTICAST)) { + if (unlikely(ether_addr_equal(eth->h_source, + skb->dev->dev_addr))) + return true; + } + return false; +} + +/** + * hdd_is_arp_local() - check if local or non local arp + * @skb: pointer to sk_buff + * + * Return: true if local arp or false otherwise. + */ +static bool hdd_is_arp_local(struct sk_buff *skb) +{ + struct arphdr *arp; + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + struct in_device *in_dev; + unsigned char *arp_ptr; + __be32 tip; + + arp = (struct arphdr *)skb->data; + if (arp->ar_op == htons(ARPOP_REQUEST)) { + in_dev = __in_dev_get_rtnl(skb->dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (!strcmp(skb->dev->name, ifa->ifa_label)) + break; + } + } + + if (ifa && ifa->ifa_local) { + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += (skb->dev->addr_len + 4 + + skb->dev->addr_len); + memcpy(&tip, arp_ptr, 4); + hdd_debug("ARP packet: local IP: %x dest IP: %x", + ifa->ifa_local, tip); + if (ifa->ifa_local == tip) + return true; + } + } + + return false; +} + +/** + * hdd_is_rx_wake_lock_needed() - check if wake lock is needed + * @skb: pointer to sk_buff + * + * RX wake lock is needed for: + * 1) Unicast data packet OR + * 2) Local ARP data packet + * + * Return: true if wake lock is needed or false otherwise. + */ +static bool hdd_is_rx_wake_lock_needed(struct sk_buff *skb) +{ + if ((skb->pkt_type != PACKET_BROADCAST && + skb->pkt_type != PACKET_MULTICAST) || hdd_is_arp_local(skb)) + return true; + + return false; +} + +#ifdef RECEIVE_OFFLOAD +/** + * hdd_resolve_rx_ol_mode() - Resolve Rx offload method, LRO or GRO + * @hdd_ctx: pointer to HDD Station Context + * + * Return: None + */ +static void hdd_resolve_rx_ol_mode(struct hdd_context *hdd_ctx) +{ + if (!(hdd_ctx->config->lro_enable ^ + hdd_ctx->config->gro_enable)) { +#ifdef WLAN_DEBUG + hdd_ctx->config->lro_enable && hdd_ctx->config->gro_enable ? + hdd_err("Can't enable both LRO and GRO, disabling Rx offload") : + hdd_debug("LRO and GRO both are disabled"); +#endif + hdd_ctx->ol_enable = 0; + } else if (hdd_ctx->config->lro_enable) { + hdd_debug("Rx offload LRO is enabled"); + hdd_ctx->ol_enable = CFG_LRO_ENABLED; + } else { + hdd_debug("Rx offload GRO is enabled"); + hdd_ctx->ol_enable = CFG_GRO_ENABLED; + } +} + +/** + * hdd_gro_rx() - Handle Rx procesing via GRO + * @adapter: pointer to adapter context + * @skb: pointer to sk_buff + * + * Return: QDF_STATUS_SUCCESS if processed via GRO or non zero return code + */ +static QDF_STATUS hdd_gro_rx(struct hdd_adapter *adapter, struct sk_buff *skb) +{ + struct qca_napi_info *qca_napii; + struct qca_napi_data *napid; + struct napi_struct *napi_to_use; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + /* Only enabling it for STA mode like LRO today */ + if (QDF_STA_MODE != adapter->device_mode) + return QDF_STATUS_E_NOSUPPORT; + + napid = hdd_napi_get_all(); + if (unlikely(napid == NULL)) + goto out; + + qca_napii = hif_get_napi(QDF_NBUF_CB_RX_CTX_ID(skb), napid); + if (unlikely(qca_napii == NULL)) + goto out; + + skb_set_hash(skb, QDF_NBUF_CB_RX_FLOW_ID(skb), PKT_HASH_TYPE_L4); + /* + * As we are breaking context in Rxthread mode, there is rx_thread NAPI + * corresponds each hif_napi. + */ + if (adapter->hdd_ctx->enable_rxthread) + napi_to_use = &qca_napii->rx_thread_napi; + else + napi_to_use = &qca_napii->napi; + + local_bh_disable(); + napi_gro_receive(napi_to_use, skb); + local_bh_enable(); + + status = QDF_STATUS_SUCCESS; +out: + + return status; +} + +/** + * hdd_rxthread_napi_gro_flush() - GRO flush callback for NAPI+Rx_Thread Rx mode + * @data: hif NAPI context + * + * Return: none + */ +static void hdd_rxthread_napi_gro_flush(void *data) +{ + struct qca_napi_info *qca_napii = (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. + */ + napi_gro_flush(&qca_napii->rx_thread_napi, false); + local_bh_enable(); +} + +/** + * hdd_hif_napi_gro_flush() - GRO flush callback for NAPI Rx mode + * @data: hif NAPI context + * + * Return: none + */ +static void hdd_hif_napi_gro_flush(void *data) +{ + struct qca_napi_info *qca_napii = (struct qca_napi_info *)data; + + local_bh_disable(); + napi_gro_flush(&qca_napii->napi, false); + local_bh_enable(); +} + +#ifdef FEATURE_LRO +/** + * hdd_qdf_lro_flush() - LRO flush wrapper + * @data: hif NAPI context + * + * Return: none + */ +static void hdd_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); +} +#else +static void hdd_qdf_lro_flush(void *data) +{ +} +#endif + +/** + * hdd_register_rx_ol() - Register LRO/GRO rx processing callbacks + * + * Return: none + */ +static void hdd_register_rx_ol(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return; + } + + hdd_ctx->en_tcp_delack_no_lro = 0; + + if (hdd_ctx->ol_enable == CFG_LRO_ENABLED) { + cdp_register_rx_offld_flush_cb(soc, hdd_qdf_lro_flush); + hdd_ctx->receive_offload_cb = hdd_lro_rx; + hdd_debug("LRO is enabled"); + } else if (hdd_ctx->ol_enable == CFG_GRO_ENABLED) { + if (hdd_ctx->enable_rxthread) + cdp_register_rx_offld_flush_cb(soc, + hdd_rxthread_napi_gro_flush); + else + cdp_register_rx_offld_flush_cb(soc, + hdd_hif_napi_gro_flush); + hdd_ctx->receive_offload_cb = hdd_gro_rx; + hdd_debug("GRO is enabled"); + } else if (HDD_MSM_CFG(hdd_ctx->config->enable_tcp_delack)) { + hdd_ctx->en_tcp_delack_no_lro = 1; + } +} + +int hdd_rx_ol_init(struct hdd_context *hdd_ctx) +{ + struct cdp_lro_hash_config lro_config = {0}; + + hdd_resolve_rx_ol_mode(hdd_ctx); + + hdd_register_rx_ol(); + + /* + * This will enable flow steering and Toeplitz hash + * So enable it for LRO or GRO processing. + */ + if (hdd_napi_enabled(HDD_NAPI_ANY) == 0) { + hdd_warn("NAPI is disabled"); + return 0; + } + + lro_config.lro_enable = 1; + lro_config.tcp_flag = TCPHDR_ACK; + lro_config.tcp_flag_mask = TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST | + TCPHDR_ACK | TCPHDR_URG | TCPHDR_ECE | TCPHDR_CWR; + + get_random_bytes(lro_config.toeplitz_hash_ipv4, + (sizeof(lro_config.toeplitz_hash_ipv4[0]) * + LRO_IPV4_SEED_ARR_SZ)); + + get_random_bytes(lro_config.toeplitz_hash_ipv6, + (sizeof(lro_config.toeplitz_hash_ipv6[0]) * + LRO_IPV6_SEED_ARR_SZ)); + + if (0 != wma_lro_init(&lro_config)) { + hdd_err("Failed to send LRO/GRO configuration!"); + hdd_ctx->ol_enable = 0; + return -EAGAIN; + } + + return 0; +} + +void hdd_disable_rx_ol_in_concurrency(bool disable) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + if (disable) { + if (HDD_MSM_CFG(hdd_ctx->config->enable_tcp_delack)) { + struct wlan_rx_tp_data rx_tp_data; + + hdd_info("Enable TCP delack as LRO disabled in concurrency"); + rx_tp_data.rx_tp_flags = TCP_DEL_ACK_IND; + rx_tp_data.level = GET_CUR_RX_LVL(hdd_ctx); + wlan_hdd_update_tcp_rx_param(hdd_ctx, &rx_tp_data); + hdd_ctx->en_tcp_delack_no_lro = 1; + } + qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 1); + } else { + if (HDD_MSM_CFG(hdd_ctx->config->enable_tcp_delack)) { + hdd_info("Disable TCP delack as LRO is enabled"); + hdd_ctx->en_tcp_delack_no_lro = 0; + hdd_reset_tcp_delack(hdd_ctx); + } + qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 0); + } +} + +void hdd_disable_rx_ol_for_low_tput(struct hdd_context *hdd_ctx, bool disable) +{ + if (disable) + qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 1); + else + qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 0); +} + +/** + * hdd_can_handle_receive_offload() - Check for dynamic disablement + * @hdd_ctx: hdd context + * @skb: pointer to sk_buff which will be processed by Rx OL + * + * Check for dynamic disablement of Rx offload + * + * Return: false if we cannot process otherwise true + */ +static bool hdd_can_handle_receive_offload(struct hdd_context *hdd_ctx, + struct sk_buff *skb) +{ + if (!hdd_ctx->receive_offload_cb) + return false; + + if (!QDF_NBUF_CB_RX_TCP_PROTO(skb) || + qdf_atomic_read(&hdd_ctx->disable_lro_in_concurrency) || + QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb) || + qdf_atomic_read(&hdd_ctx->disable_lro_in_low_tput)) + return false; + else + return true; +} +#else /* RECEIVE_OFFLOAD */ +static bool hdd_can_handle_receive_offload(struct hdd_context *hdd_ctx, + struct sk_buff *skb) +{ + return false; +} + +int hdd_rx_ol_init(struct hdd_context *hdd_ctx) +{ + hdd_err("Rx_OL, LRO/GRO not supported"); + return -EPERM; +} + +void hdd_disable_rx_ol_in_concurrency(bool disable) +{ +} + +void hdd_disable_rx_ol_for_low_tput(struct hdd_context *hdd_ctx, bool disable) +{ +} +#endif /* RECEIVE_OFFLOAD */ + +#ifdef WLAN_FEATURE_TSF_PLUS +static inline void hdd_tsf_timestamp_rx(struct hdd_context *hdd_ctx, + qdf_nbuf_t netbuf, + uint64_t target_time) +{ + if (!hdd_tsf_is_rx_set(hdd_ctx)) + return; + + hdd_rx_timestamp(netbuf, target_time); +} +#else +static inline void hdd_tsf_timestamp_rx(struct hdd_context *hdd_ctx, + qdf_nbuf_t netbuf, + uint64_t target_time) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) +static bool hdd_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb) +{ + return false; +} +#else +static bool hdd_is_gratuitous_arp_unsolicited_na(struct sk_buff *skb) +{ + return cfg80211_is_gratuitous_arp_unsolicited_na(skb); +} +#endif + +/** + * hdd_rx_packet_cbk() - Receive packet handler + * @context: pointer to HDD context + * @rxBuf: pointer to rx qdf_nbuf + * + * Receive callback registered with TL. TL will call this to notify + * the HDD 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 hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_context *hdd_ctx = NULL; + int rxstat = 0; + QDF_STATUS rx_ol_status = QDF_STATUS_E_FAILURE; + struct sk_buff *skb = NULL; + struct sk_buff *next = NULL; + struct hdd_station_ctx *sta_ctx = NULL; + unsigned int cpu_index; + struct qdf_mac_addr *mac_addr, *dest_mac_addr; + bool wake_lock = false; + uint8_t pkt_type = 0; + bool track_arp = false; + struct wlan_objmgr_vdev *vdev; + + /* Sanity check on inputs */ + if (unlikely((NULL == context) || (NULL == rxBuf))) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + adapter = (struct hdd_adapter *)context; + if (unlikely(WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); + return QDF_STATUS_E_FAILURE; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (unlikely(NULL == hdd_ctx)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: HDD context is Null", __func__); + return QDF_STATUS_E_FAILURE; + } + + cpu_index = wlan_hdd_get_cpu(); + + next = (struct sk_buff *)rxBuf; + + while (next) { + skb = next; + next = skb->next; + skb->next = NULL; + +#ifdef QCA_WIFI_QCA6290 /* Debug code, remove later */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: skb %pK skb->len %d\n", __func__, skb, skb->len); +#endif + if (QDF_NBUF_CB_PACKET_TYPE_ARP == + QDF_NBUF_CB_GET_PACKET_TYPE(skb)) { + if (qdf_nbuf_data_is_arp_rsp(skb) && + (adapter->track_arp_ip == + qdf_nbuf_get_arp_src_ip(skb))) { + ++adapter->hdd_stats.hdd_arp_stats. + rx_arp_rsp_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO, + "%s: ARP packet received", + __func__); + track_arp = true; + } + } + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info(skb, adapter, + PKT_TYPE_RSP, &pkt_type); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((sta_ctx->conn_info.proxyARPService) && + hdd_is_gratuitous_arp_unsolicited_na(skb)) { + qdf_atomic_inc(&adapter->hdd_stats.tx_rx_stats. + rx_usolict_arp_n_mcast_drp); + /* Remove SKB from internal tracking table before + * submitting it to stack. + */ + qdf_nbuf_free(skb); + continue; + } + + hdd_event_eapol_log(skb, QDF_RX); + qdf_dp_trace_log_pkt(adapter->session_id, skb, QDF_RX, + QDF_TRACE_DEFAULT_PDEV_ID); + + DPTRACE(qdf_dp_trace(skb, + QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(skb), + sizeof(qdf_nbuf_data(skb)), QDF_RX)); + + DPTRACE(qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_RX_PACKET_RECORD, + 0, QDF_RX)); + + dest_mac_addr = (struct qdf_mac_addr *)(skb->data); + mac_addr = (struct qdf_mac_addr *)(skb->data+QDF_MAC_ADDR_SIZE); + + if (!hdd_is_current_high_throughput(hdd_ctx)) { + vdev = hdd_objmgr_get_vdev(adapter); + if (vdev) { + ucfg_tdls_update_rx_pkt_cnt(vdev, + mac_addr, + dest_mac_addr); + hdd_objmgr_put_vdev(vdev); + } + } + + skb->dev = adapter->dev; + skb->protocol = eth_type_trans(skb, skb->dev); + ++adapter->hdd_stats.tx_rx_stats.rx_packets[cpu_index]; + ++adapter->stats.rx_packets; + adapter->stats.rx_bytes += skb->len; + + /* Incr GW Rx count for NUD tracking based on GW mac addr */ + hdd_nud_incr_gw_rx_pkt_cnt(adapter, mac_addr); + + /* Check & drop replayed mcast packets (for IPV6) */ + if (hdd_ctx->config->multicast_replay_filter && + hdd_is_mcast_replay(skb)) { + qdf_atomic_inc(&adapter->hdd_stats.tx_rx_stats. + rx_usolict_arp_n_mcast_drp); + qdf_nbuf_free(skb); + continue; + } + + /* hold configurable wakelock for unicast traffic */ + if (!hdd_is_current_high_throughput(hdd_ctx) && + hdd_ctx->config->rx_wakelock_timeout && + sta_ctx->conn_info.uIsAuthenticated) + wake_lock = hdd_is_rx_wake_lock_needed(skb); + + if (wake_lock) { + cds_host_diag_log_work(&hdd_ctx->rx_wake_lock, + hdd_ctx->config->rx_wakelock_timeout, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); + qdf_wake_lock_timeout_acquire(&hdd_ctx->rx_wake_lock, + hdd_ctx->config-> + rx_wakelock_timeout); + } + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(skb); + + hdd_tsf_timestamp_rx(hdd_ctx, skb, ktime_to_us(skb->tstamp)); + + if (hdd_can_handle_receive_offload(hdd_ctx, skb)) + rx_ol_status = hdd_ctx->receive_offload_cb(adapter, + skb); + + if (rx_ol_status != QDF_STATUS_SUCCESS) { + /* we should optimize this per packet check, unlikely */ + /* Account for GRO/LRO ineligible packets, mostly UDP */ + hdd_ctx->no_rx_offload_pkt_cnt++; + if (hdd_napi_enabled(HDD_NAPI_ANY) && + !hdd_ctx->enable_rxthread && + !QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb)) { + rxstat = netif_receive_skb(skb); + } else { + local_bh_disable(); + rxstat = netif_receive_skb(skb); + local_bh_enable(); + } + } + + if (!rxstat) { + ++adapter->hdd_stats.tx_rx_stats. + rx_delivered[cpu_index]; + if (track_arp) + ++adapter->hdd_stats.hdd_arp_stats. + rx_delivered; + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info( + skb, adapter, + PKT_TYPE_RX_DELIVERED, &pkt_type); + } else { + ++adapter->hdd_stats.tx_rx_stats.rx_refused[cpu_index]; + if (track_arp) + ++adapter->hdd_stats.hdd_arp_stats.rx_refused; + + /* track connectivity stats */ + if (adapter->pkt_type_bitmap) + hdd_tx_rx_collect_connectivity_stats_info( + skb, adapter, + PKT_TYPE_RX_REFUSED, &pkt_type); + + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * 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_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_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_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 + * + * 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; + } + } + +} + +/** + * wlan_hdd_stop_non_priority_queue() - stop non prority queues + * @adapter: adapter handle + * + * Return: None + */ +static inline void wlan_hdd_stop_non_priority_queue(struct hdd_adapter *adapter) +{ + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK); +} + +/** + * wlan_hdd_wake_non_priority_queue() - wake non prority queues + * @adapter: adapter handle + * + * Return: None + */ +static inline void wlan_hdd_wake_non_priority_queue(struct hdd_adapter *adapter) +{ + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_VO); + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_VI); + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_BE); + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_BK); +} + +/** + * 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; + + if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) || + (!adapter->dev)) { + hdd_err("adapter is invalid"); + return; + } + + 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); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO); + 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); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO); + 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_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; + + 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; + adapter->queue_oper_history[index].pause_map = adapter->pause_map; +} + +#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}; + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_mon_rx_packet_cbk; + hdd_monitor_set_rx_monitor_cb(&txrx_ops, hdd_rx_monitor_callback); + cdp_vdev_register(soc, + (struct cdp_vdev *)cdp_get_vdev_from_vdev_id(soc, + (struct cdp_pdev *)pdev, adapter->session_id), + adapter, &txrx_ops); + /* peer is created wma_vdev_attach->wma_create_peer */ + qdf_status = cdp_peer_register(soc, + (struct cdp_pdev *)pdev, &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); + 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 + +/** + * hdd_send_rps_ind() - send rps indication to daemon + * @adapter: adapter context + * + * 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 hdd_send_rps_ind(struct hdd_adapter *adapter) +{ + int i; + uint8_t cpu_map_list_len = 0; + struct hdd_context *hdd_ctxt = NULL; + struct wlan_rps_data rps_data; + struct cds_config_info *cds_cfg; + + cds_cfg = cds_get_ini_config(); + + if (!adapter) { + hdd_err("adapter is NULL"); + return; + } + + if (!cds_cfg) { + hdd_err("cds_cfg is NULL"); + return; + } + + hdd_ctxt = WLAN_HDD_GET_CTX(adapter); + rps_data.num_queues = NUM_TX_QUEUES; + + hdd_info("cpu_map_list '%s'", hdd_ctxt->config->cpu_map_list); + + /* in case no cpu map list is provided, simply return */ + if (!strlen(hdd_ctxt->config->cpu_map_list)) { + hdd_err("no cpu map list found"); + goto err; + } + + if (QDF_STATUS_SUCCESS != + hdd_hex_string_to_u16_array(hdd_ctxt->config->cpu_map_list, + rps_data.cpu_map_list, + &cpu_map_list_len, + WLAN_SVC_IFACE_NUM_QUEUES)) { + hdd_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++) { + hdd_info("cpu_map_list[%d] = 0x%x", + i, rps_data.cpu_map_list[i]); + } + + strlcpy(rps_data.ifname, adapter->dev->name, + sizeof(rps_data.ifname)); + wlan_hdd_send_svc_nlink_msg(hdd_ctxt->radio_index, + WLAN_SVC_RPS_ENABLE_IND, + &rps_data, sizeof(rps_data)); + + cds_cfg->rps_enabled = true; + + return; + +err: + hdd_err("Wrong RPS configuration. enabling rx_thread"); + cds_cfg->rps_enabled = false; +} + +/** + * hdd_send_rps_disable_ind() - send rps disable indication to daemon + * @adapter: adapter context + * + * Return: none + */ +void hdd_send_rps_disable_ind(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctxt = NULL; + struct wlan_rps_data rps_data; + struct cds_config_info *cds_cfg; + + cds_cfg = cds_get_ini_config(); + + if (!adapter) { + hdd_err("adapter is NULL"); + return; + } + + if (!cds_cfg) { + hdd_err("cds_cfg is NULL"); + return; + } + + hdd_ctxt = WLAN_HDD_GET_CTX(adapter); + rps_data.num_queues = NUM_TX_QUEUES; + + hdd_info("Set cpu_map_list 0"); + + qdf_mem_zero(&rps_data.cpu_map_list, sizeof(rps_data.cpu_map_list)); + + strlcpy(rps_data.ifname, adapter->dev->name, sizeof(rps_data.ifname)); + wlan_hdd_send_svc_nlink_msg(hdd_ctxt->radio_index, + WLAN_SVC_RPS_ENABLE_IND, + &rps_data, sizeof(rps_data)); + + cds_cfg->rps_enabled = false; +} + +void hdd_tx_queue_cb(void *context, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)context; + struct hdd_adapter *adapter = NULL; + + /* + * 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 == NULL) { + hdd_err("Invalid context passed"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (adapter == NULL) { + 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(adapter, action, reason); +} + +#ifdef MSM_PLATFORM +/** + * hdd_reset_tcp_delack() - Reset tcp delack value to default + * @hdd_ctx: Handle to hdd context + * + * Function used to reset TCP delack value to its default value + * + * Return: None + */ +void hdd_reset_tcp_delack(struct hdd_context *hdd_ctx) +{ + enum wlan_tp_level next_level = WLAN_SVC_TP_LOW; + struct wlan_rx_tp_data rx_tp_data = {0}; + + rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND; + rx_tp_data.level = next_level; + hdd_ctx->rx_high_ind_cnt = 0; + wlan_hdd_update_tcp_rx_param(hdd_ctx, &rx_tp_data); +} + +/** + * hdd_is_current_high_throughput() - Check if vote level is high + * @hdd_ctx: Handle to hdd context + * + * Function used to check if vote level is high + * + * Return: True if vote level is high + */ +bool hdd_is_current_high_throughput(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->cur_vote_level < PLD_BUS_WIDTH_HIGH) + return false; + else + return true; +} +#endif /* MSM_PLATFORM */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c new file mode 100644 index 0000000000000000000000000000000000000000..69566634ca818d9e5bd05ed1c09b2c5481402bf8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c @@ -0,0 +1,10239 @@ +/* + * 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: wlan_hdd_wext.c + * + * Linux Wireless Extensions Implementation + */ + +#include +#include +#include +#include +#include +#include +#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 "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 "qdf_str.h" +#include "qdf_trace.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_conc_ut.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" +#include "pld_common.h" +#endif +#include "wlan_hdd_lro.h" +#include "cds_utils.h" +#include "wlan_osif_request_manager.h" +#include "os_if_wifi_pos.h" +#include +#include +#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" + +#define HDD_FINISH_ULA_TIME_OUT 800 +#define HDD_SET_MCBC_FILTERS_TO_FW 1 +#define HDD_DELETE_MCBC_FILTERS_FROM_FW 0 + +/* 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 +/* 8 is unused */ +#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 chek 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, IBSS, 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 +#define WE_SET_TXRX_STATS 90 + +/* + * + * 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 + +/* 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 +#define WE_SET_CONFIG 5 + +/* + * + * 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 +#ifdef WLAN_FEATURE_11W +/* + * + * 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 +#endif +#define WE_GET_STATES 10 +/* + * + * getIbssSTAs - get ibss sta info + * + * @INPUT: None + * + * @OUTPUT: Give the MAC of the IBSS STA + * wlan0 getIbssSTAs: + * 1 .8c:fd:f0:01:9c:bf + * + * This IOCTL is used to get ibss sta info + * + * @E.g: iwpriv wlan0 getIbssSTAs + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define WE_GET_IBSS_STA_INFO 11 +/* + * + * 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 + +/* 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 +/* + * + * ibssPeerInfoAll - Print the ibss peers's MAC, rate and RSSI + * + * @INPUT: None + * + * @OUTPUT: print ibss peer in info logs + * pPeerInfo->numIBSSPeers = 1 + * PEER ADDR : 8c:fd:f0:01:9c:bf TxRate: 1 Mbps RSSI: -35 + * + * This IOCTL is used to rint the ibss peers's MAC, rate and RSSI + * in info logs + * + * @E.g: iwpriv wlan0 ibssPeerInfoAll + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define WE_IBSS_GET_PEER_INFO_ALL 10 +/* Sub ioctls 11 to 16 are not used */ +#define WE_GET_RECOVERY_STAT 17 +#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 */ + +/* + * + * ibssPeerInfo - Print the ibss peers's MAC, rate and RSSI + * + * @INPUT: staid + * + * @OUTPUT: print ibss peer corresponding to staid in info logs + * PEER ADDR : 8c:fd:f0:01:9c:bf TxRate: 1 Mbps RSSI: -35 + * + * This IOCTL is used to print the specific ibss peers's MAC, + * rate and RSSI in info logs + * + * @E.g: iwpriv wlan0 ibssPeerInfo + * iwpriv wlan0 ibssPeerInfo 0 + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define WE_IBSS_GET_PEER_INFO 6 +#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 + +/* + * + * pm_clist - Increments the index value of the concurrent connection list + * and update with the input parameters provided. + * + * @INPUT: Following 8 arguments: + * @vdev_id: vdev id + * @tx_streams: TX streams + * @rx_streams: RX streams + * @chain_mask: Chain mask + * @type: vdev_type + * AP:1 STA:2 IBSS:3 Monitor:4 NAN:5 OCB:6 NDI:7 + * @sub_type: vdev_subtype + * P2P_Device:1 P2P_Client:2 P2P_GO:3 + * Proxy_STA:4 Mesh:5 Mesh_11s:6 + * @channel: Channel + * @mac: Mac id + * + * @OUTPUT: None + * + * This IOCTL is used to increments the index value of the concurrent connection + * list and update with the input parameters provided. + * + * @E.g: iwpriv wlan0 pm_clist vdev_id tx_streams rx_streams chain_mask type + * sub_type channel mac + * iwpriv wlan0 pm_clist 1 2 2 1 2 3 10 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_CLIST_CMD 11 + +/* + * + * pm_dlist - Delete the index from the concurrent connection list that is + * present in the given vdev_id. + * + * @INPUT: delete_all, vdev_id + * @delete_all: delete all indices + * @vdev_id: vdev id + * + * @OUTPUT: None + * + * This IOCTL is used to delete the index from the concurrent connection list + * that is present in the given vdev_id. + * + * @E.g: iwpriv wlan0 pm_dlist delete_all vdev_id + * iwpriv wlan0 pm_dlist 0 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_DLIST_CMD 12 + +/* + * + * pm_dbs - Set dbs capability and system preference + * + * @INPUT: dbs, system_pref + * @dbs: Value of DBS capability to be set + * @system_pref: System preference + * 0:PM_THROUGHPUT 1: PM_POWERSAVE 2: PM_LATENCY + * + * @OUTPUT: None + * + * This IOCTL is used to set dbs capability and system preference. + * + * @E.g: iwpriv wlan0 pm_dbs dbs system_pref + * iwpriv wlan0 pm_dbs 1 0 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_DBS_CMD 13 + +/* + * + * pm_pcl - Set pcl for concurrency mode. + * + * @INPUT: policy_mgr_con_mode + * @policy_mgr_con_mode: concurrency mode for PCL table + * 0:STA 1:SAP 2:P2P_Client 3:P2P_GO 4:IBSS + * + * @OUTPUT: None + * + * This IOCTL is used to set pcl for concurrency mode. + * + * @E.g: iwpriv wlan0 pm_pcl policy_mgr_con_mode + * iwpriv wlan0 pm_pcl 0 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_PCL_CMD 14 + +/* + * + * 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 + +/* + * + * pm_ulist - Updates the index value of the concurrent connection list + * with the input parameters provided. + * + * @INPUT: Following 8 arguments: + * @vdev_id: vdev id + * @tx_streams: TX streams + * @rx_streams: RX streams + * @chain_mask: Chain mask + * @type: vdev_type + * AP:1 STA:2 IBSS:3 Monitor:4 NAN:5 OCB:6 NDI:7 + * @sub_type: vdev_subtype + * P2P_Device:1 P2P_Client:2 P2P_GO:3 + * Proxy_STA:4 Mesh:5 Mesh_11s:6 + * @channel: Channel + * @mac: Mac id + * + * @OUTPUT: None + * + * This IOCTL is used to updates the index value of the concurrent + * connection list with the input parameters provided. + * + * @E.g: iwpriv wlan0 pm_ulist vdev_id tx_streams rx_streams chain_mask type + * sub_type channel mac + * iwpriv wlan0 pm_ulist 1 2 2 1 2 3 10 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_ULIST_CMD 16 + +/* + * + * pm_query_action - Initiate actions needed on current connections as + * per the channel provided. + * + * @INPUT: channel + * @channel: Channel on which new connection will be. + * + * @OUTPUT: None + * + * This IOCTL is used to initiate actions needed on current connections + * as per the channel provided. + * + * @E.g: iwpriv wlan0 pm_query_action channel + * iwpriv wlan0 pm_query_action 6 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_QUERY_ACTION_CMD 17 + +/* + * + * pm_query_allow - Checks for allowed concurrency combination + * + * @INPUT: mode, channel, bandwidth + * @mode: new connection mode + * 0:STA 1:SAP 2:P2P_Client 3:P2P_GO 4:IBSS + * @channel: channel on which new connection is coming up + * @bandwidth: Bandwidth requested by the connection + * 0:None 1:5MHz 2:10MHz 3:20MHz + * 4:40MHz 5:80MHz 6:80+80MHz 7:160MHz + * + * @OUTPUT: None + * + * This IOCTL is used to checks for allowed concurrency combination. + * + * @E.g: iwpriv wlan0 pm_query_allow mode channel bandwidth + * iwpriv wlan0 pm_query_allow 0 6 4 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_QUERY_ALLOW_CMD 18 + +/* + * + * pm_run_scenario - Create scenario with number of connections provided. + * + * @INPUT: num_of_conn + * @num_of_conn: the number of connections (values: 1~3) + * + * @OUTPUT: None + * + * This IOCTL is used to create scenario with the number of connections + * provided. + * + * @E.g: iwpriv wlan0 pm_run_scenario num_of_conn + * iwpriv wlan0 pm_run_scenario 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_SCENARIO_CMD 19 + +/* + * + * pm_set_hw_mode - Set hardware for single/dual mac. + * + * @INPUT: hw_mode + * 0:single mac 1:dual mac + * + * @OUTPUT: None + * + * This IOCTL is used to set hardware for single/dual mac. + * + * @E.g: iwpriv wlan0 pm_set_hw_mode hw_mode + * iwpriv wlan0 pm_set_hw_mode 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_SET_HW_MODE_CMD 20 + +/* + * + * 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 + +#ifdef FEATURE_WLAN_TDLS +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 11 +#else +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 9 +#endif + +/* + * + * 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 */ +/* (SIOCIWFIRSTPRIV + 17) is currently unused */ +/* (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 + +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 +}; + +/* (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 VERSION_VALUE_MAX_LEN 32 + +#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 (NULL == ptr) { + hdd_err("unable to allocate memory"); + 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 ((NULL == p_priv_data) || (NULL == 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_warn_rl("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); +} + +/** + * hdd_wlan_get_stats() - Get txrx stats in SAP mode + * @adapter: Pointer to the 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 hdd_adapter *adapter, uint16_t *length, + char *buffer, uint16_t buf_len) +{ + struct hdd_tx_rx_stats *stats = &adapter->hdd_stats.tx_rx_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; + int i = 0; + + for (; i < NUM_CPUS; i++) { + total_rx_pkt += stats->rx_packets[i]; + total_rx_dropped += stats->rx_dropped[i]; + total_rx_delv += stats->rx_delivered[i]; + total_rx_refused += stats->rx_refused[i]; + } + + 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", + qdf_system_ticks(), + stats->tx_called, + stats->tx_dropped, + stats->tx_orphaned, + + stats->tx_dropped_ac[SME_AC_BK], + stats->tx_dropped_ac[SME_AC_BE], + stats->tx_dropped_ac[SME_AC_VI], + stats->tx_dropped_ac[SME_AC_VO], + + stats->tx_classified_ac[SME_AC_BK], + stats->tx_classified_ac[SME_AC_BE], + stats->tx_classified_ac[SME_AC_VI], + stats->tx_classified_ac[SME_AC_VO], + qdf_system_ticks(), + total_rx_pkt, total_rx_dropped, + qdf_atomic_read(&stats->rx_usolict_arp_n_mcast_drp), + total_rx_delv, total_rx_refused + ); + + for (i = 0; i < NUM_CPUS; i++) { + if (stats->rx_packets[i] == 0) + continue; + len += scnprintf(buffer + len, buf_len - len, + "Rx CPU[%d]:" + "packets %u, dropped %u, delivered %u, refused %u\n", + i, stats->rx_packets[i], stats->rx_dropped[i], + stats->rx_delivered[i], stats->rx_refused[i]); + } + + 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->session_id, &buffer[len], (buf_len - len)); + *length = len + 1; +} + +/** + * 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 + */ +#ifdef QCA_SUPPORT_CP_STATS +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; +} +#else +static int wlan_hdd_write_suspend_resume_stats(struct hdd_context *hdd_ctx, + char *buffer, uint16_t max_len) +{ + QDF_STATUS status; + struct suspend_resume_stats *sr_stats; + struct sir_wake_lock_stats wow_stats; + + sr_stats = &hdd_ctx->suspend_resume_stats; + + status = wma_get_wakelock_stats(&wow_stats); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get WoW stats"); + return qdf_status_to_os_return(status); + } + + return 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" + "WoW Wake Reasons\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", + 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], + wow_stats.wow_ucast_wake_up_count, + wow_stats.wow_bcast_wake_up_count, + wow_stats.wow_ipv4_mcast_wake_up_count, + wow_stats.wow_ipv6_mcast_wake_up_count, + wow_stats.wow_ipv6_mcast_ra_stats, + wow_stats.wow_ipv6_mcast_ns_stats, + wow_stats.wow_ipv6_mcast_na_stats, + wow_stats.wow_icmpv4_count, + wow_stats.wow_icmpv6_count, + wow_stats.wow_rssi_breach_wake_up_count, + wow_stats.wow_low_rssi_wake_up_count, + wow_stats.wow_gscan_wake_up_count, + wow_stats.wow_pno_complete_wake_up_count, + wow_stats.wow_pno_match_wake_up_count); +} +#endif +/** + * 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; +} +/** + * hdd_display_stats_help() - print statistics help + * + * Return: none + */ +static void hdd_display_stats_help(void) +{ + hdd_err("iwpriv wlan0 dumpStats [option] - dump statistics"); + hdd_err("iwpriv wlan0 clearStats [option] - clear statistics"); + hdd_err("options:"); + hdd_err(" 1 -- TXRX PATH statistics"); + hdd_err(" 2 -- TXRX HIST statistics"); + hdd_err(" 3 -- TSO statistics"); + hdd_err(" 4 -- Network queue statistics"); + hdd_err(" 5 -- Flow control statistics"); + hdd_err(" 6 -- Per Layer statistics"); + hdd_err(" 7 -- Copy engine interrupt statistics"); + hdd_err(" 8 -- LRO statistics"); + hdd_err(" 9 -- NAPI statistics"); +} + +/** + * hdd_wlan_dump_stats() - display dump Stats + * @adapter: adapter handle + * @value: value from user + * + * Return: 0 => success, error code on failure + */ +int hdd_wlan_dump_stats(struct hdd_adapter *adapter, int value) +{ + int ret = 0; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + switch (value) { + case CDP_TXRX_HIST_STATS: + wlan_hdd_display_tx_rx_histogram(hdd_ctx); + break; + case CDP_HDD_NETIF_OPER_HISTORY: + wlan_hdd_display_netif_queue_history + (hdd_ctx, + QDF_STATS_VERBOSITY_LEVEL_HIGH); + break; + case CDP_HIF_STATS: + hdd_display_hif_stats(); + break; + case CDP_LRO_STATS: + hdd_lro_display_stats(hdd_ctx); + break; + case CDP_NAPI_STATS: + if (hdd_display_napi_stats()) { + hdd_err("error displaying napi stats"); + ret = EFAULT; + } + break; + case CDP_DISCONNECT_STATS: + sme_display_disconnect_stats(hdd_ctx->mac_handle, + adapter->session_id); + break; + default: + status = cdp_display_stats(cds_get_context(QDF_MODULE_ID_SOC), + value, + QDF_STATS_VERBOSITY_LEVEL_HIGH); + if (status == QDF_STATUS_E_INVAL) { + hdd_display_stats_help(); + ret = EINVAL; + } + break; + } + return ret; +} + +/** + * hdd_wlan_get_ibss_peer_info() - Print IBSS peer information + * @adapter: Adapter upon which the IBSS client is active + * @staIdx: Station index of the IBSS peer + * + * Return: QDF_STATUS_STATUS if the peer was found and displayed, + * otherwise an appropriate QDF_STATUS_E_* failure code. + */ +static QDF_STATUS hdd_wlan_get_ibss_peer_info(struct hdd_adapter *adapter, + uint8_t staIdx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + struct hdd_station_ctx *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + tSirPeerInfoRspParams *pPeerInfo = &pStaCtx->ibss_peer_info; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + status = sme_request_ibss_peer_info(mac_handle, adapter, + hdd_get_ibss_peer_info_cb, + false, staIdx); + + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + + rc = wait_for_completion_timeout + (&adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (!rc) { + hdd_err("failed wait on ibss_peer_info_comp"); + return QDF_STATUS_E_FAILURE; + } + + /** Print the peer info */ + hdd_debug("pPeerInfo->numIBSSPeers = %d ", pPeerInfo->numPeers); + { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; +#ifdef WLAN_DEBUG + uint32_t tx_rate = pPeerInfo->peerInfoParams[0].txRate; +#endif + + qdf_mem_copy(mac_addr, pPeerInfo->peerInfoParams[0]. + mac_addr, sizeof(mac_addr)); + hdd_debug("PEER ADDR : %pM TxRate: %d Mbps RSSI: %d", + mac_addr, (int)tx_rate, + (int)pPeerInfo->peerInfoParams[0].rssi); + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return status; +} + +/** + * hdd_wlan_get_ibss_peer_info_all() - Print all IBSS peers + * @adapter: Adapter upon which the IBSS clients are active + * + * Return: QDF_STATUS_STATUS if the peer information was retrieved and + * displayed, otherwise an appropriate QDF_STATUS_E_* failure code. + */ +static QDF_STATUS hdd_wlan_get_ibss_peer_info_all(struct hdd_adapter *adapter) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + struct hdd_station_ctx *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + tSirPeerInfoRspParams *pPeerInfo = &pStaCtx->ibss_peer_info; + int i; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + status = sme_request_ibss_peer_info(mac_handle, adapter, + hdd_get_ibss_peer_info_cb, + true, 0xFF); + + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + + rc = wait_for_completion_timeout + (&adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (!rc) { + hdd_err("failed wait on ibss_peer_info_comp"); + return QDF_STATUS_E_FAILURE; + } + + /** Print the peer info */ + hdd_debug("pPeerInfo->numIBSSPeers = %d ", + (int)pPeerInfo->numPeers); + for (i = 0; i < pPeerInfo->numPeers; i++) { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t tx_rate; + + tx_rate = pPeerInfo->peerInfoParams[i].txRate; + qdf_mem_copy(mac_addr, + pPeerInfo->peerInfoParams[i].mac_addr, + sizeof(mac_addr)); + + hdd_debug(" PEER ADDR : %pM TxRate: %d Mbps RSSI: %d", + mac_addr, (int)tx_rate, + (int)pPeerInfo->peerInfoParams[i].rssi); + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return status; +} + +/** + * 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) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_enter(); + ret = sme_get_ht_config(mac_handle, adapter->session_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; +} + +/** + * hdd_set_ldpc() - Set adapter LDPC + * @adapter: adapter being modified + * @value: new LDPC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_ldpc(struct hdd_adapter *adapter, int value) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + QDF_STATUS status; + uint32_t cfg_value; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_config *config = hdd_ctx->config; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } u; + + hdd_debug("%d", value); + if (value) { + /* make sure HT capabilities allow this */ + if (!config->enable_rx_ldpc) { + hdd_err("LDCP not supported"); + return -EINVAL; + } + } else if (!config->enable_rx_ldpc) { + hdd_err("LDCP is already disabled"); + return 0; + } + status = sme_cfg_get_int(mac_handle, WNI_CFG_HT_CAP_INFO, &cfg_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to get HT capability info"); + return -EIO; + } + u.cfg_value16 = cfg_value & 0xFFFF; + + u.ht_cap_info.advCodingCap = value; + status = sme_cfg_set_int(mac_handle, WNI_CFG_HT_CAP_INFO, + u.cfg_value16); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to set HT capability info"); + return -EIO; + } + status = sme_cfg_set_int(mac_handle, WNI_CFG_VHT_LDPC_CODING_CAP, + value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to set VHT LDPC capability info"); + return -EIO; + } + + ret = sme_update_ht_config(mac_handle, adapter->session_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, adapter->session_id, value); + if (ret) + hdd_err("Failed to set HE LDPC value"); + + return ret; +} + +/** + * 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) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_enter(); + ret = sme_get_ht_config(mac_handle, adapter->session_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; +} + +/** + * hdd_set_tx_stbc() - Set adapter TX STBC + * @adapter: adapter being modified + * @value: new TX STBC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_tx_stbc(struct hdd_adapter *adapter, int value) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_debug("%d", value); + if (value) { + /* make sure HT capabilities allow this */ + QDF_STATUS status; + uint32_t cfg_value; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } u; + + status = sme_cfg_get_int(mac_handle, WNI_CFG_HT_CAP_INFO, + &cfg_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to get HT capability info"); + return -EIO; + } + u.cfg_value16 = cfg_value & 0xFFFF; + if (!u.ht_cap_info.txSTBC) { + hdd_err("TX STBC not supported"); + return -EINVAL; + } + } + ret = sme_update_ht_config(mac_handle, adapter->session_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, adapter->session_id, value); + if (ret) + hdd_err("Failed to set HE TX STBC value"); + + return ret; +} + +/** + * 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) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_enter(); + ret = sme_get_ht_config(mac_handle, adapter->session_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; +} + +/** + * hdd_set_rx_stbc() - Set adapter RX STBC + * @adapter: adapter being modified + * @value: new RX STBC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_rx_stbc(struct hdd_adapter *adapter, int value) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_debug("%d", value); + if (value) { + /* make sure HT capabilities allow this */ + QDF_STATUS status; + uint32_t cfg_value; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } u; + + status = sme_cfg_get_int(mac_handle, WNI_CFG_HT_CAP_INFO, + &cfg_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to get HT capability info"); + return -EIO; + } + u.cfg_value16 = cfg_value & 0xFFFF; + if (!u.ht_cap_info.rxSTBC) { + hdd_warn("RX STBC not supported"); + return -EINVAL; + } + } + ret = sme_update_ht_config(mac_handle, adapter->session_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, adapter->session_id, value); + if (ret) + hdd_err("Failed to set HE RX STBC value"); + + return ret; +} + +int hdd_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate) +{ + int set_value; + + if (sme_is_feature_supported_by_fw(DOT11AX)) + set_value = WMI_ASSEMBLE_RATECODE_V1(rate, nss, preamble); + else + set_value = (preamble << 6) | (nss << 4) | rate; + + return set_value; +} + +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 = %d", + sap_config->SapHw_mode, sap_config->channel); + return -EIO; + } + + if (set_value != 0xff) { + 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->session_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->session_id, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + + return ret; +} + +/** + * 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 *pLinkSpeed = (char *)extra; + int len = sizeof(uint32_t) + 1; + uint32_t link_speed = 0; + struct hdd_context *hdd_ctx; + int ret; + int 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, &link_speed); + if (0 != ret) + return ret; + + wrqu->data.length = len; + /* return the linkspeed as a string */ + rc = snprintf(pLinkSpeed, 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; +} + +static int iw_get_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_linkspeed(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_update_phymode() - handle change in PHY mode + * @net: device upon which PHY mode change was received + * @mac_handle: umac handle for the driver + * @new_phymode: new PHY mode for the device + * @phddctx: pointer to the HDD context + * + * 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 wlan_hdd_update_phymode(struct net_device *net, mac_handle_t mac_handle, + int new_phymode, struct hdd_context *phddctx) +{ +#ifdef QCA_HT_2040_COEX + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net); + QDF_STATUS halStatus = QDF_STATUS_E_FAILURE; +#endif + bool band_24 = false, band_5g = false; + bool ch_bond24 = false, ch_bond5g = false; + tSmeConfigParams *sme_config; + uint32_t chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + uint32_t vhtchanwidth; + eCsrPhyMode phymode = -EIO, old_phymode; + enum hdd_dot11_mode hdd_dot11mode = phddctx->config->dot11Mode; + enum band_info curr_band = BAND_ALL; + int retval = 0; + + old_phymode = sme_get_phy_mode(mac_handle); + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_get_cb_phy_state_from_cb_ini_value(phddctx->config-> + nChannelBondingMode24GHz)) + ch_bond24 = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_get_cb_phy_state_from_cb_ini_value(phddctx->config-> + nChannelBondingMode5GHz)) + ch_bond5g = true; + + if (phddctx->config->nBandCapability == BAND_ALL) + band_24 = band_5g = true; + else if (phddctx->config->nBandCapability == BAND_2G) + band_24 = true; + else if (phddctx->config->nBandCapability == BAND_5G) + band_5g = true; + + vhtchanwidth = phddctx->config->vhtChannelWidth; + hdd_debug("ch_bond24=%d ch_bond5g=%d band_24=%d band_5g=%d VHT_ch_width=%u", + ch_bond24, ch_bond5g, band_24, band_5g, vhtchanwidth); + + switch (new_phymode) { + case IEEE80211_MODE_AUTO: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_AUTO); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_AUTO) == 0) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = BAND_ALL; + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11A: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11a); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_11a; + hdd_dot11mode = eHDD_DOT11_MODE_11a; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = BAND_5G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11B: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11b); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_11b; + hdd_dot11mode = eHDD_DOT11_MODE_11b; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = BAND_2G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11G: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11g); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_11g; + hdd_dot11mode = eHDD_DOT11_MODE_11g; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = BAND_2G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + /* UMAC doesn't have option to set MODE_11NA/MODE_11NG as phymode + * so setting phymode as eCSR_DOT11_MODE_11n and updating the band + * and channel bonding in configuration to reflect MODE_11NA/MODE_11NG + */ + case IEEE80211_MODE_11NA_HT20: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11n); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = BAND_5G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NA_HT40: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11n); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = BAND_5G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NG_HT20: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11n); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = BAND_2G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NG_HT40: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11n); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = BAND_2G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11AC_VHT20: + case IEEE80211_MODE_11AC_VHT40: + case IEEE80211_MODE_11AC_VHT80: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11ac); + phymode = eCSR_DOT11_MODE_11ac; + hdd_dot11mode = eHDD_DOT11_MODE_11ac; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + if (band_5g && band_24) { + curr_band = BAND_ALL; + break; + } else if (band_5g) { + curr_band = BAND_5G; + break; + } else if (new_phymode != IEEE80211_MODE_11AC_VHT80) { + curr_band = BAND_2G; + break; + } + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_AUTO) == 0) { + curr_band = BAND_ALL; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_2G_AUTO: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_AUTO); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = BAND_2G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_5G_AUTO: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_AUTO); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + curr_band = BAND_5G; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11AGN: + sme_set_phy_mode(mac_handle, eCSR_DOT11_MODE_11n); + if (hdd_reg_set_band(net, WLAN_HDD_UI_BAND_AUTO) == 0) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = BAND_ALL; + } else { + sme_set_phy_mode(mac_handle, old_phymode); + return -EIO; + } + break; + default: + return -EIO; + } + + switch (new_phymode) { + case IEEE80211_MODE_11AC_VHT20: + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + vhtchanwidth = eHT_CHANNEL_WIDTH_20MHZ; + break; + case IEEE80211_MODE_11AC_VHT40: + vhtchanwidth = eHT_CHANNEL_WIDTH_40MHZ; + break; + case IEEE80211_MODE_11AC_VHT80: + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + break; + default: + vhtchanwidth = phddctx->config->vhtChannelWidth; + break; + } + + if (phymode != -EIO) { + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("Failed to allocate memory for sme_config"); + return -ENOMEM; + } + qdf_mem_zero(sme_config, sizeof(*sme_config)); + sme_get_config_param(mac_handle, sme_config); + sme_config->csrConfig.phyMode = phymode; +#ifdef QCA_HT_2040_COEX + if (phymode == eCSR_DOT11_MODE_11n && + chwidth == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) { + sme_config->csrConfig.obssEnabled = false; + halStatus = sme_set_ht2040_mode(mac_handle, + adapter->session_id, + eHT_CHAN_HT20, false); + if (halStatus == QDF_STATUS_E_FAILURE) { + hdd_err("Failed to disable OBSS"); + retval = -EIO; + goto free; + } + } else if (phymode == eCSR_DOT11_MODE_11n && + chwidth == WNI_CFG_CHANNEL_BONDING_MODE_ENABLE) { + sme_config->csrConfig.obssEnabled = true; + halStatus = sme_set_ht2040_mode(mac_handle, + adapter->session_id, + eHT_CHAN_HT20, true); + if (halStatus == QDF_STATUS_E_FAILURE) { + hdd_err("Failed to enable OBSS"); + retval = -EIO; + goto free; + } + } +#endif + sme_config->csrConfig.eBand = curr_band; + sme_config->csrConfig.bandCapability = curr_band; + if (curr_band == BAND_2G) + sme_config->csrConfig.Is11hSupportEnabled = 0; + else + sme_config->csrConfig.Is11hSupportEnabled = + phddctx->config->Is11hSupportEnabled; + if (curr_band == BAND_2G) + sme_config->csrConfig.channelBondingMode24GHz = chwidth; + else if (curr_band == BAND_5G) + sme_config->csrConfig.channelBondingMode5GHz = chwidth; + else { + sme_config->csrConfig.channelBondingMode24GHz = chwidth; + sme_config->csrConfig.channelBondingMode5GHz = chwidth; + } + sme_config->csrConfig.nVhtChannelWidth = vhtchanwidth; + sme_update_config(mac_handle, sme_config); + + phddctx->config->dot11Mode = hdd_dot11mode; + phddctx->config->nChannelBondingMode24GHz = + sme_config->csrConfig.channelBondingMode24GHz; + phddctx->config->nChannelBondingMode5GHz = + sme_config->csrConfig.channelBondingMode5GHz; + phddctx->config->vhtChannelWidth = vhtchanwidth; + if (hdd_update_config_cfg(phddctx) == false) { + hdd_err("could not update config_dat"); + retval = -EIO; + goto free; + } + + if (band_5g) { + struct ieee80211_supported_band *band; + + band = phddctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]; + if (phddctx->config->nChannelBondingMode5GHz) + band->ht_cap.cap |= + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + band->ht_cap.cap &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + + hdd_debug("New_Phymode= %d ch_bonding=%d band=%d VHT_ch_width=%u", + phymode, chwidth, curr_band, vhtchanwidth); + } + +free: + if (sme_config) + qdf_mem_free(sme_config); + return retval; +} + +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 hdd_adapter *adapter, int value) +{ + int ret; + + hdd_debug("%d", value); + + ret = hdd_validate_pdev_reset(value); + if (ret) + return ret; + + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_PDEV_RESET, + value, PDEV_CMD); + + return ret; +} + +static int hdd_we_set_ch_width(struct hdd_adapter *adapter, int ch_width) +{ + int errno; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ePhyChanBondState bonding_state; + uint32_t bonding_mode; + tSmeConfigParams *sme_config; + mac_handle_t mac_handle; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) + return -EINVAL; + + /* updating channel bonding only on 5Ghz */ + hdd_debug("WMI_VDEV_PARAM_CHWIDTH val %d", ch_width); + + switch (ch_width) { + case eHT_CHANNEL_WIDTH_20MHZ: + bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + break; + + case eHT_CHANNEL_WIDTH_40MHZ: + case eHT_CHANNEL_WIDTH_80MHZ: + bonding_state = csr_convert_cb_ini_value_to_phy_cb_state( + hdd_ctx->config->nChannelBondingMode5GHz); + + if (bonding_state == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) + return -EINVAL; + + bonding_mode = hdd_ctx->config->nChannelBondingMode5GHz; + break; + + default: + hdd_err("Invalid channel width 0->20 1->40 2->80"); + return -EINVAL; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("failed to allocate memory for sme_config"); + return -ENOMEM; + } + + errno = wma_cli_set_command(adapter->session_id, WMI_VDEV_PARAM_CHWIDTH, + ch_width, VDEV_CMD); + if (errno) + goto free_config; + + sme_get_config_param(mac_handle, sme_config); + sme_config->csrConfig.channelBondingMode5GHz = bonding_mode; + sme_update_config(mac_handle, sme_config); + +free_config: + qdf_mem_free(sme_config); + + return errno; +} + +static int hdd_we_set_11d_state(struct hdd_context *hdd_ctx, int state_11d) +{ + tSmeConfigParams *sme_config; + bool enable_11d; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + 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; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("failed to allocate memory for sme_config"); + return -ENOMEM; + } + + sme_get_config_param(mac_handle, sme_config); + sme_config->csrConfig.Is11dSupportEnabled = enable_11d; + sme_update_config(mac_handle, sme_config); + + qdf_mem_free(sme_config); + + hdd_debug("11D state=%d", enable_11d); + + return 0; +} + +/** + * 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); + mac_handle_t mac_handle; + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_context *hdd_ctx; + int *value = (int *)extra; + int sub_cmd = value[0]; + int set_value = value[1]; + int ret; + QDF_STATUS status; + + 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_SET_11D_STATE: + ret = hdd_we_set_11d_state(hdd_ctx, set_value); + break; + + case WE_SET_POWER: + { + if (!mac_handle) + return -EINVAL; + + switch (set_value) { + case 1: + /* Enable PowerSave */ + sme_ps_enable_disable(mac_handle, adapter->session_id, + SME_PS_ENABLE); + break; + case 2: + /* Disable PowerSave */ + sme_ps_enable_disable(mac_handle, adapter->session_id, + SME_PS_DISABLE); + break; + case 3: /* Enable UASPD */ + sme_ps_uapsd_enable(mac_handle, adapter->session_id); + break; + case 4: /* Disable UASPD */ + sme_ps_uapsd_disable(mac_handle, adapter->session_id); + break; + default: + hdd_err("Invalid arg %d in WE_SET_POWER IOCTL", + set_value); + ret = -EINVAL; + break; + } + break; + } + + case WE_SET_MAX_ASSOC: + { + if (!mac_handle) + return -EINVAL; + + if ((WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value) || + (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value)) { + ret = -EINVAL; + } else if (sme_cfg_set_int(mac_handle, WNI_CFG_ASSOC_STA_LIMIT, + set_value) + != QDF_STATUS_SUCCESS) { + hdd_err("WNI_CFG_ASSOC_STA_LIMIT failed"); + ret = -EIO; + } + break; + } + + case WE_SET_DATA_INACTIVITY_TO: + if (!mac_handle) + return -EINVAL; + + if ((set_value < CFG_DATA_INACTIVITY_TIMEOUT_MIN) || + (set_value > CFG_DATA_INACTIVITY_TIMEOUT_MAX) || + (sme_cfg_set_int(mac_handle, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + set_value) == QDF_STATUS_E_FAILURE)) { + hdd_err("WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT failed"); + ret = -EINVAL; + } + break; + case WE_SET_WOW_DATA_INACTIVITY_TO: + if (!mac_handle) { + ret = -EINVAL; + break; + } + + if ((set_value < CFG_WOW_DATA_INACTIVITY_TIMEOUT_MIN) || + (set_value > CFG_WOW_DATA_INACTIVITY_TIMEOUT_MAX) || + (sme_cfg_set_int(mac_handle, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + set_value) == QDF_STATUS_E_FAILURE)) { + hdd_err("WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT fail"); + ret = -EINVAL; + } + break; + case WE_SET_MC_RATE: + { + if (!mac_handle) + return -EINVAL; + + ret = wlan_hdd_set_mc_rate(adapter, set_value); + break; + } + case WE_SET_TX_POWER: + { + struct qdf_mac_addr bssid; + + if (!mac_handle) + return -EINVAL; + + qdf_copy_macaddr(&bssid, &sta_ctx->conn_info.bssId); + if (sme_set_tx_power + (mac_handle, adapter->session_id, bssid, + adapter->device_mode, + set_value) != QDF_STATUS_SUCCESS) { + hdd_err("Setting tx power failed"); + ret = -EIO; + break; + } + break; + } + case WE_SET_MAX_TX_POWER: + { + struct qdf_mac_addr bssid; + struct qdf_mac_addr selfMac; + + if (!mac_handle) + return -EINVAL; + + hdd_debug("Setting maximum tx power %d dBm", + set_value); + qdf_copy_macaddr(&bssid, &sta_ctx->conn_info.bssId); + qdf_copy_macaddr(&selfMac, &sta_ctx->conn_info.bssId); + + if (sme_set_max_tx_power(mac_handle, bssid, selfMac, set_value) + != QDF_STATUS_SUCCESS) { + hdd_err("Setting maximum tx power failed"); + ret = -EIO; + break; + } + + break; + } + case WE_SET_MAX_TX_POWER_2_4: + { + hdd_debug("Setting maximum tx power %d dBm for 2.4 GHz band", + set_value); + if (sme_set_max_tx_power_per_band(BAND_2G, set_value) != + QDF_STATUS_SUCCESS) { + hdd_err("Setting max tx power failed for 2.4 GHz band"); + ret = -EIO; + break; + } + + break; + } + case WE_SET_MAX_TX_POWER_5_0: + { + hdd_debug("Setting maximum tx power %d dBm for 5.0 GHz band", + set_value); + if (sme_set_max_tx_power_per_band(BAND_5G, set_value) != + QDF_STATUS_SUCCESS) { + hdd_err("Setting max tx power failed for 5.0 GHz band"); + ret = -EIO; + break; + } + + break; + } + + case WE_SET_TM_LEVEL: + { + if (!mac_handle) + return -EINVAL; + + hdd_debug("Set Thermal Mitigation Level %d", set_value); + (void)sme_set_thermal_level(mac_handle, set_value); + break; + } + + case WE_SET_PHYMODE: + if (!mac_handle) + return -EINVAL; + + ret = wlan_hdd_update_phymode(dev, mac_handle, set_value, + hdd_ctx); + break; + + case WE_SET_NSS: + { + if (!mac_handle) + return -EINVAL; + + hdd_debug("Set NSS = %d", set_value); + if ((set_value > 2) || (set_value <= 0)) { + hdd_err("NSS greater than 2 not supported"); + ret = -EINVAL; + } else { + if (QDF_STATUS_SUCCESS != + hdd_update_nss(adapter, set_value)) + ret = -EINVAL; + } + break; + } + + case WE_SET_GTX_HT_MCS: + { + hdd_debug("WMI_VDEV_PARAM_GTX_HT_MCS %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_HT_MCS, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_VHT_MCS: + { + hdd_debug("WMI_VDEV_PARAM_GTX_VHT_MCS %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_VHT_MCS, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_USRCFG: + { + hdd_debug("WMI_VDEV_PARAM_GTX_USR_CFG %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_USR_CFG, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_THRE: + { + hdd_debug("WMI_VDEV_PARAM_GTX_THRE %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_THRE, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_MARGIN: + { + hdd_debug("WMI_VDEV_PARAM_GTX_MARGIN %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_MARGIN, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_STEP: + { + hdd_debug("WMI_VDEV_PARAM_GTX_STEP %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_STEP, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_MINTPC: + { + hdd_debug("WMI_VDEV_PARAM_GTX_MINTPC %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_MINTPC, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_BWMASK: + { + hdd_debug("WMI_VDEV_PARAM_GTX_BWMASK %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_GTX_BW_MASK, + set_value, GTX_CMD); + break; + } + + case WE_SET_LDPC: + { + if (!mac_handle) + return -EINVAL; + + ret = hdd_set_ldpc(adapter, set_value); + break; + } + + case WE_SET_TX_STBC: + { + if (!mac_handle) + return -EINVAL; + + ret = hdd_set_tx_stbc(adapter, set_value); + break; + } + + case WE_SET_RX_STBC: + { + if (!mac_handle) + return -EINVAL; + + ret = hdd_set_rx_stbc(adapter, set_value); + break; + } + + case WE_SET_SHORT_GI: + { + if (!mac_handle) + return -EINVAL; + + hdd_debug("WMI_VDEV_PARAM_SGI val %d", set_value); + if (set_value & HDD_AUTO_RATE_SGI) + ret = sme_set_auto_rate_he_sgi(mac_handle, + adapter->session_id, + set_value); + else + ret = sme_update_ht_config(mac_handle, + adapter->session_id, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + set_value); + if (ret) + hdd_err("Failed to set ShortGI value %d", set_value); + + break; + } + + case WE_SET_RTSCTS: + { + uint32_t value; + + if (!mac_handle) + return -EINVAL; + + hdd_debug("WMI_VDEV_PARAM_ENABLE_RTSCTS val 0x%x", set_value); + + if ((set_value & HDD_RTSCTS_EN_MASK) == + HDD_RTSCTS_ENABLE) + value = + (WLAN_HDD_GET_CTX(adapter))->config-> + RTSThreshold; + else if (((set_value & HDD_RTSCTS_EN_MASK) == 0) + || ((set_value & HDD_RTSCTS_EN_MASK) == + HDD_CTS_ENABLE)) { + value = WNI_CFG_RTS_THRESHOLD_STAMAX; + } else { + ret = -EIO; + break; + } + + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + set_value, VDEV_CMD); + if (!ret) { + if (sme_cfg_set_int(mac_handle, WNI_CFG_RTS_THRESHOLD, + value) != QDF_STATUS_SUCCESS) { + hdd_err("FAILED TO SET RTSCTS"); + ret = -EIO; + break; + } + } + + break; + } + + case WE_SET_CHWIDTH: + ret = hdd_we_set_ch_width(adapter, set_value); + break; + + case WE_SET_ANI_EN_DIS: + { + hdd_debug("WMI_PDEV_PARAM_ANI_ENABLE val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_ANI_ENABLE, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_POLL_PERIOD: + { + hdd_debug("WMI_PDEV_PARAM_ANI_POLL_PERIOD val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_ANI_POLL_PERIOD, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_LISTEN_PERIOD: + { + hdd_debug("WMI_PDEV_PARAM_ANI_LISTEN_PERIOD val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_OFDM_LEVEL: + { + hdd_debug("WMI_PDEV_PARAM_ANI_OFDM_LEVEL val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_ANI_OFDM_LEVEL, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_CCK_LEVEL: + { + hdd_debug("WMI_PDEV_PARAM_ANI_CCK_LEVEL val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_ANI_CCK_LEVEL, + set_value, PDEV_CMD); + break; + } + + case WE_SET_DYNAMIC_BW: + { + hdd_debug("WMI_PDEV_PARAM_DYNAMIC_BW val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_DYNAMIC_BW, + set_value, PDEV_CMD); + break; + } + + case WE_SET_CTS_CBW: + { + hdd_debug("WE_SET_CTS_CBW val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_CTS_CBW, + set_value, PDEV_CMD); + break; + } + + case WE_SET_11N_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + + hdd_debug("WMI_VDEV_PARAM_FIXED_RATE val %d", + set_value); + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x80) { + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(set_value) - 1; + } else { + nss = 0; + rix = RC_2_RATE_IDX(set_value); + if (set_value & 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; + } + } + set_value = hdd_assemble_rate_code(preamble, nss, rix); + } + hdd_debug("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case WE_SET_VHT_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + + 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("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case WE_SET_AMPDU: + { + hdd_debug("SET AMPDU val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + GEN_VDEV_PARAM_AMPDU, + set_value, GEN_CMD); + break; + } + + case WE_SET_AMSDU: + { + hdd_debug("SET AMSDU val %d", set_value); + if (set_value > 1) + sme_set_amsdu(mac_handle, true); + else + sme_set_amsdu(mac_handle, false); + + ret = wma_cli_set_command(adapter->session_id, + GEN_VDEV_PARAM_AMSDU, + set_value, GEN_CMD); + /* Update the stored ini value */ + if (!ret) + hdd_ctx->config->max_amsdu_num = set_value; + break; + } + + case WE_SET_TX_CHAINMASK: + { + hdd_debug("WMI_PDEV_PARAM_TX_CHAIN_MASK val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + set_value, PDEV_CMD); + ret = hdd_set_antenna_mode(adapter, hdd_ctx, set_value); + break; + } + + case WE_SET_RX_CHAINMASK: + { + hdd_debug("WMI_PDEV_PARAM_RX_CHAIN_MASK val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + set_value, PDEV_CMD); + ret = hdd_set_antenna_mode(adapter, hdd_ctx, set_value); + break; + } + + case WE_SET_TXPOW_2G: + { + hdd_debug("WMI_PDEV_PARAM_TXPOWER_LIMIT2G val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + set_value, PDEV_CMD); + break; + } + + case WE_SET_TXPOW_5G: + { + hdd_debug("WMI_PDEV_PARAM_TXPOWER_LIMIT5G val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + set_value, PDEV_CMD); + break; + } + + /* Firmware debug log */ + case WE_DBGLOG_LOG_LEVEL: + { + hdd_debug("WE_DBGLOG_LOG_LEVEL val %d", set_value); + hdd_ctx->fw_log_settings.dl_loglevel = set_value; + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_VAP_ENABLE: + { + hdd_debug("WE_DBGLOG_VAP_ENABLE val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_VAP_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_VAP_DISABLE: + { + hdd_debug("WE_DBGLOG_VAP_DISABLE val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_VAP_DISABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_MODULE_ENABLE: + { + hdd_debug("WE_DBGLOG_MODULE_ENABLE val %d", + set_value); + hdd_ctx->fw_log_settings.enable = set_value; + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_MODULE_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_MODULE_DISABLE: + { + hdd_debug("WE_DBGLOG_MODULE_DISABLE val %d", + set_value); + hdd_ctx->fw_log_settings.enable = set_value; + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_MODULE_DISABLE, + set_value, DBG_CMD); + break; + } + case WE_DBGLOG_MOD_LOG_LEVEL: + { + hdd_debug("WE_DBGLOG_MOD_LOG_LEVEL val %d", + set_value); + + if (hdd_ctx->fw_log_settings.index >= MAX_MOD_LOGLEVEL) + hdd_ctx->fw_log_settings.index = 0; + + hdd_ctx->fw_log_settings. + dl_mod_loglevel[hdd_ctx->fw_log_settings.index] = + set_value; + hdd_ctx->fw_log_settings.index++; + + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_MOD_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_TYPE: + { + hdd_debug("WE_DBGLOG_TYPE val %d", set_value); + hdd_ctx->fw_log_settings.dl_type = set_value; + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_TYPE, + set_value, DBG_CMD); + break; + } + case WE_DBGLOG_REPORT_ENABLE: + { + hdd_debug("WE_DBGLOG_REPORT_ENABLE val %d", + set_value); + hdd_ctx->fw_log_settings.dl_report = set_value; + ret = wma_cli_set_command(adapter->session_id, + WMI_DBGLOG_REPORT_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_SET_TXRX_FWSTATS: + { + hdd_debug("WE_SET_TXRX_FWSTATS val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_TXRX_FWSTATS_RESET: + { + hdd_debug("WE_TXRX_FWSTATS_RESET val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_DUMP_STATS: + { + hdd_debug("WE_DUMP_STATS val %d", set_value); + ret = hdd_wlan_dump_stats(adapter, set_value); + break; + } + + case WE_CLEAR_STATS: + { + hdd_debug("WE_CLEAR_STATS val %d", set_value); + switch (set_value) { + case CDP_HDD_STATS: + memset(&adapter->stats, 0, sizeof(adapter->stats)); + memset(&adapter->hdd_stats, 0, + sizeof(adapter->hdd_stats)); + break; + case CDP_TXRX_HIST_STATS: + wlan_hdd_clear_tx_rx_histogram(hdd_ctx); + 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; + case CDP_NAPI_STATS: + hdd_clear_napi_stats(); + break; + default: + cdp_clear_stats(cds_get_context(QDF_MODULE_ID_SOC), + set_value); + } + break; + } + + case WE_PPS_PAID_MATCH: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + + hdd_debug("WMI_VDEV_PPS_PAID_MATCH val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_PAID_MATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_GID_MATCH: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug("WMI_VDEV_PPS_GID_MATCH val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_GID_MATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EARLY_TIM_CLEAR: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug(" WMI_VDEV_PPS_EARLY_TIM_CLEAR val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_EARLY_TIM_CLEAR, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EARLY_DTIM_CLEAR: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug("WMI_VDEV_PPS_EARLY_DTIM_CLEAR val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EOF_PAD_DELIM: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug("WMI_VDEV_PPS_EOF_PAD_DELIM val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_EOF_PAD_DELIM, + set_value, PPS_CMD); + break; + } + + case WE_PPS_MACADDR_MISMATCH: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug("WMI_VDEV_PPS_MACADDR_MISMATCH val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_MACADDR_MISMATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_DELIM_CRC_FAIL: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug("WMI_VDEV_PPS_DELIM_CRC_FAIL val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_DELIM_CRC_FAIL, + set_value, PPS_CMD); + break; + } + + case WE_PPS_GID_NSTS_ZERO: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug("WMI_VDEV_PPS_GID_NSTS_ZERO val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_GID_NSTS_ZERO, + set_value, PPS_CMD); + break; + } + + case WE_PPS_RSSI_CHECK: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + hdd_debug("WMI_VDEV_PPS_RSSI_CHECK val %d ", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_RSSI_CHECK, + set_value, PPS_CMD); + break; + } + + case WE_PPS_5G_EBT: + { + if (adapter->device_mode != QDF_STA_MODE) { + ret = -EINVAL; + break; + } + + hdd_debug("WMI_VDEV_PPS_5G_EBT val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PPS_5G_EBT, + set_value, PPS_CMD); + break; + } + + case WE_SET_HTSMPS: + { + hdd_debug("WE_SET_HTSMPS val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_STA_SMPS_FORCE_MODE_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_SET_QPOWER_MAX_PSPOLL_COUNT: + { + hdd_debug("WE_SET_QPOWER_MAX_PSPOLL_COUNT val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_MAX_TX_BEFORE_WAKE: + { + hdd_debug("WE_SET_QPOWER_MAX_TX_BEFORE_WAKE val %d", + set_value); + ret = wma_cli_set_command( + adapter->session_id, + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + { + hdd_debug("WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL val %d", + set_value); + ret = wma_cli_set_command( + adapter->session_id, + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + { + hdd_debug("WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL val %d", + set_value); + ret = wma_cli_set_command( + adapter->session_id, + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + set_value, QPOWER_CMD); + break; + } + + case WE_MCC_CONFIG_LATENCY: + { + wlan_hdd_set_mcc_latency(adapter, set_value); + break; + } + + case WE_MCC_CONFIG_QUOTA: + { + hdd_debug("iwpriv cmd to set MCC quota with val %dms", + set_value); + ret = wlan_hdd_set_mcc_p2p_quota(adapter, + set_value); + break; + } + case WE_SET_DEBUG_LOG: + { + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!mac_handle) + return -EINVAL; + + + hdd_ctx->config->gEnableDebugLog = set_value; + sme_update_connect_debug(mac_handle, set_value); + break; + } + case WE_SET_EARLY_RX_ADJUST_ENABLE: + { + hdd_debug("SET early_rx enable val %d", set_value); + if ((set_value == 0) || (set_value == 1)) + ret = wma_cli_set_command( + adapter->session_id, + WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + set_value, VDEV_CMD); + else + ret = -EINVAL; + break; + } + case WE_SET_EARLY_RX_TGT_BMISS_NUM: + { + hdd_debug("SET early_rx bmiss val %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE: + { + hdd_debug("SET early_rx bmiss sample cycle %d", + set_value); + ret = wma_cli_set_command( + adapter->session_id, + WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_SLOP_STEP: + { + hdd_debug("SET early_rx bmiss slop step val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_INIT_SLOP: + { + hdd_debug("SET early_rx init slop step val %d", + set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_ADJUST_PAUSE: + { + hdd_debug("SET early_rx adjust pause %d", set_value); + if ((set_value == 0) || (set_value == 1)) + ret = wma_cli_set_command( + adapter->session_id, + WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + set_value, VDEV_CMD); + else + ret = -EINVAL; + break; + } + case WE_SET_EARLY_RX_DRIFT_SAMPLE: + { + hdd_debug("SET early_rx drift sample %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, + set_value, VDEV_CMD); + break; + } + case WE_SET_SCAN_DISABLE: + { + if (!mac_handle) + return -EINVAL; + + hdd_debug("SET SCAN DISABLE %d", set_value); + sme_set_scan_disable(mac_handle, set_value); + break; + } + case WE_START_FW_PROFILE: + { + hdd_debug("WE_START_FW_PROFILE %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + set_value, DBG_CMD); + break; + } + case WE_SET_CHANNEL: + { + hdd_debug("Set Channel %d Session ID %d mode %d", set_value, + adapter->session_id, adapter->device_mode); + if (!mac_handle) + return -EINVAL; + + + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode)) { + + status = sme_ext_change_channel(mac_handle, + set_value, + adapter->session_id); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Error in change channel status %d", + status); + ret = -EINVAL; + } + } else { + hdd_err("change channel not supported for device mode %d", + adapter->device_mode); + ret = -EINVAL; + } + break; + } + case WE_SET_CONC_SYSTEM_PREF: + { + hdd_debug("New preference: %d", set_value); + if (!((set_value >= CFG_CONC_SYSTEM_PREF_MIN) && + (set_value <= CFG_CONC_SYSTEM_PREF_MAX))) { + hdd_err("Invalid system preference %d", set_value); + ret = -EINVAL; + break; + } + + /* hdd_ctx, hdd_ctx->config are already checked for null */ + hdd_ctx->config->conc_system_pref = set_value; + break; + } + case WE_SET_11AX_RATE: + ret = hdd_set_11ax_rate(adapter, set_value, NULL); + break; + case WE_SET_DCM: + hdd_debug("Set WMI_VDEV_PARAM_HE_DCM: %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_HE_DCM, set_value, + VDEV_CMD); + break; + case WE_SET_RANGE_EXT: + hdd_debug("Set WMI_VDEV_PARAM_HE_RANGE_EXT: %d", set_value); + ret = wma_cli_set_command(adapter->session_id, + WMI_VDEV_PARAM_HE_RANGE_EXT, + set_value, VDEV_CMD); + break; + case WE_SET_PDEV_RESET: + ret = hdd_handle_pdev_reset(adapter, set_value); + break; + case WE_SET_MODULATED_DTIM: + if ((set_value < CFG_ENABLE_MODULATED_DTIM_MIN) || + (set_value > CFG_ENABLE_MODULATED_DTIM_MAX)) { + hdd_err("Invalid gEnableModuleDTIM value %d", + set_value); + return -EINVAL; + } + + hdd_ctx->config->enableModulatedDTIM = set_value; + break; + default: + hdd_debug("Invalid sub command %d", sub_cmd); + ret = -EINVAL; + break; + } + + hdd_exit(); + + return ret; +} + +static int iw_setint_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setint_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + 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 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); + + 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, value, 3); + 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_get_threeint(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_UNIT_TEST +static int hdd_we_unit_test(struct hdd_context *hdd_ctx, const char *component) +{ + uint32_t errors = 0; + bool all = !component || !component[0]; + + if (all) + hdd_info("Starting unit tests for all components"); + else + hdd_info("Starting unit tests for component '%s'", component); + + /* add future tests here */ + + if (errors) { + hdd_err("Unit tests failed with %u errors", errors); + return -EPERM; + } + + hdd_info("Unit tests passed successfully"); + + return 0; +} +#else +static int hdd_we_unit_test(struct hdd_context *hdd_ctx, const char *component) +{ + return -EOPNOTSUPP; +} +#endif /* WLAN_UNIT_TEST */ + +/** + * 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) +{ + QDF_STATUS status; + 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 hdd_config *pConfig = hdd_ctx->config; + struct iw_point s_priv_data; + + 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 ((NULL == 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"); + hdd_add_wowl_ptrn(adapter, str_arg); + break; + case WE_WOWL_DEL_PTRN: + hdd_debug("DEL_PTRN"); + hdd_del_wowl_ptrn(adapter, str_arg); + break; + case WE_NEIGHBOR_REPORT_REQUEST: + { + tRrmNeighborReq neighborReq; + tRrmNeighborRspCallbackInfo callbackInfo; + + if (pConfig->fRrmEnable) { + neighborReq.neighbor_report_offload = false; + neighborReq.no_ssid = + (s_priv_data.length - 1) ? false : true; + hdd_debug("Neighbor Request ssid present %d", + neighborReq.no_ssid); + if (!neighborReq.no_ssid) { + neighborReq.ssid.length = + (s_priv_data.length - 1) > + 32 ? 32 : (s_priv_data.length - 1); + qdf_mem_copy(neighborReq.ssid.ssId, + str_arg, + neighborReq.ssid.length); + } + + /* + * If 11k offload is supported by FW and enabled + * in the ini, set the offload to true + */ + if (hdd_ctx->config->is_11k_offload_supported && + (hdd_ctx->config->offload_11k_enable_bitmask & + OFFLOAD_11K_BITMASK_NEIGHBOR_REPORT_REQUEST)) { + hdd_debug("Neighbor report offloaded to FW"); + neighborReq.neighbor_report_offload = true; + } + + callbackInfo.neighborRspCallback = NULL; + callbackInfo.neighborRspCallbackContext = NULL; + callbackInfo.timeout = 5000; /* 5 seconds */ + sme_neighbor_report_request( + hdd_ctx->mac_handle, + adapter->session_id, + &neighborReq, + &callbackInfo); + } 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_SET_CONFIG: + status = hdd_execute_global_config_command(hdd_ctx, str_arg); + if (QDF_IS_STATUS_ERROR(status)) + ret = -EINVAL; + + break; + case WE_UNIT_TEST: + ret = hdd_we_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; +} + +static int iw_setchar_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setchar_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + 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) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + mac_handle_t mac_handle; + int *value = (int *)extra; + int ret; + tSmeConfigParams *sme_config; + 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; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("failed to allocate memory for sme_config"); + return -ENOMEM; + } + + mac_handle = hdd_ctx->mac_handle; + switch (value[0]) { + case WE_GET_11D_STATE: + { + sme_get_config_param(mac_handle, sme_config); + + *value = sme_config->csrConfig.Is11dSupportEnabled; + + hdd_debug("11D state=%d!!", *value); + + break; + } + + case WE_GET_WLAN_DBG: + { + qdf_trace_display(); + *value = 0; + break; + } + case WE_GET_MAX_ASSOC: + { + if (sme_cfg_get_int(mac_handle, WNI_CFG_ASSOC_STA_LIMIT, + (uint32_t *) value) != QDF_STATUS_SUCCESS) { + hdd_err("WNI_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: + { + sme_get_config_param(mac_handle, sme_config); + *value = (sme_config->csrConfig.enable2x2 == 0) ? 1 : 2; + if (policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc)) + *value = *value - 1; + 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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_id, + WMI_VDEV_PARAM_FIXED_RATE, + VDEV_CMD); + break; + } + + case WE_GET_AMPDU: + { + hdd_debug("GET AMPDU"); + *value = wma_cli_get_command(adapter->session_id, + GEN_VDEV_PARAM_AMPDU, + GEN_CMD); + break; + } + + case WE_GET_AMSDU: + { + hdd_debug("GET AMSDU"); + *value = wma_cli_get_command(adapter->session_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->session_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->session_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->session_id, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case WE_GET_TXPOW_2G: + { + uint32_t txpow2g = 0; + + hdd_debug("GET WMI_PDEV_PARAM_TXPOWER_LIMIT2G"); + *value = wma_cli_get_command(adapter->session_id, + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + PDEV_CMD); + if (QDF_STATUS_SUCCESS != + sme_cfg_get_int(mac_handle, WNI_CFG_CURRENT_TX_POWER_LEVEL, + &txpow2g)) { + ret = -EIO; + break; + } + hdd_debug("2G tx_power %d", txpow2g); + break; + } + + case WE_GET_TXPOW_5G: + { + uint32_t txpow5g = 0; + + hdd_debug("GET WMI_PDEV_PARAM_TXPOWER_LIMIT5G"); + *value = wma_cli_get_command(adapter->session_id, + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + PDEV_CMD); + if (QDF_STATUS_SUCCESS != + sme_cfg_get_int(mac_handle, WNI_CFG_CURRENT_TX_POWER_LEVEL, + &txpow5g)) { + ret = -EIO; + break; + } + 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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_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->session_id, + WMI_VDEV_PARAM_HE_DCM, + VDEV_CMD); + break; + case WE_GET_RANGE_EXT: + hdd_debug("GET WMI_VDEV_PARAM_HE_RANGE_EXT"); + *value = wma_cli_get_command(adapter->session_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; +} + +static int iw_setnone_getint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_getint(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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 > (WMA_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 (NULL == fw_test) { + hdd_err("qdf_mem_malloc failed for 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; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + 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"); + if (hdd_ctx->config->dual_mac_feature_disable == + 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; +} + +int iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_three_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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_Connecting); + CASE_RETURN_STRING(eConnectionState_Associated); + CASE_RETURN_STRING(eConnectionState_IbssDisconnected); + CASE_RETURN_STRING(eConnectionState_IbssConnected); + CASE_RETURN_STRING(eConnectionState_Disconnecting); + 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 + +/** + * 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; + + 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(adapter, &(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; + + struct hdd_station_ctx *sta_ctx = NULL; + + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_adapter *useAdapter = NULL; + + /* Print wlan0 or p2p0 states based on the adapter_num + * by using the correct adapter + */ + while (adapter_num < 2) { + if (WLAN_ADAPTER == adapter_num) { + useAdapter = 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 + */ + useAdapter = + hdd_get_adapter(hdd_ctx, + QDF_P2P_CLIENT_MODE); + if (!useAdapter) { + 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; + } + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(useAdapter); + + + buf = + scnprintf(extra + len, WE_MAX_STR_LEN - len, + "\n HDD Conn State - %s " + "\n\n SME State:" + "\n Neighbour Roam State - %s" + "\n CSR State - %s" + "\n CSR Substate - %s", + hdd_connection_state_string + (sta_ctx->conn_info.connState), + mac_trace_get_neighbour_roam_state + (sme_get_neighbor_roam_state + (mac_handle, useAdapter->session_id)), + mac_trace_getcsr_roam_state + (sme_get_current_roam_state + (mac_handle, useAdapter->session_id)), + mac_trace_getcsr_roam_sub_state + (sme_get_current_roam_sub_state + (mac_handle, useAdapter->session_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_sme_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(adapter, &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. + wmmAcStatus[SME_AC_VO].wmmAcAccessRequired, + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_VO]. + wmmAcAccessAllowed ? "YES" : "NO", + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_VO].wmmAcTspecInfo. + ts_info.direction, + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_VI].wmmAcAccessRequired, + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_VI]. + wmmAcAccessAllowed ? "YES" : "NO", + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_VI].wmmAcTspecInfo. + ts_info.direction, + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_BE].wmmAcAccessRequired, + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_BE]. + wmmAcAccessAllowed ? "YES" : "NO", + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_BE].wmmAcTspecInfo. + ts_info.direction, + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_BK].wmmAcAccessRequired, + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_BK]. + wmmAcAccessAllowed ? "YES" : "NO", + adapter->hdd_wmm_status. + wmmAcStatus[SME_AC_BK].wmmAcTspecInfo. + ts_info.direction); + + wrqu->data.length = strlen(extra) + 1; + break; + } + case WE_GET_CHANNEL_LIST: + { + QDF_STATUS status; + uint8_t i, len; + char *buf; + uint8_t ubuf[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t ubuf_len = WNI_CFG_COUNTRY_CODE_LEN; + struct channel_list_info channel_list; + + memset(&channel_list, 0, sizeof(channel_list)); + status = iw_get_channel_list(dev, info, wrqu, + (char *)&channel_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("GetChannelList Failed!!!"); + return -EINVAL; + } + buf = extra; + /* + * Maximum channels = WNI_CFG_VALID_CHANNEL_LIST_LEN. + * Maximum buffer needed = 5 * number of channels. + * Check ifsufficient buffer is available and then + * proceed to fill the buffer. + */ + if (WE_MAX_STR_LEN < + (5 * WNI_CFG_VALID_CHANNEL_LIST_LEN)) { + hdd_err("Insufficient Buffer to populate channel list"); + return -EINVAL; + } + len = scnprintf(buf, WE_MAX_STR_LEN, "%u ", + channel_list.num_channels); + if (QDF_STATUS_SUCCESS == sme_get_country_code(mac_handle, + ubuf, + &ubuf_len)) { + /* Printing Country code in getChannelList */ + for (i = 0; i < (ubuf_len - 1); 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; + + 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 +#ifdef WLAN_FEATURE_11W + case WE_GET_11W_INFO: + { + struct csr_roam_profile *roam_profile = + hdd_roam_profile(adapter); + + hdd_debug("WE_GET_11W_ENABLED = %d", + roam_profile->MFPEnabled); + + snprintf(extra, WE_MAX_STR_LEN, + "\n BSSID %02X:%02X:%02X:%02X:%02X:%02X, Is PMF Assoc? %d" + "\n Number of Unprotected Disassocs %d" + "\n Number of Unprotected Deauths %d", + roam_profile->BSSIDs.bssid->bytes[0], + roam_profile->BSSIDs.bssid->bytes[1], + roam_profile->BSSIDs.bssid->bytes[2], + roam_profile->BSSIDs.bssid->bytes[3], + roam_profile->BSSIDs.bssid->bytes[4], + roam_profile->BSSIDs.bssid->bytes[5], + roam_profile->MFPEnabled, + adapter->hdd_stats.hdd_pmf_stats. + num_unprot_disassoc_rx, + adapter->hdd_stats.hdd_pmf_stats. + num_unprot_deauth_rx); + + wrqu->data.length = strlen(extra) + 1; + break; + } +#endif + case WE_GET_IBSS_STA_INFO: + { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + int idx = 0; + int length = 0, buf = 0; + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (HDD_WLAN_INVALID_STA_ID != + sta_ctx->conn_info.staId[idx]) { + buf = snprintf + ((extra + length), + WE_MAX_STR_LEN - length, + "\n%d .%02x:%02x:%02x:%02x:%02x:%02x\n", + sta_ctx->conn_info.staId[idx], + sta_ctx->conn_info. + peerMacAddress[idx].bytes[0], + sta_ctx->conn_info. + peerMacAddress[idx].bytes[1], + sta_ctx->conn_info. + peerMacAddress[idx].bytes[2], + sta_ctx->conn_info. + peerMacAddress[idx].bytes[3], + sta_ctx->conn_info. + peerMacAddress[idx].bytes[4], + sta_ctx->conn_info. + peerMacAddress[idx].bytes[5] + ); + length += buf; + } + } + 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 currBand; + tSmeConfigParams *sme_config; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("Out of memory"); + ret = -ENOMEM; + break; + } + + sme_get_config_param(mac_handle, sme_config); + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_config->csrConfig.channelBondingMode24GHz) + ch_bond24 = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_config->csrConfig.channelBondingMode5GHz) + ch_bond5g = true; + + qdf_mem_free(sme_config); + + phymode = sme_get_phy_mode(mac_handle); + if ((QDF_STATUS_SUCCESS != + sme_get_freq_band(mac_handle, &currBand))) { + 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 (currBand == BAND_2G) { + if (ch_bond24) + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT40"); + else + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT20"); + } else if (currBand == 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: + if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_20MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT20"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_40MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT40"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_80MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT80"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_160MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT160"); + break; + case eCSR_DOT11_MODE_11ax: + case eCSR_DOT11_MODE_11ax_ONLY: + /* currently using vhtChannelWidth */ + if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_20MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_20"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_40MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_40"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_80MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_80"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_160MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_160"); + 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; + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *sta_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (0 == hdd_ctx->config->fEnableSNRMonitoring || + eConnectionState_Associated != + sta_ctx->conn_info.connState) { + hdd_err("getSNR failed: Enable SNR Monitoring-%d, ConnectionState-%d", + hdd_ctx->config->fEnableSNRMonitoring, + sta_ctx->conn_info.connState); + return -ENONET; + } + wlan_hdd_get_snr(adapter, &s7snr); + snprintf(extra, WE_MAX_STR_LEN, "snr=%d", s7snr); + wrqu->data.length = strlen(extra) + 1; + break; + } + + default: + hdd_err("Invalid IOCTL command %d", sub_cmd); + break; + } + + hdd_exit(); + return ret; +} + +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_char_setnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + 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) +{ + 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_RECOVERY_STAT: + sme_get_recovery_stats(mac_handle); + break; + + case WE_GET_FW_PROFILE_DATA: + ret = wma_cli_set_command(adapter->session_id, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + 0, DBG_CMD); + break; + + case WE_IBSS_GET_PEER_INFO_ALL: + hdd_wlan_get_ibss_peer_info_all(adapter); + break; + + case WE_SET_REASSOC_TRIGGER: + { + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + tSirMacAddr bssid; + uint32_t roamId = INVALID_ROAM_ID; + uint8_t operating_ch = + adapter->session.station.conn_info.operationChannel; + tCsrRoamModifyProfileFields modProfileFields; + + sme_get_modify_profile_fields(mac_handle, adapter->session_id, + &modProfileFields); + if (roaming_offload_enabled(hdd_ctx)) { + qdf_mem_copy(bssid, + &adapter->session.station.conn_info.bssId, + sizeof(bssid)); + hdd_wma_send_fastreassoc_cmd(adapter, + bssid, operating_ch); + } else { + sme_roam_reassoc(mac_handle, adapter->session_id, + NULL, modProfileFields, &roamId, 1); + } + 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 comamnd 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->session_id); + break; + + default: + hdd_err("unknown ioctl %d", sub_cmd); + break; + } + hdd_exit(); + return ret; +} + +static int iw_setnone_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef MPC_UT_FRAMEWORK +static int iw_get_policy_manager_ut_ops(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, int sub_cmd, int *apps_args) +{ + switch (sub_cmd) { + case WE_POLICY_MANAGER_CLIST_CMD: + { + hdd_debug(" is called"); + if ((apps_args[0] < 0) || (apps_args[1] < 0) || + (apps_args[2] < 0) || (apps_args[3] < 0) || + (apps_args[4] < 0) || (apps_args[5] < 0) || + (apps_args[6] < 0) || (apps_args[7] < 0)) { + hdd_err("Invalid input params received for the IOCTL"); + return 0; + } + policy_mgr_incr_connection_count_utfw(hdd_ctx->psoc, + apps_args[0], apps_args[1], apps_args[2], apps_args[3], + apps_args[4], apps_args[5], apps_args[6], apps_args[7]); + } + break; + + case WE_POLICY_MANAGER_DLIST_CMD: + { + hdd_debug(" is called"); + if ((apps_args[0] < 0) || (apps_args[1] < 0)) { + hdd_err("Invalid input params received for the IOCTL"); + return 0; + } + policy_mgr_decr_connection_count_utfw(hdd_ctx->psoc, + apps_args[0], apps_args[1]); + } + break; + + case WE_POLICY_MANAGER_ULIST_CMD: + { + hdd_debug(" is called"); + if ((apps_args[0] < 0) || (apps_args[1] < 0) || + (apps_args[2] < 0) || (apps_args[3] < 0) || + (apps_args[4] < 0) || (apps_args[5] < 0) || + (apps_args[6] < 0) || (apps_args[7] < 0)) { + hdd_err("Invalid input params received for the IOCTL"); + return 0; + } + policy_mgr_update_connection_info_utfw(hdd_ctx->psoc, + apps_args[0], apps_args[1], apps_args[2], apps_args[3], + apps_args[4], apps_args[5], apps_args[6], apps_args[7]); + } + break; + + case WE_POLICY_MANAGER_DBS_CMD: + { + hdd_debug(" is called"); + if (apps_args[0] == 0) + wma_set_dbs_capability_ut(0); + else + wma_set_dbs_capability_ut(1); + + if (apps_args[1] >= PM_THROUGHPUT && + apps_args[1] <= PM_LATENCY) { + pr_info("setting system pref to [%d]\n", apps_args[1]); + hdd_ctx->config->conc_system_pref = apps_args[1]; + } + } + break; + + case WE_POLICY_MANAGER_PCL_CMD: + { + uint8_t pcl[QDF_MAX_NUM_CHAN] = {0}; + uint8_t weight_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0, i = 0; + + hdd_debug(" is called"); + + if (apps_args[0] < 0) { + hdd_err("Invalid input param received for the IOCTL"); + return 0; + } + policy_mgr_get_pcl(hdd_ctx->psoc, apps_args[0], + pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + pr_info("PCL list for role[%d] is {", apps_args[0]); + for (i = 0 ; i < pcl_len; i++) + pr_info(" %d, ", pcl[i]); + pr_info("}--------->\n"); + } + break; + + case WE_POLICY_SET_HW_MODE_CMD: + { + if (apps_args[0] == 0) { + hdd_err("set hw mode for single mac"); + policy_mgr_pdev_set_hw_mode(hdd_ctx->psoc, + adapter->session_id, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + POLICY_MGR_UPDATE_REASON_UT, PM_NOP); + } else if (apps_args[0] == 1) { + hdd_err("set hw mode for dual mac"); + policy_mgr_pdev_set_hw_mode(hdd_ctx->psoc, + adapter->session_id, + HW_MODE_SS_1x1, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + POLICY_MGR_UPDATE_REASON_UT, PM_NOP); + } + } + break; + + case WE_POLICY_MANAGER_QUERY_ACTION_CMD: + { + hdd_debug(" is called"); + if (apps_args[0] < 0) { + hdd_err("Invalid input params received for the IOCTL"); + return 0; + } + policy_mgr_current_connections_update( + hdd_ctx->psoc, + adapter->session_id, apps_args[0], + POLICY_MGR_UPDATE_REASON_UT); + } + break; + + case WE_POLICY_MANAGER_QUERY_ALLOW_CMD: + { + bool allow; + + hdd_debug(" is called"); + if ((apps_args[0] < 0) || (apps_args[1] < 0) || + (apps_args[2] < 0)) { + hdd_err("Invalid input params received for the IOCTL"); + return 0; + } + allow = policy_mgr_allow_concurrency(hdd_ctx->psoc, + apps_args[0], apps_args[1], apps_args[2]); + pr_info("allow %d {0 = don't allow, 1 = allow}", allow); + } + break; + + case WE_POLICY_MANAGER_SCENARIO_CMD: + { + clean_report(hdd_ctx); + if (apps_args[0] == 1) { + wlan_hdd_one_connection_scenario(hdd_ctx); + } else if (apps_args[0] == 2) { + wlan_hdd_two_connections_scenario(hdd_ctx, + 6, POLICY_MGR_TWO_TWO); + wlan_hdd_two_connections_scenario(hdd_ctx, + 36, POLICY_MGR_TWO_TWO); + wlan_hdd_two_connections_scenario(hdd_ctx, + 6, POLICY_MGR_ONE_ONE); + wlan_hdd_two_connections_scenario(hdd_ctx, + 36, POLICY_MGR_ONE_ONE); + } else if (apps_args[0] == 3) { + /* MCC on same band with 2x2 same mac*/ + wlan_hdd_three_connections_scenario(hdd_ctx, + 6, 11, POLICY_MGR_TWO_TWO, 0); + /* MCC on diff band with 2x2 same mac*/ + wlan_hdd_three_connections_scenario(hdd_ctx, + 6, 36, POLICY_MGR_TWO_TWO, 0); + /* MCC on diff band with 1x1 diff mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 6, POLICY_MGR_ONE_ONE, 0); + /* MCC on diff band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 6, POLICY_MGR_ONE_ONE, 1); + /* SCC on same band with 2x2 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 36, POLICY_MGR_TWO_TWO, 0); + /* SCC on same band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 36, POLICY_MGR_ONE_ONE, 1); + /* MCC on same band with 2x2 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 149, POLICY_MGR_TWO_TWO, 0); + /* MCC on same band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 149, POLICY_MGR_ONE_ONE, 1); + } + print_report(hdd_ctx); + } + break; + } + return 0; +} +#else +static int iw_get_policy_manager_ut_ops(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, int sub_cmd, int *apps_args) +{ + return 0; +} +#endif + +/** + * 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 +/** + * __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; + int sub_cmd; + int *apps_args = (int *) extra; + struct hdd_context *hdd_ctx; + int ret, num_args; + + 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; + + hdd_debug("Received length %d", wrqu->data.length); + + switch (sub_cmd) { + case WE_IBSS_GET_PEER_INFO: + { + pr_info("Station ID = %d\n", apps_args[0]); + hdd_wlan_get_ibss_peer_info(adapter, apps_args[0]); + } + break; + + case WE_P2P_NOA_CMD: + { + struct p2p_app_set_ps p2pNoA; + + if (adapter->device_mode != QDF_P2P_GO_MODE) { + hdd_err("Setting NoA is not allowed in Device mode %s(%d)", + hdd_device_mode_to_string( + adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + p2pNoA.opp_ps = apps_args[0]; + p2pNoA.ctWindow = apps_args[1]; + p2pNoA.duration = apps_args[2]; + p2pNoA.interval = apps_args[3]; + p2pNoA.count = apps_args[4]; + p2pNoA.single_noa_duration = apps_args[5]; + p2pNoA.psSelection = apps_args[6]; + + hdd_debug("P2P_NOA_ATTR:oppPS %d ctWindow %d duration %d interval %d count %d single noa duration %d PsSelection %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, &p2pNoA); + + } + 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++) { + pr_info("|table_index[%d]\t\t\n", i); + pr_info("|\t|vdev_id - %-10d|\n", conn_info->vdev_id); + pr_info("|\t|chan - %-10d|\n", conn_info->chan); + pr_info("|\t|bw - %-10d|\n", conn_info->bw); + pr_info("|\t|mode - %-10d|\n", conn_info->mode); + pr_info("|\t|mac - %-10d|\n", conn_info->mac); + pr_info("|\t|in_use - %-10d|\n", conn_info->in_use); + pr_info("+--------------------------+\n"); + conn_info++; + } + } + break; + + case WE_UNIT_TEST_CMD: + { + QDF_STATUS status; + + if ((apps_args[0] < WLAN_MODULE_ID_MIN) || + (apps_args[0] >= WLAN_MODULE_ID_MAX)) { + hdd_err("Invalid MODULE ID %d", apps_args[0]); + return -EINVAL; + } + if ((apps_args[1] > (WMA_MAX_NUM_ARGS)) || + (apps_args[1] < 0)) { + hdd_err("Too Many/Few args %d", apps_args[1]); + return -EINVAL; + } + status = sme_send_unit_test_cmd(adapter->session_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->session_id, + &mac_pwr_dbg_args)) { + return -EINVAL; + } + } + break; + case WE_POLICY_MANAGER_CLIST_CMD: + case WE_POLICY_MANAGER_DLIST_CMD: + case WE_POLICY_MANAGER_ULIST_CMD: + case WE_POLICY_MANAGER_DBS_CMD: + case WE_POLICY_MANAGER_PCL_CMD: + case WE_POLICY_SET_HW_MODE_CMD: + case WE_POLICY_MANAGER_QUERY_ACTION_CMD: + case WE_POLICY_MANAGER_QUERY_ALLOW_CMD: + case WE_POLICY_MANAGER_SCENARIO_CMD: + { + iw_get_policy_manager_ut_ops(hdd_ctx, adapter, + sub_cmd, apps_args); + } + break; + case WE_SET_CHAN_AVOID: + { + hdd_ch_avoid_unit_cmd(hdd_ctx, num_args, apps_args); + } + break; + 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 ret, num_args; + + 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 (NULL == 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; + } + + cds_ssr_protect(__func__); + ret = __iw_set_var_ints_getnone(dev, info, &u_priv_wrqu, + (char *)&apps_args); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_set_var_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * 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); + struct hdd_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_wlan_wmm_status_e *pStatus = (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 priviledged */ + /* 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 (eConnectionState_Associated != sta_ctx->conn_info.connState) { + *pStatus = 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)) { + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* make sure all params are correctly passed to function */ + if ((NULL == s_priv_data.pointer) || + (HDD_WLAN_WMM_PARAM_COUNT != s_priv_data.length)) { + *pStatus = 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 */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* validate the TID */ + if (params[HDD_WLAN_WMM_PARAM_TID] > 7) { + /* out of range */ + *pStatus = 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 */ + *pStatus = 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 */ + *pStatus = 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 HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK: + tSpec.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case HDD_WLAN_WMM_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 */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_addts(adapter, handle, &tSpec); + hdd_exit(); + return 0; +} + +static int iw_add_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_add_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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 *pStatus = (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 priviledged */ + /* 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 */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_delts(adapter, handle); + hdd_exit(); + return 0; +} + +static int iw_del_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_del_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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 *pStatus = (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 */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_checkts(adapter, handle); + hdd_exit(); + return 0; +} + +static int iw_get_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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_station_ctx *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + 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 == NULL) { + hdd_err("called with NULL IE"); + return -EINVAL; + } + /* Added for debug on reception of Re-assoc Req. */ + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + 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 */ + sme_set_ft_ies(hdd_ctx->mac_handle, adapter->session_id, + extra, wrqu->data.length); + hdd_exit(); + return 0; +} + +static int iw_set_fties(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_fties(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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 *pRequest = (struct host_offload_req *) extra; + tSirHostOffloadReq offloadRequest; + 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_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("dev is not in CONNECTED state, ignore!!!"); + return -EINVAL; + } + + /* Debug display of request components. */ + switch (pRequest->offloadType) { + case WLAN_IPV4_ARP_REPLY_OFFLOAD: + hdd_debug("Host offload request: ARP reply"); + switch (pRequest->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: %d.%d.%d.%d", + pRequest->params.hostIpv4Addr[0], + pRequest->params.hostIpv4Addr[1], + pRequest->params.hostIpv4Addr[2], + pRequest->params.hostIpv4Addr[3]); + } + break; + + case WLAN_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD: + hdd_debug("Host offload request: neighbor discovery"); + switch (pRequest->enableOrDisable) { + case WLAN_OFFLOAD_DISABLE: + hdd_debug(" disable"); + break; + case WLAN_OFFLOAD_ENABLE: + hdd_debug(" enable"); + hdd_debug(" IP address: %x:%x:%x:%x:%x:%x:%x:%x", + *(uint16_t *) (pRequest->params.hostIpv6Addr), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 2), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 4), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 6), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 8), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 10), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 12), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 14)); + } + } + + qdf_mem_zero(&offloadRequest, sizeof(offloadRequest)); + offloadRequest.offloadType = pRequest->offloadType; + offloadRequest.enableOrDisable = pRequest->enableOrDisable; + qdf_mem_copy(&offloadRequest.params, &pRequest->params, + sizeof(pRequest->params)); + qdf_mem_copy(&offloadRequest.bssid, &pRequest->bssId.bytes, + QDF_MAC_ADDR_SIZE); + + if (QDF_STATUS_SUCCESS != + sme_set_host_offload(hdd_ctx->mac_handle, + adapter->session_id, &offloadRequest)) { + hdd_err("Failure to execute host offload request"); + return -EINVAL; + } + hdd_exit(); + return 0; +} + +static int iw_set_host_offload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_host_offload(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * 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); + tpSirKeepAliveReq request = (tpSirKeepAliveReq) 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 > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) { + hdd_err("Value of timePeriod %d exceed Max limit %d", + request->timePeriod, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX); + return -EINVAL; + } + + /* Debug display of request components. */ + hdd_debug("Set Keep Alive Request : TimePeriod %d size %zu", + request->timePeriod, sizeof(tSirKeepAliveReq)); + + 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: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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->session_id, request)) { + hdd_err("Failure to execute Keep Alive"); + return -EINVAL; + } + hdd_exit(); + return 0; +} + +static int iw_set_keepalive_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_keepalive_params(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * validate_packet_filter_params_size() - Validate the size of the params rcvd + * @priv_data: Pointer to the priv data from user space + * @request: Pointer to the struct containing the copied data from user space + * + * 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 ((NULL == priv_data.pointer) || (0 == priv_data.length) || + priv_data.length < sizeof(struct pkt_filter_cfg)) { + 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_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + 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 (NULL == 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->session_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 ret; + + cds_ssr_protect(__func__); + ret = __iw_set_packet_filter_params(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#ifdef QCA_SUPPORT_CP_STATS +static int hdd_get_wlan_stats(struct hdd_adapter *adapter) +{ + return wlan_hdd_get_station_stats(adapter); +} +#else /* QCA_SUPPORT_CP_STATS */ +struct hdd_statistics_priv { + tCsrSummaryStatsInfo summary_stats; + tCsrGlobalClassAStatsInfo class_a_stats; + tCsrGlobalClassDStatsInfo class_d_stats; +}; + +/** + * hdd_statistics_cb() - "Get statistics" callback function + * @stats: statistics payload + * @context: opaque context originally passed to SME. HDD always passes + * a cookie for the request context + * + * Return: None + */ +static void hdd_statistics_cb(void *stats, void *context) +{ + struct osif_request *request; + struct hdd_statistics_priv *priv; + tCsrSummaryStatsInfo *summary_stats; + tCsrGlobalClassAStatsInfo *class_a_stats; + tCsrGlobalClassDStatsInfo *class_d_stats; + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + summary_stats = (tCsrSummaryStatsInfo *)stats; + priv->summary_stats = *summary_stats; + + class_a_stats = (tCsrGlobalClassAStatsInfo *)(summary_stats + 1); + priv->class_a_stats = *class_a_stats; + + class_d_stats = (tCsrGlobalClassDStatsInfo *)(class_a_stats + 1); + priv->class_d_stats = *class_d_stats; + + osif_request_complete(request); + osif_request_put(request); +} + +static int hdd_get_wlan_stats(struct hdd_adapter *adapter) +{ + int ret = 0; + void *cookie; + QDF_STATUS status; + struct osif_request *request; + struct hdd_station_ctx *sta_ctx; + struct hdd_statistics_priv *priv; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + request = osif_request_alloc(¶ms); + if (!request) { + hdd_warn("request allocation failed"); + return -EINVAL; + } + + cookie = osif_request_cookie(request); + status = sme_get_statistics(hdd_ctx->mac_handle, eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_GLOBAL_CLASSD_STATS, + hdd_statistics_cb, + sta_ctx->conn_info.staId[0], + cookie, adapter->session_id); + + if (QDF_STATUS_SUCCESS != status) { + hdd_warn("Unable to retrieve SME statistics"); + goto put_request; + } + + /* request was sent -- wait for the response */ + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Failed to wait for statistics, errno %d", ret); + goto put_request; + } + + /* update the adapter cache with the fresh results */ + priv = osif_request_priv(request); + adapter->hdd_stats.summary_stat = priv->summary_stats; + adapter->hdd_stats.class_a_stat = priv->class_a_stats; + adapter->hdd_stats.class_d_stat = priv->class_d_stats; + +put_request: + /* + * 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 ret; +} +#endif /* QCA_SUPPORT_CP_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); + if (eConnectionState_Associated != sta_ctx->conn_info.connState) { + wrqu->data.length = 0; + return 0; + } + + hdd_get_wlan_stats(adapter); + + summary_stats = &(adapter->hdd_stats.summary_stat); + class_a_stats = &(adapter->hdd_stats.class_a_stat); + class_d_stats = &(adapter->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 ret; + + cds_ssr_protect(__func__); + ret = __iw_get_statistics(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#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 */ + + wireless_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_LEGACY_MAC_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) { + hdd_err("fail to allocate memory %zu", len); + return -EINVAL; + } + 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].channel_cnt), + &offset); + + if (3 != params) { + hdd_err("Incorrect cmd %s", ptr); + ret = -EINVAL; + goto exit; + } + + hdd_debug("PNO len %d ssid %.*s auth %d encry %d channel count %d offset %d", + req.networks_list[i].ssid.length, + 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].channel_cnt, offset); + + /* Advance to channel list */ + ptr += offset; + + if (SCAN_PNO_MAX_NETW_CHANNELS_EX < + req.networks_list[i].channel_cnt) { + hdd_err("Incorrect number of channels"); + ret = -EINVAL; + goto exit; + } + + if (0 != req.networks_list[i].channel_cnt) { + for (j = 0; j < req.networks_list[i].channel_cnt; + 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].channels[j] = + 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_LEGACY_MAC_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 ret; + + cds_ssr_protect(__func__); + ret = __iw_set_pno(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#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 ret; + + cds_ssr_protect(__func__); + ret = __iw_set_band_config(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +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; +} + +static void hdd_ioctl_log_buffer(int log_id, uint32_t count) +{ + qdf_abstract_print *print = &printk_adapter; + + switch (log_id) { + case HTC_CREDIT_HISTORY_LOG: + cds_print_htc_credit_history(count, print, NULL); + break; + case COMMAND_LOG: + wma_print_wmi_cmd_log(count, print, NULL); + break; + case COMMAND_TX_CMP_LOG: + wma_print_wmi_cmd_tx_cmp_log(count, print, NULL); + break; + case MGMT_COMMAND_LOG: + wma_print_wmi_mgmt_cmd_log(count, print, NULL); + break; + case MGMT_COMMAND_TX_CMP_LOG: + wma_print_wmi_mgmt_cmd_tx_cmp_log(count, print, NULL); + break; + case EVENT_LOG: + wma_print_wmi_event_log(count, print, NULL); + break; + case RX_EVENT_LOG: + wma_print_wmi_rx_event_log(count, print, NULL); + break; + case MGMT_EVENT_LOG: + wma_print_wmi_mgmt_event_log(count, print, NULL); + break; + default: + print(NULL, "Invalid Log Id %d", log_id); + break; + } +} + +#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; + + hdd_debug("WE_SET_FW_CRASH_INJECT: %d %d", + v1, v2); + pr_err("SSR is triggered by iwpriv CRASH_INJECT: %d %d\n", + v1, v2); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx->config->crash_inject_enabled) { + 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->session_id, + GEN_PARAM_CRASH_INJECT, + v1, v2, GEN_CMD); + return ret; +} +#endif + +#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; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + void *soc = NULL; + struct cdp_pdev *pdev = NULL; + struct cdp_vdev *vdev = NULL; + struct cdp_txrx_stats_req req = {0}; + + 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_TXRX_STATS: + { + ret = cds_get_datapath_handles(&soc, &pdev, &vdev, + adapter->session_id); + + if (ret != 0) { + hdd_err("Invalid handles"); + break; + } + + req.stats = value[1]; + req.mac_id = value[2]; + hdd_debug("WE_SET_TXRX_STATS stats cmd: %d mac_id: %d", + req.stats, req.mac_id); + ret = cdp_txrx_stats_request(soc, vdev, &req); + break; + } + case WE_SET_SMPS_PARAM: + hdd_debug("WE_SET_SMPS_PARAM val %d %d", value[1], value[2]); + ret = wma_cli_set_command(adapter->session_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->session_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->session_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"); + if (hdd_ctx->config->dual_mac_feature_disable == + 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: + ret = wlan_hdd_set_mon_chan(adapter, 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); + + 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 ret; + + cds_ssr_protect(__func__); + ret = __iw_set_two_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* 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, + [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"}, + + {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 | IW_PRIV_SIZE_FIXED | 2, + 0, + "txrx_stats"}, + + {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"}, + + {WE_SET_CONFIG, + IW_PRIV_TYPE_CHAR | 512, + 0, + "setConfig"}, + +#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 +#ifdef WLAN_FEATURE_11W + { + WE_GET_11W_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getPMFInfo" + }, +#endif + { + WE_GET_IBSS_STA_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getIbssSTAs" + }, + {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"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_NONE_GET_NONE, + 0, + 0, + ""}, + + /* handlers for sub-ioctl */ + { + WE_IBSS_GET_PEER_INFO_ALL, + 0, + 0, + "ibssPeerInfoAll" + }, + {WE_GET_RECOVERY_STAT, + 0, + 0, + "getRecoverStat"}, + + {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, + ""}, + + /* handlers for sub-ioctl */ + {WE_IBSS_GET_PEER_INFO, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "ibssPeerInfo"}, + +#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"}, + +#ifdef MPC_UT_FRAMEWORK + {WE_POLICY_MANAGER_CLIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_clist"}, + + {WE_POLICY_MANAGER_DLIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_dlist"}, + + {WE_POLICY_MANAGER_DBS_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_dbs"}, + + {WE_POLICY_MANAGER_PCL_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_pcl"}, + + {WE_POLICY_MANAGER_ULIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_ulist"}, + + {WE_POLICY_MANAGER_QUERY_ACTION_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_query_action"}, + + {WE_POLICY_MANAGER_QUERY_ALLOW_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_query_allow"}, + + {WE_POLICY_MANAGER_SCENARIO_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_run_scenario"}, + + {WE_POLICY_SET_HW_MODE_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_set_hw_mode"}, +#endif + { + 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(tSirKeepAliveReq) | + 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" + } + , + + /* 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 +#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"}, +}; + +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_unregister_wext(struct net_device *dev) +{ + hdd_enter_dev(dev); + + rtnl_lock(); + dev->wireless_handlers = NULL; + rtnl_unlock(); + + hdd_exit(); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c new file mode 100644 index 0000000000000000000000000000000000000000..94324407b4ff8681e43a71b7adea8abde5b86e7d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c @@ -0,0 +1,2411 @@ +/* + * 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: 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 +#include +#include +#include +#include +#include +#include "sme_api.h" + +#define WLAN_HDD_MAX_DSCP 0x3f + +#define HDD_WMM_UP_TO_AC_MAP_SIZE 8 + +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 +}; + +/** + * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to + * operate on different traffic. + */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter) +{ + /* Enable HI_PRIO queue */ + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK); + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO); + +} +#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 + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_enable_tl_uapsd(struct hdd_wmm_qos_context *pQosContext) +{ + struct hdd_adapter *adapter = pQosContext->adapter; + sme_ac_enum_type acType = pQosContext->acType; + struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + 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; + + /* The TSPEC must be valid */ + if (pAc->wmmAcTspecValid == false) { + hdd_err("Invoked with invalid TSPEC"); + return; + } + /* determine the service interval */ + if (pAc->wmmAcTspecInfo.min_service_interval) { + service_interval = pAc->wmmAcTspecInfo.min_service_interval; + } else if (pAc->wmmAcTspecInfo.max_service_interval) { + service_interval = pAc->wmmAcTspecInfo.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 = pAc->wmmAcTspecInfo.suspension_interval; + direction = pAc->wmmAcTspecInfo.ts_info.direction; + psb = pAc->wmmAcTspecInfo.ts_info.psb; + + /* if we have previously enabled U-APSD, have any params changed? */ + if ((pAc->wmmAcUapsdInfoValid) && + (pAc->wmmAcUapsdServiceInterval == service_interval) && + (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) && + (pAc->wmmAcUapsdDirection == direction) && + (pAc->wmmAcIsUapsdEnabled == psb)) { + hdd_debug("No change in U-APSD parameters"); + return; + } + /* everything is in place to notify TL */ + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR(adapter))-> + conn_info.staId[0], acType, + pAc->wmmAcTspecInfo.ts_info.tid, + pAc->wmmAcTspecInfo.ts_info.up, + service_interval, suspension_interval, + direction, psb, adapter->session_id, + hdd_ctx->config->DelayedTriggerFrmInt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to enable U-APSD for AC=%d", acType); + return; + } + /* stash away the parameters that were used */ + pAc->wmmAcUapsdInfoValid = true; + pAc->wmmAcUapsdServiceInterval = service_interval; + pAc->wmmAcUapsdSuspensionInterval = suspension_interval; + pAc->wmmAcUapsdDirection = direction; + pAc->wmmAcIsUapsdEnabled = psb; + + hdd_debug("Enabled UAPSD in TL srv_int=%d susp_int=%d dir=%d AC=%d", + service_interval, suspension_interval, direction, acType); + +} + +/** + * hdd_wmm_disable_tl_uapsd() - function which decides whether + * to disable UAPSD parameters in TL + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_disable_tl_uapsd(struct hdd_wmm_qos_context *pQosContext) +{ + struct hdd_adapter *adapter = pQosContext->adapter; + sme_ac_enum_type acType = pQosContext->acType; + struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + QDF_STATUS status; + + /* have we previously enabled UAPSD? */ + if (pAc->wmmAcUapsdInfoValid == true) { + status = + sme_disable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info.staId[0], + acType, adapter->session_id); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to disable U-APSD for AC=%d", acType); + } else { + /* TL no longer has valid UAPSD info */ + pAc->wmmAcUapsdInfoValid = false; + hdd_debug("Disabled UAPSD in TL for AC=%d", acType); + } + } +} + +#endif + +/** + * hdd_wmm_free_context() - function which frees a QoS context + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_free_context(struct hdd_wmm_qos_context *pQosContext) +{ + struct hdd_adapter *adapter; + + hdd_debug("Entered, context %pK", pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + /* must have been freed in another thread */ + return; + } + /* get pointer to the adapter context */ + adapter = pQosContext->adapter; + + /* take the wmmLock since we're manipulating the context list */ + mutex_lock(&adapter->hdd_wmm_status.wmmLock); + + /* make sure nobody thinks this is a valid context */ + pQosContext->magic = 0; + + /* unlink the context */ + list_del(&pQosContext->node); + + /* done manipulating the list */ + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + + /* reclaim memory */ + qdf_mem_free(pQosContext); + +} + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/** + * hdd_wmm_notify_app() - function which notifies an application + * of changes in state of it flow + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +#define MAX_NOTIFY_LEN 50 +static void hdd_wmm_notify_app(struct hdd_wmm_qos_context *pQosContext) +{ + struct hdd_adapter *adapter; + union iwreq_data wrqu; + char buf[MAX_NOTIFY_LEN + 1]; + + hdd_debug("Entered, context %pK", pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->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)pQosContext->handle, + (unsigned int)pQosContext->lastStatus); + + wrqu.data.pointer = buf; + wrqu.data.length = strlen(buf); + + /* get pointer to the adapter */ + adapter = pQosContext->adapter; + + /* send the event */ + hdd_debug("Sending [%s]", buf); + wireless_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 *pQosContext = user_data; + struct hdd_adapter *adapter; + struct hdd_wmm_ac_status *pAc; + hdd_wlan_wmm_status_e status; + QDF_STATUS qdf_status; + uint32_t currentTrafficCnt = 0; + sme_ac_enum_type acType; + + if (!pQosContext) { + hdd_err("invalid user data"); + return; + } + acType = pQosContext->acType; + + adapter = pQosContext->adapter; + if ((NULL == adapter) || + (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("invalid adapter: %pK", adapter); + return; + } + + pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + + /* Get the Tx stats for this AC. */ + currentTrafficCnt = + adapter->hdd_stats.tx_rx_stats.tx_classified_ac[pQosContext-> + acType]; + + hdd_warn("WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d", + acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt); + if (pAc->wmmPrevTrafficCnt == currentTrafficCnt) { + /* there is no traffic activity, delete the TSPEC for this AC */ + status = hdd_wmm_delts(adapter, pQosContext->handle); + hdd_warn("Deleted TS on AC %d, due to inactivity with status = %d!!!", + acType, status); + } else { + pAc->wmmPrevTrafficCnt = currentTrafficCnt; + if (pAc->wmmInactivityTimer.state == QDF_TIMER_STATE_STOPPED) { + /* Restart the timer */ + qdf_status = + qdf_mc_timer_start(&pAc->wmmInactivityTimer, + pAc->wmmInactivityTime); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Restarting inactivity timer failed on AC %d", + acType); + } + } else { + QDF_ASSERT(qdf_mc_timer_get_current_state + (&pAc->wmmInactivityTimer) == + QDF_TIMER_STATE_STOPPED); + } + } +} + +/** + * hdd_wmm_enable_inactivity_timer() - + * function to enable the traffic inactivity timer for the given AC + * + * @pQosContext: [in] pointer to pQosContext + * @inactivityTime: [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 *pQosContext, + uint32_t inactivityTime) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct hdd_adapter *adapter = pQosContext->adapter; + sme_ac_enum_type acType = pQosContext->acType; + struct hdd_wmm_ac_status *pAc; + + adapter = pQosContext->adapter; + pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + + qdf_status = qdf_mc_timer_init(&pAc->wmmInactivityTimer, + QDF_TIMER_TYPE_SW, + hdd_wmm_inactivity_timer_cb, + pQosContext); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Initializing inactivity timer failed on AC %d", + acType); + return qdf_status; + } + /* Start the inactivity timer */ + qdf_status = qdf_mc_timer_start(&pAc->wmmInactivityTimer, + inactivityTime); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Starting inactivity timer failed on AC %d", + acType); + qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to destroy inactivity timer"); + + return qdf_status; + } + pAc->wmmInactivityTime = inactivityTime; + /* Initialize the current tx traffic count on this AC */ + pAc->wmmPrevTrafficCnt = + adapter->hdd_stats.tx_rx_stats.tx_classified_ac[pQosContext-> + acType]; + pQosContext->is_inactivity_timer_running = true; + return qdf_status; +} + +/** + * hdd_wmm_disable_inactivity_timer() - + * function to disable the traffic inactivity timer for the given AC. + * + * @pQosContext: [in] pointer to pQosContext + * + * 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 *pQosContext) +{ + struct hdd_adapter *adapter = pQosContext->adapter; + sme_ac_enum_type acType = pQosContext->acType; + struct hdd_wmm_ac_status *pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + /* Clear the timer and the counter */ + pAc->wmmInactivityTime = 0; + pAc->wmmPrevTrafficCnt = 0; + + if (pQosContext->is_inactivity_timer_running == true) { + pQosContext->is_inactivity_timer_running = false; + qdf_status = qdf_mc_timer_stop(&pAc->wmmInactivityTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to stop inactivity timer"); + return qdf_status; + } + qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer); + 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 *pQosContext) +{ + 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 + * @pCurrentQosInfo : [in] the TSPEC params + * @smeStatus : [in] the QoS related SME status + * @qosFlowId: [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 *pCurrentQosInfo, + enum sme_qos_statustype smeStatus, + uint32_t qosFlowId) +{ + struct hdd_wmm_qos_context *pQosContext = context; + struct hdd_adapter *adapter; + sme_ac_enum_type acType; + struct hdd_wmm_ac_status *pAc; + + hdd_debug("Entered, context %pK", pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + hdd_err("Invalid QoS Context"); + return QDF_STATUS_E_FAILURE; + } + + adapter = pQosContext->adapter; + acType = pQosContext->acType; + pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + + hdd_debug("status %d flowid %d info %pK", + smeStatus, qosFlowId, pCurrentQosInfo); + + switch (smeStatus) { + + 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 (pCurrentQosInfo) { + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + } + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = false; + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + +#ifdef FEATURE_WLAN_ESE + /* Check if the inactivity interval is specified */ + if (pCurrentQosInfo && pCurrentQosInfo->inactivity_interval) { + hdd_debug("Inactivity timer value = %d for AC=%d", + pCurrentQosInfo->inactivity_interval, acType); + hdd_wmm_enable_inactivity_timer(pQosContext, + pCurrentQosInfo-> + inactivity_interval); + } +#endif /* FEATURE_WLAN_ESE */ + + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + hdd_debug("Setup is complete (U-APSD set previously)"); + + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(pQosContext); + } + + break; + + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + hdd_err("Setup failed"); + /* QoS setup failed */ + + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = true; + pAc->wmmAcAccessAllowed = false; + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED; + + hdd_wmm_notify_app(pQosContext); + } + + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(pQosContext); + + /* 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(pQosContext); + break; + + case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: + hdd_err("Setup Invalid Params, notify TL"); + /* QoS setup failed */ + pAc->wmmAcAccessAllowed = false; + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->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" + */ + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = true; + pAc->wmmAcAccessAllowed = true; + + } else { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + hdd_err("Setup failed, not a QoS AP"); + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + hdd_info("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + hdd_wmm_notify_app(pQosContext); + } + 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 (pCurrentQosInfo) { + /* update the TSPEC */ + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFIED; + hdd_wmm_notify_app(pQosContext); + } + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + + /* this was triggered by implicit QoS so we + * know packets are pending + */ + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessAllowed = true; + + } else { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(pQosContext); + } + 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 == pQosContext->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" + */ + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessFailed = false; + pAc->wmmAcAccessPending = false; + + } else { + hdd_info("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED; + hdd_wmm_notify_app(pQosContext); + } + + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: + hdd_debug("Release is complete"); + + if (pCurrentQosInfo) { + hdd_debug("flows still active"); + + /* there is still at least one flow active for + * this AC so update the AC state + */ + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(pQosContext); + } else { + hdd_debug("last flow"); + + /* this is the last flow active for this AC so + * update the AC state + */ + pAc->wmmAcTspecValid = false; + + /* DELTS is successful, do not allow */ + pAc->wmmAcAccessAllowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(pQosContext); + } + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(pQosContext); + + /* we are done with this flow */ + hdd_wmm_free_context(pQosContext); + 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 != pQosContext->handle) { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + hdd_wmm_notify_app(pQosContext); + } + + break; + + case SME_QOS_STATUS_RELEASE_QOS_LOST_IND: + hdd_debug("QOS Lost indication received"); + + /* current TSPEC is no longer valid */ + pAc->wmmAcTspecValid = false; + /* AP has sent DELTS, do not allow */ + pAc->wmmAcAccessAllowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + /* we no longer have implicit access granted */ + pAc->wmmAcAccessGranted = false; + pAc->wmmAcAccessFailed = false; + } else { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST; + hdd_wmm_notify_app(pQosContext); + } + + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(pQosContext); + + /* we are done with this flow */ + hdd_wmm_free_context(pQosContext); + 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 != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + 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 (pCurrentQosInfo) { + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + } + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(pQosContext); + } + 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 != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + hdd_wmm_notify_app(pQosContext); + } + 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 != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: + /* invalid params -- notify the application */ + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + 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 != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED; + hdd_wmm_notify_app(pQosContext); + } + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + 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(pQosContext); + 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(pQosContext); + break; + + default: + hdd_err("unexpected SME Status=%d", smeStatus); + QDF_ASSERT(0); + } + + /* if Tspec only allows downstream traffic then access is not + * allowed + */ + if (pAc->wmmAcTspecValid && + (pAc->wmmAcTspecInfo.ts_info.direction == + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + pAc->wmmAcAccessAllowed = false; + } + /* if we have valid Tpsec or if ACM bit is not set, allow access */ + if ((pAc->wmmAcTspecValid && + (pAc->wmmAcTspecInfo.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) || !pAc->wmmAcAccessRequired) { + pAc->wmmAcAccessAllowed = true; + } + + hdd_debug("complete, access for TL AC %d is%sallowed", + acType, pAc->wmmAcAccessAllowed ? " " : " 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 (NULL == adapter) { + hdd_err("adapter is NULL"); + return -EINVAL; + } + if (NULL == 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. + * @work: [in] pointer to work structure. + * + * Return: none + */ +static void __hdd_wmm_do_implicit_qos(struct work_struct *work) +{ + struct hdd_wmm_qos_context *pQosContext = + container_of(work, struct hdd_wmm_qos_context, + wmmAcSetupImplicitQos); + struct hdd_adapter *adapter; + sme_ac_enum_type acType; + struct hdd_wmm_ac_status *pAc; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + enum sme_qos_statustype smeStatus; +#endif + struct sme_qos_wmmtspecinfo qosInfo; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + + hdd_debug("Entered, context %pK", pQosContext); + + if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) { + hdd_err("Invalid QoS Context"); + return; + } + + adapter = pQosContext->adapter; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + mac_handle = hdd_ctx->mac_handle; + + acType = pQosContext->acType; + pAc = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + + hdd_debug("adapter %pK acType %d", adapter, acType); + + if (!pAc->wmmAcAccessNeeded) { + hdd_err("AC %d doesn't need service", acType); + pQosContext->magic = 0; + qdf_mem_free(pQosContext); + return; + } + + pAc->wmmAcAccessPending = true; + pAc->wmmAcAccessNeeded = false; + + memset(&qosInfo, 0, sizeof(qosInfo)); + + qosInfo.ts_info.psb = adapter->configured_psb; + + switch (acType) { + case SME_AC_VO: + qosInfo.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) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(adapter))->config-> + UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcVo; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(adapter))->config-> + InfraMeanDataRateAcVo; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcVo; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdVoSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcVo; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcVo; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdVoSuspIntv; + break; + case SME_AC_VI: + qosInfo.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) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(adapter))->config-> + UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcVi; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(adapter))->config-> + InfraMeanDataRateAcVi; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcVi; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdViSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcVi; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcVi; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdViSuspIntv; + break; + default: + case SME_AC_BE: + qosInfo.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) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(adapter))->config-> + UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcBe; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(adapter))->config-> + InfraMeanDataRateAcBe; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcBe; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBeSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcBe; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcBe; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBeSuspIntv; + break; + case SME_AC_BK: + qosInfo.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) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(adapter))->config-> + UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(adapter))->config->InfraDirAcBk; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(adapter))->config-> + InfraMeanDataRateAcBk; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(adapter))->config->InfraMinPhyRateAcBk; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBkSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(adapter))->config->InfraNomMsduSizeAcBk; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(adapter))->config->InfraSbaAcBk; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraUapsdBkSuspIntv; + break; + } +#ifdef FEATURE_WLAN_ESE + qosInfo.inactivity_interval = + (WLAN_HDD_GET_CTX(adapter))->config->InfraInactivityInterval; +#endif + qosInfo.ts_info.burst_size_defn = + (WLAN_HDD_GET_CTX(adapter))->config->burstSizeDefinition; + + switch ((WLAN_HDD_GET_CTX(adapter))->config->tsInfoAckPolicy) { + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK: + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + + default: + /* unknown */ + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + + if (qosInfo.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, &qosInfo, + adapter->session_id)) { + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + } + + mutex_lock(&adapter->hdd_wmm_status.wmmLock); + list_add(&pQosContext->node, &adapter->hdd_wmm_status.wmmContextList); + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = sme_qos_setup_req(mac_handle, + adapter->session_id, + &qosInfo, + hdd_wmm_sme_callback, + pQosContext, + qosInfo.ts_info.up, + &pQosContext->qosFlowId); + + hdd_debug("sme_qos_setup_req returned %d flowid %d", + smeStatus, pQosContext->qosFlowId); + + /* need to check the return values and act appropriately */ + switch (smeStatus) { + 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(pQosContext); + + /* 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(pQosContext); + + /* fall through and start packets flowing */ + 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"); + + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + + break; + + default: + hdd_err("unexpected SME Status=%d", smeStatus); + QDF_ASSERT(0); + } +#endif + +} + +/** + * hdd_wmm_do_implicit_qos() - SSR wraper 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) +{ + cds_ssr_protect(__func__); + __hdd_wmm_do_implicit_qos(work); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_wmm_init() - initialize the WMM DSCP configuation + * @adapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuation 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_init(struct hdd_adapter *adapter) +{ + enum sme_qos_wmmuptype *dscp_to_up_map = adapter->dscp_to_up_map; + uint8_t dscp; + + hdd_enter(); + + /* DSCP to User Priority Lookup Table + * By default use the 3 Precedence bits of DSCP as the User Priority + */ + for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++) + dscp_to_up_map[dscp] = dscp >> 3; + + /* Special case for Expedited Forwarding (DSCP 46) */ + dscp_to_up_map[46] = SME_QOS_WMM_UP_VO; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter + * @adapter: [in] pointer to Adapter context + * + * This function will initialize the WMM configuation 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 *pAcStatus; + sme_ac_enum_type acType; + + hdd_enter(); + + adapter->hdd_wmm_status.wmmQap = false; + INIT_LIST_HEAD(&adapter->hdd_wmm_status.wmmContextList); + mutex_init(&adapter->hdd_wmm_status.wmmLock); + + for (acType = 0; acType < WLAN_MAX_AC; acType++) { + pAcStatus = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + pAcStatus->wmmAcAccessRequired = false; + pAcStatus->wmmAcAccessNeeded = false; + pAcStatus->wmmAcAccessPending = false; + pAcStatus->wmmAcAccessFailed = false; + pAcStatus->wmmAcAccessGranted = false; + pAcStatus->wmmAcAccessAllowed = false; + pAcStatus->wmmAcTspecValid = false; + pAcStatus->wmmAcUapsdInfoValid = 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 *pAcStatus; + sme_ac_enum_type acType; + + hdd_enter(); + for (acType = 0; acType < WLAN_MAX_AC; acType++) { + pAcStatus = &adapter->hdd_wmm_status.wmmAcStatus[acType]; + pAcStatus->wmmAcAccessRequired = false; + pAcStatus->wmmAcAccessNeeded = false; + pAcStatus->wmmAcAccessPending = false; + pAcStatus->wmmAcAccessFailed = false; + pAcStatus->wmmAcAccessGranted = false; + pAcStatus->wmmAcAccessAllowed = false; + pAcStatus->wmmAcTspecValid = false; + pAcStatus->wmmAcUapsdInfoValid = false; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_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 *pQosContext; + + hdd_enter(); + + /* free any context records that we still have linked */ + while (!list_empty(&adapter->hdd_wmm_status.wmmContextList)) { + pQosContext = + list_first_entry(&adapter->hdd_wmm_status.wmmContextList, + struct hdd_wmm_qos_context, node); + + hdd_wmm_disable_inactivity_timer(pQosContext); + + if (pQosContext->handle == HDD_WMM_HANDLE_IMPLICIT + && pQosContext->magic == HDD_WMM_CTX_MAGIC) + cds_flush_work(&pQosContext->wmmAcSetupImplicitQos); + + hdd_wmm_free_context(pQosContext); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_classify_pkt() - Function which will classify an OS packet + * into a 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_eapol: eapol packet flag + * + * Return: None + */ +static +void hdd_wmm_classify_pkt(struct hdd_adapter *adapter, + struct sk_buff *skb, + enum sme_qos_wmmuptype *user_pri, + bool *is_eapol) +{ + unsigned char dscp; + unsigned char tos; + union generic_ethhdr *eth_hdr; + struct iphdr *ip_hdr; + struct ipv6hdr *ipv6hdr; + unsigned char *pkt; + + /* 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; + *is_eapol = true; + } else + tos = 0; + } + + dscp = (tos >> 2) & 0x3f; + *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_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_LL_PDEV_TX_FLOW_CONTROL) +/** + * hdd_get_queue_index() - get queue index + * @up: user priority + * @is_eapol: is_eapol flag + * + * Return: queue_index + */ +static +uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol) +{ + if (qdf_unlikely(is_eapol == true)) + 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_eapol) +{ + return __hdd_get_queue_index(up); +} +#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 + */ +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 queueIndex; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + bool is_crtical = false; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int status; + enum qdf_proto_subtype proto_subtype; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) { + skb->priority = SME_QOS_WMM_UP_BE; + return HDD_LINUX_AC_BE; + } + + /* Get the user priority from IP header */ + hdd_wmm_classify_pkt(adapter, skb, &up, &is_crtical); + spin_lock_bh(&adapter->pause_map_lock); + if ((adapter->pause_map & (1 << WLAN_DATA_FLOW_CONTROL)) && + !(adapter->pause_map & (1 << WLAN_DATA_FLOW_CONTROL_PRIORITY))) { + if (qdf_nbuf_is_ipv4_arp_pkt(skb)) + is_crtical = true; + 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_crtical = true; + break; + default: + break; + } + } + } + spin_unlock_bh(&adapter->pause_map_lock); + skb->priority = up; + queueIndex = hdd_get_queue_index(skb->priority, is_crtical); + + return queueIndex; +} + +#if (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 + * @acType: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter, + sme_ac_enum_type acType) +{ + /* Each bit in the LSB nibble indicates 1 AC. + * Clearing the particular bit in LSB nibble to indicate + * access required + */ + switch (acType) { + 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 + * @acType: [in] WMM AC type of OS packet + * @pGranted: [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 acType, bool *pGranted) +{ + struct hdd_wmm_qos_context *pQosContext; + + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Entered for AC %d", __func__, acType); + + if (!hdd_wmm_is_active(adapter) || + !(WLAN_HDD_GET_CTX(adapter))->config->bImplicitQosEnabled || + !adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessRequired) { + /* 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__); + + *pGranted = + adapter->hdd_wmm_status.wmmAcStatus[acType]. + wmmAcAccessAllowed; + + return QDF_STATUS_SUCCESS; + } + /* do we already have an implicit QoS request pending for this AC? */ + if ((adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessNeeded) || + (adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessPending)) { + /* 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__, acType); + + *pGranted = 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.wmmAcStatus[acType].wmmAcAccessFailed) { + /* 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__, acType); + + if (!adapter->hdd_wmm_status.wmmAcStatus[acType]. + wmmAcAccessRequired) { + adapter->hdd_wmm_status.wmmAcStatus[acType]. + wmmAcAccessAllowed = true; + *pGranted = true; + } else { + adapter->hdd_wmm_status.wmmAcStatus[acType]. + wmmAcAccessAllowed = false; + *pGranted = 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__, acType, adapter); + + adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessNeeded = true; + + pQosContext = qdf_mem_malloc(sizeof(*pQosContext)); + if (NULL == pQosContext) { + /* no memory for QoS context. Nothing we can do but + * let data flow + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to allocate context", __func__); + adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessAllowed = + true; + *pGranted = true; + return QDF_STATUS_SUCCESS; + } + + pQosContext->acType = acType; + pQosContext->adapter = adapter; + pQosContext->qosFlowId = 0; + pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT; + pQosContext->magic = HDD_WMM_CTX_MAGIC; + pQosContext->is_inactivity_timer_running = false; + + INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, 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__, acType, pQosContext); + + schedule_work(&pQosContext->wmmAcSetupImplicitQos); + + /* caller will need to wait until the work takes place and + * TSPEC negotiation completes + */ + *pGranted = false; + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_assoc() - Function which will handle the housekeeping + * required by WMM when association takes place + * + * @adapter: [in] pointer to adapter context + * @roam_info: [in] pointer to roam information + * @eBssType: [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + eCsrRoamBssType eBssType) +{ + uint8_t uapsdMask; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* when we associate we need to notify TL if it needs to + * enable UAPSD for any access categories + */ + + hdd_enter(); + + if (roam_info->fReassocReq) { + /* 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; + } + /* get the negotiated UAPSD Mask */ + uapsdMask = + roam_info->u.pConnectedProfile->modifyProfileFields.uapsd_mask; + + hdd_debug("U-APSD mask is 0x%02x", (int)uapsdMask); + + if (uapsdMask & HDD_AC_VO) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info.staId[0], + SME_AC_VO, 7, 7, + hdd_ctx->config->InfraUapsdVoSrvIntv, + hdd_ctx->config->InfraUapsdVoSuspIntv, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->session_id, + hdd_ctx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_VI) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info.staId[0], + SME_AC_VI, 5, 5, + hdd_ctx->config->InfraUapsdViSrvIntv, + hdd_ctx->config->InfraUapsdViSuspIntv, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->session_id, + hdd_ctx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_BK) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info.staId[0], + SME_AC_BK, 2, 2, + hdd_ctx->config->InfraUapsdBkSrvIntv, + hdd_ctx->config->InfraUapsdBkSuspIntv, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->session_id, + hdd_ctx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_BE) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info.staId[0], + SME_AC_BE, 3, 3, + hdd_ctx->config->InfraUapsdBeSrvIntv, + hdd_ctx->config->InfraUapsdBeSuspIntv, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->session_id, + hdd_ctx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + status = sme_update_dsc_pto_up_mapping(hdd_ctx->mac_handle, + adapter->dscp_to_up_map, + adapter->session_id); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_wmm_init(adapter); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +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 */ +}; + +/** + * 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 + * @eBssType : [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + eCsrRoamBssType eBssType) +{ + int ac; + bool qap; + bool qosConnection; + uint8_t acmMask; + mac_handle_t mac_handle; + + hdd_enter(); + + if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) && + roam_info && roam_info->u.pConnectedProfile) { + qap = roam_info->u.pConnectedProfile->qap; + qosConnection = roam_info->u.pConnectedProfile->qosConnection; + acmMask = roam_info->u.pConnectedProfile->acm_mask; + } else { + qap = true; + qosConnection = true; + acmMask = 0x0; + } + + hdd_debug("qap is %d, qosConnection is %d, acmMask is 0x%x", + qap, qosConnection, acmMask); + + adapter->hdd_wmm_status.wmmQap = qap; + adapter->hdd_wmm_status.wmmQosConnection = qosConnection; + mac_handle = hdd_adapter_get_mac_handle(adapter); + + for (ac = 0; ac < WLAN_MAX_AC; ac++) { + if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) { + hdd_debug("ac %d on", ac); + + /* admission is required */ + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessRequired = true; + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessAllowed = false; + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessGranted = false; + /* after reassoc if we have valid tspec, allow access */ + if (adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcTspecValid + && (adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcTspecInfo.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessAllowed = true; + } + if (!roam_info->fReassocReq && + !sme_neighbor_roam_is11r_assoc( + mac_handle, + adapter->session_id) && + !sme_roam_is_ese_assoc(roam_info)) { + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcTspecValid = false; + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessAllowed = false; + } + } else { + hdd_debug("ac %d off", ac); + /* admission is not required so access is allowed */ + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessRequired = false; + adapter->hdd_wmm_status.wmmAcStatus[ac]. + wmmAcAccessAllowed = true; + } + + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_get_uapsd_mask() - Function which will calculate the + * initial value of the UAPSD mask based upon the device configuration + * + * @adapter : [in] pointer to adapter context + * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_get_uapsd_mask(struct hdd_adapter *adapter, + uint8_t *pUapsdMask) +{ + uint8_t uapsdMask; + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(adapter))->config->WmmMode) { + /* no QOS then no UAPSD */ + uapsdMask = 0; + } else { + /* start with the default mask */ + uapsdMask = (WLAN_HDD_GET_CTX(adapter))->config->UapsdMask; + + /* disable UAPSD for any ACs with a 0 Service Interval */ + if ((WLAN_HDD_GET_CTX(adapter))->config-> + InfraUapsdVoSrvIntv == 0) { + uapsdMask &= ~HDD_AC_VO; + } + + if ((WLAN_HDD_GET_CTX(adapter))->config-> + InfraUapsdViSrvIntv == 0) { + uapsdMask &= ~HDD_AC_VI; + } + + if ((WLAN_HDD_GET_CTX(adapter))->config-> + InfraUapsdBkSrvIntv == 0) { + uapsdMask &= ~HDD_AC_BK; + } + + if ((WLAN_HDD_GET_CTX(adapter))->config-> + InfraUapsdBeSrvIntv == 0) { + uapsdMask &= ~HDD_AC_BE; + } + } + + /* return calculated mask */ + *pUapsdMask = uapsdMask; + 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.wmmQosConnection) || + (!adapter->hdd_wmm_status.wmmQap)) { + 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; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Unable to fetch the hdd context"); + return false; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (hdd_validate_adapter(adapter)) { + hdd_err("Invalid adapter"); + return false; + } + + wmm_ac_status = adapter->hdd_wmm_status.wmmAcStatus; + + if (hdd_wmm_is_active(adapter) && + !(wmm_ac_status[OL_TX_WMM_AC_VI].wmmAcAccessAllowed)) + return false; + return true; +} + +/** + * 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 + * @pTspec : [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 *pTspec) +{ + struct hdd_wmm_qos_context *pQosContext; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + enum sme_qos_statustype smeStatus; +#endif + bool found = false; + 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.wmmLock); + list_for_each_entry(pQosContext, + &adapter->hdd_wmm_status.wmmContextList, node) { + if (pQosContext->handle == handle) { + found = true; + break; + } + } + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + if (found) { + /* 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 + */ + smeStatus = sme_qos_modify_req(mac_handle, + pTspec, pQosContext->qosFlowId); + + /* need to check the return value and act appropriately */ + switch (smeStatus) { + 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", + smeStatus); + QDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + } + + /* we were successful, save the status */ + mutex_lock(&adapter->hdd_wmm_status.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + + return status; + } + + pQosContext = qdf_mem_malloc(sizeof(*pQosContext)); + if (NULL == pQosContext) { + /* no memory for QoS context. Nothing we can do */ + hdd_err("Unable to allocate QoS context"); + return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE; + } + /* we assume the tspec has already been validated by the caller */ + + pQosContext->handle = handle; + if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE) + pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up]; + else { + hdd_err("ts_info.up (%d) larger than max value (%d), use default acType (%d)", + pTspec->ts_info.up, + HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]); + pQosContext->acType = hdd_wmm_up_to_ac_map[0]; + } + pQosContext->adapter = adapter; + pQosContext->qosFlowId = 0; + pQosContext->magic = HDD_WMM_CTX_MAGIC; + pQosContext->is_inactivity_timer_running = false; + + hdd_debug("Setting up QoS, context %pK", pQosContext); + + mutex_lock(&adapter->hdd_wmm_status.wmmLock); + list_add(&pQosContext->node, &adapter->hdd_wmm_status.wmmContextList); + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = sme_qos_setup_req(mac_handle, + adapter->session_id, + pTspec, + hdd_wmm_sme_callback, + pQosContext, + pTspec->ts_info.up, + &pQosContext->qosFlowId); + + hdd_debug("sme_qos_setup_req returned %d flowid %d", + smeStatus, pQosContext->qosFlowId); + + /* need to check the return value and act appropriately */ + switch (smeStatus) { + 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(pQosContext); + hdd_wmm_free_context(pQosContext); + 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(pQosContext); + /* we can't tell the difference between when a request + * fails because AP rejected it versus when SME + * encounterd an internal error + */ + hdd_wmm_free_context(pQosContext); + 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(pQosContext); + hdd_wmm_free_context(pQosContext); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + default: + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(pQosContext); + /* we didn't get back one of the + * SME_QOS_STATUS_SETUP_* status codes + */ + hdd_wmm_free_context(pQosContext); + hdd_err("unexpected SME Status=%d", smeStatus); + QDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED; + } +#endif + + /* we were successful, save the status */ + mutex_lock(&adapter->hdd_wmm_status.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + + 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 *pQosContext; + bool found = false; + sme_ac_enum_type acType = 0; + uint32_t qosFlowId = 0; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + enum sme_qos_statustype smeStatus; + 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.wmmLock); + list_for_each_entry(pQosContext, + &adapter->hdd_wmm_status.wmmContextList, node) { + if (pQosContext->handle == handle) { + found = true; + acType = pQosContext->acType; + qosFlowId = pQosContext->qosFlowId; + break; + } + } + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + + if (false == found) { + /* we didn't find the handle */ + hdd_info("handle 0x%x not found", handle); + return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + } + + hdd_debug("found handle 0x%x, flow %d, AC %d, context %pK", + handle, qosFlowId, acType, pQosContext); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = sme_qos_release_req(mac_handle, adapter->session_id, + qosFlowId); + + hdd_debug("SME flow %d released, SME status %d", qosFlowId, smeStatus); + + switch (smeStatus) { + 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.wmmAcStatus[acType].wmmAcTspecValid = + false; + adapter->hdd_wmm_status.wmmAcStatus[acType].wmmAcAccessAllowed = + false; + + /* need to tell TL to stop trigger timer, etc */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(pQosContext); + + /* we are done with this context */ + hdd_wmm_free_context(pQosContext); + + /* 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", smeStatus); + QDF_ASSERT(0); + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + } + +#endif + mutex_lock(&adapter->hdd_wmm_status.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + + 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 *pQosContext; + 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.wmmLock); + list_for_each_entry(pQosContext, + &adapter->hdd_wmm_status.wmmContextList, node) { + if (pQosContext->handle == handle) { + hdd_debug("found handle 0x%x, context %pK", + handle, pQosContext); + + status = pQosContext->lastStatus; + break; + } + } + mutex_unlock(&adapter->hdd_wmm_status.wmmLock); + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c new file mode 100644 index 0000000000000000000000000000000000000000..b7f43fe6ee9beb55ffb2f2fbb2f3d115dcbb3357 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c @@ -0,0 +1,463 @@ +/* + * 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. + */ + +/** + * @file wlan_hdd_wowl.c + * + * @brief wake up on WLAN API file + */ + +/* Include Files */ + +#include "qdf_str.h" +#include +#include +#include + +/* 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) +{ + int i; + + hdd_info("Pattern Id = 0x%x", ptrn->pattern_id); + hdd_info("Pattern Byte Offset = 0x%x", ptrn->pattern_byte_offset); + hdd_info("Pattern_size = 0x%x", ptrn->pattern_size); + hdd_info("Pattern_mask_size = 0x%x", ptrn->pattern_mask_size); + hdd_info("Pattern: "); + for (i = 0; i < ptrn->pattern_size; i++) + hdd_info(" %02X", ptrn->pattern[i]); + hdd_info("pattern_mask: "); + for (i = 0; i < ptrn->pattern_mask_size; i++) + hdd_info("%02X", ptrn->pattern_mask[i]); +} + +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; + + *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 localPattern; + int i, empty_slot, len, offset; + QDF_STATUS status; + const char *temp; + uint8_t sessionId = adapter->session_id; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t num_filters; + + 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] == NULL) { + empty_slot = i; + continue; + } + + 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!"); + ptrn += len; + goto next_ptrn; + } + + /* Extract the pattern size */ + localPattern.pattern_size = + (hex_to_bin(ptrn[0]) * 0x10) + hex_to_bin(ptrn[1]); + + /* Extract the pattern mask size */ + localPattern.pattern_mask_size = + (hex_to_bin(ptrn[3]) * 0x10) + hex_to_bin(ptrn[4]); + + if (localPattern.pattern_size > PMO_WOWL_BCAST_PATTERN_MAX_SIZE + || localPattern.pattern_mask_size > + WOWL_PTRN_MASK_MAX_SIZE) { + hdd_err("Invalid length specified. Skip!"); + ptrn += len; + goto next_ptrn; + } + + /* compute the offset of tokenizer after the pattern */ + offset = 5 + 2 * localPattern.pattern_size + 1; + if ((offset >= len) || + (ptrn[offset] != WOWL_INTRA_PTRN_TOKENIZER)) { + hdd_err("Malformed pattern string..skip!"); + ptrn += len; + goto next_ptrn; + } + + /* compute the end of pattern sring */ + offset = offset + 2 * localPattern.pattern_mask_size; + if (offset + 1 != len) { + /* offset begins with 0 */ + hdd_err("Malformed pattern string...skip!"); + ptrn += len; + goto next_ptrn; + } + + temp = ptrn; + + /* Now advance to where pattern begins */ + ptrn += 6; + + /* Extract the pattern */ + for (i = 0; i < localPattern.pattern_size; i++) { + localPattern.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 < localPattern.pattern_mask_size; i++) { + localPattern.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] == NULL) { + hdd_err("memory allocation failure"); + return false; + } + + memcpy(g_hdd_wowl_ptrns[empty_slot], temp, len); + g_hdd_wowl_ptrns[empty_slot][len] = '\0'; + localPattern.pattern_id = empty_slot; + localPattern.pattern_byte_offset = 0; + localPattern.session_id = sessionId; + + /* Register the pattern downstream */ + status = pmo_ucfg_add_wow_user_pattern( + adapter->vdev, &localPattern); + 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; + } + + dump_hdd_wowl_ptrn(&localPattern); + +next_ptrn: + if (*ptrn == WOWL_INTER_PTRN_TOKENIZER) { + /* move past the tokenizer */ + ptrn += 1; + len = find_ptrn_len(ptrn); + continue; + } else { + break; + } + } + + 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; + + 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; + + status = pmo_ucfg_del_wow_user_pattern(adapter->vdev, 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 localPattern; + QDF_STATUS qdf_ret_status; + uint8_t session_id = adapter->session_id; + uint16_t pattern_len, mask_len, i; + + 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; + } + + localPattern.pattern_id = pattern_idx; + localPattern.pattern_byte_offset = pattern_offset; + localPattern.pattern_size = pattern_len; + localPattern.session_id = session_id; + + if (localPattern.pattern_size > PMO_WOWL_BCAST_PATTERN_MAX_SIZE) { + hdd_err("WoW pattern size (%d) greater than max (%d)", + localPattern.pattern_size, + PMO_WOWL_BCAST_PATTERN_MAX_SIZE); + return false; + } + /* Extract the pattern */ + for (i = 0; i < localPattern.pattern_size; i++) { + localPattern.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 */ + localPattern.pattern_mask_size = pattern_len >> 3; + if (pattern_len % 8) + localPattern.pattern_mask_size += 1; + + mask_len = strlen(pattern_mask); + if ((mask_len % 2) + || (localPattern.pattern_mask_size != (mask_len >> 1))) { + hdd_err("Malformed WoW pattern mask!"); + + return false; + } + if (localPattern.pattern_mask_size > WOWL_PTRN_MASK_MAX_SIZE) { + hdd_err("WoW pattern mask size (%d) greater than max (%d)", + localPattern.pattern_mask_size, + WOWL_PTRN_MASK_MAX_SIZE); + return false; + } + /* Extract the pattern mask */ + for (i = 0; i < localPattern.pattern_mask_size; i++) { + localPattern.pattern_mask[i] = + (hex_to_bin(pattern_mask[0]) << 4) + + hex_to_bin(pattern_mask[1]); + + /* Skip to next byte */ + pattern_mask += 2; + } + + /* Register the pattern downstream */ + qdf_ret_status = pmo_ucfg_add_wow_user_pattern( + adapter->vdev, &localPattern); + 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(&localPattern); + + 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) +{ + 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; + } + + qdf_ret_status = pmo_ucfg_del_wow_user_pattern( + adapter->vdev, pattern_idx); + 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/drivers/staging/qcacld-3.0/core/mac/inc/ani_global.h b/drivers/staging/qcacld-3.0/core/mac/inc/ani_global.h new file mode 100644 index 0000000000000000000000000000000000000000..9be2abd97c56c3338233e331e56d149c2a148e46 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/ani_global.h @@ -0,0 +1,903 @@ +/* + * 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 _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 "cfg_global.h" +#include "sir_api.h" + +#include "csr_api.h" +#include "sme_ft_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" + +/** + * 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 tpAniSirGlobal MAC_CONTEXT(mac_handle_t handle) +{ + return (tpAniSirGlobal)handle; +} + +/* legacy definition */ +#define PMAC_STRUCT(handle) 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 PMAC_STRUCT() + * + * Return: opaque handle for @mac + */ +static inline mac_handle_t MAC_HANDLE(tpAniSirGlobal mac) +{ + return (mac_handle_t)mac; +} + +#define ANI_DRIVER_TYPE(pMac) (((tpAniSirGlobal)(pMac))->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))) + +/* 40 beacons per heart beat interval is the default + 1 to count the rest */ +#define MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL 41 + +/* max number of legacy bssid we can store during scan on one channel */ +#define MAX_NUM_LEGACY_BSSID_PER_CHANNEL 10 + +#ifdef WLAN_FEATURE_CONCURRENT_P2P +#define MAX_NO_OF_P2P_SESSIONS 5 +#endif /* WLAN_FEATURE_CONCURRENT_P2P */ + +#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 + +/* vendor element ID */ +#define IE_EID_VENDOR (221) /* 0xDD */ +#define IE_LEN_SIZE (1) +#define IE_EID_SIZE (1) +/* Minimum size of vendor IE = 3 bytes of oui_data + 1 byte of data */ +#define IE_VENDOR_OUI_SIZE (4) + +/** + * 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 + */ +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 +}; + + +/** + * 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)(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, + tpPESession psessionEntry); + +/* / LIM global definitions */ +typedef struct sAniSirLimIbss { + void *pHdr; + void *pBeacon; +} tAniSirLimIbss; + +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; + + /* / Wait for Probe after Heartbeat failure timer on STA */ + TX_TIMER gLimProbeAfterHBTimer; + + /* 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 gLimChannelSwitchTimer; + /* This TIMER is started on the STA, as indicated by the */ + /* AP in its Quiet BSS IE, for the specified interval */ + TX_TIMER gLimQuietTimer; + /* This TIMER is started on the AP, prior to the AP going */ + /* into LEARN mode */ + /* This TIMER is started on the STA, for the specified */ + /* quiet duration */ + TX_TIMER gLimQuietBssTimer; + + TX_TIMER gLimFTPreAuthRspTimer; + +#ifdef FEATURE_WLAN_ESE + TX_TIMER gLimEseTsmTimer; +#endif + 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; + +/* ********************TIMER SECTION ENDS************************************************** */ +/* ALL THE FIELDS BELOW THIS CAN BE ZEROED OUT in lim_initialize */ +/* **************************************************************************************** */ + +} tLimTimers; + +typedef struct { + void *pMlmDisassocReq; + void *pMlmDeauthReq; +} tLimDisassocDeauthCnfReq; + +typedef struct sAniSirLim { + /* //////////////////////////////////// TIMER RELATED START /////////////////////////////////////////// */ + + tLimTimers limTimers; + /* / Flag to track if LIM timers are created or not */ + uint32_t gLimTimersCreated; + + /* //////////////////////////////////// TIMER RELATED END /////////////////////////////////////////// */ + + struct lim_scan_channel_status scan_channel_status; + + uint8_t gLimCurrentBssUapsd; + + /* */ + /* Store the BSS Index returned by HAL during */ + /* WMA_ADD_BSS_RSP here. */ + /* */ + + /* For now: */ + /* This will be used during WMA_SET_BSSKEY_REQ in */ + /* order to set the GTK */ + /* Later: */ + /* There could be other interfaces needing this info */ + /* */ + + /* */ + /* Due to the asynchronous nature of the interface */ + /* between PE <-> HAL, some transient information */ + /* like this needs to be cached. */ + /* This is cached upon receipt of eWNI_SME_SETCONTEXT_REQ. */ + /* This is released while posting LIM_MLM_SETKEYS_CNF */ + /* */ + void *gpLimMlmSetKeysReq; + + /* //////////////////////////////////////// BSS RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// IBSS RELATED START /////////////////////////////////////////// */ + /* This indicates whether this STA coalesced and adapter to peer's capabilities or not. */ + uint8_t gLimIbssCoalescingHappened; + + /* / Definition for storing IBSS peers BSS description */ + tLimIbssPeerNode *gLimIbssPeerList; + uint32_t gLimNumIbssPeers; + uint32_t ibss_retry_cnt; + + /* ibss info - params for which ibss to join while coalescing */ + tAniSirLimIbss ibssInfo; + + /* //////////////////////////////////////// IBSS RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// STATS/COUNTER RELATED START /////////////////////////////////////////// */ + + uint16_t maxStation; + uint16_t maxBssId; + + uint32_t gLimNumBeaconsRcvd; + uint32_t gLimNumBeaconsIgnored; + + uint32_t gLimNumDeferredMsgs; + + /* / Variable to keep track of number of currently associated STAs */ + uint16_t gLimNumOfAniSTAs; /* count of ANI peers */ + uint16_t gLimAssocStaLimit; + + /* Heart-Beat interval value */ + uint32_t gLimHeartBeatCount; + tSirMacAddr gLimHeartBeatApMac[2]; + uint8_t gLimHeartBeatApMacIndex; + + /* Statistics to keep track of no. beacons rcvd in heart beat interval */ + uint16_t + gLimHeartBeatBeaconStats[MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL]; + +#ifdef WLAN_DEBUG + /* Debug counters */ + uint32_t numTot, numBbt, numProtErr, numLearn, numLearnIgnore; + uint32_t numSme, numMAC[4][16]; + + /* Debug counter to track number of Assoc Req frame drops */ + /* when received in pStaDs->mlmState other than LINK_ESTABLISED */ + uint32_t gLimNumAssocReqDropInvldState; + /* counters to track rejection of Assoc Req due to Admission Control */ + uint32_t gLimNumAssocReqDropACRejectTS; + uint32_t gLimNumAssocReqDropACRejectSta; + /* Debug counter to track number of Reassoc Req frame drops */ + /* when received in pStaDs->mlmState other than LINK_ESTABLISED */ + uint32_t gLimNumReassocReqDropInvldState; + /* Debug counter to track number of Hash Miss event that */ + /* will not cause a sending of de-auth/de-associate frame */ + uint32_t gLimNumHashMissIgnored; + + /* Debug counter to track number of Beacon frames */ + /* received in unexpected state */ + uint32_t gLimUnexpBcnCnt; + + /* Debug counter to track number of Beacon frames */ + /* received in wt-join-state that do have SSID mismatch */ + uint32_t gLimBcnSSIDMismatchCnt; + + /* Debug counter to track number of Link establishments on STA/BP */ + uint32_t gLimNumLinkEsts; + + /* Debug counter to track number of Rx cleanup */ + uint32_t gLimNumRxCleanup; + + /* Debug counter to track different parse problem */ + uint32_t gLim11bStaAssocRejectCount; + +#endif + + /* //////////////////////////////////////// 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 ----------------------- */ + /* these used to live in DPH but are now moved here (where they belong) */ + uint32_t gLimPhyMode; + + uint8_t gLimQosEnabled:1; /* 11E */ + uint8_t gLimWmeEnabled:1; /* WME */ + uint8_t gLimWsmEnabled:1; /* WSM */ + uint8_t gLimHcfEnabled:1; + uint8_t gLim11dEnabled:1; + uint8_t gLimProbeRespDisableFlag:1; /* control over probe response */ + /* ---------------- 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 partiular 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; + qdf_mutex_t lkPeGlobalLock; + uint8_t disableLDPCWithTxbfAP; +#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 JoinReq message */ + /* received by SME state machine */ + /* tpSirSmeJoinReq gpLimJoinReq; */ + + /* Place holder for ReassocReq message */ + /* received by SME state machine */ + /* tpSirSmeReassocReq gpLimReassocReq; sep23 review */ + + /* Current Authentication type used at STA */ + /* tAniAuthType gLimCurrentAuthType; */ + + /* 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; + + /* Placed holder to deauth reason */ + uint16_t gLimDeauthReasonCode; + + /* 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]; + + /* //////////////////////////////////////// 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; + + /* RIFS Mode. Set if no APSD legacy devices associated */ + uint8_t gHTRifsMode; + /* 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 ////////////////////////////////////////// */ + +#ifdef FEATURE_WLAN_TDLS + uint8_t gLimTdlsLinkMode; + /* ////////////////////////////// TDLS RELATED ////////////////////////////////////////// */ +#endif + + /* wsc info required to form the wsc IE */ + tLimWscIeInfo wscIeInfo; + tpPESession gpSession; /* Pointer to session table */ + /* + * sessionID and transactionID from SME is stored here for those messages, for which + * there is no session context in PE, e.g. Scan related messages. + **/ + uint8_t gSmeSessionId; + + tSirRemainOnChnReq *gpLimRemainOnChanReq; /* hold remain on chan request in this buf */ + qdf_mutex_t lim_frame_register_lock; + qdf_list_t gLimMgmtFrameRegistratinQueue; + uint32_t mgmtFrameSessionId; + uint32_t tdls_frm_session_id; + + tpPESession pSessionEntry; + uint8_t reAssocRetryAttempt; + tLimDisassocDeauthCnfReq limDisassocDeauthCnfReq; + uint8_t deferredMsgCnt; + uint8_t deauthMsgCnt; + uint8_t disassocMsgCnt; + uint8_t gLimIbssStaLimit; + + /* Number of channel switch IEs sent so far */ + uint8_t gLimDfsChanSwTxCount; + uint8_t gLimDfsTargetChanNum; + QDF_STATUS(*sme_msg_callback) + (tpAniSirGlobal mac, struct scheduler_msg *msg); + QDF_STATUS(*stop_roaming_callback) + (tpAniSirGlobal mac, uint8_t session_id, uint8_t reason); + uint8_t retry_packet_cnt; + uint8_t beacon_probe_rsp_cnt_per_scan; + wlan_scan_requester req_id; + bool global_obss_offload_enabled; + bool global_obss_color_collision_det_offload; +} tAniSirLim, *tpAniSirLim; + +struct mgmt_frm_reg_info { + qdf_list_node_t node; /* MUST be first element */ + uint16_t frameType; + uint16_t matchLen; + uint16_t sessionId; + uint8_t matchData[1]; +}; + +typedef struct sRrmContext { + tRrmSMEContext rrmSmeContext; + tRrmPEContext rrmPEContext; +} tRrmContext, *tpRrmContext; + +/** + * enum auth_tx_ack_status - Indicate TX status of AUTH + * @LIM_AUTH_ACK_NOT_RCD : Default status while waiting for ack status. + * @LIM_AUTH_ACK_RCD_SUCCESS : Ack is received. + * @LIM_AUTH_ACK_RCD_FAILURE : No Ack received. + * + * 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 auth_tx_ack_status { + LIM_AUTH_ACK_NOT_RCD, + LIM_AUTH_ACK_RCD_SUCCESS, + LIM_AUTH_ACK_RCD_FAILURE, +}; +/** + * 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. + * + * 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; +}; + +/** + * struct mgmt_beacon_probe_filter + * @bcn_filter_lock: Spinlock for the filter structure + * @num_sta_sessions: Number of active PE STA sessions + * @sta_bssid: Array of PE STA session's peer BSSIDs + * @num_ibss_sessions: Number of active PE IBSS sessions + * @ibss_ssid: Array of PE IBSS session's SSID + * @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[SIR_MAX_SUPPORTED_BSS]; + uint8_t num_ibss_sessions; + tSirMacSSid ibss_ssid[SIR_MAX_SUPPORTED_BSS]; + uint8_t num_sap_sessions; + uint8_t sap_channel[SIR_MAX_SUPPORTED_BSS]; +}; + +/* ------------------------------------------------------------------- */ +/* / MAC Sirius parameter structure */ +typedef struct sAniSirGlobal { + enum qdf_driver_type gDriverType; + + tAniSirCfg cfg; + tAniSirLim lim; + tAniSirSch sch; + tAniSirSys sys; + + /* PAL/HDD handle */ + hdd_handle_t hdd_handle; + + tSmeStruct sme; + tSapStruct sap; + struct csr_scanstruct scan; + struct csr_roamstruct roam; + tRrmContext rrm; + csr_readyToSuspendCallback readyToSuspendCallback; + void *readyToSuspendContext; + uint8_t isCoalesingInIBSSAllowed; + uint8_t lteCoexAntShare; + uint8_t beacon_offload; + bool pmf_offload; + bool is_fils_roaming_supported; + bool enable5gEBT; + uint8_t f_prefer_non_dfs_on_radar; + uint32_t fEnableDebugLog; + 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; + /* 802.11p enable */ + bool enable_dot11p; + /* DBS capability based on INI and FW capability */ + uint8_t hw_dbs_capable; + uint32_t sta_sap_scc_on_dfs_chan; + 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); + /* Based on INI parameter */ + uint32_t dual_mac_feature_disable; + + enum country_src reg_hint_src; + uint32_t rx_packet_drop_counter; + enum auth_tx_ack_status auth_ack_status; + uint8_t user_configured_nss; + bool snr_monitor_enabled; + bool ignore_assoc_disallowed; + bool sta_prefer_80MHz_over_160MHz; + int8_t first_scan_bucket_threshold; + uint32_t peer_rssi; + uint32_t peer_txrate; + uint32_t peer_rxrate; + /* 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[MAX_NUM_AC]; + uint32_t he_sgi_ltf_cfg_bit_mask; + struct mgmt_beacon_probe_filter bcn_filter; + + /* Beacon stats capability from FW */ + bool bcn_reception_stats; + /* Beacon stats enabled/disabled from ini */ + bool enable_beacon_reception_stats; +} tAniSirGlobal; + +#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/drivers/staging/qcacld-3.0/core/mac/inc/ani_system_defs.h b/drivers/staging/qcacld-3.0/core/mac/inc/ani_system_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..7efebd2a16c92d4a3ae52083fa2c9696852dfffc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/ani_system_defs.h @@ -0,0 +1,209 @@ +/* + * 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. + */ + +/* + * + * 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" + +#define ANI_OUI 0x000AF5 + +/* / Max WDS info length. */ +#define ANI_WDS_INFO_MAX_LENGTH 64 + +/* This is to force compiler to use the maximum of an int for enum */ +#define SIR_MAX_ENUM_SIZE 0x7FFFFFFF + +/* Max key size including the WAPI and TKIP */ +#define WLAN_MAX_KEY_RSC_LEN 16 +#define WLAN_WAPI_KEY_RSC_LEN 16 + +#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_OWE, + eSIR_AUTO_SWITCH, + eSIR_DONOT_USE_AUTH_TYPE = SIR_MAX_ENUM_SIZE +} tAniAuthType; + +/* / 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 enum eAniWepType { + eSIR_WEP_STATIC, + eSIR_WEP_DYNAMIC, +} tAniWepType; + +/* / Enum to specify whether key is used */ +/* / for TX only, RX only or both */ +typedef enum eAniKeyDirection { + eSIR_TX_ONLY, + eSIR_RX_ONLY, + eSIR_TX_RX, + eSIR_TX_DEFAULT, + eSIR_DONOT_USE_KEY_DIRECTION = SIR_MAX_ENUM_SIZE +} tAniKeyDirection; + +typedef struct sAniSSID { + uint8_t length; + uint8_t ssId[SIR_MAC_MAX_SSID_LENGTH]; +} tAniSSID, *tpAniSSID; + +typedef struct sAniApName { + uint8_t length; + uint8_t name[SIR_MAC_MAX_SSID_LENGTH]; +} tAniApName, *tpAniApName; + +/* / RSN IE information */ +typedef struct sSirRSNie { + uint16_t length; + uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirRSNie, *tpSirRSNie; + +typedef struct sSirWAPIie { + uint16_t length; + uint8_t wapiIEdata[SIR_MAC_MAX_IE_LENGTH + 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; + +#ifdef FEATURE_WLAN_ESE + +/* The CCKM IE needs to be in the */ +/* Join and Reassoc Req. */ +typedef struct sSirCCKMie { + uint16_t length; + uint8_t cckmIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirCCKMie, *tpSirCCKMie; + +#endif + +/* / Definition for Encryption Keys */ +typedef struct sSirKeys { + uint8_t keyId; + uint8_t unicast; /* 0 for multicast */ + tAniKeyDirection keyDirection; + uint8_t keyRsc[WLAN_MAX_KEY_RSC_LEN]; /* Usage is unknown */ + uint8_t paeRole; /* =1 for authenticator, */ + /* =0 for supplicant */ + uint16_t keyLength; + uint8_t key[SIR_MAC_MAX_KEY_LENGTH]; +} tSirKeys, *tpSirKeys; + +/* / Definition for Keying material */ +typedef struct sSirKeyMaterial { + uint16_t length; /* This is the length of all */ + /* data that follows */ + tAniEdType edType; /* Encryption/Decryption type */ + uint8_t numKeys; + tSirKeys key[1]; +} tSirKeyMaterial, *tpSirKeyMaterial; + +#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 { + uint16_t UplinkPktQueueDly; + uint16_t UplinkPktQueueDlyHist[4]; + uint32_t UplinkPktTxDly; + uint16_t UplinkPktLoss; + uint16_t UplinkPktCount; + 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/drivers/staging/qcacld-3.0/core/mac/inc/mac_init_api.h b/drivers/staging/qcacld-3.0/core/mac/inc/mac_init_api.h new file mode 100644 index 0000000000000000000000000000000000000000..4d7ac9dc34e05875812cd549cbbf1d3688b7e9b4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/mac_init_api.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/* + * + * 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); + +QDF_STATUS mac_open(struct wlan_objmgr_psoc *psoc, tHalHandle *pHalHandle, + hdd_handle_t hdd_handle, struct cds_config_info *cds_cfg); +QDF_STATUS mac_close(tHalHandle hHal); + +#endif /* __MAC_INIT_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h b/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..9398a3c1b31f462e9db6741e0537969ab8019ab6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2013-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 mac_trace.h + + * \brief definition for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#ifndef __MAC_TRACE_H +#define __MAC_TRACE_H + +#include "ani_global.h" + +#define MAC_TRACE_GET_MODULE_ID(data) ((data >> 8) & 0xff) +#define MAC_TRACE_GET_MSG_ID(data) (data & 0xffff) + +#ifdef TRACE_RECORD + +#define eLOG_NODROP_MISSED_BEACON_SCENARIO 0 +#define eLOG_PROC_DEAUTH_FRAME_SCENARIO 1 + +void mac_trace(tpAniSirGlobal pMac, uint8_t code, uint16_t session, + uint32_t data); +void mac_trace_new(tpAniSirGlobal pMac, uint8_t module, uint8_t code, + uint16_t session, uint32_t data); +uint8_t *mac_trace_get_cfg_msg_string(uint16_t cfgMsg); +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); +QDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe); +QDF_STATUS pe_release_global_lock(tAniSirLim *psPe); +uint8_t *mac_trace_get_neighbour_roam_state(uint16_t neighbourRoamState); +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/drivers/staging/qcacld-3.0/core/mac/inc/qwlan_version.h b/drivers/staging/qcacld-3.0/core/mac/inc/qwlan_version.h new file mode 100644 index 0000000000000000000000000000000000000000..f46733be3249a10529146c5065a4265241c88227 --- /dev/null +++ b/drivers/staging/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 03 +#define QWLAN_VERSION_EXTRA "E" +#define QWLAN_VERSION_BUILD 13 + +#define QWLAN_VERSIONSTR "5.2.03.13E" + +#endif /* QWLAN_VERSION_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h new file mode 100644 index 0000000000000000000000000000000000000000..88b2d06f3ff02cad75c32349e38fd07ca7df4835 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h @@ -0,0 +1,7184 @@ +/* + * 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. + */ + +/* + * 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 + + +/* Take care to avoid redefinition of this type, if it is */ +/* already defined in "halWmmApi.h" */ +#if !defined(_HALMAC_WMM_API_H) +typedef struct sAniSirGlobal *tpAniSirGlobal; +#endif + +#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" + +#define SIR_MAX_SUPPORTED_BSS 5 + +#define OFFSET_OF(structType, fldName) (&((structType *)0)->fldName) + +/* / Max supported channel list */ +#define SIR_MAX_SUPPORTED_CHANNEL_LIST 96 + +#define SIR_MDIE_ELEMENT_ID 54 +#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 4 + +#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 */ + +#define SIR_PM_SLEEP_MODE 0 +#define SIR_PM_ACTIVE_MODE 1 + +/* hidden SSID options */ +#define SIR_SCAN_NO_HIDDEN_SSID 0 +#define SIR_SCAN_HIDDEN_SSID_PE_DECISION 1 + +#define SIR_IPV4_ADDR_LEN 4 + +typedef uint8_t tSirIpv4Addr[SIR_IPV4_ADDR_LEN]; + +#define SIR_VERSION_STRING_LEN 64 +typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN]; + +/* Periodic Tx pattern offload feature */ +#define PERIODIC_TX_PTRN_MAX_SIZE 1536 +#define MAXNUM_PERIODIC_TX_PTRNS 6 +#define WIFI_SCANNING_MAC_OUI_LENGTH 3 + +/* This should not be greater than MAX_NUMBER_OF_CONC_CONNECTIONS */ +#define MAX_VDEV_SUPPORTED 4 + +#define MAX_POWER_DBG_ARGS_SUPPORTED 8 +#define QOS_MAP_MAX_EX 21 +#define QOS_MAP_LEN_MIN 16 +#define QOS_MAP_LEN_MAX \ + (QOS_MAP_LEN_MIN + 2 * QOS_MAP_MAX_EX) +#define NUM_CHAINS_MAX 2 + +#define MAX_RSSI_AVOID_BSSID_LIST 10 + +/* 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 */ +#define SIR_SAP_MAX_NUM_PEERS 32 + +#define SIR_KRK_KEY_LEN 16 +#define SIR_BTK_KEY_LEN 32 +#define SIR_KCK_KEY_LEN 16 +#define SIR_KEK_KEY_LEN 16 +#define SIR_KEK_KEY_LEN_FILS 64 +#define SIR_REPLAY_CTR_LEN 8 +#define SIR_PMK_LEN 48 +#define SIR_PMKID_LEN 16 +#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 + +/** + * 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. + */ +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, +}; +/** + * Module ID definitions. + */ +enum { + SIR_BOOT_MODULE_ID = 1, + SIR_HAL_MODULE_ID = 0x10, + SIR_CFG_MODULE_ID = 0x12, + SIR_LIM_MODULE_ID, + SIR_ARQ_MODULE_ID, + SIR_SCH_MODULE_ID, + SIR_PMM_MODULE_ID, + SIR_MNT_MODULE_ID, + SIR_DBG_MODULE_ID, + SIR_DPH_MODULE_ID, + SIR_SYS_MODULE_ID, + SIR_SMS_MODULE_ID, +}; + +#define SIR_WMA_MODULE_ID SIR_HAL_MODULE_ID + +/** + * First and last module definition for logging utility + * + * NOTE: The following definitions need to be updated if + * the above list is changed. + */ +#define SIR_FIRST_MODULE_ID SIR_HAL_MODULE_ID +#define SIR_LAST_MODULE_ID SIR_SMS_MODULE_ID + +/* 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; + +/* Rsn Capabilities structure */ +struct rsn_caps { + uint16_t PreAuthSupported:1; + uint16_t NoPairwise:1; + uint16_t PTKSAReplayCounter:2; + uint16_t GTKSAReplayCounter:2; + uint16_t MFPRequired:1; + uint16_t MFPCapable:1; + uint16_t Reserved:8; +}; + +/** + * 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; +}; + +/* / 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_SME_PEER_CREATE_FAILED, + 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; + uint8_t max_randn_interval; + uint8_t rm_capability[RMENABLEDCAP_MAX_LEN]; +}; + +/* + * although in tSirSupportedRates each IE is 16bit but PE only passes IEs in 8 + * bits with MSB=1 for basic rates. change the mask for bit0-7 only so HAL gets + * correct basic rates for setting response rates. + */ +#define IERATE_BASICRATE_MASK 0x80 +#define IERATE_RATE_MASK 0x7f +#define IERATE_IS_BASICRATE(x) ((x) & IERATE_BASICRATE_MASK) + +const char *lim_bss_type_to_string(const uint16_t bss_type); +/** + * struct sSirSupportedRates - 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 + */ +typedef struct sSirSupportedRates { + 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 +} tSirSupportedRates, *tpSirSupportedRates; + +typedef struct sSirRemainOnChnReq { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr selfMacAddr; + uint8_t chnNum; + uint8_t phyMode; + uint32_t duration; + uint8_t isProbeRequestAllowed; + uint32_t scan_id; + uint8_t probeRspIe[1]; +} tSirRemainOnChnReq, *tpSirRemainOnChnReq; + +/** + * struct sir_roc_rsp - Structure to store the remain on channel response + * @message_type: Message Type + * @length: Message Length + * @session_id: SME session Id + * @scan_id : scan identifier + * @status: result status + */ +struct sir_roc_rsp { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint32_t scan_id; + tSirResultCodes status; +}; + +typedef struct sSirRegisterMgmtFrame { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + bool registerFrame; + uint16_t frameType; + uint16_t matchLen; + uint8_t matchData[1]; +} tSirRegisterMgmtFrame, *tpSirRegisterMgmtFrame; + +/* / 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 sessionId; /* To support BT-AMP */ + uint16_t transactionId; /* To support BT-AMP */ + tSirResultCodes statusCode; + struct wlan_objmgr_psoc *psoc; +} tSirSmeRsp, *tpSirSmeRsp; + +/* / Definition for indicating all modules ready on STA */ +typedef struct sSirSmeReadyReq { + uint16_t messageType; /* eWNI_SME_SYS_READY_IND */ + uint16_t length; + uint16_t transactionId; + void *csr_roam_synch_cb; + void *pe_roam_synch_cb; + void *stop_roaming_cb; + QDF_STATUS (*sme_msg_cb)(tpAniSirGlobal mac, + struct scheduler_msg *msg); +} tSirSmeReadyReq, *tpSirSmeReadyReq; + +/** + * 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 tSirBssType - Enum for BSS type used in scanning/joining etc. + * + * @eSIR_INFRASTRUCTURE_MODE: Infrastructure station + * @eSIR_INFRA_AP_MODE: softAP mode + * @eSIR_IBSS_MODE: IBSS mode + * @eSIR_AUTO_MODE: Auto role + * @eSIR_MONITOR_MODE: Monitor mode + * @eSIR_NDI_MODE: NAN datapath mode + */ +typedef enum eSirBssType { + eSIR_INFRASTRUCTURE_MODE, + eSIR_INFRA_AP_MODE, + eSIR_IBSS_MODE, + eSIR_AUTO_MODE, + eSIR_MONITOR_MODE, + eSIR_NDI_MODE, + eSIR_DONOT_USE_BSS_TYPE = SIR_MAX_ENUM_SIZE +} tSirBssType; + +/* / Power Capability info used in 11H */ +typedef struct sSirMacPowerCapInfo { + uint8_t minTxPower; + uint8_t maxTxPower; +} tSirMacPowerCapInfo, *tpSirMacPowerCapInfo; + +/* / Supported Channel info used in 11H */ +typedef struct sSirSupChnl { + uint8_t numChnl; + uint8_t channelList[SIR_MAX_SUPPORTED_CHANNEL_LIST]; +} tSirSupChnl, *tpSirSupChnl; + +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_DONOT_USE_NW_TYPE = SIR_MAX_ENUM_SIZE +} tSirNwType; + +/* / Definition for new iBss peer info */ +typedef struct sSirNewIbssPeerInfo { + struct qdf_mac_addr peerAddr; + uint16_t aid; +} tSirNewIbssPeerInfo, *tpSirNewIbssPeerInfo; + +/* HT configuration values */ +typedef struct sSirHtConfig { + /* Enable/Disable receiving LDPC coded packets */ + uint32_t ht_rx_ldpc:1; + /* Enable/Disable TX STBC */ + uint32_t ht_tx_stbc:1; + /* Enable/Disable RX STBC */ + uint32_t ht_rx_stbc:2; + /* Enable/Disable SGI */ + uint32_t ht_sgi20:1; + uint32_t ht_sgi40:1; + uint32_t unused:27; +} qdf_packed tSirHTConfig, *tpSirHTConfig; + +/** + * struct sir_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 + * @tx_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 + */ +struct sir_vht_config { + 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 unused:2; +}; + + +typedef struct sSirAddIeParams { + uint16_t probeRespDataLen; + uint8_t *probeRespData_buff; + uint16_t assocRespDataLen; + uint8_t *assocRespData_buff; + uint16_t probeRespBCNDataLen; + uint8_t *probeRespBCNData_buff; +} tSirAddIeParams, *tpSirAddIeParams; + +/* / Definition for kick starting BSS */ +/* / ---> MAC */ +/** + * Usage of ssId, numSSID & ssIdList: + * --------------------------------- + * 1. ssId.length of zero indicates that Broadcast/Suppress SSID + * feature is enabled. + * 2. If ssId.length is zero, MAC SW will advertise NULL SSID + * and interpret the SSID list from numSSID & ssIdList. + * 3. If ssId.length is non-zero, MAC SW will advertise the SSID + * specified in the ssId field and it is expected that + * application will set numSSID to one (only one SSID present + * in the list) and SSID in the list is same as ssId field. + * 4. Application will always set numSSID >= 1. + */ +/* ***** NOTE: Please make sure all codes are updated if inserting field into + * this structure..********** */ +typedef struct sSirSmeStartBssReq { + uint16_t messageType; /* eWNI_SME_START_BSS_REQ */ + uint16_t length; + uint8_t sessionId; /* Added for BT-AMP Support */ + uint16_t transactionId; /* Added for BT-AMP Support */ + struct qdf_mac_addr bssid; /* Added for BT-AMP Support */ + struct qdf_mac_addr self_macaddr; /* Added for BT-AMP Support */ + uint16_t beaconInterval; /* Added for BT-AMP Support */ + uint8_t dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + tSirBssType bssType; + tSirMacSSid ssId; + uint8_t channelId; + ePhyChanBondState cbMode; + uint8_t vht_channel_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; + uint8_t sec_ch_offset; + + uint8_t privacy; + uint8_t apUapsdEnable; + uint8_t ssidHidden; + bool fwdWPSPBCProbeReq; + bool protEnabled; + bool obssProtEnabled; + uint16_t ht_capab; + tAniAuthType authType; + uint32_t dtimPeriod; + uint8_t wps_state; + uint8_t isCoalesingInIBSSAllowed; /* Coalesing on/off knob */ + enum QDF_OPMODE bssPersona; + + uint8_t txLdpcIniFeatureEnabled; + + tSirRSNie rsnIE; /* RSN IE to be sent in */ + /* Beacon and Probe */ + /* Response frames */ + tSirNwType nwType; /* Indicates 11a/b/g */ + tSirMacRateSet operationalRateSet; /* Has 11a or 11b rates */ + tSirMacRateSet extendedRateSet; /* Has 11g rates */ + tSirHTConfig htConfig; + struct sir_vht_config vht_config; +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_config; +#endif +#ifdef WLAN_FEATURE_11W + bool pmfCapable; + bool pmfRequired; +#endif + + tSirAddIeParams addIeParams; + + bool obssEnabled; + uint8_t sap_dot11mc; + uint16_t beacon_tx_rate; + bool vendor_vht_sap; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; + +} tSirSmeStartBssReq, *tpSirSmeStartBssReq; + +#define GET_IE_LEN_IN_BSS(lenInBss) (lenInBss + sizeof(lenInBss) - \ + ((uintptr_t)OFFSET_OF(tSirBssDescription,\ + 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; + unsigned long scansystimensec; + uint32_t timeStamp[2]; + uint16_t beaconInterval; + uint16_t capabilityInfo; + tSirNwType nwType; /* Indicates 11a/b/g */ + int8_t rssi; + int8_t rssi_raw; + int8_t sinr; + /* channelId what peer sent in beacon/probersp. */ + uint8_t channelId; + /* channelId on which we are parked at. */ + /* used only in scan case. */ + uint8_t channelIdSelf; + uint8_t sSirBssDescriptionRsvd[3]; + /* Based on system time, not a relative time. */ + uint64_t received_time; + uint32_t parentTSF; + uint32_t startTSF[2]; + uint8_t mdiePresent; + /* MDIE for 11r, picked from the beacons */ + uint8_t mdie[SIR_MDIE_SIZE]; +#ifdef FEATURE_WLAN_ESE + uint16_t QBSSLoad_present; + uint16_t QBSSLoad_avail; + /* To achieve 8-byte alignment with ESE enabled */ + uint32_t reservedPadding5; +#endif + /* whether it is from a probe rsp */ + uint8_t fProbeRsp; + /* Actual channel the beacon/probe response was received on */ + uint8_t rx_channel; + tSirMacSeqCtl seq_ctrl; + uint32_t WscIeLen; + uint8_t WscIeProbeRsp[WSCIE_PROBE_RSP_LEN]; + uint8_t reservedPadding4; + uint32_t tsf_delta; +#ifdef WLAN_FEATURE_FILS_SK + struct fils_ind_elements fils_info_element; +#endif + /* Please keep the structure 4 bytes aligned above the ieFields */ + uint32_t ieFields[1]; +}; +typedef struct bss_description tSirBssDescription, *tpSirBssDescription; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +typedef struct sSirSmeHTProfile { + uint8_t dot11mode; + uint8_t htCapability; + uint8_t htSupportedChannelWidthSet; + uint8_t htRecommendedTxWidthSet; + ePhyChanBondState htSecondaryChannelOffset; + uint8_t vhtCapability; + uint8_t apCenterChan; + uint8_t apChanWidth; +} tSirSmeHTProfile; +#endif +/* / Definition for response message to previously */ +/* / issued start BSS request */ +/* / MAC ---> */ +typedef struct sSirSmeStartBssRsp { + uint16_t messageType; /* eWNI_SME_START_BSS_RSP */ + uint16_t length; + uint8_t sessionId; + uint16_t transactionId; /* transaction ID for cmd */ + tSirResultCodes statusCode; + tSirBssType bssType; /* Add new type for WDS mode */ + uint16_t beaconInterval; /* Beacon Interval for both type */ + uint32_t staId; /* Station ID for Self */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile HTProfile; +#endif + tSirBssDescription bssDescription; /* Peer BSS description */ +} tSirSmeStartBssRsp, *tpSirSmeStartBssRsp; + +typedef struct sSirChannelList { + uint8_t numChannels; + uint8_t channelNumber[SIR_ESE_MAX_MEAS_IE_REQS]; +} tSirChannelList, *tpSirChannelList; + +/* / Two Background Scan mode */ +typedef enum eSirBackgroundScanMode { + eSIR_ROAMING_SCAN = 2, +} tSirBackgroundScanMode; + +/* / Two types of traffic check */ +typedef enum eSirLinkTrafficCheck { + eSIR_DONT_CHECK_LINK_TRAFFIC_BEFORE_SCAN = 0, + eSIR_CHECK_LINK_TRAFFIC_BEFORE_SCAN = 1, + eSIR_CHECK_ROAMING_SCAN = 2, +} tSirLinkTrafficCheck; + +#define SIR_BG_SCAN_RETURN_CACHED_RESULTS 0x0 +#define SIR_BG_SCAN_PURGE_RESUTLS 0x80 +#define SIR_BG_SCAN_RETURN_FRESH_RESULTS 0x01 +#define SIR_SCAN_MAX_NUM_SSID 0x0A +#define SIR_BG_SCAN_RETURN_LFR_CACHED_RESULTS 0x02 +#define SIR_BG_SCAN_PURGE_LFR_RESULTS 0x40 + +typedef struct sSirSmeScanAbortReq { + uint16_t type; + uint16_t msgLen; + uint8_t sessionId; + uint32_t scan_id; +} tSirSmeScanAbortReq, *tpSirSmeScanAbortReq; + +typedef struct sSirSmeScanChanReq { + uint16_t type; + uint16_t msgLen; + uint8_t sessionId; + uint16_t transcationId; +} tSirSmeGetScanChanReq, *tpSirSmeGetScanChanReq; + +#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; + tSirMacTspecIE tspec; +} tTspecInfo; + +#define SIR_ESE_MAX_TSPEC_IES 4 +typedef struct sESETspecTspecInfo { + uint8_t numTspecs; + tTspecInfo tspec[SIR_ESE_MAX_TSPEC_IES]; +} tESETspecInfo; + +typedef struct sSirTsmIE { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tSirTsmIE, *tpSirTsmIE; +typedef struct sSirSmeTsmIEInd { + tSirTsmIE tsmIe; + uint8_t sessionId; +} tSirSmeTsmIEInd, *tpSirSmeTsmIEInd; +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; + +#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) +#define MAX_VDEV_NSS 2 +#define MAX_VDEV_CHAINS 2 + +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 staId; + 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 */ + uint32_t staId; /* + * Per STA stats request must + * contain valid + */ + tAniTrafStrmMetrics tsmMetrics; + void *tsmStatsReq; /* tsm stats request backup */ +} tAniGetTsmStatsRsp, *tpAniGetTsmStatsRsp; + +typedef struct sSirEseBcnReportBssInfo { + tBcnReportFields bcnReportFields; + uint8_t ieLen; + uint8_t *pBuf; +} tSirEseBcnReportBssInfo, *tpSirEseBcnReportBssInfo; + +typedef struct sSirEseBcnReportRsp { + uint16_t measurementToken; + uint8_t flag; /* Flag to report measurement done and more data */ + uint8_t numBss; + tSirEseBcnReportBssInfo bcnRepBssInfo[SIR_BCN_REPORT_MAX_BSS_DESC]; +} tSirEseBcnReportRsp, *tpSirEseBcnReportRsp; + +#define TSRS_11AG_RATE_6MBPS 0xC +#define TSRS_11B_RATE_5_5MBPS 0xB +typedef struct sSirMacESETSRSIE { + uint8_t tsid; + uint8_t rates[8]; +} tSirMacESETSRSIE; +typedef struct sSirMacESETSMIE { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tSirMacESETSMIE; +typedef struct sTSMStats { + uint8_t tid; + struct qdf_mac_addr bssid; + tTrafStrmMetrics tsmMetrics; +} tTSMStats, *tpTSMStats; +typedef struct sEseTSMContext { + uint8_t tid; + tSirMacESETSMIE tsmInfo; + tTrafStrmMetrics tsmMetrics; +} tEseTSMContext, *tpEseTSMContext; +typedef struct sEsePEContext { + tEseTSMContext tsm; +} tEsePEContext, *tpEsePEContext; + +typedef struct sSirPlmReq { + uint16_t diag_token; /* Dialog token */ + uint16_t meas_token; /* measurement token */ + uint16_t numBursts; /* total number of bursts */ + uint16_t burstInt; /* burst interval in seconds */ + uint16_t measDuration; /* in TU's,STA goes off-ch */ + /* no of times the STA should cycle through PLM ch list */ + uint8_t burstLen; + int8_t desiredTxPwr; /* desired tx power */ + struct qdf_mac_addr mac_addr; /* MC dest addr */ + /* no of channels */ + uint8_t plmNumCh; + /* channel numbers */ + uint8_t plmChList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t sessionId; + bool enable; +} tSirPlmReq, *tpSirPlmReq; + +#endif /* FEATURE_WLAN_ESE */ + +/* / Definition for response message to previously issued scan request */ +typedef struct sSirSmeScanRsp { + uint16_t messageType; /* eWNI_SME_SCAN_RSP */ + uint16_t length; + uint8_t sessionId; + tSirResultCodes statusCode; + uint16_t transcationId; + uint32_t scan_id; +} tSirSmeScanRsp, *tpSirSmeScanRsp; + +/* / Definition for join request */ +/* / ---> MAC */ +/* / WARNING! If you add a field in JOIN REQ. */ +/* / Make sure to add it in REASSOC REQ */ +/* / The Serdes function is the same and its */ +/* / shared with REASSOC. So if we add a field */ +/* here and dont add it in REASSOC REQ. It will BREAK!!! REASSOC. */ +typedef struct sSirSmeJoinReq { + uint16_t messageType; /* eWNI_SME_JOIN_REQ */ + uint16_t length; + uint8_t sessionId; + uint16_t transactionId; + tSirMacSSid ssId; + tSirMacAddr selfMacAddr; /* self Mac address */ + tSirBssType bsstype; /* add new type for BT-AMP STA and AP Modules */ + uint8_t dot11mode; /* to support BT-AMP */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + enum QDF_OPMODE staPersona; /* Persona */ + bool wps_registration; + ePhyChanBondState cbMode; /* Pass CB mode value in Join. */ + + /*This contains the UAPSD Flag for all 4 AC + * B0: AC_VO UAPSD FLAG + * B1: AC_VI UAPSD FLAG + * B2: AC_BK UAPSD FLAG + * B3: AC_BE UASPD FLAG + */ + uint8_t uapsdPerAcBitmask; + + tSirMacRateSet operationalRateSet; /* Has 11a or 11b rates */ + tSirMacRateSet extendedRateSet; /* Has 11g rates */ + tSirRSNie rsnIE; /* RSN IE to be sent in */ + /* (Re) Association Request */ +#ifdef FEATURE_WLAN_ESE + /* CCMK IE to be included as handler for join and reassoc is */ + tSirCCKMie cckmIE; + /* the same. The join will never carry cckm, but will be set to */ + /* 0. */ +#endif + + tSirAddie addIEScan; /* Additional IE to be sent in */ + /* (unicast) Probe Request at the time of join */ + + tSirAddie addIEAssoc; /* Additional IE to be sent in */ + /* (Re) Association Request */ + + tAniEdType UCEncryptionType; + + tAniEdType MCEncryptionType; + +#ifdef WLAN_FEATURE_11W + tAniEdType MgmtEncryptionType; +#endif + + bool is11Rconnection; +#ifdef FEATURE_WLAN_ESE + bool isESEFeatureIniEnabled; + bool isESEconnection; + tESETspecInfo eseTspecInfo; +#endif + + bool isFastTransitionEnabled; + bool isFastRoamIniFeatureEnabled; + + uint8_t txLdpcIniFeatureEnabled; + tSirHTConfig htConfig; + struct sir_vht_config vht_config; +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_config; +#endif + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + bool send_smps_action; + bool he_with_wep_tkip; + uint8_t max_amsdu_num; + bool isWMEenabled; + bool isQosEnabled; + bool isOSENConnection; + struct rrm_config_param rrm_config; + bool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + bool enable_bcast_probe_rsp; +#ifdef WLAN_FEATURE_FILS_SK + struct cds_fils_connection_info fils_con_info; +#endif + bool sae_pmk_cached; + /* Pls make this as last variable in struct */ + bool force_24ghz_in_ht20; + bool force_rsne_override; + bool supported_nss_1x1; + uint8_t vdev_nss; + uint8_t nss; + bool nss_forced_1x1; + bool enable_session_twt_support; + tSirBssDescription bssDescription; + /* + * WARNING: Pls make bssDescription as last variable in struct + * tSirSmeJoinReq as it has ieFields followed after this bss + * description. Adding a variable after this corrupts the ieFields + */ +} tSirSmeJoinReq, *tpSirSmeJoinReq; + +/* / Definition for response message to previously issued join request */ +/* / MAC ---> */ +typedef struct sSirSmeJoinRsp { + uint16_t messageType; /* eWNI_SME_JOIN_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + tAniAuthType authType; + uint32_t vht_channel_width; + /* It holds reasonCode when join fails due to deauth/disassoc frame. + * Otherwise it holds status code. + */ + uint16_t protStatusCode; + uint16_t aid; + uint32_t beaconLength; + uint32_t assocReqLength; + uint32_t assocRspLength; + uint32_t parsedRicRspLen; + uint8_t uapsd_mask; +#ifdef FEATURE_WLAN_ESE + uint32_t tspecIeLen; +#endif + uint32_t staId; /* Station ID for peer */ + + /*Timing measurement capability */ + uint8_t timingMeasCap; + +#ifdef FEATURE_WLAN_TDLS + /* TDLS prohibited and TDLS channel switch prohibited are set as + * per ExtCap IE in received assoc/re-assoc response from AP + */ + bool tdls_prohibited; + bool tdls_chan_swit_prohibited; +#endif + uint8_t nss; + uint32_t max_rate_flags; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile HTProfile; +#endif + bool supported_nss_1x1; + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tDot11fIEHTInfo ht_operation; + tDot11fIEVHTOperation vht_operation; + tDot11fIEhs20vendor_ie hs20vendor_ie; + bool is_fils_connection; + uint16_t fils_seq_num; +#ifdef WLAN_FEATURE_FILS_SK + struct fils_join_rsp_params *fils_join_rsp; +#endif + uint8_t frames[1]; +} tSirSmeJoinRsp, *tpSirSmeJoinRsp; + +/* / probereq from peer, when wsc is enabled */ +typedef struct sSirSmeProbereq { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr peer_macaddr; + uint16_t devicePasswdId; +} tSirSmeProbeReq, *tpSirSmeProbeReq; + +typedef struct sSirSmeChanInfo { + uint8_t chan_id; + 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; +} tSirSmeChanInfo, *tpSirSmeChanInfo; + +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 ---> */ +typedef struct sSirSmeAssocInd { + 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; + 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; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + bool wmmEnabledSta; /* if present - STA is WMM enabled */ + bool reassocReq; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + + /* Timing measurement capability */ + uint8_t timingMeasCap; + tSirSmeChanInfo 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 rx_mcs_map; + uint8_t tx_mcs_map; + /* Extended CSA capability of station */ + uint8_t ecsa_capable; + tDot11fIEHTCaps HTCaps; + tDot11fIEVHTCaps VHTCaps; + bool he_caps_present; + tSirMacCapabilityInfo capability_info; +} tSirSmeAssocInd, *tpSirSmeAssocInd; + +/* / Definition for Association confirm */ +/* / ---> MAC */ +typedef struct sSirSmeAssocCnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; /* Self BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t aid; + struct qdf_mac_addr alternate_bssid; + uint8_t alternateChannelId; +} tSirSmeAssocCnf, *tpSirSmeAssocCnf; + +/* / Enum definition for Wireless medium status change codes */ +typedef enum eSirSmeStatusChangeCode { + eSIR_SME_DEAUTH_FROM_PEER, + eSIR_SME_DISASSOC_FROM_PEER, + eSIR_SME_LOST_LINK_WITH_PEER, + eSIR_SME_CHANNEL_SWITCH, + eSIR_SME_JOINED_NEW_BSS, + eSIR_SME_LEAVING_BSS, + eSIR_SME_IBSS_ACTIVE, + eSIR_SME_IBSS_INACTIVE, + eSIR_SME_IBSS_PEER_DEPARTED, + eSIR_SME_RADAR_DETECTED, + eSIR_SME_IBSS_NEW_PEER, + eSIR_SME_AP_CAPS_CHANGED, +} tSirSmeStatusChangeCode; + +typedef struct sSirSmeNewBssInfo { + struct qdf_mac_addr bssId; + uint8_t channelNumber; + uint8_t reserved; + tSirMacSSid ssId; +} tSirSmeNewBssInfo, *tpSirSmeNewBssInfo; + +typedef struct sSirSmeApNewCaps { + uint16_t capabilityInfo; + struct qdf_mac_addr bssId; + uint8_t channelId; + uint8_t reserved[3]; + tSirMacSSid ssId; +} tSirSmeApNewCaps, *tpSirSmeApNewCaps; + +/** + * 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_JOINED_NEW_BSS BSSID, SSID and channel number + * eSIR_SME_LEAVING_BSS None + * eSIR_SME_IBSS_ACTIVE Indicates that another STA joined + * IBSS apart from this STA that + * started IBSS + * eSIR_SME_IBSS_INACTIVE Indicates that only this STA is left + * in IBSS + * eSIR_SME_RADAR_DETECTED Indicates that radar is detected + * eSIR_SME_IBSS_NEW_PEER Indicates that a new peer is detected + * eSIR_SME_AP_CAPS_CHANGED Indicates that capabilities of the AP + * that STA is currently associated with + * have changed. + */ + +/* / Definition for Wireless medium status change notification */ +typedef struct sSirSmeWmStatusChangeNtf { + uint16_t messageType; /* eWNI_SME_WM_STATUS_CHANGE_NTF */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirSmeStatusChangeCode statusChangeCode; + struct qdf_mac_addr bssid; /* Self BSSID */ + union { + uint16_t deAuthReasonCode; /* eSIR_SME_DEAUTH_FROM_PEER */ + /* eSIR_SME_DISASSOC_FROM_PEER */ + uint16_t disassocReasonCode; + /* none for eSIR_SME_LOST_LINK_WITH_PEER */ + uint8_t newChannelId; /* eSIR_SME_CHANNEL_SWITCH */ + tSirSmeNewBssInfo newBssInfo; /* eSIR_SME_JOINED_NEW_BSS */ + /* none for eSIR_SME_LEAVING_BSS */ + /* none for eSIR_SME_IBSS_ACTIVE */ + /* none for eSIR_SME_IBSS_INACTIVE */ + /* eSIR_SME_IBSS_NEW_PEER */ + tSirNewIbssPeerInfo newIbssPeerInfo; + tSirSmeApNewCaps apNewCaps; /* eSIR_SME_AP_CAPS_CHANGED */ + } statusChangeInfo; +} tSirSmeWmStatusChangeNtf, *tpSirSmeWmStatusChangeNtf; + +/* Definition for Disassociation request */ +typedef struct sSirSmeDisassocReq { + uint16_t messageType; /* eWNI_SME_DISASSOC_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + 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; +} qdf_packed tSirSmeDisassocReq, *tpSirSmeDisassocReq; + +/* / Definition for Tkip countermeasures request */ +typedef struct sSirSmeTkipCntrMeasReq { + uint16_t messageType; /* eWNI_SME_DISASSOC_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssId; /* Peer BSSID */ + bool bEnable; /* Start/stop countermeasures */ +} qdf_packed tSirSmeTkipCntrMeasReq, *tpSirSmeTkipCntrMeasReq; + +typedef struct sAni64BitCounters { + uint32_t Hi; + uint32_t Lo; +} tAni64BitCounters, *tpAni64BitCounters; + +typedef struct sAniSecurityStat { + tAni64BitCounters txBlks; + tAni64BitCounters rxBlks; + tAni64BitCounters formatErrorCnt; + tAni64BitCounters decryptErr; + tAni64BitCounters protExclCnt; + tAni64BitCounters unDecryptableCnt; + tAni64BitCounters decryptOkCnt; + +} tAniSecurityStat, *tpAniSecurityStat; + +typedef struct sAniTxRxStats { + tAni64BitCounters txFrames; + tAni64BitCounters rxFrames; + tAni64BitCounters nRcvBytes; + tAni64BitCounters nXmitBytes; + +} tAniTxRxStats, *tpAniTxRxStats; + +typedef struct sAniSecStats { + tAniSecurityStat aes; + tAni64BitCounters aesReplays; + tAniSecurityStat tkip; + tAni64BitCounters tkipReplays; + tAni64BitCounters tkipMicError; + + tAniSecurityStat wep; +#if defined(FEATURE_WLAN_WAPI) && !defined(LIBRA_WAPI_SUPPORT) + tAniSecurityStat wpi; + tAni64BitCounters wpiReplays; + tAni64BitCounters wpiMicError; +#endif +} tAniSecStats, *tpAniSecStats; + +#define SIR_MAX_RX_CHAINS 3 + +typedef struct sAniStaStatStruct { + /* following statistic elements till expandPktRxCntLo are not filled + * with valid data. These are kept as it is, since WSM is using this + * structure. These elements can be removed whenever WSM is updated. + * Phystats is used to hold phystats from BD. + */ + uint32_t sentAesBlksUcastHi; + uint32_t sentAesBlksUcastLo; + uint32_t recvAesBlksUcastHi; + uint32_t recvAesBlksUcastLo; + uint32_t aesFormatErrorUcastCnts; + uint32_t aesReplaysUcast; + uint32_t aesDecryptErrUcast; + uint32_t singleRetryPkts; + uint32_t failedTxPkts; + uint32_t ackTimeouts; + uint32_t multiRetryPkts; + uint32_t fragTxCntsHi; + uint32_t fragTxCntsLo; + uint32_t transmittedPktsHi; + uint32_t transmittedPktsLo; + uint32_t phyStatHi; /* These are used to fill in the phystats. */ + uint32_t phyStatLo; /* This is only for private use. */ + + uint32_t uplinkRssi; + uint32_t uplinkSinr; + uint32_t uplinkRate; + uint32_t downlinkRssi; + uint32_t downlinkSinr; + uint32_t downlinkRate; + uint32_t nRcvBytes; + uint32_t nXmitBytes; + + /* + * Following elements are valid and filled in correctly. They have + * valid values. + */ + + /* Unicast frames and bytes. */ + tAniTxRxStats ucStats; + + /* Broadcast frames and bytes. */ + tAniTxRxStats bcStats; + + /* Multicast frames and bytes. */ + tAniTxRxStats mcStats; + + uint32_t currentTxRate; + uint32_t currentRxRate; /* Rate in 100Kbps */ + + uint32_t maxTxRate; + uint32_t maxRxRate; + + int8_t rssi[SIR_MAX_RX_CHAINS]; + + tAniSecStats securityStats; + + uint8_t currentRxRateIdx; /* This the softmac rate Index. */ + uint8_t currentTxRateIdx; + +} tAniStaStatStruct, *tpAniStaStatStruct; + +typedef enum sPacketType { + ePACKET_TYPE_UNKNOWN, + ePACKET_TYPE_11A, + ePACKET_TYPE_11G, + ePACKET_TYPE_11B, + ePACKET_TYPE_11N +} tPacketType, *tpPacketType; + +/* / Definition for Disassociation response */ +typedef struct sSirSmeDisassocRsp { + uint16_t messageType; /* eWNI_SME_DISASSOC_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peer_macaddr; + tAniStaStatStruct perStaStats; /* STA stats */ + uint16_t staId; +} tSirSmeDisassocRsp, *tpSirSmeDisassocRsp; + +/* / Definition for Disassociation indication from peer */ +typedef struct sSirSmeDisassocInd { + uint16_t messageType; /* eWNI_SME_DISASSOC_IND */ + uint16_t length; + uint8_t sessionId; /* Session Identifier */ + uint16_t transactionId; /* Transaction Identifier with PE */ + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; + tAniStaStatStruct perStaStats; /* STA stats */ + uint16_t staId; + uint32_t reasonCode; +} tSirSmeDisassocInd, *tpSirSmeDisassocInd; + +/* / Definition for Disassociation confirm */ +/* / MAC ---> */ +typedef struct sSirSmeDisassocCnf { + uint16_t messageType; /* eWNI_SME_DISASSOC_CNF */ + uint16_t length; + uint8_t sme_session_id; + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; +} tSirSmeDisassocCnf, *tpSirSmeDisassocCnf, + tSirSmeDeauthCnf, *tpSirSmeDeauthCnf; + +/** + * 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 */ +typedef struct sSirSmeDeauthReq { + uint16_t messageType; /* eWNI_SME_DEAUTH_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssid; /* AP BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; +} tSirSmeDeauthReq, *tpSirSmeDeauthReq; + +/* / Definition for Deauthetication response */ +typedef struct sSirSmeDeauthRsp { + uint16_t messageType; /* eWNI_SME_DEAUTH_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peer_macaddr; +} tSirSmeDeauthRsp, *tpSirSmeDeauthRsp; + +/* / Definition for Deauthetication indication from peer */ +typedef struct sSirSmeDeauthInd { + uint16_t messageType; /* eWNI_SME_DEAUTH_IND */ + uint16_t length; + uint8_t sessionId; /* Added for BT-AMP */ + uint16_t transactionId; /* Added for BT-AMP */ + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; /* AP BSSID */ + struct qdf_mac_addr peer_macaddr; + + uint16_t staId; + uint32_t reasonCode; + int8_t rssi; +} tSirSmeDeauthInd, *tpSirSmeDeauthInd; + +/* / Definition for stop BSS request message */ +typedef struct sSirSmeStopBssReq { + uint16_t messageType; /* eWNI_SME_STOP_BSS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* tranSaction ID for cmd */ + tSirResultCodes reasonCode; + struct qdf_mac_addr bssid; /* Self BSSID */ +} tSirSmeStopBssReq, *tpSirSmeStopBssReq; + +/* / Definition for stop BSS response message */ +typedef struct sSirSmeStopBssRsp { + uint16_t messageType; /* eWNI_SME_STOP_BSS_RSP */ + uint16_t length; + tSirResultCodes statusCode; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ +} tSirSmeStopBssRsp, *tpSirSmeStopBssRsp; + +/* / Definition for Channel Switch indication for station */ +/* / MAC ---> */ +typedef struct sSirSmeSwitchChannelInd { + uint16_t messageType; /* eWNI_SME_SWITCH_CHL_IND */ + uint16_t length; + uint8_t sessionId; + uint16_t newChannelId; + struct ch_params chan_params; + struct qdf_mac_addr bssid; /* BSSID */ +} tSirSmeSwitchChannelInd, *tpSirSmeSwitchChannelInd; + +/* / Definition for Neighbor BSS indication */ +/* / MAC ---> */ +/* / MAC reports this each time a new I/BSS is detected */ +typedef struct sSirSmeNeighborBssInd { + uint16_t messageType; /* eWNI_SME_NEIGHBOR_BSS_IND */ + uint16_t length; + uint8_t sessionId; + tSirBssDescription bssDescription[1]; +} tSirSmeNeighborBssInd, *tpSirSmeNeighborBssInd; + +/* / Definition for MIC failure indication */ +/* / MAC ---> */ +/* / MAC reports this each time a MIC failure occures on Rx TKIP packet */ +typedef struct sSirSmeMicFailureInd { + uint16_t messageType; /* eWNI_SME_MIC_FAILURE_IND */ + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr bssId; + tSirMicFailureInfo info; +} tSirSmeMicFailureInd, *tpSirSmeMicFailureInd; + +typedef struct sSirSmeMissedBeaconInd { + uint16_t messageType; /* eWNI_SME_MISSED_BEACON_IND */ + uint16_t length; + uint8_t bssIdx; +} tSirSmeMissedBeaconInd, *tpSirSmeMissedBeaconInd; + +/* / Definition for Set Context request */ +/* / ---> MAC */ +typedef struct sSirSmeSetContextReq { + uint16_t messageType; /* eWNI_SME_SET_CONTEXT_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr peer_macaddr; + struct qdf_mac_addr bssid; /* BSSID */ + tSirKeyMaterial keyMaterial; +} tSirSmeSetContextReq, *tpSirSmeSetContextReq; + +/* / Definition for Set Context response */ +/* / MAC ---> */ +typedef struct sSirSmeSetContextRsp { + uint16_t messageType; /* eWNI_SME_SET_CONTEXT_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peer_macaddr; +} tSirSmeSetContextRsp, *tpSirSmeSetContextRsp; + +/* / Statistic definitions */ +/* ============================================================= */ +/* Per STA statistic structure; This same struct will be used for Aggregate */ +/* STA stats as well. */ + +/* Clear radio stats and clear per sta stats */ +typedef enum { + eANI_CLEAR_ALL_STATS, /* Clears all stats */ + eANI_CLEAR_RX_STATS, /* Clears RX stats of the radio interface */ + eANI_CLEAR_TX_STATS, /* Clears TX stats of the radio interface */ + eANI_CLEAR_RADIO_STATS, /* Clears all the radio stats */ + eANI_CLEAR_PER_STA_STATS, /* Clears Per STA stats */ + eANI_CLEAR_AGGR_PER_STA_STATS, /* Clears aggregate stats */ + + /* Used to distinguish between per sta to security stats. */ + /* Used only by AP, FW just returns the same param as it received. */ + eANI_LINK_STATS, /* Get Per STA stats */ + eANI_SECURITY_STATS, /* Get Per STA security stats */ + + eANI_CLEAR_STAT_TYPES_END +} tAniStatSubTypes; + +typedef struct sAniTxCtrs { + /* add the rate counters here */ + uint32_t tx1Mbps; + uint32_t tx2Mbps; + uint32_t tx5_5Mbps; + uint32_t tx6Mbps; + uint32_t tx9Mbps; + uint32_t tx11Mbps; + uint32_t tx12Mbps; + uint32_t tx18Mbps; + uint32_t tx24Mbps; + uint32_t tx36Mbps; + uint32_t tx48Mbps; + uint32_t tx54Mbps; + uint32_t tx72Mbps; + uint32_t tx96Mbps; + uint32_t tx108Mbps; + + /* tx path radio counts */ + uint32_t txFragHi; + uint32_t txFragLo; + uint32_t txFrameHi; + uint32_t txFrameLo; + uint32_t txMulticastFrameHi; + uint32_t txMulticastFrameLo; + uint32_t txFailedHi; + uint32_t txFailedLo; + uint32_t multipleRetryHi; + uint32_t multipleRetryLo; + uint32_t singleRetryHi; + uint32_t singleRetryLo; + uint32_t ackFailureHi; + uint32_t ackFailureLo; + uint32_t xmitBeacons; +} tAniTxCtrs, *tpAniTxCtrs; + +typedef struct sAniRxCtrs { + /* receive frame rate counters */ + uint32_t rx1Mbps; + uint32_t rx2Mbps; + uint32_t rx5_5Mbps; + uint32_t rx6Mbps; + uint32_t rx9Mbps; + uint32_t rx11Mbps; + uint32_t rx12Mbps; + uint32_t rx18Mbps; + uint32_t rx24Mbps; + uint32_t rx36Mbps; + uint32_t rx48Mbps; + uint32_t rx54Mbps; + uint32_t rx72Mbps; + uint32_t rx96Mbps; + uint32_t rx108Mbps; + + /* receive size counters; 'Lte' = Less than or equal to */ + uint32_t rxLte64; + uint32_t rxLte128Gt64; + uint32_t rxLte256Gt128; + uint32_t rxLte512Gt256; + uint32_t rxLte1kGt512; + uint32_t rxLte1518Gt1k; + uint32_t rxLte2kGt1518; + uint32_t rxLte4kGt2k; + + /* rx radio stats */ + uint32_t rxFrag; + uint32_t rxFrame; + uint32_t fcsError; + uint32_t rxMulticast; + uint32_t duplicate; + uint32_t rtsSuccess; + uint32_t rtsFailed; + uint32_t wepUndecryptables; + uint32_t drops; + uint32_t aesFormatErrorUcastCnts; + uint32_t aesReplaysUcast; + uint32_t aesDecryptErrUcast; +} tAniRxCtrs, *tpAniRxCtrs; + +/* *************************************************************** */ + +/*******************PE Statistics*************************/ + +/* + * tpAniGetPEStatsReq is tied to + * for SME ==> PE eWNI_SME_GET_STATISTICS_REQ msgId and + * for PE ==> HAL SIR_HAL_GET_STATISTICS_REQ msgId + */ +typedef struct sAniGetPEStatsReq { + /* 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 */ + uint32_t staId; /* Per STA stats request must contain valid */ + /* categories of stats requested. look at ePEStatsMask */ + uint32_t statsMask; + uint8_t sessionId; +} tAniGetPEStatsReq, *tpAniGetPEStatsReq; + +/* + * tpAniGetPEStatsRsp is tied to + * for PE ==> SME eWNI_SME_GET_STATISTICS_RSP msgId and + * for HAL ==> PE SIR_HAL_GET_STATISTICS_RSP msgId + */ +typedef struct sAniGetPEStatsRsp { + /* Common for all types are responses */ + uint16_t msgType; /* message type is same as the request type */ + /* length of the entire request, includes the pStatsBuf length too */ + uint16_t msgLen; + uint8_t sessionId; + uint32_t rc; /* success/failure */ + uint32_t staId; /* Per STA stats request must contain valid */ + /* categories of stats requested. look at ePEStatsMask */ + uint32_t statsMask; + /* void *pStatsBuf; */ + /* + * The Stats buffer starts here and can be an aggregate of more than one + * statistics structure depending on statsMask. The void pointer + * "pStatsBuf" is commented out intentionally and the src code that uses + * this structure should take that into account. + */ +} tAniGetPEStatsRsp, *tpAniGetPEStatsRsp; + +typedef struct sAniGetRssiReq { + /* 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 staId; + int8_t lastRSSI; /* in case of error, return last RSSI */ + void *rssiCallback; + void *pDevContext; /* device context */ +} tAniGetRssiReq, *tpAniGetRssiReq; + +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; + uint8_t staId; + void *snrCallback; + void *pDevContext; /* device context */ + int8_t snr; +} tAniGetSnrReq, *tpAniGetSnrReq; + +/** + * struct ani_roc_req - Remain on channel request + * @msg_type: Message type + * @msg_len: Message Length + * @session_id: SME session Id + * @channel: channel number + * @callback: call back function for scan result + * @duration: Roc duration + * @is_p2pprobe_allowed : flag for p2p probe request + * @ctx: Global context + * @scan_id: Scan Identifier + * + * Remain on channel request message structure + */ +struct ani_roc_req { + /* message type is same as the request type */ + uint16_t msg_type; + /* length of the entire request */ + uint16_t msg_len; + uint16_t session_id; + uint8_t channel; + uint32_t duration; + uint8_t is_p2pprobe_allowed; + void *callback; + void *ctx; + uint32_t scan_id; +}; + +/* 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[WNI_CFG_COUNTRY_CODE_LEN]; /* 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; + +typedef struct sAniTXFailMonitorInd { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t tx_fail_count; + void *txFailIndCallback; +} tAniTXFailMonitorInd, *tpAniTXFailMonitorInd; + +#ifndef QCA_SUPPORT_CP_STATS +/** + * 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 + */ +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 +}; +#endif +/**********************PE Statistics end*************************/ + +typedef struct sSirP2PNoaStart { + uint32_t status; + uint32_t bssIdx; +} tSirP2PNoaStart, *tpSirP2PNoaStart; + +typedef struct sSirTdlsInd { + uint16_t status; + uint16_t assocId; + uint16_t staIdx; + uint16_t reasonCode; +} tSirTdlsInd, *tpSirTdlsInd; + +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; + tSirMacTspecIE tspec; + + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; +#if defined(FEATURE_WLAN_ESE) + tSirMacESETSRSIE 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; + tSirMacStatusCodes status; + tSirMacTsDelayIE delay; + + tSirMacTspecIE tspec; + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; + tSirMacScheduleIE schedule; +#ifdef FEATURE_WLAN_ESE + tSirMacESETSMIE 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; + +typedef struct sSirDeltsReqInfo { + tSirMacTSInfo tsinfo; + tSirMacTspecIE tspec; + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; +} tSirDeltsReqInfo, *tpSirDeltsReqInfo; + +/* / Add a tspec as defined */ +typedef struct sSirAddtsReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + 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 */ + uint16_t transactionId; /* sme transaction Id - 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 */ + uint16_t transactionId; + 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; + tSirDeltsReqInfo req; +} tSirDeltsReq, *tpSirDeltsReq; + +typedef struct sSirDeltsRsp { + uint16_t messageType; /* eWNI_SME_DELTS_RSP */ + uint16_t length; + uint8_t sessionId; /* sme sessionId Added for BT-AMP support */ + uint16_t transactionId; /* sme transaction Id - for BT-AMP Support */ + 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 */ + tSirDeltsReqInfo rsp; +} tSirDeltsRsp, *tpSirDeltsRsp; + +#define SIR_QOS_NUM_AC_MAX 4 + +typedef struct sSirAggrQosReqInfo { + uint16_t tspecIdx; + tSirAddtsReqInfo aggrAddTsInfo[SIR_QOS_NUM_AC_MAX]; +} tSirAggrQosReqInfo, *tpSirAggrQosReqInfo; + +typedef struct sSirAggrQosReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + struct qdf_mac_addr bssid; /* BSSID */ + uint32_t timeout; /* in ms */ + uint8_t rspReqd; + tSirAggrQosReqInfo aggrInfo; +} tSirAggrQosReq, *tpSirAggrQosReq; + +typedef struct sSirAggrQosRspInfo { + uint16_t tspecIdx; + tSirAddtsRspInfo aggrRsp[SIR_QOS_NUM_AC_MAX]; +} tSirAggrQosRspInfo, *tpSirAggrQosRspInfo; + +typedef struct sSirAggrQosRsp { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + tSirAggrQosRspInfo aggrInfo; +} tSirAggrQosRsp, *tpSirAggrQosRsp; + + +typedef struct sSirQosMapSet { + uint8_t present; + uint8_t num_dscp_exceptions; + uint8_t dscp_exceptions[21][2]; + uint8_t dscp_range[8][2]; +} tSirQosMapSet, *tpSirQosMapSet; + +typedef struct sSmeIbssPeerInd { + uint16_t mesgType; + uint16_t mesgLen; + uint8_t sessionId; + + struct qdf_mac_addr peer_addr; + uint16_t staId; + + /* Beacon will be appended for new Peer indication. */ +} tSmeIbssPeerInd, *tpSmeIbssPeerInd; + +typedef struct sSirIbssPeerInactivityInd { + uint8_t bssIdx; + uint8_t staIdx; + struct qdf_mac_addr peer_addr; +} tSirIbssPeerInactivityInd, *tpSirIbssPeerInactivityInd; + +typedef struct sLimScanChn { + uint16_t numTimeScan; /* how many time this channel is scan */ + uint8_t channelId; +} tLimScanChn; + +/** + * struct lim_channel_status + * @channelfreq: 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 + */ +struct lim_channel_status { + uint32_t channelfreq; + 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; +}; + +/** + * 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, +}; + +/** + * struct lim_scan_channel_status + * @total_channel: total number of be scanned channel + * @channel_status_list: channel status info store in this array + */ +struct lim_scan_channel_status { + uint8_t total_channel; + struct lim_channel_status + channel_status_list[SIR_MAX_SUPPORTED_CHANNEL_LIST]; +}; + +typedef struct sSmeGetScanChnRsp { + /* Message Type */ + uint16_t mesgType; + /* Message Length */ + uint16_t mesgLen; + uint8_t sessionId; + uint8_t numChn; + tLimScanChn scanChn[1]; +} tSmeGetScanChnRsp, *tpSmeGetScanChnRsp; + +typedef struct sSirSmeGetAssocSTAsReq { + uint16_t messageType; /* eWNI_SME_GET_ASSOC_STAS_REQ */ + uint16_t length; + struct qdf_mac_addr bssid; /* BSSID */ + uint16_t modId; + void *pUsrContext; + void *pSapEventCallback; + /* Pointer to allocated mem passed in wlansap_get_assoc_stations API */ + void *pAssocStasArray; +} tSirSmeGetAssocSTAsReq, *tpSirSmeGetAssocSTAsReq; + +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; + +typedef struct sSmeCsaOffloadInd { + uint16_t mesgType; /* eWNI_SME_CSA_OFFLOAD_EVENT */ + uint16_t mesgLen; + struct qdf_mac_addr bssid; /* BSSID */ +} tSmeCsaOffloadInd, *tpSmeCsaOffloadInd; + +#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; /* Configuaration 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; + +#define SIR_WPS_ASSOCRSP_VER_PRESENT 0x00000001 +#define SIR_WPS_ASSOCRSP_RESPONSETYPE_PRESENT 0x00000002 + +typedef struct sSirWPSAssocRspIE { + uint32_t FieldPresent; + uint32_t Version; + uint8_t ResposeType; +} tSirWPSAssocRspIE; + +typedef struct sSirAPWPSIEs { + tSirWPSProbeRspIE SirWPSProbeRspIE; /*WPS Set Probe Respose IE */ + tSirWPSBeaconIE SirWPSBeaconIE; /*WPS Set Beacon IE */ + tSirWPSAssocRspIE SirWPSAssocRspIE; /*WPS Set Assoc Response IE */ +} tSirAPWPSIEs, *tpSiriAPWPSIEs; + +typedef struct sSirUpdateAPWPSIEsReq { + uint16_t messageType; /* eWNI_SME_UPDATE_APWPSIE_REQ */ + uint16_t length; + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssid; /* BSSID */ + uint8_t sessionId; /* Session ID */ + tSirAPWPSIEs APWPSIEs; +} tSirUpdateAPWPSIEsReq, *tpSirUpdateAPWPSIEsReq; + +struct update_config { + uint16_t messageType; /* eWNI_SME_UPDATE_CONFIG */ + uint16_t length; + uint8_t sme_session_id; + uint16_t capab; + uint32_t value; +}; + +/* + * enum sir_update_session_param_type - session param type + * @SIR_PARAM_SSID_HIDDEN: ssidHidden parameter + * @SIR_PARAM_IGNORE_ASSOC_DISALLOWED: ignore_assoc_disallowed parameter + */ +enum sir_update_session_param_type { + SIR_PARAM_SSID_HIDDEN, + SIR_PARAM_IGNORE_ASSOC_DISALLOWED, +}; + +/* + * struct sir_update_session_param + * @message_type: SME message type + * @length: size of struct sir_update_session_param + * @session_id: Session 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 session_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 + * @session_id: Session ID + * @bss_color: bss color value + */ +struct sir_set_he_bss_color { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint8_t bss_color; +}; + +/** + * 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; + struct qdf_mac_addr bss_id; +}; + +/* Beacon Interval */ +typedef struct sSirChangeBIParams { + uint16_t messageType; + uint16_t length; + uint16_t beaconInterval; /* Beacon Interval */ + struct qdf_mac_addr bssid; + uint8_t sessionId; /* Session ID */ +} tSirChangeBIParams, *tpSirChangeBIParams; + +#ifdef QCA_HT_2040_COEX +typedef struct sSirSetHT2040Mode { + uint16_t messageType; + uint16_t length; + uint8_t cbMode; + bool obssEnabled; + struct qdf_mac_addr bssid; + uint8_t sessionId; /* Session ID */ +} tSirSetHT2040Mode, *tpSirSetHT2040Mode; +#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 sSirSmeGetWPSPBCSessionsReq { + uint16_t messageType; /* eWNI_SME_GET_WPSPBC_SESSION_REQ */ + uint16_t length; + void *pUsrContext; + void *pSapEventCallback; + struct qdf_mac_addr bssid; /* BSSID */ + /* MAC Address of STA in WPS Session to be removed */ + struct qdf_mac_addr remove_mac; +} tSirSmeGetWPSPBCSessionsReq, *tpSirSmeGetWPSPBCSessionsReq; + +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; + +typedef struct sSirUpdateAPWPARSNIEsReq { + uint16_t messageType; /* eWNI_SME_SET_APWPARSNIEs_REQ */ + uint16_t length; + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssid; /* BSSID */ + uint8_t sessionId; /* Session ID */ + tSirRSNie APWPARSNIEs; +} tSirUpdateAPWPARSNIEsReq, *tpSirUpdateAPWPARSNIEsReq; + +#define SIR_ROAM_MAX_CHANNELS 80 +#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 +#define SIR_ROAM_SCAN_24G_DEFAULT_CH 1 +#define SIR_ROAM_SCAN_5G_DEFAULT_CH 36 +#define SIR_ROAM_SCAN_RESERVED_BYTES 61 + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_ROAM_SCAN_PSK_SIZE 48 +#define SIR_ROAM_R0KH_ID_MAX_LEN 48 +#endif +/* SME -> HAL - This is the host offload request. */ +#define SIR_IPV4_ARP_REPLY_OFFLOAD 0 +#define SIR_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 +#define SIR_IPV6_NS_OFFLOAD 2 +#define SIR_OFFLOAD_DISABLE 0 +#define SIR_OFFLOAD_ENABLE 1 + +#ifdef WLAN_NS_OFFLOAD +typedef struct sSirNsOffloadReq { + uint8_t srcIPv6Addr[SIR_MAC_IPV6_ADDR_LEN]; + uint8_t selfIPv6Addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][SIR_MAC_IPV6_ADDR_LEN]; + uint8_t targetIPv6Addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][SIR_MAC_IPV6_ADDR_LEN]; + struct qdf_mac_addr self_macaddr; + uint8_t srcIPv6AddrValid; + uint8_t targetIPv6AddrValid[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t target_ipv6_addr_ac_type[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t slotIdx; +} tSirNsOffloadReq, *tpSirNsOffloadReq; +#endif /* WLAN_NS_OFFLOAD */ + +typedef struct sSirHostOffloadReq { + uint8_t offloadType; + uint8_t enableOrDisable; + uint32_t num_ns_offload_count; + union { + uint8_t hostIpv4Addr[SIR_IPV4_ADDR_LEN]; + uint8_t hostIpv6Addr[SIR_MAC_IPV6_ADDR_LEN]; + } params; +#ifdef WLAN_NS_OFFLOAD + tSirNsOffloadReq nsOffloadInfo; +#endif /* WLAN_NS_OFFLOAD */ + struct qdf_mac_addr bssid; +} tSirHostOffloadReq, *tpSirHostOffloadReq; + +/* Packet Types. */ +#define SIR_KEEP_ALIVE_NULL_PKT 1 +#define SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 + +/* Keep Alive request. */ +typedef struct sSirKeepAliveReq { + uint8_t packetType; + uint32_t timePeriod; + tSirIpv4Addr hostIpv4Addr; + tSirIpv4Addr destIpv4Addr; + struct qdf_mac_addr dest_macaddr; + struct qdf_mac_addr bssid; + uint8_t sessionId; +} tSirKeepAliveReq, *tpSirKeepAliveReq; + +typedef struct sSirSmeMgmtFrameInd { + uint16_t frame_len; + uint32_t rxChan; + uint8_t sessionId; + uint8_t frameType; + int8_t rxRssi; + uint8_t frameBuf[1]; /* variable */ +} 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 void (*sir_purge_pdev_cmd_cb)(hdd_handle_t hdd_ctx); +/** + * struct sir_purge_pdev_cmd_req - Register a + * management frame callback req + * + * @message_type: message id + * @length: msg length + * @purge_complete_cb: callback for pdev purge cmd complete + */ +struct sir_purge_pdev_cmd_req { + uint16_t message_type; + uint16_t length; + sir_purge_pdev_cmd_cb purge_complete_cb; +}; + +#ifdef WLAN_FEATURE_11W +typedef struct sSirSmeUnprotMgmtFrameInd { + uint8_t sessionId; + uint8_t frameType; + uint8_t frameLen; + uint8_t frameBuf[1]; /* variable */ +} tSirSmeUnprotMgmtFrameInd, *tpSirSmeUnprotMgmtFrameInd; +#endif + +#define SIR_IS_FULL_POWER_REASON_DISCONNECTED(eReason) \ + ((eSME_LINK_DISCONNECTED_BY_HDD == (eReason)) || \ + (eSME_LINK_DISCONNECTED_BY_OTHER == (eReason))) +#define SIR_IS_FULL_POWER_NEEDED_BY_HDD(eReason) \ + ((eSME_LINK_DISCONNECTED_BY_HDD == (eReason)) || \ + (eSME_FULL_PWR_NEEDED_BY_HDD == (eReason))) + +/* P2P Power Save Related */ +typedef struct sSirNoAParam { + uint8_t ctWindow:7; + uint8_t OppPS:1; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t singleNoADuration; + uint8_t psSelection; +} tSirNoAParam, *tpSirNoAParam; + +typedef struct sSirWlanResumeParam { + uint8_t configuredMcstBcstFilterSetting; +} tSirWlanResumeParam, *tpSirWlanResumeParam; + +#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 + +#define ANI_MAX_IBSS_ROUTE_TABLE_ENTRY 100 + +typedef struct sAniDestIpNextHopMacPair { + uint8_t destIpv4Addr[QDF_IPV4_ADDR_SIZE]; + uint8_t nextHopMacAddr[QDF_MAC_ADDR_SIZE]; +} tAniDestIpNextHopMacPair; + +typedef struct sAniIbssRouteTable { + uint8_t sessionId; + uint16_t numEntries; + tAniDestIpNextHopMacPair destIpNextHopPair[1]; +} tAniIbssRouteTable; + +#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 + +typedef struct { + tSirMacSSid ssId; + uint8_t currAPbssid[QDF_MAC_ADDR_SIZE]; + uint32_t authentication; + uint8_t encryption; + uint8_t mcencryption; + uint8_t ChannelCount; + uint8_t ChannelCache[SIR_ROAM_MAX_CHANNELS]; +#ifdef WLAN_FEATURE_11W + bool mfp_enabled; +#endif + +} tSirRoamNetworkType; + +typedef struct SirMobilityDomainInfo { + uint8_t mdiePresent; + uint16_t mobilityDomain; +} tSirMobilityDomainInfo; + +typedef enum { + SIR_ROAMING_DFS_CHANNEL_DISABLED = 0, + SIR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL = 1, + SIR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE = 2 +} eSirDFSRoamScanMode; +#define MAX_SSID_ALLOWED_LIST 4 +#define MAX_BSSID_AVOID_LIST 16 +#define MAX_BSSID_FAVORED 16 +/** + * struct roam_ext_params - Structure holding roaming parameters + * @num_bssid_avoid_list: The number of BSSID's that we should + * avoid connecting to. It is like a + * blacklist of BSSID's. + * @num_ssid_allowed_list: The number of SSID profiles that are + * in the Whitelist. When roaming, we + * consider the BSSID's with this SSID + * also for roaming apart from the connected one's + * @num_bssid_favored: Number of BSSID's which have a preference over + * others + * @ssid_allowed_list: Whitelist SSID's + * @bssid_avoid_list: Blacklist SSID's + * @bssid_favored: Favorable BSSID's + * @bssid_favored_factor: RSSI to be added to this BSSID to prefer it + * @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_rssi_type_5g: Algorithm to apply the boost factor + * @raise_factor_5g: Boost factor + * @drop_rssi_type_5g: Algorithm to apply the penalty factor + * @drop_factor_5g: Penalty factor + * @max_raise_rssi_5g: Maximum amount of Boost that can added + * @max_drop_rssi_5g: Maximum amount of penalty that can be subtracted + * @good_rssi_threshold: The Lookup UP threshold beyond which roaming + * scan should be performed. + * @rssi_diff: RSSI difference for the AP to be better over the + * current AP to avoid ping pong effects + * @good_rssi_roam: Lazy Roam + * @is_5g_pref_enabled: 5GHz BSSID preference feature enable/disable. + * @bg_scan_bad_rssi_thresh: Bad RSSI threshold to perform bg scan. + * @bad_rssi_thresh_offset_2g: Offset from Bad RSSI threshold for 2G to 5G Roam + * @bg_scan_client_bitmap: Bitmap to identify the client scans to snoop. + * + * This structure holds all the key parameters related to + * initial connection and also roaming connections. + * */ +struct roam_ext_params { + uint8_t num_bssid_avoid_list; + uint8_t num_ssid_allowed_list; + uint8_t num_bssid_favored; + tSirMacSSid ssid_allowed_list[MAX_SSID_ALLOWED_LIST]; + struct qdf_mac_addr bssid_avoid_list[MAX_BSSID_AVOID_LIST]; + struct qdf_mac_addr bssid_favored[MAX_BSSID_FAVORED]; + uint8_t bssid_favored_factor[MAX_BSSID_FAVORED]; + int raise_rssi_thresh_5g; + int drop_rssi_thresh_5g; + uint8_t raise_rssi_type_5g; + uint8_t raise_factor_5g; + uint8_t drop_rssi_type_5g; + uint8_t drop_factor_5g; + int max_raise_rssi_5g; + int max_drop_rssi_5g; + int alert_rssi_threshold; + int rssi_diff; + int good_rssi_roam; + bool is_5g_pref_enabled; + int dense_rssi_thresh_offset; + int dense_min_aps_cnt; + int initial_dense_status; + int traffic_threshold; + uint8_t num_rssi_rejection_ap; + struct rssi_disallow_bssid rssi_rejection_ap[MAX_RSSI_AVOID_BSSID_LIST]; + int8_t bg_scan_bad_rssi_thresh; + uint8_t roam_bad_rssi_thresh_offset_2g; + uint32_t bg_scan_client_bitmap; +}; + +/** + * struct sir_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 + */ +struct sir_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; +}; + +struct sir_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 sir_per_slot_scoring - define % score for differents slots for a + * scoring param. + * num_slot: number of slots in which the param will be divided. + * Max 15. index 0 is used for 'not_present. Num_slot will + * equally divide 100. e.g, if num_slot = 4 slot 0 = 0-25%, slot + * 1 = 26-50% slot 2 = 51-75%, slot 3 = 76-100% + * score_pcnt3_to_0: Conatins score percentage for slot 0-3 + * BITS 0-7 :- the scoring pcnt when not present + * BITS 8-15 :- SLOT_1 + * BITS 16-23 :- SLOT_2 + * BITS 24-31 :- SLOT_3 + * score_pcnt7_to_4: Conatins score percentage for slot 4-7 + * BITS 0-7 :- SLOT_4 + * BITS 8-15 :- SLOT_5 + * BITS 16-23 :- SLOT_6 + * BITS 24-31 :- SLOT_7 + * score_pcnt11_to_8: Conatins score percentage for slot 8-11 + * BITS 0-7 :- SLOT_8 + * BITS 8-15 :- SLOT_9 + * BITS 16-23 :- SLOT_10 + * BITS 24-31 :- SLOT_11 + * score_pcnt15_to_12: Conatins score percentage for slot 12-15 + * BITS 0-7 :- SLOT_12 + * BITS 8-15 :- SLOT_13 + * BITS 16-23 :- SLOT_14 + * BITS 24-31 :- SLOT_15 + */ +struct sir_per_slot_scoring { + uint32_t num_slot; + uint32_t score_pcnt3_to_0; + uint32_t score_pcnt7_to_4; + uint32_t score_pcnt11_to_8; + uint32_t score_pcnt15_to_12; +}; + +struct sir_score_config { + bool enable_scoring_for_roam; + struct sir_weight_config weight_cfg; + struct sir_rssi_cfg_score rssi_score; + struct sir_per_slot_scoring esp_qbss_scoring; + struct sir_per_slot_scoring oce_wan_scoring; + uint32_t bandwidth_weight_per_index; + uint32_t nss_weight_per_index; + uint32_t band_weight_per_index; + uint32_t roam_score_delta; + uint32_t roam_score_delta_bitmap; +}; + +/** + * 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 lca_disallow_config_params - LCA[Last Connected AP] + * disallow config params + * @disallow_duration: LCA AP disallowed duration + * @rssi_channel_penalization: RSSI channel Penalization + * @num_disallowed_aps: Maximum number of AP's in LCA list + * + */ +struct lca_disallow_config_params { + uint32_t disallow_duration; + uint32_t rssi_channel_penalization; + uint32_t num_disallowed_aps; +}; + +/** + * struct mawc_params - Motion Aided Wireless Connectivity configuration + * @MAWCEnabled: Global configuration for MAWC (Roaming/PNO/ExtScan) + * @mawc_roam_enabled: MAWC roaming enable/disable + * @mawc_roam_traffic_threshold: Traffic threshold in kBps for MAWC roaming + * @mawc_roam_ap_rssi_threshold: AP RSSI threshold for MAWC roaming + * @mawc_roam_rssi_high_adjust: High Adjustment value for suppressing scan + * @mawc_roam_rssi_low_adjust: Low Adjustment value for suppressing scan + */ +struct mawc_params { + bool mawc_enabled; + bool mawc_roam_enabled; + uint32_t mawc_roam_traffic_threshold; + int8_t mawc_roam_ap_rssi_threshold; + uint8_t mawc_roam_rssi_high_adjust; + uint8_t mawc_roam_rssi_low_adjust; +}; + +typedef struct sSirRoamOffloadScanReq { + uint16_t message_type; + uint16_t length; + bool RoamScanOffloadEnabled; + struct mawc_params mawc_roam_params; + int8_t LookupThreshold; + int8_t rssi_thresh_offset_5g; + uint8_t delay_before_vdev_stop; + uint8_t OpportunisticScanThresholdDiff; + uint8_t RoamRescanRssiDiff; + uint8_t RoamRssiDiff; + struct rsn_caps rsn_caps; + int32_t rssi_abs_thresh; + uint8_t ChannelCacheType; + uint8_t Command; + uint8_t reason; + uint16_t NeighborScanTimerPeriod; + uint16_t neighbor_scan_min_timer_period; + uint16_t NeighborRoamScanRefreshPeriod; + uint16_t NeighborScanChannelMinTime; + uint16_t NeighborScanChannelMaxTime; + uint16_t EmptyRefreshScanPeriod; + uint8_t ValidChannelCount; + uint8_t ValidChannelList[SIR_ROAM_MAX_CHANNELS]; + bool IsESEAssoc; + bool is_11r_assoc; + uint8_t nProbes; + uint16_t HomeAwayTime; + tSirRoamNetworkType ConnectedNetwork; + tSirMobilityDomainInfo MDID; + uint8_t sessionId; + uint8_t RoamBmissFirstBcnt; + uint8_t RoamBmissFinalBcnt; + uint8_t RoamBeaconRssiWeight; + eSirDFSRoamScanMode allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t RoamOffloadEnabled; + uint8_t PSK_PMK[SIR_ROAM_SCAN_PSK_SIZE]; + uint32_t pmk_len; + uint8_t Prefer5GHz; + uint8_t RoamRssiCatGap; + uint8_t Select5GHzMargin; + uint8_t KRK[SIR_KRK_KEY_LEN]; + uint8_t BTK[SIR_BTK_KEY_LEN]; + uint32_t ReassocFailureTimeout; + tSirAcUapsd AcUapsd; + uint8_t R0KH_ID[SIR_ROAM_R0KH_ID_MAX_LEN]; + uint32_t R0KH_ID_Length; + uint8_t RoamKeyMgmtOffloadEnabled; + struct pmkid_mode_bits pmkid_modes; + uint32_t roam_preauth_retry_count; + uint32_t roam_preauth_no_ack_timeout; +#endif + struct roam_ext_params roam_params; + uint8_t middle_of_roaming; + 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; + uint8_t early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + enum scan_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + tSirAddie assoc_ie; + struct lca_disallow_config_params lca_config_params; + struct scoring_param score_params; +#ifdef WLAN_FEATURE_FILS_SK + bool is_fils_connection; + struct roam_fils_params roam_fils_params; +#endif + 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; + struct wmi_11k_offload_params offload_11k_params; + uint32_t ho_delay_for_rx; + uint32_t min_delay_btw_roam_scans; + uint32_t roam_trigger_reason_bitmask; + bool roam_force_rssi_trigger; + /* bss load triggered roam related params */ + bool bss_load_trig_enabled; + struct wmi_bss_load_config bss_load_config; + bool roaming_scan_policy; +} tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq; + +typedef struct sSirRoamOffloadScanRsp { + uint8_t sessionId; + uint32_t reason; +} tSirRoamOffloadScanRsp, *tpSirRoamOffloadScanRsp; + + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/*--------------------------------------------------------------------------- + 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 +#define SIR_MAX_NUM_FILTERS 20 +#define SIR_MAX_NUM_TESTS_PER_FILTER 10 + +/* */ +/* Filter Packet Match Count Parameters */ +/* */ +typedef struct sSirRcvFltPktMatchCnt { + uint8_t filterId; + uint32_t matchCnt; +} tSirRcvFltPktMatchCnt, tpSirRcvFltPktMatchCnt; + +typedef struct sSirRcvFltPktMatchRsp { + uint16_t mesgType; + uint16_t mesgLen; + + /* Success or Failure */ + uint32_t status; + tSirRcvFltPktMatchCnt filterMatchCnt[SIR_MAX_NUM_FILTERS]; + struct qdf_mac_addr bssid; +} tSirRcvFltPktMatchRsp, *tpSirRcvFltPktMatchRsp; + +/* */ +/* Receive Filter Clear Parameters */ +/* */ +typedef struct sSirRcvFltPktClearParam { + uint32_t status; /* only valid for response message */ + uint8_t filterId; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; +} tSirRcvFltPktClearParam, *tpSirRcvFltPktClearParam; + +/* */ +/* 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; +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* */ +/* Generic version information */ +/* */ +typedef struct { + uint8_t revision; + uint8_t version; + uint8_t minor; + uint8_t major; +} tSirVersionType; + +/** + * 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[128]; + uint8_t weight_list[128]; +}; + +/** + * 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[128]; + uint32_t pcl_len; + uint8_t saved_chan_list[128]; + uint32_t saved_num_chan; + uint8_t weighed_valid_list[128]; + uint8_t weight_list[128]; +}; + +/** + * 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_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 + */ +struct sir_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]; +}; + +/** + * 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; +}; + +/*--------------------------------------------------------------------------- + sAniSetTmLevelReq + ---------------------------------------------------------------------------*/ +typedef struct sAniSetTmLevelReq { + uint16_t tmMode; + uint16_t newTmLevel; +} tAniSetTmLevelReq, *tpAniSetTmLevelReq; + +#ifdef FEATURE_WLAN_TDLS +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsSendMgmtReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + uint8_t reqType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_mac; + enum wifi_traffic_ac ac; + /* Variable length. Dont add any field after this. */ + uint8_t addIe[1]; +} tSirTdlsSendMgmtReq, *tpSirSmeTdlsSendMgmtReq; + +typedef enum TdlsAddOper { + TDLS_OPER_NONE, + TDLS_OPER_ADD, + TDLS_OPER_UPDATE +} eTdlsAddOper; + +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsAddStaReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + eTdlsAddOper tdlsAddOper; + struct qdf_mac_addr peermac; + uint16_t capability; + uint8_t extn_capability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_length; + uint8_t supported_rates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + struct htcap_cmn_ie htCap; + uint8_t vhtcap_present; + tSirVHTCap vhtCap; + uint8_t uapsd_queues; + uint8_t max_sp; +} tSirTdlsAddStaReq, *tpSirSmeTdlsAddStaReq; + +/* TDLS Response struct PE-->SME */ +typedef struct sSirTdlsAddStaRsp { + uint16_t messageType; + uint16_t length; + tSirResultCodes statusCode; + struct qdf_mac_addr peermac; + uint8_t sessionId; /* Session ID */ + uint16_t staId; + uint16_t staType; + eTdlsAddOper tdlsAddOper; + struct wlan_objmgr_psoc *psoc; +} tSirTdlsAddStaRsp; + +/* TDLS Request struct SME-->PE */ +typedef struct { + uint16_t messageType; /* eWNI_SME_TDLS_LINK_ESTABLISH_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + uint8_t uapsdQueues; /* Peer's uapsd Queues Information */ + uint8_t maxSp; /* Peer's Supported Maximum Service Period */ + uint8_t isBufSta; /* Does Peer Support as Buffer Station. */ + /* Does Peer Support as TDLS Off Channel. */ + uint8_t isOffChannelSupported; + uint8_t isResponder; /* Is Peer a responder. */ + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + struct qdf_mac_addr peermac; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[REG_MAX_SUPP_OPER_CLASSES]; +} tSirTdlsLinkEstablishReq, *tpSirTdlsLinkEstablishReq; + +/* TDLS Request struct SME-->PE */ +typedef struct { + uint16_t messageType; /* eWNI_SME_TDLS_LINK_ESTABLISH_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peermac; +} tSirTdlsLinkEstablishReqRsp, *tpSirTdlsLinkEstablishReqRsp; + +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsDelStaReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + struct qdf_mac_addr peermac; +} tSirTdlsDelStaReq, *tpSirSmeTdlsDelStaReq; +/* TDLS Response struct PE-->SME */ +typedef struct sSirTdlsDelStaRsp { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirResultCodes statusCode; + struct qdf_mac_addr peermac; + uint16_t staId; + struct wlan_objmgr_psoc *psoc; +} tSirTdlsDelStaRsp, *tpSirTdlsDelStaRsp; +/* TDLS Delete Indication struct PE-->SME */ +typedef struct sSirTdlsDelStaInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + struct qdf_mac_addr peermac; + uint16_t staId; + uint16_t reasonCode; +} tSirTdlsDelStaInd, *tpSirTdlsDelStaInd; +typedef struct sSirTdlsDelAllPeerInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ +} tSirTdlsDelAllPeerInd, *tpSirTdlsDelAllPeerInd; +typedef struct sSirMgmtTxCompletionInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint32_t txCompleteStatus; + struct wlan_objmgr_psoc *psoc; +} tSirMgmtTxCompletionInd, *tpSirMgmtTxCompletionInd; + +typedef struct sSirTdlsEventnotify { + uint8_t sessionId; + struct qdf_mac_addr peermac; + uint16_t messageType; + uint32_t peer_reason; +} tSirTdlsEventnotify; +#endif /* FEATURE_WLAN_TDLS */ + +/* Reset AP Caps Changed */ +typedef struct sSirResetAPCapsChange { + uint16_t messageType; + uint16_t length; + struct qdf_mac_addr bssId; +} tSirResetAPCapsChange, *tpSirResetAPCapsChange; + +/* / Definition for Candidate found indication from FW */ +typedef struct sSirSmeCandidateFoundInd { + uint16_t messageType; /* eWNI_SME_CANDIDATE_FOUND_IND */ + uint16_t length; + uint8_t sessionId; /* Session Identifier */ +} tSirSmeCandidateFoundInd, *tpSirSmeCandidateFoundInd; + +#ifdef WLAN_FEATURE_11W +typedef struct sSirWlanExcludeUnencryptParam { + bool excludeUnencrypt; + struct qdf_mac_addr bssid; +} tSirWlanExcludeUnencryptParam, *tpSirWlanExcludeUnencryptParam; +#endif + +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]; + uint8_t channel; + 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 FORIEGN 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 + * @chanId: ID 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 + */ +typedef struct sSirUpdateChanParam { + uint8_t chanId; + uint8_t pwr; + bool dfsSet; + bool half_rate; + bool quarter_rate; +} tSirUpdateChanParam, *tpSirUpdateChanParam; + +typedef struct sSirUpdateChan { + uint8_t numChan; + uint8_t ht_en; + uint8_t vht_en; + uint8_t vht_24_en; + tSirUpdateChanParam chanParam[1]; +} 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 */ + +typedef struct sSirLinkSpeedInfo { + /* MAC Address for the peer */ + struct qdf_mac_addr peer_macaddr; + uint32_t estLinkSpeed; /* Linkspeed from firmware */ +} tSirLinkSpeedInfo, *tpSirLinkSpeedInfo; + +/** + * struct sir_peer_info_req - peer info request struct + * @peer_macaddr: MAC address + * @sessionid: vdev id + * + * peer info request message's struct + */ +struct sir_peer_info_req { + struct qdf_mac_addr peer_macaddr; + uint8_t sessionid; +}; + +/** + * struct sir_peer_info - peer information struct + * @peer_macaddr: MAC address + * @rssi: rssi + * @tx_rate: last tx rate + * @rx_rate: last rx rate + * + * a station's information + */ +struct sir_peer_info { + struct qdf_mac_addr peer_macaddr; + int8_t rssi; + uint32_t tx_rate; + uint32_t rx_rate; +}; + +/** + * struct sir_peer_info_resp - all peers information struct + * @count: peer's number + * @info: peer information + * + * all station's information + */ +struct sir_peer_info_resp { + uint8_t count; + struct sir_peer_info info[0]; +}; + +/** + * struct sir_peer_info_ext_req - peer info request struct + * @peer_macaddr: MAC address + * @sessionid: vdev id + * @reset_after_request: fw reset statistics after query + * + * peer info request message's struct + */ +struct sir_peer_info_ext_req { + struct qdf_mac_addr peer_macaddr; + uint8_t sessionid; + uint8_t reset_after_request; +}; + +/** + * struct sir_peer_info_ext - peer info information struct + * (refer to station_info struct in Kernel) + * @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 + * @rx_retries: cumulative retry counts + * @tx_failed: number of failed transmissions + * @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) + * + * a station's information + */ +struct sir_peer_info_ext { + 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; + int32_t rssi; + uint32_t tx_rate; + uint32_t tx_rate_code; + uint32_t rx_rate; + uint32_t rx_rate_code; +}; + +/** + * struct sir_peer_info_ext_resp - all peers' information struct + * @count: peer's number + * @info: peer information + * + * all station's information + */ +struct sir_peer_info_ext_resp { + uint8_t count; + struct sir_peer_info_ext info[0]; +}; + +/** + * @sta_num: number of peer station which has valid info + * @info: peer information + * + * all SAP peer station's information retrieved + */ +struct sir_peer_sta_info { + uint8_t sta_num; + struct sir_peer_info info[MAX_PEER_STA]; +}; + +/** + * @sta_num: number of peer station which has valid info + * @info: peer extended information + * + * all SAP peer station's extended information retrieved + */ +struct sir_peer_sta_ext_info { + uint8_t sta_num; + struct sir_peer_info_ext info[MAX_PEER_STA]; +}; + +/** + * 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; + /* Bitmap of pattern IDs that need to be deleted */ + uint32_t ucPatternIdBitmap; + uint8_t ucPtrnId; /* Pattern ID */ +} tSirDelPeriodicTxPtrn, *tpSirDelPeriodicTxPtrn; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoReqParams +*--------------------------------------------------------------------------*/ +typedef struct { + bool allPeerInfoReqd; /* If set, all IBSS peers stats are reported */ + uint8_t staIdx; /* If allPeerInfoReqd is not set, only stats */ + /* of peer with staIdx is reported */ +} tSirIbssGetPeerInfoReqParams, *tpSirIbssGetPeerInfoReqParams; + +/** + * typedef struct - tSirIbssGetPeerInfoParams + * @mac_addr: mac address received from target + * @txRate: TX rate + * @mcsIndex: MCS index + * @txRateFlags: TX rate flags + * @rssi: RSSI + */ +typedef struct { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t txRate; + uint32_t mcsIndex; + uint32_t txRateFlags; + int8_t rssi; +} tSirIbssPeerInfoParams; + +typedef struct { + uint32_t status; + uint8_t numPeers; + tSirIbssPeerInfoParams peerInfoParams[32]; +} tSirPeerInfoRspParams, *tpSirIbssPeerInfoRspParams; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoRspParams +*--------------------------------------------------------------------------*/ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + tSirPeerInfoRspParams ibssPeerInfoRspParams; +} tSirIbssGetPeerInfoRspParams, *tpSirIbssGetPeerInfoRspParams; + +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + bool suspended; +} tSirReadyToSuspendInd, *tpSirReadyToSuspendInd; +#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 RA, positive value implies fixed rate, -1 implies ignore + * this param. + */ + int32_t ucastDataRate; + + /* TX flag to differentiate between HT20, HT40 etc */ + enum tx_rate_info ucastDataRateTxFlag; + + /* + * 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; + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +#define SIR_CH_AVOID_MAX_RANGE 4 + +typedef struct sSirChAvoidFreqType { + uint32_t start_freq; + uint32_t end_freq; +} tSirChAvoidFreqType; + +typedef struct sSirChAvoidIndType { + uint32_t avoid_range_count; + tSirChAvoidFreqType avoid_freq_range[SIR_CH_AVOID_MAX_RANGE]; +} tSirChAvoidIndType; +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +#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 sSirSmeDfsEventInd { + uint32_t sessionId; + tSirSmeDfsChannelList chan_list; + uint32_t dfs_radar_status; + int use_nol; +} tSirSmeDfsEventInd, *tpSirSmeDfsEventInd; + +typedef struct sSirChanChangeRequest { + uint16_t messageType; + uint16_t messageLen; + uint8_t targetChannel; + uint8_t sec_ch_offset; + enum phy_ch_width ch_width; + uint8_t center_freq_seg_0; + uint8_t center_freq_seg_1; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint32_t dot11mode; + tSirNwType nw_type; + tSirMacRateSet operational_rateset; + tSirMacRateSet extended_rateset; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; +} tSirChanChangeRequest, *tpSirChanChangeRequest; + +typedef struct sSirChanChangeResponse { + uint8_t sessionId; + uint8_t newChannelNumber; + 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 smeSessionId; + 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 smeSessionId; + 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; + uint8_t targetChannel; + 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; +} 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 bssIdx; +} 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_MAX_THERMAL_LEVELS +} t_thermal_level; + +#define WLAN_THROTTLE_DUTY_CYCLE_LEVEL_MAX (4) + +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]; +} t_thermal_mgmt, *tp_thermal_mgmt; + +typedef struct sSirTxPowerLimit { + /* Thermal limits for 2g and 5g */ + uint32_t txPower2g; + uint32_t txPower5g; +} tSirTxPowerLimit; + +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 + +typedef struct { + uint32_t event_data_len; + uint8_t event_data[]; +} tSirNanEvent, *tpSirNanEvent; + +typedef struct sSirSmeRoamOffloadSynchInd { + uint16_t messageType; /*eWNI_SME_ROAM_OFFLOAD_SYNCH_IND */ + uint16_t length; + uint16_t beaconProbeRespOffset; + uint16_t beaconProbeRespLength; + uint16_t reassocRespOffset; + uint16_t reassocRespLength; + uint16_t reassoc_req_offset; + uint16_t reassoc_req_length; + uint8_t isBeacon; + uint8_t roamedVdevId; + struct qdf_mac_addr bssid; + struct qdf_mac_addr self_mac; + int8_t txMgmtPower; + uint32_t authStatus; + uint8_t rssi; + uint8_t roamReason; + uint32_t chan_freq; + uint8_t kck[SIR_KCK_KEY_LEN]; + uint32_t kek_len; + uint8_t kek[SIR_KEK_KEY_LEN_FILS]; + uint32_t pmk_len; + uint8_t pmk[SIR_PMK_LEN]; + uint8_t pmkid[SIR_PMKID_LEN]; + bool update_erp_next_seq_num; + uint16_t next_erp_seq_num; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + void *add_bss_params; + tpSirSmeJoinRsp join_rsp; + uint16_t aid; + struct sir_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]; +} roam_offload_synch_ind; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef struct sSirSmeRoamOffloadSynchCnf { + uint8_t sessionId; +} tSirSmeRoamOffloadSynchCnf, *tpSirSmeRoamOffloadSynchCnf; + +typedef struct sSirSmeHOFailureInd { + uint8_t sessionId; +} tSirSmeHOFailureInd, *tpSirSmeHOFailureInd; + +struct roam_offload_synch_fail { + uint8_t session_id; +}; + +#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; +}; + +#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; + +/** + * 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; + +/** + * 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, +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirGetExtScanCapabilitiesReqParams, *tpSirGetExtScanCapabilitiesReqParams; + +/** + * 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_white_listed_ssid: max number of white listed SSIDs + * @max_number_of_black_listed_bssid: max number of black 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_white_listed_ssid; + uint32_t max_number_of_black_listed_bssid; +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; + + /* + * 1 - return cached results and flush it + * 0 - return cached results and do not flush + */ + bool flush; +} tSirExtScanGetCachedResultsReqParams, *tpSirExtScanGetCachedResultsReqParams; + +typedef struct { + uint32_t requestId; + uint32_t status; +} tSirExtScanGetCachedResultsRspParams, *tpSirExtScanGetCachedResultsRspParams; + +typedef struct { + /* Time of discovery */ + uint64_t ts; + + /* Null terminated SSID */ + uint8_t ssid[SIR_MAC_MAX_SSID_LENGTH + 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 tSirWifiScanResultEvent - wifi scan result event + * @requestId: request identifier + * @ap_found: flag to indicate ap found or not + * true: AP was found + * false: AP was lost + * @numOfAps: number of aps + * @moreData: more data + * @ap: bssid information + * + */ +typedef struct { + uint32_t requestId; + bool ap_found; + uint32_t numOfAps; + bool moreData; + tSirWifiScanResult ap[]; +} tSirWifiScanResultEvent, *tpSirWifiScanResultEvent; + +/** + * 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 reportEvents + * enabled in tSirWifiScanCmdReqParams + */ +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[]; +}; + +typedef struct { + /* Frequency in MHz */ + uint32_t channel; + + uint32_t dwellTimeMs; + + /* 0 => active + 1 => passive scan; ignored for DFS */ + bool passive; + + uint8_t chnlClass; +} tSirWifiScanChannelSpec, *tpSirWifiScanChannelSpec; + +/** + * struct tSirWifiScanBucketSpec - wifi scan bucket spec + * @bucket: bucket identifier + * @band: wifi band + * @period: Desired period, in millisecond; if this is too + * low, the firmware should choose to generate results as fast as + * it can instead of failing the command byte + * for exponential backoff bucket this is the min_period + * @reportEvents: 0 => normal reporting (reporting rssi history + * only, when rssi history buffer is % full) + * 1 => same as 0 + report a scan completion event after scanning + * this bucket + * 2 => same as 1 + forward scan results + * (beacons/probe responses + IEs) in real time to HAL + * @max_period: if max_period is non zero or different than period, + * then this bucket is an exponential backoff bucket and + * the scan period will grow exponentially as per formula: + * actual_period(N) = period ^ (N/(step_count+1)) to a + * maximum period of max_period + * @exponent: for exponential back off bucket: multiplier: + * new_period = old_period * exponent + * @step_count: for exponential back off bucket, number of scans performed + * at a given period and until the exponent is applied + * @numChannels: channels to scan; these may include DFS channels + * Note that a given channel may appear in multiple buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @channels: Channel list + */ +typedef struct { + uint8_t bucket; + tWifiBand band; + uint32_t period; + uint32_t reportEvents; + uint32_t max_period; + uint32_t exponent; + uint32_t step_count; + uint32_t numChannels; + + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + tSirWifiScanChannelSpec channels[WLAN_EXTSCAN_MAX_CHANNELS]; +} tSirWifiScanBucketSpec, *tpSirWifiScanBucketSpec; + +/** + * struct tSirWifiScanCmdReqParams - wifi scan command request params + * @basePeriod: base timer period + * @maxAPperScan: max ap per scan + * @report_threshold_percent: report threshold + * in %, when buffer is this much full, wake up host + * @report_threshold_num_scans: report threshold number of scans + * in number of scans, wake up host after these many scans + * @requestId: request id + * @sessionId: session id + * @numBuckets: number of buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @configuration_flags: configuration flags + * @buckets: buckets array + */ +typedef struct { + uint32_t basePeriod; + uint32_t maxAPperScan; + + uint32_t report_threshold_percent; + uint32_t report_threshold_num_scans; + + uint32_t requestId; + uint8_t sessionId; + uint32_t numBuckets; + + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + uint32_t configuration_flags; + enum scan_dwelltime_adaptive_mode extscan_adaptive_dwell_mode; + tSirWifiScanBucketSpec buckets[WLAN_EXTSCAN_MAX_BUCKETS]; +} tSirWifiScanCmdReqParams, *tpSirWifiScanCmdReqParams; + +/** + * 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 { + uint32_t requestId; + uint8_t sessionId; +} tSirExtScanStopReqParams, *tpSirExtScanStopReqParams; + +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 + +/** + * struct wifi_epno_network - enhanced pno network block + * @ssid: ssid + * @flags: WIFI_PNO_FLAG_XXX + * @auth_bit_field: auth bit field for matching WPA IE + */ +struct wifi_epno_network { + tSirMacSSid ssid; + uint8_t flags; + uint8_t auth_bit_field; +}; + +/** + * struct wifi_epno_params - enhanced pno network params + * @request_id: request id number + * @session_id: session_id number + * @min_5ghz_rssi: minimum 5GHz RSSI for a BSSID to be considered + * @min_24ghz_rssi: minimum 2.4GHz RSSI for a BSSID to be considered + * @initial_score_max: maximum score that a network can have before bonuses + * @current_connection_bonus: only report when there is a network's score this + * much higher than the current connection + * @same_network_bonus: score bonus for all n/w with the same network flag + * @secure_bonus: score bonus for networks that are not open + * @band_5ghz_bonus: 5GHz RSSI score bonus (applied to all 5GHz networks) + * @num_networks: number of ssids + * @networks: EPNO networks + */ +struct wifi_epno_params { + uint32_t request_id; + uint32_t session_id; + uint32_t min_5ghz_rssi; + uint32_t min_24ghz_rssi; + uint32_t initial_score_max; + uint32_t current_connection_bonus; + uint32_t same_network_bonus; + uint32_t secure_bonus; + uint32_t band_5ghz_bonus; + uint32_t num_networks; + struct wifi_epno_network networks[]; +}; + +#define SIR_PASSPOINT_LIST_MAX_NETWORKS 8 +#define SIR_PASSPOINT_REALM_LEN 256 +#define SIR_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM 16 +#define SIR_PASSPOINT_PLMN_LEN 3 +/** + * struct wifi_passpoint_network - passpoint network block + * @id: identifier of this network block + * @realm: null terminated UTF8 encoded realm, 0 if unspecified + * @roaming_consortium_ids: roaming consortium ids to match, 0s if unspecified + * @plmn: mcc/mnc combination as per rules, 0s if unspecified + */ +struct wifi_passpoint_network { + uint32_t id; + uint8_t realm[SIR_PASSPOINT_REALM_LEN]; + int64_t roaming_consortium_ids[SIR_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM]; + uint8_t plmn[SIR_PASSPOINT_PLMN_LEN]; +}; + +/** + * struct wifi_passpoint_req - passpoint request + * @request_id: request identifier + * @num_networks: number of networks + * @networks: passpoint networks + */ +struct wifi_passpoint_req { + uint32_t request_id; + uint32_t session_id; + uint32_t num_networks; + struct wifi_passpoint_network networks[]; +}; + +/** + * 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 +typedef struct { + uint32_t timer_val; +} tSirAutoShutdownCmdParams; + +typedef struct { + uint32_t shutdown_reason; +} tSirAutoShutdownEvtParams; +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +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; +} tSirLLStatsGetReq, *tpSirLLStatsGetReq; + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t statsClearReqMask; + uint8_t stopReq; +} tSirLLStatsClearReq, *tpSirLLStatsClearReq; + +#ifdef WLAN_POWER_DEBUGFS +/** + * 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; +}; + +typedef struct { + uint8_t oui[WIFI_SCANNING_MAC_OUI_LENGTH]; + uint32_t vdev_id; + bool enb_probe_req_sno_randomization; + struct probe_req_whitelist_attr ie_whitelist; +} tSirScanMacOui, *tpSirScanMacOui; + +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; +}; + +/** + * 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; +}; + +/*--------------------------------------------------------------------------- + WLAN_HAL_LL_NOTIFY_STATS + ---------------------------------------------------------------------------*/ + +/******************************LINK LAYER Statistics**********************/ + +typedef int tSirWifiRadio; +typedef int tSirWifiChannel; +typedef int tSirwifiTxRate; + +/* channel operating width */ +typedef enum { + WIFI_CHAN_WIDTH_20 = 0, + WIFI_CHAN_WIDTH_40 = 1, + WIFI_CHAN_WIDTH_80 = 2, + WIFI_CHAN_WIDTH_160 = 3, + WIFI_CHAN_WIDTH_80P80 = 4, + WIFI_CHAN_WIDTH_5 = 5, + WIFI_CHAN_WIDTH_10 = 6, +} tSirWifiChannelWidth; + +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 + +typedef struct { + /* 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[WNI_CFG_COUNTRY_CODE_LEN]; + /* country string for this association */ + uint8_t countryStr[WNI_CFG_COUNTRY_CODE_LEN]; +} tSirWifiInterfaceInfo, *tpSirWifiInterfaceInfo; + +/* channel information */ +typedef struct { + /* channel width (20, 40, 80, 80+80, 160) */ + tSirWifiChannelWidth width; + /* primary 20 MHz channel */ + tSirWifiChannel centerFreq; + /* center frequency (MHz) first segment */ + tSirWifiChannel centerFreq0; + /* center frequency (MHz) second segment */ + tSirWifiChannel centerFreq1; +} tSirWifiChannelInfo, *tpSirWifiChannelInfo; + +/* wifi rate info */ +typedef struct { + /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ + uint32_t preamble:3; + /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ + uint32_t nss:2; + /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ + uint32_t bw:3; + /* OFDM/CCK rate code would be as per ieee std in units of 0.5mbps */ + /* HT/VHT it would be mcs index */ + uint32_t rateMcsIdx:8; + /* reserved */ + uint32_t reserved:16; + /* units of 100 Kbps */ + uint32_t bitrate; +} tSirWifiRate, *tpSirWifiRate; + +/* channel statistics */ +typedef struct { + /* channel */ + tSirWifiChannelInfo channel; + /* msecs the radio is awake (32 bits number accruing over time) */ + uint32_t onTime; + /* msecs the CCA register is busy (32 bits number accruing over time) */ + uint32_t ccaBusyTime; +} tSirWifiChannelStats, *tpSirWifiChannelStats; + +#define MAX_TPC_LEVELS 64 +/* radio statistics */ +typedef struct { + /* wifi radio (if multiple radio supported) */ + tSirWifiRadio radio; + /* msecs the radio is awake (32 bits number accruing over time) */ + uint32_t onTime; + /* msecs the radio is transmitting + * (32 bits number accruing over time) + */ + uint32_t txTime; + /* msecs the radio is in active receive + *(32 bits number accruing over time) + */ + uint32_t rxTime; + /* msecs the radio is awake due to all scan + * (32 bits number accruing over time) + */ + uint32_t onTimeScan; + /* msecs the radio is awake due to NAN + * (32 bits number accruing over time) + */ + uint32_t onTimeNbd; + /* msecs the radio is awake due to Gscan + * (32 bits number accruing over time) + */ + uint32_t onTimeGscan; + /* msecs the radio is awake due to roam?scan + * (32 bits number accruing over time) + */ + uint32_t onTimeRoamScan; + /* msecs the radio is awake due to PNO scan + * (32 bits number accruing over time) + */ + uint32_t onTimePnoScan; + /* msecs the radio is awake due to HS2.0 scans and GAS exchange + * (32 bits number accruing over time) + */ + uint32_t onTimeHs20; + + /* tx time (in milliseconds) per TPC level (0.5 dBm) */ + uint32_t total_num_tx_power_levels; + uint32_t *tx_time_per_power_level; + + /* number of channels */ + uint32_t numChannels; + + /* tx time (in milliseconds) per TPC level (0.5 dBm) */ + uint32_t tx_time_per_tpc[MAX_TPC_LEVELS]; + + uint32_t on_time_host_scan; + uint32_t on_time_lpi_scan; + + /* channel statistics tSirWifiChannelStats */ + tSirWifiChannelStats *channels; +} tSirWifiRadioStat, *tpSirWifiRadioStat; + +/* per rate statistics */ +typedef struct { + /* rate information */ + tSirWifiRate rate; + /* number of successfully transmitted data pkts (ACK rcvd) */ + uint32_t txMpdu; + /* number of received data pkts */ + uint32_t rxMpdu; + /* number of data packet losses (no ACK) */ + uint32_t mpduLost; + /* total number of data pkt retries * */ + uint32_t retries; + /* number of short data pkt retries */ + uint32_t retriesShort; + /* number of long data pkt retries */ + uint32_t retriesLong; +} tSirWifiRateStat, *tpSirWifiRateStat; + +/* 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; + +/* per peer statistics */ +typedef struct { + /* peer type (AP, TDLS, GO etc.) */ + enum wmi_peer_type type; + /* mac address */ + struct qdf_mac_addr peerMacAddress; + /* peer WIFI_CAPABILITY_XXX */ + uint32_t capabilities; + union { + /* peer power saving mode */ + uint32_t power_saving; + /* number of rates */ + uint32_t numRate; + }; + /* per rate statistics, number of entries = num_rate */ + tSirWifiRateStat rateStats[0]; +} tSirWifiPeerInfo, *tpSirWifiPeerInfo; + +/* Interface statistics - corresponding to 2nd most + * LSB in wifi statistics bitmap for getting statistics + */ +typedef struct { + /* current state of the interface */ + tSirWifiInterfaceInfo info; + + uint32_t rts_succ_cnt; + uint32_t rts_fail_cnt; + uint32_t ppdu_succ_cnt; + uint32_t ppdu_fail_cnt; + + /* link statistics */ + wmi_iface_link_stats link_stats; + + /* per ac data packet statistics */ + 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]; +} tSirWifiIfaceStat, *tpSirWifiIfaceStat; + +/* Peer statistics - corresponding to 3rd most LSB in + * wifi statistics bitmap for getting statistics + */ +typedef struct { + /* number of peers */ + uint32_t numPeers; + /* per peer statistics */ + tSirWifiPeerInfo peerInfo[0]; +} tSirWifiPeerStat, *tpSirWifiPeerStat; + +/* 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 successed 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; +}; + +#define WIFI_INVALID_PEER_ID (-1) +#define WIFI_INVALID_VDEV_ID (-1) +#define WIFI_MAX_AC (4) + +/** + * 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 statictics 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 mechnism 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 pervious 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 + +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[0]; +} tSirLLStatsResults, *tpSirLLStatsResults; + +/* 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; + +#ifdef DHCP_SERVER_OFFLOAD +typedef struct { + uint32_t vdev_id; + uint32_t dhcpSrvOffloadEnabled; + uint32_t dhcpClientNum; + uint32_t dhcpSrvIP; +} tSirDhcpSrvOffloadInfo, *tpSirDhcpSrvOffloadInfo; +#endif /* DHCP_SERVER_OFFLOAD */ + +/** + * 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 + +/** + * enum fine_time_meas_mask - bit mask to identify device's + * fine timing measurement capability + * @FINE_TIME_MEAS_STA_INITIATOR - STA role, Initiator capability is supported + * @FINE_TIME_MEAS_STA_RESPONDER - STA role, Responder capability is supported + * @FINE_TIME_MEAS_P2PCLI_INITIATOR - P2P-CLI supports initiator capability + * @FINE_TIME_MEAS_P2PCLI_RESPONDER - P2P-CLI supports responder capability + * @FINE_TIME_MEAS_P2PGO_INITIATOR - P2P-GO supports initiator capability + * @FINE_TIME_MEAS_P2PGO_RESPONDER - P2P-GO supports responder capability + * @FINE_TIME_MEAS_SAP_INITIATOR - SAP role, Initiator capability is supported + * @FINE_TIME_MEAS_SAP_RESPONDER - SAP role, Responder capability is supported + */ +enum fine_time_meas_mask { + FINE_TIME_MEAS_STA_INITIATOR = (1 << (0)), + FINE_TIME_MEAS_STA_RESPONDER = (1 << (1)), + FINE_TIME_MEAS_P2PCLI_INITIATOR = (1 << (2)), + FINE_TIME_MEAS_P2PCLI_RESPONDER = (1 << (3)), + FINE_TIME_MEAS_P2PGO_INITIATOR = (1 << (4)), + FINE_TIME_MEAS_P2PGO_RESPONDER = (1 << (5)), + FINE_TIME_MEAS_SAP_INITIATOR = (1 << (6)), + FINE_TIME_MEAS_SAP_RESPONDER = (1 << (7)), +}; + +/* 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_monitor_req - rssi monitoring + * @request_id: request id + * @session_id: session id + * @min_rssi: minimum rssi + * @max_rssi: maximum rssi + * @control: flag to indicate start or stop + */ +struct rssi_monitor_req { + uint32_t request_id; + uint32_t session_id; + int8_t min_rssi; + int8_t max_rssi; + bool control; +}; + +/** + * 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 - Maxmimum 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 + * @session_id: Session 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 session_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 (*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); +typedef void (*antenna_mode_cb)(uint32_t status, void *context); + +/** + * struct sir_nss_update_request + * @msgType: nss update msg type + * @msgLen: length of the msg + * @new_nss: new spatial stream value + * @vdev_id: session id + */ +struct sir_nss_update_request { + uint16_t msgType; + uint16_t msgLen; + uint8_t new_nss; + 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 + */ +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, +}; + +/** + * 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; +}; + +/** + * enum powersave_qpower_mode: QPOWER modes + * @QPOWER_DISABLED: Qpower is disabled + * @QPOWER_ENABLED: Qpower is enabled + * @QPOWER_DUTY_CYCLING: Qpower is enabled with duty cycling + */ +enum powersave_qpower_mode { + QPOWER_DISABLED = 0, + QPOWER_ENABLED = 1, + QPOWER_DUTY_CYCLING = 2 +}; + +/** + * enum powersave_qpower_mode: powersave_mode + * @PS_NOT_SUPPORTED: Power save is not supported + * @PS_LEGACY_NODEEPSLEEP: Legacy power save enabled and deep sleep disabled + * @PS_QPOWER_NODEEPSLEEP: QPOWER enabled and deep sleep disabled + * @PS_LEGACY_DEEPSLEEP: Legacy power save enabled and deep sleep enabled + * @PS_QPOWER_DEEPSLEEP: QPOWER enabled and deep sleep enabled + * @PS_DUTY_CYCLING_QPOWER: QPOWER enabled in duty cycling mode + */ +enum powersave_mode { + PS_NOT_SUPPORTED = 0, + PS_LEGACY_NODEEPSLEEP = 1, + PS_QPOWER_NODEEPSLEEP = 2, + PS_LEGACY_DEEPSLEEP = 3, + PS_QPOWER_DEEPSLEEP = 4, + PS_DUTY_CYCLING_QPOWER = 5 +}; +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * struct gateway_param_update_req - gateway parameter update request + * @request_id: request id + * @session_id: session 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_param_update_req { + uint32_t request_id; + uint32_t session_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]; +}; +#else +struct gateway_param_update_req; +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * struct sir_sme_ext_change_chan_req - channel change request + * @message_type: message id + * @length: msg length + * @new_channel: new channel + * @session_id: session id + */ +struct sir_sme_ext_cng_chan_req { + uint16_t message_type; /* eWNI_SME_EXT_CHANGE_CHANNEL */ + uint16_t length; + uint32_t new_channel; + uint8_t session_id; +}; + +/** + * struct sir_sme_ext_change_chan_ind. + * @session_id: session id + * @new_channel: new channel to change + */ +struct sir_sme_ext_cng_chan_ind { + uint8_t session_id; + uint8_t new_channel; +}; + +/** + * 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 + * + * driver use this struct to store the tsf info + */ +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; +}; + +#define SIR_BCN_FLT_MAX_ELEMS_IE_LIST 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; +}; + +/** + * struct csa_offload_params - CSA offload request parameters + * @channel: channel + * @switch_mode: switch mode + * @sec_chan_offset: second channel offset + * @new_ch_width: new channel width + * @new_ch_freq_seg1: channel center freq 1 + * @new_ch_freq_seg2: channel center freq 2 + * @ies_present_flag: IE present flag + */ +struct csa_offload_params { + uint8_t channel; + uint8_t switch_mode; + uint8_t sec_chan_offset; + uint8_t new_ch_width; + uint8_t new_op_class; + uint8_t new_ch_freq_seg1; + uint8_t new_ch_freq_seg2; + uint32_t ies_present_flag; + tSirMacAddr bssId; +}; + +/** + * 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_id: self sta identification + * @bss_id: BSS index + * @fortymhz_intolerent: Ht40mhz intolerance + * @channel_count: channel count + * @channels: channel information + * @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; + uint8_t channels[SIR_ROAM_MAX_CHANNELS]; + 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 + * @remaining_bytes_for_apf_inst: remaining bytes for apf instructions + * + */ +struct sir_apf_get_offload { + uint32_t apf_version; + uint32_t max_apf_filters; + uint32_t max_bytes_for_apf_inst; + uint32_t remaining_bytes_for_apf_inst; +}; + +#ifndef QCA_SUPPORT_CP_STATS +/** + * struct sir_wake_lock_stats - wake lock stats structure + * @wow_unspecified_wake_up_count: number of non-wow related wake ups + * @wow_ucast_wake_up_count: Unicast wakeup count + * @wow_bcast_wake_up_count: Broadcast wakeup count + * @wow_ipv4_mcast_wake_up_count: ipv4 multicast wakeup count + * @wow_ipv6_mcast_wake_up_count: ipv6 multicast wakeup count + * @wow_ipv6_mcast_ra_stats: ipv6 multicast ra stats + * @wow_ipv6_mcast_ns_stats: ipv6 multicast ns stats + * @wow_ipv6_mcast_na_stats: ipv6 multicast na stats + * @wow_icmpv4_count: ipv4 icmp packet count + * @wow_icmpv6_count: ipv6 icmp packet count + * @wow_rssi_breach_wake_up_count: rssi breach wakeup count + * @wow_low_rssi_wake_up_count: low rssi wakeup count + * @wow_gscan_wake_up_count: gscan wakeup count + * @wow_pno_complete_wake_up_count: pno complete wakeup count + * @wow_pno_match_wake_up_count: pno match wakeup count + * @wow_oem_response_wake_up_count: oem response wakeup count + * @pwr_save_fail_detected: pwr save fail detected wakeup count + */ +struct sir_wake_lock_stats { + uint32_t wow_unspecified_wake_up_count; + uint32_t wow_ucast_wake_up_count; + uint32_t wow_bcast_wake_up_count; + uint32_t wow_ipv4_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_ra_stats; + uint32_t wow_ipv6_mcast_ns_stats; + uint32_t wow_ipv6_mcast_na_stats; + uint32_t wow_icmpv4_count; + uint32_t wow_icmpv6_count; + uint32_t wow_rssi_breach_wake_up_count; + uint32_t wow_low_rssi_wake_up_count; + uint32_t wow_gscan_wake_up_count; + uint32_t wow_pno_complete_wake_up_count; + uint32_t wow_pno_match_wake_up_count; + uint32_t wow_oem_response_wake_up_count; + uint32_t pwr_save_fail_detected; +}; + +/** + * struct sir_vdev_wow_stats - container for per vdev wow related stat counters + * @ucast: Unicast wakeup count + * @bcast: Broadcast wakeup count + * @ipv4_mcast: ipv4 multicast wakeup count + * @ipv6_mcast: ipv6 multicast wakeup count + * @ipv6_mcast_ra: ipv6 multicast ra stats + * @ipv6_mcast_ns: ipv6 multicast ns stats + * @ipv6_mcast_na: ipv6 multicast na stats + * @icmpv4: ipv4 icmp packet count + * @icmpv6: ipv6 icmp packet count + * @rssi_breach: rssi breach wakeup count + * @low_rssi: low rssi wakeup count + * @gscan: gscan wakeup count + * @pno_complete: pno complete wakeup count + * @pno_match: pno match wakeup count + * @oem_response: oem response wakeup coun + * @scan_11d: 11d scan wakeup count + */ +struct sir_vdev_wow_stats { + uint32_t ucast; + uint32_t bcast; + uint32_t ipv4_mcast; + uint32_t ipv6_mcast; + uint32_t ipv6_mcast_ra; + uint32_t ipv6_mcast_ns; + uint32_t ipv6_mcast_na; + uint32_t icmpv4; + uint32_t icmpv6; + uint32_t rssi_breach; + uint32_t low_rssi; + uint32_t gscan; + uint32_t pno_complete; + uint32_t pno_match; + uint32_t oem_response; + uint32_t pwr_save_fail_detected; + uint32_t scan_11d; +}; +#endif + +/** + * enum ht_capability_fields - HT Capabilities bit fields + * @HT_CAPS_LDPC: ldpc coding capability bit field + * @HT_CAPS_SUPPORTED_CHANNEL_SET: channel width set bit field + * @HT_CAPS_SM_PWR_SAVE: SM power save bit field + * @HT_CAPS_GREENFIELD: greenfield capability bit field + * @HT_CAPS_SHORT_GI20: short GI 20 bit field + * @HT_CAPS_SHORT_GI40: short GI 40 bit field + * @HT_CAPS_TX_STBC: Tx STBC bit field + * @HT_CAPS_RX_STBC: Rx STBC bit fields + */ +enum ht_capability_fields { + HT_CAPS_LDPC = 0x0001, + HT_CAPS_SUPPORTED_CHANNEL_SET = 0x0002, + HT_CAPS_SM_PWR_SAVE = 0x000c, + HT_CAPS_GREENFIELD = 0x0010, + HT_CAPS_SHORT_GI20 = 0x0020, + HT_CAPS_SHORT_GI40 = 0x0040, + HT_CAPS_TX_STBC = 0x0080, + HT_CAPS_RX_STBC = 0x0300 +}; + +#ifdef WLAN_FEATURE_NAN_DATAPATH + +#define IFACE_NAME_SIZE 64 + +/** + * enum ndp_accept_policy - nan data path accept policy + * @NDP_ACCEPT_POLICY_NONE: the framework will decide the policy + * @NDP_ACCEPT_POLICY_ALL: accept policy offloaded to fw + * + */ +enum ndp_accept_policy { + NDP_ACCEPT_POLICY_NONE = 0, + NDP_ACCEPT_POLICY_ALL = 1, +}; + +/** + * enum ndp_self_role - nan data path role + * @NDP_ROLE_INITIATOR: initiator of nan data path request + * @NDP_ROLE_RESPONDER: responder to nan data path request + * + */ +enum ndp_self_role { + NDP_ROLE_INITIATOR = 0, + NDP_ROLE_RESPONDER = 1, +}; + +/** + * enum ndp_response_code - responder's response code to nan data path request + * @NDP_RESPONSE_ACCEPT: ndp request accepted + * @NDP_RESPONSE_REJECT: ndp request rejected + * @NDP_RESPONSE_DEFER: ndp request deferred until later (response to follow + * any time later) + * + */ +enum ndp_response_code { + NDP_RESPONSE_ACCEPT = 0, + NDP_RESPONSE_REJECT = 1, + NDP_RESPONSE_DEFER = 2, +}; + +/** + * 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 ndp_cfg - ndp configuration + * @tag: unique identifier + * @ndp_cfg_len: ndp configuration length + * @ndp_cfg: variable length ndp configuration + * + */ +struct ndp_cfg { + uint32_t tag; + uint32_t ndp_cfg_len; + uint8_t *ndp_cfg; +}; + +/** + * struct ndp_qos_cfg - ndp qos configuration + * @tag: unique identifier + * @ndp_qos_cfg_len: ndp qos configuration length + * @ndp_qos_cfg: variable length ndp qos configuration + * + */ +struct ndp_qos_cfg { + uint32_t tag; + uint32_t ndp_qos_cfg_len; + uint8_t ndp_qos_cfg[]; +}; + +/** + * struct ndp_app_info - application info shared during ndp setup + * @tag: unique identifier + * @ndp_app_info_len: ndp app info length + * @ndp_app_info: variable length application information + * + */ +struct ndp_app_info { + uint32_t tag; + uint32_t ndp_app_info_len; + uint8_t *ndp_app_info; +}; + +/** + * struct ndp_scid - structure to hold sceurity context identifier + * @scid_len: length of scid + * @scid: scid + * + */ +struct ndp_scid { + uint32_t scid_len; + uint8_t *scid; +}; + +/** + * struct ndp_pmk - structure to hold pairwise master key + * @pmk_len: length of pairwise master key + * @pmk: buffer containing pairwise master key + * + */ +struct ndp_pmk { + uint32_t pmk_len; + uint8_t *pmk; +}; + +/** + * struct ndi_create_req - ndi create request params + * @transaction_id: unique identifier + * @iface_name: interface name + * + */ +struct ndi_create_req { + uint32_t transaction_id; + char iface_name[IFACE_NAME_SIZE]; +}; + +/** + * 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 ndp_initiator_req - ndp initiator request params + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @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 + * + */ +struct ndp_initiator_req { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t channel; + uint32_t channel_cfg; + uint32_t service_instance_id; + struct qdf_mac_addr peer_discovery_mac_addr; + struct qdf_mac_addr self_ndi_mac_addr; + struct ndp_cfg ndp_config; + struct ndp_app_info ndp_info; + uint32_t ncs_sk_type; + struct ndp_pmk pmk; +}; + +/** + * struct ndp_initiator_rsp - response event from FW + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @ndp_instance_id: locally created NDP instance ID + * @status: status of the ndp request + * @reason: reason for failure if any + * + */ +struct ndp_initiator_rsp { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t ndp_instance_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct ndp_indication_event - create ndp indication on the responder + * @vdev_id: session id of the interface over which ndp is being created + * @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 + * @ndp_accept_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 + * + */ +struct ndp_indication_event { + uint32_t vdev_id; + 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 ndp_self_role role; + enum ndp_accept_policy policy; + struct ndp_cfg ndp_config; + struct ndp_app_info ndp_info; + uint32_t ncs_sk_type; + struct ndp_scid scid; +}; + +/** + * struct ndp_responder_req - responder's response to ndp create request + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @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 + * + */ +struct ndp_responder_req { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t ndp_instance_id; + enum ndp_response_code ndp_rsp; + struct ndp_cfg ndp_config; + struct ndp_app_info ndp_info; + struct ndp_pmk pmk; + uint32_t ncs_sk_type; +}; + +/** + * struct ndp_responder_rsp_event - response to responder's request + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @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 ndp_responder_rsp_event { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t status; + uint32_t reason; + struct qdf_mac_addr peer_mac_addr; + bool create_peer; +}; + +/** + * struct ndp_confirm_event - ndp confirmation event from FW + * @vdev_id: session id of the interface over which ndp is being created + * @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 + * @ndp_info: ndp application info + * + */ +struct ndp_confirm_event { + uint32_t vdev_id; + 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 ndp_response_code rsp_code; + struct ndp_app_info ndp_info; +}; + +/** + * struct ndp_end_req - ndp end request + * @transaction_id: unique transaction identifier + * @num_ndp_instances: number of ndp instances to be terminated + * @ndp_ids: pointer to array of ndp_instance_id to be terminated + * + */ +struct ndp_end_req { + uint32_t transaction_id; + uint32_t num_ndp_instances; + uint32_t *ndp_ids; +}; + +/** + * 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; +}; + +/** + * struct ndp_end_rsp_event - firmware response to ndp end request + * @transaction_id: unique identifier for the request + * @status: status of operation + * @reason: reason(opaque to host driver) + * + */ +struct ndp_end_rsp_event { + uint32_t transaction_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct ndp_end_indication_event - ndp termination notification from FW + * @num_ndp_ids: number of NDP ids + * @ndp_map: mapping of NDP instances to peer and vdev + * + */ +struct ndp_end_indication_event { + uint32_t num_ndp_ids; + struct peer_ndp_map ndp_map[]; +}; + +/** + * struct ndp_schedule_update_req - ndp schedule update request + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @ndp_instance_id: ndp instance id for which schedule update is requested + * @ndp_qos: new set of qos parameters + * + */ +struct ndp_schedule_update_req { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t ndp_instance_id; + struct ndp_qos_cfg ndp_qos; +}; + +/** + * struct ndp_schedule_update_rsp - ndp schedule update response + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @status: status of the request + * @reason: reason code for failure if any + * + */ +struct ndp_schedule_update_rsp { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct sme_ndp_peer_ind - ndp peer indication + * @msg_type: message id + * @msg_len: message length + * @session_id: session id + * @peer_mac_addr: peer mac address + * @sta_id: station id + * + */ +struct sme_ndp_peer_ind { + uint16_t msg_type; + uint16_t msg_len; + uint8_t session_id; + struct qdf_mac_addr peer_mac_addr; + uint16_t sta_id; +}; + +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +/** + * struct sir_set_tx_rx_aggregation_size - sets tx rx aggregation size + * @vdev_id: vdev id of the session + * @aggr_type: TX Aggregation Type (0=A-MPDU, 1=A-MSDU) + * @tx_aggregation_size: Tx aggregation size + * @tx_aggregation_size_be: Tx aggregation size for be queue + * @tx_aggregation_size_bk: Tx aggregation size for bk queue + * @tx_aggregation_size_vi: Tx aggregation size for vi queue + * @tx_aggregation_size_vo: Tx aggregation size for vo queue + * @rx_aggregation_size: Rx aggregation size + */ +struct sir_set_tx_rx_aggregation_size { + uint8_t vdev_id; + wmi_vdev_custom_aggr_type_t aggr_type; + 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; +}; + +/** + * struct sir_set_tx_sw_retry_threshold - set sw retry threshold + * @vdev_id: vdev id of the session + * @tx_aggr_sw_retry_threshold_be: sw retry threshold for BE + * @tx_aggr_sw_retry_threshold_bk: sw retry threshold for BK + * @tx_aggr_sw_retry_threshold_vi: sw retry threshold for VI + * @tx_aggr_sw_retry_threshold_vo: sw retry threshold for VO + * @tx_aggr_sw_retry_threshold: 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 + */ +struct sir_set_tx_sw_retry_threshold { + uint8_t vdev_id; + 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; +}; + +/** + * 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 + * @session_id: session id + * @trans_id: transaction 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 session_id; + uint16_t trans_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 + * @sme_session_id: sme session 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 sme_session_id; + uint8_t ie[SIR_MAC_MAX_IE_LENGTH]; + uint8_t access_policy; +}; + +/** + * struct sir_encrypt_decrypt_rsp_params - encrypt/decrypt rsp params + * @vdev_id: vdev id + * @status: status + * @data_length: data length + * @data: data pointer + */ +struct sir_encrypt_decrypt_rsp_params { + uint32_t vdev_id; + int32_t status; + uint32_t data_length; + uint8_t *data; +}; + +/** + * 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: tranmission retry limit for short frame. + * + */ +struct sme_short_retry_limit { + uint8_t session_id; + uint32_t short_retry_limit; +}; + +/** + * struct sme_long_retry_limit - tranmission retry limit for long frames + * @session_id: Session id + * @short_retry_limit: tranmission 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 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 + * + * 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; +}; + + +/** + * 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 + */ +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; +}; + +/** + * 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 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) + +#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)) + +/* + * 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 + +/* + * 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) + +/** + * struct sir_del_all_tdls_peers - delete all tdls peers + * @msg_type: type of message + * @msg_len: length of message + * @bssid: bssid of peer device + */ +struct sir_del_all_tdls_peers { + uint16_t msg_type; + uint16_t msg_len; + struct qdf_mac_addr bssid; +}; + +/** + * 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. + */ +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, +}; + +/** + * 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 initate + * @time_during_rejection: Timestamp during last rejection in millisec + */ +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; +}; + +/** + * 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 + */ +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; +}; + +/** + * struct sir_sae_msg - SAE msg used for message posting + * @message_type: message type + * @length: message length + * @session_id: SME session id + * @sae_status: SAE status, 0: Success, Non-zero: Failure. + */ +struct sir_sae_msg { + uint16_t message_type; + uint16_t length; + uint16_t session_id; + uint8_t sae_status; +}; + +/** + * struct set_pcl_req - Request message to set the PCL + * @chan_weights: PCL channel weights + * @band: Supported band + */ +struct set_pcl_req { + struct wmi_pcl_chan_weights chan_weights; + enum band_info band; +}; + +#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 */ +#endif /* __SIR_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h new file mode 100644 index 0000000000000000000000000000000000000000..4e0a3740b0bb327e4dc3040523edf89c3f72ec3f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011-2015, 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. + */ + +/* + * + * 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 == WNI_CFG_DOT11_MODE_11N) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11N_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AX) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AX_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_VHT(dot11Mode) \ + (((dot11Mode == WNI_CFG_DOT11_MODE_11AC) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AX) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AX_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_HE(dot11Mode) \ + (((dot11Mode == WNI_CFG_DOT11_MODE_11AX) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AX_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_11B(dot11Mode) \ + ((dot11Mode == WNI_CFG_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 + +/* / Proprietary IE definition */ +typedef struct sSirMacPropIE { + uint8_t elementID; /* SIR_MAC_ANI_PROP_IE_EID */ + uint8_t length; + uint8_t oui[3]; /* ANI_OUI for Airgo products */ + uint8_t info[1]; +} tSirMacPropIE, *tpSirMacPropIE; + +typedef struct sSirMacPropRateSet { + uint8_t numPropRates; + uint8_t propRate[8]; +} tSirMacPropRateSet, *tpSirMacPropRateSet; + +#define SIR_PROP_VERSION_STR_MAX 20 +typedef struct sSirMacPropVersion { + uint32_t chip_rev; /* board, chipset info */ + uint8_t card_type; /* Type of Card */ + /* build version string */ + uint8_t build_version[SIR_PROP_VERSION_STR_MAX]; +} tSirMacPropVersion, *tpSirMacPropVersion; + +/* generic proprietary IE structure definition */ +typedef struct sSirPropIEStruct { + uint8_t propRatesPresent:1; + uint8_t apNamePresent:1; + uint8_t loadBalanceInfoPresent:1; + uint8_t versionPresent:1; + uint8_t edcaParamPresent:1; + uint8_t capabilityPresent:1; + uint8_t propChannelSwitchPresent:1; + uint8_t triggerStaScanPresent:1; + uint8_t rsvd:8; + + tSirMacPropRateSet propRates; + tAniApName apName; /* used in beacon/probe only */ + uint16_t capability; /* capability bit map */ + tSirMacPropVersion version; + tSirMacEdcaParamSetIE edca; + uint8_t triggerStaScanEnable; + +} tSirPropIEStruct, *tpSirPropIEStruct; + +#endif /* __MAC_PROP_EXTS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h new file mode 100644 index 0000000000000000000000000000000000000000..4fd931b61cd4f61263c92ff2e512d76a1ae12c21 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h @@ -0,0 +1,2540 @@ +/* + * 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. + */ + +/* + * 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 + +#define SIR_MAC_FRAME_TYPE_START 0x0 +#define SIR_MAC_FRAME_TYPE_END 0x3 + +/* Control frame subtype definitions */ + +#define SIR_MAC_CTRL_RR 4 +#define SIR_MAC_CTRL_BAR 8 +#define SIR_MAC_CTRL_BA 9 +#define SIR_MAC_CTRL_PS_POLL 10 +#define SIR_MAC_CTRL_RTS 11 +#define SIR_MAC_CTRL_CTS 12 +#define SIR_MAC_CTRL_ACK 13 +#define SIR_MAC_CTRL_CF_END 14 +#define SIR_MAC_CTRL_CF_END_ACK 15 + +#define SIR_MAC_MAX_DURATION_MICRO_SECONDS 32767 + +/* 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_FRAME_SUBTYPE_START 0 +#define SIR_MAC_FRAME_SUBTYPE_END 16 + +#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 + +/* Action frame categories */ + +#define SIR_MAC_ACTION_SPECTRUM_MGMT 0 +#define SIR_MAC_ACTION_QOS_MGMT 1 +#define SIR_MAC_ACTION_DLP 2 +#define SIR_MAC_ACTION_BLKACK 3 +#define SIR_MAC_ACTION_PUBLIC_USAGE 4 +#define SIR_MAC_ACTION_RRM 5 +#define SIR_MAC_ACTION_FAST_BSS_TRNST 6 +#define SIR_MAC_ACTION_HT 7 +#define SIR_MAC_ACTION_SA_QUERY 8 +#define SIR_MAC_ACTION_PROT_DUAL_PUB 9 +#define SIR_MAC_ACTION_WNM 10 +#define SIR_MAC_ACTION_UNPROT_WNM 11 +#define SIR_MAC_ACTION_TDLS 12 +#define SIR_MAC_ACITON_MESH 13 +#define SIR_MAC_ACTION_MHF 14 +#define SIR_MAC_SELF_PROTECTED 15 +#define SIR_MAC_ACTION_WME 17 +#define SIR_MAC_ACTION_FST 18 +#define SIR_MAC_ACTION_VHT 21 +#define SIR_MAC_ACTION_MAX 256 + +#define SIR_MAC_ACTION_TX 1 +#define SIR_MAC_ACTION_RX 2 + +/* QoS management action codes */ + +#define SIR_MAC_QOS_ADD_TS_REQ 0 +#define SIR_MAC_QOS_ADD_TS_RSP 1 +#define SIR_MAC_QOS_DEL_TS_REQ 2 +#define SIR_MAC_QOS_SCHEDULE 3 +#define SIR_MAC_QOS_MAP_CONFIGURE 4 +/* and these are proprietary */ +#define SIR_MAC_QOS_DEF_BA_REQ 4 +#define SIR_MAC_QOS_DEF_BA_RSP 5 + +#define SIR_MAC_ADDBA_REQ 0 +#define SIR_MAC_ADDBA_RSP 1 +#define SIR_MAC_DELBA_REQ 2 + +#define SIR_MAC_BA_POLICY_DELAYED 0 +#define SIR_MAC_BA_POLICY_IMMEDIATE 1 +#define SIR_MAC_BA_AMSDU_SUPPORTED 1 +#define SIR_MAC_BA_DEFAULT_BUFF_SIZE 64 + +#ifdef ANI_SUPPORT_11H +#define SIR_MAC_ACTION_MEASURE_REQUEST_ID 0 +#define SIR_MAC_ACTION_MEASURE_REPORT_ID 1 +#define SIR_MAC_ACTION_TPC_REQUEST_ID 2 +#define SIR_MAC_ACTION_TPC_REPORT_ID 3 +#endif /* ANI_SUPPORT_11H */ +#define SIR_MAC_ACTION_CHANNEL_SWITCH_ID 4 + +#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 + +/* RRM action codes */ +#define SIR_MAC_RRM_RADIO_MEASURE_REQ 0 +#define SIR_MAC_RRM_RADIO_MEASURE_RPT 1 +#define SIR_MAC_RRM_LINK_MEASUREMENT_REQ 2 +#define SIR_MAC_RRM_LINK_MEASUREMENT_RPT 3 +#define SIR_MAC_RRM_NEIGHBOR_REQ 4 +#define SIR_MAC_RRM_NEIGHBOR_RPT 5 + +/* VHT Action Field */ +#define SIR_MAC_VHT_GID_NOTIFICATION 1 +#define SIR_MAC_VHT_OPMODE_NOTIFICATION 2 + +#define SIR_MAC_VHT_OPMODE_SIZE 3 + +#define NUM_OF_SOUNDING_DIMENSIONS 1 /*Nss - 1, (Nss = 2 for 2x2)*/ +/* HT Action Field Codes */ +#define SIR_MAC_SM_POWER_SAVE 1 + +/* DLP action frame types */ +#define SIR_MAC_DLP_REQ 0 +#define SIR_MAC_DLP_RSP 1 +#define SIR_MAC_DLP_TEARDOWN 2 + +/* block acknowledgment action frame types */ +#define SIR_MAC_ACTION_VENDOR_SPECIFIC 9 +#define SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY 0x7F +#define SIR_MAC_ACTION_P2P_SUBTYPE_PRESENCE_RSP 2 + +/* Public Action for 20/40 BSS Coexistence */ +#define SIR_MAC_ACTION_2040_BSS_COEXISTENCE 0 +#define SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID 4 + +/* Public Action frames for GAS */ +#define SIR_MAC_ACTION_GAS_INITIAL_REQUEST 0x0A +#define SIR_MAC_ACTION_GAS_INITIAL_RESPONSE 0x0B +#define SIR_MAC_ACTION_GAS_COMEBACK_REQUEST 0x0C +#define SIR_MAC_ACTION_GAS_COMEBACK_RESPONSE 0x0D + +#ifdef WLAN_FEATURE_11W +/* 11w SA query request/response action frame category code */ +#define SIR_MAC_SA_QUERY_REQ 0 +#define SIR_MAC_SA_QUERY_RSP 1 +#endif + +#ifdef FEATURE_WLAN_TDLS +#define SIR_MAC_TDLS_SETUP_REQ 0 +#define SIR_MAC_TDLS_SETUP_RSP 1 +#define SIR_MAC_TDLS_SETUP_CNF 2 +#define SIR_MAC_TDLS_TEARDOWN 3 +#define SIR_MAC_TDLS_PEER_TRAFFIC_IND 4 +#define SIR_MAC_TDLS_CH_SWITCH_REQ 5 +#define SIR_MAC_TDLS_CH_SWITCH_RSP 6 +#define SIR_MAC_TDLS_PEER_TRAFFIC_RSP 9 +#define SIR_MAC_TDLS_DIS_REQ 10 +#define SIR_MAC_TDLS_DIS_RSP 14 +#endif + +/* WNM Action field values; IEEE Std 802.11-2012, 8.5.14.1, Table 8-250 */ +#define SIR_MAC_WNM_BSS_TM_QUERY 6 +#define SIR_MAC_WNM_BSS_TM_REQUEST 7 +#define SIR_MAC_WNM_BSS_TM_RESPONSE 8 +#define SIR_MAC_WNM_NOTIF_REQUEST 26 +#define SIR_MAC_WNM_NOTIF_RESPONSE 27 + +/* Protected Dual of Public Action(PDPA) frames Action field */ +#define SIR_MAC_PDPA_GAS_INIT_REQ 10 +#define SIR_MAC_PDPA_GAS_INIT_RSP 11 +#define SIR_MAC_PDPA_GAS_COMEBACK_REQ 12 +#define SIR_MAC_PDPA_GAS_COMEBACK_RSP 13 + +#define SIR_MAC_MAX_RANDOM_LENGTH 2306 + +/* ----------------------------------------------------------------------------- */ +/* EID (Element ID) definitions */ +/* and their min/max lengths */ +/* ----------------------------------------------------------------------------- */ + +#define SIR_MAC_SSID_EID 0 +#define SIR_MAC_SSID_EID_MIN 0 +#define SIR_MAC_SSID_EID_MAX 32 +#define SIR_MAC_RATESET_EID 1 +#define SIR_MAC_RATESET_EID_MIN 1 +#define SIR_MAC_RATESET_EID_MAX 12 +#define SIR_MAC_FH_PARAM_SET_EID 2 +#define SIR_MAC_FH_PARAM_SET_EID_MIN 5 +#define SIR_MAC_FH_PARAM_SET_EID_MAX 5 +#define SIR_MAC_DS_PARAM_SET_EID 3 +#define SIR_MAC_DS_PARAM_SET_EID_MIN 1 +#define SIR_MAC_DS_PARAM_SET_EID_MAX 1 +#define SIR_MAC_CF_PARAM_SET_EID 4 +#define SIR_MAC_CF_PARAM_SET_EID_MIN 6 +#define SIR_MAC_CF_PARAM_SET_EID_MAX 6 +#define SIR_MAC_TIM_EID 5 +#define SIR_MAC_TIM_EID_MIN 3 +#define SIR_MAC_TIM_EID_MAX 254 +#define SIR_MAC_IBSS_PARAM_SET_EID 6 +#define SIR_MAC_IBSS_PARAM_SET_EID_MIN 2 +#define SIR_MAC_IBSS_PARAM_SET_EID_MAX 2 +#define SIR_MAC_COUNTRY_EID 7 +#define SIR_MAC_COUNTRY_EID_MIN 6 +#define SIR_MAC_COUNTRY_EID_MAX 254 +#define SIR_MAC_FH_PARAMS_EID 8 +#define SIR_MAC_FH_PARAMS_EID_MIN 4 +#define SIR_MAC_FH_PARAMS_EID_MAX 4 +#define SIR_MAC_FH_PATTERN_EID 9 +#define SIR_MAC_FH_PATTERN_EID_MIN 4 +#define SIR_MAC_FH_PATTERN_EID_MAX 254 +#define SIR_MAC_REQUEST_EID 10 +#define SIR_MAC_REQUEST_EID_MIN 1 +#define SIR_MAC_REQUEST_EID_MAX 255 +#define SIR_MAC_QBSS_LOAD_EID 11 +#define SIR_MAC_QBSS_LOAD_EID_MIN 5 +#define SIR_MAC_QBSS_LOAD_EID_MAX 5 +#define SIR_MAC_EDCA_PARAM_SET_EID 12 /* EDCA parameter set */ +#define SIR_MAC_EDCA_PARAM_SET_EID_MIN 18 +#define SIR_MAC_EDCA_PARAM_SET_EID_MAX 20 /* TBD temp - change backto 18 */ +#define SIR_MAC_TSPEC_EID 13 +#define SIR_MAC_TSPEC_EID_MIN 55 +#define SIR_MAC_TSPEC_EID_MAX 55 +#define SIR_MAC_TCLAS_EID 14 +#define SIR_MAC_TCLAS_EID_MIN 4 +#define SIR_MAC_TCLAS_EID_MAX 255 +#define SIR_MAC_QOS_SCHEDULE_EID 15 +#define SIR_MAC_QOS_SCHEDULE_EID_MIN 14 +#define SIR_MAC_QOS_SCHEDULE_EID_MAX 14 +#define SIR_MAC_CHALLENGE_TEXT_EID 16 +#define SIR_MAC_CHALLENGE_TEXT_EID_MIN 1 +#define SIR_MAC_CHALLENGE_TEXT_EID_MAX 253 +/* reserved 17-31 */ +#define SIR_MAC_PWR_CONSTRAINT_EID 32 +#define SIR_MAC_PWR_CONSTRAINT_EID_MIN 1 +#define SIR_MAC_PWR_CONSTRAINT_EID_MAX 1 +#define SIR_MAC_PWR_CAPABILITY_EID 33 +#define SIR_MAC_PWR_CAPABILITY_EID_MIN 2 +#define SIR_MAC_PWR_CAPABILITY_EID_MAX 2 +#define SIR_MAC_TPC_REQ_EID 34 +#define SIR_MAC_TPC_REQ_EID_MIN 0 +#define SIR_MAC_TPC_REQ_EID_MAX 255 +/* SIR_MAC_EXTENDED_CAP_EID 35 */ +#define SIR_MAC_TPC_RPT_EID 35 +#define SIR_MAC_TPC_RPT_EID_MIN 2 +#define SIR_MAC_TPC_RPT_EID_MAX 2 +#define SIR_MAC_SPRTD_CHNLS_EID 36 +#define SIR_MAC_SPRTD_CHNLS_EID_MIN 2 +#define SIR_MAC_SPRTD_CHNLS_EID_MAX 254 +#define SIR_MAC_CHNL_SWITCH_ANN_EID 37 +#define SIR_MAC_CHNL_SWITCH_ANN_EID_MIN 3 +#define SIR_MAC_CHNL_SWITCH_ANN_EID_MAX 3 +#define SIR_MAC_MEAS_REQ_EID 38 +#define SIR_MAC_MEAS_REQ_EID_MIN 3 +#define SIR_MAC_MEAS_REQ_EID_MAX 255 +#define SIR_MAC_MEAS_RPT_EID 39 +#define SIR_MAC_MEAS_RPT_EID_MIN 3 +#define SIR_MAC_MEAS_RPT_EID_MAX 255 +#define SIR_MAC_QUIET_EID 40 +#define SIR_MAC_QUIET_EID_MIN 6 +#define SIR_MAC_QUIET_EID_MAX 6 +#define SIR_MAC_IBSS_DFS_EID 41 +#define SIR_MAC_IBSS_DFS_EID_MIN 7 +#define SIR_MAC_IBSS_DFS_EID_MAX 255 +#define SIR_MAC_ERP_INFO_EID 42 +#define SIR_MAC_ERP_INFO_EID_MIN 0 +#define SIR_MAC_ERP_INFO_EID_MAX 255 +#define SIR_MAC_TS_DELAY_EID 43 +#define SIR_MAC_TS_DELAY_EID_MIN 4 +#define SIR_MAC_TS_DELAY_EID_MAX 4 +#define SIR_MAC_TCLAS_PROC_EID 44 +#define SIR_MAC_TCLAS_PROC_EID_MIN 1 +#define SIR_MAC_TCLAS_PROC_EID_MAX 1 +#define SIR_MAC_QOS_CAPABILITY_EID 46 +#define SIR_MAC_QOS_CAPABILITY_EID_MIN 1 +#define SIR_MAC_QOS_CAPABILITY_EID_MAX 1 +#define SIR_MAC_RSN_EID 48 +#define SIR_MAC_RSN_EID_MIN 4 +#define SIR_MAC_RSN_EID_MAX 254 + +/* using reserved EID for Qos Action IE for now, */ +/* need to check 11e spec for the actual EID */ +#define SIR_MAC_QOS_ACTION_EID 49 +#define SIR_MAC_QOS_ACTION_EID_MIN 4 +#define SIR_MAC_QOS_ACTION_EID_MAX 255 +#define SIR_MAC_EXTENDED_RATE_EID 50 +#define SIR_MAC_EXTENDED_RATE_EID_MIN 0 +#define SIR_MAC_EXTENDED_RATE_EID_MAX 255 +#define SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID 60 +#define SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID_MIN 0 +#define SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID_MAX 255 + +#define SIR_MAC_OPERATING_CLASS_EID 59 +#define SIR_MAC_OPERATING_CLASS_EID_MIN 2 +#define SIR_MAC_OPERATING_CLASS_EID_MAX 253 +/* reserved 51-69 */ +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID 70 +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID_MIN 5 +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX 5 +/* reserved 71-220 */ +#define SIR_MAC_WPA_EID 221 +#define SIR_MAC_WPA_EID_MIN 0 +#define SIR_MAC_WPA_EID_MAX 255 + +#define SIR_MAC_EID_VENDOR 221 + +#define SIR_MAC_WAPI_EID 68 +/* reserved 222-254 */ +#define SIR_MAC_HT_CAPABILITIES_EID 45 +#define SIR_MAC_HT_CAPABILITIES_EID_MIN 0 +#define SIR_MAC_HT_CAPABILITIES_EID_MAX 255 +#define SIR_MAC_HT_INFO_EID 61 +#define SIR_MAC_HT_INFO_EID_MIN 0 +#define SIR_MAC_HT_INFO_EID_MAX 255 + +#define SIR_MAC_VHT_CAPABILITIES_EID 191 +#define SIR_MAC_VHT_OPERATION_EID 192 +#define SIR_MAC_VHT_EXT_BSS_LOAD_EID 193 +#define SIR_MAC_VHT_OPMODE_EID 199 +#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_CAP_160_SUPP 1 +#define VHT_CAP_160_AND_80P80_SUPP 2 + +#define VHT_MCS_1x1 0xFFFC +#define VHT_MCS_2x2 0xFFF3 + +/* Mask to check if BTM offload is enabled/disabled*/ +#define BTM_OFFLOAD_ENABLED_MASK 0x01 + +#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 */ + +/* / Workaround IE to change beacon length when it is 4*n+1 */ +#define SIR_MAC_ANI_WORKAROUND_EID 255 +#define SIR_MAC_ANI_WORKAROUND_EID_MIN 0 +#define SIR_MAC_ANI_WORKAROUND_EID_MAX 255 + +#define SIR_MAC_MAX_ADD_IE_LENGTH 2048 + +/* / Maximum length of each IE */ +#define SIR_MAC_MAX_IE_LENGTH 255 + +/* / Maximum length of each IE */ +#define SIR_MAC_RSN_IE_MAX_LENGTH 255 +/* / 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 + +/* OUI and type definition for WPA IE in network byte order */ +#define SIR_MAC_WPA_OUI 0x01F25000 +#define SIR_MAC_WME_OUI 0x02F25000 +#define SIR_MAC_WSM_OUI SIR_MAC_WME_OUI +#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_MAX_NOA_DESCR 2 +#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 + +/* min size of wme oui header: oui(3) + type + subtype + version */ +#define SIR_MAC_OUI_WME_HDR_MIN 6 + +/* OUI subtype and their lengths */ +#define SIR_MAC_OUI_SUBTYPE_WME_INFO 0 +#define SIR_MAC_OUI_WME_INFO_MIN 7 +#define SIR_MAC_OUI_WME_INFO_MAX 7 + +#define SIR_MAC_OUI_SUBTYPE_WME_PARAM 1 +#define SIR_MAC_OUI_WME_PARAM_MIN 24 +#define SIR_MAC_OUI_WME_PARAM_MAX 24 + +#define SIR_MAC_OUI_SUBTYPE_WME_TSPEC 2 +#define SIR_MAC_OUI_WME_TSPEC_MIN 61 +#define SIR_MAC_OUI_WME_TSPEC_MAX 61 + +#define SIR_MAC_OUI_SUBTYPE_WSM_TSPEC 2 /* same as WME TSPEC */ +#define SIR_MAC_OUI_WSM_TSPEC_MIN 61 +#define SIR_MAC_OUI_WSM_TSPEC_MAX 61 + +/* reserved subtypes 3-4 */ +/* WSM capability */ +#define SIR_MAC_OUI_SUBTYPE_WSM_CAPABLE 5 +#define SIR_MAC_OUI_WSM_CAPABLE_MIN 7 +#define SIR_MAC_OUI_WSM_CAPABLE_MAX 7 +/* WSM classifier */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TCLAS 6 +#define SIR_MAC_OUI_WSM_TCLAS_MIN 10 +#define SIR_MAC_OUI_WSM_TCLAS_MAX 255 +/* classifier processing element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TCLASPROC 7 +#define SIR_MAC_OUI_WSM_TCLASPROC_MIN 7 +#define SIR_MAC_OUI_WSM_TCLASPROC_MAX 7 +/* tspec delay element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TSDELAY 8 +#define SIR_MAC_OUI_WSM_TSDELAY_MIN 10 +#define SIR_MAC_OUI_WSM_TSDELAY_MAX 10 +/* schedule element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_SCHEDULE 9 +#define SIR_MAC_OUI_WSM_SCHEDULE_MIN 20 +#define SIR_MAC_OUI_WSM_SCHEDULE_MAX 20 + +#ifdef WLAN_NS_OFFLOAD +#define SIR_MAC_NS_OFFLOAD_SIZE 1 /* support only one IPv6 offload */ +/* Number of target IP V6 addresses for NS offload */ +#define SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA 16 +#define SIR_MAC_IPV6_ADDR_LEN 16 +#define SIR_IPV6_ADDR_VALID 1 +#define SIR_IPV6_ADDR_UC_TYPE 0 +#define SIR_IPV6_ADDR_AC_TYPE 1 +#endif /* WLAN_NS_OFFLOAD */ + +/* ----------------------------------------------------------------------------- */ + +/* OFFSET definitions for fixed fields in Management frames */ + +/* Beacon/Probe Response offsets */ +#define SIR_MAC_TS_OFFSET 0 +#define SIR_MAC_BEACON_INT_OFFSET 8 /* Beacon Interval offset */ +#define SIR_MAC_B_PR_CAPAB_OFFSET 10 +#define SIR_MAC_B_PR_SSID_OFFSET 12 + +/* Association/Reassociation offsets */ +#define SIR_MAC_ASSOC_CAPAB_OFFSET 0 +#define SIR_MAC_LISTEN_INT_OFFSET 2 /* Listen Interval offset */ +#define SIR_MAC_ASSOC_SSID_OFFSET 4 +#define SIR_MAC_CURRENT_AP_OFFSET 4 +#define SIR_MAC_REASSOC_SSID_OFFSET 10 +#define SIR_MAC_ASSOC_STATUS_CODE_OFFSET 2 +#define SIR_MAC_ASSOC_AID_OFFSET 4 +#define SIR_MAC_ASSOC_RSP_RATE_OFFSET 6 + +/* Disassociation/Deauthentication offsets */ +#define SIR_MAC_REASON_CODE_OFFSET 0 + +/* Probe Request offset */ +#define SIR_MAC_PROBE_REQ_SSID_OFFSET 0 + +/* Authentication offsets */ +#define SIR_MAC_AUTH_ALGO_OFFSET 0 +#define SIR_MAC_AUTH_XACT_SEQNUM_OFFSET 2 +#define SIR_MAC_AUTH_STATUS_CODE_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_SSID_LENGTH 32 +#define SIR_MAC_MAX_NUMBER_OF_RATES 12 +#define SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS 4 +#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 +#define SIR_MAC_MAX_KEY_RSC_LEN 16 + +/* / 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)->roam.configParam.isWESModeEnabled) + +#define BA_RECIPIENT 1 +#define BA_INITIATOR 2 +#define BA_BOTH_DIRECTIONS 3 + +#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 + +/* Maximum allowable size of a beacon and probe rsp frame */ +#define SIR_MAX_BEACON_SIZE 512 +#define SIR_MAX_PROBE_RESP_SIZE 512 + +/* / Status Code (present in Management response frames) enum */ + +typedef enum eSirMacStatusCodes { + eSIR_MAC_SUCCESS_STATUS = 0, /* Reserved */ + eSIR_MAC_UNSPEC_FAILURE_STATUS = 1, /* Unspecified reason */ + /* 802.11 reserved 2-9 */ + /* + WMM status codes(standard 1.1 table 9) + Table 9 ADDTS Response Status Codes + Value Operation + 0 Admission accepted + 1 Invalid parameters + 2 Reserved + 3 Refused + 4-255 Reserved + */ + eSIR_MAC_WME_INVALID_PARAMS_STATUS = 1, /* ?? */ + eSIR_MAC_WME_REFUSED_STATUS = 3, /* ?? */ + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS = 10, /* Cannot support all requested capabilities in the Capability Information field */ + eSIR_MAC_INABLITY_TO_CONFIRM_ASSOC_STATUS = 11, /* Reassociation denied due to inability to confirm that association exists */ + eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS = 12, /* Association denied due to reason outside the scope of this standard */ + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS = 13, /* Responding station does not support the specified authentication algorithm */ + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS = 14, /* Received an Authentication frame with authentication transaction sequence number */ + /* out of expected sequence */ + eSIR_MAC_CHALLENGE_FAILURE_STATUS = 15, /* Authentication rejected because of challenge failure */ + eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS = 16, /* Authentication rejected due to timeout waiting for next frame in sequence */ + eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS = 17, /* Association denied because AP is unable to handle additional associated stations */ + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS = 18, /* Association denied due to requesting station not supporting all of the data rates in the */ + /* BSSBasicRateSet parameter */ + eSIR_MAC_SHORT_PREAMBLE_NOT_SUPPORTED_STATUS = 19, /* Association denied due to requesting station not supporting the short preamble */ + /* option */ + eSIR_MAC_PBCC_NOT_SUPPORTED_STATUS = 20, /* Association denied due to requesting station not supporting the PBCC modulation */ + /* option */ + eSIR_MAC_CHANNEL_AGILITY_NOT_SUPPORTED_STATUS = 21, /* Association denied due to requesting station not supporting the Channel Agility */ + /* option */ + eSIR_MAC_SPECTRUM_MGMT_REQD_STATUS = 22, /* Association request rejected because Spectrum Management capability is required */ + eSIR_MAC_PWR_CAPABILITY_BAD_STATUS = 23, /* Association request rejected because the information in the Power Capability */ + /* element is unacceptable */ + eSIR_MAC_SPRTD_CHANNELS_BAD_STATUS = 24, /* Association request rejected because the information in the Supported Channels */ + /* element is unacceptable */ + eSIR_MAC_SHORT_SLOT_NOT_SUPPORTED_STATUS = 25, /* Association denied due to requesting station not supporting the Short Slot Time */ + /* option */ + eSIR_MAC_DSSS_OFDM_NOT_SUPPORTED_STATUS = 26, /* Association denied due to requesting station not supporting the DSSS-OFDM option */ + /* reserved 27-29 */ + eSIR_MAC_TRY_AGAIN_LATER = 30, /* Association request rejected temporarily, try again later */ + /* reserved 31 */ + eSIR_MAC_QOS_UNSPECIFIED_FAILURE_STATUS = 32, /* Unspecified, QoS-related failure */ + eSIR_MAC_QAP_NO_BANDWIDTH_STATUS = 33, /* Association denied because QoS AP has insufficient bandwidth to handle another */ + /* QoS STA */ + /* + * Association denied due to excessive frame loss rates + * and/or poor conditions/RSSI on cur channel + */ + eSIR_MAC_XS_FRAME_LOSS_POOR_CHANNEL_RSSI_STATUS = 34, + /* rent operating channel */ + eSIR_MAC_STA_QOS_NOT_SUPPORTED_STATUS = 35, /* Association (with QoS BSS) denied because the requesting STA does not support the */ + /* QoS facility */ + eSIR_MAC_STA_BLK_ACK_NOT_SUPPORTED_STATUS = 36, /* Reserved */ + eSIR_MAC_REQ_DECLINED_STATUS = 37, /* The request has been declined */ + eSIR_MAC_INVALID_PARAM_STATUS = 38, /* The request has not been successful as one or more parameters have invalid values */ + eSIR_MAC_TS_NOT_HONOURED_STATUS = 39, /* The TS has not been created because the request cannot be honored; however, a suggested */ + /* TSPEC is provided so that the initiating STA may attempt to set another TS */ + /* with the suggested changes to the TSPEC */ + eSIR_MAC_INVALID_IE_STATUS = 40, /* Invalid information element, i.e., an information element defined in this standard for */ + /* which the content does not meet the specifications in Clause 7 */ + eSIR_MAC_INVALID_GROUP_CIPHER_STATUS = 41, /* Invalid group cipher */ + eSIR_MAC_INVALID_PAIRWISE_CIPHER_STATUS = 42, /* Invalid pairwise cipher */ + eSIR_MAC_INVALID_AKMP_STATUS = 43, /* Invalid AKMP */ + eSIR_MAC_UNSUPPORTED_RSN_IE_VERSION_STATUS = 44, /* Unsupported RSN information element version */ + eSIR_MAC_INVALID_RSN_IE_CAPABILITIES_STATUS = 45, /* Invalid RSN information element capabilities */ + eSIR_MAC_CIPHER_SUITE_REJECTED_STATUS = 46, /* Cipher suite rejected because of security policy */ + eSIR_MAC_TS_NOT_CREATED_STATUS = 47, /* The TS has not been created; however, the HC may be capable of creating a TS, in */ + /* response to a request, after the time indicated in the TS Delay element */ + eSIR_MAC_DL_NOT_ALLOWED_STATUS = 48, /* Direct link is not allowed in the BSS by policy */ + eSIR_MAC_DEST_STA_NOT_KNOWN_STATUS = 49, /* The Destination STA is not present within this BSS */ + eSIR_MAC_DEST_STA_NOT_QSTA_STATUS = 50, /* The Destination STA is not a QoS STA */ + eSIR_MAC_INVALID_LISTEN_INTERVAL_STATUS = 51, /* Association denied because the ListenInterval is too large */ + + eSIR_MAC_DSSS_CCK_RATE_MUST_SUPPORT_STATUS = 52, /* FIXME: */ + eSIR_MAC_DSSS_CCK_RATE_NOT_SUPPORT_STATUS = 53, + eSIR_MAC_PSMP_CONTROLLED_ACCESS_ONLY_STATUS = 54, +#ifdef FEATURE_WLAN_ESE + eSIR_MAC_ESE_UNSPECIFIED_QOS_FAILURE_STATUS = 200, /* ESE-Unspecified, QoS related failure in (Re)Assoc response frames */ + eSIR_MAC_ESE_TSPEC_REQ_REFUSED_STATUS = 201, /* ESE-TSPEC request refused due to AP's policy configuration in AddTs Rsp, (Re)Assoc Rsp. */ + eSIR_MAC_ESE_ASSOC_DENIED_INSUFF_BW_STATUS = 202, /* ESE-Assoc denied due to insufficient bandwidth to handle new TS in (Re)Assoc Rsp. */ + eSIR_MAC_ESE_INVALID_PARAMETERS_STATUS = 203, /* ESE-Invalid parameters. (Re)Assoc request had one or more TSPEC parameters with */ + /* invalid values. */ +#endif + +} tSirMacStatusCodes; + +/** + * Reason Code (present in Deauthentication/Disassociation + * Management frames) enum + */ +typedef enum eSirMacReasonCodes { + eSIR_MAC_UNSPEC_FAILURE_REASON = 1, /* Unspecified reason */ + eSIR_MAC_PREV_AUTH_NOT_VALID_REASON = 2, /* Previous authentication no longer valid */ + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON = 3, /* Deauthenticated because sending station is leaving (or has left) IBSS or ESS */ + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON = 4, /* Disassociated due to inactivity */ + eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON = 5, /* Disassociated because AP is unable to handle all currently associated stations */ + eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON = 6, /* Class 2 frame received from nonauthenticated station */ + eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON = 7, /* Class 3 frame received from nonassociated station */ + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON = 8, /* Disassociated because sending station is leaving (or has left) BSS */ + eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON = 9, /* Station requesting (re)association is not authenticated with responding station */ + eSIR_MAC_PWR_CAPABILITY_BAD_REASON = 10, /* Disassociated because the information in the Power Capability element is unacceptable */ + eSIR_MAC_SPRTD_CHANNELS_BAD_REASON = 11, /* Disassociated because the information in the Supported Channels element is unacceptable */ + /* reserved 12 */ + eSIR_MAC_INVALID_IE_REASON = 13, /* Invalid information element, i.e., an information element defined in this standard for */ + /* which the content does not meet the specifications in Clause 7 */ + eSIR_MAC_MIC_FAILURE_REASON = 14, /* Message integrity code (MIC) failure */ + eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON = 15, /* 4-Way Handshake timeout */ + eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON = 16, /* Group Key Handshake timeout */ + eSIR_MAC_RSN_IE_MISMATCH_REASON = 17, /* Information element in 4-Way Handshake different from (Re)Association Request/Probe */ + /* Response/Beacon frame */ + eSIR_MAC_INVALID_MC_CIPHER_REASON = 18, /* Invalid group cipher */ + eSIR_MAC_INVALID_UC_CIPHER_REASON = 19, /* Invalid pairwise cipher */ + eSIR_MAC_INVALID_AKMP_REASON = 20, /* Invalid AKMP */ + eSIR_MAC_UNSUPPORTED_RSN_IE_VER_REASON = 21, /* Unsupported RSN information element version */ + eSIR_MAC_INVALID_RSN_CAPABILITIES_REASON = 22, /* Invalid RSN information element capabilities */ + eSIR_MAC_1X_AUTH_FAILURE_REASON = 23, /* IEEE 802.1X authentication failed */ + eSIR_MAC_CIPHER_SUITE_REJECTED_REASON = 24, /* Cipher suite rejected because of the security policy */ +#ifdef FEATURE_WLAN_TDLS + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE = 25, /* TDLS direct link teardown due to TDLS peer STA unreachable via the TDLS direct link */ + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON = 26, /* TDLS direct link teardown for unspecified reason */ +#endif + /* reserved 27 - 30 */ +#ifdef WLAN_FEATURE_11W + eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION = 31, /* Robust management frames policy violation */ +#endif + eSIR_MAC_QOS_UNSPECIFIED_REASON = 32, /* Disassociated for unspecified, QoS-related reason */ + eSIR_MAC_QAP_NO_BANDWIDTH_REASON = 33, /* Disassociated because QoS AP lacks sufficient bandwidth for this QoS STA */ + eSIR_MAC_XS_UNACKED_FRAMES_REASON = 34, /* Disassociated because excessive number of frames need to be acknowledged, but are not */ + /* acknowledged due to AP transmissions and/or poor channel conditions */ + eSIR_MAC_BAD_TXOP_USE_REASON = 35, /* Disassociated because STA is transmitting outside the limits of its TXOPs */ + eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON = 36, /* Requested from peer STA as the STA is leaving the BSS (or resetting) */ + eSIR_MAC_PEER_REJECT_MECHANISIM_REASON = 37, /* Requested from peer STA as it does not want to use the mechanism */ + eSIR_MAC_MECHANISM_NOT_SETUP_REASON = 38, /* Requested from peer STA as the STA received frames using the mechanism for which a */ + /* setup is required */ + eSIR_MAC_PEER_TIMEDOUT_REASON = 39, /* Requested from peer STA due to timeout */ + eSIR_MAC_CIPHER_NOT_SUPPORTED_REASON = 45, /* Peer STA does not support the requested cipher suite */ + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON = 46, /* FT reason */ + /* reserved 47 - 65535. */ + eSIR_BEACON_MISSED = 65534, /* We invented this to tell beacon missed case */ +} tSirMacReasonCodes; + +/* BA Initiator v/s Recipient */ +typedef enum eBADirection { + eBA_RECIPIENT, + eBA_INITIATOR +} tBADirection; + +/* A-MPDU/BA Enable/Disable in Tx/Rx direction */ +typedef enum eBAEnable { + eBA_DISABLE, + eBA_ENABLE +} tBAEnable; + +/* A-MPDU/BA Policy */ +typedef enum eBAPolicy { + eBA_UNCOMPRESSED, + eBA_COMPRESSED +} tBAPolicy; + +/* A-MPDU/BA Policy */ +typedef enum eBAPolicyType { + eBA_POLICY_DELAYED, + eBA_POLICY_IMMEDIATE +} tBAPolicyType; + +/* / 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 pbcc: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 pbcc: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_RATESET_EID_MAX]; +} 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 * SIR_MAC_RATESET_EID_MAX]; +}; + +/* Reserve 1 byte for NULL character in the SSID name field to print in %s */ +typedef struct sSirMacSSid { + uint8_t length; + uint8_t ssId[SIR_MAC_MAX_SSID_LENGTH +1]; +} qdf_packed tSirMacSSid; + +typedef struct sSirMacWpaInfo { + uint8_t length; + uint8_t info[SIR_MAC_MAX_IE_LENGTH]; +} qdf_packed tSirMacWpaInfo, *tpSirMacWpaInfo, +tSirMacRsnInfo, *tpSirMacRsnInfo; + +typedef struct sSirMacWapiInfo { + uint8_t length; + uint8_t info[SIR_MAC_MAX_IE_LENGTH]; +} 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; + +/* ---------------- + * EDCA Profiles + * --------------- + */ + +#define EDCA_AC_BE 0 +#define EDCA_AC_BK 1 +#define EDCA_AC_VI 2 +#define EDCA_AC_VO 3 +#define AC_MGMT_LO 4 +#define AC_MGMT_HI 5 +#define MAX_NUM_AC 4 + +/* access categories */ +#define SIR_MAC_EDCAACI_BESTEFFORT (EDCA_AC_BE) +#define SIR_MAC_EDCAACI_BACKGROUND (EDCA_AC_BK) +#define SIR_MAC_EDCAACI_VIDEO (EDCA_AC_VI) +#define SIR_MAC_EDCAACI_VOICE (EDCA_AC_VO) + +/* 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; + +typedef struct sSirMacQoSParams { + uint8_t count; + uint16_t limit; + uint8_t CWmin[8]; + uint8_t AIFS[8]; +} qdf_packed tSirMacQoSParams; + +/* 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 + +typedef struct sSirMacTSInfoTfc { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t burstSizeDefn:1; + uint8_t reserved:7; +#else + uint8_t reserved:7; + uint8_t burstSizeDefn:1; +#endif + +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t ackPolicy:2; + uint16_t userPrio:3; + uint16_t psb:1; + uint16_t aggregation:1; + uint16_t accessPolicy:2; + uint16_t direction:2; + uint16_t tsid:4; + uint16_t trafficType:1; +#else + uint16_t trafficType:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t accessPolicy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t userPrio:3; + uint16_t ackPolicy:2; +#endif +} qdf_packed tSirMacTSInfoTfc; + +typedef struct sSirMacTSInfoSch { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t rsvd:7; + uint8_t schedule:1; +#else + uint8_t schedule:1; + uint8_t rsvd:7; +#endif +} qdf_packed tSirMacTSInfoSch; + +typedef struct sSirMacTSInfo { + tSirMacTSInfoTfc traffic; + tSirMacTSInfoSch schedule; +} qdf_packed tSirMacTSInfo; + +typedef struct sSirMacTspecIE { + uint8_t type; + uint8_t length; + tSirMacTSInfo tsinfo; + uint16_t nomMsduSz; + uint16_t maxMsduSz; + uint32_t minSvcInterval; + uint32_t maxSvcInterval; + uint32_t inactInterval; + uint32_t suspendInterval; + uint32_t svcStartTime; + uint32_t minDataRate; + uint32_t meanDataRate; + uint32_t peakDataRate; + uint32_t maxBurstSz; + uint32_t delayBound; + uint32_t minPhyRate; + uint16_t surplusBw; + uint16_t mediumTime; +} qdf_packed tSirMacTspecIE; + +/* 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 +#define SIR_MAC_TCLAS_IPV6 6 + +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 sSirMacChanInfo { + tSirMacChanNum firstChanNum; + uint8_t numChannels; + int8_t maxTxPower; +} qdf_packed tSirMacChanInfo; + +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; + +#define SIR_MAC_MAX_SUPP_RATES 32 + +#define SIR_MAC_MAX_SUPP_CHANNELS 100 +#define SIR_MAC_MAX_EXTN_CAP 8 + +/* VHT Capabilities Info */ +typedef struct sSirMacVHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t reserved1: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 reserved1:2; +#endif +} qdf_packed tSirMacVHTCapabilityInfo; + +typedef struct sSirMacVHTTxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:3; + uint16_t txSupDataRate:13; +#else + uint16_t txSupDataRate:13; + uint16_t reserved:3; +#endif +} qdf_packed tSirMacVHTTxSupDataRateInfo; + +typedef struct sSirMacVHTRxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:3; + uint16_t rxSupDataRate:13; +#else + uint16_t rxSupDataRate:13; + uint16_t reserved: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; + +/** + * struct sSirHtCap - HT capabilities + * + * This structure refers to "HT capabilities element" as + * described in 802.11n draft section 7.3.2.52 + */ + +typedef struct sSirHtCap { + uint16_t capInfo; + uint8_t ampduParamsInfo; + uint8_t suppMcsSet[16]; + uint16_t extendedHtCapInfo; + uint32_t txBFCapInfo; + uint8_t antennaSelectionInfo; +} tSirHTCap; + +/* HT Cap and HT IE Size defines */ +#define HT_CAPABILITY_IE_SIZE 28 +#define HT_INFO_IE_SIZE 24 + +/* */ +/* 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_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; + +/* During 11h channel switch, the AP can indicate if the + * STA needs to stop the transmission or continue until the + * channel-switch. + * eSIR_CHANSW_MODE_NORMAL - STA can continue transmission + * eSIR_CHANSW_MODE_SILENT - STA should stop transmission + */ +typedef enum eSirMacChanSwMode { + eSIR_CHANSW_MODE_NORMAL = 0, + eSIR_CHANSW_MODE_SILENT = 1 +} tSirMacChanSwitchMode; + +typedef struct _BarControl { + +#ifndef ANI_BIG_BYTE_ENDIAN + + uint16_t barAckPolicy:1; + uint16_t multiTID:1; + uint16_t bitMap:1; + uint16_t rsvd:9; + uint16_t numTID:4; + +#else + uint16_t numTID:4; + uint16_t rsvd:9; + uint16_t bitMap:1; + uint16_t multiTID:1; + uint16_t barAckPolicy:1; + +#endif + +} qdf_packed barCtrlType; + +typedef struct _BARFrmStruct { + tSirMacFrameCtl fc; + uint16_t duration; + tSirMacAddr rxAddr; + tSirMacAddr txAddr; + barCtrlType barControl; + tSirMacSeqCtl ssnCtrl; +} qdf_packed BARFrmType; + +/* 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 Capabilities Info */ +typedef struct sSirMacHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t lsigTXOPProtection:1; /* Dynamic state */ + uint16_t stbcControlFrame:1; /* Static via CFG */ + uint16_t psmp:1; /* Static via CFG */ + uint16_t dsssCckMode40MHz:1; /* Static via CFG */ + uint16_t maximalAMSDUsize:1; /* Static via CFG */ + uint16_t delayedBA:1; /* Static via CFG */ + uint16_t rxSTBC:2; /* Static via CFG */ + uint16_t txSTBC:1; /* Static via CFG */ + uint16_t shortGI40MHz:1; /* Static via CFG */ + uint16_t shortGI20MHz:1; /* Static via CFG */ + uint16_t greenField:1; /* Static via CFG */ + uint16_t mimoPowerSave:2; /* Dynamic state */ + uint16_t supportedChannelWidthSet:1; /* Static via CFG */ + uint16_t advCodingCap:1; /* Static via CFG */ +#else + 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; +#endif +} qdf_packed tSirMacHTCapabilityInfo; + +/* 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; + +/* Additional HT IE Field1 */ +typedef struct sSirMacHTInfoField1 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t serviceIntervalGranularity:3; /* Dynamic state */ + uint8_t controlledAccessOnly:1; /* Static via CFG */ + uint8_t rifsMode:1; /* Dynamic state */ + uint8_t recommendedTxWidthSet:1; /* Dynamic state */ + uint8_t secondaryChannelOffset:2; /* Dynamic state */ +#else + uint8_t secondaryChannelOffset:2; + uint8_t recommendedTxWidthSet:1; + uint8_t rifsMode:1; + uint8_t controlledAccessOnly:1; + uint8_t serviceIntervalGranularity:3; +#endif +} qdf_packed tSirMacHTInfoField1; + +/* Additional HT IE Field2 */ +typedef struct sSirMacHTInfoField2 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:11; + uint16_t obssNonHTStaPresent:1; /*added for Obss */ + uint16_t transmitBurstLimit:1; + uint16_t nonGFDevicesPresent:1; + uint16_t opMode:2; /* Dynamic state */ +#else + uint16_t opMode:2; + uint16_t nonGFDevicesPresent:1; + uint16_t transmitBurstLimit:1; + uint16_t obssNonHTStaPresent:1; /*added for Obss */ + uint16_t reserved:11; +#endif +} qdf_packed tSirMacHTInfoField2; + +/* Additional HT IE Field3 */ +typedef struct sSirMacHTInfoField3 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:4; + uint16_t pcoPhase:1; /* Dynamic state */ + uint16_t pcoActive:1; /* Dynamic state */ + uint16_t lsigTXOPProtectionFullSupport:1; /* Dynamic state */ + uint16_t secondaryBeacon:1; /* Dynamic state */ + uint16_t dualCTSProtection:1; /* Dynamic state */ + uint16_t basicSTBCMCS:7; /* Dynamic state */ +#else + 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 reserved:4; +#endif +} qdf_packed tSirMacHTInfoField3; + +typedef struct sSirMacProbeReqFrame { + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; +} qdf_packed tSirMacProbeReqFrame, *tpSirMacProbeReqFrame; + +typedef struct sSirMacProbeRspFrame { + tSirMacTimeStamp ts; + tSirMacBeaconInterval beaconInterval; + tSirMacCapabilityInfo capabilityInfo; + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; + tSirMacNonErpPresentIE nonErpPresent; + tSirMacDsParamSetIE dsParamsIE; + tSirMacCfParamSetIE cfParamsIE; +} qdf_packed tSirMacProbeRspFrame, *tpSirMacProbeRspFrame; + +typedef struct sSirMacAuthFrameBody { + uint16_t authAlgoNumber; + uint16_t authTransactionSeqNumber; + uint16_t authStatusCode; + uint8_t type; /* = SIR_MAC_CHALLENGE_TEXT_EID */ + uint8_t length; /* = SIR_MAC_AUTH_CHALLENGE_LENGTH */ + uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; +#ifdef WLAN_FEATURE_FILS_SK + tSirMacRsnInfo rsn_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 +} qdf_packed tSirMacAuthFrameBody, *tpSirMacAuthFrameBody; + +typedef struct sSirMacAuthenticationFrame { + tSirMacAuthFrameBody authFrameBody; +} qdf_packed tSirMacAuthFrame, *tpSirMacAuthFrame; + +typedef struct sSirMacAssocReqFrame { + tSirMacCapabilityInfo capabilityInfo; + uint16_t listenInterval; + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; +} qdf_packed tSirMacAssocReqFrame, *tpSirMacAssocReqFrame; + +typedef struct sSirMacAssocRspFrame { + tSirMacCapabilityInfo capabilityInfo; + uint16_t statusCode; + uint16_t aid; + tSirMacRateSetIE supportedRates; + tSirMacRateSetIE extendedRateSetIE; +} qdf_packed tSirMacAssocRspFrame, *tpSirMacAssocRspFrame; + +typedef struct sSirMacDisassocFrame { + uint16_t reasonCode; +} qdf_packed tSirMacDisassocFrame, *tpSirMacDisassocFrame; + +typedef struct sDSirMacDeauthFrame { + uint16_t reasonCode; +} qdf_packed tSirMacDeauthFrame, *tpSirMacDeauthFrame; + +/* / 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 sSirMacP2PActionFrameHdr { + uint8_t category; + uint8_t Oui[4]; + uint8_t OuiSubType; + uint8_t dialogToken; +} qdf_packed tSirMacP2PActionFrameHdr, *tpSirMacP2PActionFrameHdr; + +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 224 /* Refer IEEE 802.11k-2008, Table 7-31d */ +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 Ies[BEACON_REPORT_MAX_IES]; + +} tSirMacBeaconReport, *tpSirMacBeaconReport; + +#define RADIO_REPORTS_MAX_IN_A_FRAME 4 +typedef struct sSirMacRadioMeasureReport { + uint8_t token; + uint8_t refused; + uint8_t incapable; + uint8_t type; + union { + tSirMacBeaconReport beaconReport; + } 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:3; + uint32_t min_frag_size:2; + uint32_t trigger_frm_mac_pad:2; + uint32_t multi_tid_aggr:3; + uint32_t he_link_adaptation:2; + uint32_t all_ack:1; + uint32_t ul_mu_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 dl_mu_ba:1; + uint32_t omi_a_ctrl:1; + uint32_t ofdma_ra:1; + uint32_t max_ampdu_len:2; + uint32_t amsdu_frag:1; + uint32_t flex_twt_sched:1; + uint32_t rx_ctrl_frame:1; + + uint8_t bsrp_ampdu_aggr:1; + uint8_t qtp:1; + uint8_t a_bqr:1; + uint8_t sr_responder:1; + uint8_t ndp_feedback_supp:1; + uint8_t ops_supp:1; + uint8_t amsdu_in_ampdu:1; + uint8_t reserved1:1; + + uint32_t dual_band: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_rx_max_nsts:2; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t 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 tx_stbc_gt_80mhz:1; + uint32_t rx_stbc_gt_80mhz:1; + + uint8_t er_he_ltf_800_gi_4x:1; + uint8_t he_ppdu_20_in_40Mhz_2G:1; + uint8_t he_ppdu_20_in_160_80p80Mhz:1; + uint8_t he_ppdu_80_in_160_80p80Mhz:1; + uint8_t er_1x_he_ltf_gi:1; + uint8_t midamble_rx_1x_he_ltf:1; + uint8_t reserved2:2; + + 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 { + uint32_t bss_color:6; + uint32_t default_pe:3; + uint32_t twt_required:1; + uint32_t rts_threshold:10; + uint32_t partial_bss_col:1; + uint32_t vht_oper_present:1; + uint32_t reserved1:6; + uint32_t mbssid_ap:1; + uint32_t tx_bssid_ind:1; + uint32_t bss_col_disabled:1; + uint32_t reserved2: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; /* mbssid_ap = 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:2; + uint32_t ofdma_ra:1; + uint32_t omi_a_ctrl:1; + uint32_t dl_mu_ba: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 ul_mu_rsp_sched:1; + uint32_t all_ack:1; + uint32_t he_link_adaptation:2; + uint32_t multi_tid_aggr:3; + uint32_t trigger_frm_mac_pad:2; + uint32_t min_frag_size:2; + uint32_t max_num_frag_msdu:3; + uint32_t fragmentation:2; + uint32_t twt_responder:1; + uint32_t twt_request:1; + uint32_t htc_he:1; + + uint8_t reserved1:1; + uint8_t amsdu_in_ampdu:1; + uint8_t ops_supp:1; + uint8_t ndp_feedback_supp:1; + uint8_t sr_responder:1; + uint8_t a_bqr:1; + uint8_t qtp:1; + uint8_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 tx_stbc_lt_80mhz:1; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t midamble_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 dual_band:1; + + uint32_t rx_stbc_gt_80mhz:1; + uint32_t 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; + + uint8_t reserved2:2; + uint8_t midamble_rx_1x_he_ltf:1; + uint8_t er_1x_he_ltf_gi:1; + uint8_t he_ppdu_80_in_160_80p80Mhz:1; + uint8_t he_ppdu_20_in_160_80p80Mhz:1; + uint8_t he_ppdu_20_in_40Mhz_2G:1; + uint8_t er_he_ltf_800_gi_4x:1; + + 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:3; + uint32_t min_frag_size:2; + uint32_t trigger_frm_mac_pad:2; + uint32_t multi_tid_aggr:3; + uint32_t he_link_adaptation:2; + uint32_t all_ack:1; + uint32_t ul_mu_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 dl_mu_ba:1; + uint32_t omi_a_ctrl:1; + uint32_t ofdma_ra:1; + uint32_t max_ampdu_len:2; + uint32_t amsdu_frag:1; + uint32_t flex_twt_sched:1; + uint32_t rx_ctrl_frame:1; + + uint8_t bsrp_ampdu_aggr:1; + uint8_t qtp:1; + uint8_t a_bqr:1; + uint8_t sr_responder:1; + uint8_t ndp_feedback_supp:1; + uint8_t ops_supp:1; + uint8_t amsdu_in_ampdu:1; + uint8_t reserved1:1; + + uint32_t dual_band: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_rx_max_nsts:2; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t 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 tx_stbc_gt_80mhz:1; + uint32_t rx_stbc_gt_80mhz:1; + + uint8_t er_he_ltf_800_gi_4x:1; + uint8_t he_ppdu_20_in_40Mhz_2G:1; + uint8_t he_ppdu_20_in_160_80p80Mhz:1; + uint8_t he_ppdu_80_in_160_80p80Mhz:1; + uint8_t er_1x_he_ltf_gi:1; + uint8_t midamble_rx_1x_he_ltf:1; + uint8_t reserved2:2; + + 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; +#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 + 8) + +/* 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_REASSOC_DEADLINE 1 +#define SIR_MAC_TI_TYPE_KEY_LIFETIME 2 +#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_RESERVED2 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 + +#endif /* __MAC_PROT_DEFS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_types.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_types.h new file mode 100644 index 0000000000000000000000000000000000000000..1e3b73d52ce75b983041b087475a6b2b122ab0df --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_types.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011-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. + */ + +/* + * + * 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; + +/* retain legacy name until all instances have been replaced */ +typedef mac_handle_t tHalHandle; + +/** + * 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; + +#define HAL_NUM_ASSOC_STA 32 +#define HAL_NUM_STA 41 + +#define STACFG_MAX_TC 8 + +#endif /* __SIR_TYPES_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/wlan_tgt_def_config.h b/drivers/staging/qcacld-3.0/core/mac/inc/wlan_tgt_def_config.h new file mode 100644 index 0000000000000000000000000000000000000000..2dc52fc0bfa6286e287dbe68bfa7daa3593e9b76 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/wlan_tgt_def_config.h @@ -0,0 +1,264 @@ +/* + * 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 __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 */ +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x3 + +/* 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 + */ +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 3 + +/* + * 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 + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/wlan_tgt_def_config_hl.h b/drivers/staging/qcacld-3.0/core/mac/inc/wlan_tgt_def_config_hl.h new file mode 100644 index 0000000000000000000000000000000000000000..482202052832e0582920718faea122cb063e8e7a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/wlan_tgt_def_config_hl.h @@ -0,0 +1,301 @@ +/* + * 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 __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. + */ +#define CFG_TGT_AST_SKID_LIMIT 6 +/* + * 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 interals (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 */ +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x2 + +/* 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 + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/wni_api.h b/drivers/staging/qcacld-3.0/core/mac/inc/wni_api.h new file mode 100644 index 0000000000000000000000000000000000000000..e54e35c38532a0ce1306c79c49af1bdbdb338aec --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/wni_api.h @@ -0,0 +1,540 @@ +/* + * 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. + */ + +/* + * 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 + +#define SIR_SME_MODULE_ID 0x16 + +/* / Start of Sirius/Host message types */ +#define WNI_HOST_MSG_START 0x1500 + +enum eWniMsgTypes { + /* / CFG message types */ + eWNI_CFG_MSG_TYPES_BEGIN = WNI_HOST_MSG_START, + eWNI_CFG_MSG_TYPES_END = eWNI_CFG_MSG_TYPES_BEGIN + 0xFF, + + /* / SME message types */ + eWNI_SME_MSG_TYPES_BEGIN = eWNI_CFG_MSG_TYPES_END, + eWNI_SME_SYS_READY_IND, + eWNI_SME_SCAN_REQ, + eWNI_SME_SCAN_ABORT_IND, + eWNI_SME_SCAN_RSP, + eWNI_SME_JOIN_REQ, + eWNI_SME_JOIN_RSP, + eWNI_SME_SETCONTEXT_REQ, + eWNI_SME_SETCONTEXT_RSP, + eWNI_SME_REASSOC_REQ, + eWNI_SME_REASSOC_RSP, + eWNI_SME_DISASSOC_REQ, + eWNI_SME_DISASSOC_RSP, + eWNI_SME_DISASSOC_IND, + eWNI_SME_DISASSOC_CNF, + eWNI_SME_DEAUTH_REQ, + eWNI_SME_DEAUTH_RSP, + eWNI_SME_DEAUTH_IND, + eWNI_SME_DISCONNECT_DONE_IND, + eWNI_SME_WM_STATUS_CHANGE_NTF, + eWNI_SME_IBSS_NEW_PEER_IND, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + eWNI_SME_START_BSS_REQ, + eWNI_SME_START_BSS_RSP, + eWNI_SME_ASSOC_IND, + eWNI_SME_ASSOC_CNF, + eWNI_SME_SWITCH_CHL_IND, + eWNI_SME_STOP_BSS_REQ, + eWNI_SME_STOP_BSS_RSP, + eWNI_SME_DEAUTH_CNF, + eWNI_SME_MIC_FAILURE_IND, + eWNI_SME_ADDTS_REQ, + eWNI_SME_ADDTS_RSP, + eWNI_SME_DELTS_REQ, + eWNI_SME_DELTS_RSP, + eWNI_SME_DELTS_IND, + eWNI_SME_GET_STATISTICS_REQ, + eWNI_SME_GET_STATISTICS_RSP, + eWNI_SME_GET_RSSI_REQ, + eWNI_SME_GET_ASSOC_STAS_REQ, + eWNI_SME_WPS_PBC_PROBE_REQ_IND, + eWNI_SME_UPPER_LAYER_ASSOC_CNF, + eWNI_SME_SESSION_UPDATE_PARAM, + eWNI_SME_CHNG_MCC_BEACON_INTERVAL, + eWNI_SME_GET_SNR_REQ, + + eWNI_SME_RRM_MSG_TYPE_BEGIN, + + eWNI_SME_NEIGHBOR_REPORT_REQ_IND, + eWNI_SME_NEIGHBOR_REPORT_IND, + eWNI_SME_BEACON_REPORT_REQ_IND, + eWNI_SME_BEACON_REPORT_RESP_XMIT_IND, + + eWNI_SME_ADD_STA_SELF_RSP, + eWNI_SME_DEL_STA_SELF_RSP, + + eWNI_SME_FT_PRE_AUTH_REQ, + eWNI_SME_FT_PRE_AUTH_RSP, + eWNI_SME_FT_UPDATE_KEY, + eWNI_SME_FT_AGGR_QOS_REQ, + eWNI_SME_FT_AGGR_QOS_RSP, + +#if defined FEATURE_WLAN_ESE + eWNI_SME_ESE_ADJACENT_AP_REPORT, +#endif + + eWNI_SME_REGISTER_MGMT_FRAME_REQ, + eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE, + eWNI_SME_MAX_ASSOC_EXCEEDED, +#ifdef FEATURE_WLAN_TDLS + eWNI_SME_TDLS_SEND_MGMT_REQ, + eWNI_SME_TDLS_SEND_MGMT_RSP, + eWNI_SME_TDLS_ADD_STA_REQ, + eWNI_SME_TDLS_ADD_STA_RSP, + eWNI_SME_TDLS_DEL_STA_REQ, + eWNI_SME_TDLS_DEL_STA_RSP, + eWNI_SME_TDLS_DEL_STA_IND, + eWNI_SME_TDLS_DEL_ALL_PEER_IND, + eWNI_SME_MGMT_FRM_TX_COMPLETION_IND, + eWNI_SME_TDLS_LINK_ESTABLISH_REQ, + eWNI_SME_TDLS_LINK_ESTABLISH_RSP, + eWNI_SME_TDLS_SHOULD_DISCOVER, + eWNI_SME_TDLS_SHOULD_TEARDOWN, + eWNI_SME_TDLS_PEER_DISCONNECTED, + eWNI_SME_TDLS_CONNECTION_TRACKER_NOTIFICATION, +#endif + /* NOTE: If you are planning to add more mesages, please make sure that */ + /* SIR_LIM_ITC_MSG_TYPES_BEGIN is moved appropriately. It is set as */ + /* SIR_LIM_MSG_TYPES_BEGIN+0xB0 = 12B0 (which means max of 176 messages and */ + /* eWNI_SME_TDLS_DEL_STA_RSP = 175. */ + /* Should fix above issue to enable TDLS_INTERNAL */ + eWNI_SME_RESET_AP_CAPS_CHANGED, +#ifdef WLAN_FEATURE_11W + eWNI_SME_UNPROT_MGMT_FRM_IND, +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD + eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + eWNI_SME_CANDIDATE_FOUND_IND, /*ROAM candidate indication from FW */ + eWNI_SME_HANDOFF_REQ, /*upper layer requested handoff to driver in STA mode */ + eWNI_SME_ROAM_SCAN_OFFLOAD_RSP, /*Fwd the LFR scan offload rsp from FW to SME */ + eWNI_SME_IBSS_PEER_INFO_RSP, + eWNI_SME_GET_TSM_STATS_REQ, + eWNI_SME_GET_TSM_STATS_RSP, + eWNI_SME_TSM_IE_IND, + + eWNI_SME_READY_TO_SUSPEND_IND, + /* DFS EVENTS */ + eWNI_SME_DFS_RADAR_FOUND, /* RADAR found indication from DFS */ + eWNI_SME_CHANNEL_CHANGE_REQ, /* Channel Change Request from SAP */ + eWNI_SME_CHANNEL_CHANGE_RSP, /* Channel Change Response from WMA */ + eWNI_SME_START_BEACON_REQ, /* Start Beacon Transmission. */ + eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ, /* Transmit CSA IE in beacons */ + eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND, /* To indicate completion of CSA IE */ + /* update in beacons/probe rsp */ + eWNI_SME_STATS_EXT_EVENT, + eWNI_SME_GET_PEER_INFO_IND, + eWNI_SME_GET_PEER_INFO_EXT_IND, + eWNI_SME_CSA_OFFLOAD_EVENT, + eWNI_SME_UPDATE_ADDITIONAL_IES, /* indicates Additional IE from hdd to PE */ + eWNI_SME_MODIFY_ADDITIONAL_IES, /* To indicate IE modify from hdd to PE */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + eWNI_SME_AUTO_SHUTDOWN_IND, +#endif +#ifdef QCA_HT_2040_COEX + eWNI_SME_SET_HT_2040_MODE, +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + eWNI_SME_HO_FAIL_IND, /* Hand Off Failure Ind from WMA to SME */ +#endif +#ifdef WLAN_FEATURE_NAN + eWNI_SME_NAN_EVENT, +#endif + eWNI_SME_LINK_STATUS_IND, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + eWNI_SME_READY_TO_EXTWOW_IND, +#endif + eWNI_SME_MSG_GET_TEMPERATURE_IND, + eWNI_SME_SNR_IND, +#ifdef FEATURE_WLAN_EXTSCAN + eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND, + eWNI_SME_EPNO_NETWORK_FOUND_IND, +#endif + eWNI_SME_SET_HW_MODE_REQ, + eWNI_SME_SET_HW_MODE_RESP, + eWNI_SME_HW_MODE_TRANS_IND, + eWNI_SME_NSS_UPDATE_REQ, + eWNI_SME_NSS_UPDATE_RSP, + eWNI_SME_OCB_SET_CONFIG_RSP, + eWNI_SME_OCB_GET_TSF_TIMER_RSP, + eWNI_SME_DCC_GET_STATS_RSP, + eWNI_SME_DCC_UPDATE_NDL_RSP, + eWNI_SME_DCC_STATS_EVENT, + eWNI_SME_SET_DUAL_MAC_CFG_REQ, + eWNI_SME_SET_DUAL_MAC_CFG_RESP, + eWNI_SME_SET_THERMAL_LEVEL_IND, + eWNI_SME_SET_IE_REQ, + eWNI_SME_EXT_CHANGE_CHANNEL, + eWNI_SME_EXT_CHANGE_CHANNEL_IND, + eWNI_SME_REGISTER_MGMT_FRAME_CB, + eWNI_SME_HT40_OBSS_SCAN_IND, /* START and UPDATE OBSS SCAN Indication*/ + eWNI_SME_SET_ANTENNA_MODE_REQ, + eWNI_SME_SET_ANTENNA_MODE_RESP, + eWNI_SME_TSF_EVENT, + eWNI_SME_MON_INIT_SESSION, + eWNI_SME_PDEV_SET_HT_VHT_IE, + eWNI_SME_SET_VDEV_IES_PER_BAND, + eWNI_SME_SEND_DISASSOC_FRAME, + eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE, + eWNI_SME_DEFAULT_SCAN_IE, + eWNI_SME_ROAM_INVOKE, + eWNI_SME_ROAM_SCAN_OFFLOAD_REQ, + eWNI_SME_LOST_LINK_INFO_IND, + eWNI_SME_DEL_ALL_TDLS_PEERS, + eWNI_SME_RSO_CMD_STATUS_IND, + eWMI_SME_LL_STATS_IND, + eWNI_SME_DFS_CAC_COMPLETE, + eWNI_SME_UPDATE_CONFIG, + eWNI_SME_BT_ACTIVITY_INFO_IND, + eWNI_SME_SET_HE_BSS_COLOR, + eWNI_SME_TRIGGER_SAE, + eWNI_SME_SEND_MGMT_FRAME_TX, + eWNI_SME_SEND_SAE_MSG, + eWNI_SME_SET_ADDBA_ACCEPT, + eWNI_SME_UPDATE_EDCA_PROFILE, + eWNI_SME_PURGE_ALL_PDEV_CMDS_REQ, + /* To indicate Hidden ssid start complition to upper layer */ + eWNI_SME_HIDDEN_SSID_RESTART_RSP, + eWNI_SME_ANTENNA_ISOLATION_RSP, + eWNI_SME_MSG_TYPES_END +}; + +typedef enum { + eWNI_TDLS_TEARDOWN_REASON_TX, + eWNI_TDLS_TEARDOWN_REASON_RSSI, + eWNI_TDLS_TEARDOWN_REASON_SCAN, + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE, + eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT, + eWNI_TDLS_TEARDOWN_REASON_BAD_PTR, + eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE, +} eWniTdlsTeardownReason; + +/** + * enum ewni_tdls_connection_tracker_notification - connection tracker events + * @eWNI_TDLS_PEER_ENTER_BUF_STA: TDLS peer enters buff sta + * @eWNI_TDLS_PEER_EXIT_BUF_STA: TDLS peer exit buff sta + * @eWNI_TDLS_ENTER_BT_BUSY_MODE: Enter BT busy event + * @eWNI_TDLS_EXIT_BT_BUSY_MODE: Exit BT busy event + * @eWMI_TDLS_SCAN_STARTED_EVENT: offload scan start event + * @eWMI_TDLS_SCAN_COMPLETED_EVENT: offload scan end event + */ +enum ewni_tdls_connection_tracker_notification { + eWNI_TDLS_PEER_ENTER_BUF_STA, + eWNI_TDLS_PEER_EXIT_BUF_STA, + eWNI_TDLS_ENTER_BT_BUSY_MODE, + eWNI_TDLS_EXIT_BT_BUSY_MODE, + eWMI_TDLS_SCAN_STARTED_EVENT, + eWMI_TDLS_SCAN_COMPLETED_EVENT, +}; + +#define WNI_CFG_MSG_TYPES_BEGIN 0x1200 + +/*---------------------------------------------------------------------*/ +/* CFG Module Definitions */ +/*---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------*/ +/* CFG message definitions */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_MSG_HDR_MASK 0xffff0000 +#define WNI_CFG_MSG_LEN_MASK 0x0000ffff +#define WNI_CFG_MB_HDR_LEN 4 +#define WNI_CFG_MAX_PARAM_NUM 32 + +/*---------------------------------------------------------------------*/ +/* CFG to HDD message types */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_PARAM_UPDATE_IND (WNI_CFG_MSG_TYPES_BEGIN | 0x00) +#define WNI_CFG_DNLD_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x01) +#define WNI_CFG_DNLD_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x02) +#define WNI_CFG_GET_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x03) +#define WNI_CFG_SET_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x04) +#define WNI_CFG_GET_ATTRIB_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x05) +#define WNI_CFG_ADD_GRP_ADDR_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x06) +#define WNI_CFG_DEL_GRP_ADDR_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x07) + +#define ANI_CFG_GET_RADIO_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x08) +#define ANI_CFG_GET_PER_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x09) +#define ANI_CFG_GET_AGG_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0a) +#define ANI_CFG_CLEAR_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0b) + +/*---------------------------------------------------------------------*/ +/* CFG to HDD message parameter indices */ + +/* The followings are word indices starting from the message body */ + +/* WNI_CFG_xxxx_xxxx_xxxx: index of parameter */ +/* WNI_CFG_xxxx_xxxx_NUM: number of parameters in message */ + +/* WNI_CFG_xxxx_xxxx_LEN: byte length of message including */ +/* MB header */ +/* */ +/* WNI_CFG_xxxx_xxxx_PARTIAL_LEN: byte length of message including */ +/* parameters and MB header but */ +/* excluding variable data length */ +/*---------------------------------------------------------------------*/ + +/* Parameter update indication */ +#define WNI_CFG_PARAM_UPDATE_IND_PID 0 + +#define WNI_CFG_PARAM_UPDATE_IND_NUM 1 +#define WNI_CFG_PARAM_UPDATE_IND_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_PARAM_UPDATE_IND_NUM << 2)) + +/* Configuration download request */ +#define WNI_CFG_DNLD_REQ_NUM 0 +#define WNI_CFG_DNLD_REQ_LEN WNI_CFG_MB_HDR_LEN + +/* Configuration download confirm */ +#define WNI_CFG_DNLD_CNF_RES 0 + +#define WNI_CFG_DNLD_CNF_NUM 1 +#define WNI_CFG_DNLD_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DNLD_CNF_NUM << 2)) +/* Get response */ +#define WNI_CFG_GET_RSP_RES 0 +#define WNI_CFG_GET_RSP_PID 1 +#define WNI_CFG_GET_RSP_PLEN 2 + +#define WNI_CFG_GET_RSP_NUM 3 +#define WNI_CFG_GET_RSP_PARTIAL_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_RSP_NUM << 2)) +/* Set confirm */ +#define WNI_CFG_SET_CNF_RES 0 +#define WNI_CFG_SET_CNF_PID 1 + +#define WNI_CFG_SET_CNF_NUM 2 +#define WNI_CFG_SET_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_SET_CNF_NUM << 2)) +/* Get attribute response */ +#define WNI_CFG_GET_ATTRIB_RSP_RES 0 +#define WNI_CFG_GET_ATTRIB_RSP_PID 1 +#define WNI_CFG_GET_ATTRIB_RSP_TYPE 2 +#define WNI_CFG_GET_ATTRIB_RSP_PLEN 3 +#define WNI_CFG_GET_ATTRIB_RSP_RW 4 + +#define WNI_CFG_GET_ATTRIB_RSP_NUM 5 +#define WNI_CFG_GET_ATTRIB_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_ATTRIB_RSP_NUM << 2)) + +/* Add group address confirm */ +#define WNI_CFG_ADD_GRP_ADDR_CNF_RES 0 + +#define WNI_CFG_ADD_GRP_ADDR_CNF_NUM 1 +#define WNI_CFG_ADD_GRP_ADDR_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_ADD_GRP_ADDR_CNF_NUM << 2)) + +/* Delete group address confirm */ +#define WNI_CFG_DEL_GRP_ADDR_CNF_RES 0 + +#define WNI_CFG_DEL_GRP_ADDR_CNF_NUM 1 +#define WNI_CFG_DEL_GRP_ADDR_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DEL_GRP_ADDR_CNF_NUM << 2)) + +#define IS_CFG_MSG(msg) ((msg & 0xff00) == WNI_CFG_MSG_TYPES_BEGIN) + +/* Clear stats types. */ +#define ANI_CLEAR_ALL_STATS 0 +#define ANI_CLEAR_RX_STATS 1 +#define ANI_CLEAR_TX_STATS 2 +#define ANI_CLEAR_PER_STA_STATS 3 +#define ANI_CLEAR_AGGR_PER_STA_STATS 4 +#define ANI_CLEAR_STAT_TYPES_END 5 + +/*---------------------------------------------------------------------*/ +/* HDD to CFG message types */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_DNLD_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x80) +#define WNI_CFG_GET_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x81) + +/* Shall be removed after stats integration */ + +/*---------------------------------------------------------------------*/ +/* HDD to CFG message parameter indices */ +/* */ +/* The followings are word indices starting from the message body */ +/* */ +/* WNI_CFG_xxxx_xxxx_xxxx: index of parameter */ +/* */ +/* WNI_CFG_xxxx_xxxx_NUM: number of parameters in message */ +/* */ +/* WNI_CFG_xxxx_xxxx_LEN: byte length of message including */ +/* MB header */ +/* */ +/* WNI_CFG_xxxx_xxxx_PARTIAL_LEN: byte length of message including */ +/* parameters and MB header but */ +/* excluding variable data length */ +/*---------------------------------------------------------------------*/ + +/* Download response */ +#define WNI_CFG_DNLD_RSP_BIN_LEN 0 + +#define WNI_CFG_DNLD_RSP_NUM 1 +#define WNI_CFG_DNLD_RSP_PARTIAL_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DNLD_RSP_NUM << 2)) + +/* Set parameter request */ +#define WNI_CFG_SET_REQ_PID 0 +#define WNI_CFG_SET_REQ_PLEN 1 + +/*---------------------------------------------------------------------*/ +/* CFG return values */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_SUCCESS 1 +#define WNI_CFG_NOT_READY 2 +#define WNI_CFG_INVALID_PID 3 +#define WNI_CFG_INVALID_LEN 4 +#define WNI_CFG_RO_PARAM 5 +#define WNI_CFG_WO_PARAM 6 +#define WNI_CFG_INVALID_STAID 7 +#define WNI_CFG_OTHER_ERROR 8 +#define WNI_CFG_NEED_RESTART 9 +#define WNI_CFG_NEED_RELOAD 10 + +/*---------------------------------------------------------------------*/ +/* CFG definitions */ +/*---------------------------------------------------------------------*/ + +/* Shall be removed after integration of stats. */ +/* Get statistic response */ +#define WNI_CFG_GET_STAT_RSP_RES 0 +#define WNI_CFG_GET_STAT_RSP_PARAMID 1 +#define WNI_CFG_GET_STAT_RSP_VALUE 2 + +#define WNI_CFG_GET_STAT_RSP_NUM 3 +#define WNI_CFG_GET_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_STAT_RSP_NUM << 2)) +/* Get per station statistic response */ +#define WNI_CFG_GET_PER_STA_STAT_RSP_RES 0 +#define WNI_CFG_GET_PER_STA_STAT_RSP_STAID 1 +#define WNI_CFG_GET_PER_STA_STAT_RSP_FIRST_PARAM 2 + +/* Per STA statistic structure */ +typedef struct sAniCfgPerStaStatStruct { + unsigned long sentAesBlksUcastHi; + unsigned long sentAesBlksUcastLo; + + unsigned long recvAesBlksUcastHi; + unsigned long recvAesBlksUcastLo; + + unsigned long aesFormatErrorUcastCnts; + + unsigned long aesReplaysUcast; + + unsigned long aesDecryptErrUcast; + + unsigned long singleRetryPkts; + + unsigned long failedTxPkts; + + unsigned long ackTimeouts; + + unsigned long multiRetryPkts; + + unsigned long fragTxCntsHi; + unsigned long fragTxCntsLo; + + unsigned long transmittedPktsHi; + unsigned long transmittedPktsLo; + + unsigned long phyStatHi; + unsigned long phyStatLo; +} tCfgPerStaStatStruct, *tpAniCfgPerStaStatStruct; + +#define WNI_CFG_GET_PER_STA_STAT_RSP_NUM 23 +#define WNI_CFG_GET_PER_STA_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_PER_STA_STAT_RSP_NUM << 2)) + +/* Shall be removed after integrating stats. */ +#define WNI_CFG_GET_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x08) +#define WNI_CFG_GET_PER_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x09) +#define WNI_CFG_GET_AGG_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0a) +#define WNI_CFG_GET_TX_RATE_CTR_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0b) + +#define WNI_CFG_GET_AGG_STA_STAT_RSP_NUM 21 +#define WNI_CFG_GET_AGG_STA_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_AGG_STA_STAT_RSP_NUM << 2)) +#define WNI_CFG_GET_AGG_STA_STAT_RSP_RES 0 + +/* Get TX rate based stats */ +#define WNI_CFG_GET_TX_RATE_CTR_RSP_RES 0 + +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; + +#define WNI_CFG_GET_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x86) +#define WNI_CFG_GET_PER_STA_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x87) +#define WNI_CFG_GET_AGG_STA_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x88) +#define WNI_CFG_GET_TX_RATE_CTR_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x89) + +/* Get statistic request */ +#define WNI_CFG_GET_STAT_REQ_PARAMID 0 + +#define WNI_CFG_GET_STAT_REQ_NUM 1 +#define WNI_CFG_GET_STAT_REQ_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_STAT_REQ_NUM << 2)) + +/* Get per station statistic request */ +#define WNI_CFG_GET_PER_STA_STAT_REQ_STAID 0 + +#define WNI_CFG_GET_PER_STA_STAT_REQ_NUM 1 +#define WNI_CFG_GET_PER_STA_STAT_REQ_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_PER_STA_STAT_REQ_NUM << 2)) + +#define DYNAMIC_CFG_TYPE_SELECTED_REGISTRAR (0) +#define DYNAMIC_CFG_TYPE_WPS_STATE (1) + +#endif /* __WNI_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/wni_cfg.h b/drivers/staging/qcacld-3.0/core/mac/inc/wni_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..a35550f2c9ad800d7c5dad9325ecd964c2d97b9a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/wni_cfg.h @@ -0,0 +1,1657 @@ +/* + * 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. + */ + +#ifndef __WNICFG_H +#define __WNICFG_H + +/* + * Configuration Parameter ID for STA + */ + +enum { + WNI_CFG_STA_ID, + WNI_CFG_CFP_PERIOD, + WNI_CFG_CFP_MAX_DURATION, + WNI_CFG_SSID, + WNI_CFG_BEACON_INTERVAL, + WNI_CFG_DTIM_PERIOD, + WNI_CFG_WEP_DEFAULT_KEY_1, + WNI_CFG_WEP_DEFAULT_KEY_2, + WNI_CFG_WEP_DEFAULT_KEY_3, + WNI_CFG_WEP_DEFAULT_KEY_4, + WNI_CFG_WEP_DEFAULT_KEYID, + WNI_CFG_RTS_THRESHOLD, + WNI_CFG_FRAGMENTATION_THRESHOLD, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + WNI_CFG_JOIN_FAILURE_TIMEOUT, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + WNI_CFG_SUPPORTED_RATES_11B, + WNI_CFG_SUPPORTED_RATES_11A, + WNI_CFG_DOT11_MODE, + WNI_CFG_OPERATIONAL_RATE_SET, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + WNI_CFG_LISTEN_INTERVAL, + WNI_CFG_VALID_CHANNEL_LIST, + WNI_CFG_APSD_ENABLED, + WNI_CFG_SHARED_KEY_AUTH_ENABLE, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + WNI_CFG_AUTHENTICATION_TYPE, + WNI_CFG_PRIVACY_ENABLED, + WNI_CFG_SHORT_PREAMBLE, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + WNI_CFG_QOS_ENABLED, + WNI_CFG_HCF_ENABLED, + WNI_CFG_RSN_ENABLED, + WNI_CFG_MAX_NUM_PRE_AUTH, + WNI_CFG_HEART_BEAT_THRESHOLD, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + WNI_CFG_MANUFACTURER_NAME, + WNI_CFG_MODEL_NUMBER, + WNI_CFG_MODEL_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + WNI_CFG_11D_ENABLED, + WNI_CFG_MAX_TX_POWER_2_4, + WNI_CFG_MAX_TX_POWER_5, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + WNI_CFG_NEW_BSS_FOUND_IND, + WNI_CFG_COUNTRY_CODE, + WNI_CFG_11H_ENABLED, + WNI_CFG_WT_CNF_TIMEOUT, + WNI_CFG_OLBC_DETECT_TIMEOUT, + WNI_CFG_PROTECTION_ENABLED, + WNI_CFG_11G_PROTECTION_ALWAYS, + WNI_CFG_FORCE_POLICY_PROTECTION, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + WNI_CFG_11G_ONLY_POLICY, + WNI_CFG_WME_ENABLED, + WNI_CFG_ADDTS_RSP_TIMEOUT, + WNI_CFG_MAX_SP_LENGTH, + WNI_CFG_WSM_ENABLED, + WNI_CFG_EDCA_PROFILE, + WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACBE_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL, + WNI_CFG_EDCA_ANI_ACVO_LOCAL, + WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACBE, + WNI_CFG_EDCA_ANI_ACVI, + WNI_CFG_EDCA_ANI_ACVO, + WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACBE_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, + WNI_CFG_EDCA_WME_ACVO_LOCAL, + WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACBE, + WNI_CFG_EDCA_WME_ACVI, + WNI_CFG_EDCA_WME_ACVO, + WNI_CFG_LOCAL_POWER_CONSTRAINT, + WNI_CFG_ADMIT_POLICY, + WNI_CFG_ADMIT_BWFACTOR, + WNI_CFG_CHANNEL_BONDING_MODE, + WNI_CFG_BLOCK_ACK_ENABLED, + WNI_CFG_HT_CAP_INFO, + WNI_CFG_HT_AMPDU_PARAMS, + WNI_CFG_SUPPORTED_MCS_SET, + WNI_CFG_EXT_HT_CAP_INFO, + WNI_CFG_TX_BF_CAP, + WNI_CFG_AS_CAP, + WNI_CFG_HT_INFO_FIELD1, + WNI_CFG_HT_INFO_FIELD2, + WNI_CFG_HT_INFO_FIELD3, + WNI_CFG_BASIC_MCS_SET, + WNI_CFG_CURRENT_MCS_SET, + WNI_CFG_VHT_MAX_MPDU_LENGTH, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + WNI_CFG_VHT_LDPC_CODING_CAP, + WNI_CFG_VHT_SHORT_GI_80MHZ, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + WNI_CFG_VHT_TXSTBC, + WNI_CFG_VHT_RXSTBC, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + WNI_CFG_VHT_MU_BEAMFORMER_CAP, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + WNI_CFG_VHT_TXOP_PS, + WNI_CFG_VHT_HTC_VHTC_CAP, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + WNI_CFG_VHT_LINK_ADAPTATION_CAP, + WNI_CFG_VHT_RX_ANT_PATTERN, + WNI_CFG_VHT_TX_ANT_PATTERN, + WNI_CFG_VHT_RX_MCS_MAP, + WNI_CFG_VHT_TX_MCS_MAP, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + WNI_CFG_VHT_BASIC_MCS_SET, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + WNI_CFG_VHT_SS_UNDER_UTIL, + WNI_CFG_VHT_40MHZ_UTILIZATION, + WNI_CFG_VHT_80MHZ_UTILIZATION, + WNI_CFG_VHT_160MHZ_UTILIZATION, + WNI_CFG_MPDU_DENSITY, + WNI_CFG_MAX_RX_AMPDU_FACTOR, + WNI_CFG_MAX_PS_POLL, + WNI_CFG_SCAN_IN_POWERSAVE, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + WNI_CFG_WOWLAN_DEAUTH_ENABLE, + WNI_CFG_WOWLAN_DISASSOC_ENABLE, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + WNI_CFG_IBSS_AUTO_BSSID, + WNI_CFG_WPS_ENABLE, + WNI_CFG_WPS_STATE, + WNI_CFG_WPS_VERSION, + WNI_CFG_WPS_CFG_METHOD, + WNI_CFG_WPS_UUID, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, + WNI_CFG_WPS_PIMARY_DEVICE_OUI, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY, + WNI_CFG_WPS_DEVICE_PASSWORD_ID, + WNI_CFG_SINGLE_TID_RC, + WNI_CFG_TELE_BCN_WAKEUP_EN, + WNI_CFG_TELE_BCN_MAX_LI, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + WNI_CFG_ASSOC_STA_LIMIT, + WNI_CFG_ENABLE_LTE_COEX, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + WNI_CFG_ENABLE_MC_ADDR_LIST, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + WNI_CFG_TDLS_BUF_STA_ENABLED, + WNI_CFG_TDLS_PUAPSD_INACT_TIME, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + WNI_CFG_CURRENT_RSSI, + WNI_CFG_RTT3_ENABLE, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + WNI_CFG_DFS_MASTER_ENABLED, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + WNI_CFG_TDLS_WMM_MODE_ENABLED, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD, + WNI_CFG_TGT_GTX_USR_CFG, + WNI_CFG_MAX_HT_MCS_TX_DATA, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + WNI_CFG_RATE_FOR_TX_MGMT, + WNI_CFG_HE_CONTROL, + WNI_CFG_HE_TWT_REQUESTOR, + WNI_CFG_HE_TWT_RESPONDER, + WNI_CFG_HE_FRAGMENTATION, + WNI_CFG_HE_MAX_FRAG_MSDU, + WNI_CFG_HE_MIN_FRAG_SIZE, + WNI_CFG_HE_TRIG_PAD, + WNI_CFG_HE_MTID_AGGR, + WNI_CFG_HE_LINK_ADAPTATION, + WNI_CFG_HE_ALL_ACK, + WNI_CFG_HE_UL_MU_RSP_SCHEDULING, + WNI_CFG_HE_BUFFER_STATUS_RPT, + WNI_CFG_HE_BCAST_TWT, + WNI_CFG_HE_BA_32BIT, + WNI_CFG_HE_MU_CASCADING, + WNI_CFG_HE_MULTI_TID, + WNI_CFG_HE_DL_MU_BA, + WNI_CFG_HE_OMI, + WNI_CFG_HE_OFDMA_RA, + WNI_CFG_HE_MAX_AMPDU_LEN, + WNI_CFG_HE_AMSDU_FRAG, + WNI_CFG_HE_FLEX_TWT_SCHED, + WNI_CFG_HE_RX_CTRL, + WNI_CFG_HE_BSRP_AMPDU_AGGR, + WNI_CFG_HE_QTP, + WNI_CFG_HE_A_BQR, + WNI_CFG_HE_SR_RESPONDER, + WNI_CFG_HE_NDP_FEEDBACK_SUPP, + WNI_CFG_HE_OPS_SUPP, + WNI_CFG_HE_AMSDU_IN_AMPDU, + WNI_CFG_HE_DUAL_BAND, + WNI_CFG_HE_CHAN_WIDTH, + WNI_CFG_HE_RX_PREAM_PUNC, + WNI_CFG_HE_CLASS_OF_DEVICE, + WNI_CFG_HE_LDPC, + WNI_CFG_HE_LTF_PPDU, + WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS, + WNI_CFG_HE_LTF_NDP, + WNI_CFG_HE_TX_STBC_LT80, + WNI_CFG_HE_RX_STBC_LT80, + WNI_CFG_HE_DOPPLER, + WNI_CFG_HE_UL_MUMIMO, + WNI_CFG_HE_DCM_TX, + WNI_CFG_HE_DCM_RX, + WNI_CFG_HE_MU_PPDU, + WNI_CFG_HE_SU_BEAMFORMER, + WNI_CFG_HE_SU_BEAMFORMEE, + WNI_CFG_HE_MU_BEAMFORMER, + WNI_CFG_HE_BFEE_STS_LT80, + WNI_CFG_HE_BFEE_STS_GT80, + WNI_CFG_HE_NUM_SOUND_LT80, + WNI_CFG_HE_NUM_SOUND_GT80, + WNI_CFG_HE_SU_FEED_TONE16, + WNI_CFG_HE_MU_FEED_TONE16, + WNI_CFG_HE_CODEBOOK_SU, + WNI_CFG_HE_CODEBOOK_MU, + WNI_CFG_HE_BFRM_FEED, + WNI_CFG_HE_ER_SU_PPDU, + WNI_CFG_HE_DL_PART_BW, + WNI_CFG_HE_PPET_PRESENT, + WNI_CFG_HE_SRP, + WNI_CFG_HE_POWER_BOOST, + WNI_CFG_HE_4x_LTF_GI, + WNI_CFG_HE_MAX_NC, + WNI_CFG_HE_TX_STBC_GT80, + WNI_CFG_HE_RX_STBC_GT80, + WNI_CFG_HE_ER_4x_LTF_GI, + WNI_CFG_HE_PPDU_20_IN_40MHZ_2G, + WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ, + WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ, + WNI_CFG_HE_ER_1X_HE_LTF_GI, + WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF, + WNI_CFG_HE_RX_MCS_MAP_LT_80, + WNI_CFG_HE_TX_MCS_MAP_LT_80, + WNI_CFG_HE_RX_MCS_MAP_160, + WNI_CFG_HE_TX_MCS_MAP_160, + WNI_CFG_HE_RX_MCS_MAP_80_80, + WNI_CFG_HE_TX_MCS_MAP_80_80, + WNI_CFG_HE_PPET_2G, + WNI_CFG_HE_PPET_5G, + WNI_CFG_HE_OPS_BSS_COLOR, + WNI_CFG_HE_OPS_DEFAULT_PE, + WNI_CFG_HE_OPS_TWT_REQUIRED, + WNI_CFG_HE_OPS_RTS_THRESHOLD, + WNI_CFG_HE_OPS_PARTIAL_BSS_COL, + WNI_CFG_HE_OPS_VHT_OPER_PRESENT, + WNI_CFG_HE_OPS_MBSSID_AP, + WNI_CFG_HE_OPS_TX_BSSID_IND, + WNI_CFG_HE_OPS_BSS_COL_DISABLED, + WNI_CFG_HE_OPS_BASIC_MCS_NSS, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + WNI_CFG_HE_STA_OBSSPD, + WNI_CFG_SAP_MAX_MCS_DATA, + WNI_CFG_RATE_FOR_TX_MGMT_2G, + WNI_CFG_RATE_FOR_TX_MGMT_5G, + WNI_CFG_EDCA_ETSI_ACBK_LOCAL, + WNI_CFG_EDCA_ETSI_ACBE_LOCAL, + WNI_CFG_EDCA_ETSI_ACVI_LOCAL, + WNI_CFG_EDCA_ETSI_ACVO_LOCAL, + WNI_CFG_EDCA_ETSI_ACBK, + WNI_CFG_EDCA_ETSI_ACBE, + WNI_CFG_EDCA_ETSI_ACVI, + WNI_CFG_EDCA_ETSI_ACVO, + WNI_CFG_OBSS_DETECTION_OFFLOAD, + WNI_CFG_OBSS_COLOR_COLLISION_OFFLOAD, + WNI_CFG_TWT_REQUESTOR, + WNI_CFG_TWT_RESPONDER, + WNI_CFG_BCAST_TWT, + /* Any new items to be added should be above this strictly */ + CFG_PARAM_MAX_NUM +}; +/* + * String parameter lengths + */ + +#define WNI_CFG_STA_ID_LEN 6 +#define WNI_CFG_SSID_LEN 32 +#define WNI_CFG_WEP_DEFAULT_KEY_1_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_2_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_3_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_4_LEN 13 +#define WNI_CFG_SUPPORTED_RATES_11B_LEN 4 +#define WNI_CFG_SUPPORTED_RATES_11A_LEN 8 +#define WNI_CFG_OPERATIONAL_RATE_SET_LEN 12 +#define WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN 8 +#define WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET_LEN 4 +#define WNI_CFG_VALID_CHANNEL_LIST_LEN 100 +#define WNI_CFG_MANUFACTURER_NAME_LEN 64 +#define WNI_CFG_MODEL_NUMBER_LEN 32 +#define WNI_CFG_MODEL_NAME_LEN 32 +#define WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN 32 +#define WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN 32 +#define WNI_CFG_MAX_TX_POWER_2_4_LEN 128 +#define WNI_CFG_MAX_TX_POWER_5_LEN 128 +#define WNI_CFG_COUNTRY_CODE_LEN 3 +#define WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBE_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVI_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVO_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBK_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBE_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVI_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVO_LEN 20 +#define WNI_CFG_EDCA_WME_ACBK_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACBE_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACVI_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACVO_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACBK_LEN 20 +#define WNI_CFG_EDCA_WME_ACBE_LEN 20 +#define WNI_CFG_EDCA_WME_ACVI_LEN 20 +#define WNI_CFG_EDCA_WME_ACVO_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACBK_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACBE_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACVI_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACVO_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACBK_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACBE_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACVI_LEN 20 +#define WNI_CFG_EDCA_ETSI_ACVO_LEN 20 +#define WNI_CFG_SUPPORTED_MCS_SET_LEN 16 +#define WNI_CFG_BASIC_MCS_SET_LEN 16 +#define WNI_CFG_CURRENT_MCS_SET_LEN 16 +#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_CFP_PERIOD_STAMIN 0 +#define WNI_CFG_CFP_PERIOD_STAMAX 255 +#define WNI_CFG_CFP_PERIOD_STADEF 1 + +#define WNI_CFG_CFP_MAX_DURATION_STAMIN 0 +#define WNI_CFG_CFP_MAX_DURATION_STAMAX 65535 +#define WNI_CFG_CFP_MAX_DURATION_STADEF 30000 + +#define WNI_CFG_BEACON_INTERVAL_STAMIN 0 +#define WNI_CFG_BEACON_INTERVAL_STAMAX 65535 +#define WNI_CFG_BEACON_INTERVAL_STADEF 100 + +#define WNI_CFG_DTIM_PERIOD_STAMIN 0 +#define WNI_CFG_DTIM_PERIOD_STAMAX 65535 +#define WNI_CFG_DTIM_PERIOD_STADEF 1 + +#define WNI_CFG_WEP_KEY_LENGTH_5 5 +#define WNI_CFG_WEP_KEY_LENGTH_13 13 + +#define WNI_CFG_WEP_DEFAULT_KEYID_STAMIN 0 +#define WNI_CFG_WEP_DEFAULT_KEYID_STAMAX 3 +#define WNI_CFG_WEP_DEFAULT_KEYID_STADEF 0 + +#define WNI_CFG_WEP_DEFAULT_KEYID_0 0 +#define WNI_CFG_WEP_DEFAULT_KEYID_1 1 +#define WNI_CFG_WEP_DEFAULT_KEYID_2 2 +#define WNI_CFG_WEP_DEFAULT_KEYID_3 3 + +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STAMIN 0 +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STAMAX 1 +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STADEF 0 + +#define WNI_CFG_RTS_THRESHOLD_STAMIN 0 +#define WNI_CFG_RTS_THRESHOLD_STAMAX 1048576 +#define WNI_CFG_RTS_THRESHOLD_STADEF 2347 + +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN 256 +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX 8000 +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF 8000 + +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STADEF 20 + +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STADEF 40 + +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STADEF 60 + +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STADEF 110 + +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF 3000 + +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMIN 500 +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMAX 5000 +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF 1000 + +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMIN 0 +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STADEF 1000 + +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF 2000 + +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STADEF 1000 + +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STAMIN 0 +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STAMAX 1 +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STADEF 1 + +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STAMIN 0 +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STAMAX 1 +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STADEF 1 + +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMIN 0 +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMAX 1 +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STADEF 0 + +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMIN 1 +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMAX 255 +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STADEF 200 + +#define WNI_CFG_RF_SETTLING_TIME_CLK_STAMIN 0 +#define WNI_CFG_RF_SETTLING_TIME_CLK_STAMAX 60000 +#define WNI_CFG_RF_SETTLING_TIME_CLK_STADEF 1500 + +#define WNI_CFG_PHY_MODE_STAMIN 0 +#define WNI_CFG_PHY_MODE_STAMAX 3 +#define WNI_CFG_PHY_MODE_STADEF 0 + +#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_DOT11_MODE_STAMIN 0 +#define WNI_CFG_DOT11_MODE_STAMAX 10 +#define WNI_CFG_DOT11_MODE_STADEF 0 + +#define WNI_CFG_DOT11_MODE_ALL 0 +#define WNI_CFG_DOT11_MODE_11A 1 +#define WNI_CFG_DOT11_MODE_11B 2 +#define WNI_CFG_DOT11_MODE_11G 3 +#define WNI_CFG_DOT11_MODE_11N 4 +#define WNI_CFG_DOT11_MODE_11G_ONLY 5 +#define WNI_CFG_DOT11_MODE_11N_ONLY 6 +#define WNI_CFG_DOT11_MODE_11AC 7 +#define WNI_CFG_DOT11_MODE_11AC_ONLY 8 +#define WNI_CFG_DOT11_MODE_11AX 9 +#define WNI_CFG_DOT11_MODE_11AX_ONLY 10 + +#define WNI_CFG_LISTEN_INTERVAL_STAMIN 0 +#define WNI_CFG_LISTEN_INTERVAL_STAMAX 65535 +#define WNI_CFG_LISTEN_INTERVAL_STADEF 1 + +#define WNI_CFG_CURRENT_CHANNEL_STAMIN 0 +#define WNI_CFG_CURRENT_CHANNEL_STAMAX 173 +#define WNI_CFG_CURRENT_CHANNEL_STADEF 1 + +#define WNI_CFG_RATE_ADAPTATION_TYPE_FIXED 0 +#define WNI_CFG_RATE_ADAPTATION_TYPE_AUTO 1 +#define WNI_CFG_RATE_ADAPTATION_TYPE_SNR_BASED 2 + +#define WNI_CFG_FIXED_RATE_STAMIN 0 +#define WNI_CFG_FIXED_RATE_STAMAX 44 +#define WNI_CFG_FIXED_RATE_STADEF 0 + +#define WNI_CFG_FIXED_RATE_AUTO 0 +#define WNI_CFG_FIXED_RATE_1MBPS 1 +#define WNI_CFG_FIXED_RATE_2MBPS 2 +#define WNI_CFG_FIXED_RATE_5_5MBPS 3 +#define WNI_CFG_FIXED_RATE_11MBPS 4 +#define WNI_CFG_FIXED_RATE_6MBPS 5 +#define WNI_CFG_FIXED_RATE_9MBPS 6 +#define WNI_CFG_FIXED_RATE_12MBPS 7 +#define WNI_CFG_FIXED_RATE_18MBPS 8 +#define WNI_CFG_FIXED_RATE_24MBPS 9 +#define WNI_CFG_FIXED_RATE_36MBPS 10 +#define WNI_CFG_FIXED_RATE_48MBPS 11 +#define WNI_CFG_FIXED_RATE_54MBPS 12 +#define WNI_CFG_FIXED_RATE_6_5MBPS_MCS0_20MHZ_SIMO 13 +#define WNI_CFG_FIXED_RATE_13MBPS_MCS1_20MHZ_SIMO 14 +#define WNI_CFG_FIXED_RATE_19_5MBPS_MCS2_20MHZ_SIMO 15 +#define WNI_CFG_FIXED_RATE_26MBPS_MCS3_20MHZ_SIMO 16 +#define WNI_CFG_FIXED_RATE_39MBPS_MCS4_20MHZ_SIMO 17 +#define WNI_CFG_FIXED_RATE_52MBPS_MCS5_20MHZ_SIMO 18 +#define WNI_CFG_FIXED_RATE_58_5MBPS_MCS6_20MHZ_SIMO 19 +#define WNI_CFG_FIXED_RATE_65MBPS_MCS7_20MHZ_SIMO 20 +#define WNI_CFG_FIXED_RATE_7_2MBPS_MCS0_20MHZ_SIMO_SGI 21 +#define WNI_CFG_FIXED_RATE_14_4MBPS_MCS1_20MHZ_SIMO_SGI 22 +#define WNI_CFG_FIXED_RATE_21_7MBPS_MCS2_20MHZ_SIMO_SGI 23 +#define WNI_CFG_FIXED_RATE_28_9MBPS_MCS3_20MHZ_SIMO_SGI 24 +#define WNI_CFG_FIXED_RATE_43_3MBPS_MCS4_20MHZ_SIMO_SGI 25 +#define WNI_CFG_FIXED_RATE_57_8MBPS_MCS5_20MHZ_SIMO_SGI 26 +#define WNI_CFG_FIXED_RATE_65MBPS_MCS6_20MHZ_SIMO_SGI 27 +#define WNI_CFG_FIXED_RATE_72_2MBPS_MCS7_20MHZ_SIMO_SGI 28 +#define WNI_CFG_FIXED_RATE_0_25MBPS_SLR_20MHZ_SIMO 29 +#define WNI_CFG_FIXED_RATE_0_5MBPS_SLR_20MHZ_SIMO 30 +#define WNI_CFG_FIXED_RATE_68_25MBPS_QC_PROP_20MHZ_SIMO 31 +#define WNI_CFG_FIXED_RATE_54MBPS_MCS3_40MHZ_SIMO 32 +#define WNI_CFG_FIXED_RATE_81MBPS_MCS4_40MHZ_SIMO 33 +#define WNI_CFG_FIXED_RATE_108MBPS_MCS5_40MHZ_SIMO 34 +#define WNI_CFG_FIXED_RATE_121_5MBPS_MCS6_40MHZ_SIMO 35 +#define WNI_CFG_FIXED_RATE_135MBPS_MCS7_40MHZ_SIMO 36 +#define WNI_CFG_FIXED_RATE_15MBPS_MCS0_40MHZ_SIMO_SGI 37 +#define WNI_CFG_FIXED_RATE_30MBPS_MCS1_40MHZ_SIMO_SGI 38 +#define WNI_CFG_FIXED_RATE_45MBPS_MCS2_40MHZ_SIMO_SGI 39 +#define WNI_CFG_FIXED_RATE_60MBPS_MCS3_40MHZ_SIMO_SGI 40 +#define WNI_CFG_FIXED_RATE_90MBPS_MCS4_40MHZ_SIMO_SGI 41 +#define WNI_CFG_FIXED_RATE_120MBPS_MCS5_40MHZ_SIMO_SGI 42 +#define WNI_CFG_FIXED_RATE_135MBPS_MCS6_40MHZ_SIMO_SGI 43 +#define WNI_CFG_FIXED_RATE_150MBPS_MCS7_40MHZ_SIMO_SGI 44 + +#define WNI_CFG_RETRYRATE_POLICY_MIN_SUPPORTED 0 +#define WNI_CFG_RETRYRATE_POLICY_PRIMARY 1 +#define WNI_CFG_RETRYRATE_POLICY_RESERVED 2 +#define WNI_CFG_RETRYRATE_POLICY_CLOSEST 3 +#define WNI_CFG_RETRYRATE_POLICY_AUTOSELECT 4 +#define WNI_CFG_RETRYRATE_POLICY_MAX 5 + +#define WNI_CFG_APSD_ENABLED_STAMIN 0 +#define WNI_CFG_APSD_ENABLED_STAMAX 1 +#define WNI_CFG_APSD_ENABLED_STADEF 0 + +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMIN 0 +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMAX 1 +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STADEF 1 + +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMIN 0 +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMAX 1 +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STADEF 1 + +#define WNI_CFG_AUTHENTICATION_TYPE_STAMIN 0 +#define WNI_CFG_AUTHENTICATION_TYPE_STAMAX 65535 +#define WNI_CFG_AUTHENTICATION_TYPE_STADEF 0 + +#define WNI_CFG_PRIVACY_ENABLED_STAMIN 0 +#define WNI_CFG_PRIVACY_ENABLED_STAMAX 1 +#define WNI_CFG_PRIVACY_ENABLED_STADEF 0 + +#define WNI_CFG_SHORT_PREAMBLE_STAMIN 0 +#define WNI_CFG_SHORT_PREAMBLE_STAMAX 1 +#define WNI_CFG_SHORT_PREAMBLE_STADEF 1 + +#define WNI_CFG_SHORT_SLOT_TIME_STAMIN 0 +#define WNI_CFG_SHORT_SLOT_TIME_STAMAX 1 +#define WNI_CFG_SHORT_SLOT_TIME_STADEF 1 + +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMIN 0 +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMAX 1 +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STADEF 0 + +#define WNI_CFG_QOS_ENABLED_STAMIN 0 +#define WNI_CFG_QOS_ENABLED_STAMAX 1 +#define WNI_CFG_QOS_ENABLED_STADEF 0 + +#define WNI_CFG_HCF_ENABLED_STAMIN 0 +#define WNI_CFG_HCF_ENABLED_STAMAX 1 +#define WNI_CFG_HCF_ENABLED_STADEF 0 + +#define WNI_CFG_RSN_ENABLED_STAMIN 0 +#define WNI_CFG_RSN_ENABLED_STAMAX 1 +#define WNI_CFG_RSN_ENABLED_STADEF 0 + +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STAMIN 0 +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STAMAX 180000 +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STADEF 5000 + +#define WNI_CFG_MAX_NUM_PRE_AUTH_STAMIN 0 +#define WNI_CFG_MAX_NUM_PRE_AUTH_STAMAX 256 +#define WNI_CFG_MAX_NUM_PRE_AUTH_STADEF 64 + +#define WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN 0 +#define WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX 65535 +#define WNI_CFG_HEART_BEAT_THRESHOLD_STADEF 40 + +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMIN 10 +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMAX 10000 +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STADEF 70 + +#define WNI_CFG_11D_ENABLED_STAMIN 0 +#define WNI_CFG_11D_ENABLED_STAMAX 1 +#define WNI_CFG_11D_ENABLED_STADEF 1 + +#define WNI_CFG_NETWORK_DENSITY_LOW 0 +#define WNI_CFG_NETWORK_DENSITY_MEDIUM 1 +#define WNI_CFG_NETWORK_DENSITY_HIGH 2 +#define WNI_CFG_NETWORK_DENSITY_ADAPTIVE 3 + +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_CARRIER 1 +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_CORRELATION 2 + +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN 0 +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX 128 +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STADEF 27 + + + +#define WNI_CFG_NEW_BSS_FOUND_IND_STAMIN 0 +#define WNI_CFG_NEW_BSS_FOUND_IND_STAMAX 1 +#define WNI_CFG_NEW_BSS_FOUND_IND_STADEF 0 + +#define WNI_CFG_11H_ENABLED_STAMIN 0 +#define WNI_CFG_11H_ENABLED_STAMAX 1 +#define WNI_CFG_11H_ENABLED_STADEF 1 + +#define WNI_CFG_WT_CNF_TIMEOUT_STAMIN 10 +#define WNI_CFG_WT_CNF_TIMEOUT_STAMAX 3000 +#define WNI_CFG_WT_CNF_TIMEOUT_STADEF 1000 + +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STAMIN 1000 +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STAMAX 30000 +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STADEF 10000 + +#define WNI_CFG_PROTECTION_ENABLED_STAMIN 0 +#define WNI_CFG_PROTECTION_ENABLED_STAMAX 65535 +#define WNI_CFG_PROTECTION_ENABLED_STADEF 65535 + +#define WNI_CFG_PROTECTION_ENABLED_FROM_llA 0 +#define WNI_CFG_PROTECTION_ENABLED_FROM_llB 1 +#define WNI_CFG_PROTECTION_ENABLED_FROM_llG 2 +#define WNI_CFG_PROTECTION_ENABLED_HT_20 3 +#define WNI_CFG_PROTECTION_ENABLED_NON_GF 4 +#define WNI_CFG_PROTECTION_ENABLED_LSIG_TXOP 5 +#define WNI_CFG_PROTECTION_ENABLED_RIFS 6 +#define WNI_CFG_PROTECTION_ENABLED_OBSS 7 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llA 8 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llB 9 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llG 10 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_HT20 11 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_NON_GF 12 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_LSIG_TXOP 13 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_RIFS 14 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_OBSS 15 + +#define WNI_CFG_11G_PROTECTION_ALWAYS_STAMIN 0 +#define WNI_CFG_11G_PROTECTION_ALWAYS_STAMAX 1 +#define WNI_CFG_11G_PROTECTION_ALWAYS_STADEF 0 + +#define WNI_CFG_FORCE_POLICY_PROTECTION_STAMIN 0 +#define WNI_CFG_FORCE_POLICY_PROTECTION_STAMAX 5 +#define WNI_CFG_FORCE_POLICY_PROTECTION_STADEF 5 + +#define WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE 0 +#define WNI_CFG_FORCE_POLICY_PROTECTION_CTS 1 +#define WNI_CFG_FORCE_POLICY_PROTECTION_RTS 2 +#define WNI_CFG_FORCE_POLICY_PROTECTION_DUAL_CTS 3 +#define WNI_CFG_FORCE_POLICY_PROTECTION_RTS_ALWAYS 4 +#define WNI_CFG_FORCE_POLICY_PROTECTION_AUTO 5 + +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMIN 0 +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMAX 1 +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STADEF 0 + +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMIN 0 +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMAX 1 +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STADEF 1 + +#define WNI_CFG_11G_ONLY_POLICY_STAMIN 0 +#define WNI_CFG_11G_ONLY_POLICY_STAMAX 1 +#define WNI_CFG_11G_ONLY_POLICY_STADEF 0 + +#define WNI_CFG_WME_ENABLED_STAMIN 0 +#define WNI_CFG_WME_ENABLED_STAMAX 1 +#define WNI_CFG_WME_ENABLED_STADEF 1 + +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STAMIN 0 +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STAMAX 65535 +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STADEF 1000 + +#define WNI_CFG_MAX_SP_LENGTH_STAMIN 0 +#define WNI_CFG_MAX_SP_LENGTH_STAMAX 3 +#define WNI_CFG_MAX_SP_LENGTH_STADEF 0 + +#define WNI_CFG_WSM_ENABLED_STAMIN 0 +#define WNI_CFG_WSM_ENABLED_STAMAX 1 +#define WNI_CFG_WSM_ENABLED_STADEF 0 + +#define WNI_CFG_EDCA_PROFILE_STAMIN 0 +#define WNI_CFG_EDCA_PROFILE_STAMAX 255 +#define WNI_CFG_EDCA_PROFILE_STADEF 1 + +#define WNI_CFG_EDCA_PROFILE_ANI 0 +#define WNI_CFG_EDCA_PROFILE_WMM 1 +#define WNI_CFG_EDCA_PROFILE_TIT_DEMO 2 +#define WNI_CFG_EDCA_PROFILE_ETSI_EUROPE 3 +#define WNI_CFG_EDCA_PROFILE_MAX 4 +#define WNI_CFG_EDCA_PROFILE_ACM_IDX 0 +#define WNI_CFG_EDCA_PROFILE_AIFSN_IDX 1 +#define WNI_CFG_EDCA_PROFILE_CWMINA_IDX 2 +#define WNI_CFG_EDCA_PROFILE_CWMAXA_IDX 4 +#define WNI_CFG_EDCA_PROFILE_TXOPA_IDX 6 +#define WNI_CFG_EDCA_PROFILE_CWMINB_IDX 7 +#define WNI_CFG_EDCA_PROFILE_CWMAXB_IDX 9 +#define WNI_CFG_EDCA_PROFILE_TXOPB_IDX 11 +#define WNI_CFG_EDCA_PROFILE_CWMING_IDX 12 +#define WNI_CFG_EDCA_PROFILE_CWMAXG_IDX 14 +#define WNI_CFG_EDCA_PROFILE_TXOPG_IDX 16 + +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMIN 0 +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMAX 255 +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STADEF 0 + +#define WNI_CFG_ADMIT_POLICY_STAMIN 0 +#define WNI_CFG_ADMIT_POLICY_STAMAX 2 +#define WNI_CFG_ADMIT_POLICY_STADEF 0 + +#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_ADMIT_BWFACTOR_STAMIN 0 +#define WNI_CFG_ADMIT_BWFACTOR_STAMAX 100 +#define WNI_CFG_ADMIT_BWFACTOR_STADEF 20 + +#define WNI_CFG_CHANNEL_BONDING_MODE_STAMIN 0 +#define WNI_CFG_CHANNEL_BONDING_MODE_STAMAX 10 +#define WNI_CFG_CHANNEL_BONDING_MODE_STADEF 1 + +#define WNI_CFG_CHANNEL_BONDING_MODE_DISABLE 0 +#define WNI_CFG_CHANNEL_BONDING_MODE_ENABLE 1 +#define WNI_CFG_CHANNEL_BONDING_MODE_IF_NO_LEGACY_BSS 2 +#define WNI_CFG_CHANNEL_BONDING_MODE_IF_NO_LEGACY_ALL 3 +#define WNI_CFG_CHANNEL_BONDING_MODE_INTELLIGENT 4 + +#define WNI_CFG_BLOCK_ACK_ENABLED_STAMIN 0 +#define WNI_CFG_BLOCK_ACK_ENABLED_STAMAX 3 +#define WNI_CFG_BLOCK_ACK_ENABLED_STADEF 0 + +#define WNI_CFG_BLOCK_ACK_ENABLED_DELAYED 0 +#define WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE 1 + +#define WNI_CFG_HT_RX_STBC_STAMIN 0 +#define WNI_CFG_HT_RX_STBC_STAMAX 3 +#define WNI_CFG_HT_RX_STBC_STADEF 1 + +#define WNI_CFG_HT_CAP_INFO_STAMIN 0 +#define WNI_CFG_HT_CAP_INFO_STAMAX 65535 +#define WNI_CFG_HT_CAP_INFO_STADEF 364 + +#define WNI_CFG_HT_CAP_INFO_ADVANCE_CODING 0 +#define WNI_CFG_HT_CAP_INFO_SUPPORTED_CHAN_WIDTH_SET 1 +#define WNI_CFG_HT_CAP_INFO_SM_POWER_SAVE 2 +#define WNI_CFG_HT_CAP_INFO_GREEN_FIELD 4 +#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_HT_CAP_INFO_DELAYED_BA 10 +#define WNI_CFG_HT_CAP_INFO_MAX_AMSDU_SIZE 11 +#define WNI_CFG_HT_CAP_INFO_DSSS_CCK_MODE_40MHZ 12 +#define WNI_CFG_HT_CAP_INFO_PSMP 13 +#define WNI_CFG_HT_CAP_INFO_STBC_CONTROL_FRAME 14 +#define WNI_CFG_HT_CAP_INFO_LSIG_TXOP_PROTECTION 15 + +#define WNI_CFG_HT_AMPDU_PARAMS_STAMIN 0 +#define WNI_CFG_HT_AMPDU_PARAMS_STAMAX 255 +#define WNI_CFG_HT_AMPDU_PARAMS_STADEF 0 + +#define WNI_CFG_HT_AMPDU_PARAMS_MAX_RX_AMPDU_FACTOR 0 +#define WNI_CFG_HT_AMPDU_PARAMS_MPDU_DENSITY 2 +#define WNI_CFG_HT_AMPDU_PARAMS_RESERVED 5 + +#define WNI_CFG_EXT_HT_CAP_INFO_STAMIN 0 +#define WNI_CFG_EXT_HT_CAP_INFO_STAMAX 65535 +#define WNI_CFG_EXT_HT_CAP_INFO_STADEF 1024 + +#define WNI_CFG_EXT_HT_CAP_INFO_PCO 0 +#define WNI_CFG_EXT_HT_CAP_INFO_TRANSITION_TIME 1 +#define WNI_CFG_EXT_HT_CAP_INFO_RESERVED1 3 +#define WNI_CFG_EXT_HT_CAP_INFO_MCS_FEEDBACK 8 +#define WNI_CFG_EXT_HT_CAP_INFO_HTC_SUPPORT 10 +#define WNI_CFG_EXT_HT_CAP_INFO_RD_RESPONDER 11 +#define WNI_CFG_EXT_HT_CAP_INFO_RESERVED2 12 + +#define WNI_CFG_TX_BF_CAP_STAMIN 0 +#define WNI_CFG_TX_BF_CAP_STAMAX 4294967295 +#define WNI_CFG_TX_BF_CAP_STADEF 0 + +#define WNI_CFG_AS_CAP_STAMIN 0 +#define WNI_CFG_AS_CAP_STAMAX 255 +#define WNI_CFG_AS_CAP_STADEF 0 + +#define WNI_CFG_AS_CAP_ANTENNA_SELECTION 0 +#define WNI_CFG_AS_CAP_EXPLICIT_CSI_FEEDBACK_TX 1 +#define WNI_CFG_AS_CAP_ANTENNA_INDICES_FEEDBACK_TX 2 +#define WNI_CFG_AS_CAP_EXPLICIT_CSI_FEEDBACK 3 +#define WNI_CFG_AS_CAP_ANTENNA_INDICES_FEEDBACK 4 +#define WNI_CFG_AS_CAP_RX_AS 5 +#define WNI_CFG_AS_CAP_TX_SOUNDING_PPDUS 6 +#define WNI_CFG_AS_CAP_RESERVED 7 + +#define WNI_CFG_HT_INFO_FIELD1_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD1_STAMAX 255 +#define WNI_CFG_HT_INFO_FIELD1_STADEF 15 + +#define WNI_CFG_HT_INFO_FIELD1_SECONDARY_CHANNEL_OFFSET 0 +#define WNI_CFG_HT_INFO_FIELD1_RECOMMENDED_CHANNEL_WIDTH 2 +#define WNI_CFG_HT_INFO_FIELD1_RIFS_MODE 3 +#define WNI_CFG_HT_INFO_FIELD1_PSMP_ACCESS_ONLY 4 +#define WNI_CFG_HT_INFO_FIELD1_SERVICE_INTERVAL_GRANULARITY 5 + +#define WNI_CFG_HT_INFO_FIELD2_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD2_STAMAX 65535 +#define WNI_CFG_HT_INFO_FIELD2_STADEF 0 + +#define WNI_CFG_HT_INFO_FIELD2_OP_MODE 0 +#define WNI_CFG_HT_INFO_FIELD2_NON_GF_DEVICES_PRESENT 2 +#define WNI_CFG_HT_INFO_FIELD2_RESERVED 3 + +#define WNI_CFG_HT_INFO_FIELD3_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD3_STAMAX 65535 +#define WNI_CFG_HT_INFO_FIELD3_STADEF 0 + +#define WNI_CFG_HT_INFO_FIELD3_BASIC_STBC_MCS 0 +#define WNI_CFG_HT_INFO_FIELD3_DUAL_STBC_PROTECTION 7 +#define WNI_CFG_HT_INFO_FIELD3_SECONDARY_BEACON 8 +#define WNI_CFG_HT_INFO_FIELD3_LSIG_TXOP_PROTECTION_FULL_SUPPORT 9 +#define WNI_CFG_HT_INFO_FIELD3_PCO_ACTIVE 10 +#define WNI_CFG_HT_INFO_FIELD3_PCO_PHASE 11 +#define WNI_CFG_HT_INFO_FIELD3_RESERVED 12 + +#define WNI_CFG_GREENFIELD_CAPABILITY_STAMIN 0 +#define WNI_CFG_GREENFIELD_CAPABILITY_STAMAX 1 +#define WNI_CFG_GREENFIELD_CAPABILITY_STADEF 0 + +#define WNI_CFG_GREENFIELD_CAPABILITY_ENABLE 1 +#define WNI_CFG_GREENFIELD_CAPABILITY_DISABLE 0 + +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMIN 0 +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMAX 2 +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STADEF 0 + +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMIN 0 +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMAX 2 +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STADEF 0 + +#define WNI_CFG_VHT_LDPC_CODING_CAP_STAMIN 0 +#define WNI_CFG_VHT_LDPC_CODING_CAP_STAMAX 1 +#define WNI_CFG_VHT_LDPC_CODING_CAP_STADEF 0 + +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STAMIN 0 +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STAMAX 1 +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STADEF 1 + +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMIN 0 +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMAX 1 +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STADEF 0 + +#define WNI_CFG_VHT_TXSTBC_STAMIN 0 +#define WNI_CFG_VHT_TXSTBC_STAMAX 1 +#define WNI_CFG_VHT_TXSTBC_STADEF 0 + +#define WNI_CFG_VHT_RXSTBC_STAMIN 0 +#define WNI_CFG_VHT_RXSTBC_STAMAX 1 +#define WNI_CFG_VHT_RXSTBC_STADEF 1 + +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMIN 0 +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMAX 1 +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STADEF 0 + +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN 0 +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX 1 +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF 1 + +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN 0 +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX 8 +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF 8 +/* + * 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_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF 3 + +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMIN 0 +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMAX 3 +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STADEF 0 + +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMIN 0 +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMAX 1 +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STADEF 0 + +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMIN 0 +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMAX 1 +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STADEF 0 + +#define WNI_CFG_VHT_TXOP_PS_STAMIN 0 +#define WNI_CFG_VHT_TXOP_PS_STAMAX 1 +#define WNI_CFG_VHT_TXOP_PS_STADEF 0 + +#define WNI_CFG_VHT_HTC_VHTC_CAP_STAMIN 0 +#define WNI_CFG_VHT_HTC_VHTC_CAP_STAMAX 1 +#define WNI_CFG_VHT_HTC_VHTC_CAP_STADEF 0 + +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMIN 0 +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMAX 7 +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STADEF 3 + +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMIN 0 +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMAX 3 +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STADEF 0 + +#define WNI_CFG_VHT_RX_ANT_PATTERN_STAMIN 0 +#define WNI_CFG_VHT_RX_ANT_PATTERN_STAMAX 1 +#define WNI_CFG_VHT_RX_ANT_PATTERN_STADEF 1 + +#define WNI_CFG_VHT_TX_ANT_PATTERN_STAMIN 0 +#define WNI_CFG_VHT_TX_ANT_PATTERN_STAMAX 1 +#define WNI_CFG_VHT_TX_ANT_PATTERN_STADEF 1 + +#define WNI_CFG_VHT_RX_MCS_MAP_STAMIN 0 +#define WNI_CFG_VHT_RX_MCS_MAP_STAMAX 65535 +#define WNI_CFG_VHT_RX_MCS_MAP_STADEF 65534 + +#define WNI_CFG_VHT_TX_MCS_MAP_STAMIN 0 +#define WNI_CFG_VHT_TX_MCS_MAP_STAMAX 65535 +#define WNI_CFG_VHT_TX_MCS_MAP_STADEF 65534 + +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN 0 +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX 780 +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STADEF 780 + +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN 0 +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX 780 +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STADEF 780 + +#define WNI_CFG_VHT_BASIC_MCS_SET_STAMIN 0 +#define WNI_CFG_VHT_BASIC_MCS_SET_STAMAX 65535 +#define WNI_CFG_VHT_BASIC_MCS_SET_STADEF 65534 + +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMIN 0 +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMAX 4 +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STADEF 0 + +#define WNI_CFG_VHT_SS_UNDER_UTIL_STAMIN 0 +#define WNI_CFG_VHT_SS_UNDER_UTIL_STAMAX 0 +#define WNI_CFG_VHT_SS_UNDER_UTIL_STADEF 0 + +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_MAX_AMSDU_LENGTH_STAMIN 0 +#define WNI_CFG_MAX_AMSDU_LENGTH_STAMAX 1 +#define WNI_CFG_MAX_AMSDU_LENGTH_STADEF 0 + +#define WNI_CFG_MAX_AMSDU_LENGTH_SHORT_3839_BYTES 0 +#define WNI_CFG_MAX_AMSDU_LENGTH_LONG_7935__BYTES 1 + +#define WNI_CFG_MPDU_DENSITY_STAMIN 0 +#define WNI_CFG_MPDU_DENSITY_STAMAX 7 +#define WNI_CFG_MPDU_DENSITY_STADEF 7 + +#define WNI_CFG_NUM_BUFF_ADVERT_STAMIN 0 +#define WNI_CFG_NUM_BUFF_ADVERT_STAMAX 128 +#define WNI_CFG_NUM_BUFF_ADVERT_STADEF 64 + +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN 0 +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX 3 +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STADEF 3 + +#define WNI_CFG_SHORT_GI_20MHZ_STAMIN 0 +#define WNI_CFG_SHORT_GI_20MHZ_STAMAX 1 +#define WNI_CFG_SHORT_GI_20MHZ_STADEF 1 + +#define WNI_CFG_SHORT_GI_20MHZ_ENABLE 1 +#define WNI_CFG_SHORT_GI_20MHZ_DISABLE 0 + +#define WNI_CFG_SHORT_GI_40MHZ_STAMIN 0 +#define WNI_CFG_SHORT_GI_40MHZ_STAMAX 1 +#define WNI_CFG_SHORT_GI_40MHZ_STADEF 0 + +#define WNI_CFG_SHORT_GI_40MHZ_ENABLE 1 +#define WNI_CFG_SHORT_GI_40MHZ_DISABLE 0 + +#define WNI_CFG_MAX_PS_POLL_STAMIN 0 +#define WNI_CFG_MAX_PS_POLL_STAMAX 255 +#define WNI_CFG_MAX_PS_POLL_STADEF 0 + +#define WNI_CFG_SCAN_IN_POWERSAVE_STAMIN 0 +#define WNI_CFG_SCAN_IN_POWERSAVE_STAMAX 1 +#define WNI_CFG_SCAN_IN_POWERSAVE_STADEF 1 + +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMIN 0 +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMAX 65535 +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STADEF 40 + +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMIN 0 +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMAX 65535 +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STADEF 65535 + +#define WNI_CFG_IBSS_AUTO_BSSID_STAMIN 0 +#define WNI_CFG_IBSS_AUTO_BSSID_STAMAX 1 +#define WNI_CFG_IBSS_AUTO_BSSID_STADEF 1 + +#define WNI_CFG_WPS_ENABLE_STAMIN 0 +#define WNI_CFG_WPS_ENABLE_STAMAX 255 +#define WNI_CFG_WPS_ENABLE_STADEF 0 + +#define WNI_CFG_WPS_ENABLE_AP 1 +#define WNI_CFG_WPS_ENABLE_STA 2 + +#define WNI_CFG_WPS_STATE_STAMIN 0 +#define WNI_CFG_WPS_STATE_STAMAX 255 +#define WNI_CFG_WPS_STATE_STADEF 1 + +#define WNI_CFG_WPS_VERSION_STAMIN 0 +#define WNI_CFG_WPS_VERSION_STAMAX 255 +#define WNI_CFG_WPS_VERSION_STADEF 16 + +#define WNI_CFG_WPS_CFG_METHOD_STAMIN 0 +#define WNI_CFG_WPS_CFG_METHOD_STAMAX 4294967295 +#define WNI_CFG_WPS_CFG_METHOD_STADEF 8 + +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMIN 0 +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMAX 65535 +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STADEF 1 + +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMIN 0 +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMAX 4294967295 +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STADEF 5304836 + +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMIN 0 +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMAX 65535 +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STADEF 1 + +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMIN 0 +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMAX 4294967295 +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STADEF 0 + +#define WNI_CFG_SINGLE_TID_RC_STAMIN 0 +#define WNI_CFG_SINGLE_TID_RC_STAMAX 1 +#define WNI_CFG_SINGLE_TID_RC_STADEF 1 + +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STAMIN 0 +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STAMAX 1 +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STADEF 0 + +#define WNI_CFG_TELE_BCN_MAX_LI_STAMIN 0 +#define WNI_CFG_TELE_BCN_MAX_LI_STAMAX 7 +#define WNI_CFG_TELE_BCN_MAX_LI_STADEF 5 + +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMIN 0 +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX 1000 +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STADEF 0 + +#define WNI_CFG_ASSOC_STA_LIMIT_STAMIN 1 +#define WNI_CFG_ASSOC_STA_LIMIT_STAMAX 32 +#define WNI_CFG_ASSOC_STA_LIMIT_STADEF 10 + +#define WNI_CFG_ENABLE_LTE_COEX_STAMIN 0 +#define WNI_CFG_ENABLE_LTE_COEX_STAMAX 1 +#define WNI_CFG_ENABLE_LTE_COEX_STADEF 0 + +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN 1 +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF 20 + +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN 1 +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF 20 + +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STAMIN 0 +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STAMAX 1 +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STADEF 0 + +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN 0 +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX 1 +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF 0 + +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMIN 0 +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMAX 1 +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STADEF 0 + +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMIN 1 +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMAX 255 +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STADEF 3 + +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMIN 0 +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMAX 15 +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STADEF 0 + +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STADEF 0 + +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMIN 0 +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMAX 10 +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STADEF 0 + +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMIN 10 +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMAX 20 +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STADEF 10 + +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMIN 0 +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMAX 20 +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STADEF 5 + +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN 10 +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMAX 2000 +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF 200 + +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMIN 3 +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX 50 +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF 10 + +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN 100 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX 1000 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF 300 + +#define WNI_CFG_CURRENT_RSSI_STAMIN 0 +#define WNI_CFG_CURRENT_RSSI_STAMAX 127 +#define WNI_CFG_CURRENT_RSSI_STADEF 0 + +#define WNI_CFG_RTT3_ENABLE_STAMIN 0 +#define WNI_CFG_RTT3_ENABLE_STAMAX 1 +#define WNI_CFG_RTT3_ENABLE_STADEF 1 + +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMIN 0 +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMAX 1 +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STADEF 0 + +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STADEF 0 + +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMIN 0 +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMAX 100 +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STADEF 0 + +#define WNI_CFG_DFS_MASTER_ENABLED_STAMIN 0 +#define WNI_CFG_DFS_MASTER_ENABLED_STAMAX 1 +#define WNI_CFG_DFS_MASTER_ENABLED_STADEF 0 + +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMIN 0 +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMAX 1 +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STADEF 0 + +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STADEF 0 + +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMIN 5 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMAX 1000 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STADEF 20 + +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMIN 10 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMAX 1000 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STADEF 10 + +#define WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMIN 10 +#define WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMAX 900 +#define WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STADEF 200 + +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMIN 200 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMAX 10000 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STADEF 200 + +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMIN 20 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMAX 10000 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STADEF 20 + +#define WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMIN 5 +#define WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMAX 100 +#define WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STADEF 5 + +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMIN 0 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMAX 100 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STADEF 25 + +#define WNI_CFG_TGT_GTX_USR_CFG_STAMIN 0 +#define WNI_CFG_TGT_GTX_USR_CFG_STAMAX 32 +#define WNI_CFG_TGT_GTX_USR_CFG_STADEF 32 + +#define WNI_CFG_MAX_HT_MCS_TX_DATA_STAMIN 0x0 +#define WNI_CFG_MAX_HT_MCS_TX_DATA_STAMAX 0x17f +#define WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF 0x0 + +#define WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMIN 0 +#define WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMAX 1 +#define WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF 0 + +#define WNI_CFG_RATE_FOR_TX_MGMT_STAMIN 0x0 +#define WNI_CFG_RATE_FOR_TX_MGMT_STAMAX 0xFF +#define WNI_CFG_RATE_FOR_TX_MGMT_STADEF 0xFF + +#define WNI_CFG_HE_CONTROL_STAMIN 0 +#define WNI_CFG_HE_CONTROL_STAMAX 1 +#define WNI_CFG_HE_CONTROL_STADEF 0 + +#define WNI_CFG_HE_TWT_REQUESTOR_STAMIN 0 +#define WNI_CFG_HE_TWT_REQUESTOR_STAMAX 1 +#define WNI_CFG_HE_TWT_REQUESTOR_STADEF 0 + +#define WNI_CFG_HE_TWT_RESPONDER_STAMIN 0 +#define WNI_CFG_HE_TWT_RESPONDER_STAMAX 1 +#define WNI_CFG_HE_TWT_RESPONDER_STADEF 0 + +#define WNI_CFG_HE_FRAGMENTATION_STAMIN 0 +#define WNI_CFG_HE_FRAGMENTATION_STAMAX 0x3 +#define WNI_CFG_HE_FRAGMENTATION_STADEF 0 + +#define WNI_CFG_HE_MAX_FRAG_MSDU_STAMIN 0 +#define WNI_CFG_HE_MAX_FRAG_MSDU_STAMAX 0x7 +#define WNI_CFG_HE_MAX_FRAG_MSDU_STADEF 0 + +#define WNI_CFG_HE_MIN_FRAG_SIZE_STAMIN 0 +#define WNI_CFG_HE_MIN_FRAG_SIZE_STAMAX 0x3 +#define WNI_CFG_HE_MIN_FRAG_SIZE_STADEF 0 + +#define WNI_CFG_HE_TRIG_PAD_STAMIN 0 +#define WNI_CFG_HE_TRIG_PAD_STAMAX 2 +#define WNI_CFG_HE_TRIG_PAD_STADEF 0 + +#define WNI_CFG_HE_MTID_AGGR_STAMIN 0 +#define WNI_CFG_HE_MTID_AGGR_STAMAX 0x7 +#define WNI_CFG_HE_MTID_AGGR_STADEF 0 + +#define WNI_CFG_HE_LINK_ADAPTATION_STAMIN 0 +#define WNI_CFG_HE_LINK_ADAPTATION_STAMAX 0x3 +#define WNI_CFG_HE_LINK_ADAPTATION_STADEF 0 + +#define WNI_CFG_HE_ALL_ACK_STAMIN 0 +#define WNI_CFG_HE_ALL_ACK_STAMAX 1 +#define WNI_CFG_HE_ALL_ACK_STADEF 0 + +#define WNI_CFG_HE_UL_MU_RSP_SCHEDULING_STAMIN 0 +#define WNI_CFG_HE_UL_MU_RSP_SCHEDULING_STAMAX 1 +#define WNI_CFG_HE_UL_MU_RSP_SCHEDULING_STADEF 0 + +#define WNI_CFG_HE_BUFFER_STATUS_RPT_STAMIN 0 +#define WNI_CFG_HE_BUFFER_STATUS_RPT_STAMAX 1 +#define WNI_CFG_HE_BUFFER_STATUS_RPT_STADEF 0 + +#define WNI_CFG_HE_BCAST_TWT_STAMIN 0 +#define WNI_CFG_HE_BCAST_TWT_STAMAX 1 +#define WNI_CFG_HE_BCAST_TWT_STADEF 0 + +#define WNI_CFG_HE_BA_32BIT_STAMIN 0 +#define WNI_CFG_HE_BA_32BIT_STAMAX 1 +#define WNI_CFG_HE_BA_32BIT_STADEF 0 + +#define WNI_CFG_HE_MU_CASCADING_STAMIN 0 +#define WNI_CFG_HE_MU_CASCADING_STAMAX 1 +#define WNI_CFG_HE_MU_CASCADING_STADEF 0 + +#define WNI_CFG_HE_MULTI_TID_STAMIN 0 +#define WNI_CFG_HE_MULTI_TID_STAMAX 1 +#define WNI_CFG_HE_MULTI_TID_STADEF 0 + +#define WNI_CFG_HE_DL_MU_BA_STAMIN 0 +#define WNI_CFG_HE_DL_MU_BA_STAMAX 1 +#define WNI_CFG_HE_DL_MU_BA_STADEF 0 + +#define WNI_CFG_HE_OMI_STAMIN 0 +#define WNI_CFG_HE_OMI_STAMAX 1 +#define WNI_CFG_HE_OMI_STADEF 0 + +#define WNI_CFG_HE_OFDMA_RA_STAMIN 0 +#define WNI_CFG_HE_OFDMA_RA_STAMAX 1 +#define WNI_CFG_HE_OFDMA_RA_STADEF 0 + +#define WNI_CFG_HE_MAX_AMPDU_LEN_STAMIN 0 +#define WNI_CFG_HE_MAX_AMPDU_LEN_STAMAX 0x3 +#define WNI_CFG_HE_MAX_AMPDU_LEN_STADEF 0 + +#define WNI_CFG_HE_AMSDU_FRAG_STAMIN 0 +#define WNI_CFG_HE_AMSDU_FRAG_STAMAX 1 +#define WNI_CFG_HE_AMSDU_FRAG_STADEF 0 + +#define WNI_CFG_HE_FLEX_TWT_SCHED_STAMIN 0 +#define WNI_CFG_HE_FLEX_TWT_SCHED_STAMAX 1 +#define WNI_CFG_HE_FLEX_TWT_SCHED_STADEF 0 + +#define WNI_CFG_HE_RX_CTRL_STAMIN 0 +#define WNI_CFG_HE_RX_CTRL_STAMAX 1 +#define WNI_CFG_HE_RX_CTRL_STADEF 0 + +#define WNI_CFG_HE_BSRP_AMPDU_AGGR_STAMIN 0 +#define WNI_CFG_HE_BSRP_AMPDU_AGGR_STAMAX 1 +#define WNI_CFG_HE_BSRP_AMPDU_AGGR_STADEF 0 + +#define WNI_CFG_HE_QTP_STAMIN 0 +#define WNI_CFG_HE_QTP_STAMAX 1 +#define WNI_CFG_HE_QTP_STADEF 0 + +#define WNI_CFG_HE_A_BQR_STAMIN 0 +#define WNI_CFG_HE_A_BQR_STAMAX 1 +#define WNI_CFG_HE_A_BQR_STADEF 0 + +#define WNI_CFG_HE_SR_RESPONDER_STAMIN 0 +#define WNI_CFG_HE_SR_RESPONDER_STAMAX 1 +#define WNI_CFG_HE_SR_RESPONDER_STADEF 0 + +#define WNI_CFG_HE_NDP_FEEDBACK_SUPP_STAMIN 0 +#define WNI_CFG_HE_NDP_FEEDBACK_SUPP_STAMAX 1 +#define WNI_CFG_HE_NDP_FEEDBACK_SUPP_STADEF 0 + +#define WNI_CFG_HE_OPS_SUPP_STAMIN 0 +#define WNI_CFG_HE_OPS_SUPP_STAMAX 1 +#define WNI_CFG_HE_OPS_SUPP_STADEF 0 + +#define WNI_CFG_HE_AMSDU_IN_AMPDU_MIN 0 +#define WNI_CFG_HE_AMSDU_IN_AMPDU_MAX 1 +#define WNI_CFG_HE_AMSDU_IN_AMPDU_DEF 0 + +#define WNI_CFG_HE_DUAL_BAND_STAMIN 0 +#define WNI_CFG_HE_DUAL_BAND_STAMAX 1 +#define WNI_CFG_HE_DUAL_BAND_STADEF 1 + +#define WNI_CFG_HE_CHAN_WIDTH_STAMIN 0 +#define WNI_CFG_HE_CHAN_WIDTH_STAMAX 0x3F +#define WNI_CFG_HE_CHAN_WIDTH_STADEF 0 + +#define WNI_CFG_HE_RX_PREAM_PUNC_STAMIN 0 +#define WNI_CFG_HE_RX_PREAM_PUNC_STAMAX 0xF +#define WNI_CFG_HE_RX_PREAM_PUNC_STADEF 0 + +#define WNI_CFG_HE_CLASS_OF_DEVICE_STAMIN 0 +#define WNI_CFG_HE_CLASS_OF_DEVICE_STAMAX 1 +#define WNI_CFG_HE_CLASS_OF_DEVICE_STADEF 0 + +#define WNI_CFG_HE_LDPC_STAMIN 0 +#define WNI_CFG_HE_LDPC_STAMAX 1 +#define WNI_CFG_HE_LDPC_STADEF 0 + +#define WNI_CFG_HE_LTF_PPDU_STAMIN 0 +#define WNI_CFG_HE_LTF_PPDU_STAMAX 0x3 +#define WNI_CFG_HE_LTF_PPDU_STADEF 0 + +#define WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS_MIN 0 +#define WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS_MAX 0x3 +#define WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS_DEF 0 + +#define WNI_CFG_HE_LTF_NDP_STAMIN 0 +#define WNI_CFG_HE_LTF_NDP_STAMAX 0x3 +#define WNI_CFG_HE_LTF_NDP_STADEF 0 + +#define WNI_CFG_HE_TX_STBC_LT80_STAMIN 0 +#define WNI_CFG_HE_TX_STBC_LT80_STAMAX 1 +#define WNI_CFG_HE_TX_STBC_LT80_STADEF 0 + +#define WNI_CFG_HE_RX_STBC_LT80_STAMIN 0 +#define WNI_CFG_HE_RX_STBC_LT80_STAMAX 1 +#define WNI_CFG_HE_RX_STBC_LT80_STADEF 0 + +#define WNI_CFG_HE_DOPPLER_STAMIN 0 +#define WNI_CFG_HE_DOPPLER_STAMAX 0x3 +#define WNI_CFG_HE_DOPPLER_STADEF 0 + +#define WNI_CFG_HE_UL_MUMIMO_STAMIN 0 +#define WNI_CFG_HE_UL_MUMIMO_STAMAX 0x3 +#define WNI_CFG_HE_UL_MUMIMO_STADEF 0 + +#define WNI_CFG_HE_DCM_TX_STAMIN 0 +#define WNI_CFG_HE_DCM_TX_STAMAX 0x7 +#define WNI_CFG_HE_DCM_TX_STADEF 0 + +#define WNI_CFG_HE_DCM_RX_STAMIN 0 +#define WNI_CFG_HE_DCM_RX_STAMAX 0x7 +#define WNI_CFG_HE_DCM_RX_STADEF 0 + +#define WNI_CFG_HE_MU_PPDU_STAMIN 0 +#define WNI_CFG_HE_MU_PPDU_STAMAX 1 +#define WNI_CFG_HE_MU_PPDU_STADEF 0 + +#define WNI_CFG_HE_SU_BEAMFORMER_STAMIN 0 +#define WNI_CFG_HE_SU_BEAMFORMER_STAMAX 1 +#define WNI_CFG_HE_SU_BEAMFORMER_STADEF 0 + +#define WNI_CFG_HE_SU_BEAMFORMEE_STAMIN 0 +#define WNI_CFG_HE_SU_BEAMFORMEE_STAMAX 1 +#define WNI_CFG_HE_SU_BEAMFORMEE_STADEF 0 + +#define WNI_CFG_HE_MU_BEAMFORMER_STAMIN 0 +#define WNI_CFG_HE_MU_BEAMFORMER_STAMAX 1 +#define WNI_CFG_HE_MU_BEAMFORMER_STADEF 0 + +#define WNI_CFG_HE_BFEE_STS_LT80_STAMIN 0 +#define WNI_CFG_HE_BFEE_STS_LT80_STAMAX 0x7 +#define WNI_CFG_HE_BFEE_STS_LT80_STADEF 0 + +#define WNI_CFG_HE_BFEE_STS_GT80_STAMIN 0 +#define WNI_CFG_HE_BFEE_STS_GT80_STAMAX 0x7 +#define WNI_CFG_HE_BFEE_STS_GT80_STADEF 0 + +#define WNI_CFG_HE_NUM_SOUND_LT80_STAMIN 0 +#define WNI_CFG_HE_NUM_SOUND_LT80_STAMAX 0x7 +#define WNI_CFG_HE_NUM_SOUND_LT80_STADEF 0 + +#define WNI_CFG_HE_NUM_SOUND_GT80_STAMIN 0 +#define WNI_CFG_HE_NUM_SOUND_GT80_STAMAX 0x7 +#define WNI_CFG_HE_NUM_SOUND_GT80_STADEF 0 + +#define WNI_CFG_HE_SU_FEED_TONE16_STAMIN 0 +#define WNI_CFG_HE_SU_FEED_TONE16_STAMAX 1 +#define WNI_CFG_HE_SU_FEED_TONE16_STADEF 0 + +#define WNI_CFG_HE_MU_FEED_TONE16_STAMIN 0 +#define WNI_CFG_HE_MU_FEED_TONE16_STAMAX 1 +#define WNI_CFG_HE_MU_FEED_TONE16_STADEF 0 + +#define WNI_CFG_HE_CODEBOOK_SU_STAMIN 0 +#define WNI_CFG_HE_CODEBOOK_SU_STAMAX 1 +#define WNI_CFG_HE_CODEBOOK_SU_STADEF 0 + +#define WNI_CFG_HE_CODEBOOK_MU_STAMIN 0 +#define WNI_CFG_HE_CODEBOOK_MU_STAMAX 1 +#define WNI_CFG_HE_CODEBOOK_MU_STADEF 0 + +#define WNI_CFG_HE_BFRM_FEED_STAMIN 0 +#define WNI_CFG_HE_BFRM_FEED_STAMAX 0x7 +#define WNI_CFG_HE_BFRM_FEED_STADEF 0 + +#define WNI_CFG_HE_ER_SU_PPDU_STAMIN 0 +#define WNI_CFG_HE_ER_SU_PPDU_STAMAX 1 +#define WNI_CFG_HE_ER_SU_PPDU_STADEF 0 + +#define WNI_CFG_HE_DL_PART_BW_STAMIN 0 +#define WNI_CFG_HE_DL_PART_BW_STAMAX 1 +#define WNI_CFG_HE_DL_PART_BW_STADEF 0 + +#define WNI_CFG_HE_PPET_PRESENT_STAMIN 0 +#define WNI_CFG_HE_PPET_PRESENT_STAMAX 1 +#define WNI_CFG_HE_PPET_PRESENT_STADEF 0 + +#define WNI_CFG_HE_SRP_STAMIN 0 +#define WNI_CFG_HE_SRP_STAMAX 1 +#define WNI_CFG_HE_SRP_STADEF 0 + +#define WNI_CFG_HE_POWER_BOOST_STAMIN 0 +#define WNI_CFG_HE_POWER_BOOST_STAMAX 1 +#define WNI_CFG_HE_POWER_BOOST_STADEF 0 + +#define WNI_CFG_HE_4x_LTF_GI_STAMIN 0 +#define WNI_CFG_HE_4x_LTF_GI_STAMAX 1 +#define WNI_CFG_HE_4x_LTF_GI_STADEF 0 + +#define WNI_CFG_HE_MAX_NC_STAMIN 0 +#define WNI_CFG_HE_MAX_NC_STAMAX 0x7 +#define WNI_CFG_HE_MAX_NC_STADEF 0 + +#define WNI_CFG_HE_TX_STBC_GT80_STAMIN 0 +#define WNI_CFG_HE_TX_STBC_GT80_STAMAX 1 +#define WNI_CFG_HE_TX_STBC_GT80_STADEF 0 + +#define WNI_CFG_HE_RX_STBC_GT80_STAMIN 0 +#define WNI_CFG_HE_RX_STBC_GT80_STAMAX 1 +#define WNI_CFG_HE_RX_STBC_GT80_STADEF 0 + +#define WNI_CFG_HE_ER_4x_LTF_GI_STAMIN 0 +#define WNI_CFG_HE_ER_4x_LTF_GI_STAMAX 1 +#define WNI_CFG_HE_ER_4x_LTF_GI_STADEF 0 + +#define WNI_CFG_HE_PPDU_20_IN_40MHZ_2G_MIN 0 +#define WNI_CFG_HE_PPDU_20_IN_40MHZ_2G_MAX 1 +#define WNI_CFG_HE_PPDU_20_IN_40MHZ_2G_DEF 0 + +#define WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ_MIN 0 +#define WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ_MAX 1 +#define WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ_DEF 0 + +#define WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ_MIN 0 +#define WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ_MAX 1 +#define WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ_DEF 0 + +#define WNI_CFG_HE_ER_1X_HE_LTF_GI_MIN 0 +#define WNI_CFG_HE_ER_1X_HE_LTF_GI_MAX 1 +#define WNI_CFG_HE_ER_1X_HE_LTF_GI_DEF 0 + +#define WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF_MIN 0 +#define WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF_MAX 1 +#define WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF_DEF 0 + +#define WNI_CFG_HE_RX_MCS_MAP_LT_80_MIN 0x0000 +#define WNI_CFG_HE_RX_MCS_MAP_LT_80_MAX 0xFFFF +#define WNI_CFG_HE_RX_MCS_MAP_LT_80_DEF 0xFFF0 + +#define WNI_CFG_HE_TX_MCS_MAP_LT_80_MIN 0x0000 +#define WNI_CFG_HE_TX_MCS_MAP_LT_80_MAX 0xFFFF +#define WNI_CFG_HE_TX_MCS_MAP_LT_80_DEF 0xFFF0 + +#define WNI_CFG_HE_RX_MCS_MAP_160_MIN 0x0000 +#define WNI_CFG_HE_RX_MCS_MAP_160_MAX 0xFFFF +#define WNI_CFG_HE_RX_MCS_MAP_160_DEF 0xFFF0 + +#define WNI_CFG_HE_TX_MCS_MAP_160_MIN 0x0000 +#define WNI_CFG_HE_TX_MCS_MAP_160_MAX 0xFFFF +#define WNI_CFG_HE_TX_MCS_MAP_160_DEF 0xFFF0 + +#define WNI_CFG_HE_RX_MCS_MAP_80_80_MIN 0x0000 +#define WNI_CFG_HE_RX_MCS_MAP_80_80_MAX 0xFFFF +#define WNI_CFG_HE_RX_MCS_MAP_80_80_DEF 0xFFF0 + +#define WNI_CFG_HE_TX_MCS_MAP_80_80_MIN 0x0000 +#define WNI_CFG_HE_TX_MCS_MAP_80_80_MAX 0xFFFF +#define WNI_CFG_HE_TX_MCS_MAP_80_80_DEF 0xFFF0 + +#define WNI_CFG_HE_OPS_BSS_COLOR_MIN 0x01 +#define WNI_CFG_HE_OPS_BSS_COLOR_MAX 0x3F +#define WNI_CFG_HE_OPS_BSS_COLOR_DEF 0x01 + +#define WNI_CFG_HE_OPS_DEFAULT_PE_MIN 0x0 +#define WNI_CFG_HE_OPS_DEFAULT_PE_MAX 0x7 +#define WNI_CFG_HE_OPS_DEFAULT_PE_DEF 0x0 + +#define WNI_CFG_HE_OPS_TWT_REQUIRED_MIN 0 +#define WNI_CFG_HE_OPS_TWT_REQUIRED_MAX 1 +#define WNI_CFG_HE_OPS_TWT_REQUIRED_DEF 0 + +#define WNI_CFG_HE_OPS_RTS_THRESHOLD_MIN 0x000 +#define WNI_CFG_HE_OPS_RTS_THRESHOLD_MAX 0x3FF +#define WNI_CFG_HE_OPS_RTS_THRESHOLD_DEF 0x000 + +#define WNI_CFG_HE_OPS_PARTIAL_BSS_COL_MIN 0 +#define WNI_CFG_HE_OPS_PARTIAL_BSS_COL_MAX 1 +#define WNI_CFG_HE_OPS_PARTIAL_BSS_COL_DEF 0 + +#define WNI_CFG_HE_OPS_VHT_OPER_PRESENT_MIN 0 +#define WNI_CFG_HE_OPS_VHT_OPER_PRESENT_MAX 1 +#define WNI_CFG_HE_OPS_VHT_OPER_PRESENT_DEF 0 + +#define WNI_CFG_HE_OPS_MBSSID_AP_MIN 0 +#define WNI_CFG_HE_OPS_MBSSID_AP_MAX 1 +#define WNI_CFG_HE_OPS_MBSSID_AP_DEF 0 + +#define WNI_CFG_HE_OPS_TX_BSSID_IND_MIN 0 +#define WNI_CFG_HE_OPS_TX_BSSID_IND_MAX 1 +#define WNI_CFG_HE_OPS_TX_BSSID_IND_DEF 0 + +#define WNI_CFG_HE_OPS_BSS_COL_DISABLED_MIN 0 +#define WNI_CFG_HE_OPS_BSS_COL_DISABLED_MAX 1 +#define WNI_CFG_HE_OPS_BSS_COL_DISABLED_DEF 0 + +#define WNI_CFG_HE_OPS_BASIC_MCS_NSS_MIN 0x0000 +#define WNI_CFG_HE_OPS_BASIC_MCS_NSS_MAX 0xFFFF +#define WNI_CFG_HE_OPS_BASIC_MCS_NSS_DEF 0xFFFC + +#define WNI_CFG_HE_STA_OBSSPD_STAMIN 0 +#define WNI_CFG_HE_STA_OBSSPD_STAMAX 0xffffffff +#define WNI_CFG_HE_STA_OBSSPD_STADEF 0x15b8c2ae + +#define WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMIN 1 +#define WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMAX 255 +#define WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STADEF 50 + +#define WNI_CFG_SAP_MAX_MCS_DATA_STAMIN 0x0 +#define WNI_CFG_SAP_MAX_MCS_DATA_STAMAX 0x17f +#define WNI_CFG_SAP_MAX_MCS_DATA_STADEF 0x0 + +#define WNI_CFG_RATE_FOR_TX_MGMT_2G_STAMIN 0x0 +#define WNI_CFG_RATE_FOR_TX_MGMT_2G_STAMAX 0xFF +#define WNI_CFG_RATE_FOR_TX_MGMT_2G_STADEF 0xFF + +#define WNI_CFG_RATE_FOR_TX_MGMT_5G_STAMIN 0x0 +#define WNI_CFG_RATE_FOR_TX_MGMT_5G_STAMAX 0xFF +#define WNI_CFG_RATE_FOR_TX_MGMT_5G_STADEF 0xFF + +#define WNI_CFG_TWT_REQUESTOR_STAMIN 0 +#define WNI_CFG_TWT_REQUESTOR_STAMAX 1 +#define WNI_CFG_TWT_REQUESTOR_STADEF 0 + +#define WNI_CFG_TWT_RESPONDER_STAMIN 0 +#define WNI_CFG_TWT_RESPONDER_STAMAX 1 +#define WNI_CFG_TWT_RESPONDER_STADEF 0 + +#define WNI_CFG_BCAST_TWT_STAMIN 0 +#define WNI_CFG_BCAST_TWT_STAMAX 1 +#define WNI_CFG_BCAST_TWT_STADEF 0 + +#define CFG_STA_MAGIC_DWORD 0xbeefbeef + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/cfg.txt b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/cfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..62119d71c458b9597c084f5985dec50b435d68ab --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/cfg.txt @@ -0,0 +1,4043 @@ +* Copyright (c) 2014-2015 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 is the data definition file for the CFG module. +* Author: Kevin Nguyen +* Date: 03/18/02 +* History:- +* 03/18/02 Created. +* 08/10/05 ww: add maoe channels to have a complete channel listing: (see WNI_CFG_VALID_CHANNEL_LIST) +* 08/10/05 ww: WNI_CFG_SCAN_CONTROL_LIST has a new contents +* -------------------------------------------------------------------- + +********************************************************************** +* +* This file contains the descriptions of all configuration parameters +* for both STA and AP. +* +* OUTPUT: +* ------- +* The output files are: +* wniCfgSta.h - C header file for STA mode only +* wniCfgAp.h - C header file for both STA and AP +* wniCfgSta.bin - Control and default values for STA system +* wniCfgAp.bin - Control and default values for AP system +* +* PARAMETER DESCRIPTION: +* ---------------------- +* For each parameter, the description must be on separate lines and +* exactly as specified below. [] are comments and should not be included. +* +* [Common info] parameter_name type maxLen semIndx +* [STA flags] valid RW P/NP RESTART/RELOAD +* [STA_NTF] notification_mask +* [STA values] min max value [for integer] +* length byte1 byte2 ... [for string] +* [AP flags] valid RW/RO/WO P/NP RESTART/RELOAD +* [AP_NTF] notification_mask +* [AP values] min max value [for integer] +* length byte1 byte2 ... [for string] +* +* parameter_name: +* This will be used as the base name for C macro definition. +* Therefore, C syntax rule must be observed. +* +* type: +* Specifies parameter type +* S - variable-length string +* I - integer +* +* maxLen: +* Specifies maximum parameter length in bytes. +* +* semIndx: +* Specifies semaphore index to use for locking this parameter. +* More than one parameters (those belonging to the same group) +* can share the same semaphore index. +* +* valid: +* Specifies if this parameter will be valid in current mode. +* V - Valid +* NV - Not valid +* +* RW: +* Specifies Read/Write mode. +* RO - Read only +* RW - Read/Write +* WO - Write only +* XX - Not accessible from host +* +* P: +* Specifies persistent memory option +* P - Save to persistent memory +* NP - No save +* +* RELOAD: +* Specifies whether setting this requires reloading the MAC module +* This attribute can be changed only when SME is in OFFLINE or SUSPEND(OFFLINE) state +* +* RESTART: +* Specifies whether setting this requires (re)assoc at STA and restart at AP +* This attribute can be changed only when SME is in OFFLINE, SUSPEND(OFFLINE), +* IDLE or SUSPEND(IDLE) states +* +* STA_notification: +* Lists modules to be notified in STA mode. Valid modules are: +* HDD, LIM, SCH, ARQ, DPH, NIM, SP, RFP, RHP, TFP. More than one +* modules can be listed on the same line using space or tab as the +* separator. If no notification is required, 'NONE' must be specified. +* +* AP_notification: +* Lists module to be notified in AP mode. Valid modules are: +* HDD, LIM, SCH, ARQ, DPH, NIM, SP, RFP, RHP, TFP. More than one +* modules can be listed on the same line using space or tab as the +* separator. If no notification is required, 'NONE' must be specified. +* +* STA/AP integer values: +* min: +* Specifies minimum value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* max: +* Specifies maximum value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* default: +* Specifies default value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* STA/AP string values: +* len: +* The actual length of the string +* +* bytei: +* byte i of the string where i varies from 1 to len +* +* TABLE GENERATION: +* ----------------- +* Table can be generated using keywords '#TABLE' and '#END' as below: +* +* #TABLE table_name number_of_row +* WNI_CFG_xxxx +* ....... +* ....... +* #END +* +* The CFG utility will generate the following output: +* WNI_CFG_table_xxx_ID xxx +* WNI_CFG_table_xxx_ROW number_of_rows +* WNI_CFG_table_xxx_COL number_of_columns +* +* These will be followed by the parameter definition for each entry in +* the table. Table is organized in column-major order. +* +* #ENTRY_VALUES 1 +* 0 4 1 +* 0 0 0 +* #ENTRY_VALUES 2 +* 0 4 2 +* 0 0 0 +* #ENTRY_VALUES 3 +* 0 4 3 +* 0 0 0 +* #ENTRY_VALUES 4 +* 0 4 4 +* 0 0 0 +* +* +* ENUMERATION +* ----------- +* Enumerations can be define using keyword '#ENUM' +* +* #ENUM xxx val +* +* The cfg utility will generate the following output in the header file +* #define paramname_xxx val +* + + +* +* Station ID (changing requires restart) +* + +WNI_CFG_STA_ID S 6 1 +V RW NP RELOAD +HAL +6 0x22 0x22 0x44 0x44 0x33 0x33 +V RW NP RELOAD +HAL +6 0x22 0x22 0x11 0x11 0x33 0x33 + +* +* CF Pollable +* + +WNI_CFG_CF_POLLABLE I 4 1 +NV RO NP RESTART +NONE +0 0 0 +V RO NP RESTART +NONE +0 1 0 + +* +* CFP Period +* + +WNI_CFG_CFP_PERIOD I 4 1 +V RO NP +NONE +0 255 1 +V RW NP +SCH +0 255 1 + +* +* CFP Max Duration +* + +WNI_CFG_CFP_MAX_DURATION I 4 1 +V RO NP +NONE +0 65535 30000 +V RW NP +HAL +0 65535 30000 + +* +* SSID (changing requires restart) +* + +WNI_CFG_SSID S 32 1 +V RW NP RESTART +NONE +10 1 2 3 4 5 6 7 8 9 0 +V RW NP RESTART +NONE +10 1 2 3 4 5 6 7 8 9 0 + +* +* Beacon Period +* Can't be changed on STA in infrastructure, ignore notification at SCH +* + +WNI_CFG_BEACON_INTERVAL I 4 2 +V RW NP +SCH +0 65535 100 +V RW NP +SCH +0 65535 100 + +* +* DTIM Period +* + +WNI_CFG_DTIM_PERIOD I 4 2 +V RO NP +NONE +0 65535 1 +V RW NP +SCH +0 65535 1 + +* +* Default Key Table +* + +#TABLE WNI_CFG_WEP_DEFAULT_KEY_TABLE 4 + +WNI_CFG_WEP_DEFAULT_KEY S 13 4 +V WO NP RESTART +NONE +0 +V WO NP RESTART +NONE +0 + +#END + +* +* WEP Default Key id +* + +WNI_CFG_WEP_DEFAULT_KEYID I 4 5 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +#ENUM 0 0 +#ENUM 1 1 +#ENUM 2 2 +#ENUM 3 3 + +* +* RTS Threshold +* + +WNI_CFG_RTS_THRESHOLD I 4 6 +V RW NP +HAL +0 1048576 2347 +V RW NP +HAL +0 1048576 2347 + +* +* Long Retry Limit +* + +* +* Fragmentation Threshold +* + +WNI_CFG_FRAGMENTATION_THRESHOLD I 4 6 +V RW NP +HAL +256 8000 8000 +V RW NP +HAL +256 8000 8000 + + +* +* Minimum Channel Time (TU) +* + +WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 20 +V RW NP +NONE +0 65535 20 + +* +* Maximum Channel Time (TU) +* + +WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 40 +V RW NP +NONE +0 65535 40 +* +* Minimum Channel Time (TU) +* + +WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 60 +V RW NP +NONE +0 65535 60 + +* +* Maximum Channel Time (TU) +* + +WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 110 +V RW NP +NONE +0 65535 110 + +* +* Join Failure Timeout (TU) +* + +WNI_CFG_JOIN_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 3000 +V RW NP +NONE +0 65535 3000 + +* +* Authenticate Failure Timeout (TU) +* + +WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + +* +* Authenticate Response Timeout (TU) +* + +WNI_CFG_AUTHENTICATE_RSP_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + +* +* Assocation Failure Timeout (TU) +* + +WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT I 4 8 +V RW NP +LIM +0 65535 2000 +V RW NP +LIM +0 65535 3000 + +* +* Reassociation Failure Timeout (TU) +* + +WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 3000 + + +* +* RA periodicity Timeout (TU) +* + +WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS I 4 7 +V RW NP +HAL +0 65535 1000 +NV RW NP +NONE +0 0 0 + +* +* PS Data InActivity Timeout (TU) +* + +WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT I 4 7 +V RW NP +HAL +1 255 20 +NV RW NP +NONE +1 255 20 + +* +* Supported Rate Set for 11b +* + +WNI_CFG_SUPPORTED_RATES_11B S 4 2 +V RO NP +NONE +4 2 4 11 22 +V RO NP +NONE +4 2 4 11 22 + +* +* Supported Rate Set for 11a +* + +WNI_CFG_SUPPORTED_RATES_11A S 8 7 +V RO NP +NONE +8 12 18 24 36 48 72 96 108 +V RO NP +NONE +8 12 18 24 36 48 72 96 108 + +* +*The Dot11 mode can change dynamically on STA +* +WNI_CFG_DOT11_MODE I 4 9 +V RW NP RESTART +LIM +0 11 0 +V RW NP RESTART +LIM +0 11 0 + +#ENUM ALL 0 +#ENUM 11A 1 +#ENUM 11B 2 +#ENUM 11G 3 +#ENUM 11N 4 +#ENUM 11G_ONLY 5 +#ENUM 11N_ONLY 6 +#ENUM 11AC 7 +#ENUM 11AC_ONLY 8 + + + + + + +* +* Operational Rate Set (goes in beacon, probe rsp and assoc req) +* + +WNI_CFG_OPERATIONAL_RATE_SET S 12 2 +V RW NP RESTART +NONE +0 +V RW NP RESTART +NONE +4 0x82 0x84 11 22 +* 8 0x8c 18 24 36 48 72 96 108 + +* +* Extended Operational Rate Set (goes in beacon, assoc req) +* required for 11g +* + +WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET S 8 7 +V RW NP RESTART +NONE +0 +V RW NP RESTART +NONE +0 + +* +* BSSID +* In IBSS, this can be changed for coalescing, should SME go into IDLE state? +* + +* +* Listen Interval +* + +WNI_CFG_LISTEN_INTERVAL I 4 7 +V RW NP RESTART +NONE +0 65535 1 +V RO NP +NONE +0 65535 1 + +* +* Valid Channel List +* + +WNI_CFG_VALID_CHANNEL_LIST S 100 8 +V RW NP RESTART +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 +V RW NP RESTART +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 + +* +* For 11a or pure 11g, use 6Mbps(rateindex 11) +* as the default beaconRateIndex and +* nonBeaconRateIndex. +* +WNI_CFG_DEFAULT_RATE_INDEX_5GHZ I 4 9 +V RW NP +NONE +0 11 5 +V RW NP +NONE +0 11 5 + +* ********************************************************* +* +* Rate adaptation type +* + +WNI_CFG_RATE_ADAPTATION_TYPE I 4 0 +V RW NP +SCH +0 2 1 +V RW NP +SCH +0 2 1 + +#ENUM FIXED 0 +#ENUM AUTO 1 +#ENUM SNR_BASED 2 + +* +* Rate adaptation fixed rate +* Used to determine the rate for all peer stations +* +* + +WNI_CFG_FIXED_RATE I 4 0 +V RW NP +HAL +0 44 0 +V RW NP +HAL +0 44 0 + +#ENUM AUTO 0 + +#ENUM 1MBPS 1 +#ENUM 2MBPS 2 +#ENUM 5_5MBPS 3 +#ENUM 11MBPS 4 + +#ENUM 6MBPS 5 +#ENUM 9MBPS 6 +#ENUM 12MBPS 7 +#ENUM 18MBPS 8 +#ENUM 24MBPS 9 +#ENUM 36MBPS 10 +#ENUM 48MBPS 11 +#ENUM 54MBPS 12 + +#ENUM 6_5MBPS_MCS0_20MHZ_SIMO 13 +#ENUM 13MBPS_MCS1_20MHZ_SIMO 14 +#ENUM 19_5MBPS_MCS2_20MHZ_SIMO 15 +#ENUM 26MBPS_MCS3_20MHZ_SIMO 16 +#ENUM 39MBPS_MCS4_20MHZ_SIMO 17 +#ENUM 52MBPS_MCS5_20MHZ_SIMO 18 +#ENUM 58_5MBPS_MCS6_20MHZ_SIMO 19 +#ENUM 65MBPS_MCS7_20MHZ_SIMO 20 + +#ENUM 7_2MBPS_MCS0_20MHZ_SIMO_SGI 21 +#ENUM 14_4MBPS_MCS1_20MHZ_SIMO_SGI 22 +#ENUM 21_7MBPS_MCS2_20MHZ_SIMO_SGI 23 +#ENUM 28_9MBPS_MCS3_20MHZ_SIMO_SGI 24 +#ENUM 43_3MBPS_MCS4_20MHZ_SIMO_SGI 25 +#ENUM 57_8MBPS_MCS5_20MHZ_SIMO_SGI 26 +#ENUM 65MBPS_MCS6_20MHZ_SIMO_SGI 27 +#ENUM 72_2MBPS_MCS7_20MHZ_SIMO_SGI 28 + +#ENUM 0_25MBPS_SLR_20MHZ_SIMO 29 +#ENUM 0_5MBPS_SLR_20MHZ_SIMO 30 + +#ENUM 68_25MBPS_QC_PROP_20MHZ_SIMO 31 +#ENUM 54MBPS_MCS3_40MHZ_SIMO 32 +#ENUM 81MBPS_MCS4_40MHZ_SIMO 33 +#ENUM 108MBPS_MCS5_40MHZ_SIMO 34 +#ENUM 121_5MBPS_MCS6_40MHZ_SIMO 35 +#ENUM 135MBPS_MCS7_40MHZ_SIMO 36 +#ENUM 15MBPS_MCS0_40MHZ_SIMO_SGI 37 +#ENUM 30MBPS_MCS1_40MHZ_SIMO_SGI 38 +#ENUM 45MBPS_MCS2_40MHZ_SIMO_SGI 39 +#ENUM 60MBPS_MCS3_40MHZ_SIMO_SGI 40 +#ENUM 90MBPS_MCS4_40MHZ_SIMO_SGI 41 +#ENUM 120MBPS_MCS5_40MHZ_SIMO_SGI 42 +#ENUM 135MBPS_MCS6_40MHZ_SIMO_SGI 43 +#ENUM 150MBPS_MCS7_40MHZ_SIMO_SGI 44 + +* ********************************************************* +* +* Broadcast/mutlicast rates for 2.4GHZ +* uses the same rate indices definition as WNI_CFG_FIXED_RATE +* default value corresponds to 1M + +WNI_CFG_FIXED_RATE_MULTICAST_24GHZ I 4 8 +V RW NP +HAL +0 31 1 +V RW NP +HAL +0 31 1 + +* ********************************************************* +* +* Broadcast/mutlicast rates for 5 GHZ +* uses the same rate indices definition as WNI_CFG_FIXED_RATE +* default value corresponds to 6M + +WNI_CFG_FIXED_RATE_MULTICAST_5GHZ I 4 8 +V RW NP +HAL +0 31 5 +V RW NP +HAL +0 31 5 + +* +* retry rate selection policy +* 0 => use the minimum supported rate +* 1 => use the same rate as the chosen primary rate +* 2 => use the rate specified in RETRYRATE_SECONDARY +* 3 => use the rate closest to the primary +* 4 => autoselect the retry rate based on RA algorithm +* + +WNI_CFG_RETRYRATE_POLICY I 4 0 +V RW NP +HAL +0 255 4 +V RW NP +HAL +0 255 4 + +#ENUM MIN_SUPPORTED 0 +#ENUM PRIMARY 1 +#ENUM RESERVED 2 +#ENUM CLOSEST 3 +#ENUM AUTOSELECT 4 +#ENUM MAX 5 + +* +* the following two CFG's are +* used only if the retryrate policy == 2 +* These should be set to one of the values used +* for configuring fixed rates (see enumerated rates) +* + +WNI_CFG_RETRYRATE_SECONDARY I 4 0 +V RW NP +HAL +0 255 0 +V RW NP +HAL +0 255 0 + +WNI_CFG_RETRYRATE_TERTIARY I 4 0 +V RW NP +HAL +0 255 0 +V RW NP +HAL +0 255 0 + +* ********************************************************* +* +* Automatic Power Save Delivery capability +* + +WNI_CFG_APSD_ENABLED I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Shared key authentication supported +* + +WNI_CFG_SHARED_KEY_AUTH_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* Open system authentication supported +* + +WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* Authentication Type (change requires restart) +* + +WNI_CFG_AUTHENTICATION_TYPE I 4 8 +V RW NP RESTART +NONE +0 65535 0 +V RW NP RESTART +NONE +0 65535 0 + +* +* CF Poll Request (change requires restart) +* + +WNI_CFG_CF_POLL_REQUEST I 4 8 +NV RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Privacy Enabled (change requires restart) +* + +WNI_CFG_PRIVACY_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Short Preamble (change requires restart) +* + +WNI_CFG_SHORT_PREAMBLE I 4 8 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Short Slot time +* This is the operational state of the BSS + +WNI_CFG_SHORT_SLOT_TIME I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 0 + + +* +* ACCEPT Short Slot Association only +* +* 1: If AP supports shortSlot, then AP will accept +* association only from stations that supports +* supports short slot +* 0: AP supports shortSlot, but AP will accept association +* from stations regardless of whether station supports +* short slot or long slot +* +WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + + +* +* QOS Enabled (change requires restart) +* + +WNI_CFG_QOS_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* HCF Enabled (change requires restart) +* + +WNI_CFG_HCF_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* RSN (11i/WPA) Enabled +* + +WNI_CFG_RSN_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Background scanning periodicity (kilo usec) +* + +WNI_CFG_BACKGROUND_SCAN_PERIOD I 4 8 +V RW NP +LIM +0 180000 5000 +V RW NP +LIM +0 18000 5000 + +* +* Max number of Preauthentication +* + +WNI_CFG_MAX_NUM_PRE_AUTH I 4 8 +V RW NP RESTART +NONE +0 256 64 +V RW NP RESTART +NONE +0 256 64 + +* +* Preauthentication Cleanup Timeout (kilo usec) +* + +WNI_CFG_PREAUTH_CLNUP_TIMEOUT I 4 8 +NV XX NP +NONE +0 0 0 +V RW NP +LIM +0 120000 30000 + +* +* Release AID Timeout +* + +WNI_CFG_RELEASE_AID_TIMEOUT I 4 8 +NV XX NP +NONE +0 0 0 +V RW NP +LIM +0 100000 1000 +* +* Heartbeat Threshold +* + +WNI_CFG_HEART_BEAT_THRESHOLD I 4 8 +V RW NP +LIM +0 65535 40 +NV RW NP +NONE +0 65535 40 + +* +* Probe response wait time out after heartbeat failure +* + +WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT I 4 8 +V RW NP +NONE +10 10000 40 +V RW NP +NONE +10 10000 40 + +* +* Manufacturer OUI (from eeprom) +* + +WNI_CFG_MANUFACTURER_OUI S 3 8 +V RO NP +NONE +3 0x0 0xa 0xf5 +V RO NP +NONE +3 0x0 0xa 0xf5 + +* +* Manufacture Name (from eeprom) +* + +WNI_CFG_MANUFACTURER_NAME S 65 8 +V RO NP +NONE +8 0x51 0x75 0x61 0x6c 0x63 0x6f 0x6D 0x6D +V RO NP +NONE +8 0x51 0x75 0x61 0x6c 0x63 0x6f 0x6D 0x6D + +* +* Model Number (from eeprom) +* + +WNI_CFG_MODEL_NUMBER S 33 8 +V RO NP +NONE +6 0x4d 0x4e 0x31 0x32 0x33 0x34 +V RO NP +NONE +6 0x4d 0x4e 0x31 0x32 0x33 0x34 + + + +* +* Model Name (from eeprom) +* WFR4031 +* + +WNI_CFG_MODEL_NAME S 33 8 +V RO NP +NONE +7 0x57 0x46 0x52 0x34 0x30 0x33 0x31 +V RO NP +NONE +7 0x57 0x46 0x52 0x34 0x30 0x33 0x31 + + + + +* +* Manufacture Product Name (from eeprom) +* + +WNI_CFG_MANUFACTURER_PRODUCT_NAME S 33 8 +V RO NP +NONE +6 0x31 0x31 0x6e 0x2D 0x41 0x50 +V RO NP +NONE +6 0x31 0x31 0x6e 0x2D 0x41 0x50 + + +* +* Manufacture Product Version (from eeprom) +* + +WNI_CFG_MANUFACTURER_PRODUCT_VERSION S 33 8 +V RO NP +NONE +6 0x53 0x4e 0x31 0x32 0x33 0x34 +V RO NP +NONE +6 0x53 0x4e 0x31 0x32 0x33 0x34 + +* +* Multi Domain Capability (11d) Enable +* + +WNI_CFG_11D_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 0 + +* +* per channel Max power transmit (in dBm) +* this parameter correspond to the MAX_COUNTRY_EID +* table of (Channel Number/num channel/max tx power) +* +* There is one table for 5GHz channels and one table for 2.4GHz channels +* + +WNI_CFG_MAX_TX_POWER_2_4 S 128 8 +V RW NP +NONE +3 1 14 20 +V RW NP +NONE +3 1 14 20 + +WNI_CFG_MAX_TX_POWER_5 S 128 8 +V RW NP +NONE +3 36 126 20 +V RW NP +NONE +3 36 126 20 + +* +* Cell size configurations. These are canned configurations for a specified +* cell size. +* +WNI_CFG_NETWORK_DENSITY I 4 9 +V RW NP +HAL +0 3 3 +V RW NP +HAL +0 3 0 + +#ENUM LOW 0 +#ENUM MEDIUM 1 +#ENUM HIGH 2 +#ENUM ADAPTIVE 3 + + +* +* Adaptive Threshold Algorithm +* +WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM I 4 9 +V RW NP +HAL +1 2 2 +V RW NP +HAL +1 2 2 + +#ENUM CARRIER 1 +#ENUM CORRELATION 2 + + + +* +* Current TX Antenna +* + +WNI_CFG_CURRENT_TX_ANTENNA I 4 9 +V RW NP +HAL +1 1 1 +V RW NP +HAL +1 2 2 + +* +* Current RX Antenna +* + +WNI_CFG_CURRENT_RX_ANTENNA I 4 9 +V RW NP +HAL +1 2 2 +V RW NP +HAL +1 3 3 + +* +* Current TX Power Level +* + +WNI_CFG_CURRENT_TX_POWER_LEVEL I 4 9 +V RW NP +NONE +0 128 27 +V RW NP +NONE +0 128 27 + +* +* Parameter to indicate or not new BSS found +* +WNI_CFG_NEW_BSS_FOUND_IND I 4 9 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + + +* +* Qualcomm Prop Rates are disabled by default +* +WNI_CFG_PROPRIETARY_RATES_ENABLED I 4 12 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + + +* +* AP node Name +* + +WNI_CFG_AP_NODE_NAME S 32 8 +NV RO NP +NONE +0 +V RW NP RESTART +NONE +0 + +* +* Country code (from EEPROM) +* + +WNI_CFG_COUNTRY_CODE S 3 8 +V RW NP +NONE +0 +V RW NP +NONE +3 0x11 0x22 0x33 + +* +* Spectrum Management (11h) enable/disable +* + +WNI_CFG_11H_ENABLED I 4 12 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Wait for CNF Timeout. CNF include (RE)ASSOC, DISASSOC, AUTH, DEAUTH, +* DUMMY packet +* + +WNI_CFG_WT_CNF_TIMEOUT I 4 12 +V RW NP +NONE +10 3000 1000 +V RW NP +NONE +10 3000 1000 + +* +* Proximity, set it for very short distances +* Proxmity setting is applied via halPhySetNwDensity() +* +* close proximity off = densityOn is true. network density config applies. +* close proximity on = densityOn is false. Don't care about network density config. +* + +WNI_CFG_PROXIMITY I 4 12 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +#ENUM OFF 0 +#ENUM ON 1 + +* +* OLBC detection timeout +* + +WNI_CFG_OLBC_DETECT_TIMEOUT I 4 12 +V RW NP +NONE +1000 30000 10000 +V RW NP +NONE +1000 30000 10000 + +********************************** +* Protection Enable +* +*LOWER byte for associated stations +*UPPER byte for overlapping stations. +*11g ==> protection from 11g +*11b ==> protection from 11b +*each byte will have the following info +*bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 +*reserved reserved RIFS Lsig n-GF ht20 11g 11b +********************************** +WNI_CFG_PROTECTION_ENABLED I 4 9 +V RW NP RESTART +LIM +0 0xffff 0xffff +V RW NP RESTART +LIM +0 0xffff 0xffff + +#ENUM FROM_llA 0 +#ENUM FROM_llB 1 +#ENUM FROM_llG 2 +#ENUM HT_20 3 +#ENUM NON_GF 4 +#ENUM LSIG_TXOP 5 +#ENUM RIFS 6 +#ENUM OBSS 7 +#ENUM OLBC_FROM_llA 8 +#ENUM OLBC_FROM_llB 9 +#ENUM OLBC_FROM_llG 10 +#ENUM OLBC_HT20 11 +#ENUM OLBC_NON_GF 12 +#ENUM OLBC_LSIG_TXOP 13 +#ENUM OLBC_RIFS 14 +#ENUM OLBC_OBSS 15 + + +* **************************************** +* +* 11G Protection Enable Always +* Valid only if protection is enabled +* forces uses of protection regardless of legacy stations +* + +WNI_CFG_11G_PROTECTION_ALWAYS I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +********************************************* +* Force protection +* 0 : disable protection +* 1 : CTS +* 2 : RTS by threshold (threshold nonzero) +* 3 : dual CTS (not supported right now) +* 4 : RTS (threshold 0) +* 5 : auto + +WNI_CFG_FORCE_POLICY_PROTECTION I 4 9 +V RW NP RESTART +HAL +0 5 5 +V RW NP RESTART +HAL +0 5 5 + +#ENUM DISABLE 0 +#ENUM CTS 1 +#ENUM RTS 2 +#ENUM DUAL_CTS 3 +#ENUM RTS_ALWAYS 4 +#ENUM AUTO 5 + + + + + + +******************************************** +* 11G Short Preamble Enable +* + +WNI_CFG_11G_SHORT_PREAMBLE_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* 11G Short Slot Time Enable (change requires restart) +* This is the admin state of short slot support. + +WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Calibration periodicity (minutes) +* + +WNI_CFG_CAL_PERIOD I 4 12 +V RW NP +HAL +2 10 5 +V RW NP +HAL +2 10 5 + +* +* Statistics collection periodicity (seconds) +* + +WNI_CFG_STATS_PERIOD I 4 12 +V RW NP +HAL +1 10 10 +V RW NP +HAL +1 10 10 + +* +* Calibration on/off control +* + +WNI_CFG_CAL_CONTROL I 4 12 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +#ENUM CAL_ON 0 +#ENUM CAL_OFF 1 + + +* +* Parameter to allow 11g only STAs while operating in 11g mode +* + +WNI_CFG_11G_ONLY_POLICY I 4 12 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Packet Classification +* This flag is a bitmask used to indicate which +* frame classifier to be enabled: +* b0: DSCP +* b1: 802.1P +* + +WNI_CFG_PACKET_CLASSIFICATION I 4 12 +V RW NP +HAL +0 3 0 +V RW NP +HAL +0 3 0 + +#ENUM DISABLED 0 +#ENUM DSCP 1 +#ENUM 8021P 2 +#ENUM ALL 3 + +* +* WME Enabled (change requires restart) +* + +WNI_CFG_WME_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* ADDTS response timeout (in ms) +* + +WNI_CFG_ADDTS_RSP_TIMEOUT I 4 8 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + + + * Max SP Length indicates the max number of + * total buffered MSDUs and MMPDUs the WMM AP + * may deliver to WMM STA during any service period + * triggered by WMM STA. + * 1) If AP sends WMM IE with the UAPSD bit 0, max_sp_length=0 + * 2) If WMM STA's all 4 UAPSD flag are set to 0, max_sp_length=0 + * 3) If AP sends WMM IE with UAPSD=1, and at least one of stations + * UAPSD flag is set to 1, then max_sp_length can be set to: + * [b5:b6]=0x00: WMM AP may deliver all buffered frames + * [b5:b6]=0x10: WMM AP may deliver max 2 buffered frames + * [b5:b6]=0x01: WMM AP may deliver max 4 buffered frames + * [b5:b6]=0x11: WMM AP may deliver max 6 buffered frames + +WNI_CFG_MAX_SP_LENGTH I 4 8 +V RW NP +NONE +0 3 0 +V RW NP +NONE +0 3 0 + + +* +* KEEP ALIVE STA Limit Threshold , used in AP to delete the STA +* from Station Table which didn't respond to Probe Response Messages +* + +WNI_CFG_KEEP_ALIVE_STA_LIMIT_THRESHOLD I 4 8 +NV RW NP +NONE +0 32 0 +V RW NP +NONE +0 32 0 + +* +* Parameter that specifies whether to send SSID +* in Probe Response when SSID is suppressed +* + +WNI_CFG_SEND_SINGLE_SSID_ALWAYS I 4 12 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* WSM Enabled (change requires restart) +* Takes effect only if WME is also enabled +* + +WNI_CFG_WSM_ENABLED I 4 8 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* **************************************** +* + + + +* Background Channel List +* Contains pairs of {channelNumber, scanType} +* where scanType = 0 indicates active scan and +* = 1 indicates passive scan +* +* +*WNI_CFG_BACKGROUND_SCAN_LIST S 128 8 +*V RW NP RESTART +*LIM +*60 36 0 40 0 44 0 48 0 52 0 56 0 60 0 64 0 1 0 6 0 11 0 34 0 38 0 42 0 46 0 2 0 3 0 4 0 5 0 7 0 8 0 9 0 10 0 12 0 13 0 14 0 149 0 153 0 157 0 161 0 +*V RW NP RESTART +*LIM +*60 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 34 0 36 0 38 0 40 0 42 0 44 0 46 0 48 0 52 0 56 0 60 0 64 0 149 0 153 0 157 0 161 0 +* + +* **************************************** +* EDCA paramters are contained in profiles - each profile contains +* the parameters [ACM, AIFSN, CWmin, CWmax, TxOp] for four +* access categories (i.e., four sets). Two such sets of four parameters +* make a single profile: One set is used locally by the AP, the other set +* is broadcast for use by stations. +* +* Cwmin and Cwmax are two bytes each, MSB first. So Cwmin of [3 255] is +* equivalent to 0x3ff, i.e. 3*256+255=1023 +* +* The profile to use is selected based on the valus of the profile select param +* See ENUMs below for definitions of profile values +* + +WNI_CFG_EDCA_PROFILE I 4 8 +V RW NP +SCH +0 255 1 +V RW NP +SCH +0 255 1 + +#ENUM ANI 0 +#ENUM WMM 1 +#ENUM TIT_DEMO 2 +#ENUM MAX 3 + +#ENUM ACM_IDX 0 +#ENUM AIFSN_IDX 1 +#ENUM CWMINA_IDX 2 +#ENUM CWMAXA_IDX 4 +#ENUM TXOPA_IDX 6 +#ENUM CWMINB_IDX 7 +#ENUM CWMAXB_IDX 9 +#ENUM TXOPB_IDX 11 +#ENUM CWMING_IDX 12 +#ENUM CWMAXG_IDX 14 +#ENUM TXOPG_IDX 16 + + +* **************************************** +* Profile 0 (Airgo) parameters - AC_BK Local +* ACM, AIFSN, [CWminH, CWminL, CWmaxH, CWmaxL, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBK_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 + +* +* Profile 0 (Airgo) parameters AC_BE Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBE_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 + +* +* Profile 0 (Airgo) parameters AC_VI Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVI_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 + +* +* Profile 0 (Airgo) parameters AC_VO Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVO_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 + +* +* Profile 0 (Airgo) parameters - AC_BK Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBK S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 + +* +* Profile 0 (Airgo) parameters AC_BE Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBE S 20 8 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 + +* +* Profile 0 (Airgo) parameters AC_VI Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVI S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 + +* +* Profile 0 (Airgo) parameters AC_VO Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVO S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 + + +* **************************************** +* Profile 1 (WME) parameters - AC_BK Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBK_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + + +* +* Profile 1 (WME) parameters AC_BE Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBE_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 3 0 15 0 63 0 0 31 3 255 0 0 15 0 63 0 +V RW NP RESTART +NONE +17 0 3 0 15 0 63 0 0 15 0 63 0 0 15 0 63 0 + +* +* Profile 1 (WME) parameters AC_VI Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVI_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 1 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 +V RW NP RESTART +NONE +17 0 1 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 + +* +* Profile 1 (WME) parameters AC_VO Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVO_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 1 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 +V RW NP RESTART +NONE +17 0 1 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 + +* +* Profile 1 (WME) parameters - AC_BK Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBK S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + +* +* Profile 1 (WME) parameters AC_BE Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBE S 20 8 +V RW NP RESTART +NONE +17 0 3 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 3 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + +* +* Profile 1 (WME) parameters AC_VI Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVI S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 + +* +* Profile 1 (WME) parameters AC_VO Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVO S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 + +* +* Radar detector flag enable/disable +* + +WNI_CFG_RDET_FLAG I 4 9 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +WNI_CFG_RADAR_CHANNEL_LIST S 20 8 +V RW NP RESTART +NONE +15 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 +V RW NP RESTART +NONE +15 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 + +* +* Local Power Constraint (dBm) +* + +WNI_CFG_LOCAL_POWER_CONSTRAINT I 4 12 +V RW NP RESTART +NONE +0 255 0 +V RW NP RESTART +NONE +0 255 0 + +* ********************************************************* +* +* Admission Control Policy +* used for admitting tspec's when either edca or hcca are in use +* + +WNI_CFG_ADMIT_POLICY I 4 8 +V RW NP RESTART +NONE +0 2 0 +V RW NP +SCH +0 2 0 + +#ENUM ADMIT_ALL 0 +#ENUM REJECT_ALL 1 +#ENUM BW_FACTOR 2 + +* +* Oversubscription factor for admission control +* valid only when admit policy is set to BW_FACTOR +* units are in terms of 1/10th of available bandwidth +* + +WNI_CFG_ADMIT_BWFACTOR I 4 8 +V RW NP RESTART +NONE +0 100 20 +V RW NP +SCH +0 100 20 + +* ********************************************************* +* +* Number of "consecutive" Background Scan Failure needed +* before LIM is forced to perform 1 aggressive background scan +* +WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE I 4 8 +V RW NP RESTART +NONE +0 256 60 +V RW NP RESTART +NONE +0 256 60 + + +************************************* +* Feature: Channel Bonding +************************************* +* +* Global flag to enable/disable Channel Bonding +* 0 - Disable: Force disable channel bonding for all TC-ids +* 1 - Enable: Force enable channel bonding for all TC-ids +* 2 - no legacy bss: Enable channel bonding if no legacy BSS are present +* 3 - no legacy all: Enable channel bonding if no legacy BSS or devices are present +* 4 - intelligent: Enable channel bonding depending on load level on secondary channel +* +WNI_CFG_CHANNEL_BONDING_MODE I 4 12 +V RW NP RESTART +LIM +0 10 0 +V RW NP RESTART +LIM +0 10 0 + +#ENUM DISABLE 0 +#ENUM ENABLE 1 +#ENUM IF_NO_LEGACY_BSS 2 +#ENUM IF_NO_LEGACY_ALL 3 +#ENUM INTELLIGENT 4 + + +* +* When the channel is 40MHz wide, this CFG indicates +* if the secondary channel is located above (at +* a higher frequency), or located below (at a +* lower frequency). +* +* 0 - There is no secondary channel. The channel is 20Mhz +* 1 - LOWER: Secondary channel 40MHZ is located below the primary channel +* 2 - CENTERED:Secondary channel and primary located at centered +* 3 - HIGHER: Secondary channel 40 MHZ is located above the primary channel +* 4 - 80MHZ_LOW_CENTERED : 20/40MHZ offset LOW 40/80MHZ offset CENTERED +* 5 - 80MHZ_CENTERED_CENTERED : 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED +* 6 - 80MHZ_HIGH_CENTERED : 20/40MHZ offset HIGH 40/80MHZ offset CENTERED +* 7 - 80MHZ_LOW_LOW: 20/40MHZ offset LOW 40/80MHZ offset LOW +* 8 - 80MHZ_HIGH_LOW: 20/40MHZ offset HIGH 40/80MHZ offset LOW +* 9 - 80MHZ_LOW_HIGH: 20/40MHZ offset LOW 40/80MHZ offset HIGH +* 10 - 80MHZ_HIGH_HIGH: 20/40MHZ offset HIGH 40/80MHZ offset HIGH +* +WNI_CFG_CB_SECONDARY_CHANNEL_STATE I 4 12 +V RW NP +NONE +0 10 0 +V RW NP +NONE +0 10 0 + +#ENUM NONE 0 +#ENUM LOWER 1 +#ENUM HIGHER 2 +#ENUM 11AC_20MHZ_LOW_40MHZ_CENTERED 3 +#ENUM 11AC_20MHZ_CENTERED_40MHZ_CENTERED 4 +#ENUM 11AC_20MHZ_HIGH_40MHZ_CENTERED 5 +#ENUM 11AC_20MHZ_LOW_40MHZ_LOW 6 +#ENUM 11AC_20MHZ_HIGH_40MHZ_LOW 7 +#ENUM 11AC_20MHZ_LOW_40MHZ_HIGH 8 +#ENUM 11AC_20MHZ_HIGH_40MHZ_HIGH 9 + +* +* Trigger Station Background Scan Flag +* +WNI_CFG_TRIG_STA_BK_SCAN I 4 12 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 1 + +* ********************************************************* +* control of dynamic EDCA parameter profile switching +* +* OOB, we would like to support WMM standard edca profile +* However, when Airgo STA's join the BSS, we would like +* to switch the profile to Airgo high-performance edca parameters +* +* This cfg supports that behaviour. It is used only if 11e qos +* has been enabled and is ignored otherwise. +* +* When set to any value (other than unused), it determines the +* edca profile to switch to when an Airgo STA joins the BSS. +* +* By default, we choose to switch to Airgo profile. +* +* NOTE: This parameter applies only to an AP +* + +WNI_CFG_DYNAMIC_PROFILE_SWITCHING I 4 8 +V RW NP RESTART +NONE +0 255 255 +V RW NP RESTART +NONE +0 255 1 + +#ENUM UNUSED 255 + +* ********************************************************* +* +* Scan control list +* Contains pairs of {channelNumber, activeScanAllowedFlag} +* where scanType = 1 indicates active scan is allowed, and +* = 0 indicates passive scan is used +* If a channel is not on this list, active scan is NOT allowed. So it is +* sufficient to inlude only those channels where active scan is allowed +* on this list. +* +* The list determines only whether active scan is allowed or not; it does not +* determine which type of scan is actually performed. +* + +WNI_CFG_SCAN_CONTROL_LIST S 128 8 +V RW NP RESTART +LIM +112 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 1 34 1 36 1 38 1 40 1 42 1 44 1 46 1 48 1 50 1 52 0 54 0 56 0 58 0 60 0 62 0 64 0 100 0 104 0 108 0 112 0 116 0 120 0 124 0 128 0 132 0 136 0 140 0 149 1 151 1 153 1 155 1 157 1 159 1 161 1 165 1 240 1 242 1 244 1 246 1 248 1 250 1 252 1 +V RW NP RESTART +LIM +112 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 1 34 1 36 1 38 1 40 1 42 1 44 1 46 1 48 1 50 1 52 0 54 0 56 0 58 0 60 0 62 0 64 0 100 0 104 0 108 0 112 0 116 0 120 0 124 0 128 0 132 0 136 0 140 0 149 1 151 1 153 1 155 1 157 1 159 1 161 1 165 1 240 1 242 1 244 1 246 1 248 1 250 1 252 1 + + +* **************************************** +* +* MIMO rates enabled (for rate adaptation, to start) +* + +WNI_CFG_MIMO_ENABLED I 4 9 +V RW NP RELOAD +NONE +0 1 1 +V RW NP RELOAD +NIM +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + + +* +* BLOCK ACK Enabled (change requires restart) +* change default to ON +* bit 0 ==> delayed BA +* bit 1 ==> immediate BA +WNI_CFG_BLOCK_ACK_ENABLED I 4 8 +V RW NP RESTART +LIM +0 3 0 +V RW NP RESTART +LIM +0 3 0 + +#ENUM DELAYED 0 +#ENUM IMMEDIATE 1 + + +* +*BA Activity check global timer +* +WNI_CFG_BA_ACTIVITY_CHECK_TIMEOUT I 4 7 +V RW NP +HAL +0 65535 1000 +V RW NP +HAL +0 65535 1000 + + +* +* Rx STBC support +* +WNI_CFG_HT_RX_STBC I 4 7 +V RW NP RESTART +LIM +0 3 1 +V RW NP RESTART +LIM +0 3 1 + + +* +* 1. HT capabilities Info: 2 bytes size +* +* Supported channel Width is set to 1 (40 Mhz) +* SM Power Save is disabled. +* GreenField support is enabled. +* Short GI for 20 and 40Mhz is enabled. +* Max AMSDU Size is set to 0(3839 Octets) +* DSSS-CCK Mode is enabled. +* LSIG TXOP Protection is disabled +* Rest of the features are not supported at this moment. +* +* fedc ba98 7654 3210 +* 0000 0001 0010 0000 +* +WNI_CFG_HT_CAP_INFO I 4 10 +V RW NP RESTART +LIM +0 0xffff 0x016c +V RW NP RESTART +LIM +0 0xffff 0x106e + +#ENUM ADVANCE_CODING 0 +#ENUM SUPPORTED_CHAN_WIDTH_SET 1 +#ENUM SM_POWER_SAVE 2 +#ENUM GREEN_FIELD 4 +#ENUM SHORT_GI_20MHZ 5 +#ENUM SHORT_GI_40MHZ 6 +#ENUM TX_STBC 7 +#ENUM RX_STBC 8 +#ENUM DELAYED_BA 10 +#ENUM MAX_AMSDU_SIZE 11 +#ENUM DSSS_CCK_MODE_40MHZ 12 +#ENUM PSMP 13 +#ENUM STBC_CONTROL_FRAME 14 +#ENUM LSIG_TXOP_PROTECTION 15 + +* +* 2. HT Parameters Info: 1 byte size +* +* Max AMPDU Rx Factor is defined using bit #0 and #1 +* MPDU Density is defined using bit #2 thru #4. +* The default values are, +* 7654 3210 +* 0000 0010 --> 2 for RX AMPDU Factor, 0 for MPDU density +* +WNI_CFG_HT_AMPDU_PARAMS I 4 7 +V RW NP RESTART +LIM +0 0xff 0x00 +V RW NP RESTART +LIM +0 0xff 0x02 + +#ENUM MAX_RX_AMPDU_FACTOR 0 +#ENUM MPDU_DENSITY 2 +#ENUM RESERVED 5 + +* +* 3. Supported MCS Set: 16 bytes size +* +* MCS #0-15 and #32 is supported. +* +WNI_CFG_SUPPORTED_MCS_SET S 16 7 +V RW P RESTART +LIM +16 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 255 255 0 0 1 0 0 0 0 0 0 0 0 0 0 0 + +* +* 4. Extended HT Capabilities Info: 2 bytes size +* +* Only HTC Support is enabled, rest all features are not +* supported at this moment. +* +* fedc ba98 7654 3210 +* 0000 0100 0000 0000 +* +WNI_CFG_EXT_HT_CAP_INFO I 4 10 +V RW P RESTART +LIM +0 0xffff 0x0400 +V RW P RESTART +LIM +0 0xffff 0x0400 + +#ENUM PCO 0 +#ENUM TRANSITION_TIME 1 +#ENUM RESERVED1 3 +#ENUM MCS_FEEDBACK 8 +#ENUM HTC_SUPPORT 10 +#ENUM RD_RESPONDER 11 +#ENUM RESERVED2 12 + + +* +* 5. Transmit Beam Forming Capabiliries Info: 4 bytes size +* +WNI_CFG_TX_BF_CAP I 4 7 +V RO NP RESTART +LIM +0 0xffffffff 0x00000000 +V RO NP RESTART +LIM +0 0xffffffff 0x00000000 + +* +* 6. Antenna Selection Capabilities: 1 byte size +* +WNI_CFG_AS_CAP I 4 7 +V RW P RESTART +LIM +0 0xff 0x00 +V RW P RESTART +LIM +0 0xff 0x00 + +#ENUM ANTENNA_SELECTION 0 +#ENUM EXPLICIT_CSI_FEEDBACK_TX 1 +#ENUM ANTENNA_INDICES_FEEDBACK_TX 2 +#ENUM EXPLICIT_CSI_FEEDBACK 3 +#ENUM ANTENNA_INDICES_FEEDBACK 4 +#ENUM RX_AS 5 +#ENUM TX_SOUNDING_PPDUS 6 +#ENUM RESERVED 7 + +************************************************** +* Beacon HT (High Through) Info IE +*************************************************** +* +* 3. HT Info Field1: 1 byte size. +* +* Secondary Channel Offset is set to 3 (Down) by default and will +* be updated dynamically by DFS algorithm. +* Channel Width is set to 1 (40 Mhz) +* RIFS Mode is enabled +* Rest of the features are not supported at this moment. +* +* 7654 3210 +* 0000 1111 +* +WNI_CFG_HT_INFO_FIELD1 I 4 10 +V RW NP RESTART +LIM +0 0xff 0x0f +V RW NP RESTART +LIM +0 0xff 0x0f + +#ENUM SECONDARY_CHANNEL_OFFSET 0 +#ENUM RECOMMENDED_CHANNEL_WIDTH 2 +#ENUM RIFS_MODE 3 +#ENUM PSMP_ACCESS_ONLY 4 +#ENUM SERVICE_INTERVAL_GRANULARITY 5 + +* +* 4. HT Info Field2: 2 bytes +* +* Operation mode is set to 0(Pure, GF) to begin with and +* will be updated dynamically. +* 'NonGF Devices present is also set to zero and +* will be updated dynamically. +* +* fedc ba98 7654 3210 +* 0000 0000 0000 0000 +* +WNI_CFG_HT_INFO_FIELD2 I 4 10 +V RW P +LIM +0 0xffff 0x00 +V RW P +LIM +0 0xffff 0x00 + +#ENUM OP_MODE 0 +#ENUM NON_GF_DEVICES_PRESENT 2 +#ENUM RESERVED 3 + +* +* 5. HT Info Field3: 2 bytes +* +* fedc ba98 7654 3210 +* 0000 0000 0000 0000 +* +* LSIG TXOP Full Protection will be zero to begin with and +* updated dynamically. +* Everything else is not supported at this moment. +* +WNI_CFG_HT_INFO_FIELD3 I 4 10 +V RW P +LIM +0 0xffff 0x0000 +V RW P +LIM +0 0xffff 0x0000 + +#ENUM BASIC_STBC_MCS 0 +#ENUM DUAL_STBC_PROTECTION 7 +#ENUM SECONDARY_BEACON 8 +#ENUM LSIG_TXOP_PROTECTION_FULL_SUPPORT 9 +#ENUM PCO_ACTIVE 10 +#ENUM PCO_PHASE 11 +#ENUM RESERVED 12 + +* +* 6. Basic MCS Set: 16 bytes size +* +* For now set this to zero and don't put any restrictions. +* +WNI_CFG_BASIC_MCS_SET S 16 7 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +* +* 7. Current supported MCS Set: 16 bytes size +* +* For now set this to zero and don't put any restrictions. +* +WNI_CFG_CURRENT_MCS_SET S 16 7 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + +* +* Greenfield Capability +* By default Greenfield is enabled +* +WNI_CFG_GREENFIELD_CAPABILITY I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 0 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +* +* Maximum AMPDU Length +* By default set to zero for 3895 octets +* +WNI_CFG_VHT_MAX_MPDU_LENGTH I 4 19 +V RW NP +LIM +0 2 0 +V RW NP +LIM +0 2 0 + +* +* Supported Channel Width Set +* By default set to zero for +* STAs does not support either 160 or 80+80MHz +* +WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* LDPC Coding Capability +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_LDPC_CODING_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Short GI for 80MHz +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_SHORT_GI_80MHZ I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* Short GI for 160MHz and 80+80MHz +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Transmission of 2x1 STBC +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_TXSTBC I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Reception of PPDUs using STBC +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_RXSTBC I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* Support for Operating as SU Beamformer +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_SU_BEAMFORMER_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Operating as SU Beamformee +* Riva does not support, But Pronto supports, default set to 0 +* +WNI_CFG_VHT_SU_BEAMFORMEE_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Compressed Steering Number of Beamformer Antennas Supported +* Riva does not support,Pronto supports, default set to 0 +* +WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED I 4 19 +V RW NP +LIM +0 4 0 +V RW NP +LIM +0 4 0 + +* +* Number of Sounding Dimensions indicates Number +* of antennas used by the beamformer when sending beamformed transmissions +* Riva/Pronto does not support beamformer, default set to 0 +* +WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS I 4 19 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +* +* MU Beamformer Capable +* Riva/Pronto does not support, default set to 0 +* +WNI_CFG_VHT_MU_BEAMFORMER_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* MU Beamformee Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_MU_BEAMFORMEE_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* VHT TXOP PS +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_TXOP_PS I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* +HTC-VHT Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_HTC_VHTC_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Maximum AMPDU Length exponent range 0-7 +* 2^(13+Max AMPDU Length)-1, default set to 0 +* +WNI_CFG_VHT_AMPDU_LEN_EXPONENT I 4 19 +V RW NP +LIM +0 7 3 +V RW NP +LIM +0 7 3 + +* +* VHT Link Adaptation Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_LINK_ADAPTATION_CAP I 4 19 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +* +* VHT Rx Antenna Pattern Consistency +* +WNI_CFG_VHT_RX_ANT_PATTERN I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* VHT Tx Antenna Pattern Consistency +* +WNI_CFG_VHT_TX_ANT_PATTERN I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* RxMCS Map is 16 bits, The 2bit Max MCS for n SS field. +* Indicates the maximum MCS that can be received for each +* number of spacial streams. Riva supports MCS 0-9 +* +WNI_CFG_VHT_RX_MCS_MAP I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* TxMCS Map is 16 bits, The 2bit Max MCS for n SS field. +* Indicates the maximum MCS that can be transmitted for each +* number of spacial streams. +* +WNI_CFG_VHT_TX_MCS_MAP I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* +* Rx Highest supported data rate. +* +WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE I 4 19 +V RW NP +LIM +0 780 780 +V RW NP +LIM +0 780 780 + +* +* Tx Highest supported data rate. +* +WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE I 4 19 +V RW NP +LIM +0 780 780 +V RW NP +LIM +0 780 780 + +* +* Channel center freq Seg1 +* +WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1 I 4 19 +V RW NP +LIM +0 256 0 +V RW NP +LIM +0 256 0 + +* +* Channel center freq Seg2 for 80+80 Mhz +* +WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2 I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Basic MCS Set +* +WNI_CFG_VHT_BASIC_MCS_SET I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* +* MU-MIMO Capable STA Count +* +WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT I 4 19 +V RW NP +LIM +0 4 0 +V RW NP +LIM +0 4 0 + +* +* Spatial Stream Under-Utilization +* +WNI_CFG_VHT_SS_UNDER_UTIL I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Forty MHZ Utilization +* +WNI_CFG_VHT_40MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Eighty MHz Utilization +* +WNI_CFG_VHT_80MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Hundred Sixty MHz Utilization +* +WNI_CFG_VHT_160MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Maximum AMSDU length +* User can set it to either 3839 or 7935 bytes. +* +WNI_CFG_MAX_AMSDU_LENGTH I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 0 + +#ENUM SHORT_3839_BYTES 0 +#ENUM LONG_7935__BYTES 1 + + +* +* Minimum MPDU Start Spacing +* Determines the minimum time between the start of adjacent MPDUs within an AMPDU. +* Set to 0 for no restriction +* Set to 1 for 1/4 s +* Set to 2 for 1/2 s +* Set to 3 for 1 s +* Set to 4 for 2 s +* Set to 5 for 4 s +* Set to 6 for 8 s +* Set to 7 for 16 s +* default is set to 0 +WNI_CFG_MPDU_DENSITY I 4 7 +V RW NP RESTART +LIM +0 7 0 +V RW NP RESTART +LIM +0 7 0 + +* +* NUM BUFFERS ADVERTISED +* Defines number of buffers advertised in ADDBA +* +WNI_CFG_NUM_BUFF_ADVERT I 4 7 +V RW NP +LIM +0 128 64 +V RW NP +LIM +0 128 64 + +* +* Maximum Rx AMPDU Factor +* Indicates the maximum length of A-MPDU +* that the STA can receive. +* The Maximum Rx A-MPDU defined by this field is equal to (2 ^ (13 + MAX RX AMPDU FActor))-1 octets. +* Maximum Rx A-MPDU Factor is an integer in the range 0 to 3. +* default is set to 2 for 32K max RX side. +* +WNI_CFG_MAX_RX_AMPDU_FACTOR I 4 7 +V RW NP RESTART +LIM +0 3 3 +V RW NP RESTART +LIM +0 3 3 + + +* +* Short GI support for the reception of 20Mhz packets +* By default it is enabled +* +WNI_CFG_SHORT_GI_20MHZ I 4 7 +V RW NP RESTART +LIM +0 1 1 +V RW NP RESTART +LIM +0 1 1 + + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* +* Short GI support for the reception of 40Mhz packets +* By default it is enabled +* +WNI_CFG_SHORT_GI_40MHZ I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 1 + + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* +* RIFS support on TX Side +* on RX side it is always supported, it is mandatory +* +WNI_CFG_RIFS_ENABLED I 4 7 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* ********************************************************* +* +* Power Save Configuration +* +WNI_CFG_MAX_PS_POLL I 4 5 +V RW NP +LIM +0 255 0 +NV RW NP +LIM +0 255 0 + + +WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE I 4 5 +V RW NP +LIM +1 20 20 +NV RW NP +LIM +1 20 20 + +WNI_CFG_MIN_RSSI_THRESHOLD I 4 5 +V RW NP +LIM +0 10 10 +NV RW NP +LIM +0 10 10 + + +WNI_CFG_NTH_BEACON_FILTER I 4 5 +V RW NP +LIM +0 255 10 +NV RW NP +LIM +0 255 10 + + +WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE I 4 5 +V RW NP +LIM +0 1 0 +NV RW NP +LIM +0 1 0 + + +WNI_CFG_SCAN_IN_POWERSAVE I 4 5 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* ********************************************************* +* +* WoWLAN Configuration The following configurations +* are valid only when magicPktEnable = 1. +* +WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_DEAUTH_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_DISASSOC_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_MAX_MISSED_BEACON I 4 5 +V RW NP +NONE +0 65535 40 +NV RW NP +NONE +0 65535 40 + +* +* Timeout value in units of us. It requests +* hardware to unconditionally wake up after +* it has stayed in WoWLAN mode for some time. +* +WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD I 4 5 +V RW NP +NONE +0 65535 65535 +NV RW NP +NONE +0 65535 65535 + + +* +* BA timeout in TUs, set to 1 minute = approx 58593 TUs +* 16 bit wide +* +WNI_CFG_BA_TIMEOUT I 4 7 +V RW NP RESTART +HAL +0 0xffff 0 +V RW NP +HAL +0 0xffff 0 + + +* +* This threshold is registered with a traffic monitoring interface (probably HAL), +* on a per-STA, per-TID basis. Once this threshold has been reached, +* HAL will indicate to PE that the threshold has been reached for that TID. +* PE is then free to negotiate a BA session for that peer +* defaults to 128 +* 16 bit wide +* +WNI_CFG_BA_THRESHOLD_HIGH I 4 7 +V RW NP RESTART +HAL +0 0xffff 0x80 +V RW NP +HAL +0 0xffff 0x80 + + +* +* MAX BA Buffers to be allocated. +* This count is system wide. +* 16 bit wide +* +WNI_CFG_MAX_BA_BUFFERS I 4 7 +V RW NP RESTART +HAL +0 2560 2560 +V RW NP +HAL +0 2560 2560 + + +* +* MAX BA Sessions. +* This count is system wide. +* 16 bit wide +* +WNI_CFG_MAX_BA_SESSIONS I 4 7 +V RW NP RESTART +HAL +0 64 40 +V RW NP +HAL +0 64 40 + + +* +* BA setup based on Traffic +* +WNI_CFG_BA_AUTO_SETUP I 4 7 +V RW NP RESTART +HAL +0 1 1 +V RW NP RESTART +HAL +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +* +* Decline an ADDBA Request +* +WNI_CFG_ADDBA_REQ_DECLINE I 4 7 +V RW NP RESTART +LIM +0 0xff 0 +V RW NP RESTART +LIM +0 0xff 0 + +* +* Valid Channel List +* + +WNI_CFG_BG_SCAN_CHANNEL_LIST S 100 8 +V RW NP +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 +V RW NP +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 + +* +* Maximum number of MPDUs in single A-MPDU. +* +WNI_CFG_MAX_MPDUS_IN_AMPDU I 4 8 +V RW NP +HAL +0 65535 64 +V RW NP +HAL +0 65535 64 + + +* +* Auto BSSID - When set, BSSID is generated automatically in IBSS, else BSSID in cfg will be used. +* + +WNI_CFG_IBSS_AUTO_BSSID I 4 0 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 1 + +* +* Include Additional IEs in probe request. +* +WNI_CFG_PROBE_REQ_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in probe request. +* +WNI_CFG_PROBE_REQ_ADDNIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IEs in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA1 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA2 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA3 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IEs in assoc response. +* +WNI_CFG_ASSOC_RSP_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in assoc response. +* +WNI_CFG_ASSOC_RSP_ADDNIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional P2P IEs in probe request. +* +WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional P2P IE in probe request. +* +WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IEs in probe response/beacon. +* +WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA S 255 0 +V RW NP +LIM +0 0 +V RW NP +LIM +0 0 + + +* +* wpsApEnable and wpsStaEnable is specified in here +* wpsApEnable is bit #0 and wpsStaEnable is bit #1 +* +WNI_CFG_WPS_ENABLE I 4 7 +V RW NP +LIM +0 0xff 0 +V RW NP +LIM +0 0xff 0 + +#ENUM AP 1 +#ENUM STA 2 + +WNI_CFG_WPS_STATE I 4 7 +V RW NP +LIM +0 0xff 1 +V RW NP +LIM +0 0xff 1 + +* +* TRUE => include this information in Probe Requests, FALSE => omit it +* + +WNI_CFG_WPS_PROBE_REQ_FLAG I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Wi-Fi Protected Setup Version +* +* This 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. +* + +WNI_CFG_WPS_VERSION I 4 7 +V RW NP +LIM +0 0xff 0x10 +V RW NP +LIM +0 0xff 0x10 + +* +* Wi-Fi Protected Setup Request type +* 0x00: Enrollee, Info only +* 0x01: Enrollee, open 802.1X +* 0x02: Registrar +* 0x03: WLAN Manager Registrar + +WNI_CFG_WPS_REQUEST_TYPE I 4 7 +V RW NP +LIM +0 0xff 0x00 +V RW NP +LIM +0 0xff 0x03 + +* Configuration Method(s) +* +* 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. +* +* 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 +* +* The bottom 16 bits contain the configuration method(s) when acting +* as an Enrollee, and the top 16 when acting as a Registrar. +* +* QNE-TODO: Merge this with the inappropriately named +* 'WNI_CFG_WSC_AP_CFG_METHOD'-- this one can serve both puposes. +* + +WNI_CFG_WPS_CFG_METHOD I 4 7 +V RW NP +LIM +0 0xFFFFFFFF 0x00000008 +V RW NP +LIM +0 0xFFFFFFFF 0x018c018e + +* UUID +* The universally unique identifier (UUID) element is a unique +* GUID generated by the Enrollee or 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. +* +* QNE-TODO: Re-name their cfg from 'WNI_CFG_UUID' + +WNI_CFG_WPS_UUID S 16 8 +V RW NP +LIM +6 0xa 0xb 0xc 0xd 0xe 0xf +V RW NP +LIM +6 0xa 0xb 0xc 0xd 0xe 0xf + +************************************************************************ +* The following cfgs contains the primary type of the device. Its format +* follows: +* +* 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 | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* +* 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. +* +* 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 +* +************************************************************************ + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_CATEGORY' +WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY I 4 7 +V RW NP +LIM +0 0xffff 1 +V RW NP +LIM +0 0xffff 6 + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_OUI' +WNI_CFG_WPS_PIMARY_DEVICE_OUI I 4 7 +V RW NP +LIM +0 0xffffffff 0x0050f204 +V RW NP +LIM +0 0xffffffff 0x0050f204 + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_SUB_CATEGORY' +WNI_CFG_WPS_DEVICE_SUB_CATEGORY I 4 7 +V RW NP +LIM +0 0xffff 1 +V RW NP +LIM +0 0xffff 1 + +* Association State +* + +* The Association State component shows the configuration and previous +* association state of the wireless station when sending a Discovery +* request. +* +* Association State Description +* 0 Not Associated +* 1 Connection Success +* 2 Configuration Failure +* 3 Association Failure +* 4 IP Failure + +WNI_CFG_WPS_ASSOCIATION_STATE I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* Configuration Error +* +* The Configuration Error component shows the result of the device +* attempting to configure itself and to associate with the WLAN. +* +* 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 Couldnt 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 +* +* 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. + +WNI_CFG_WPS_CONFIGURATION_ERROR I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* 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. +* +* Value Description +* 0x0000 Default (PIN) +* 0x0001 User-specified +* 0x0002 Machine-specified +* 0x0003 Rekey +* 0x0004 PushButton +* 0x0005 Registrar-specified +* 0x0006 - 0x000F Reserved' +* + +WNI_CFG_WPS_DEVICE_PASSWORD_ID I 4 7 +V RW NP +LIM +0 0xffffffff 0 +V RW NP +LIM +0 0xffffffff 0 + +* +* WPS Association +* +* Wi-Fi Protected Setup requires a prospective enrollee to associate to +* an AP in the network in which the STA would like to enroll. Once +* associated, the enrollment takes place over an EAPOL conversation +* (there's actually a new EAP method: EAP-WSC). The STA would +* presumably send an EAPOL-Start over his new link, to which the AP +* would respond with an EAP Identity Request. When the STA sends back +* "WSC-Enrollee-1" as his EAP Identity, the AP knows that he's got a WPS +* supplicant on his hands, and proceeds to talk EAP-WSC. +* +* Toward the end of the specification's development, a problem came up. +* Microsoft's EAP supplicant on XP SP1 & SP2 will send an EAPOL-Start, +* no matter what. Even if the AP is beaconing WPA-PSK, say, the MS +* supplicant will send an EAPOL-Start. If it receives an EAP Identity +* Request in return, it decides that the AP is really using 802.1x +* authentication, and proceeds on that assumption. +* +* Now, imagine an AP that is configured for WPA-PSK, and is WPS-capable. +* It receives an association request from some STA, and then sees an +* EAPOL-Start from the newly joined STA. It naturally sends back an EAP +* Identity Request to see if the new STA wants to talk EAP-WSC. On +* Windows XP SP1 & SP2, the supplicant will take that to mean that this +* AP is using 802.1x authentication, and will never let the user provide +* the PSK. Consequently, WZC will never be able to associate with this +* AP. +* +* Naturally, Microsoft's solution was to have the world change to +* accommodate them. After a lot of back & forth, the WFA decided on the +* following change to the WPS spec: when associating for purposes of WPS +* enrollment, "A client that intends to use the EAP-WSC method with a +* WSC enabled AP may include a WSC IE in its 802.11 (re)association +* request. If a WSC IE is present in the (re)association request, the AP +* shall engage in EAP-WSC with the station and must not attempt other +* security handshake. If the client does not include a WSC IE in its +* 802.11 (re)association request, it must send its 802.11 Authentication +* frame with Authentication set to open and an 802.11 Association +* Request frame without an RSN IE or SSN IE, regardless of the network +* type that is hosted by the AP. On successful association, the client +* will then send an EAPOL-Start to the AP and wait for +* EAP-Request/Identity. When the client receives an EAP Request/ +* Identity, it will respond with EAP-Response/Identity and the +* appropriate WSC string to indicate if it is an Enrollee or Registrar. +* ' +* +* This configuration variable contains a bitvector: +* +* 0x0001 Incldue the WPS Information Element in Assoc Request frames +* 0x0002 Elide the the WPA and RSN Information Elements from the +* Assoc Request frame +* + +WNI_CFG_WPS_ASSOC_METHOD I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* +* Listen Mode Enable/Disable +* + +WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE I 4 7 +V RW NP +HAL +0 128 128 +V RW NP +HAL +0 128 128 + +* +* On chip reodering polling threshold +* + +WNI_CFG_RPE_POLLING_THRESHOLD I 4 2 +V RW NP +HAL +0 65535 10 +V RW NP +HAL +0 65535 10 + +* +* On chip reodering aging threshold for AC0 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC1 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC2 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC3 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* Number of On-Chip reorder sessions +* + +WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS I 4 2 +V RW NP +HAL +0 2 1 +V RW NP +HAL +0 2 1 + + +* +* Single RC for all TID +* + +WNI_CFG_SINGLE_TID_RC I 4 7 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* RRM Enabled +* + +WNI_CFG_RRM_ENABLED I 4 8 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* RRM measurement max duration. Section 11.10.3 802.11k-2008. +* Max Duration represented as maxDuration inTUs = 2^(*WNI_CFG_RRM_IN_CHAN_MAX - 4) * bcnIntvl +* Operating channel max measurement duration. +* + +WNI_CFG_RRM_OPERATING_CHAN_MAX I 4 8 +V RW NP +NONE +0 8 0 +V RW NP +NONE +0 8 0 + +* +* Non-Operating channel max measurement duration. +* + +WNI_CFG_RRM_NON_OPERATING_CHAN_MAX I 4 8 +V RW NP +NONE +0 8 0 +V RW NP +NONE +0 8 0 + +* +* TX power control feature +* + +WNI_CFG_TX_PWR_CTRL_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* BTC DHCP No of Bt slots to block +* +WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK I 4 7 +V RW NP +HAL +0 0xFF 0 +V RW NP +HAL +0 0xFF 0 + +* +* Config parameter to Enable/Disable Telescopic Bcn Wakeups +* 0: Disable, 1: Enable +* + +WNI_CFG_TELE_BCN_WAKEUP_EN I 4 7 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* Config parameter for Max LI +* 0: Disable, x: Max LI +* + +WNI_CFG_TELE_BCN_MAX_LI I 4 7 +V RW NP +HAL +0 7 5 +V RW NP +HAL +0 7 5 + +* +* BTC DHCP No of Bt sub interval during DHCP +* +WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS I 4 7 +V RW NP +HAL +0 0xFF 7 +V RW NP +HAL +0 0xFF 7 + +* +* Infra STA mode Keep alive period (in secs) for +* sending keep alive (Qos)Null frames to the AP. +* 0 = disabled. Recommended values is 30 secs +* +WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD I 4 7 +V RW NP +HAL +0 1000 0 +V RW NP +HAL +0 1000 0 + +* Limit on number of associated stations +* (applies to peer stations in IBSS, SoftAP, BT-AMP AP, & P2P-GO modes) +* + +WNI_CFG_ASSOC_STA_LIMIT I 4 8 +V RW NP +LIM +1 32 10 +V RW NP +LIM +1 32 10 + +* +* SAP channel select start channel number +* +WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL I 4 7 +V RW NP +NONE +1 0xFC 1 +V RW NP +NONE +1 0xFC 1 + +* +* SAP channel select end channel number +* +WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL I 4 7 +V RW NP +NONE +1 0xFC 11 +V RW NP +NONE +1 0xFC 11 + +* +* SAP channel select operating band +* 0- 2.4GHZ / 1- Low 5GHZ /2-MID /3-HIGH/4-Japan4.9GHZ +* +WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND I 4 7 +V RW NP +NONE +0 0x5 0 +V RW NP +NONE +0 0x5 0 + +* +* Close loop power control will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_CLOSE_LOOP I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* LTE Coexistence will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_LTE_COEX I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* AP Keep Alive Timeout (TU) +* +WNI_CFG_AP_KEEP_ALIVE_TIMEOUT I 4 7 +V RW NP +HAL +1 65535 20 +V RW NP +HAL +1 65535 20 + +* +* GO Keep Alive Timeout (TU) +* +WNI_CFG_GO_KEEP_ALIVE_TIMEOUT I 4 7 +V RW NP +HAL +1 65535 20 +V RW NP +HAL +1 65535 20 + +* +* MC Addr List power control will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_MC_ADDR_LIST I 4 0 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* UC Filter will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_UC_FILTER I 4 0 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* MCC Adaptive Scheduler will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 +* +*Disable LDPC in STA mode when AP is TXBF capable +* +* +* +WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* AP Link Monitor Timeout (TU) +* +WNI_CFG_AP_LINK_MONITOR_TIMEOUT I 4 7 +V RW NP +HAL +1 255 3 +V RW NP +HAL +1 255 3 + +* +*TDLS Station's UAPSD MASK Configuration +* +* +* +WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK I 4 7 +V RW NP +LIM +0 15 0 +V RW NP +LIM +0 15 0 +* +*TDLS Stations Buffer STA Capability +* +* +* +WNI_CFG_TDLS_BUF_STA_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 +*TDLS Stations PUAPSD Inactivity Timer +* +* +* +WNI_CFG_TDLS_PUAPSD_INACT_TIME I 4 7 +V RW NP +LIM +0 10 0 +V RW NP +LIM +0 10 0 +*TDLS Stations PUAPSD RX Frame Threshold +* +* +* +WNI_CFG_TDLS_RX_FRAME_THRESHOLD I 4 7 +V RW NP +LIM +10 20 10 +V RW NP +LIM +10 20 10 + +* +* PMF SA Query Maximum Retries +* + +WNI_CFG_PMF_SA_QUERY_MAX_RETRIES I 4 1 +V RW NP RESTART +NONE +0 20 5 +V RW NP RESTART +NONE +0 20 5 + +* +* PMF SA Query Retry Interval (in TUs) +* + +WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL I 4 1 +V RW NP RESTART +NONE +10 2000 200 +V RW NP RESTART +NONE +10 2000 200 + +* +* FlexConnect Power Factor +* Default is set to 0 (disable) +* +* +WNI_CFG_FLEX_CONNECT_POWER_FACTOR I 4 0 +V RW NP +NONE +0 9 0 +V RW NP +NONE +0 9 0 + +* GO Link Monitor Timeout (TU) +* +WNI_CFG_GO_LINK_MONITOR_TIMEOUT I 4 7 +V RW NP +HAL +3 50 10 +V RW NP +HAL +3 50 10 +* +* + +* RMC action period frequency (milli seconds) +* +WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY I 4 7 +V RW NP +HAL +100 1000 300 +V RW NP +HAL +100 1000 300 +* +* + +* Current RSSI value (of connected AP) +* +WNI_CFG_CURRENT_RSSI I 4 7 +V RW NP +NONE +0 127 0 +V RW NP +NONE +0 127 0 + +* RTT3 Bit Value +* +WNI_CFG_RTT3_ENABLE I 1 1 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* Debug p2p remain on channel +* +WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* TDLS Off Channel Implementation +* +WNI_CFG_TDLS_OFF_CHANNEL_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +WNI_CFG_IBSS_ATIM_WIN_SIZE I 4 7 +V RW NP +NONE +0 100 0 +V RW NP +NONE +0 100 0 + +* +* DFS Master capability (11h) enable/disable +* + +WNI_CFG_DFS_MASTER_ENABLED I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +WNI_CFG_VHT_ENABLE_TXBF_20MHZ I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 +* +*TDLS WMM Mode +* +* +WNI_CFG_TDLS_WMM_MODE_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms new file mode 100644 index 0000000000000000000000000000000000000000..442d965071ad03ebe5ce88480db481f456ce8c02 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms @@ -0,0 +1,4326 @@ +/* + * Copyright (c) 2006-2007, 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. + */ + +/** + * \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_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 VHT_TRANSMIT_POWER_ENVELOPE = 195; +const EID_CHANNEL_SWITCH_WRAPPER = 196; +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; + +///////////////////////////////////////////////////////////////////////////// +// 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; + pbcc: 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; + } +} + +IE addba_extn_element(EID_ADDBA_EXTN_ELEMENT) +{ + { + no_fragmentation: 1; + he_frag_operation: 2; + reserved: 5; + } +} + +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 ]; + + /** + * \breif 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 IBSSParams (EID_IBSS_PARAM_SET) // 7.3.2.7 +{ + atim, 2; +} + +IE ChallengeText (EID_CHALLENGE_TEXT) // 7.3.2.8 +{ + text[1..253]; +} + +IE RequestedInfo (EID_REQUEST) // 7.3.2.12 +{ + requested_eids[0..255]; +} + +IE Country (EID_COUNTRY) // 7.3.2.9 +{ + country[3]; + OPTIONAL triplets[3][0..84]; +} + +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 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; +} + +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; + } + 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 + } + }; +} + +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 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 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; + reserved1: 2; + } + rxMCSMap, 2; + { + rxHighSupDataRate: 13; + reserved2: 3; + } + txMCSMap, 2; + { + txSupDataRate: 13; + reserved3: 3; + } +} + +IE VHTOperation (EID_VHT_OPERATION_ELEMENT) +{ + chanWidth, 1; + chanCenterFreqSeg1, 1; + chanCenterFreqSeg2, 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 vht_transmit_power_env (VHT_TRANSMIT_POWER_ENVELOPE) +{ + bytes[2..5]; +} + +IE ChannelSwitchWrapper (EID_CHANNEL_SWITCH_WRAPPER) +{ + OPTIE IE WiderBWChanSwitchAnn; + OPTIE IE vht_transmit_power_env; +} +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; + reserved: 11; + } + + + // 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; + reserved: 2; + rxNSS: 3; + rxNSSType: 1; + } +} + +IE QosMapSet (EID_QOS_MAP_SET) +{ + dscp_exceptions[0..60]; +} + +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]; +} + +IE QCN_IE (EID_VENDOR_SPECIFIC) OUI ( 0x8C, 0xFD, 0xF0, 0x01 ) +{ + version[4]; +} + +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_BEACON_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; + +IE BeaconReporting (EID_RRM_BEACON_REPORTING) +{ + reportingCondition, 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; + } + Beacon (measurement_type IS 5) + { + regClass, 1; + channel, 1; + randomization, 2; + meas_duration, 2; + meas_mode, 1; + BSSID[6]; + OPTIE SSID; + OPTIE BeaconReporting; + OPTIE BcnReportingDetail; + OPTIE RequestedInfo; + 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; + } + + }; +} + +IE he_cap (EID_EXTN_ID_ELEMENT) OUI (0x23) +{ + { + htc_he:1; + twt_request:1; + twt_responder:1; + fragmentation:2; + max_num_frag_msdu:3; + min_frag_size:2; + trigger_frm_mac_pad:2; + multi_tid_aggr:3; + he_link_adaptation:2; + all_ack:1; + ul_mu_rsp_sched:1; + a_bsr:1; + broadcast_twt:1; + ba_32bit_bitmap:1; + mu_cascade:1; + ack_enabled_multitid:1; + dl_mu_ba:1; + omi_a_ctrl:1; + ofdma_ra:1; + max_ampdu_len:2; + amsdu_frag:1; + flex_twt_sched:1; + rx_ctrl_frame:1; + } + { + bsrp_ampdu_aggr:1; + qtp:1; + a_bqr:1; + sr_responder:1; + ndp_feedback_supp:1; + ops_supp:1; + amsdu_in_ampdu:1; + reserved1:1; + } + { + dual_band: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_rx_max_nsts:2; + he_4x_ltf_3200_gi_ndp:1; + 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; + 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_rx_1x_he_ltf:1; + reserved2:2; + } + 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) +{ + { + bss_color: 6; + default_pe: 3; + twt_required: 1; + rts_threshold: 10; + partial_bss_col: 1; + vht_oper_present: 1; + reserved1: 6; + mbssid_ap: 1; + tx_bssid_ind: 1; + bss_col_disabled: 1; + reserved2: 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 mbssid_ap) + { + info (mbssid_ap IS 1) + { + data, 1; + } + }; +} + +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 reponse 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; +} + +///////////////////////////////////////////////////////////////////////////// +// 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 IBSSParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscBeacon; + OPTIE P2PBeacon; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE fils_indication; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; + OPTIE MBO_IE; + OPTIE QCN_IE; + OPTIE he_cap; + OPTIE he_op; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE esp_information; +} // 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, & IBSSParams. 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; + OPTIE IBSSParams; +} + +FRAME Beacon2 +{ + OPTIE Country; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE EDCAParamSet; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WscBeacon; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE P2PBeacon; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE fils_indication; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; + OPTIE QCN_IE; + OPTIE he_cap; + OPTIE he_op; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE esp_information; +} + +// 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 IBSSParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESEVersion; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscBeaconProbeRes; + OPTIE P2PBeaconProbeRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE fils_indication; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE MBO_IE; + OPTIE QCN_IE; + OPTIE he_cap; + OPTIE he_op; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE esp_information; +} // 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 OperatingMode; + OPTIE PowerCaps; + OPTIE SuppChannels; + OPTIE HTCaps; + OPTIE QOSCapsStation; + OPTIE RSNOpaque; + OPTIE ExtSuppRates; + OPTIE MobilityDomain; + OPTIE SuppOperatingClasses; + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE RRMEnabledCap; + OPTIE QosMapSet; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE fils_session; + OPTIE fils_public_key; + OPTIE fils_key_confirmation; + OPTIE fils_hlp_container; + OPTIE fragment_ie; + OPTIE dh_parameter_element; + 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 he_cap; + 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 RICDataDesc[2]; + OPTIE WPA; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE WMMTSPEC[0..4]; + OPTIE WscAssocRes; + OPTIE P2PAssocRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE QosMapSet; + OPTIE fils_session; + OPTIE fils_public_key; + OPTIE fils_key_confirmation; + OPTIE fils_hlp_container; + OPTIE fragment_ie; + OPTIE fils_kde; + OPTIE vendor_vht_ie; + OPTIE QCN_IE; + OPTIE he_cap; + OPTIE he_op; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE MBO_IE; +} // 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 WPAOpaque; + OPTIE HTCaps; + OPTIE WMMCaps; + OPTIE WMMInfoStation; + OPTIE WscIEOpaque; + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESEVersion; + OPTIE ESECckmOpaque; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE P2PIEOpaque; + OPTIE WFDIEOpaque; + OPTIE VHTCaps; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE QosMapSet; + OPTIE vendor_vht_ie; + OPTIE hs20vendor_ie; + OPTIE he_cap; +} // 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 WPA; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE WMMParams; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE WscReassocRes; + OPTIE P2PAssocRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE QosMapSet; + OPTIE vendor_vht_ie; + OPTIE he_cap; + OPTIE he_op; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE MBO_IE; +} // End frame ReAssocResponse. + +FRAME ProbeRequest // 7.2.3.8 +{ + MANDIE SSID; + MANDIE SuppRates; + OPTIE RequestedInfo; + OPTIE ExtSuppRates; + OPTIE DSParams; + OPTIE HTCaps; + OPTIE WscProbeReq; + OPTIE WFATPC; + OPTIE P2PProbeReq; + OPTIE VHTCaps; + OPTIE ExtCap; + OPTIE QCN_IE; + OPTIE he_cap; +} // 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 IBSSParams; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE RRMEnabledCap; + OPTIE APChannelReport; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscProbeRes; + OPTIE P2PProbeRes; + + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE fils_indication; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; + OPTIE MBO_IE; + OPTIE QCN_IE; + OPTIE he_cap; + OPTIE he_op; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE esp_information; +} // 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; +} // 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..2]; +} + +FRAME RadioMeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + //Measurement Report elements. + MANDIE MeasurementReport[1..4]; +} + +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; +} + +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; +} + +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; +} + +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; +} +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; +} + +FRAME SaQueryRsp +{ + FF Category; + FF Action; + FF TransactionId; +} + +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; +} + +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; +} + +// 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/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_api.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..05c705c18f715e3a5ad2be5ac8f93cb8095d736b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_api.c @@ -0,0 +1,905 @@ +/* + * 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. + */ + +/* + * + * This file contains the source code for CFG API functions. + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ + +#include "cds_api.h" +#include "cfg_priv.h" +#include "wma_types.h" +#include "cfg_api.h" + +/* --------------------------------------------------------------------- */ +/* Static Variables */ +/* ---------------------------------------------------------------------- */ +static tCfgCtl __g_cfg_entry[CFG_PARAM_MAX_NUM]; +static uint8_t __g_s_buffer[CFG_MAX_STR_LEN]; +static uint32_t __g_param_list[WNI_CFG_MAX_PARAM_NUM + + WNI_CFG_GET_PER_STA_STAT_RSP_NUM]; + +static void notify(tpAniSirGlobal, uint16_t, uint32_t); + +typedef enum { + eRF_BAND_UNKNOWN = 0, + eRF_BAND_2_4_GHZ = 1, + eRF_BAND_5_GHZ = 2 +} eRfBandMode; + +extern cfgstatic_string cfg_static_string[CFG_MAX_STATIC_STRING]; +extern cgstatic cfg_static[CFG_PARAM_MAX_NUM]; + +/* --------------------------------------------------------------------- */ +uint32_t cfg_need_restart(tpAniSirGlobal pMac, uint16_t cfgId) +{ + if (!pMac->cfg.gCfgEntry) { + pe_err("gCfgEntry is NULL"); + return 0; + } + return !!(pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_RESTART); +} + +static void cfg_get_strindex(tpAniSirGlobal pMac, uint16_t cfgId) +{ + uint16_t i = 0; + + for (i = 0; i < CFG_MAX_STATIC_STRING; i++) { + if (cfgId == cfg_static_string[i].cfgId) + break; + } + if (i == CFG_MAX_STATIC_STRING) { + pe_warn("Entry not found for cfg id: %d", cfgId); + cfg_static[cfgId].pStrData = NULL; + return; + } + cfg_static[cfgId].pStrData = &cfg_static_string[i]; +} +/* --------------------------------------------------------------------- */ +uint32_t cfg_need_reload(tpAniSirGlobal pMac, uint16_t cfgId) +{ + if (!pMac->cfg.gCfgEntry) { + pe_err("gCfgEntry is NULL"); + return 0; + } + return !!(pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_RELOAD); +} + +/* --------------------------------------------------------------------- */ +QDF_STATUS cfg_init(tpAniSirGlobal pMac) +{ + uint16_t i = 0; + uint16_t combined_buff_size = 0; + uint32_t max_i_count = 0; + uint32_t max_s_count = 0; + cfgstatic_string *str_cfg; + + pMac->cfg.gSBuffer = __g_s_buffer; + pMac->cfg.gCfgEntry = __g_cfg_entry; + pMac->cfg.gParamList = __g_param_list; + + for (i = 0; i < CFG_PARAM_MAX_NUM; i++) { + if (!(cfg_static[i].control & CFG_CTL_INT)) { + cfg_get_strindex(pMac, i); + } else { + cfg_static[i].pStrData = NULL; + } + } + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + if (cfg_static[i].control & CFG_CTL_INT) { + max_i_count++; + } else { + str_cfg = (cfgstatic_string *)cfg_static[i].pStrData; + if (str_cfg == NULL) { + pe_warn("pStrCfg is NULL for CfigID: %d", i); + continue; + } + /* + 2 to include len field and max len field */ + max_s_count += str_cfg->maxLen + 2; + } + } + + pMac->cfg.gCfgMaxIBufSize = max_i_count; + pMac->cfg.gCfgMaxSBufSize = max_s_count; + + /* Allocate a combined memory */ + combined_buff_size = max_s_count + (3 * sizeof(uint32_t) * max_i_count); + + pe_debug("Size of cfg I buffer: %d S buffer: %d", + max_i_count, max_s_count); + + pe_debug("Allocation for cfg buffers: %d bytes", combined_buff_size); + + if (combined_buff_size > 4 * PAGE_SIZE) { + pe_err("Mem alloc request too big"); + return QDF_STATUS_E_NOMEM; + } + /* at this point pMac->cfg.gCfgSBuf starts */ + pMac->cfg.gCfgSBuf = qdf_mem_malloc(combined_buff_size); + if (NULL == pMac->cfg.gCfgSBuf) { + pe_err("Failed to allocate memory for cfg array"); + return QDF_STATUS_E_NOMEM; + } + /* at offset max_s_count, pMac->cfg.gCfgIBuf starts */ + pMac->cfg.gCfgIBuf = (uint32_t *)&pMac->cfg.gCfgSBuf[max_s_count]; + /* after max_i_count integers, pMac->cfg.gCfgIBufMin starts */ + pMac->cfg.gCfgIBufMin = &pMac->cfg.gCfgIBuf[max_i_count]; + /* after max_i_count integers, pMac->cfg.gCfgIBufMax starts */ + pMac->cfg.gCfgIBufMax = &pMac->cfg.gCfgIBufMin[max_i_count]; + + return QDF_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------- */ +void cfg_de_init(tpAniSirGlobal pMac) +{ + qdf_mem_free(pMac->cfg.gCfgSBuf); + pMac->cfg.gCfgIBufMin = NULL; + pMac->cfg.gCfgIBufMax = NULL; + pMac->cfg.gCfgIBuf = NULL; + pMac->cfg.gCfgSBuf = NULL; + pMac->cfg.gSBuffer = NULL; + pMac->cfg.gCfgEntry = NULL; + pMac->cfg.gParamList = NULL; +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_check_valid() + * + * FUNCTION: + * This function is called to check if a parameter is valid + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + */ +QDF_STATUS cfg_check_valid(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *index) +{ + uint32_t control; + + if (cfgId >= CFG_PARAM_MAX_NUM) { + pe_warn("Invalid cfg id: %d", cfgId); + return QDF_STATUS_E_INVAL; + } + if (!pMac->cfg.gCfgEntry) { + pe_warn("gCfgEntry is NULL"); + return QDF_STATUS_E_INVAL; + } + + control = pMac->cfg.gCfgEntry[cfgId].control; + + /* Check if parameter is valid */ + if ((control & CFG_CTL_VALID) == 0) { + pe_warn("Not valid cfg id: %d", cfgId); + return QDF_STATUS_E_INVAL; + } + + *index = control & CFG_BUF_INDX_MASK; + + if (*index >= pMac->cfg.gCfgMaxSBufSize) { + pe_warn("cfg index out of bounds: %d", *index); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; + +} /*** end cfg_check_valid() ***/ + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_int() + * + * FUNCTION: + * This function is called to update an integer parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Range checking is performed by the calling function. In case this + * function call is being triggered by a request from host, then host + * is responsible for performing range checking before sending the + * request. + * + * - Host RW permission checking should already be done prior to calling + * this function by the message processing function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param value: 32-bit unsigned value + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + */ + +QDF_STATUS cfg_set_int(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t value) +{ + uint32_t index; + uint32_t control; + uint32_t mask; + QDF_STATUS status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (QDF_STATUS_SUCCESS != status) + return status; + + if ((pMac->cfg.gCfgIBufMin[index] > value) || + (pMac->cfg.gCfgIBufMax[index] < value)) { + pe_warn("Value: %d out of range: [%d,%d] cfg id: %d, %s", + value, pMac->cfg.gCfgIBufMin[index], + pMac->cfg.gCfgIBufMax[index], cfgId, + cfg_get_string(cfgId)); + return QDF_STATUS_E_INVAL; + } else { + /* Write integer value */ + pMac->cfg.gCfgIBuf[index] = value; + + control = pMac->cfg.gCfgEntry[cfgId].control; + /* Update hardware if necessary */ + mask = control & CFG_CTL_NTF_MASK; +#ifdef WLAN_DEBUG + if ((mask & CFG_CTL_NTF_HW) != 0) + pe_debug("CFG notify HW not supported!!!"); +#endif + /* notify other modules if necessary */ + if ((mask & CFG_CTL_NTF_MASK) != 0) + notify(pMac, cfgId, mask); + } + return status; +} /*** end cfg_set_int ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_int() + * + * FUNCTION: + * This function is called to read an integer parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pVal: address where parameter value will be written + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + */ + +QDF_STATUS wlan_cfg_get_int(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pValue) +{ + uint32_t index; + QDF_STATUS status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (QDF_STATUS_SUCCESS != status) + return status; + + /* Get integer value */ + *pValue = pMac->cfg.gCfgIBuf[index]; + + return QDF_STATUS_SUCCESS; +} /*** end wlan_cfg_get_int() ***/ + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_str() + * + * FUNCTION: + * This function is called to set a string parameter. + * + * LOGIC: + * This function invokes the cfg_set_str_notify function passing the notify + * bool value set to true. This basically means that HAL needs to be + * notified. This is true in the case of non-integrated SOC's or Libra/Volans. + * In the case of Prima the cfg_set_str_notify is invoked with the bool value + * set to false. + * + * ASSUMPTIONS: + * - always notify has to be called + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pStr: address of string data + * @param len: string length + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + * @return QDF_STATUS_E_INVAL: invalid CFG parameter length + * + */ + +QDF_STATUS cfg_set_str(tpAniSirGlobal pMac, uint16_t cfgId, uint8_t *pStr, + uint32_t length) +{ + return cfg_set_str_notify(pMac, cfgId, pStr, length, true); +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_str_notify() + * + * FUNCTION: + * This function is called to set a string parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - No length checking will be performed. Should be done by calling + * module. + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pStr: address of string data + * @param len: string length + * @param notifyMod. notify respective Module + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + * @return QDF_STATUS_E_INVAL: invalid CFG parameter length + * + */ + +QDF_STATUS cfg_set_str_notify(tpAniSirGlobal pMac, uint16_t cfgId, + uint8_t *pStr, uint32_t length, + int notifyMod) +{ + uint8_t *pDst, *pDstEnd; + uint32_t index, paramLen, mask; + uint32_t control; + QDF_STATUS status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (QDF_STATUS_SUCCESS != status) + return status; + + pDst = &pMac->cfg.gCfgSBuf[index]; + paramLen = *pDst++; + control = pMac->cfg.gCfgEntry[cfgId].control; + if (length > paramLen) { + pe_warn("Invalid length: %d (>%d) cfg id: %d", + length, paramLen, cfgId); + return QDF_STATUS_E_INVAL; + } else { + *pDst++ = (uint8_t) length; + pDstEnd = pDst + length; + while (pDst < pDstEnd) { + *pDst++ = *pStr++; + } + if (notifyMod) { + /* Update hardware if necessary */ + mask = control & CFG_CTL_NTF_MASK; + if ((mask & CFG_CTL_NTF_HW) != 0) { + pe_debug("CFG notify HW not supported!"); + } + /* notify other modules if necessary */ + if ((mask & CFG_CTL_NTF_MASK) != 0) { + notify(pMac, cfgId, mask); + } + } + } + return QDF_STATUS_SUCCESS; +} /*** end cfg_set_str_notify() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str() + * + * FUNCTION: + * This function is called to get a string parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pBuf: address of string buffer + * @param pLen: address of max buffer length + * actual length will be returned at this address + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + * @return QDF_STATUS_E_INVAL: invalid CFG parameter length + * + */ + +QDF_STATUS wlan_cfg_get_str(tpAniSirGlobal pMac, uint16_t cfgId, + uint8_t *pBuf, uint32_t *pLength) +{ + uint8_t *pSrc, *pSrcEnd; + uint32_t index; + QDF_STATUS status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (QDF_STATUS_SUCCESS != status) + return status; + + /* Get string */ + pSrc = &pMac->cfg.gCfgSBuf[index]; + pSrc++; /* skip over max length */ + if (*pLength < *pSrc) { + pe_warn("Invalid length: %d (<%d) cfg id: %d", + *pLength, *pSrc, cfgId); + return QDF_STATUS_E_INVAL; + } else { + *pLength = *pSrc++; /* save parameter length */ + pSrcEnd = pSrc + *pLength; + while (pSrc < pSrcEnd) + *pBuf++ = *pSrc++; + } + return QDF_STATUS_SUCCESS; +} /*** end wlan_cfg_get_str() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str_max_len() + * + * FUNCTION: + * This function is called to get a string maximum length. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pLen: maximum length will be returned at this address + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + * + */ + +QDF_STATUS wlan_cfg_get_str_max_len(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pLength) +{ + uint32_t index; + QDF_STATUS status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (QDF_STATUS_SUCCESS != status) + return status; + + *pLength = pMac->cfg.gCfgSBuf[index]; + + return status; +} /*** end wlan_cfg_get_str_max_len() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str_len() + * + * FUNCTION: + * This function is called to get a string length. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pLen: current length will be returned at this address + * + * @return QDF_STATUS_SUCCESS: request completed successfully + * @return QDF_STATUS_E_INVAL: invalid CFG parameter ID + * + */ + +QDF_STATUS wlan_cfg_get_str_len(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pLength) +{ + uint32_t index; + QDF_STATUS status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (QDF_STATUS_SUCCESS != status) + return status; + + *pLength = pMac->cfg.gCfgSBuf[index + 1]; + + return status; + +} /*** end wlan_cfg_get_str_len() ***/ + +/** + * cfg_get_dot11d_transmit_power() - regulatory max transmit power + * @pMac: pointer to mac data + * @cfgId: configuration ID + * @cfgLength: configuration length + * @channel: channel number + * + * Return: int8_t - power + */ +static int8_t +cfg_get_dot11d_transmit_power(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t cfgLength, uint8_t channel) +{ + uint8_t *pCountryInfo = NULL; + uint8_t count = 0; + int8_t maxTxPwr = WMA_MAX_TXPOWER_INVALID; + + /* At least one element is present */ + if (cfgLength < sizeof(tSirMacChanInfo)) { + pe_err("Invalid CFGLENGTH: %d while getting 11d txpower", + cfgLength); + goto error; + } + + pCountryInfo = qdf_mem_malloc(cfgLength); + if (NULL == pCountryInfo) { + pe_err(" failed to allocate memory"); + goto error; + } + /* The CSR will always update this CFG. The contents will be from country IE if regulatory domain + * is enabled on AP else will contain EEPROM contents + */ + if (wlan_cfg_get_str(pMac, cfgId, pCountryInfo, &cfgLength) != + QDF_STATUS_SUCCESS) { + qdf_mem_free(pCountryInfo); + pCountryInfo = NULL; + + pe_warn("Failed to retrieve 11d configuration parameters while retrieving 11d tuples"); + goto error; + } + /* Identify the channel and maxtxpower */ + while (count <= (cfgLength - (sizeof(tSirMacChanInfo)))) { + uint8_t firstChannel, maxChannels; + + firstChannel = pCountryInfo[count++]; + maxChannels = pCountryInfo[count++]; + maxTxPwr = pCountryInfo[count++]; + + if ((channel >= firstChannel) && + (channel < (firstChannel + maxChannels))) { + break; + } + } + +error: + if (NULL != pCountryInfo) + qdf_mem_free(pCountryInfo); + + return maxTxPwr; +} + +/**---------------------------------------------------------------------- + \fn cfg_get_regulatory_max_transmit_power + + \brief Gets regulatory tx power on the current channel. + + \param pMac + \param channel + \param rfBand + -----------------------------------------------------------------------*/ +int8_t cfg_get_regulatory_max_transmit_power(tpAniSirGlobal pMac, + uint8_t channel) +{ + uint32_t cfgLength = 0; + uint16_t cfgId = 0; + int8_t maxTxPwr; + eRfBandMode rfBand = eRF_BAND_UNKNOWN; + + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + rfBand = eRF_BAND_5_GHZ; + else + rfBand = eRF_BAND_2_4_GHZ; + + /* Get the max transmit power for current channel for the current regulatory domain */ + switch (rfBand) { + case eRF_BAND_2_4_GHZ: + cfgId = WNI_CFG_MAX_TX_POWER_2_4; + cfgLength = WNI_CFG_MAX_TX_POWER_2_4_LEN; + pe_debug("HAL: Reading CFG for 2.4 GHz channels to get regulatory max tx power"); + break; + + case eRF_BAND_5_GHZ: + cfgId = WNI_CFG_MAX_TX_POWER_5; + cfgLength = WNI_CFG_MAX_TX_POWER_5_LEN; + pe_debug("HAL: Reading CFG for 5.0 GHz channels to get regulatory max tx power"); + break; + + case eRF_BAND_UNKNOWN: + default: + pe_warn("HAL: Invalid current working band for the device"); + return WMA_MAX_TXPOWER_INVALID; /* Its return, not break. */ + } + + maxTxPwr = cfg_get_dot11d_transmit_power(pMac, cfgId, cfgLength, channel); + + return maxTxPwr; +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_get_capability_info + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +QDF_STATUS cfg_get_capability_info(tpAniSirGlobal pMac, uint16_t *pCap, + tpPESession sessionEntry) +{ + uint32_t val = 0; + tpSirMacCapabilityInfo pCapInfo; + + *pCap = 0; + pCapInfo = (tpSirMacCapabilityInfo) pCap; + + if (LIM_IS_IBSS_ROLE(sessionEntry)) + pCapInfo->ibss = 1; /* IBSS bit */ + else if (LIM_IS_AP_ROLE(sessionEntry) || + LIM_IS_STA_ROLE(sessionEntry)) + pCapInfo->ess = 1; /* ESS bit */ + else if (LIM_IS_P2P_DEVICE_ROLE(sessionEntry) || + LIM_IS_NDI_ROLE(sessionEntry)) { + pCapInfo->ess = 0; + pCapInfo->ibss = 0; + } else + pe_warn("can't get capability, role is UNKNOWN!!"); + + if (LIM_IS_AP_ROLE(sessionEntry)) { + val = sessionEntry->privacy; + } else { + /* PRIVACY bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_PRIVACY_ENABLED failed"); + return QDF_STATUS_E_FAILURE; + } + } + if (val) + pCapInfo->privacy = 1; + + /* Short preamble bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_SHORT_PREAMBLE failed"); + return QDF_STATUS_E_FAILURE; + } + if (val) + pCapInfo->shortPreamble = 1; + + /* PBCC bit */ + pCapInfo->pbcc = 0; + + /* Channel agility bit */ + pCapInfo->channelAgility = 0; + /* If STA/AP operating in 11B mode, don't set rest of the + * capability info bits. + */ + if (sessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11B) + return QDF_STATUS_SUCCESS; + + /* Short slot time bit */ + if (LIM_IS_AP_ROLE(sessionEntry)) { + pCapInfo->shortSlotTime = sessionEntry->shortSlotTimeSupported; + } else { + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val) != QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_11G_SHORT_SLOT_TIME failed"); + return QDF_STATUS_E_FAILURE; + } + /* 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 (val) { + pCapInfo->shortSlotTime = + sessionEntry->shortSlotTimeSupported; + } + } + + /* Spectrum Management bit */ + if (!LIM_IS_IBSS_ROLE(sessionEntry) && sessionEntry->lim11hEnable) { + if (wlan_cfg_get_int(pMac, WNI_CFG_11H_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_11H_ENABLED failed"); + return QDF_STATUS_E_FAILURE; + } + if (val) + pCapInfo->spectrumMgt = 1; + } + /* QoS bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_QOS_ENABLED failed"); + return QDF_STATUS_E_FAILURE; + } + if (val) + pCapInfo->qos = 1; + + /* APSD bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_APSD_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_APSD_ENABLED failed"); + return QDF_STATUS_E_FAILURE; + } + if (val) + pCapInfo->apsd = 1; + + pCapInfo->rrm = pMac->rrm.rrmSmeContext.rrmConfig.rrm_enabled; + pe_debug("RRM: %d", pCapInfo->rrm); + /* DSSS-OFDM */ + /* FIXME : no config defined yet. */ + + /* Block ack bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_BLOCK_ACK_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_BLOCK_ACK_ENABLED failed"); + return QDF_STATUS_E_FAILURE; + } + pCapInfo->delayedBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + pCapInfo->immediateBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + return QDF_STATUS_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * cfg_set_capability_info + * + * FUNCTION: + * This function is called on BP based on the capabilities + * received in SME_JOIN/REASSOC_REQ message. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: 1. ESS/IBSS capabilities are based on system role. + * 2. Since PBCC, Channel agility and Extended capabilities + * are not supported, they're not set at CFG + * + * @param pMac Pointer to global MAC structure + * @param caps 16-bit Capability Info field + * @return None + */ + +void cfg_set_capability_info(tpAniSirGlobal pMac, uint16_t caps) +{ +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_cleanup() + * + * FUNCTION: + * CFG cleanup function. + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * This function must be called during system shutdown. + * + * @param None + * + * @return None. + * + */ + +void cfg_cleanup(tpAniSirGlobal pMac) +{ + /* Set status to not-ready */ + pMac->cfg.gCfgStatus = CFG_INCOMPLETE; + +} /*** end CfgCleanup() ***/ + +/* --------------------------------------------------------------------- */ +/** + * notify() + * + * FUNCTION: + * This function is called to notify other modules of parameter update. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: configuration parameter ID + * @param mask: notification mask + * + * @return None. + * + */ + +static void notify(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t ntfMask) +{ + + struct scheduler_msg mmhMsg = {0}; + + mmhMsg.type = SIR_CFG_PARAM_UPDATE_IND; + mmhMsg.bodyval = (uint32_t) cfgId; + mmhMsg.bodyptr = NULL; + + if ((ntfMask & CFG_CTL_NTF_SCH) != 0) + sch_post_message(pMac, &mmhMsg); + + if ((ntfMask & CFG_CTL_NTF_LIM) != 0) + lim_post_msg_api(pMac, &mmhMsg); + + if ((ntfMask & CFG_CTL_NTF_TARGET) != 0) + wma_post_ctrl_msg(pMac, &mmhMsg); + + /* notify ARQ */ + +} /*** end notify() ***/ + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_def.h b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_def.h new file mode 100644 index 0000000000000000000000000000000000000000..e521c6be8509d3d169e61907a25386ddaef4144a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_def.h @@ -0,0 +1,63 @@ +/* + * 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 is the private header file for CFG module. + * + * Author: Kevin Nguyen + * Date: 03/20/02 + * History:- + * 03/20/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGDEF_H +#define __CFGDEF_H + +/* + * CFG Control Flag definitions + */ +#define CFG_CTL_VALID 0x00010000 +#define CFG_CTL_RE 0x00020000 +#define CFG_CTL_WE 0x00040000 +#define CFG_CTL_INT 0x00080000 +#define CFG_CTL_SAVE 0x00100000 +#define CFG_CTL_RESTART 0x00200000 +#define CFG_CTL_RELOAD 0x00400000 +#define CFG_CTL_NTF_PHY 0x00800000 +#define CFG_CTL_NTF_MAC 0x01000000 +#define CFG_CTL_NTF_LOG 0x02000000 +#define CFG_CTL_NTF_TARGET 0x04000000 +#define CFG_CTL_NTF_DPH 0x08000000 +#define CFG_CTL_NTF_ARQ 0x10000000 +#define CFG_CTL_NTF_SCH 0x20000000 +#define CFG_CTL_NTF_LIM 0x40000000 +#define CFG_CTL_NTF_HDD 0x80000000 +#define CFG_CTL_NTF_MASK 0xFFE00000 + +#define CFG_CTL_NTF_TFP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_RHP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_RFP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_SP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_HW (CFG_CTL_NTF_MAC | CFG_CTL_NTF_PHY) + +#define CFG_BUF_INDX_MASK 0x00000fff + +#endif /* __CFGDEF_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_param_name.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_param_name.c new file mode 100644 index 0000000000000000000000000000000000000000..5c4301951d2d47d332694d9c1e00ce7b42db22ad --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_param_name.c @@ -0,0 +1,333 @@ +/* + * 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. + */ + +/* + * DO NOT EDIT - This file is generated automatically + */ + +/* + * IMPORTANT: This file is for system that supports STA mode ONLY. + */ +#include "cfg_priv.h" + +/** + * cfg_get_string() - return string conversion of HE WNI CFG + * @cfg_id: Config ID. + * + * This utility function helps log string conversion of WNI config ID. + * + * Return: string conversion of the HE WNI config ID, if match found; + * "Invalid" otherwise. + */ +const char *cfg_get_string(uint16_t cfg_id) +{ + switch (cfg_id) { + default: + break; + CASE_RETURN_STRING(WNI_CFG_STA_ID); + CASE_RETURN_STRING(WNI_CFG_CFP_PERIOD); + CASE_RETURN_STRING(WNI_CFG_CFP_MAX_DURATION); + CASE_RETURN_STRING(WNI_CFG_SSID); + CASE_RETURN_STRING(WNI_CFG_BEACON_INTERVAL); + CASE_RETURN_STRING(WNI_CFG_DTIM_PERIOD); + CASE_RETURN_STRING(WNI_CFG_WEP_DEFAULT_KEY_1); + CASE_RETURN_STRING(WNI_CFG_WEP_DEFAULT_KEY_2); + CASE_RETURN_STRING(WNI_CFG_WEP_DEFAULT_KEY_3); + CASE_RETURN_STRING(WNI_CFG_WEP_DEFAULT_KEY_4); + CASE_RETURN_STRING(WNI_CFG_WEP_DEFAULT_KEYID); + CASE_RETURN_STRING(WNI_CFG_RTS_THRESHOLD); + CASE_RETURN_STRING(WNI_CFG_FRAGMENTATION_THRESHOLD); + CASE_RETURN_STRING(WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME); + CASE_RETURN_STRING(WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME); + CASE_RETURN_STRING(WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME); + CASE_RETURN_STRING(WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME); + CASE_RETURN_STRING(WNI_CFG_JOIN_FAILURE_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_AUTHENTICATE_RSP_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_SUPPORTED_RATES_11B); + CASE_RETURN_STRING(WNI_CFG_SUPPORTED_RATES_11A); + CASE_RETURN_STRING(WNI_CFG_DOT11_MODE); + CASE_RETURN_STRING(WNI_CFG_OPERATIONAL_RATE_SET); + CASE_RETURN_STRING(WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET); + CASE_RETURN_STRING(WNI_CFG_LISTEN_INTERVAL); + CASE_RETURN_STRING(WNI_CFG_VALID_CHANNEL_LIST); + CASE_RETURN_STRING(WNI_CFG_APSD_ENABLED); + CASE_RETURN_STRING(WNI_CFG_SHARED_KEY_AUTH_ENABLE); + CASE_RETURN_STRING(WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE); + CASE_RETURN_STRING(WNI_CFG_AUTHENTICATION_TYPE); + CASE_RETURN_STRING(WNI_CFG_PRIVACY_ENABLED); + CASE_RETURN_STRING(WNI_CFG_SHORT_PREAMBLE); + CASE_RETURN_STRING(WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY); + CASE_RETURN_STRING(WNI_CFG_QOS_ENABLED); + CASE_RETURN_STRING(WNI_CFG_HCF_ENABLED); + CASE_RETURN_STRING(WNI_CFG_RSN_ENABLED); + CASE_RETURN_STRING(WNI_CFG_MAX_NUM_PRE_AUTH); + CASE_RETURN_STRING(WNI_CFG_HEART_BEAT_THRESHOLD); + CASE_RETURN_STRING(WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_MANUFACTURER_NAME); + CASE_RETURN_STRING(WNI_CFG_MODEL_NUMBER); + CASE_RETURN_STRING(WNI_CFG_MODEL_NAME); + CASE_RETURN_STRING(WNI_CFG_MANUFACTURER_PRODUCT_NAME); + CASE_RETURN_STRING(WNI_CFG_MANUFACTURER_PRODUCT_VERSION); + CASE_RETURN_STRING(WNI_CFG_11D_ENABLED); + CASE_RETURN_STRING(WNI_CFG_MAX_TX_POWER_2_4); + CASE_RETURN_STRING(WNI_CFG_MAX_TX_POWER_5); + CASE_RETURN_STRING(WNI_CFG_CURRENT_TX_POWER_LEVEL); + CASE_RETURN_STRING(WNI_CFG_NEW_BSS_FOUND_IND); + CASE_RETURN_STRING(WNI_CFG_COUNTRY_CODE); + CASE_RETURN_STRING(WNI_CFG_11H_ENABLED); + CASE_RETURN_STRING(WNI_CFG_WT_CNF_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_OLBC_DETECT_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_PROTECTION_ENABLED); + CASE_RETURN_STRING(WNI_CFG_11G_PROTECTION_ALWAYS); + CASE_RETURN_STRING(WNI_CFG_FORCE_POLICY_PROTECTION); + CASE_RETURN_STRING(WNI_CFG_11G_SHORT_PREAMBLE_ENABLED); + CASE_RETURN_STRING(WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED); + CASE_RETURN_STRING(WNI_CFG_11G_ONLY_POLICY); + CASE_RETURN_STRING(WNI_CFG_WME_ENABLED); + CASE_RETURN_STRING(WNI_CFG_ADDTS_RSP_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_MAX_SP_LENGTH); + CASE_RETURN_STRING(WNI_CFG_WSM_ENABLED); + CASE_RETURN_STRING(WNI_CFG_EDCA_PROFILE); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACBK_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACBE_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACVI_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACVO_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACBK); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACBE); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACVI); + CASE_RETURN_STRING(WNI_CFG_EDCA_ANI_ACVO); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACBK_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACBE_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACVI_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACVO_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACBK); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACBE); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACVI); + CASE_RETURN_STRING(WNI_CFG_EDCA_WME_ACVO); + CASE_RETURN_STRING(WNI_CFG_LOCAL_POWER_CONSTRAINT); + CASE_RETURN_STRING(WNI_CFG_ADMIT_POLICY); + CASE_RETURN_STRING(WNI_CFG_ADMIT_BWFACTOR); + CASE_RETURN_STRING(WNI_CFG_CHANNEL_BONDING_MODE); + CASE_RETURN_STRING(WNI_CFG_BLOCK_ACK_ENABLED); + CASE_RETURN_STRING(WNI_CFG_HT_CAP_INFO); + CASE_RETURN_STRING(WNI_CFG_HT_AMPDU_PARAMS); + CASE_RETURN_STRING(WNI_CFG_SUPPORTED_MCS_SET); + CASE_RETURN_STRING(WNI_CFG_EXT_HT_CAP_INFO); + CASE_RETURN_STRING(WNI_CFG_TX_BF_CAP); + CASE_RETURN_STRING(WNI_CFG_AS_CAP); + CASE_RETURN_STRING(WNI_CFG_HT_INFO_FIELD1); + CASE_RETURN_STRING(WNI_CFG_HT_INFO_FIELD2); + CASE_RETURN_STRING(WNI_CFG_HT_INFO_FIELD3); + CASE_RETURN_STRING(WNI_CFG_BASIC_MCS_SET); + CASE_RETURN_STRING(WNI_CFG_CURRENT_MCS_SET); + CASE_RETURN_STRING(WNI_CFG_VHT_MAX_MPDU_LENGTH); + CASE_RETURN_STRING(WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET); + CASE_RETURN_STRING(WNI_CFG_VHT_LDPC_CODING_CAP); + CASE_RETURN_STRING(WNI_CFG_VHT_SHORT_GI_80MHZ); + CASE_RETURN_STRING(WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ); + CASE_RETURN_STRING(WNI_CFG_VHT_TXSTBC); + CASE_RETURN_STRING(WNI_CFG_VHT_RXSTBC); + CASE_RETURN_STRING(WNI_CFG_VHT_SU_BEAMFORMER_CAP); + CASE_RETURN_STRING(WNI_CFG_VHT_SU_BEAMFORMEE_CAP); + CASE_RETURN_STRING(WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED); + CASE_RETURN_STRING(WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS); + CASE_RETURN_STRING(WNI_CFG_VHT_MU_BEAMFORMER_CAP); + CASE_RETURN_STRING(WNI_CFG_VHT_MU_BEAMFORMEE_CAP); + CASE_RETURN_STRING(WNI_CFG_VHT_TXOP_PS); + CASE_RETURN_STRING(WNI_CFG_VHT_HTC_VHTC_CAP); + CASE_RETURN_STRING(WNI_CFG_VHT_AMPDU_LEN_EXPONENT); + CASE_RETURN_STRING(WNI_CFG_VHT_LINK_ADAPTATION_CAP); + CASE_RETURN_STRING(WNI_CFG_VHT_RX_ANT_PATTERN); + CASE_RETURN_STRING(WNI_CFG_VHT_TX_ANT_PATTERN); + CASE_RETURN_STRING(WNI_CFG_VHT_RX_MCS_MAP); + CASE_RETURN_STRING(WNI_CFG_VHT_TX_MCS_MAP); + CASE_RETURN_STRING(WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE); + CASE_RETURN_STRING(WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE); + CASE_RETURN_STRING(WNI_CFG_VHT_BASIC_MCS_SET); + CASE_RETURN_STRING(WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT); + CASE_RETURN_STRING(WNI_CFG_VHT_SS_UNDER_UTIL); + CASE_RETURN_STRING(WNI_CFG_VHT_40MHZ_UTILIZATION); + CASE_RETURN_STRING(WNI_CFG_VHT_80MHZ_UTILIZATION); + CASE_RETURN_STRING(WNI_CFG_VHT_160MHZ_UTILIZATION); + CASE_RETURN_STRING(WNI_CFG_MPDU_DENSITY); + CASE_RETURN_STRING(WNI_CFG_MAX_RX_AMPDU_FACTOR); + CASE_RETURN_STRING(WNI_CFG_MAX_PS_POLL); + CASE_RETURN_STRING(WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE); + CASE_RETURN_STRING(WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE); + CASE_RETURN_STRING(WNI_CFG_WOWLAN_DEAUTH_ENABLE); + CASE_RETURN_STRING(WNI_CFG_WOWLAN_DISASSOC_ENABLE); + CASE_RETURN_STRING(WNI_CFG_WOWLAN_MAX_MISSED_BEACON); + CASE_RETURN_STRING(WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD); + CASE_RETURN_STRING(WNI_CFG_IBSS_AUTO_BSSID); + CASE_RETURN_STRING(WNI_CFG_WPS_ENABLE); + CASE_RETURN_STRING(WNI_CFG_WPS_STATE); + CASE_RETURN_STRING(WNI_CFG_WPS_VERSION); + CASE_RETURN_STRING(WNI_CFG_WPS_CFG_METHOD); + CASE_RETURN_STRING(WNI_CFG_WPS_UUID); + CASE_RETURN_STRING(WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY); + CASE_RETURN_STRING(WNI_CFG_WPS_PIMARY_DEVICE_OUI); + CASE_RETURN_STRING(WNI_CFG_WPS_DEVICE_SUB_CATEGORY); + CASE_RETURN_STRING(WNI_CFG_WPS_DEVICE_PASSWORD_ID); + CASE_RETURN_STRING(WNI_CFG_SINGLE_TID_RC); + CASE_RETURN_STRING(WNI_CFG_TELE_BCN_WAKEUP_EN); + CASE_RETURN_STRING(WNI_CFG_TELE_BCN_MAX_LI); + CASE_RETURN_STRING(WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD); + CASE_RETURN_STRING(WNI_CFG_ASSOC_STA_LIMIT); + CASE_RETURN_STRING(WNI_CFG_ENABLE_LTE_COEX); + CASE_RETURN_STRING(WNI_CFG_AP_KEEP_ALIVE_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_GO_KEEP_ALIVE_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_ENABLE_MC_ADDR_LIST); + CASE_RETURN_STRING(WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED); + CASE_RETURN_STRING(WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP); + CASE_RETURN_STRING(WNI_CFG_AP_LINK_MONITOR_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK); + CASE_RETURN_STRING(WNI_CFG_TDLS_BUF_STA_ENABLED); + CASE_RETURN_STRING(WNI_CFG_TDLS_PUAPSD_INACT_TIME); + CASE_RETURN_STRING(WNI_CFG_TDLS_RX_FRAME_THRESHOLD); + CASE_RETURN_STRING(WNI_CFG_PMF_SA_QUERY_MAX_RETRIES); + CASE_RETURN_STRING(WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL); + CASE_RETURN_STRING(WNI_CFG_GO_LINK_MONITOR_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY); + CASE_RETURN_STRING(WNI_CFG_CURRENT_RSSI); + CASE_RETURN_STRING(WNI_CFG_RTT3_ENABLE); + CASE_RETURN_STRING(WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL); + CASE_RETURN_STRING(WNI_CFG_TDLS_OFF_CHANNEL_ENABLED); + CASE_RETURN_STRING(WNI_CFG_IBSS_ATIM_WIN_SIZE); + CASE_RETURN_STRING(WNI_CFG_DFS_MASTER_ENABLED); + CASE_RETURN_STRING(WNI_CFG_VHT_ENABLE_TXBF_20MHZ); + CASE_RETURN_STRING(WNI_CFG_TDLS_WMM_MODE_ENABLED); + CASE_RETURN_STRING(WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME); + CASE_RETURN_STRING(WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME); + CASE_RETURN_STRING(WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL); + CASE_RETURN_STRING(WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL); + CASE_RETURN_STRING(WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL); + CASE_RETURN_STRING(WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY); + CASE_RETURN_STRING(WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD); + CASE_RETURN_STRING(WNI_CFG_TGT_GTX_USR_CFG); + CASE_RETURN_STRING(WNI_CFG_MAX_HT_MCS_TX_DATA); + CASE_RETURN_STRING(WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA); + CASE_RETURN_STRING(WNI_CFG_RATE_FOR_TX_MGMT); + CASE_RETURN_STRING(WNI_CFG_HE_CONTROL); + CASE_RETURN_STRING(WNI_CFG_HE_TWT_REQUESTOR); + CASE_RETURN_STRING(WNI_CFG_HE_TWT_RESPONDER); + CASE_RETURN_STRING(WNI_CFG_HE_FRAGMENTATION); + CASE_RETURN_STRING(WNI_CFG_HE_MAX_FRAG_MSDU); + CASE_RETURN_STRING(WNI_CFG_HE_MIN_FRAG_SIZE); + CASE_RETURN_STRING(WNI_CFG_HE_TRIG_PAD); + CASE_RETURN_STRING(WNI_CFG_HE_MTID_AGGR); + CASE_RETURN_STRING(WNI_CFG_HE_LINK_ADAPTATION); + CASE_RETURN_STRING(WNI_CFG_HE_ALL_ACK); + CASE_RETURN_STRING(WNI_CFG_HE_UL_MU_RSP_SCHEDULING); + CASE_RETURN_STRING(WNI_CFG_HE_BUFFER_STATUS_RPT); + CASE_RETURN_STRING(WNI_CFG_HE_BCAST_TWT); + CASE_RETURN_STRING(WNI_CFG_HE_BA_32BIT); + CASE_RETURN_STRING(WNI_CFG_HE_MU_CASCADING); + CASE_RETURN_STRING(WNI_CFG_HE_MULTI_TID); + CASE_RETURN_STRING(WNI_CFG_HE_DL_MU_BA); + CASE_RETURN_STRING(WNI_CFG_HE_OMI); + CASE_RETURN_STRING(WNI_CFG_HE_OFDMA_RA); + CASE_RETURN_STRING(WNI_CFG_HE_MAX_AMPDU_LEN); + CASE_RETURN_STRING(WNI_CFG_HE_AMSDU_FRAG); + CASE_RETURN_STRING(WNI_CFG_HE_FLEX_TWT_SCHED); + CASE_RETURN_STRING(WNI_CFG_HE_RX_CTRL); + CASE_RETURN_STRING(WNI_CFG_HE_BSRP_AMPDU_AGGR); + CASE_RETURN_STRING(WNI_CFG_HE_QTP); + CASE_RETURN_STRING(WNI_CFG_HE_A_BQR); + CASE_RETURN_STRING(WNI_CFG_HE_SR_RESPONDER); + CASE_RETURN_STRING(WNI_CFG_HE_NDP_FEEDBACK_SUPP); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_SUPP); + CASE_RETURN_STRING(WNI_CFG_HE_DUAL_BAND); + CASE_RETURN_STRING(WNI_CFG_HE_CHAN_WIDTH); + CASE_RETURN_STRING(WNI_CFG_HE_RX_PREAM_PUNC); + CASE_RETURN_STRING(WNI_CFG_HE_CLASS_OF_DEVICE); + CASE_RETURN_STRING(WNI_CFG_HE_LDPC); + CASE_RETURN_STRING(WNI_CFG_HE_LTF_PPDU); + CASE_RETURN_STRING(WNI_CFG_HE_LTF_NDP); + CASE_RETURN_STRING(WNI_CFG_HE_TX_STBC_LT80); + CASE_RETURN_STRING(WNI_CFG_HE_RX_STBC_LT80); + CASE_RETURN_STRING(WNI_CFG_HE_DOPPLER); + CASE_RETURN_STRING(WNI_CFG_HE_UL_MUMIMO); + CASE_RETURN_STRING(WNI_CFG_HE_DCM_TX); + CASE_RETURN_STRING(WNI_CFG_HE_DCM_RX); + CASE_RETURN_STRING(WNI_CFG_HE_MU_PPDU); + CASE_RETURN_STRING(WNI_CFG_HE_SU_BEAMFORMER); + CASE_RETURN_STRING(WNI_CFG_HE_SU_BEAMFORMEE); + CASE_RETURN_STRING(WNI_CFG_HE_MU_BEAMFORMER); + CASE_RETURN_STRING(WNI_CFG_HE_BFEE_STS_LT80); + CASE_RETURN_STRING(WNI_CFG_HE_BFEE_STS_GT80); + CASE_RETURN_STRING(WNI_CFG_HE_NUM_SOUND_LT80); + CASE_RETURN_STRING(WNI_CFG_HE_NUM_SOUND_GT80); + CASE_RETURN_STRING(WNI_CFG_HE_SU_FEED_TONE16); + CASE_RETURN_STRING(WNI_CFG_HE_MU_FEED_TONE16); + CASE_RETURN_STRING(WNI_CFG_HE_CODEBOOK_SU); + CASE_RETURN_STRING(WNI_CFG_HE_CODEBOOK_MU); + CASE_RETURN_STRING(WNI_CFG_HE_BFRM_FEED); + CASE_RETURN_STRING(WNI_CFG_HE_ER_SU_PPDU); + CASE_RETURN_STRING(WNI_CFG_HE_DL_PART_BW); + CASE_RETURN_STRING(WNI_CFG_HE_PPET_PRESENT); + CASE_RETURN_STRING(WNI_CFG_HE_SRP); + CASE_RETURN_STRING(WNI_CFG_HE_POWER_BOOST); + CASE_RETURN_STRING(WNI_CFG_HE_4x_LTF_GI); + CASE_RETURN_STRING(WNI_CFG_HE_MAX_NC); + CASE_RETURN_STRING(WNI_CFG_HE_TX_STBC_GT80); + CASE_RETURN_STRING(WNI_CFG_HE_RX_STBC_GT80); + CASE_RETURN_STRING(WNI_CFG_HE_ER_4x_LTF_GI); + CASE_RETURN_STRING(WNI_CFG_HE_RX_MCS_MAP_LT_80); + CASE_RETURN_STRING(WNI_CFG_HE_TX_MCS_MAP_LT_80); + CASE_RETURN_STRING(WNI_CFG_HE_RX_MCS_MAP_160); + CASE_RETURN_STRING(WNI_CFG_HE_TX_MCS_MAP_160); + CASE_RETURN_STRING(WNI_CFG_HE_RX_MCS_MAP_80_80); + CASE_RETURN_STRING(WNI_CFG_HE_TX_MCS_MAP_80_80); + CASE_RETURN_STRING(WNI_CFG_HE_PPET_2G); + CASE_RETURN_STRING(WNI_CFG_HE_PPET_5G); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_BSS_COLOR); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_DEFAULT_PE); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_TWT_REQUIRED); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_RTS_THRESHOLD); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_PARTIAL_BSS_COL); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_VHT_OPER_PRESENT); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_MBSSID_AP); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_TX_BSSID_IND); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_BSS_COL_DISABLED); + CASE_RETURN_STRING(WNI_CFG_HE_OPS_BASIC_MCS_NSS); + CASE_RETURN_STRING(WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT); + CASE_RETURN_STRING(WNI_CFG_HE_STA_OBSSPD); + CASE_RETURN_STRING(WNI_CFG_SAP_MAX_MCS_DATA); + CASE_RETURN_STRING(WNI_CFG_RATE_FOR_TX_MGMT_2G); + CASE_RETURN_STRING(WNI_CFG_RATE_FOR_TX_MGMT_5G); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACBK_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACBE_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACVI_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACVO_LOCAL); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACBK); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACBE); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACVI); + CASE_RETURN_STRING(WNI_CFG_EDCA_ETSI_ACVO); + CASE_RETURN_STRING(WNI_CFG_OBSS_DETECTION_OFFLOAD); + CASE_RETURN_STRING(WNI_CFG_OBSS_COLOR_COLLISION_OFFLOAD); + CASE_RETURN_STRING(WNI_CFG_TWT_REQUESTOR); + CASE_RETURN_STRING(WNI_CFG_TWT_RESPONDER); + CASE_RETURN_STRING(WNI_CFG_BCAST_TWT); + } + + return "invalid"; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_priv.h b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..79fc0d7ce56e42238d512255ed42b59f714b2e79 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_priv.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011-2015 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 is the private header file for CFG module. + * + * Author: Kevin Nguyen + * Date: 03/20/02 + * History:- + * 03/20/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGPRIV_H +#define __CFGPRIV_H + +#include +#include +#include +#include +#include +#include +#include +#include "cfg_def.h" + +#include + +/*--------------------------------------------------------------------*/ +/* CFG miscellaneous definition */ +/*--------------------------------------------------------------------*/ + +/* Function index bit mask */ +#define CFG_FUNC_INDX_MASK 0x7f +#define CFG_GET_FUNC_INDX(val) (val & CFG_FUNC_INDX_MASK) + +/* Macro to convert return code to debug string index */ +#define CFG_GET_DBG_INDX(val) (val - eCFG_SUCCESS - 1) + +/*--------------------------------------------------------------------*/ +/* Binary header structure */ +/*--------------------------------------------------------------------*/ +typedef struct sCfgBinHdr { + uint32_t hdrInfo; + uint32_t controlSize; + uint32_t iBufSize; + uint32_t sBufSize; +} tCfgBinHdr, *tpCfgBinHdr; + +/*--------------------------------------------------------------------*/ +/* Polaris HW counter access structure */ +/*--------------------------------------------------------------------*/ + +#define CFG_STAT_CNT_LO_MASK 0x0000ffff +#define CFG_STAT_CNT_HI_MASK 0xffff0000 +#define CFG_STAT_CNT_HI_INCR 0x00010000 + +/*--------------------------------------------------------------------*/ +/* CFG function prototypes */ +/*--------------------------------------------------------------------*/ + +extern void cfg_send_host_msg(tpAniSirGlobal, uint16_t, uint32_t, uint32_t, + uint32_t *, uint32_t, uint32_t *); + +#endif /* __CFGPRIV_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_proc_msg.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_proc_msg.c new file mode 100644 index 0000000000000000000000000000000000000000..7adac63e11c3c7b1013ede7c76e8b75532e7f17b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_proc_msg.c @@ -0,0 +1,2218 @@ +/* + * 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 contains CFG functions for processing host messages. + */ +#include "cds_api.h" +#include "ani_global.h" +#include "cfg_priv.h" +#include "wma_types.h" +#include "lim_trace.h" + +cgstatic cfg_static[CFG_PARAM_MAX_NUM] = { + {WNI_CFG_STA_ID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RELOAD, + 0, 255, 1}, + {WNI_CFG_CFP_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CFP_PERIOD_STAMIN, + WNI_CFG_CFP_PERIOD_STAMAX, + WNI_CFG_CFP_PERIOD_STADEF}, + {WNI_CFG_CFP_MAX_DURATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CFP_MAX_DURATION_STAMIN, + WNI_CFG_CFP_MAX_DURATION_STAMAX, + WNI_CFG_CFP_MAX_DURATION_STADEF}, + {WNI_CFG_SSID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 255, 6}, + {WNI_CFG_BEACON_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_SCH, + WNI_CFG_BEACON_INTERVAL_STAMIN, + WNI_CFG_BEACON_INTERVAL_STAMAX, + WNI_CFG_BEACON_INTERVAL_STADEF}, + {WNI_CFG_DTIM_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_DTIM_PERIOD_STAMIN, + WNI_CFG_DTIM_PERIOD_STAMAX, + WNI_CFG_DTIM_PERIOD_STADEF}, + {WNI_CFG_WEP_DEFAULT_KEY_1, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 65535, 0}, + {WNI_CFG_WEP_DEFAULT_KEY_2, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 1, 1, 1}, + {WNI_CFG_WEP_DEFAULT_KEY_3, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 5, 5}, + {WNI_CFG_WEP_DEFAULT_KEY_4, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 1, 0}, + {WNI_CFG_WEP_DEFAULT_KEYID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WEP_DEFAULT_KEYID_STAMIN, + WNI_CFG_WEP_DEFAULT_KEYID_STAMAX, + WNI_CFG_WEP_DEFAULT_KEYID_STADEF}, + {WNI_CFG_RTS_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_TARGET, + WNI_CFG_RTS_THRESHOLD_STAMIN, + WNI_CFG_RTS_THRESHOLD_STAMAX, + WNI_CFG_RTS_THRESHOLD_STADEF}, + {WNI_CFG_FRAGMENTATION_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_TARGET, + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN, + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX, + WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF}, + {WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_JOIN_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMIN, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMAX, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STADEF}, + {WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMIN, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMAX, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STADEF}, + {WNI_CFG_SUPPORTED_RATES_11B, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 3, 1}, + {WNI_CFG_SUPPORTED_RATES_11A, CFG_CTL_VALID | CFG_CTL_RE, + 0, 255, 15}, + {WNI_CFG_DOT11_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + WNI_CFG_DOT11_MODE_STAMIN, + WNI_CFG_DOT11_MODE_STAMAX, + WNI_CFG_DOT11_MODE_STADEF}, + {WNI_CFG_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 1, 1}, + {WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 65535, 65534}, + {WNI_CFG_LISTEN_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_LISTEN_INTERVAL_STAMIN, + WNI_CFG_LISTEN_INTERVAL_STAMAX, + WNI_CFG_LISTEN_INTERVAL_STADEF}, + {WNI_CFG_VALID_CHANNEL_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + 0, 1, 1}, + {WNI_CFG_APSD_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_APSD_ENABLED_STAMIN, + WNI_CFG_APSD_ENABLED_STAMAX, + WNI_CFG_APSD_ENABLED_STADEF}, + {WNI_CFG_SHARED_KEY_AUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMIN, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMAX, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STADEF}, + {WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMIN, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMAX, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STADEF}, + {WNI_CFG_AUTHENTICATION_TYPE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_AUTHENTICATION_TYPE_STAMIN, + WNI_CFG_AUTHENTICATION_TYPE_STAMAX, + WNI_CFG_AUTHENTICATION_TYPE_STADEF}, + {WNI_CFG_PRIVACY_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PRIVACY_ENABLED_STAMIN, + WNI_CFG_PRIVACY_ENABLED_STAMAX, + WNI_CFG_PRIVACY_ENABLED_STADEF}, + {WNI_CFG_SHORT_PREAMBLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_SHORT_PREAMBLE_STAMIN, + WNI_CFG_SHORT_PREAMBLE_STAMAX, + WNI_CFG_SHORT_PREAMBLE_STADEF}, + {WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMIN, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMAX, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STADEF}, + {WNI_CFG_QOS_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_QOS_ENABLED_STAMIN, + WNI_CFG_QOS_ENABLED_STAMAX, + WNI_CFG_QOS_ENABLED_STADEF}, + {WNI_CFG_HCF_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_HCF_ENABLED_STAMIN, + WNI_CFG_HCF_ENABLED_STAMAX, + WNI_CFG_HCF_ENABLED_STADEF}, + {WNI_CFG_RSN_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_RSN_ENABLED_STAMIN, + WNI_CFG_RSN_ENABLED_STAMAX, + WNI_CFG_RSN_ENABLED_STADEF}, + {WNI_CFG_MAX_NUM_PRE_AUTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_MAX_NUM_PRE_AUTH_STAMIN, + WNI_CFG_MAX_NUM_PRE_AUTH_STAMAX, + WNI_CFG_MAX_NUM_PRE_AUTH_STADEF}, + {WNI_CFG_HEART_BEAT_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN, + WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX, + WNI_CFG_HEART_BEAT_THRESHOLD_STADEF}, + {WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | + CFG_CTL_INT, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMIN, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMAX, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STADEF}, + {WNI_CFG_MANUFACTURER_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MODEL_NUMBER, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MODEL_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MANUFACTURER_PRODUCT_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_11D_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11D_ENABLED_STAMIN, + WNI_CFG_11D_ENABLED_STAMAX, + WNI_CFG_11D_ENABLED_STADEF}, + {WNI_CFG_MAX_TX_POWER_2_4, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_MAX_TX_POWER_5, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_CURRENT_TX_POWER_LEVEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STADEF}, + {WNI_CFG_NEW_BSS_FOUND_IND, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_NEW_BSS_FOUND_IND_STAMIN, + WNI_CFG_NEW_BSS_FOUND_IND_STAMAX, + WNI_CFG_NEW_BSS_FOUND_IND_STADEF}, + {WNI_CFG_COUNTRY_CODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_NTF_SCH, + 0, 0, 0}, + {WNI_CFG_11H_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11H_ENABLED_STAMIN, + WNI_CFG_11H_ENABLED_STAMAX, + WNI_CFG_11H_ENABLED_STADEF}, + {WNI_CFG_WT_CNF_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WT_CNF_TIMEOUT_STAMIN, + WNI_CFG_WT_CNF_TIMEOUT_STAMAX, + WNI_CFG_WT_CNF_TIMEOUT_STADEF}, + {WNI_CFG_OLBC_DETECT_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_OLBC_DETECT_TIMEOUT_STAMIN, + WNI_CFG_OLBC_DETECT_TIMEOUT_STAMAX, + WNI_CFG_OLBC_DETECT_TIMEOUT_STADEF}, + {WNI_CFG_PROTECTION_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_PROTECTION_ENABLED_STAMIN, + WNI_CFG_PROTECTION_ENABLED_STAMAX, + WNI_CFG_PROTECTION_ENABLED_STADEF}, + {WNI_CFG_11G_PROTECTION_ALWAYS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_PROTECTION_ALWAYS_STAMIN, + WNI_CFG_11G_PROTECTION_ALWAYS_STAMAX, + WNI_CFG_11G_PROTECTION_ALWAYS_STADEF}, + {WNI_CFG_FORCE_POLICY_PROTECTION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_FORCE_POLICY_PROTECTION_STAMIN, + WNI_CFG_FORCE_POLICY_PROTECTION_STAMAX, + WNI_CFG_FORCE_POLICY_PROTECTION_STADEF}, + {WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMIN, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMAX, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STADEF}, + {WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMIN, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMAX, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STADEF}, + {WNI_CFG_11G_ONLY_POLICY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_11G_ONLY_POLICY_STAMIN, + WNI_CFG_11G_ONLY_POLICY_STAMAX, + WNI_CFG_11G_ONLY_POLICY_STADEF}, + {WNI_CFG_WME_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_WME_ENABLED_STAMIN, + WNI_CFG_WME_ENABLED_STAMAX, + WNI_CFG_WME_ENABLED_STADEF}, + {WNI_CFG_ADDTS_RSP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ADDTS_RSP_TIMEOUT_STAMIN, + WNI_CFG_ADDTS_RSP_TIMEOUT_STAMAX, + WNI_CFG_ADDTS_RSP_TIMEOUT_STADEF}, + {WNI_CFG_MAX_SP_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_MAX_SP_LENGTH_STAMIN, + WNI_CFG_MAX_SP_LENGTH_STAMAX, + WNI_CFG_MAX_SP_LENGTH_STADEF}, + {WNI_CFG_WSM_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WSM_ENABLED_STAMIN, + WNI_CFG_WSM_ENABLED_STAMAX, + WNI_CFG_WSM_ENABLED_STADEF}, + {WNI_CFG_EDCA_PROFILE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_SCH, + WNI_CFG_EDCA_PROFILE_STAMIN, + WNI_CFG_EDCA_PROFILE_STAMAX, + WNI_CFG_EDCA_PROFILE_STADEF}, + {WNI_CFG_EDCA_ANI_ACBK_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBE_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVI_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVO_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBK_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBE_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVI_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVO_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_LOCAL_POWER_CONSTRAINT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMIN, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMAX, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STADEF}, + {WNI_CFG_ADMIT_POLICY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ADMIT_POLICY_STAMIN, + WNI_CFG_ADMIT_POLICY_STAMAX, + WNI_CFG_ADMIT_POLICY_STADEF}, + {WNI_CFG_ADMIT_BWFACTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ADMIT_BWFACTOR_STAMIN, + WNI_CFG_ADMIT_BWFACTOR_STAMAX, + WNI_CFG_ADMIT_BWFACTOR_STADEF}, + {WNI_CFG_CHANNEL_BONDING_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_CHANNEL_BONDING_MODE_STAMIN, + WNI_CFG_CHANNEL_BONDING_MODE_STAMAX, + WNI_CFG_CHANNEL_BONDING_MODE_STADEF}, + {WNI_CFG_BLOCK_ACK_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_BLOCK_ACK_ENABLED_STAMIN, + WNI_CFG_BLOCK_ACK_ENABLED_STAMAX, + WNI_CFG_BLOCK_ACK_ENABLED_STADEF}, + {WNI_CFG_HT_CAP_INFO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_CAP_INFO_STAMIN, + WNI_CFG_HT_CAP_INFO_STAMAX, + WNI_CFG_HT_CAP_INFO_STADEF}, + {WNI_CFG_HT_AMPDU_PARAMS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_AMPDU_PARAMS_STAMIN, + WNI_CFG_HT_AMPDU_PARAMS_STAMAX, + WNI_CFG_HT_AMPDU_PARAMS_STADEF}, + {WNI_CFG_SUPPORTED_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_EXT_HT_CAP_INFO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_EXT_HT_CAP_INFO_STAMIN, + WNI_CFG_EXT_HT_CAP_INFO_STAMAX, + WNI_CFG_EXT_HT_CAP_INFO_STADEF}, + {WNI_CFG_TX_BF_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + WNI_CFG_TX_BF_CAP_STAMIN, + 4294967295u, + WNI_CFG_TX_BF_CAP_STADEF}, + {WNI_CFG_AS_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_AS_CAP_STAMIN, + WNI_CFG_AS_CAP_STAMAX, + WNI_CFG_AS_CAP_STADEF}, + {WNI_CFG_HT_INFO_FIELD1, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD1_STAMIN, + WNI_CFG_HT_INFO_FIELD1_STAMAX, + WNI_CFG_HT_INFO_FIELD1_STADEF}, + {WNI_CFG_HT_INFO_FIELD2, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD2_STAMIN, + WNI_CFG_HT_INFO_FIELD2_STAMAX, + WNI_CFG_HT_INFO_FIELD2_STADEF}, + {WNI_CFG_HT_INFO_FIELD3, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD3_STAMIN, + WNI_CFG_HT_INFO_FIELD3_STAMAX, + WNI_CFG_HT_INFO_FIELD3_STADEF}, + {WNI_CFG_BASIC_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_CURRENT_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_VHT_MAX_MPDU_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMIN, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMAX, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STADEF}, + {WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMIN, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMAX, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STADEF}, + {WNI_CFG_VHT_LDPC_CODING_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_LDPC_CODING_CAP_STAMIN, + WNI_CFG_VHT_LDPC_CODING_CAP_STAMAX, + WNI_CFG_VHT_LDPC_CODING_CAP_STADEF}, + {WNI_CFG_VHT_SHORT_GI_80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SHORT_GI_80MHZ_STAMIN, + WNI_CFG_VHT_SHORT_GI_80MHZ_STAMAX, + WNI_CFG_VHT_SHORT_GI_80MHZ_STADEF}, + {WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMIN, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMAX, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STADEF}, + {WNI_CFG_VHT_TXSTBC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TXSTBC_STAMIN, + WNI_CFG_VHT_TXSTBC_STAMAX, + WNI_CFG_VHT_TXSTBC_STADEF}, + {WNI_CFG_VHT_RXSTBC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RXSTBC_STAMIN, + WNI_CFG_VHT_RXSTBC_STAMAX, + WNI_CFG_VHT_RXSTBC_STADEF}, + {WNI_CFG_VHT_SU_BEAMFORMER_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMIN, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMAX, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STADEF}, + {WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF}, + {WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF}, + {WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMIN, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMAX, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STADEF}, + {WNI_CFG_VHT_MU_BEAMFORMER_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMIN, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMAX, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STADEF}, + {WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMIN, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMAX, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STADEF}, + {WNI_CFG_VHT_TXOP_PS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TXOP_PS_STAMIN, + WNI_CFG_VHT_TXOP_PS_STAMAX, + WNI_CFG_VHT_TXOP_PS_STADEF}, + {WNI_CFG_VHT_HTC_VHTC_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_HTC_VHTC_CAP_STAMIN, + WNI_CFG_VHT_HTC_VHTC_CAP_STAMAX, + WNI_CFG_VHT_HTC_VHTC_CAP_STADEF}, + {WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMIN, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMAX, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STADEF}, + {WNI_CFG_VHT_LINK_ADAPTATION_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMIN, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMAX, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STADEF}, + {WNI_CFG_VHT_RX_ANT_PATTERN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_ANT_PATTERN_STAMIN, + WNI_CFG_VHT_RX_ANT_PATTERN_STAMAX, + WNI_CFG_VHT_RX_ANT_PATTERN_STADEF}, + {WNI_CFG_VHT_TX_ANT_PATTERN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_ANT_PATTERN_STAMIN, + WNI_CFG_VHT_TX_ANT_PATTERN_STAMAX, + WNI_CFG_VHT_TX_ANT_PATTERN_STADEF}, + {WNI_CFG_VHT_RX_MCS_MAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_MCS_MAP_STAMIN, + WNI_CFG_VHT_RX_MCS_MAP_STAMAX, + WNI_CFG_VHT_RX_MCS_MAP_STADEF}, + {WNI_CFG_VHT_TX_MCS_MAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_MCS_MAP_STAMIN, + WNI_CFG_VHT_TX_MCS_MAP_STAMAX, + WNI_CFG_VHT_TX_MCS_MAP_STADEF}, + {WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STADEF}, + {WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STADEF}, + {WNI_CFG_VHT_BASIC_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_BASIC_MCS_SET_STAMIN, + WNI_CFG_VHT_BASIC_MCS_SET_STAMAX, + WNI_CFG_VHT_BASIC_MCS_SET_STADEF}, + {WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMIN, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMAX, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STADEF}, + {WNI_CFG_VHT_SS_UNDER_UTIL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SS_UNDER_UTIL_STAMIN, + WNI_CFG_VHT_SS_UNDER_UTIL_STAMAX, + WNI_CFG_VHT_SS_UNDER_UTIL_STADEF}, + {WNI_CFG_VHT_40MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_40MHZ_UTILIZATION_STAMIN, + WNI_CFG_VHT_40MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_40MHZ_UTILIZATION_STADEF}, + {WNI_CFG_VHT_80MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_80MHZ_UTILIZATION_STAMIN, + WNI_CFG_VHT_80MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF}, + {WNI_CFG_VHT_160MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF, + WNI_CFG_VHT_160MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_160MHZ_UTILIZATION_STADEF}, + {WNI_CFG_MPDU_DENSITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_MPDU_DENSITY_STAMIN, + WNI_CFG_MPDU_DENSITY_STAMAX, + WNI_CFG_MPDU_DENSITY_STADEF}, + {WNI_CFG_MAX_RX_AMPDU_FACTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX}, + {WNI_CFG_MAX_PS_POLL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_MAX_PS_POLL_STAMIN, + WNI_CFG_MAX_PS_POLL_STAMAX, + WNI_CFG_MAX_PS_POLL_STADEF}, + {WNI_CFG_SCAN_IN_POWERSAVE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_SCAN_IN_POWERSAVE_STAMIN, + WNI_CFG_SCAN_IN_POWERSAVE_STAMAX, + WNI_CFG_SCAN_IN_POWERSAVE_STADEF}, + {WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMIN, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMAX, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMIN, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMAX, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_DEAUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMIN, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMAX, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_DISASSOC_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMIN, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMAX, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMIN, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMAX, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STADEF}, + {WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMIN, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMAX, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STADEF}, + {WNI_CFG_IBSS_AUTO_BSSID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IBSS_AUTO_BSSID_STAMIN, + WNI_CFG_IBSS_AUTO_BSSID_STAMAX, + WNI_CFG_IBSS_AUTO_BSSID_STADEF}, + {WNI_CFG_WPS_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_ENABLE_STAMIN, + WNI_CFG_WPS_ENABLE_STAMAX, + WNI_CFG_WPS_ENABLE_STADEF}, + {WNI_CFG_WPS_STATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_STATE_STAMIN, + WNI_CFG_WPS_STATE_STAMAX, + WNI_CFG_WPS_STATE_STADEF}, + {WNI_CFG_WPS_VERSION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_VERSION_STAMIN, + WNI_CFG_WPS_VERSION_STAMAX, + WNI_CFG_WPS_VERSION_STADEF}, + {WNI_CFG_WPS_CFG_METHOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_CFG_METHOD_STAMIN, + 4294967295u, + WNI_CFG_WPS_CFG_METHOD_STADEF}, + {WNI_CFG_WPS_UUID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMIN, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMAX, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STADEF}, + {WNI_CFG_WPS_PIMARY_DEVICE_OUI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMIN, + 4294967295u, + WNI_CFG_WPS_PIMARY_DEVICE_OUI_STADEF}, + {WNI_CFG_WPS_DEVICE_SUB_CATEGORY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMIN, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMAX, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STADEF}, + {WNI_CFG_WPS_DEVICE_PASSWORD_ID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMIN, + 4294967295u, + WNI_CFG_WPS_DEVICE_PASSWORD_ID_STADEF}, + {WNI_CFG_SINGLE_TID_RC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SINGLE_TID_RC_STAMIN, + WNI_CFG_SINGLE_TID_RC_STAMAX, + WNI_CFG_SINGLE_TID_RC_STADEF}, + {WNI_CFG_TELE_BCN_WAKEUP_EN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_TELE_BCN_WAKEUP_EN_STAMIN, + WNI_CFG_TELE_BCN_WAKEUP_EN_STAMAX, + WNI_CFG_TELE_BCN_WAKEUP_EN_STADEF}, + {WNI_CFG_TELE_BCN_MAX_LI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_TELE_BCN_MAX_LI_STAMIN, + WNI_CFG_TELE_BCN_MAX_LI_STAMAX, + WNI_CFG_TELE_BCN_MAX_LI_STADEF}, + {WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMIN, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STADEF}, + {WNI_CFG_ASSOC_STA_LIMIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_ASSOC_STA_LIMIT_STAMIN, + WNI_CFG_ASSOC_STA_LIMIT_STAMAX, + WNI_CFG_ASSOC_STA_LIMIT_STADEF}, + {WNI_CFG_ENABLE_LTE_COEX, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_LTE_COEX_STAMIN, + WNI_CFG_ENABLE_LTE_COEX_STAMAX, + WNI_CFG_ENABLE_LTE_COEX_STADEF}, + {WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF}, + {WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF}, + {WNI_CFG_ENABLE_MC_ADDR_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_MC_ADDR_LIST_STAMIN, + WNI_CFG_ENABLE_MC_ADDR_LIST_STAMAX, + WNI_CFG_ENABLE_MC_ADDR_LIST_STADEF}, + {WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF}, + {WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMIN, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMAX, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STADEF}, + {WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMIN, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMAX, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STADEF}, + {WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMIN, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMAX, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STADEF}, + {WNI_CFG_TDLS_BUF_STA_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_BUF_STA_ENABLED_STAMIN, + WNI_CFG_TDLS_BUF_STA_ENABLED_STAMAX, + WNI_CFG_TDLS_BUF_STA_ENABLED_STADEF}, + {WNI_CFG_TDLS_PUAPSD_INACT_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMIN, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMAX, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STADEF}, + {WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMIN, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMAX, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STADEF}, + {WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMIN, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMAX, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STADEF}, + {WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMAX, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF}, + {WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMIN, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF}, + {WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF}, + {WNI_CFG_CURRENT_RSSI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_CURRENT_RSSI_STAMIN, + WNI_CFG_CURRENT_RSSI_STAMAX, + WNI_CFG_CURRENT_RSSI_STADEF}, + {WNI_CFG_RTT3_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RTT3_ENABLE_STAMIN, + WNI_CFG_RTT3_ENABLE_STAMAX, + WNI_CFG_RTT3_ENABLE_STADEF}, + {WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMIN, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMAX, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STADEF}, + {WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMIN, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMAX, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STADEF}, + {WNI_CFG_IBSS_ATIM_WIN_SIZE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMIN, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMAX, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STADEF}, + {WNI_CFG_DFS_MASTER_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DFS_MASTER_ENABLED_STAMIN, + WNI_CFG_DFS_MASTER_ENABLED_STAMAX, + WNI_CFG_DFS_MASTER_ENABLED_STADEF}, + {WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMIN, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMAX, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STADEF}, + {WNI_CFG_TDLS_WMM_MODE_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMIN, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMAX, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STADEF}, + {WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMIN, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMAX, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STADEF}, + {WNI_CFG_TGT_GTX_USR_CFG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_TGT_GTX_USR_CFG_STAMIN, + WNI_CFG_TGT_GTX_USR_CFG_STAMAX, + WNI_CFG_TGT_GTX_USR_CFG_STADEF}, + {WNI_CFG_MAX_HT_MCS_TX_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_MAX_HT_MCS_TX_DATA_STAMIN, + WNI_CFG_MAX_HT_MCS_TX_DATA_STAMAX, + WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF}, + {WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMIN, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMAX, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF}, + {WNI_CFG_RATE_FOR_TX_MGMT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RATE_FOR_TX_MGMT_STAMIN, + WNI_CFG_RATE_FOR_TX_MGMT_STAMAX, + WNI_CFG_RATE_FOR_TX_MGMT_STADEF}, + {WNI_CFG_HE_CONTROL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_CONTROL_STAMIN, WNI_CFG_HE_CONTROL_STAMAX, + WNI_CFG_HE_CONTROL_STADEF}, + {WNI_CFG_HE_TWT_REQUESTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TWT_REQUESTOR_STAMIN, WNI_CFG_HE_TWT_REQUESTOR_STAMAX, + WNI_CFG_HE_TWT_REQUESTOR_STADEF}, + {WNI_CFG_HE_TWT_RESPONDER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TWT_RESPONDER_STAMIN, WNI_CFG_HE_TWT_RESPONDER_STAMAX, + WNI_CFG_HE_TWT_RESPONDER_STADEF}, + {WNI_CFG_HE_FRAGMENTATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_FRAGMENTATION_STAMIN, WNI_CFG_HE_FRAGMENTATION_STAMAX, + WNI_CFG_HE_FRAGMENTATION_STADEF}, + {WNI_CFG_HE_MAX_FRAG_MSDU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MAX_FRAG_MSDU_STAMIN, WNI_CFG_HE_MAX_FRAG_MSDU_STAMAX, + WNI_CFG_HE_MAX_FRAG_MSDU_STADEF}, + {WNI_CFG_HE_MIN_FRAG_SIZE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MIN_FRAG_SIZE_STAMIN, WNI_CFG_HE_MIN_FRAG_SIZE_STAMAX, + WNI_CFG_HE_MIN_FRAG_SIZE_STADEF}, + {WNI_CFG_HE_TRIG_PAD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TRIG_PAD_STAMIN, WNI_CFG_HE_TRIG_PAD_STAMAX, + WNI_CFG_HE_TRIG_PAD_STADEF}, + {WNI_CFG_HE_MTID_AGGR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MTID_AGGR_STAMIN, WNI_CFG_HE_MTID_AGGR_STAMAX, + WNI_CFG_HE_MTID_AGGR_STADEF}, + {WNI_CFG_HE_LINK_ADAPTATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_LINK_ADAPTATION_STAMIN, WNI_CFG_HE_LINK_ADAPTATION_STAMAX, + WNI_CFG_HE_LINK_ADAPTATION_STADEF}, + {WNI_CFG_HE_ALL_ACK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_ALL_ACK_STAMIN, WNI_CFG_HE_ALL_ACK_STAMAX, + WNI_CFG_HE_ALL_ACK_STADEF}, + {WNI_CFG_HE_UL_MU_RSP_SCHEDULING, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_UL_MU_RSP_SCHEDULING_STAMIN, + WNI_CFG_HE_UL_MU_RSP_SCHEDULING_STAMAX, + WNI_CFG_HE_UL_MU_RSP_SCHEDULING_STADEF}, + {WNI_CFG_HE_BUFFER_STATUS_RPT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_BUFFER_STATUS_RPT_STAMIN, + WNI_CFG_HE_BUFFER_STATUS_RPT_STAMAX, + WNI_CFG_HE_BUFFER_STATUS_RPT_STADEF}, + {WNI_CFG_HE_BCAST_TWT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_BCAST_TWT_STAMIN, WNI_CFG_HE_BCAST_TWT_STAMAX, + WNI_CFG_HE_BCAST_TWT_STADEF}, + {WNI_CFG_HE_BA_32BIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_BA_32BIT_STAMIN, WNI_CFG_HE_BA_32BIT_STAMAX, + WNI_CFG_HE_BA_32BIT_STADEF}, + {WNI_CFG_HE_MU_CASCADING, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MU_CASCADING_STAMIN, WNI_CFG_HE_MU_CASCADING_STAMAX, + WNI_CFG_HE_MU_CASCADING_STADEF}, + {WNI_CFG_HE_MULTI_TID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MULTI_TID_STAMIN, WNI_CFG_HE_MULTI_TID_STAMAX, + WNI_CFG_HE_MULTI_TID_STADEF}, + {WNI_CFG_HE_DL_MU_BA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_DL_MU_BA_STAMIN, WNI_CFG_HE_DL_MU_BA_STAMAX, + WNI_CFG_HE_DL_MU_BA_STADEF}, + {WNI_CFG_HE_OMI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OMI_STAMIN, WNI_CFG_HE_OMI_STAMAX, + WNI_CFG_HE_OMI_STADEF}, + {WNI_CFG_HE_OFDMA_RA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OFDMA_RA_STAMIN, WNI_CFG_HE_OFDMA_RA_STAMAX, + WNI_CFG_HE_OFDMA_RA_STADEF}, + {WNI_CFG_HE_MAX_AMPDU_LEN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MAX_AMPDU_LEN_STAMIN, WNI_CFG_HE_MAX_AMPDU_LEN_STAMAX, + WNI_CFG_HE_MAX_AMPDU_LEN_STADEF}, + {WNI_CFG_HE_AMSDU_FRAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_AMSDU_FRAG_STAMIN, WNI_CFG_HE_AMSDU_FRAG_STAMAX, + WNI_CFG_HE_AMSDU_FRAG_STADEF}, + {WNI_CFG_HE_FLEX_TWT_SCHED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_FLEX_TWT_SCHED_STAMIN, WNI_CFG_HE_FLEX_TWT_SCHED_STAMAX, + WNI_CFG_HE_FLEX_TWT_SCHED_STADEF}, + {WNI_CFG_HE_RX_CTRL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_RX_CTRL_STAMIN, WNI_CFG_HE_RX_CTRL_STAMAX, + WNI_CFG_HE_RX_CTRL_STADEF}, + {WNI_CFG_HE_BSRP_AMPDU_AGGR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_BSRP_AMPDU_AGGR_STAMIN, WNI_CFG_HE_BSRP_AMPDU_AGGR_STAMAX, + WNI_CFG_HE_BSRP_AMPDU_AGGR_STADEF}, + {WNI_CFG_HE_QTP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_QTP_STAMIN, WNI_CFG_HE_QTP_STAMAX, + WNI_CFG_HE_QTP_STADEF}, + {WNI_CFG_HE_A_BQR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_A_BQR_STAMIN, WNI_CFG_HE_A_BQR_STAMAX, + WNI_CFG_HE_A_BQR_STADEF}, + {WNI_CFG_HE_SR_RESPONDER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_SR_RESPONDER_STAMIN, WNI_CFG_HE_SR_RESPONDER_STAMAX, + WNI_CFG_HE_SR_RESPONDER_STADEF}, + {WNI_CFG_HE_NDP_FEEDBACK_SUPP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_NDP_FEEDBACK_SUPP_STAMIN, + WNI_CFG_HE_NDP_FEEDBACK_SUPP_STAMAX, + WNI_CFG_HE_NDP_FEEDBACK_SUPP_STADEF}, + {WNI_CFG_HE_AMSDU_IN_AMPDU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_AMSDU_IN_AMPDU_MIN, + WNI_CFG_HE_AMSDU_IN_AMPDU_MAX, + WNI_CFG_HE_AMSDU_IN_AMPDU_DEF}, + {WNI_CFG_HE_A_BQR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_A_BQR_STAMIN, WNI_CFG_HE_A_BQR_STAMAX, + WNI_CFG_HE_A_BQR_STADEF}, + {WNI_CFG_HE_DUAL_BAND, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_DUAL_BAND_STAMIN, WNI_CFG_HE_DUAL_BAND_STAMAX, + WNI_CFG_HE_DUAL_BAND_STADEF}, + {WNI_CFG_HE_CHAN_WIDTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_CHAN_WIDTH_STAMIN, WNI_CFG_HE_CHAN_WIDTH_STAMAX, + WNI_CFG_HE_CHAN_WIDTH_STADEF}, + {WNI_CFG_HE_RX_PREAM_PUNC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_RX_PREAM_PUNC_STAMIN, WNI_CFG_HE_RX_PREAM_PUNC_STAMAX, + WNI_CFG_HE_RX_PREAM_PUNC_STADEF}, + {WNI_CFG_HE_CLASS_OF_DEVICE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_CLASS_OF_DEVICE_STAMIN, WNI_CFG_HE_CLASS_OF_DEVICE_STAMAX, + WNI_CFG_HE_CLASS_OF_DEVICE_STADEF}, + {WNI_CFG_HE_LDPC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_LDPC_STAMIN, WNI_CFG_HE_LDPC_STAMAX, + WNI_CFG_HE_LDPC_STADEF}, + {WNI_CFG_HE_LTF_PPDU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_LTF_PPDU_STAMIN, WNI_CFG_HE_LTF_PPDU_STAMAX, + WNI_CFG_HE_LTF_PPDU_STADEF}, + {WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS_MIN, + WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS_MAX, + WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS_DEF}, + {WNI_CFG_HE_LTF_NDP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_LTF_NDP_STAMIN, WNI_CFG_HE_LTF_NDP_STAMAX, + WNI_CFG_HE_LTF_NDP_STADEF}, + {WNI_CFG_HE_TX_STBC_LT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TX_STBC_LT80_STAMIN, WNI_CFG_HE_TX_STBC_LT80_STAMAX, + WNI_CFG_HE_TX_STBC_LT80_STADEF}, + {WNI_CFG_HE_RX_STBC_LT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_RX_STBC_LT80_STAMIN, WNI_CFG_HE_RX_STBC_LT80_STAMAX, + WNI_CFG_HE_RX_STBC_LT80_STADEF}, + {WNI_CFG_HE_DOPPLER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_DOPPLER_STAMIN, WNI_CFG_HE_DOPPLER_STAMAX, + WNI_CFG_HE_DOPPLER_STADEF}, + {WNI_CFG_HE_UL_MUMIMO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_UL_MUMIMO_STAMIN, WNI_CFG_HE_UL_MUMIMO_STAMAX, + WNI_CFG_HE_UL_MUMIMO_STADEF}, + {WNI_CFG_HE_DCM_TX, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_DCM_TX_STAMIN, WNI_CFG_HE_DCM_TX_STAMAX, + WNI_CFG_HE_DCM_TX_STADEF}, + {WNI_CFG_HE_DCM_RX, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_DCM_RX_STAMIN, WNI_CFG_HE_DCM_RX_STAMAX, + WNI_CFG_HE_DCM_RX_STADEF}, + {WNI_CFG_HE_MU_PPDU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MU_PPDU_STAMIN, WNI_CFG_HE_MU_PPDU_STAMAX, + WNI_CFG_HE_MU_PPDU_STADEF}, + {WNI_CFG_HE_SU_BEAMFORMER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_SU_BEAMFORMER_STAMIN, WNI_CFG_HE_SU_BEAMFORMER_STAMAX, + WNI_CFG_HE_SU_BEAMFORMER_STADEF}, + {WNI_CFG_HE_SU_BEAMFORMEE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_SU_BEAMFORMEE_STAMIN, WNI_CFG_HE_SU_BEAMFORMEE_STAMAX, + WNI_CFG_HE_SU_BEAMFORMEE_STADEF}, + {WNI_CFG_HE_MU_BEAMFORMER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MU_BEAMFORMER_STAMIN, WNI_CFG_HE_MU_BEAMFORMER_STAMAX, + WNI_CFG_HE_MU_BEAMFORMER_STADEF}, + {WNI_CFG_HE_BFEE_STS_LT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_BFEE_STS_LT80_STAMIN, WNI_CFG_HE_BFEE_STS_LT80_STAMAX, + WNI_CFG_HE_BFEE_STS_LT80_STADEF}, + {WNI_CFG_HE_BFEE_STS_GT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_BFEE_STS_GT80_STAMIN, WNI_CFG_HE_BFEE_STS_GT80_STAMAX, + WNI_CFG_HE_BFEE_STS_GT80_STADEF}, + {WNI_CFG_HE_NUM_SOUND_LT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_NUM_SOUND_LT80_STAMIN, WNI_CFG_HE_NUM_SOUND_LT80_STAMAX, + WNI_CFG_HE_NUM_SOUND_LT80_STADEF}, + {WNI_CFG_HE_NUM_SOUND_GT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_NUM_SOUND_GT80_STAMIN, WNI_CFG_HE_NUM_SOUND_GT80_STAMAX, + WNI_CFG_HE_NUM_SOUND_GT80_STADEF}, + {WNI_CFG_HE_SU_FEED_TONE16, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_SU_FEED_TONE16_STAMIN, WNI_CFG_HE_SU_FEED_TONE16_STAMAX, + WNI_CFG_HE_SU_FEED_TONE16_STADEF}, + {WNI_CFG_HE_MU_FEED_TONE16, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MU_FEED_TONE16_STAMIN, WNI_CFG_HE_MU_FEED_TONE16_STAMAX, + WNI_CFG_HE_MU_FEED_TONE16_STADEF}, + {WNI_CFG_HE_CODEBOOK_SU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_CODEBOOK_SU_STAMIN, WNI_CFG_HE_CODEBOOK_SU_STAMAX, + WNI_CFG_HE_CODEBOOK_SU_STADEF}, + {WNI_CFG_HE_CODEBOOK_MU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_CODEBOOK_MU_STAMIN, WNI_CFG_HE_CODEBOOK_MU_STAMAX, + WNI_CFG_HE_CODEBOOK_MU_STADEF}, + {WNI_CFG_HE_BFRM_FEED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_BFRM_FEED_STAMIN, WNI_CFG_HE_BFRM_FEED_STAMAX, + WNI_CFG_HE_BFRM_FEED_STADEF}, + {WNI_CFG_HE_ER_SU_PPDU, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_ER_SU_PPDU_STAMIN, WNI_CFG_HE_ER_SU_PPDU_STAMAX, + WNI_CFG_HE_ER_SU_PPDU_STADEF}, + {WNI_CFG_HE_DL_PART_BW, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_DL_PART_BW_STAMIN, WNI_CFG_HE_DL_PART_BW_STAMAX, + WNI_CFG_HE_DL_PART_BW_STADEF}, + {WNI_CFG_HE_PPET_PRESENT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_PPET_PRESENT_STAMIN, WNI_CFG_HE_PPET_PRESENT_STAMAX, + WNI_CFG_HE_PPET_PRESENT_STADEF}, + {WNI_CFG_HE_SRP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_SRP_STAMIN, WNI_CFG_HE_SRP_STAMAX, + WNI_CFG_HE_SRP_STADEF}, + {WNI_CFG_HE_POWER_BOOST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_POWER_BOOST_STAMIN, WNI_CFG_HE_POWER_BOOST_STAMAX, + WNI_CFG_HE_POWER_BOOST_STADEF}, + {WNI_CFG_HE_4x_LTF_GI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_4x_LTF_GI_STAMIN, WNI_CFG_HE_4x_LTF_GI_STAMAX, + WNI_CFG_HE_4x_LTF_GI_STADEF}, + {WNI_CFG_HE_MAX_NC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MAX_NC_STAMIN, WNI_CFG_HE_MAX_NC_STAMAX, + WNI_CFG_HE_MAX_NC_STADEF}, + {WNI_CFG_HE_TX_STBC_GT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TX_STBC_GT80_STAMIN, WNI_CFG_HE_TX_STBC_GT80_STAMAX, + WNI_CFG_HE_TX_STBC_GT80_STADEF}, + {WNI_CFG_HE_RX_STBC_GT80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_RX_STBC_GT80_STAMIN, WNI_CFG_HE_RX_STBC_GT80_STAMAX, + WNI_CFG_HE_RX_STBC_GT80_STADEF}, + {WNI_CFG_HE_ER_4x_LTF_GI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_ER_4x_LTF_GI_STAMIN, WNI_CFG_HE_ER_4x_LTF_GI_STAMAX, + WNI_CFG_HE_ER_4x_LTF_GI_STADEF}, + + {WNI_CFG_HE_PPDU_20_IN_40MHZ_2G, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_PPDU_20_IN_40MHZ_2G_MIN, WNI_CFG_HE_PPDU_20_IN_40MHZ_2G_MAX, + WNI_CFG_HE_PPDU_20_IN_40MHZ_2G_DEF}, + {WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ_MIN, + WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ_MAX, + WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ_DEF}, + {WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ_MIN, + WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ_MAX, + WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ_DEF}, + {WNI_CFG_HE_ER_1X_HE_LTF_GI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_ER_1X_HE_LTF_GI_MIN, WNI_CFG_HE_ER_1X_HE_LTF_GI_MAX, + WNI_CFG_HE_ER_1X_HE_LTF_GI_DEF}, + {WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF_MIN, + WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF_MAX, + WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF_DEF}, + + {WNI_CFG_HE_RX_MCS_MAP_LT_80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_RX_MCS_MAP_LT_80_MIN, WNI_CFG_HE_RX_MCS_MAP_LT_80_MAX, + WNI_CFG_HE_RX_MCS_MAP_LT_80_DEF}, + + {WNI_CFG_HE_TX_MCS_MAP_LT_80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TX_MCS_MAP_LT_80_MIN, WNI_CFG_HE_TX_MCS_MAP_LT_80_MAX, + WNI_CFG_HE_TX_MCS_MAP_LT_80_DEF}, + + {WNI_CFG_HE_RX_MCS_MAP_160, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_RX_MCS_MAP_160_MIN, WNI_CFG_HE_RX_MCS_MAP_160_MAX, + WNI_CFG_HE_RX_MCS_MAP_160_DEF}, + + {WNI_CFG_HE_TX_MCS_MAP_160, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TX_MCS_MAP_160_MIN, WNI_CFG_HE_TX_MCS_MAP_160_MAX, + WNI_CFG_HE_TX_MCS_MAP_160_DEF}, + + {WNI_CFG_HE_RX_MCS_MAP_80_80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_RX_MCS_MAP_80_80_MIN, WNI_CFG_HE_RX_MCS_MAP_80_80_MAX, + WNI_CFG_HE_RX_MCS_MAP_80_80_DEF}, + + {WNI_CFG_HE_TX_MCS_MAP_80_80, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_TX_MCS_MAP_80_80_MIN, WNI_CFG_HE_TX_MCS_MAP_80_80_MAX, + WNI_CFG_HE_TX_MCS_MAP_80_80_DEF}, + + {WNI_CFG_HE_PPET_2G, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_HE_PPET_5G, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + + {WNI_CFG_HE_OPS_BSS_COLOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_BSS_COLOR_MIN, WNI_CFG_HE_OPS_BSS_COLOR_MAX, + WNI_CFG_HE_OPS_BSS_COLOR_DEF}, + + {WNI_CFG_HE_OPS_DEFAULT_PE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_DEFAULT_PE_MIN, WNI_CFG_HE_OPS_DEFAULT_PE_MAX, + WNI_CFG_HE_OPS_DEFAULT_PE_DEF}, + + {WNI_CFG_HE_OPS_TWT_REQUIRED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_TWT_REQUIRED_MIN, WNI_CFG_HE_OPS_TWT_REQUIRED_MAX, + WNI_CFG_HE_OPS_TWT_REQUIRED_DEF}, + + {WNI_CFG_HE_OPS_RTS_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_RTS_THRESHOLD_MIN, WNI_CFG_HE_OPS_RTS_THRESHOLD_MAX, + WNI_CFG_HE_OPS_RTS_THRESHOLD_DEF}, + + {WNI_CFG_HE_OPS_PARTIAL_BSS_COL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_PARTIAL_BSS_COL_MIN, WNI_CFG_HE_OPS_PARTIAL_BSS_COL_MAX, + WNI_CFG_HE_OPS_PARTIAL_BSS_COL_DEF}, + + {WNI_CFG_HE_OPS_VHT_OPER_PRESENT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_VHT_OPER_PRESENT_MIN, + WNI_CFG_HE_OPS_VHT_OPER_PRESENT_MAX, + WNI_CFG_HE_OPS_VHT_OPER_PRESENT_DEF}, + + {WNI_CFG_HE_OPS_MBSSID_AP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_MBSSID_AP_MIN, WNI_CFG_HE_OPS_MBSSID_AP_MAX, + WNI_CFG_HE_OPS_MBSSID_AP_DEF}, + + {WNI_CFG_HE_OPS_TX_BSSID_IND, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_TX_BSSID_IND_MIN, WNI_CFG_HE_OPS_TX_BSSID_IND_MAX, + WNI_CFG_HE_OPS_TX_BSSID_IND_DEF}, + + {WNI_CFG_HE_OPS_BSS_COL_DISABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_BSS_COL_DISABLED_MIN, + WNI_CFG_HE_OPS_BSS_COL_DISABLED_MAX, + WNI_CFG_HE_OPS_BSS_COL_DISABLED_DEF}, + + {WNI_CFG_HE_OPS_BASIC_MCS_NSS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_OPS_BASIC_MCS_NSS_MIN, WNI_CFG_HE_OPS_BASIC_MCS_NSS_MAX, + WNI_CFG_HE_OPS_BASIC_MCS_NSS_DEF}, + + {WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMIN, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMAX, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STADEF}, + {WNI_CFG_HE_STA_OBSSPD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_HE_STA_OBSSPD_STAMIN, WNI_CFG_HE_STA_OBSSPD_STAMAX, + WNI_CFG_HE_STA_OBSSPD_STADEF}, + {WNI_CFG_SAP_MAX_MCS_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SAP_MAX_MCS_DATA_STAMIN, + WNI_CFG_SAP_MAX_MCS_DATA_STAMAX, + WNI_CFG_SAP_MAX_MCS_DATA_STADEF}, + {WNI_CFG_RATE_FOR_TX_MGMT_2G, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RATE_FOR_TX_MGMT_2G_STAMIN, + WNI_CFG_RATE_FOR_TX_MGMT_2G_STAMAX, + WNI_CFG_RATE_FOR_TX_MGMT_2G_STADEF}, + {WNI_CFG_RATE_FOR_TX_MGMT_5G, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RATE_FOR_TX_MGMT_5G_STAMIN, + WNI_CFG_RATE_FOR_TX_MGMT_5G_STAMAX, + WNI_CFG_RATE_FOR_TX_MGMT_5G_STADEF}, + {WNI_CFG_EDCA_ETSI_ACBK_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ETSI_ACBE_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ETSI_ACVI_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ETSI_ACVO_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ETSI_ACBK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ETSI_ACBE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ETSI_ACVI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ETSI_ACVO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_OBSS_DETECTION_OFFLOAD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + 0, 1, 0}, + {WNI_CFG_OBSS_COLOR_COLLISION_OFFLOAD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + 0, 1, 0}, + {WNI_CFG_TWT_REQUESTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_TWT_REQUESTOR_STAMIN, WNI_CFG_TWT_REQUESTOR_STAMAX, + WNI_CFG_TWT_REQUESTOR_STADEF}, + {WNI_CFG_TWT_RESPONDER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_TWT_RESPONDER_STAMIN, WNI_CFG_TWT_RESPONDER_STAMAX, + WNI_CFG_TWT_RESPONDER_STADEF}, + {WNI_CFG_BCAST_TWT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_BCAST_TWT_STAMIN, WNI_CFG_BCAST_TWT_STAMAX, + WNI_CFG_BCAST_TWT_STADEF}, +}; + + +cfgstatic_string cfg_static_string[CFG_MAX_STATIC_STRING] = { + + {WNI_CFG_STA_ID, + WNI_CFG_STA_ID_LEN, + 6, + {0x22, 0x22, 0x44, 0x44, 0x33, 0x33} }, + {WNI_CFG_SSID, + WNI_CFG_SSID_LEN, + 10, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 0} }, + {WNI_CFG_WEP_DEFAULT_KEY_1, + WNI_CFG_WEP_DEFAULT_KEY_1_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_2, + WNI_CFG_WEP_DEFAULT_KEY_2_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_3, + WNI_CFG_WEP_DEFAULT_KEY_3_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_4, + WNI_CFG_WEP_DEFAULT_KEY_4_LEN, + 0, + {0} }, + {WNI_CFG_SUPPORTED_RATES_11B, + WNI_CFG_SUPPORTED_RATES_11B_LEN, + 4, + {2, 4, 11, 22} }, + {WNI_CFG_SUPPORTED_RATES_11A, + WNI_CFG_SUPPORTED_RATES_11A_LEN, + 8, + {12, 18, 24, 36, 48, 72, 96, 108} }, + {WNI_CFG_OPERATIONAL_RATE_SET, + WNI_CFG_OPERATIONAL_RATE_SET_LEN, + 0, + {0} }, + {WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN, + 0, + {0} }, + {WNI_CFG_VALID_CHANNEL_LIST, + WNI_CFG_VALID_CHANNEL_LIST_LEN, + 55, + {36, 40, 44, 48, 52, 56, 60, 64, 1, 6, 11, 34, 38, 42, 46, 2, 3, 4, + 5, 7, 8, 9, 10, 12, 13, 14, 100, 104, 108, 112, 116, 120, 124, 128, + 132, 136, 140, 149, 151, 153, 155, 157, 159, 161, 50, 54, 58, 62, 240, + 242, 244, 246, 248, 250, 252} }, + + {WNI_CFG_MANUFACTURER_NAME, + WNI_CFG_MANUFACTURER_NAME_LEN, + 8, + {0x51, 0x75, 0x61, 0x6c, 0x63, 0x6f, 0x6d, 0x6d} }, + {WNI_CFG_MODEL_NUMBER, + WNI_CFG_MODEL_NUMBER_LEN, + 6, + {0x4d, 0x4e, 0x31, 0x32, 0x33, 0x34} }, + {WNI_CFG_MODEL_NAME, + WNI_CFG_MODEL_NAME_LEN, + 7, + {0x57, 0x46, 0x52, 0x34, 0x30, 0x33, 0x31} }, + {WNI_CFG_MANUFACTURER_PRODUCT_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN, + 6, + {0x31, 0x31, 0x6e, 0x2d, 0x41, 0x50} }, + {WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN, + 6, + {0x53, 0x4e, 0x31, 0x32, 0x33, 0x34} }, + {WNI_CFG_MAX_TX_POWER_2_4, + WNI_CFG_MAX_TX_POWER_2_4_LEN, + 3, + {0x1, 0xe, 0x14} }, + {WNI_CFG_MAX_TX_POWER_5, + WNI_CFG_MAX_TX_POWER_5_LEN, + 3, + {0x24, 0x7e, 0x14} }, + {WNI_CFG_COUNTRY_CODE, + WNI_CFG_COUNTRY_CODE_LEN, + 0, + {0} }, + {WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ANI_ACBE_LOCAL, + WNI_CFG_EDCA_ANI_ACBE_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, + 0xf, 0x3, 0xff, 0x64} }, + {WNI_CFG_EDCA_ANI_ACVI_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, 0xbc, 0x0, + 0x7, 0x0, 0xf, 0xc8} }, + {WNI_CFG_EDCA_ANI_ACVO_LOCAL, + WNI_CFG_EDCA_ANI_ACVO_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, + 0x3, 0x0, 0x7, 0x64} }, + {WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACBK_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ANI_ACBE, + WNI_CFG_EDCA_ANI_ACBE_LEN, + 17, + {0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, + 0xf, 0x3, 0xff, 0x64} }, + {WNI_CFG_EDCA_ANI_ACVI, + WNI_CFG_EDCA_ANI_ACVI_LEN, + 17, {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, + 0xbc, 0x0, 0x7, 0x0, 0xf, 0xc8} }, + {WNI_CFG_EDCA_ANI_ACVO, + WNI_CFG_EDCA_ANI_ACVO_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x64} }, + {WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACBK_LOCAL_LEN, + 17, {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, + 0x0, 0x0, 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACBE_LOCAL, + WNI_CFG_EDCA_WME_ACBE_LOCAL_LEN, + 17, {0x0, 0x3, 0x0, 0xf, 0x0, 0x3f, 0x0, 0x0, 0x1f, 0x3, 0xff, + 0x0, 0x0, 0xf, 0x0, 0x3f, 0x0} }, + {WNI_CFG_EDCA_WME_ACVI_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, + 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_WME_ACVO_LOCAL, + WNI_CFG_EDCA_WME_ACVO_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x2f} }, + {WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACBK_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, + 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACBE, + WNI_CFG_EDCA_WME_ACBE_LEN, + 17, + {0x0, 0x3, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, + 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACVI, + WNI_CFG_EDCA_WME_ACVI_LEN, + 17, + {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, + 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_WME_ACVO, + WNI_CFG_EDCA_WME_ACVO_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x2f} }, + {WNI_CFG_SUPPORTED_MCS_SET, + WNI_CFG_SUPPORTED_MCS_SET_LEN, + 16, + {0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_BASIC_MCS_SET, + WNI_CFG_BASIC_MCS_SET_LEN, + 16, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_CURRENT_MCS_SET, + WNI_CFG_CURRENT_MCS_SET_LEN, + 16, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_WPS_UUID, + WNI_CFG_WPS_UUID_LEN, + 6, + {0xa, 0xb, 0xc, 0xd, 0xe, 0xf} }, + {WNI_CFG_HE_PPET_2G, + WNI_CFG_HE_PPET_LEN, + WNI_CFG_HE_PPET_LEN, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }, + {WNI_CFG_HE_PPET_5G, + WNI_CFG_HE_PPET_LEN, + WNI_CFG_HE_PPET_LEN, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }, + {WNI_CFG_EDCA_ETSI_ACBK_LOCAL, + WNI_CFG_EDCA_ETSI_ACBK_LOCAL_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0xbb, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ETSI_ACBE_LOCAL, + WNI_CFG_EDCA_ETSI_ACBE_LOCAL_LEN, + 17, + {0x0, 0x3, 0x0, 0xf, 0x0, 0x3f, 0xbb, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x0, 0x3f, 0x0} }, + {WNI_CFG_EDCA_ETSI_ACVI_LOCAL, + WNI_CFG_EDCA_ETSI_ACVI_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x7, 0x0, 0xf, 0x7d, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, + 0x7, 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_ETSI_ACVO_LOCAL, + WNI_CFG_EDCA_ETSI_ACVO_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x3, 0x0, 0x7, 0x3e, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, + 0x3, 0x0, 0x7, 0x2f} }, + {WNI_CFG_EDCA_ETSI_ACBK, + WNI_CFG_EDCA_ETSI_ACBK_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0xbb, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ETSI_ACBE, + WNI_CFG_EDCA_ETSI_ACBE_LEN, + 17, + {0x0, 0x3, 0x0, 0xf, 0x3, 0xff, 0xbb, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ETSI_ACVI, + WNI_CFG_EDCA_ETSI_ACVI_LEN, + 17, + {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0x7d, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, + 0x7, 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_ETSI_ACVO, + WNI_CFG_EDCA_ETSI_ACVO_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x3e, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, + 0x3, 0x0, 0x7, 0x2f} }, +}; + +/*--------------------------------------------------------------------*/ +/* Static function prototypes */ +/*--------------------------------------------------------------------*/ +static void proc_dnld_rsp(tpAniSirGlobal, uint16_t, uint32_t *); +static void proc_get_req(tpAniSirGlobal, uint16_t, uint32_t *); + +static uint8_t check_param(tpAniSirGlobal, uint16_t, uint32_t, uint32_t, + uint32_t *); +/*--------------------------------------------------------------------*/ +/* Module global variables */ +/*--------------------------------------------------------------------*/ + +/* CFG function table */ +void (*g_cfg_func[])(tpAniSirGlobal, uint16_t, uint32_t *) = { + proc_dnld_rsp, proc_get_req +}; + +/**--------------------------------------------------------------------- + * cfg_process_mb_msg() + * + ***FUNCTION: + * CFG mailbox message processing function. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * None. + * + ***NOTE: + * + * @param pMsg Message pointer + * + * @return None. + * + */ +void cfg_process_mb_msg(tpAniSirGlobal pMac, tSirMbMsg *pMsg) +{ + uint16_t index; + uint16_t len; + uint32_t *pParam; + + /* Use type[7:0] as index to function table */ + index = CFG_GET_FUNC_INDX(pMsg->type); + + if (index >= QDF_ARRAY_SIZE(g_cfg_func)) { + qdf_mem_free(pMsg); + return; + } + len = pMsg->msgLen - WNI_CFG_MB_HDR_LEN; + pParam = ((uint32_t *) pMsg) + 1; + + /* Call processing function */ + g_cfg_func[index] (pMac, len, pParam); + + /* Free up buffer */ + qdf_mem_free(pMsg); + +} /*** end cfg_process_mb_msg() ***/ + +/**--------------------------------------------------------------------- + * proc_dnld_rsp() + * + * FUNCTION: + * This function processes CFG_DNLD_RSP message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param length: message length + * @param pParam: parameter list pointer + * + * @return None + * + */ +static void proc_dnld_rsp(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + int32_t i; + + uint32_t expLen, retVal, bufStart, bufEnd; + uint32_t *pSrc, *pDst, *pDstEnd; + uint32_t strSize, j; + uint8_t pStr[CFG_MAX_STR_LEN]; + tpCfgBinHdr pHdr; + struct scheduler_msg mmhMsg = {0}; + + /* First Dword must contain the AP or STA magic dword */ + pe_debug("CFG size: %d bytes MAGIC dword is: 0x%x", + length, sir_read_u32_n((uint8_t *) pParam)); + + /* if the string is not correct, return failure */ + if (*pParam == CFG_STA_MAGIC_DWORD) { + } + + else { + pe_warn("Invalid magic dword: 0x%x", + sir_read_u32_n((uint8_t *) pParam)); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + pParam++; + length -= 4; + + /* Parse the Cfg header */ + pHdr = (tpCfgBinHdr) pParam; + pParam += (sizeof(tCfgBinHdr) >> 2); + pe_debug("CFG hdr totParams: %d intParams: %d strBufSize: %d/%d", + pHdr->controlSize, pHdr->iBufSize, pHdr->sBufSize, + pMac->cfg.gCfgMaxSBufSize); + + if (pHdr->sBufSize > (UINT_MAX - + (((CFG_PARAM_MAX_NUM + 3 * pMac->cfg.gCfgMaxIBufSize) << 2) + + sizeof(tCfgBinHdr)))) { + pe_warn("Invalid sBufSize coming from fw: %d", pHdr->sBufSize); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + expLen = + ((CFG_PARAM_MAX_NUM + 3 * pMac->cfg.gCfgMaxIBufSize) << 2) + + pHdr->sBufSize + sizeof(tCfgBinHdr); + + if (length != expLen) { + pe_warn(" DNLD_RSP invalid length: %d (exp: %d)", length, + expLen); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + if (pHdr->controlSize != CFG_PARAM_MAX_NUM) { + pe_warn(" Total parameter count mismatch"); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + if (pHdr->iBufSize != pMac->cfg.gCfgMaxIBufSize) { + pe_warn(" Integer parameter count mismatch"); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + /* Copy control array */ + pDst = (uint32_t *) pMac->cfg.gCfgEntry; + pDstEnd = pDst + CFG_PARAM_MAX_NUM; + pSrc = pParam; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + /* Copy default values */ + pDst = pMac->cfg.gCfgIBuf; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + /* Copy min values */ + pDst = pMac->cfg.gCfgIBufMin; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + /* Copy max values */ + pDst = pMac->cfg.gCfgIBufMax; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + for (i = 0; i < pMac->cfg.gCfgMaxIBufSize; i++) + if (pMac->cfg.gCfgIBuf[i] < pMac->cfg.gCfgIBufMin[i] || + pMac->cfg.gCfgIBuf[i] > pMac->cfg.gCfgIBufMax[i]) { + pe_debug("cfg id: %d Invalid def value: %d min: %d max: %d", + i, pMac->cfg.gCfgIBuf[i], + pMac->cfg.gCfgIBufMin[i], + pMac->cfg.gCfgIBufMax[i]); + } + /* Calculate max string buffer lengths for all string parameters */ + bufEnd = pMac->cfg.gCfgMaxSBufSize; + for (i = CFG_PARAM_MAX_NUM - 1; i >= 0; i--) { + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) + continue; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + + bufStart = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + pMac->cfg.gCfgSBuf[bufStart] = + (uint8_t) (bufEnd - bufStart - 2); + + pe_debug("id: %d max: %d bufStart: %d bufEnd: %d", i, + pMac->cfg.gCfgSBuf[bufStart], bufStart, bufEnd); + bufEnd = bufStart; + } + + /* Initialize string defaults */ + strSize = pHdr->sBufSize; + while (strSize) { + uint32_t paramId, paramLen, paramLenCeil4; + + if (strSize < 4) { + pe_warn("parsing str defaults, rem: %d bytes", + strSize); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + paramId = *pSrc >> 16; + paramLen = *pSrc & 0xff; + pSrc++; + strSize -= 4; + + paramLenCeil4 = ((paramLen + 3) >> 2); + if (strSize < paramLenCeil4 << 2) { + pe_warn("parsing str defaults, rem: %d bytes", + strSize); + pe_warn("param id: %d len: %d bytes", + paramId, paramLen); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + for (j = 0; j < paramLenCeil4; j++) { + pStr[4 * j] = (uint8_t) (*pSrc >> 24) & 0xff; + pStr[4 * j + 1] = (uint8_t) (*pSrc >> 16) & 0xff; + pStr[4 * j + 2] = (uint8_t) (*pSrc >> 8) & 0xff; + pStr[4 * j + 3] = (uint8_t) (*pSrc) & 0xff; + + pSrc++; + strSize -= 4; + } + + pe_debug("set str id: %d len: %d", paramId, paramLen); + + if (cfg_set_str(pMac, (uint16_t) paramId, pStr, paramLen) != + QDF_STATUS_SUCCESS) { + pe_warn("setting str default param %d len %d", + paramId, paramLen); + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + } + + /* Set status to READY */ + pMac->cfg.gCfgStatus = CFG_SUCCESS; + retVal = WNI_CFG_SUCCESS; + pe_debug(" Completed successfully"); + +end: + + if (retVal != WNI_CFG_SUCCESS) + pMac->cfg.gCfgStatus = CFG_FAILURE; + + /* Send response message to host */ + pMac->cfg.gParamList[WNI_CFG_DNLD_CNF_RES] = retVal; + cfg_send_host_msg(pMac, WNI_CFG_DNLD_CNF, WNI_CFG_DNLD_CNF_LEN, + WNI_CFG_DNLD_CNF_NUM, pMac->cfg.gParamList, 0, 0); + + /* notify WMA that the config has downloaded */ + mmhMsg.type = SIR_CFG_DOWNLOAD_COMPLETE_IND; + mmhMsg.bodyptr = NULL; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + if (wma_post_ctrl_msg(pMac, &mmhMsg) != QDF_STATUS_SUCCESS) { + pe_err("WMAPostMsgApi failed!"); + } + +} /*** end procDnldRsp() ***/ + +/**--------------------------------------------------------------------- + * proc_get_req() + * + * FUNCTION: + * This function processes CFG_GET_REQ message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * For every parameter ID specified on the list, CFG will send a separate + * CFG_GET_RSP back to host. + * + * @param length: message length + * @param pParam: parameter list pointer + * + * @return None + * + */ +static void proc_get_req(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + uint16_t cfgId; +#ifdef WLAN_DEBUG + uint16_t i; +#endif + uint32_t value, valueLen, result; + uint32_t *pValue; + + pe_debug("Rcvd cfg get request %d bytes", length); +#ifdef WLAN_DEBUG + for (i = 0; i < length / 4; i++) + pe_debug("[%2d] 0x%08x", i, pParam[i]); +#endif + + if (!pMac->cfg.gCfgStatus) { + cfgId = (uint16_t) sir_read_u32_n((uint8_t *) pParam); + pe_debug("CFG not ready, param %d", cfgId); + pMac->cfg.gParamList[WNI_CFG_GET_RSP_RES] = + WNI_CFG_NOT_READY; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PID] = cfgId; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PLEN] = 0; + cfg_send_host_msg(pMac, WNI_CFG_GET_RSP, + WNI_CFG_GET_RSP_PARTIAL_LEN, WNI_CFG_GET_RSP_NUM, + pMac->cfg.gParamList, 0, 0); + } else { + /* Process all parameter ID's on the list */ + while (length >= sizeof(uint32_t)) { + cfgId = (uint16_t) *pParam++; + pValue = 0; + valueLen = 0; + + pe_debug("Cfg get param %d", cfgId); + /* Check for valid parameter ID, etc... */ + if (check_param + (pMac, cfgId, CFG_CTL_RE, WNI_CFG_WO_PARAM, + &result)) { + if ((pMac->cfg.gCfgEntry[cfgId]. + control & CFG_CTL_INT) != 0) { + /* Get integer parameter */ + result = + (wlan_cfg_get_int(pMac, cfgId, &value) + == + QDF_STATUS_SUCCESS ? WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + pValue = &value; + valueLen = sizeof(uint32_t); + } else { + /* Get string parameter */ + valueLen = sizeof(pMac->cfg.gSBuffer); + result = + (wlan_cfg_get_str + (pMac, cfgId, pMac->cfg.gSBuffer, + &valueLen) + == QDF_STATUS_SUCCESS ? WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + pValue = + (uint32_t *) pMac->cfg.gSBuffer; + } + } else { + pe_warn("Check param failed, param %d", + cfgId); + result = WNI_CFG_INVALID_LEN; + } + + /* Send response message to host */ + pMac->cfg.gParamList[WNI_CFG_GET_RSP_RES] = result; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PID] = cfgId; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PLEN] = valueLen; + + /* We need to round up buffer length to word-increment */ + valueLen = (((valueLen + 3) >> 2) << 2); + cfg_send_host_msg(pMac, WNI_CFG_GET_RSP, + WNI_CFG_GET_RSP_PARTIAL_LEN + valueLen, + WNI_CFG_GET_RSP_NUM, + pMac->cfg.gParamList, valueLen, pValue); + + /* Decrement length */ + length -= sizeof(uint32_t); + } + } + +} /*** end procGetReq() ***/ + +/**--------------------------------------------------------------------- + * check_param() + * + * FUNCTION: + * This function is called to perform various check on a parameter. + * + * LOGIC: + * - If cfgId is out of bound or parameter is not valid, result + * WNI_CFG_INVALID_PID is returned at address specified in pResult. + * + * - If specified 'flag' is not set in the parameter control entry, + * 'failedResult' is returned at address specified in pResult. + * + * ASSUMPTIONS: + * Since this function is used internally, 'pResult' is always valid. + * + * NOTE: + * + * @param None + * + * @return true: Parameter is valid and matches checked condition \n + * @return false: Parameter either is not valid or does not match + * checked condition. + * + */ +static uint8_t +check_param(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t flag, + uint32_t failedResult, uint32_t *pResult) +{ + /* Check if parameter ID is out of bound */ + if (cfgId >= CFG_PARAM_MAX_NUM) { + pe_warn("Invalid param id: %d", cfgId); + *pResult = WNI_CFG_INVALID_PID; + } else { + /* Check if parameter is valid */ + if ((pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_VALID) == 0) { + pe_warn("Param id: %d not valid", cfgId); + *pResult = WNI_CFG_INVALID_PID; + } else { + /* Check control field against flag */ + if ((pMac->cfg.gCfgEntry[cfgId].control & flag) == 0) { + pe_debug("Param id: %d wrong permissions: %x", + cfgId, + pMac->cfg.gCfgEntry[cfgId].control); + *pResult = failedResult; + } else + return true; + } + } + return false; + +} /*** cfgParamCheck() ***/ + +/**--------------------------------------------------------------------- + * process_cfg_download_req() + * + * FUNCTION: This function does the Cfg Download and is invoked + * only in the case of Prima or the Integrated SOC + * solutions. Not applicable to Volans or Libra + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac: Pointer to Mac Structure + * + * @return None + * + */ + +void +process_cfg_download_req(tpAniSirGlobal pMac) +{ + int32_t i; + uint32_t index; + uint8_t *pDstTest, *pSrcTest; + uint8_t len; + cfgstatic_string * pStrCfg; + uint32_t bufStart, bufEnd; + uint32_t retVal; + uint32_t iCount = 0; + uint32_t sCount = 0; + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + if ((cfg_static[i].control & CFG_CTL_VALID) != 0) { + if (!(cfg_static[i].control & CFG_CTL_INT)) { + pStrCfg = (cfgstatic_string*)cfg_static[i]. + pStrData; + if (pStrCfg == NULL) { + pe_err("pStrCfg is NULL for CfigID : %d", + i); + continue; + } + index = sCount & CFG_BUF_INDX_MASK; + sCount += pStrCfg->maxLen + 1 + 1; + } else { + index = iCount & CFG_BUF_INDX_MASK; + iCount++; + } + } else { + index = 0; + } + pMac->cfg.gCfgEntry[i].control = cfg_static[i].control | index; + } + + /*Fill the SBUF wih maxLength*/ + bufEnd = pMac->cfg.gCfgMaxSBufSize; + for (i = CFG_PARAM_MAX_NUM - 1; i >= 0; i--) { + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) + continue; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + + bufStart = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + pMac->cfg.gCfgSBuf[bufStart] = (uint8_t)(bufEnd - bufStart - 2); + + pe_debug("id: %d max: %d bufStart: %d bufEnd: %d", + i, pMac->cfg.gCfgSBuf[bufStart], + bufStart, bufEnd); + bufEnd = bufStart; + } + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + index = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) { + pMac->cfg.gCfgIBufMin[index] = cfg_static[i].cfgIMin; + pMac->cfg.gCfgIBufMax[index] = cfg_static[i].cfgIMax; + pMac->cfg.gCfgIBuf[index] = cfg_static[i].cfgIVal; + } else { + uint8_t maxSavedLen; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + if (index >= pMac->cfg.gCfgMaxSBufSize) { + pe_debug("No space id:%d BufSize:%d index:%d", + i, pMac->cfg.gCfgMaxSBufSize, index); + continue; + } + + pDstTest = &pMac->cfg.gCfgSBuf[index]; + pStrCfg = (cfgstatic_string*)cfg_static[i].pStrData; + pSrcTest = pStrCfg->data; + if ((pDstTest == NULL) || (pStrCfg == NULL) || + (pSrcTest == NULL)) + continue; + maxSavedLen = *pDstTest; + len = pStrCfg->length; + if (len > maxSavedLen) + continue; + *pDstTest++ = pStrCfg->maxLen; + *pDstTest++ = len; + while (len) { + *pDstTest++ = *pSrcTest++; + len--; + } + } + } + + /* Set status to READY */ + pMac->cfg.gCfgStatus = CFG_SUCCESS; + retVal = WNI_CFG_SUCCESS; + pe_debug(" Completed successfully"); + + pMac->cfg.gParamList[WNI_CFG_DNLD_CNF_RES] = retVal; + +} /*** end ProcessDownloadReq() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_send_msg.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_send_msg.c new file mode 100644 index 0000000000000000000000000000000000000000..2536633ffeb76821a9b4605e2383337d6907e846 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_send_msg.c @@ -0,0 +1,123 @@ +/* + * 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. + */ + +/* + * This file contains the source code for composing and sending messages + * to host. + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ +#include "cds_api.h" +#include "cfg_priv.h" +#include "lim_trace.h" + +/*--------------------------------------------------------------------*/ +/* ATTENTION: The functions contained in this module are to be used */ +/* by CFG module ONLY. */ +/*--------------------------------------------------------------------*/ + +/**--------------------------------------------------------------------- + * cfg_send_host_msg() + * + * FUNCTION: + * Send CNF/RSP to host. + * + * LOGIC: + * Please see Configuration & Statistic Collection Micro-Architecture + * specification for details. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param msgType: message type + * @param msgLen: message length + * @param paramNum: number of parameters + * @param pParamList: pointer to parameter list + * @param dataLen: data length + * @param pData: pointer to additional data + * + * @return None. + * + */ +void +cfg_send_host_msg(tpAniSirGlobal pMac, uint16_t msgType, uint32_t msgLen, + uint32_t paramNum, uint32_t *pParamList, uint32_t dataLen, + uint32_t *pData) +{ + uint32_t *pMsg, *pEnd; + struct scheduler_msg mmhMsg = {0}; + + if ((paramNum > 0) && (NULL == pParamList)) { + pe_err("pParamList NULL when paramNum greater than 0!"); + return; + } + if ((dataLen > 0) && (NULL == pData)) { + pe_err("pData NULL when dataLen greater than 0!"); + return; + } + pMsg = qdf_mem_malloc(msgLen); + if (NULL == pMsg) { + pe_err("Memory allocation failure!"); + return; + } + /* Fill in message details */ + mmhMsg.type = msgType; + mmhMsg.bodyptr = pMsg; + mmhMsg.bodyval = 0; + ((tSirMbMsg *) pMsg)->type = msgType; + ((tSirMbMsg *) pMsg)->msgLen = (uint16_t) msgLen; + + switch (msgType) { + case WNI_CFG_GET_RSP: + case WNI_CFG_PARAM_UPDATE_IND: + case WNI_CFG_DNLD_REQ: + case WNI_CFG_DNLD_CNF: + case WNI_CFG_SET_CNF: + /* Fill in parameters */ + pMsg++; + if (NULL != pParamList) { + pEnd = pMsg + paramNum; + while (pMsg < pEnd) { + *pMsg++ = *pParamList++; + } + } + /* Copy data if there is any */ + if (NULL != pData) { + pEnd = pMsg + (dataLen >> 2); + while (pMsg < pEnd) { + *pMsg++ = *pData++; + } + } + break; + + default: + pe_warn("Unknown msg: %d!", (int)msgType); + qdf_mem_free(pMsg); + return; + } + + /* Ship it */ + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + sys_process_mmh_msg(pMac, &mmhMsg); + +} /*** end cfg_send_host_msg() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.c b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.c new file mode 100644 index 0000000000000000000000000000000000000000..ced3e663fc109583c49e1dda09d2d95a7d30d87c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.c @@ -0,0 +1,421 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_api.h" +#include "sch_api.h" +#include "dph_global.h" +#include "lim_api.h" +#include "wma_if.h" + +/* --------------------------------------------------------------------- */ +/** + * dphHashTableClass() + * + * FUNCTION: + * Constructor function + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void dph_hash_table_class_init(tpAniSirGlobal pMac, + dphHashTableClass *pDphHashTable) +{ + uint16_t i; + + for (i = 0; i < pDphHashTable->size; i++) { + pDphHashTable->pHashTable[i] = 0; + } + + for (i = 0; i < pDphHashTable->size; i++) { + pDphHashTable->pDphNodeArray[i].valid = 0; + pDphHashTable->pDphNodeArray[i].added = 0; + pDphHashTable->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(tpAniSirGlobal pMac, 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(tpAniSirGlobal pMac, uint8_t staAddr[], + uint16_t *pAssocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr = NULL; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + if (!pDphHashTable->pHashTable) { + pe_err("pHashTable is NULL"); + return ptr; + } + + for (ptr = pDphHashTable->pHashTable[index]; ptr; ptr = ptr->next) { + if (dph_compare_mac_addr(staAddr, ptr->staAddr)) { + *pAssocId = ptr->assocId; + break; + } + } + return ptr; +} + +/* --------------------------------------------------------------------- */ +/** + * 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(tpAniSirGlobal pMac, uint16_t peerIdx, + dphHashTableClass *pDphHashTable) +{ + if (peerIdx < pDphHashTable->size) { + if (pDphHashTable->pDphNodeArray[peerIdx].added) + return &pDphHashTable->pDphNodeArray[peerIdx]; + else + return NULL; + } else + return NULL; + +} + +static inline tpDphHashNode get_node(tpAniSirGlobal pMac, uint8_t assocId, + dphHashTableClass *pDphHashTable) +{ + return &pDphHashTable->pDphNodeArray[assocId]; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_lookup_assoc_id + * + * FUNCTION: + * This function looks up assocID given the station Id. It traverses the complete table to do this. + * Need to find an efficient way to do this. + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac pointer to global Mac structure. + * @param staIdx station ID + * @param *assocId pointer to associd to be returned by this function. + * @return pointer to the dph node. + */ +tpDphHashNode dph_lookup_assoc_id(tpAniSirGlobal pMac, uint16_t staIdx, + uint16_t *assocId, + dphHashTableClass *pDphHashTable) +{ + uint8_t i; + + for (i = 0; i < pDphHashTable->size; i++) { + if ((pDphHashTable->pDphNodeArray[i].added) && + (pDphHashTable->pDphNodeArray[i].staIndex == staIdx)) { + *assocId = i; + break; + } + + } + if (i == pDphHashTable->size) + return NULL; + return &pDphHashTable->pDphNodeArray[i]; + +} + +/** ------------------------------------------------------------- + \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 tpAniSirGlobal pMac + \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(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, uint8_t validStaIdx, + dphHashTableClass *pDphHashTable) +{ + uint32_t val; + + tpDphHashNode pStaDs, pnext; + uint16_t staIdx = STA_INVALID_IDX; + + if (assocId >= pDphHashTable->size) { + pe_err("Invalid Assoc Id %d", assocId); + return NULL; + } + + pStaDs = get_node(pMac, (uint8_t) assocId, pDphHashTable); + staIdx = pStaDs->staIndex; + pnext = pStaDs->next; + + /* Clear the STA node except for the next pointer */ + qdf_mem_zero((uint8_t *)pStaDs, sizeof(tDphHashNode)); + pStaDs->next = pnext; + + /* Initialize the assocId */ + pStaDs->assocId = assocId; + if (true == validStaIdx) + pStaDs->staIndex = staIdx; + else + pStaDs->staIndex = STA_INVALID_IDX; + + /* Initialize STA mac address */ + qdf_mem_copy(pStaDs->staAddr, staAddr, sizeof(tSirMacAddr)); + + /* Initialize fragmentation threshold */ + if (wlan_cfg_get_int(pMac, WNI_CFG_FRAGMENTATION_THRESHOLD, &val) != + QDF_STATUS_SUCCESS) + pe_warn("could not retrieve fragmentation threshold"); + else + pStaDs->fragSize = (uint16_t) val; + + pStaDs->added = 1; + pStaDs->encPolicy = ENC_POLICY_NULL; + pStaDs->is_disassoc_deauth_in_progress = 0; + pStaDs->last_assoc_received_time = 0; + pStaDs->last_disassoc_deauth_received_time = 0; + pStaDs->sta_deletion_in_progress = false; + pStaDs->valid = 1; + return pStaDs; +} + +/* --------------------------------------------------------------------- */ +/** + * 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(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr, node; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + pe_debug("assocId %d index %d STA addr", + assocId, index); + pe_debug(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(staAddr)); + + if (assocId >= pDphHashTable->size) { + pe_err("invalid STA id %d", assocId); + return NULL; + } + + if (pDphHashTable->pDphNodeArray[assocId].added) { + pe_err("already added STA %d", assocId); + return NULL; + } + + for (ptr = pDphHashTable->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 + (pMac, staAddr, assocId, false, pDphHashTable) == NULL) { + pe_err("could not Init STA id: %d", assocId); + return NULL; + } + /* Add the node to the link list */ + pDphHashTable->pDphNodeArray[assocId].next = + pDphHashTable->pHashTable[index]; + pDphHashTable->pHashTable[index] = + &pDphHashTable->pDphNodeArray[assocId]; + + node = pDphHashTable->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(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr, prev; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + pe_debug("assocId %d index %d STA addr", assocId, index); + pe_debug(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(staAddr)); + + if (assocId >= pDphHashTable->size) { + pe_err("invalid STA id %d", assocId); + return QDF_STATUS_E_FAILURE; + } + + if (pDphHashTable->pDphNodeArray[assocId].added == 0) { + pe_err("STA %d never added", assocId); + return QDF_STATUS_E_FAILURE; + } + + for (prev = 0, ptr = pDphHashTable->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) + pDphHashTable->pHashTable[index] = ptr->next; + else + prev->next = ptr->next; + ptr->added = 0; + ptr->is_disassoc_deauth_in_progress = 0; + ptr->last_assoc_received_time = 0; + ptr->last_disassoc_deauth_received_time = 0; + ptr->sta_deletion_in_progress = false; + ptr->next = 0; + } else { + pe_err("Entry not present STA addr"); + pe_err(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(staAddr)); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.h b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.h new file mode 100644 index 0000000000000000000000000000000000000000..83c6d49a63ecb16e37bfe35981e0f8a67ae556f1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011-2015, 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. + */ + +/* + * + * 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]); +} + +/* Hash table class */ +typedef struct { + + /* The hash table itself */ + tpDphHashNode *pHashTable; + + /* The state array */ + tDphHashNode *pDphNodeArray; + uint16_t size; +} dphHashTableClass; + +/* The hash table object */ +extern dphHashTableClass dphHashTable; + +tpDphHashNode dph_lookup_hash_entry(tpAniSirGlobal pMac, uint8_t staAddr[], + uint16_t *pStaId, + dphHashTableClass *pDphHashTable); +tpDphHashNode dph_lookup_assoc_id(tpAniSirGlobal pMac, uint16_t staIdx, + uint16_t *assocId, + dphHashTableClass *pDphHashTable); + +/* Get a pointer to the hash node */ +extern tpDphHashNode dph_get_hash_entry(tpAniSirGlobal pMac, uint16_t staId, + dphHashTableClass *pDphHashTable); + +/* Add an entry to the hash table */ +extern tpDphHashNode dph_add_hash_entry(tpAniSirGlobal pMac, + tSirMacAddr staAddr, + uint16_t staId, + dphHashTableClass *pDphHashTable); + +/* Delete an entry from the hash table */ +QDF_STATUS dph_delete_hash_entry(tpAniSirGlobal pMac, + tSirMacAddr staAddr, uint16_t staId, + dphHashTableClass *pDphHashTable); + +void dph_hash_table_class_init(tpAniSirGlobal pMac, + dphHashTableClass *pDphHashTable); +/* Initialize STA state */ +extern tpDphHashNode dph_init_sta_state(tpAniSirGlobal pMac, + tSirMacAddr staAddr, + uint16_t staId, uint8_t validStaIdx, + dphHashTableClass *pDphHashTable); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_api.h b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..ee5b7aa3f2e2b0c63523b99e7db4f8e4d219a5b1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_api.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +/* + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGAPI_H +#define __CFGAPI_H + +#include +#include +#include +#include +#include + +/*---------------------------------------------------------------------*/ +/* CFG definitions */ +/*---------------------------------------------------------------------*/ + +/* CFG status */ +typedef enum eCfgStatusTypes { + CFG_INCOMPLETE, + CFG_SUCCESS, + CFG_FAILURE +} tCfgStatusTypes; + +/* WEP key mapping table row structure */ +typedef struct { + uint8_t keyMappingAddr[QDF_MAC_ADDR_SIZE]; + uint32_t wepOn; + uint8_t key[SIR_MAC_KEY_LENGTH]; + uint32_t status; +} tCfgWepKeyEntry; + +/*---------------------------------------------------------------------*/ +/* CFG function prototypes */ +/*---------------------------------------------------------------------*/ + +uint32_t cfg_need_restart(tpAniSirGlobal pMac, uint16_t cfgId); +uint32_t cfg_need_reload(tpAniSirGlobal pMac, uint16_t cfgId); + +/* / Process host message */ +void cfg_process_mb_msg(tpAniSirGlobal, tSirMbMsg *); + +/* / Set integer parameter value */ +QDF_STATUS cfg_set_int(tpAniSirGlobal, uint16_t, uint32_t); + +/* / Check if the parameter is valid */ +QDF_STATUS cfg_check_valid(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get integer parameter value */ +QDF_STATUS wlan_cfg_get_int(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Set string parameter value */ +QDF_STATUS cfg_set_str(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t); + +QDF_STATUS cfg_set_str_notify(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t, + int); + +/* Cfg Download function for Prima or Integrated solutions. */ +void process_cfg_download_req(tpAniSirGlobal); + +/* / Get string parameter value */ +QDF_STATUS wlan_cfg_get_str(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t *); + +/* / Get string parameter maximum length */ +QDF_STATUS wlan_cfg_get_str_max_len(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get string parameter maximum length */ +QDF_STATUS wlan_cfg_get_str_len(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get the regulatory tx power on given channel */ +int8_t cfg_get_regulatory_max_transmit_power(tpAniSirGlobal pMac, + uint8_t channel); + +/* / Get capability info */ +QDF_STATUS cfg_get_capability_info(tpAniSirGlobal pMac, uint16_t *pCap, + tpPESession psessionEntry); + +/* / Set capability info */ +void cfg_set_capability_info(tpAniSirGlobal, uint16_t); + +/* / Cleanup CFG module */ +void cfg_cleanup(tpAniSirGlobal pMac); + +const char *cfg_get_string(uint16_t cfg_id); + +#endif /* __CFGAPI_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_global.h b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_global.h new file mode 100644 index 0000000000000000000000000000000000000000..ebc4f17c0b2fe53249401219eced0747b8cb7037 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_global.h @@ -0,0 +1,86 @@ +/* + * 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. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/09/03 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGGLOBAL_H +#define __CFGGLOBAL_H + +#include "sir_common.h" +#include "sir_types.h" +#include "wni_cfg.h" + +#define CFG_MAX_NUM_STA SIR_MAX_NUM_STA_IN_IBSS + +#define CFG_MAX_STATIC_STRING 70 +/* as the number of channels grows, 128 is not big enough */ +#define CFG_MAX_STR_LEN 256 + +/*--------------------------------------------------------------------*/ +/* Configuration Control Structure */ +/*--------------------------------------------------------------------*/ +typedef struct { + uint32_t control; +} tCfgCtl; + + +typedef struct sAniSirCfgStaticString { + uint16_t cfgId; + uint8_t maxLen; + uint8_t length; + uint8_t data[255]; +} cfgstatic_string; + +typedef struct sAniSirCfgStatic { + uint16_t cfgId; + uint32_t control; + uint32_t cfgIMin; + uint32_t cfgIMax; + uint32_t cfgIVal; + void *pStrData; +} cgstatic; + +typedef struct sAniSirCfg { + /* CFG module status */ + uint8_t gCfgStatus; + uint16_t gCfgMaxIBufSize; + uint16_t gCfgMaxSBufSize; + + tCfgCtl *gCfgEntry; + + uint8_t *gCfgSBuf; + uint32_t *gCfgIBuf; + uint32_t *gCfgIBufMin; + uint32_t *gCfgIBufMax; + + /* Static buffer for string parameter (must be word-aligned) */ + uint8_t *gSBuffer; + + /* Message param list buffer (enough for largest possible response) */ + uint32_t *gParamList; +} tAniSirCfg, *tpAniSirCfg; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/dot11f.h b/drivers/staging/qcacld-3.0/core/mac/src/include/dot11f.h new file mode 100644 index 0000000000000000000000000000000000000000..44a516e977f597d95ccacca5f40285240b78a8d0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/dot11f.h @@ -0,0 +1,11217 @@ +/* + * 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 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' + * Mon Mar 25 14:48:07 2019 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 pbcc: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_PBCC_OFFSET 6 +#define CAPABILITIES_PBCC_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 *); + + +/********************************************************************* + * 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 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 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 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 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 1 (0x01) */ +typedef struct sDot11fIEBeaconReporting { + uint8_t present; + uint8_t reportingCondition; + uint8_t threshold; +} tDot11fIEBeaconReporting; + +#define DOT11F_EID_BEACONREPORTING (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BEACONREPORTING_MIN_LEN (2) + +#define DOT11F_IE_BEACONREPORTING_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_beacon_reporting( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBeaconReporting*, + bool); + +uint32_t dot11f_pack_ie_beacon_reporting( + tpAniSirGlobal, + tDot11fIEBeaconReporting *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BeaconReporting( + tpAniSirGlobal, + tDot11fIEBeaconReporting *, + 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 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 reserved1:2; + uint16_t rxMCSMap; + uint16_t rxHighSupDataRate:13; + uint16_t reserved2:3; + uint16_t txMCSMap; + uint16_t txSupDataRate:13; + uint16_t reserved3:3; +} 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 chanCenterFreqSeg1; + uint8_t chanCenterFreqSeg2; + 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 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 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 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 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 sDot11fIEvht_transmit_power_env { + uint8_t present; + uint8_t num_bytes; + uint8_t bytes[5]; +} tDot11fIEvht_transmit_power_env; + +#define DOT11F_EID_VHT_TRANSMIT_POWER_ENV (195) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHT_TRANSMIT_POWER_ENV_MIN_LEN (2) + +#define DOT11F_IE_VHT_TRANSMIT_POWER_ENV_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_vht_transmit_power_env( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEvht_transmit_power_env*, + bool); + +uint32_t dot11f_pack_ie_vht_transmit_power_env( + tpAniSirGlobal, + tDot11fIEvht_transmit_power_env *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_vht_transmit_power_env( + tpAniSirGlobal, + tDot11fIEvht_transmit_power_env *, + 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; + tDot11fIEvht_transmit_power_env vht_transmit_power_env; +} 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 (12) + +#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 num_triplets; + uint8_t triplets[84][3]; +} tDot11fIECountry; + +#define DOT11F_EID_COUNTRY (7) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_COUNTRY_MIN_LEN (3) + +#define DOT11F_IE_COUNTRY_MAX_LEN (255) + +#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 reserved:11; + 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 6 (0x06) */ +typedef struct sDot11fIEIBSSParams { + uint8_t present; + uint16_t atim; +} tDot11fIEIBSSParams; + +#define DOT11F_EID_IBSSPARAMS (6) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_IBSSPARAMS_MIN_LEN (2) + +#define DOT11F_IE_IBSSPARAMS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ibss_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEIBSSParams*, + bool); + +uint32_t dot11f_pack_ie_ibss_params( + tpAniSirGlobal, + tDot11fIEIBSSParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_IBSSParams( + tpAniSirGlobal, + tDot11fIEIBSSParams *, + 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 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 */ + } 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 (29) + +#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 regClass; + uint8_t channel; + uint16_t randomization; + uint16_t meas_duration; + uint8_t meas_mode; + uint8_t BSSID[6]; + tDot11fIESSID SSID; + tDot11fIEBeaconReporting BeaconReporting; + tDot11fIEBcnReportingDetail BcnReportingDetail; + tDot11fIERequestedInfo RequestedInfo; + 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 */ + } 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 reserved:2; + 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 0x8c, 0xfd, 0xf0, 0x01} */ +typedef struct sDot11fIEQCN_IE { + uint8_t present; + uint8_t version[4]; +} 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 (8) + +#define DOT11F_IE_QCN_IE_MAX_LEN (8) + +#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 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[60]; +} tDot11fIEQosMapSet; + +#define DOT11F_EID_QOSMAPSET (110) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSMAPSET_MIN_LEN (0) + +#define DOT11F_IE_QOSMAPSET_MAX_LEN (60) + +#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:5; +} 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 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 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 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:3; + uint32_t min_frag_size:2; + uint32_t trigger_frm_mac_pad:2; + uint32_t multi_tid_aggr:3; + uint32_t he_link_adaptation:2; + uint32_t all_ack:1; + uint32_t ul_mu_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 dl_mu_ba:1; + uint32_t omi_a_ctrl:1; + uint32_t ofdma_ra:1; + uint32_t max_ampdu_len:2; + uint32_t amsdu_frag:1; + uint32_t flex_twt_sched:1; + uint32_t rx_ctrl_frame:1; + uint8_t bsrp_ampdu_aggr:1; + uint8_t qtp:1; + uint8_t a_bqr:1; + uint8_t sr_responder:1; + uint8_t ndp_feedback_supp:1; + uint8_t ops_supp:1; + uint8_t amsdu_in_ampdu:1; + uint8_t reserved1:1; + uint32_t dual_band: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_rx_max_nsts:2; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t 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 tx_stbc_gt_80mhz:1; + uint32_t rx_stbc_gt_80mhz:1; + uint8_t er_he_ltf_800_gi_4x:1; + uint8_t he_ppdu_20_in_40Mhz_2G:1; + uint8_t he_ppdu_20_in_160_80p80Mhz:1; + uint8_t he_ppdu_80_in_160_80p80Mhz:1; + uint8_t er_1x_he_ltf_gi:1; + uint8_t midamble_rx_1x_he_ltf:1; + uint8_t reserved2:2; + 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 (18) + +#define DOT11F_IE_HE_CAP_MAX_LEN (51) + +#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; + uint32_t bss_color:6; + uint32_t default_pe:3; + uint32_t twt_required:1; + uint32_t rts_threshold:10; + uint32_t partial_bss_col:1; + uint32_t vht_oper_present:1; + uint32_t reserved1:6; + uint32_t mbssid_ap:1; + uint32_t tx_bssid_ind:1; + uint32_t bss_col_disabled:1; + uint32_t reserved2: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; /* mbssid_ap = 1 */ + } maxbssid_ind; +} 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 (10) + +#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 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 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 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 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; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEPowerCaps PowerCaps; + tDot11fIESuppChannels SuppChannels; + tDot11fIEHTCaps HTCaps; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEfils_session fils_session; + tDot11fIEfils_public_key fils_public_key; + tDot11fIEfils_key_confirmation fils_key_confirmation; + tDot11fIEfils_hlp_container fils_hlp_container; + tDot11fIEfragment_ie fragment_ie; + tDot11fIEdh_parameter_element dh_parameter_element; + 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; + tDot11fIEhe_cap he_cap; + 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; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEWPA WPA; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEWscAssocRes WscAssocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEfils_session fils_session; + tDot11fIEfils_public_key fils_public_key; + tDot11fIEfils_key_confirmation fils_key_confirmation; + tDot11fIEfils_hlp_container fils_hlp_container; + tDot11fIEfragment_ie fragment_ie; + tDot11fIEfils_kde fils_kde; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEQCN_IE QCN_IE; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEMBO_IE MBO_IE; +} 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; +} 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; + tDot11fIEIBSSParams IBSSParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEfils_indication fils_indication; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEQCN_IE QCN_IE; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEesp_information esp_information; +} 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; + tDot11fIEIBSSParams IBSSParams; +} 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; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEfils_indication fils_indication; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; + tDot11fIEQCN_IE QCN_IE; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEesp_information esp_information; +} 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; + tDot11fIEIBSSParams IBSSParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscBeaconProbeRes WscBeaconProbeRes; + tDot11fIEP2PBeaconProbeRes P2PBeaconProbeRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEfils_indication fils_indication; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEQCN_IE QCN_IE; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEesp_information esp_information; +} 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; + tDot11fIEWscProbeReq WscProbeReq; + tDot11fIEWFATPC WFATPC; + tDot11fIEP2PProbeReq P2PProbeReq; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEQCN_IE QCN_IE; + tDot11fIEhe_cap he_cap; +} 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; + tDot11fIEIBSSParams IBSSParams; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscProbeRes WscProbeRes; + tDot11fIEP2PProbeRes P2PProbeRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEfils_indication fils_indication; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEQCN_IE QCN_IE; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEesp_information esp_information; +} 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[4]; +} 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[2]; +} 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]; + tDot11fIEWPAOpaque WPAOpaque; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEWscIEOpaque WscIEOpaque; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESECckmOpaque ESECckmOpaque; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEP2PIEOpaque P2PIEOpaque; + tDot11fIEWFDIEOpaque WFDIEOpaque; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEhe_cap he_cap; +} 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]; + tDot11fIEWPA WPA; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEWMMParams WMMParams; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEWscReassocRes WscReassocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEMBO_IE MBO_IE; +} 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; +} 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; +} 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; +} 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; +} 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; +} 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; +} 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 sDot11fext_channel_switch_action_frame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfext_chan_switch_ann_action ext_chan_switch_ann_action; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; +} tDot11fext_channel_switch_action_frame; + +#define DOT11F_EXT_CHANNEL_SWITCH_ACTION_FRAME (49) + +#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 (50) + +#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 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 (51) + +#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++ */ + +#endif /* DOT11F_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/dph_global.h b/drivers/staging/qcacld-3.0/core/mac/src/include/dph_global.h new file mode 100644 index 0000000000000000000000000000000000000000..ea1ed1c8cb47d68227ff7e0efd440fd91507ae0d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/dph_global.h @@ -0,0 +1,275 @@ +/* + * 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. + */ + +/* + + * + + * 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_mac_prop_exts.h" +#include "sir_api.h" + +/* Following determines whether statistics are maintained or not */ +#define DPH_STATS + +/* STAID for Management frames */ +#define DPH_USE_MGMT_STAID -1 + +/* Keep Alive frames */ +#define DPH_NON_KEEPALIVE_FRAME 0 +#define DPH_KEEPALIVE_FRAME 1 + +/* DPH Hash Index for BSS(STA's Peer) on station. */ +#define DPH_STA_HASH_INDEX_PEER 1 + +#ifdef WLAN_FEATURE_11W +/* 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 +#endif + +typedef struct sDphRateBasedCtr { + uint32_t hi; + uint32_t lo; +} tDphRateBasedCtr; + +typedef struct sDphPhyRates { + uint8_t dataRateX2; + uint8_t ackRateX2; + uint8_t rtsRateX2; +} tDphPhyRates; + +typedef struct sDphIFSValues { + uint8_t sifs; + uint8_t pifs; + uint8_t difs; + uint8_t preamble; +} tDphIFSValues; + +typedef struct sDphQosParams { + uint8_t addtsPresent; + tSirAddtsReqInfo addts; + tSirMacQosCapabilityStaIE capability; +} tDphQosParams; + +/* Queue attribute structure */ +typedef struct sDphQueueAttr { + uint16_t valid:1; + uint16_t seqNum:12; + uint16_t ackPolicy:2; + uint16_t rsvd:1; +} tDphQueueAttr, *tpDphQueueAttr; + +/** + * 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 + * + * 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; +}; + +/* STA state node */ +typedef struct sDphHashNode { + /* + * BYTE 0 + * HASH ENTRY FIELDS NOT NEEDED IN HAL. + * This STA valid or not + */ + uint8_t valid:1; + uint8_t encPolicy:3; + uint8_t defaultKey:1; + uint8_t defaultKeyId:2; + uint8_t qosMode:1; + /* BYTE 1 */ + uint8_t erpEnabled:1; + /* This has been added to the dph hash table */ + uint8_t added:1; + uint8_t linkTestOn:1; + uint8_t shortPreambleEnabled:1; + uint8_t shortSlotTimeEnabled:1; + uint8_t stopTx: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; + /* BYTE 2 */ + /* set if both ap and sta are wsm capable */ + uint8_t wsmEnabled:1; + /* station gave version info */ + uint8_t versionPresent:1; + /* allow bursting regardless of qosMode */ + uint8_t burstEnableForce:1; + uint8_t staAuthenticated:1; + uint8_t fAniCount:1; + uint8_t rmfEnabled:1; + /* Number of Tim to wait if the STA doesn't respond / fetch data */ + uint8_t timWaitCount; + /* Fragmentation size */ + uint16_t fragSize; + /* Taurus capabilities */ + uint16_t baPolicyFlag; /* BA Policy for each TID. */ + /* LIM state */ + tLimMlmStaContext mlmStaContext; + /* number of consecutive TIMs sent without response */ + uint8_t numTimSent; + /* Number of Successful MPDU's being sent */ + uint32_t curTxMpduCnt; + /* qos parameter info */ + tDphQosParams qos; + /* station version info - valid only if versionPresent is set */ + tSirMacPropVersion version; +#ifdef PLM_WDS + uint8_t wdsIndex; + uint8_t wdsPeerBeaconSeen; +#endif + /* + * All the legacy and airgo supported rates. + */ + tSirSupportedRates 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; + uint8_t rsvd1:2; + /* DPH HASH ENTRY FIELDS NEEDED IN HAL ONLY */ + uint8_t dpuSig:4; /* DPU signiture */ + uint8_t staSig:4; /* STA signature */ + uint16_t bssId; /* BSSID */ + uint16_t assocId; /* Association ID */ + /* This is the real sta index generated by HAL */ + uint16_t staIndex; + uint8_t staAddr[6]; + uint8_t staType; + + uint8_t vhtSupportedChannelWidthSet; + uint8_t vhtSupportedRxNss; + uint8_t vhtBeamFormerCapable; + uint8_t vht_su_bfee_capable; +#ifdef WLAN_FEATURE_11W + TX_TIMER pmfSaQueryTimer; + uint16_t pmfSaQueryCurrentTransId; + uint16_t pmfSaQueryStartTransId; + uint8_t pmfSaQueryState; + uint8_t pmfSaQueryRetryCount; + uint8_t proct_deauh_disassoc_cnt; +#endif + 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; + qdf_time_t last_assoc_received_time; + qdf_time_t last_disassoc_deauth_received_time; + + 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; + +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_config; +#endif + + /* + * 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; +} tDphHashNode, *tpDphHashNode; + +#include "dph_hash_table.h" + +/* ------------------------------------------------------------------- */ +typedef struct sAniSirDph { + /* The hash table object */ + dphHashTableClass dphHashTable; +} tAniSirDph, *tpAniSirDph; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/parser_api.h b/drivers/staging/qcacld-3.0/core/mac/src/include/parser_api.h new file mode 100644 index 0000000000000000000000000000000000000000..4a4af2c31fc23abeabfe2d2cefdad6f37d2c9230 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/parser_api.h @@ -0,0 +1,1268 @@ +/* + * 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. + */ + +/* + * 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 +#include "sir_mac_prop_exts.h" +#include "dot11f.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#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 MBO_IE_ASSOC_DISALLOWED_SUBATTR_ID 0x04 + +/* 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 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 + +#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 */ + +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; + +typedef struct sSirQCNIE { + bool is_present; + uint8_t version; + uint8_t sub_version; +} tSirQCNIE, *tpSirQCNIE; + +#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 + +/* Structure common to Beacons & Probe Responses */ +typedef struct sSirProbeRespBeacon { + tSirMacTimeStamp timeStamp; + uint16_t beaconInterval; + tSirMacCapabilityInfo capabilityInfo; + + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirMacChanNum channelNumber; + tSirMacCfParamSet cfParamSet; + tSirMacTim tim; + tSirMacEdcaParamSetIE edcaParams; + tSirMacQosCapabilityIE qosCapability; + + tSirCountryInformation countryInfoParam; + tSirMacWpaInfo wpa; + tSirMacRsnInfo rsn; + + tSirMacErpInfo erpIEInfo; + + tSirPropIEStruct propIEinfo; + 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; + tDot11fIEIBSSParams IBSSParams; +#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; + tSirQCNIE QCN_IE; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_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 +} 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; + + tSirPropIEStruct propIEinfo; + tSirMacPowerCapabilityIE powerCapability; + tSirMacSupportedChannelIE supportedChannels; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + /* / 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 */ + uint32_t assocReqFrameLength; + uint8_t *assocReqFrame; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode operMode; + tDot11fIEExtCap ExtCap; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEhe_cap he_cap; +} tSirAssocReq, *tpSirAssocReq; + +/* / Association Response structure (one day to be replaced by */ +/* / tDot11fAssocRequest) */ +typedef struct sSirAssocRsp { + + tSirMacCapabilityInfo capabilityInfo; + uint16_t aid; + uint16_t statusCode; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirPropIEStruct propIEinfo; + tSirMacEdcaParamSetIE edca; + tSirAddtsRspInfo addtsRsp; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEFTInfo FTInfo; + uint8_t mdie[SIR_MDIE_SIZE]; + uint8_t num_RICData; + tDot11fIERICDataDesc RICData[2]; + +#ifdef FEATURE_WLAN_ESE + uint8_t num_tspecs; + tDot11fIEWMMTSPEC TSPECInfo[SIR_ESE_MAX_TSPEC_IES]; + tSirMacESETSMIE 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; + tSirQosMapSet QosMapSet; +#ifdef WLAN_FEATURE_11W + tDot11fIETimeoutInterval TimeoutInterval; +#endif + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEOBSSScanParameters obss_scanparams; + tDot11fTLVrssi_assoc_rej rssi_assoc_rej; + tSirQCNIE QCN_IE; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + bool mu_edca_present; + tSirMacEdcaParamSetIE mu_edca; +#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 +} 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; + tSirMacIBSSParams ibssParamSet; + tSirMacTim tim; + tSirMacRRMEnabledCap rmEnabledCapabilities; + + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t fhParamPresent; + uint8_t dsParamsPresent; + uint8_t cfPresent; + uint8_t ibssParamPresent; + 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 sirIsPropCapabilityEnabled(struct sAniSirGlobal *pMac, uint32_t bitnum); + +#define CFG_GET_INT(nStatus, pMac, nItem, cfg) do { \ + (nStatus) = wlan_cfg_get_int((pMac), (nItem), &(cfg)); \ + if (QDF_STATUS_SUCCESS != (nStatus)) { \ + pe_err("Failed to retrieve nItem from CFG status: %d", (nStatus)); \ + return nStatus; \ + } \ +} while (0) + +#define CFG_GET_INT_NO_STATUS(nStatus, pMac, nItem, cfg) do { \ + (nStatus) = wlan_cfg_get_int((pMac), (nItem), &(cfg)); \ + if (QDF_STATUS_SUCCESS != (nStatus)) { \ + pe_err("Failed to retrieve nItem from CFG status: %d", (nStatus)); \ + return; \ + } \ +} while (0) + +#define CFG_GET_STR(nStatus, pMac, nItem, cfg, nCfg, nMaxCfg) do { \ + (nCfg) = (nMaxCfg); \ + (nStatus) = wlan_cfg_get_str((pMac), (nItem), (cfg), &(nCfg)); \ + if (QDF_STATUS_SUCCESS != (nStatus)) { \ + pe_err("Failed to retrieve nItem from CFG status: %d", (nStatus)); \ + return nStatus; \ + } \ +} while (0) + +#define CFG_GET_STR_NO_STATUS(nStatus, pMac, nItem, cfg, nCfg, nMaxCfg) do { \ + (nCfg) = (nMaxCfg); \ + (nStatus) = wlan_cfg_get_str((pMac), (nItem), (cfg), &(nCfg)); \ + if (QDF_STATUS_SUCCESS != (nStatus)) { \ + pe_err("Failed to retrieve nItem from CFG status: %d", (nStatus)); \ + return; \ + } \ +} while (0) + +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 sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirProbeReq probe); + +QDF_STATUS +sir_convert_probe_frame2_struct(struct sAniSirGlobal *pMac, uint8_t *frame, + uint32_t len, tpSirProbeRespBeacon probe); + +QDF_STATUS +sir_convert_assoc_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); + +QDF_STATUS +sir_convert_assoc_resp_frame2_struct(struct sAniSirGlobal *pMac, + tpPESession session_entry, + uint8_t *frame, uint32_t len, + tpSirAssocRsp assoc); + +QDF_STATUS +sir_convert_reassoc_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); + +QDF_STATUS +sir_parse_beacon_ie(struct sAniSirGlobal *pMac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t payloadLength); + +QDF_STATUS +sir_convert_beacon_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *pBeaconFrame, + tpSirProbeRespBeacon pBeaconStruct); + +QDF_STATUS +sir_convert_auth_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirMacAuthFrameBody auth); + +QDF_STATUS +sir_convert_addts_req2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirAddtsReqInfo *addTs); + +QDF_STATUS +sir_convert_addts_rsp2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirAddtsRspInfo *addts); + +QDF_STATUS +sir_convert_delts_req2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirDeltsReqInfo *delTs); +QDF_STATUS +sir_convert_qos_map_configure_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, uint32_t nFrame, + tSirQosMapSet *pQosMapSet); + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +sir_convert_tpc_req_frame2_struct(struct sAniSirGlobal *, uint8_t *, + tpSirMacTpcReqActionFrame, uint32_t); + +QDF_STATUS +sir_convert_meas_req_frame2_struct(struct sAniSirGlobal *, uint8_t *, + tpSirMacMeasReqActionFrame, uint32_t); +#endif + +/** + * \brief Populated a tDot11fFfCapabilities + * + * \sa PopulatedDot11fCapabilities2 + * + * + * \param pMac 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(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + tpPESession psessionEntry); + +/** + * \brief Populated a tDot11fFfCapabilities + * + * \sa PopulatedDot11fCapabilities2 + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param pDot11f Address of a tDot11fFfCapabilities to be filled in + * + * \param pSta Pointer to a tDphHashNode representing a peer + * + * + * \note If SIR_MAC_PROP_CAPABILITY_11EQOS is enabled on our peer, we'll + * clear the QOS bit in pDot11f + * + * + */ + +struct sDphHashNode; + +QDF_STATUS +populate_dot11f_capabilities2(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + struct sDphHashNode *pSta, + tpPESession psessionEntry); + +/* / Populate a tDot11fIEChanSwitchAnn */ +void +populate_dot11f_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEChanSwitchAnn *pDot11f, + tpPESession psessionEntry); + +void +populate_dot_11_f_ext_chann_switch_ann(tpAniSirGlobal mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + tpPESession session_entry); + +/* / Populate a tDot11fIEChannelSwitchWrapper */ +void +populate_dot11f_chan_switch_wrapper(tpAniSirGlobal pMac, + tDot11fIEChannelSwitchWrapper *pDot11f, + tpPESession psessionEntry); + +/* / Populate a tDot11fIECountry */ +QDF_STATUS +populate_dot11f_country(tpAniSirGlobal pMac, + tDot11fIECountry *pDot11f, tpPESession psessionEntry); + +/* Populated a populate_dot11f_ds_params */ +QDF_STATUS +populate_dot11f_ds_params(tpAniSirGlobal pMac, + tDot11fIEDSParams *pDot11f, uint8_t channel); + +/* / Populated a tDot11fIEEDCAParamSet */ +void +populate_dot11f_edca_param_set(tpAniSirGlobal pMac, + tDot11fIEEDCAParamSet *pDot11f, + tpPESession psessionEntry); + +QDF_STATUS +populate_dot11f_erp_info(tpAniSirGlobal pMac, + tDot11fIEERPInfo *pDot11f, tpPESession psessionEntry); + +QDF_STATUS +populate_dot11f_ext_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, tDot11fIEExtSuppRates *pDot11f, + tpPESession psessionEntry); + +/** + * populate_dot11f_beacon_report() - Populate the Beacon Report IE + * @pMac: Pointer to the global MAC context + * @pDot11f: Pointer to the measurement report structure + * @pBeaconReport: Pointer to the Beacon Report structure + * @last_beacon_report_params: Last Beacon Report indication params + * + * Return: Ret Status + */ +QDF_STATUS +populate_dot11f_beacon_report(tpAniSirGlobal pMac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport, + struct rrm_beacon_report_last_beacon_params + *last_beacon_report_params); + +/** + * \brief Populate a tDot11fIEExtSuppRates + * + * + * \param pMac 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(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f); + +QDF_STATUS +populate_dot11f_ht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEHTCaps *pDot11f); + +QDF_STATUS +populate_dot11f_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pDot11f, tpPESession psessionEntry); + +void populate_dot11f_ibss_params(tpAniSirGlobal pMac, + tDot11fIEIBSSParams *pDot11f, + tpPESession psessionEntry); + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +populate_dot11f_measurement_report0(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is CCA */ +QDF_STATUS +populate_dot11f_measurement_report1(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is RPI Hist */ +QDF_STATUS +populate_dot11f_measurement_report2(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); +#endif /* ANI_SUPPORT_11H */ + +/* / Populate a tDot11fIEPowerCaps */ +void +populate_dot11f_power_caps(tpAniSirGlobal pMac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, tpPESession psessionEntry); + +/* / Populate a tDot11fIEPowerConstraints */ +QDF_STATUS +populate_dot11f_power_constraints(tpAniSirGlobal pMac, + tDot11fIEPowerConstraints *pDot11f); + +void +populate_dot11f_qos_caps_ap(tpAniSirGlobal pMac, + tDot11fIEQOSCapsAp *pDot11f, + tpPESession psessionEntry); + +void +populate_dot11f_qos_caps_station(tpAniSirGlobal pMac, tpPESession session, + tDot11fIEQOSCapsStation *pDot11f); + +QDF_STATUS +populate_dot11f_rsn(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f); + +QDF_STATUS +populate_dot11f_rsn_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSNOpaque *pDot11f); + +#if defined(FEATURE_WLAN_WAPI) + +QDF_STATUS +populate_dot11f_wapi(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f); + +QDF_STATUS populate_dot11f_wapi_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f); + +#endif /* defined(FEATURE_WLAN_WAPI) */ + +/* / Populate a tDot11fIESSID given a tSirMacSSid */ +void +populate_dot11f_ssid(tpAniSirGlobal pMac, + tSirMacSSid *pInternal, tDot11fIESSID *pDot11f); + +/* / Populate a tDot11fIESSID from CFG */ +QDF_STATUS populate_dot11f_ssid2(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, tpPESession psessionEntry); + +/** + * \brief Populated a tDot11fIESuppRates + * + * + * \param pMac 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(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, tpPESession); + +QDF_STATUS +populate_dot11f_rates_tdls(tpAniSirGlobal p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates, + uint8_t curr_oper_channel); + +QDF_STATUS populate_dot11f_tpc_report(tpAniSirGlobal pMac, + tDot11fIETPCReport *pDot11f, + tpPESession psessionEntry); + +/* / Populate a tDot11FfTSInfo */ +void populate_dot11f_ts_info(tSirMacTSInfo *pInfo, tDot11fFfTSInfo *pDot11f); + +void populate_dot11f_wmm(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, tpPESession psessionEntry); + +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(tpAniSirGlobal pMac, + tpSirCCKMie pCCKMie, + tDot11fIEESECckmOpaque *pDot11f); + +void populate_dot11_tsrsie(tpAniSirGlobal pMac, + tSirMacESETSRSIE *pOld, + tDot11fIEESETrafStrmRateSet *pDot11f, + uint8_t rate_length); +void populate_dot11f_re_assoc_tspec(tpAniSirGlobal pMac, + tDot11fReAssocRequest *pReassoc, + tpPESession psessionEntry); +QDF_STATUS +sir_beacon_ie_ese_bcn_report(tpAniSirGlobal pMac, + 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(tSirMacTspecIE *source, ese_wmm_tspec_ie *dest); + +#endif + +void populate_dot11f_wmm_info_ap(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tpPESession psessionEntry); + +void populate_dot11f_wmm_info_station_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEWMMInfoStation *pInfo); + +void populate_dot11f_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pParams, + tpPESession psessionEntry); + +/** + * \brief Populate a tDot11fIEWMMSchedule + * + * \sa PopulatedDot11fSchedule + * + * + * \param pSchedule Address of a tSirMacScheduleIE struct + * + * \param pDot11f Address of a tDot11fIEWMMSchedule to be filled in + * + * + */ + +void +populate_dot11f_wmm_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIEWMMSchedule *pDot11f); + +QDF_STATUS +populate_dot11f_wpa(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f); + +QDF_STATUS +populate_dot11f_wpa_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPAOpaque *pDot11f); + +void populate_dot11f_tspec(tSirMacTspecIE *pOld, tDot11fIETSPEC *pDot11f); + +void populate_dot11f_wmmtspec(tSirMacTspecIE *pOld, tDot11fIEWMMTSPEC *pDot11f); + +QDF_STATUS +populate_dot11f_tclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f); + +QDF_STATUS +populate_dot11f_wmmtclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pDot11f); + +QDF_STATUS populate_dot11f_wsc(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +QDF_STATUS populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +QDF_STATUS de_populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +QDF_STATUS populate_dot11f_probe_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f, + tpPESession psessionEntry); +QDF_STATUS populate_dot11f_assoc_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpPESession psessionEntry); +QDF_STATUS populate_dot11f_beacon_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f, + tpPESession psessionEntry); + +QDF_STATUS populate_dot11f_wsc_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +QDF_STATUS +populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +QDF_STATUS +de_populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +QDF_STATUS populate_dot11f_assoc_res_wsc_ie(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq); + +QDF_STATUS populate_dot11_assoc_res_p2p_ie(tpAniSirGlobal pMac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq); + +QDF_STATUS populate_dot11f_wscInAssocRes(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f); + +QDF_STATUS populate_dot11f_wfatpc(tpAniSirGlobal pMac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin); + +QDF_STATUS populate_dot11f_rrm_ie(tpAniSirGlobal pMac, + tDot11fIERRMEnabledCap *pDot11f, + tpPESession psessionEntry); + +void populate_mdie(tpAniSirGlobal pMac, + tDot11fIEMobilityDomain * pDot11f, uint8_t mdie[]); +void populate_ft_info(tpAniSirGlobal pMac, tDot11fIEFTInfo *pDot11f); + +void populate_dot11f_assoc_rsp_rates(tpAniSirGlobal pMac, + tDot11fIESuppRates *pSupp, + tDot11fIEExtSuppRates *pExt, + uint16_t *_11bRates, uint16_t *_11aRates); + +int find_ie_location(tpAniSirGlobal pMac, tpSirRSNie pRsnIe, uint8_t EID); + +void lim_log_vht_cap(tpAniSirGlobal pMac, tDot11fIEVHTCaps *pDot11f); + +QDF_STATUS +populate_dot11f_vht_caps(tpAniSirGlobal pMac, tpPESession psessionEntry, + tDot11fIEVHTCaps *pDot11f); + +QDF_STATUS +populate_dot11f_vht_operation(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEVHTOperation *pDot11f); + +QDF_STATUS +populate_dot11f_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f); + +QDF_STATUS +populate_dot11f_ext_cap(tpAniSirGlobal pMac, bool isVHTEnabled, + tDot11fIEExtCap *pDot11f, tpPESession psessionEntry); + +void populate_dot11f_qcn_ie(tDot11fIEQCN_IE *pDot11f); + +#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(tpAniSirGlobal mac_ctx, + tDot11fAssocRequest * frm, + tpPESession pe_session); +#else +static inline void populate_dot11f_fils_params(tpAniSirGlobal mac_ctx, + tDot11fAssocRequest *frm, + tpPESession pe_session) +{ } +#endif + +QDF_STATUS +populate_dot11f_operating_mode(tpAniSirGlobal pMac, + tDot11fIEOperatingMode *pDot11f, + tpPESession psessionEntry); + +void +populate_dot11f_wider_bw_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEWiderBWChanSwitchAnn *pDot11f, + tpPESession psessionEntry); + +void populate_dot11f_timeout_interval(tpAniSirGlobal pMac, + tDot11fIETimeoutInterval *pDot11f, + uint8_t type, uint32_t value); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* Populate a tDot11fIEQComVendorIE */ +void +populate_dot11f_avoid_channel_ie(tpAniSirGlobal mac_ctx, + tDot11fIEQComVendorIE *dot11f, + tpPESession session_entry); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +QDF_STATUS populate_dot11f_timing_advert_frame(tpAniSirGlobal pMac, + tDot11fTimingAdvertisementFrame *frame); +void populate_dot11_supp_operating_classes(tpAniSirGlobal mac_ptr, + tDot11fIESuppOperatingClasses *dot_11_ptr, tpPESession session_entry); + +QDF_STATUS +sir_validate_and_rectify_ies(tpAniSirGlobal 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(tpAniSirGlobal 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 +QDF_STATUS populate_dot11f_he_caps(tpAniSirGlobal, tpPESession, + tDot11fIEhe_cap *); +QDF_STATUS populate_dot11f_he_operation(tpAniSirGlobal, tpPESession, + tDot11fIEhe_op *); +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +QDF_STATUS populate_dot11f_he_bss_color_change(tpAniSirGlobal mac_ctx, + tpPESession session, + tDot11fIEbss_color_change *bss_color); +#else +static inline QDF_STATUS populate_dot11f_he_bss_color_change( + tpAniSirGlobal mac_ctx, + tpPESession session, + tDot11fIEbss_color_change *bss_color) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#else +static inline QDF_STATUS populate_dot11f_he_caps(tpAniSirGlobal mac_ctx, + tpPESession session, tDot11fIEhe_cap *he_cap) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS populate_dot11f_he_operation(tpAniSirGlobal mac_ctx, + tpPESession session, tDot11fIEhe_op *he_op) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS populate_dot11f_he_bss_color_change( + tpAniSirGlobal mac_ctx, + tpPESession session, + tDot11fIEbss_color_change *bss_color) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef 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(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + tDot11fIEExtCap *dot11f); +#else +static inline +QDF_STATUS populate_dot11f_twt_extended_caps(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + tDot11fIEExtCap *dot11f) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sir_unpack_beacon_ie: wrapper to unpack beacon and update def RSN params + * if optional fields are not present. + * @mac_ctx: mac context + * @buf: beacon buffer pointer + * @buf_len: beacon buffer length + * @frame: outframe frame structure + * @append_ie: flag to indicate if the frame need to be appended from buf + * + * Return: parse status + */ +uint32_t sir_unpack_beacon_ie(tpAniSirGlobal mac_ctx, uint8_t *buf, + uint32_t buf_len, + tDot11fBeaconIEs *frame, bool append_ie); + +/** + * lim_truncate_ppet: truncates ppet of trailling 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; +} +#endif /* __PARSE_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/sir_common.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_common.h new file mode 100644 index 0000000000000000000000000000000000000000..66078b9bcea7a74e05d74238ab9a2e6b6ef9d884 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/mac/src/include/sir_debug.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..d294ae229a5773c950403a975bf16ca0e83cce62 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_debug.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011-2012, 2014-2015, 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. + */ + +/* + * 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 MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" + +#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_ENTER() pe_debug("enter") +#define PE_EXIT() pe_debug("exit") +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/sir_params.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_params.h new file mode 100644 index 0000000000000000000000000000000000000000..6f56d64142eaacc0e16869409f995ae741690e5c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_params.h @@ -0,0 +1,829 @@ +/* + * 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. + */ + +/* + * 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 + +/* + * 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 SIR_INSTALL_KEY_TIMEOUT_SEC 70 +#define SIR_INSTALL_KEY_TIMEOUT_MS \ + (SIR_INSTALL_KEY_TIMEOUT_SEC * SYSTEM_TIME_SEC_TO_MSEC) + +/* 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 + * SLM_SESSIONIZATION - indicate SLM_SESSIONIZATION + * 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 + * WOW - indicate WOW + * WLAN_ROAM_SCAN_OFFLOAD - indicate Roam scan offload + * IBSS_HEARTBEAT_OFFLOAD - indicate IBSS HB 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, + SLM_SESSIONIZATION = 3, + DOT11AC_OPMODE = 4, + SAP32STA = 5, + TDLS = 6, + P2P_GO_NOA_DECOUPLE_INIT_SCAN = 7, + WLANACTIVE_OFFLOAD = 8, +#ifdef FEATURE_WLAN_EXTSCAN + EXTENDED_SCAN = 9, +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + PNO = 10, +#endif +#ifdef WLAN_FEATURE_NAN + NAN = 11, +#endif + RTT = 12, + DOT11AX = 13, + WOW = 22, + WLAN_ROAM_SCAN_OFFLOAD = 23, + IBSS_HEARTBEAT_OFFLOAD = 26, + 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 */ +}; + +typedef enum eSriLinkState { + eSIR_LINK_IDLE_STATE = 0, + eSIR_LINK_PREASSOC_STATE = 1, + eSIR_LINK_POSTASSOC_STATE = 2, + eSIR_LINK_AP_STATE = 3, + eSIR_LINK_IBSS_STATE = 4, + eSIR_LINK_DOWN_STATE = 5, +} tSirLinkState; + +/* / 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. + */ + uint32_t data[1]; +} tSirMbMsg, *tpSirMbMsg; + +/* / Mailbox Message Structure for P2P */ +typedef struct sSirMbMsgP2p { + 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; + + uint8_t sessionId; + uint8_t noack; + uint16_t wait; + uint16_t channel_freq; + uint32_t scan_id; + + /** + * 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. + */ + uint32_t data[1]; +} tSirMbMsgP2p, *tpSirMbMsgP2p; + +/** + * struct sir_mgmt_msg - Structure used to send auth frame from CSR to LIM + * @type: Message type + * @msg_len: Message length + * @session_id: session id + * @data: Pointer to data tobe transmitted + */ +struct sir_mgmt_msg { + uint16_t type; + uint16_t msg_len; + uint8_t session_id; + uint8_t *data; +}; + +/* ******************************************* * +* * +* 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. + */ + +/* HAL message types */ +#define SIR_HAL_MSG_TYPES_BEGIN (SIR_HAL_MODULE_ID << 8) +#define SIR_HAL_ITC_MSG_TYPES_BEGIN (SIR_HAL_MSG_TYPES_BEGIN+0x20) +#define SIR_HAL_RADAR_DETECTED_IND SIR_HAL_ITC_MSG_TYPES_BEGIN + +/* + * New Taurus related messages + */ +#define SIR_HAL_ADD_STA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 1) +#define SIR_HAL_ADD_STA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 2) +#define SIR_HAL_DELETE_STA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 3) +#define SIR_HAL_DELETE_STA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 4) +#define SIR_HAL_ADD_BSS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 5) +#define SIR_HAL_ADD_BSS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 6) +#define SIR_HAL_DELETE_BSS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 7) +#define SIR_HAL_DELETE_BSS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 8) +#define SIR_HAL_INIT_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 9) +#define SIR_HAL_INIT_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 10) +#define SIR_HAL_START_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 11) +#define SIR_HAL_START_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 12) +#define SIR_HAL_END_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 13) +#define SIR_HAL_END_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 14) +#define SIR_HAL_FINISH_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 15) +#define SIR_HAL_FINISH_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 16) +#define SIR_HAL_SEND_BEACON_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 17) + +#define SIR_HAL_SET_BSSKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 18) +#define SIR_HAL_SET_BSSKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 19) +#define SIR_HAL_SET_STAKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 20) +#define SIR_HAL_SET_STAKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 21) +#define SIR_HAL_UPDATE_EDCA_PROFILE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 22) + +#define SIR_HAL_UPDATE_BEACON_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 23) +#define SIR_HAL_UPDATE_CF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 24) +#define SIR_HAL_CHNL_SWITCH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 25) +#define SIR_HAL_ADD_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 26) +#define SIR_HAL_DEL_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 27) + +#define SIR_HAL_MISSED_BEACON_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 34) + +#define SIR_HAL_SWITCH_CHANNEL_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 35) +#define SIR_HAL_PWR_SAVE_CFG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 36) + +#define SIR_HAL_REGISTER_PE_CALLBACK (SIR_HAL_ITC_MSG_TYPES_BEGIN + 37) + +#define SIR_HAL_IBSS_STA_ADD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 43) +#define SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 44) +#define SIR_HAL_SET_LINK_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 45) +#define SIR_HAL_DELETE_BSS_HO_FAIL_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 46) +#define 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 + */ + +#define SIR_HAL_SET_STA_BCASTKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 58) +#define SIR_HAL_SET_STA_BCASTKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 59) +#define SIR_HAL_ADD_TS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 60) +#define SIR_HAL_DPU_MIC_ERROR (SIR_HAL_ITC_MSG_TYPES_BEGIN + 61) +#define SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 63) +#define SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 64) +#define SIR_HAL_TIMER_ADC_RSSI_STATS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 65) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 66) is unused */ +#define SIR_HAL_SET_MIMOPS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 67) +#define SIR_HAL_SET_MIMOPS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 68) +#define SIR_HAL_SYS_READY_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 69) +#define SIR_HAL_SET_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 70) +#define SIR_HAL_SET_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 71) +#define SIR_HAL_GET_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 72) +#define SIR_HAL_GET_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 73) +#define SIR_HAL_GET_NOISE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 74) + +/* Messages to support transmit_halt and transmit_resume */ +#define SIR_HAL_TRANSMISSION_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 75) + +#define SIR_HAL_LOW_RSSI_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 80) +#define SIR_HAL_BEACON_FILTER_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 81) + +/* 82-87 are unused */ + +/* / PE <-> HAL statistics messages */ +#define SIR_HAL_GET_STATISTICS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 88) +#define SIR_HAL_GET_STATISTICS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 89) +#define SIR_HAL_SET_KEY_DONE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 90) + +/* / PE <-> HAL BTC messages */ +#define SIR_HAL_BTC_SET_CFG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 91) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 92) is unused */ +#define SIR_HAL_HANDLE_FW_MBOX_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 93) +#define SIR_HAL_SEND_PROBE_RSP_TMPL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 94) + +/* PE <-> HAL addr2 mismatch message */ +#define SIR_LIM_ADDR2_MISS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 95) +#ifdef FEATURE_OEM_DATA_SUPPORT +/* PE <-> HAL OEM_DATA RELATED MESSAGES */ +#define SIR_HAL_START_OEM_DATA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 96) +#define SIR_HAL_START_OEM_DATA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 97) +#endif + +#define SIR_HAL_SET_MAX_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 98) +#define SIR_HAL_SET_MAX_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 99) + +/* / PE <-> HAL Host Offload message */ +#define SIR_HAL_SET_HOST_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 100) + +#define SIR_HAL_ADD_STA_SELF_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 101) +#define SIR_HAL_ADD_STA_SELF_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 102) +#define SIR_HAL_DEL_STA_SELF_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 103) +#define SIR_HAL_DEL_STA_SELF_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 104) + +#define SIR_HAL_CFG_RXP_FILTER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 106) + +#define SIR_HAL_AGGR_ADD_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 107) +#define SIR_HAL_AGGR_ADD_TS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 108) +#define SIR_HAL_AGGR_QOS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 109) +#define SIR_HAL_AGGR_QOS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 110) + +/* P2P <-> HAL P2P msg */ +#define SIR_HAL_SET_P2P_GO_NOA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 111) +#define SIR_HAL_P2P_NOA_ATTR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 112) +#define SIR_HAL_P2P_NOA_START_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 113) + +#define SIR_HAL_SET_LINK_STATE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 114) + +#define SIR_HAL_WLAN_SUSPEND_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 115) +#define SIR_HAL_WLAN_RESUME_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 116) + +/* / PE <-> HAL Keep Alive message */ +#define SIR_HAL_SET_KEEP_ALIVE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 117) + +#ifdef WLAN_NS_OFFLOAD +#define SIR_HAL_SET_NS_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 118) +#endif /* WLAN_NS_OFFLOAD */ + +#define SIR_HAL_SOC_ANTENNA_MODE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 120) +#define SIR_HAL_SOC_ANTENNA_MODE_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 121) + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 122) is unused */ + +#ifdef WLAN_FEATURE_PACKET_FILTERING +#define SIR_HAL_8023_MULTICAST_LIST_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 123) +#define SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 124) +#define SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 125) +#define SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 126) +#define 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 +#define SIR_HAL_GTK_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 129) +#define SIR_HAL_GTK_OFFLOAD_GETINFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 130) +#define SIR_HAL_GTK_OFFLOAD_GETINFO_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 131) +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#ifdef FEATURE_WLAN_ESE +#define SIR_HAL_TSM_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 132) +#define SIR_HAL_TSM_STATS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 133) +#endif + +#define SIR_HAL_SET_TM_LEVEL_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 134) + +#define SIR_HAL_UPDATE_OP_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 135) + +#ifdef FEATURE_WLAN_TDLS +/* / PE <-> HAL TDLS messages */ +#define SIR_HAL_TDLS_LINK_ESTABLISH (SIR_HAL_ITC_MSG_TYPES_BEGIN + 136) +#define SIR_HAL_TDLS_LINK_TEARDOWN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 137) +#endif +#define SIR_HAL_ROAM_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 138) + +#define SIR_HAL_TRAFFIC_STATS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 141) + +#ifdef WLAN_FEATURE_11W +#define SIR_HAL_EXCLUDE_UNENCRYPTED_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 142) +#endif +#ifdef FEATURE_WLAN_TDLS +/* / PE <-> HAL TDLS messages */ +#define SIR_HAL_TDLS_LINK_ESTABLISH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 143) +#define SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 144) +#define SIR_HAL_TDLS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 145) +#endif + +#define SIR_HAL_STOP_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 146) +#define SIR_HAL_RX_SCAN_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 147) +#define SIR_HAL_DHCP_START_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 148) +#define SIR_HAL_DHCP_STOP_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 149) +#define SIR_HAL_IBSS_PEER_INACTIVITY_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 150) + +#define SIR_HAL_LPHB_CONF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 151) + +#define SIR_HAL_ADD_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 152) +#define SIR_HAL_DEL_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 153) + +/* Messages between 156 to 157 are not used */ +#define SIR_HAL_PDEV_DUAL_MAC_CFG_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 154) +#define SIR_HAL_PDEV_MAC_CFG_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 155) + +/* For IBSS peer info related messages */ +#define SIR_HAL_IBSS_PEER_INFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 158) + +#define SIR_HAL_RATE_UPDATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 159) + +#define SIR_HAL_FLUSH_LOG_TO_FW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 160) + +#define SIR_HAL_PDEV_SET_PCL_TO_FW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 161) + +#ifdef WLAN_MWS_INFO_DEBUGFS +#define SIR_HAL_GET_MWS_COEX_INFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 162) +#endif /* WLAN_MWS_INFO_DEBUGFS */ + +#define SIR_HAL_CLI_SET_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 163) +#ifndef REMOVE_PKT_LOG +#define SIR_HAL_PKTLOG_ENABLE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 164) +#endif +#define SIR_HAL_START_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 166) +#define SIR_HAL_UPDATE_CHAN_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 167) +#define SIR_CSA_OFFLOAD_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 169) + +#define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 170) + +#define SIR_HAL_TX_FAIL_MONITOR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 171) + +#define SIR_HAL_UPDATE_MEMBERSHIP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 172) +#define 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 */ +#define SIR_HAL_UPDATE_TDLS_PEER_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 175) +#define SIR_HAL_TDLS_SHOULD_DISCOVER (SIR_HAL_ITC_MSG_TYPES_BEGIN + 176) +#define SIR_HAL_TDLS_SHOULD_TEARDOWN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 177) +#define SIR_HAL_TDLS_PEER_DISCONNECTED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 178) +#endif + +/* Handling of beacon tx indication from FW */ +#define SIR_HAL_BEACON_TX_SUCCESS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 179) +#define SIR_HAL_DFS_RADAR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 180) + +#define SIR_HAL_IBSS_CESIUM_ENABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 181) + +#define SIR_HAL_RMC_ENABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 182) +#define SIR_HAL_RMC_DISABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 183) +#define SIR_HAL_RMC_ACTION_PERIOD_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 184) +#define SIR_HAL_INIT_THERMAL_INFO_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 185) +#define SIR_HAL_SET_THERMAL_LEVEL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 186) + +#ifdef FEATURE_WLAN_ESE +#define SIR_HAL_SET_PLM_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 187) +#endif + +#define SIR_HAL_SET_TX_POWER_LIMIT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 188) +#define SIR_HAL_SET_SAP_INTRABSS_DIS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 189) + +#define SIR_HAL_MODEM_POWER_STATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 190) + +#define SIR_HAL_DISASSOC_TX_COMP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 191) +#define SIR_HAL_DEAUTH_TX_COMP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 192) + +#define SIR_HAL_UPDATE_RX_NSS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 193) + +#ifdef WLAN_FEATURE_STATS_EXT +#define SIR_HAL_STATS_EXT_REQUEST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 194) +#define SIR_HAL_STATS_EXT_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 195) +#endif /* WLAN_FEATURE_STATS_EXT */ + +#define SIR_HAL_HIDE_SSID_VDEV_RESTART (SIR_HAL_ITC_MSG_TYPES_BEGIN + 196) + +#define SIR_HAL_GET_LINK_SPEED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 197) + +#ifdef FEATURE_WLAN_EXTSCAN +#define SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 198) +#define SIR_HAL_EXTSCAN_START_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 199) +#define SIR_HAL_EXTSCAN_STOP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 200) +#define SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 201) +#define SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 202) +#define SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 203) +#define SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 204) +#define SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 205) +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef FEATURE_WLAN_CH_AVOID +#define SIR_HAL_CH_AVOID_UPDATE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 206) +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define SIR_HAL_LL_STATS_CLEAR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 207) +#define SIR_HAL_LL_STATS_SET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 208) +#define SIR_HAL_LL_STATS_GET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 209) +#define SIR_HAL_LL_STATS_RESULTS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 210) +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_CNF (SIR_HAL_ITC_MSG_TYPES_BEGIN + 211) +#endif +#ifdef WLAN_FEATURE_NAN +#define SIR_HAL_NAN_REQUEST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 212) +#endif /* WLAN_FEATURE_NAN */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 213) +#endif + +#define SIR_HAL_SET_BASE_MACADDR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 214) + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 215) is unused */ + +#define SIR_HAL_LINK_STATUS_GET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 216) + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define SIR_HAL_CONFIG_EXT_WOW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 217) +#define SIR_HAL_CONFIG_APP_TYPE1_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 218) +#define SIR_HAL_CONFIG_APP_TYPE2_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 219) +#endif + +#define SIR_HAL_GET_TEMPERATURE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 220) +#define SIR_HAL_SET_SCAN_MAC_OUI_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 221) +#ifdef DHCP_SERVER_OFFLOAD +#define SIR_HAL_SET_DHCP_SERVER_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 222) +#endif /* DHCP_SERVER_OFFLOAD */ +#define SIR_HAL_LED_FLASHING_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 223) +#define SIR_HAL_PROCESS_FW_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 224) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 225) +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 226) +#define SIR_HAL_ROAM_INVOKE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 227) +#endif + +#ifdef FEATURE_WLAN_TDLS +#define SIR_HAL_TDLS_SET_OFFCHAN_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 228) +#endif + +#define SIR_HAL_SET_MAS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 229) +#define SIR_HAL_SET_MIRACAST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 230) +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define SIR_HAL_UPDATE_Q2Q_IE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 231) +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#define SIR_HAL_CONFIG_STATS_FACTOR (SIR_HAL_ITC_MSG_TYPES_BEGIN + 232) +#define SIR_HAL_CONFIG_GUARD_TIME (SIR_HAL_ITC_MSG_TYPES_BEGIN + 233) +#define SIR_HAL_IPA_OFFLOAD_ENABLE_DISABLE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 234) + +#define SIR_HAL_ENTER_PS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 235) +#define SIR_HAL_EXIT_PS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 236) +#define SIR_HAL_ENABLE_UAPSD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 237) +#define SIR_HAL_DISABLE_UAPSD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 238) +#define SIR_HAL_GATEWAY_PARAM_UPDATE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 239) + +#define SIR_HAL_RUNTIME_PM_SUSPEND_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 308) +#define SIR_HAL_RUNTIME_PM_RESUME_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 309) + +#define SIR_HAL_SET_EPNO_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 313) +#define SIR_HAL_SET_PASSPOINT_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 316) +#define SIR_HAL_RESET_PASSPOINT_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 317) +/* 318 unused */ + +#define SIR_HAL_OCB_SET_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 319) +#define SIR_HAL_OCB_SET_UTC_TIME_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 320) +#define SIR_HAL_OCB_START_TIMING_ADVERT_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 321) +#define SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 322) +#define SIR_HAL_OCB_GET_TSF_TIMER_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 323) +#define SIR_HAL_DCC_GET_STATS_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 324) +#define SIR_HAL_DCC_CLEAR_STATS_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 325) +#define SIR_HAL_DCC_UPDATE_NDL_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 326) + +/* FW Memory Dump feature is deprecated */ + +#define SIR_HAL_START_STOP_LOGGING (SIR_HAL_ITC_MSG_TYPES_BEGIN + 328) +#define SIR_HAL_PDEV_SET_HW_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 329) +#define SIR_HAL_PDEV_SET_HW_MODE_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 330) +#define SIR_HAL_PDEV_HW_MODE_TRANS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 331) + +#define SIR_HAL_BAD_PEER_TX_CTL_INI_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 332) +#define SIR_HAL_SET_RSSI_MONITOR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 333) +#define SIR_HAL_SET_IE_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 334) + +#define SIR_HAL_LRO_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 335) + +#define SIR_HAL_HT40_OBSS_SCAN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 337) + +#define SIR_HAL_TSF_GPIO_PIN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 338) + +#define SIR_HAL_ADD_BCN_FILTER_CMDID (SIR_HAL_ITC_MSG_TYPES_BEGIN + 339) +#define SIR_HAL_REMOVE_BCN_FILTER_CMDID (SIR_HAL_ITC_MSG_TYPES_BEGIN + 340) + + +#define SIR_HAL_APF_GET_CAPABILITIES_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 341) +#define SIR_HAL_APF_SET_INSTRUCTIONS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 342) + +#define SIR_HAL_SET_WISA_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 343) +#define SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 344) +#define SIR_HAL_SET_PDEV_IE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 345) + +#ifdef FEATURE_WLAN_TDLS +#define SIR_HAL_TDLS_CONNECTION_TRACKER_NOTIFICATION (SIR_HAL_ITC_MSG_TYPES_BEGIN + 346) +#endif + +#define SIR_HAL_NDP_GET_CAP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 347) +#define SIR_HAL_NDP_INITIATOR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 348) +#define SIR_HAL_NDP_RESPONDER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 349) +#define SIR_HAL_NDP_END_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 350) +#define SIR_HAL_NDI_CAP_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 351) +#define SIR_HAL_NDP_INITIATOR_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 352) +#define SIR_HAL_NDP_RESPONDER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 353) +#define SIR_HAL_NDP_END_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 354) +#define SIR_HAL_NDP_INDICATION (SIR_HAL_ITC_MSG_TYPES_BEGIN + 355) +#define SIR_HAL_NDP_CONFIRM (SIR_HAL_ITC_MSG_TYPES_BEGIN + 356) +#define SIR_HAL_NDP_END_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 357) +#define SIR_HAL_UPDATE_WEP_DEFAULT_KEY (SIR_HAL_ITC_MSG_TYPES_BEGIN + 358) + +#define SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 360) +#define SIR_HAL_POWER_DBG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 362) +#define SIR_HAL_SET_DTIM_PERIOD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 363) +#define SIR_HAL_ENCRYPT_DECRYPT_MSG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 364) +#define SIR_HAL_SHORT_RETRY_LIMIT_CNT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 365) +#define SIR_HAL_LONG_RETRY_LIMIT_CNT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 366) +#define SIR_HAL_UPDATE_TX_FAIL_CNT_TH (SIR_HAL_ITC_MSG_TYPES_BEGIN + 367) +#define SIR_HAL_POWER_DEBUG_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 368) + +#define SIR_HAL_SET_WOW_PULSE_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 369) + +#define SIR_HAL_SET_UDP_RESP_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 370) + +#define SIR_HAL_SET_PER_ROAM_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 371) +#define SIR_HAL_RX_CHN_STATUS_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 372) + +#define SIR_HAL_GET_RCPI_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 373) + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define SIR_HAL_LL_STATS_EXT_SET_THRESHOLD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 378) +#endif +#define SIR_HAL_SET_DBS_SCAN_SEL_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 379) + +#define SIR_HAL_HIDDEN_SSID_RESTART_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 379) + +#define SIR_HAL_GET_PEER_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 386) +#define SIR_HAL_GET_PEER_INFO_EXT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 387) + +/* ARP Debug stats */ +#define SIR_HAL_SET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 388) +#define SIR_HAL_GET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 389) + +#define SIR_HAL_SET_LIMIT_OFF_CHAN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 390) + +#define SIR_HAL_SET_DEL_PMKID_CACHE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 391) +#define SIR_HAL_HLP_IE_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 392) +#define SIR_HAL_OBSS_DETECTION_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 393) +#define SIR_HAL_OBSS_DETECTION_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 394) +#define SIR_HAL_INVOKE_NEIGHBOR_REPORT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 395) +#define SIR_HAL_OBSS_COLOR_COLLISION_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 396) +#define SIR_HAL_OBSS_COLOR_COLLISION_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 397) + +#define SIR_HAL_SEND_ADDBA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 398) +#define SIR_HAL_GET_ROAM_SCAN_STATS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 399) +#define SIR_HAL_SEND_BCN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 401) +#define SIR_HAL_BEACON_DEBUG_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 403) +#define SIR_HAL_ROAM_BLACKLIST_MSG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 404) + +#define SIR_HAL_SEND_PEER_UNMAP_CONF (SIR_HAL_ITC_MSG_TYPES_BEGIN + 411) + +#define SIR_HAL_GET_ISOLATION (SIR_HAL_ITC_MSG_TYPES_BEGIN + 412) + +#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) + +/* CFG message types */ +#define SIR_CFG_MSG_TYPES_BEGIN (SIR_CFG_MODULE_ID << 8) +#define SIR_CFG_ITC_MSG_TYPES_BEGIN (SIR_CFG_MSG_TYPES_BEGIN+0xB0) +#define SIR_CFG_PARAM_UPDATE_IND (SIR_CFG_ITC_MSG_TYPES_BEGIN) +#define SIR_CFG_DOWNLOAD_COMPLETE_IND (SIR_CFG_ITC_MSG_TYPES_BEGIN + 1) +#define SIR_CFG_MSG_TYPES_END (SIR_CFG_MSG_TYPES_BEGIN+0xFF) + +/* 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) + +/* Messages to/from HAL */ +/* Removed as part of moving HAL down to FW */ + +/* Message from ISR upon TFP retry interrupt */ +#define SIR_LIM_RETRY_INTERRUPT_MSG (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 + 6 */ +/* Message from ISR upon SP's Invalid session key interrupt */ +#define SIR_LIM_INV_KEY_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 7) +/* Message from ISR upon SP's Invalid key ID interrupt */ +#define SIR_LIM_KEY_ID_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 8) +/* Message from ISR upon SP's Replay threshold reached interrupt */ +#define SIR_LIM_REPLAY_THRES_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 9) +/* Message from HDD after the TD dummy packet is cleaned up */ +#define SIR_LIM_TD_DUMMY_CALLBACK_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xA) +/* Message from SCH when the STA is ready to be deleted */ +#define SIR_LIM_SCH_CLEAN_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xB) +/* Message from ISR upon Radar Detection */ +#define SIR_LIM_RADAR_DETECT_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xC) +/* Message id 0xD available */ + +/* Message from Hal to send out a DEL-TS indication */ +#define SIR_LIM_DEL_TS_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xE) +/* 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) + +/* 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_CHANNEL_SWITCH_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1A) +#define SIR_LIM_QUIET_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1B) +#define SIR_LIM_QUIET_BSS_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1C) + +#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_BEACON_GEN_IND (SIR_LIM_TIMEOUT_MSG_START + 0x23) +#define SIR_LIM_PERIODIC_PROBE_REQ_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_MSG_TYPES_END (SIR_LIM_MSG_TYPES_BEGIN+0xFF) + +/* PMM message types */ +#define SIR_PMM_MSG_TYPES_BEGIN (SIR_PMM_MODULE_ID << 8) +#define SIR_PMM_CHANGE_PM_MODE (SIR_PMM_MSG_TYPES_BEGIN) +#define SIR_PMM_MSG_TYPES_END (SIR_PMM_MSG_TYPES_BEGIN+0xFF) + +/* MNT message types */ +#define SIR_MNT_MSG_TYPES_BEGIN (SIR_MNT_MODULE_ID << 8) +#define SIR_MNT_RELEASE_BD (SIR_MNT_MSG_TYPES_BEGIN + 0) +#define SIR_MNT_MSG_TYPES_END (SIR_MNT_MSG_TYPES_BEGIN + 0xFF) + +/* ****************************************** * +* * +* EVENT TYPE Definitions * +* * +* ****************************************** */ + +/* MMH Events that are used in other modules to post events to MMH */ +#define SIR_HSTEMUL_TXMB_DONE_EVT 0x00000100 +#define SIR_HSTEMUL_RXMB_READY_EVT 0x00000200 +#define SIR_HSTEMUL_MSGQ_NE_EVT 0x00000400 + +#define SIR_TST_XMIT_MSG_QS_EMPTY_EVT 0x00000080 + +/* 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/drivers/staging/qcacld-3.0/core/mac/src/include/sys_global.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sys_global.h new file mode 100644 index 0000000000000000000000000000000000000000..98c6980775b87dd736d35d4650efed6821a1f334 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/mac/src/include/utils_api.h b/drivers/staging/qcacld-3.0/core/mac/src/include/utils_api.h new file mode 100644 index 0000000000000000000000000000000000000000..2094a9e3b1aad4731a3ac92493f472600be21560 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/utils_api.h @@ -0,0 +1,587 @@ +/* + * 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 __UTILSAPI_H +#define __UTILSAPI_H + +#include +#include +#include "ani_global.h" +#include "sys_wrapper.h" + +/* / System role definition on a per BSS */ +typedef enum eBssSystemRole { + eSYSTEM_UNKNOWN_ROLE, + eSYSTEM_AP_ROLE, + eSYSTEM_STA_IN_IBSS_ROLE, + eSYSTEM_STA_ROLE, + eSYSTEM_BTAMP_STA_ROLE, + eSYSTEM_BTAMP_AP_ROLE, + + eSYSTEM_LAST_ROLE, + eSYSTEM_MULTI_BSS_ROLE = eSYSTEM_LAST_ROLE +} tBssSystemRole; + +QDF_STATUS cfg_init(tpAniSirGlobal); +void cfg_de_init(tpAniSirGlobal); + +/** + * 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 endiannes 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 endiannes 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 + * + */ + +static inline void sir_swap_u32_buf(uint32_t *ptr, uint32_t nWords) +{ + uint32_t i; + + for (i = 0; i < nWords; i++) + ptr[i] = sir_swap_u32(ptr[i]); +} + +/** + * sir_swap_u32_buf_if_needed() + * + * FUNCTION: + * This function is called to swap U8s of U32s in the buffer depending + * on endiannes of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBuf Buffer that will get swapped + * @param nWords Number DWORDS will be swapped + * @return void + */ + +static inline void sir_swap_u32_buf_if_needed(uint32_t *pBuf, uint32_t nWords) +{ +#ifdef ANI_LITTLE_BYTE_ENDIAN + sir_swap_u32_buf(pBuf, nWords); +#endif +} /*** end sir_swap_u32if_needed() ***/ + +/** + * sir_swap_bd_if_needed + * + * FUNCTION: + * Byte swap all the dwords in the BD, except the PHY/MAC headers + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBd BD that will get swapped + * @return void + */ + +static inline void sir_swap_bd_if_needed(uint32_t *pBd) +{ + sir_swap_u32_buf_if_needed(pBd, 6); + sir_swap_u32_buf_if_needed(pBd + 18, 14); +} + +/** + * sir_store_u16_n + * + * FUNCTION: + * It stores a 16 bit number into the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u16_n(uint8_t *ptr, uint16_t val) +{ + *ptr++ = (val >> 8) & 0xff; + *ptr = val & 0xff; +} + +/** + * sir_store_u32_n + * + * FUNCTION: + * It stores a 32 bit number into the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u32_n(uint8_t *ptr, uint32_t val) +{ + *ptr++ = (uint8_t) (val >> 24) & 0xff; + *ptr++ = (uint8_t) (val >> 16) & 0xff; + *ptr++ = (uint8_t) (val >> 8) & 0xff; + *ptr = (uint8_t) (val) & 0xff; +} + +/** + * sir_store_u16 + * + * FUNCTION: + * It stores a 16 bit number into the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u16(uint8_t *ptr, uint16_t val) +{ + *ptr++ = val & 0xff; + *ptr = (val >> 8) & 0xff; +} + +/** + * sir_store_u32 + * + * FUNCTION: + * It stores a 32 bit number into the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u32(uint8_t *ptr, uint32_t val) +{ + *ptr++ = (uint8_t) val & 0xff; + *ptr++ = (uint8_t) (val >> 8) & 0xff; + *ptr++ = (uint8_t) (val >> 16) & 0xff; + *ptr = (uint8_t) (val >> 24) & 0xff; +} + +/** + * sir_store_u32BufN + * + * FUNCTION: + * It stores a 32 bit number into the byte array in network byte order + * i.e. the least significant byte first. It performs the above operation + * on entire buffer and writes to the dst buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * Assumes that the pSrc buffer is of all uint32_t data type fields. + * + * NOTE: + * Must be used if all the fields in the buffer must be of uint32_t types. + * + * @param pDst address of destination byte array + * @param pSrc address of the source DWORD array + * @param length number of DWORDs + * @return None + */ + +static inline void +sir_store_buf_n(uint8_t *pDst, uint32_t *pSrc, uint32_t length) +{ + while (length) { + sir_store_u32_n(pDst, *pSrc); + pDst += 4; + pSrc++; + length--; + } +} + +/** + * sir_read_u16_n + * + * FUNCTION: + * It reads a 16 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 16 bit value + */ + +static inline uint16_t sir_read_u16_n(uint8_t *ptr) +{ + return ((*ptr) << 8) | (*(ptr + 1)); +} + +/** + * 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 + * + */ + +static inline void +sir_swap_n_store(uint32_t *src, uint32_t *dst, uint32_t nWords) +{ + uint32_t i; + + for (i = 0; i < nWords; i++) + dst[i] = sir_swap_u32(src[i]); +} + +/** + * 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) + +/* ------------------------------------------------------------------- */ + +/* New functions for endianness conversion */ +#ifdef ANI_LITTLE_BYTE_ENDIAN +#define ani_cpu_to_be16(x) sir_swap_u16((x)) +#define ani_cpu_to_le16(x) (x) +#define ani_cpu_to_be32(x) sir_swap_u32((x)) +#define ani_cpu_to_le32(x) (x) +#else /* ANI_LITTLE_BYTE_ENDIAN */ +#define ani_cpu_to_be16(x) (x) +#define ani_cpu_to_le16(x) sir_swap_u16((x)) +#define ani_cpu_to_be32(x) (x) +#define ani_cpu_to_le32(x) sir_swap_u32((x)) +#endif /* ANI_LITTLE_BYTE_ENDIAN */ + +#define ani_le16_to_cpu(x) ani_cpu_to_le16(x) +#define ani_le32_to_cpu(x) ani_cpu_to_le32(x) +#define ani_be16_to_cpu(x) ani_cpu_to_be16(x) +#define ani_be32_to_cpu(x) ani_cpu_to_be32(x) + +#endif /* __UTILSAPI_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h new file mode 100644 index 0000000000000000000000000000000000000000..35204cbdbbf61ecb1a74e063fd66375a3e050ce2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +/* + * + * 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(tpAniSirGlobal, uint16_t, tSirMacTspecIE *, + tpLimTspecInfo, tpLimTspecInfo *); + +/* Add TSPEC in lim local table */ +QDF_STATUS lim_tspec_add(tpAniSirGlobal pMac, + uint8_t *pAddr, + uint16_t assocId, + tSirMacTspecIE *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo); + +/* admit control interface */ +extern QDF_STATUS lim_admit_control_add_ts(tpAniSirGlobal pMac, + uint8_t *pAddr, tSirAddtsReqInfo *addts, + tSirMacQosCapabilityStaIE *qos, + uint16_t assocId, uint8_t alloc, + tSirMacScheduleIE *pSch, + /* index to the lim tspec table. */ + uint8_t *pTspecIdx, + tpPESession psessionEntry); + +static inline QDF_STATUS +lim_admit_control_add_sta(tpAniSirGlobal pMac, uint8_t *staAddr, uint8_t alloc) +{ + return QDF_STATUS_SUCCESS; +} + +extern QDF_STATUS +lim_admit_control_delete_sta(tpAniSirGlobal pMac, uint16_t assocId); + +extern QDF_STATUS +lim_admit_control_delete_ts(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *tsinfo, + uint8_t *tsStatus, uint8_t *tspecIdx); + +extern QDF_STATUS lim_update_admit_policy(tpAniSirGlobal pMac); + +QDF_STATUS lim_admit_control_init(tpAniSirGlobal pMac); +#ifdef FEATURE_WLAN_ESE +QDF_STATUS lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId, uint16_t tsm_interval); +#else +QDF_STATUS lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId); +#endif + +QDF_STATUS lim_send_hal_msg_del_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirDeltsReqInfo delts, + uint8_t sessionId, uint8_t *bssId); +void lim_process_hal_add_ts_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsg); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_api.h new file mode 100644 index 0000000000000000000000000000000000000000..26f19714b13c90e1f99ee09573de95d8cd52f190 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_api.h @@ -0,0 +1,403 @@ +/* + * 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. + */ + +/* + * + * 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" + +/* Macro to count heartbeat */ +#define limResetHBPktCount(psessionEntry) (psessionEntry->LimRxedBeaconCntDuringHB = 0) + +/* Useful macros for fetching various states in pMac->lim */ +/* gLimSystemRole */ +#define GET_LIM_SYSTEM_ROLE(psessionEntry) (psessionEntry->limSystemRole) +#define LIM_IS_AP_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_AP_ROLE) +#define LIM_IS_STA_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_STA_ROLE) +#define LIM_IS_IBSS_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_STA_IN_IBSS_ROLE) +#define LIM_IS_UNKNOWN_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_UNKNOWN_ROLE) +#define LIM_IS_P2P_DEVICE_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_P2P_DEVICE_ROLE) +#define LIM_IS_P2P_DEVICE_GO(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_P2P_DEVICE_GO) +#define LIM_IS_NDI_ROLE(psessionEntry) \ + (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_NDI_ROLE) +/* gLimSmeState */ +#define GET_LIM_SME_STATE(pMac) (pMac->lim.gLimSmeState) +#define SET_LIM_SME_STATE(pMac, state) (pMac->lim.gLimSmeState = state) +/* gLimMlmState */ +#define GET_LIM_MLM_STATE(pMac) (pMac->lim.gLimMlmState) +#define SET_LIM_MLM_STATE(pMac, state) (pMac->lim.gLimMlmState = state) +/*tpdphHashNode mlmStaContext*/ +#define GET_LIM_STA_CONTEXT_MLM_STATE(pStaDs) (pStaDs->mlmStaContext.mlmState) +#define SET_LIM_STA_CONTEXT_MLM_STATE(pStaDs, state) (pStaDs->mlmStaContext.mlmState = state) +/* gLimQuietState */ +#define GET_LIM_QUIET_STATE(pMac) (pMac->lim.gLimSpecMgmt.quietState) +#define SET_LIM_QUIET_STATE(pMac, state) (pMac->lim.gLimSpecMgmt.quietState = state) +#define LIM_IS_CONNECTION_ACTIVE(psessionEntry) (psessionEntry->LimRxedBeaconCntDuringHB) +/*pMac->lim.gLimProcessDefdMsgs*/ +#define GET_LIM_PROCESS_DEFD_MESGS(pMac) (pMac->lim.gLimProcessDefdMsgs) +#define SET_LIM_PROCESS_DEFD_MESGS(pMac, val) \ + pMac->lim.gLimProcessDefdMsgs = val; \ + pe_debug("%s Defer LIM messages - value %d", __func__, val); + +/* 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, +} tMgmtFrmDropReason; + +/** + * Function to initialize LIM state machines. + * This called upon LIM thread creation. + */ +extern QDF_STATUS lim_initialize(tpAniSirGlobal); +QDF_STATUS pe_open(tpAniSirGlobal pMac, struct cds_config_info *cds_cfg); +QDF_STATUS pe_close(tpAniSirGlobal pMac); +void pe_register_tl_handle(tpAniSirGlobal pMac); +QDF_STATUS lim_start(tpAniSirGlobal pMac); +QDF_STATUS pe_start(tpAniSirGlobal pMac); +void pe_stop(tpAniSirGlobal pMac); +QDF_STATUS peProcessMsg(tpAniSirGlobal pMac, struct scheduler_msg *limMsg); + +/** + * 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx); + +/** + * pe_register_callbacks_with_wma() - register SME and PE callback functions to + * WMA. + * @pMac: mac global ctx + * @ready_req: Ready request parameters, containing callback pointers + * + * Return: None + */ +void pe_register_callbacks_with_wma(tpAniSirGlobal pMac, + tSirSmeReadyReq *ready_req); + +/** + * Function to cleanup LIM state. + * This called upon reset/persona change etc + */ +extern void lim_cleanup(tpAniSirGlobal); + +/** + * 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(tpAniSirGlobal mac, struct scheduler_msg *msg); + +/** + * 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(tpAniSirGlobal mac, + struct scheduler_msg *msg); + +/** + * Function to process messages posted to LIM thread + * and dispatch to various sub modules within LIM module. + */ +extern void lim_message_processor(tpAniSirGlobal, struct scheduler_msg *); +/** + * Function to check the LIM state if system is in Scan/Learn state. + */ +extern uint8_t lim_is_system_in_scan_state(tpAniSirGlobal); +/** + * Function to handle IBSS coalescing. + * Beacon Processing module to call this. + */ +extern QDF_STATUS lim_handle_ibss_coalescing(tpAniSirGlobal, + tpSchBeaconStruct, + uint8_t *, tpPESession); +/* / Function used by other Sirius modules to read global SME state */ +static inline tLimSmeStates lim_get_sme_state(tpAniSirGlobal pMac) +{ + return pMac->lim.gLimSmeState; +} + +extern void lim_received_hb_handler(tpAniSirGlobal, uint8_t, tpPESession); +extern void limCheckAndQuietBSS(tpAniSirGlobal); +/* / Function that triggers STA context deletion */ +extern void lim_trigger_sta_deletion(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry); + +#ifdef FEATURE_WLAN_TDLS +/* Function that sends TDLS Del Sta indication to SME */ +extern void lim_send_sme_tdls_del_sta_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry, + uint16_t reasonCode); +/** + * lim_set_tdls_flags() - update tdls flags based on newer STA connection + * information + * @roam_sync_ind_ptr: pointer to roam offload structure + * @ft_session_ptr: pointer to PE session + * + * Set TDLS flags as per new STA connection capabilities. + * + * Return: None + */ +void lim_set_tdls_flags(roam_offload_synch_ind *roam_sync_ind_ptr, + tpPESession ft_session_ptr); +#else +static inline void lim_set_tdls_flags(roam_offload_synch_ind *roam_sync_ind_ptr, + tpPESession ft_session_ptr) +{ +} +#endif + +/* / Function that checks for change in AP's capabilties on STA */ +extern void lim_detect_change_in_ap_capabilities(tpAniSirGlobal, + tpSirProbeRespBeacon, tpPESession); +QDF_STATUS lim_update_short_slot(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + tpPESession); + +void lim_ps_offload_handle_missed_beacon_ind(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg); +void lim_send_heart_beat_timeout_ind(tpAniSirGlobal pMac, tpPESession psessionEntry); +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + uint32_t subType); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, + struct sSirSmeRoamOffloadSynchInd *roam_sync_ind_ptr, + tpSirBssDescription bss_desc_ptr, enum sir_roam_op_code reason); +#else +static inline QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, + struct sSirSmeRoamOffloadSynchInd *roam_sync_ind_ptr, + tpSirBssDescription bss_desc_ptr, enum sir_roam_op_code reason) +{ + 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(tpAniSirGlobal mac, tpPESession 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(tpAniSirGlobal mac_ptr, + struct sir_create_session *msg); + +#define limGetQosMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limQosEnabled) +#define limGetWmeMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limWmeEnabled) +#define limGetWsmMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limWsmEnabled) +#define limGet11dMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->lim11dEnabled) +/* ----------------------------------------------------------------------- */ +static inline void lim_get_phy_mode(tpAniSirGlobal pMac, uint32_t *phyMode, + tpPESession psessionEntry) +{ + *phyMode = + psessionEntry ? psessionEntry->gLimPhyMode : pMac->lim.gLimPhyMode; +} + +/* ----------------------------------------------------------------------- */ +static inline void lim_get_rf_band_new(tpAniSirGlobal pMac, + enum band_info *band, + tpPESession psessionEntry) +{ + *band = psessionEntry ? psessionEntry->limRFBand : 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 tpAniSirGlobal pMac + \param struct scheduler_msg pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(tpAniSirGlobal pMac, struct scheduler_msg *pMsg); + +/*-------------------------------------------------------------------------- + + \brief lim_remain_on_chn_rsp() - API for sending remain on channel response. + + LIM calls this api to send the remain on channel response to SME. + + \param pMac - Pointer to Global MAC structure + \param status - status of the response + \param data - pointer to msg + + \return void + + --------------------------------------------------------------------------*/ +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, QDF_STATUS status, uint32_t *data); + +/** + * 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(tpAniSirGlobal pMac, uint8_t vdev_id, + uint32_t scan_id, uint32_t scan_requestor_id); + +void __lim_process_sme_assoc_cnf_new(tpAniSirGlobal, uint32_t, uint32_t *); + +/** + * lim_process_sme_addts_rsp_timeout(): Send addts rsp timeout to SME + * @pMac: 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(tpAniSirGlobal pMac, uint32_t param); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void lim_fill_join_rsp_ht_caps(tpPESession session, tpSirSmeJoinRsp rsp); +#else +static inline void lim_fill_join_rsp_ht_caps(tpPESession session, + tpSirSmeJoinRsp rsp) +{} +#endif +QDF_STATUS lim_update_ext_cap_ie(tpAniSirGlobal mac_ctx, + uint8_t *ie_data, uint8_t *local_ie_buf, uint16_t *local_ie_len); + +/** + * 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); + +/************************************************************/ +#endif /* __LIM_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_fils_defs.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_fils_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..c109763298b6a72d2de4cbb0b27772232cfa5c53 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_fils_defs.h @@ -0,0 +1,273 @@ +/* + * 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. + */ + +#define FILS_EAP_TLV_MAX_DATA_LEN 255 +#define FILS_SHA256_128_AUTH_TAG 16 +#define FILS_SHA256_256_AUTH_TAG 32 + +#define FILS_SHA256_CRYPTO_TYPE "hmac(sha256)" +#define FILS_SHA384_CRYPTO_TYPE "hmac(sha384)" + +/* 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 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 +#define FILS_MAX_HLP_DATA_LEN 2048 + +/* 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_PKM_LEN 32 +#define FILS_SHA384_PKM_LEN 48 + +#define PMKID_LEN 16 + +#define MAX_PRF_INTERATIONS_COUNT 255 + +/* 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 + +#define MAX_IE_LENGTH 255 + +/* 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 reverved:5; +}; + +/* + * enum fils_erp_cryptosuite: this enum defines the cryptosuites used + * to calculate auth tag and auth tag length as defined by RFC 6696 5.3.1 + * @HMAC_SHA256_64: sha256 with auth tag len as 64 bits + * @HMAC_SHA256_128: sha256 with auth tag len as 128 bits + * @HMAC_SHA256_256: sha256 with auth tag len as 256 bits + */ +enum fils_erp_cryptosuite { + INVALID_CRYPTO = 0, /* reserved */ + HMAC_SHA256_64, + HMAC_SHA256_128, + HMAC_SHA256_256, +}; + +/* + * 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; +}; + +/* + * 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 + * @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 + * @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[MAX_IE_LENGTH]; + uint8_t rsn_ie_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 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/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft.h new file mode 100644 index 0000000000000000000000000000000000000000..25abe4e34bd10f909ccbb200758428a6e706b750 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft.h @@ -0,0 +1,127 @@ +/* + * 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. + */ + +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFT_H__ +#define __LIMFT_H__ + +#include +#include +#include +#include + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +void lim_ft_open(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_ft_cleanup(tpAniSirGlobal pMac, tpPESession psessionEntry); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_ft_cleanup_pre_auth_info(tpAniSirGlobal pMac, + tpPESession psessionEntry); +int lim_process_ft_pre_auth_req(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg); +void lim_process_ft_preauth_rsp_timeout(tpAniSirGlobal pMac); +void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tpPESession psessionEntry); +void lim_perform_ft_pre_auth(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); +void lim_post_ft_pre_auth_rsp(tpAniSirGlobal pMac, QDF_STATUS status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + tpPESession psessionEntry); +void lim_handle_ft_pre_auth_rsp(tpAniSirGlobal pMac, QDF_STATUS status, + uint8_t *auth_rsp, uint16_t auth_rsp_len, + tpPESession psessionEntry); +QDF_STATUS lim_ft_setup_auth_session(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_process_mlm_reassoc_cnf(tpAniSirGlobal mac_ctx, uint32_t *msg); +void lim_process_sta_mlm_add_bss_rsp_ft(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, tpPESession psessionEntry); +void lim_process_mlm_reassoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg); +void lim_preauth_scan_event_handler(tpAniSirGlobal mac_ctx, + enum sir_scan_event_type event, + uint8_t session_id, + uint32_t scan_id); +QDF_STATUS lim_send_preauth_scan_offload(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirFTPreAuthReq *ft_preauth_req); +#else +static inline void lim_ft_cleanup_pre_auth_info(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{} +static inline void lim_process_ft_preauth_rsp_timeout(tpAniSirGlobal pMac) +{} +static inline void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf, tpPESession psessionEntry) +{} +static inline void lim_handle_ft_pre_auth_rsp(tpAniSirGlobal pMac, + QDF_STATUS status, uint8_t *auth_rsp, + uint16_t auth_rsp_len, tpPESession psessionEntry) +{} +static inline void lim_process_mlm_reassoc_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{} +static inline void lim_process_sta_mlm_add_bss_rsp_ft(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, tpPESession psessionEntry) +{} +static inline void lim_process_mlm_reassoc_req(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{} +static inline void lim_preauth_scan_event_handler(tpAniSirGlobal mac_ctx, + enum sir_scan_event_type event, + uint8_t session_id, uint32_t scan_id) +{} +static inline int lim_process_ft_pre_auth_req(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + return 0; +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, + tpPESession psessionEntry); +void lim_ft_prepare_add_bss_req(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession pftSessionEntry, + tpSirBssDescription bssDescription); +QDF_STATUS lim_send_preauth_scan_offload(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirFTPreAuthReq *ft_preauth_req); +#else +static inline void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, + tpPESession psessionEntry) +{} +static inline void lim_ft_prepare_add_bss_req(tpAniSirGlobal pMac, + uint8_t updateEntry, tpPESession pftSessionEntry, + tpSirBssDescription bssDescription) +{} +#endif + +bool lim_process_ft_update_key(tpAniSirGlobal pMac, uint32_t *pMsgBuf); +QDF_STATUS lim_process_ft_aggr_qos_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +void lim_process_ft_aggr_qo_s_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsg); +void lim_ft_cleanup_all_ft_sessions(tpAniSirGlobal pMac); +#endif /* __LIMFT_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..909143c9ef9e9b20fd2f48e341944c56875911dc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h @@ -0,0 +1,124 @@ +/* + * 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. + */ + +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFTDEFS_H__ +#define __LIMFTDEFS_H__ + +#include +#include "wma_if.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define MAX_FTIE_SIZE 384 /* Max size limited to 384, on acct. of IW custom events */ + +/* Time to dwell on preauth channel during roaming, in milliseconds */ +#define LIM_FT_PREAUTH_SCAN_TIME 50 + +/*-------------------------------------------------------------------------- + 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; + uint8_t preAuthchannelNum; + /* 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]; + tpSirBssDescription 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 smeSessionId; + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + QDF_STATUS status; + uint16_t ft_ies_length; + uint8_t ft_ies[MAX_FTIE_SIZE]; + uint16_t ric_ies_length; + uint8_t ric_ies[MAX_FTIE_SIZE]; +} tSirFTPreAuthRsp, *tpSirFTPreAuthRsp; + +/*-------------------------------------------------------------------------- + FT Pre Auth Rsp Key SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTUpdateKeyInfo { + uint16_t messageType; + uint16_t length; + uint32_t smeSessionId; + struct qdf_mac_addr bssid; + tSirKeyMaterial keyMaterial; +} tSirFTUpdateKeyInfo, *tpSirFTUpdateKeyInfo; + +/*-------------------------------------------------------------------------- + FT Pre Auth Rsp Key SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthKeyInfo { + uint8_t extSetStaKeyParamValid; /* Ext Bss Config Msg if set */ + /* SetStaKeyParams for ext bss msg */ + tLimMlmSetKeysReq extSetStaKeyParam; +} tSirFTPreAuthKeyInfo, *tpSirFTPreAuthKeyInfo; + +/*------------------------------------------------------------------------- + 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]; + tSirFTPreAuthKeyInfo PreAuthKeyInfo; + /* 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/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_global.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_global.h new file mode 100644 index 0000000000000000000000000000000000000000..fe78fca27e70f8334248f3bd2f7478af70f12e35 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_global.h @@ -0,0 +1,583 @@ +/* + * 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. + */ + +/* + * + * 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 + +/* Maximum number of PS - TIM's to be sent with out wakeup from STA */ +#define LIM_TIM_WAIT_COUNT_FACTOR 5 + +/* + * Use this count if (LIM_TIM_WAIT_FACTOR * ListenInterval) + * is less than LIM_MIN_TIM_WAIT_CNT + */ +#define LIM_MIN_TIM_WAIT_COUNT 50 + +#define GET_TIM_WAIT_COUNT(LIntrvl) \ + ((LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) > LIM_MIN_TIM_WAIT_COUNT ? \ + (LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) : LIM_MIN_TIM_WAIT_COUNT) + +#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_IN_IBSS_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_SCAN_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_LINK_EST_WT_SCAN_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, + eLIM_SME_CHANNEL_SCAN_STATE, + eLIM_SME_NORMAL_CHANNEL_SCAN_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_PROBE_RESP_STATE, + eLIM_MLM_PASSIVE_SCAN_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_LEARN_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_SET_MIMOPS_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE, + eLIM_MLM_P2P_LISTEN_STATE, + eLIM_MLM_WT_SAE_AUTH_STATE, +} tLimMlmStates; + +/* 11h channel quiet states */ + +/* + * This enum indicates in which state the device is in + * when it receives quiet element in beacon or probe-response. + * The default quiet state of the device is always INIT + * eLIM_QUIET_BEGIN - When Quiet period is started + * eLIM_QUIET_CHANGED - When Quiet period is updated + * eLIM_QUIET_RUNNING - Between two successive Quiet updates + * eLIM_QUIET_END - When quiet period ends + */ +typedef enum eLimQuietStates { + eLIM_QUIET_INIT, + eLIM_QUIET_BEGIN, + eLIM_QUIET_CHANGED, + eLIM_QUIET_RUNNING, + eLIM_QUIET_END +} tLimQuietStates; + +/* 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; + uint32_t authFailureTimeout; + uint8_t sessionId; +} tLimMlmAuthReq, *tpLimMlmAuthReq; + +typedef struct sLimMlmJoinReq { + uint32_t joinFailureTimeout; + tSirMacRateSet operationalRateSet; + uint8_t sessionId; + tSirBssDescription 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; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/* OEM Data related structure definitions */ +typedef struct sLimMlmOemDataReq { + struct qdf_mac_addr selfMacAddr; + uint32_t data_len; + uint8_t *data; +} tLimMlmOemDataReq, *tpLimMlmOemDataReq; + +typedef struct sLimMlmOemDataRsp { + bool target_rsp; + uint32_t rsp_len; + uint8_t *oem_data_rsp; +} tLimMlmOemDataRsp, *tpLimMlmOemDataRsp; +#endif + +/* 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; +} tLimPreAuthNode, *tpLimPreAuthNode; + +/* Pre-authentication table definition */ +typedef struct tLimPreAuthTable { + uint32_t numEntry; + tLimPreAuthNode **pTable; +} tLimPreAuthTable, *tpLimPreAuthTable; + +/* / Per STA context structure definition */ +typedef struct sLimMlmStaContext { + tLimMlmStates mlmState; + tAniAuthType authType; + uint16_t listenInterval; + tSirMacCapabilityInfo capabilityInfo; + tSirMacReasonCodes disassocReason; + + tSirResultCodes resultCode; + + tSirMacPropRateSet propRateSet; + 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 +} tLimMlmStaContext, *tpLimMlmStaContext; + +/* 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; + +typedef struct tLimIbssPeerNode tLimIbssPeerNode; +struct tLimIbssPeerNode { + tLimIbssPeerNode *next; + tSirMacAddr peerMacAddr; + uint8_t extendedRatesPresent:1; + uint8_t edcaPresent:1; + uint8_t wmeEdcaPresent:1; + uint8_t wmeInfoPresent:1; + uint8_t htCapable:1; + uint8_t vhtCapable:1; + uint8_t rsvd:2; + uint8_t htSecondaryChannelOffset; + tSirMacCapabilityInfo capabilityInfo; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + uint8_t supportedMCSSet[SIZE_OF_SUPPORTED_MCS_SET]; + tSirMacEdcaParamSetIE edcaParams; + uint8_t erpIePresent; + + /* HT Capabilities of IBSS Peer */ + uint8_t htGreenfield; + uint8_t htShortGI40Mhz; + uint8_t htShortGI20Mhz; + + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t htDsssCckRate40MHzSupport; + + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState htMIMOPSState; + + /* */ + /* 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; + + /* Maximum Rx A-MPDU factor */ + uint8_t htMaxRxAMpduFactor; + + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t htMaxAmsduLength; + + /* */ + /* Recommended Tx Width Set */ + /* 0 - use 20 MHz channel (control channel) */ + /* 1 - use 40 Mhz channel */ + /* */ + uint8_t htSupportedChannelWidthSet; + + uint8_t htLdpcCapable; + + uint8_t beaconHBCount; + uint8_t heartbeatFailure; + + uint8_t *beacon; /* Hold beacon to be sent to HDD/CSR */ + uint16_t beaconLen; + + tDot11fIEVHTCaps VHTCaps; + uint8_t vhtSupportedChannelWidthSet; + uint8_t vhtBeamFormerCapable; + /* + * Peer Atim Info + */ + uint8_t atimIePresent; + uint32_t peerAtimWindowLength; +}; + +/* 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; + 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; + int8_t switchCount; + uint32_t switchTimeoutValue; + uint8_t switchMode; +} tLimChannelSwitchInfo, *tpLimChannelSwitchInfo; + +typedef struct sLimOperatingModeInfo { + uint8_t present; + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tLimOperatingModeInfo, *tpLimOperatingModeInfo; + +typedef struct sLimWiderBWChannelSwitch { + uint8_t newChanWidth; + uint8_t newCenterChanFreq0; + uint8_t newCenterChanFreq1; +} tLimWiderBWChannelSwitchInfo, *tpLimWiderBWChannelSwitchInfo; + +/* Enums used when stopping the Tx. */ +typedef enum eLimQuietTxMode { + /* Stop/resume transmission of all stations,Uses the global flag */ + eLIM_TX_ALL = 0, + /* + * Stops/resumes the transmission of specific stations identified + * by staId. + */ + eLIM_TX_STA, + /* Stops/resumes the transmission of all the packets in BSS */ + eLIM_TX_BSS, + /* + * Stops/resumes the transmission of all packets except beacons in BSS + * This is used when radar is detected in the current operating channel. + * Beacon has to be sent to notify the stations associated about the + * scheduled channel switch + */ + eLIM_TX_BSS_BUT_BEACON +} tLimQuietTxMode; + +typedef enum eLimControlTx { + eLIM_RESUME_TX = 0, + eLIM_STOP_TX +} tLimControlTx; + +/* -------------------------------------------------------------------- */ + +typedef struct sLimTspecInfo { + /* 0==free, else used */ + uint8_t inuse; + /* index in list */ + uint8_t idx; + tSirMacAddr staAddr; + uint16_t assocId; + tSirMacTspecIE 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 { + tLimQuietStates quietState; + uint32_t quietCount; + /* This is in units of system TICKS */ + uint32_t quietDuration; + /* This is in units of TU, for over the air transmission */ + uint32_t quietDuration_TU; + /* After this timeout, actual quiet starts */ + uint32_t quietTimeoutValue; + /* Used on AP, if quiet is enabled during learning */ + bool fQuietEnabled; + tLimDot11hChanSwStates dot11hChanSwState; + /* Radar detected in cur oper chan on AP */ + bool fRadarDetCurOperChan; + /* Whether radar interrupt has been configured */ + bool fRadarIntrConfigured; +} tLimSpecMgmtInfo, *tpLimSpecMgmtInfo; + +#ifdef FEATURE_WLAN_TDLS +/* + * Peer info needed for TDLS setup.. + */ +typedef struct tLimTDLSPeerSta { + struct tLimTDLSPeerSta *next; + uint8_t dialog; + tSirMacAddr peerMac; + tSirMacCapabilityInfo capabilityInfo; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirMacQosCapabilityStaIE qosCaps; + tSirMacEdcaParamSetIE edcaParams; + uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; + uint8_t tdls_bIsResponder; + /* HT Capabilties */ + tDot11fIEHTCaps tdlsPeerHTCaps; + tDot11fIEExtCap tdlsPeerExtCaps; + uint8_t tdls_flags; + uint8_t tdls_link_state; + uint8_t tdls_prev_link_state; + uint8_t tdls_sessionId; + uint8_t ExtRatesPresent; + TX_TIMER gLimTdlsLinkSetupRspTimeoutTimer; + TX_TIMER gLimTdlsLinkSetupCnfTimeoutTimer; +} tLimTdlsLinkSetupPeer, *tpLimTdlsLinkSetupPeer; + +typedef struct tLimTdlsLinkSetupInfo { + tLimTdlsLinkSetupPeer *tdlsLinkSetupList; + uint8_t num_tdls_peers; + uint8_t tdls_flags; + uint8_t tdls_state; + uint8_t tdls_prev_state; +} tLimTdlsLinkSetupInfo, *tpLimTdlsLinkSetupInfo; + +typedef enum tdlsLinkMode { + TDLS_LINK_MODE_BG, + TDLS_LINK_MODE_N, + TDLS_LINK_MODE_AC, + TDLS_LINK_MODE_NONE +} eLimTdlsLinkMode; +#endif /* FEATURE_WLAN_TDLS */ + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_process_fils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_process_fils.h new file mode 100644 index 0000000000000000000000000000000000000000..3e6f9b9ef868f0fc0633c1c71bd16e91e20f8447 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_process_fils.h @@ -0,0 +1,282 @@ +/* + * 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. + */ + +#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(tpAniSirGlobal mac_ctx, + tpPESession 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(tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession 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. + * @session: PE session + * @sme_join_req: pointer to join request + * + * Return: None + */ +void lim_update_fils_config(tpPESession session, tpSirSmeJoinReq sme_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 + */ +uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, tpPESession session); + +/** + * 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(tpPESession 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 + * @sme_join_rsp: SME join rsp + * + * This API copies the FILS connect params from PE session to SME join rsp + * + * Return: None + */ +void populate_fils_connect_params(tpAniSirGlobal mac_ctx, + tpPESession session, + tpSirSmeJoinRsp sme_join_rsp); + +/** + * 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(tpAniSirGlobal mac_ctx, + tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession 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(tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tpSirAssocRsp assoc_rsp, + tLimMlmAssocCnf * assoc_cnf); + +/** + * lim_update_fils_rik() - API to update FILS RIK in RSO + * @pe_session: PE Session + * @req_buffer: Pointer to RSO request + * + * This API is used to calculate(if required) RIK and fill + * the same in RSO request to fw. + * + * Return: None + */ +void lim_update_fils_rik(tpPESession pe_session, + tSirRoamOffloadScanReq *req_buffer); +#else +static inline bool lim_process_fils_auth_frame2(tpAniSirGlobal mac_ctx, + tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body) +{ + return false; +} + +static inline void +lim_increase_fils_sequence_number(tpPESession session_entry) +{ } + +static inline void +lim_add_fils_data_to_auth_frame(tpPESession session, uint8_t *body) +{ +} + +static inline bool lim_is_valid_fils_auth_frame(tpAniSirGlobal mac_ctx, + tpPESession pe_session, tSirMacAuthFrameBody *rx_auth_frm_body) +{ + return true; +} + +static inline void +lim_update_fils_config(tpPESession session, tpSirSmeJoinReq sme_join_req) +{ } + +static inline uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, tpPESession session) +{ + return 0; +} + +static inline bool lim_is_fils_connection(tpPESession pe_session) +{ + return false; +} + +static inline void populate_fils_connect_params(tpAniSirGlobal mac_ctx, + tpPESession session, + tpSirSmeJoinRsp sme_join_rsp) +{ } + +static inline QDF_STATUS aead_encrypt_assoc_req(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + uint8_t *frame, + uint32_t *payload) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS aead_decrypt_assoc_rsp(tpAniSirGlobal mac_ctx, + tpPESession session, + tDot11fAssocResponse *ar, + uint8_t *p_frame, uint32_t *n_frame) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tpSirAssocRsp assoc_rsp, + tLimMlmAssocCnf *assoc_cnf) + +{ + return true; +} + +static inline void lim_update_fils_rik(tpPESession pe_session, + tSirRoamOffloadScanReq *req_buffer) +{ } +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_session.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_session.h new file mode 100644 index 0000000000000000000000000000000000000000..a5be574f7b64d9ccdb7d0d831e9937e9844bf78c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_session.h @@ -0,0 +1,739 @@ +/* + * 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. + */ + +#if !defined(__LIM_SESSION_H) +#define __LIM_SESSION_H + +/**========================================================================= + + \file lim_session.h + + \brief prototype for lim Session related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/* Powersave Offload Implementation */ +typedef enum ePowersaveState { + PMM_FULL_POWER, + PMM_POWER_SAVE +} tPowersaveState; + +/* Master Structure: This will be part of PE Session Entry */ +typedef struct sPowersaveoffloadInfo { + tPowersaveState psstate; + uint8_t bcnmiss; +} tPowersaveoffloadInfo, tpPowersaveoffloadInfo; + +#ifdef WLAN_FEATURE_11W +typedef struct tagComebackTimerInfo { + tpAniSirGlobal pMac; + uint8_t sessionID; + tLimMlmStates limPrevMlmState; /* Previous MLM State */ + tLimMlmStates limMlmState; /* MLM State */ +} tComebackTimerInfo; +#endif /* WLAN_FEATURE_11W */ +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +/* Maximum Number of WEP KEYS */ +#define MAX_WEP_KEYS 4 + +#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; + +#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 10000 +#define OBSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS 5000 +#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; +}; + +typedef struct sPESession /* Added to Support BT-AMP */ +{ + /* To check session table is in use or free */ + uint8_t available; + uint16_t peSessionId; + uint8_t smeSessionId; + uint16_t transactionId; + qdf_wake_lock_t ap_ecsa_wakelock; + qdf_runtime_lock_t ap_ecsa_runtime_lock; + /* In AP role: BSSID and selfMacAddr will be the same. */ + /* In STA role: they will be different */ + tSirMacAddr bssId; + tSirMacAddr selfMacAddr; + tSirMacSSid ssId; + uint8_t bssIdx; + uint8_t valid; + tLimMlmStates limMlmState; /* MLM State */ + tLimMlmStates limPrevMlmState; /* Previous MLM State */ + tLimSmeStates limSmeState; /* SME State */ + tLimSmeStates limPrevSmeState; /* Previous SME State */ + tLimSystemRole limSystemRole; + tSirBssType bssType; + uint8_t operMode; /* AP - 0; STA - 1 ; */ + tSirNwType nwType; + tpSirSmeStartBssReq pLimStartBssReq; /* handle to smestart bss req */ + tpSirSmeJoinReq pLimJoinReq; /* handle to sme join req */ + tpSirSmeJoinReq pLimReAssocReq; /* handle to sme reassoc req */ + tpLimMlmJoinReq pLimMlmJoinReq; /* handle to MLM join Req */ + void *pLimMlmReassocRetryReq; /* keep reasoc req for retry */ + void *pLimMlmReassocReq; /* handle to MLM reassoc Req */ + uint16_t channelChangeReasonCode; + uint8_t dot11mode; + uint8_t htCapability; + /* Supported Channel Width Set: 0-20MHz 1 - 40MHz */ + uint8_t htSupportedChannelWidthSet; + /* Recommended Tx Width Set + * 0 - use 20 MHz channel (control channel) + * 1 - use channel width enabled under Supported Channel Width Set + */ + uint8_t htRecommendedTxWidthSet; + /* Identifies the 40 MHz extension channel */ + ePhyChanBondState htSecondaryChannelOffset; + enum band_info limRFBand; + uint8_t limIbssActive; /* TO SUPPORT CONCURRENCY */ + + /* These global varibales moved to session Table to support BT-AMP : Oct 9th review */ + tAniAuthType limCurrentAuthType; + uint16_t limCurrentBssCaps; + uint8_t limCurrentBssQosCaps; + uint16_t limCurrentBssPropCap; + uint8_t limSentCapsChangeNtf; + uint16_t limAID; + + /* Parameters For Reassociation */ + tSirMacAddr limReAssocbssId; + tSirMacChanNum limReassocChannelId; + /* CB paramaters required/duplicated for Reassoc since re-assoc mantains its own params in lim */ + uint8_t reAssocHtSupportedChannelWidthSet; + uint8_t reAssocHtRecommendedTxWidthSet; + ePhyChanBondState reAssocHtSecondaryChannelOffset; + tSirMacSSid limReassocSSID; + uint16_t limReassocBssCaps; + uint8_t limReassocBssQosCaps; + uint16_t limReassocBssPropCap; + + /* Assoc or ReAssoc Response Data/Frame */ + void *limAssocResponseData; + + /** BSS Table parameters **/ + + /* + * staId: Start BSS: this is the Sta Id for the BSS. + * Join: this is the selfStaId + * In both cases above, the peer STA ID wll be stored in dph hash table. + */ + uint16_t staId; + uint16_t statypeForBss; /* to know session is for PEER or SELF */ + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + tSirMacRateSet rateSet; + tSirMacRateSet extRateSet; + tSirMacHTOperatingMode htOperMode; + uint8_t currentOperChannel; + uint8_t currentReqChannel; + uint8_t LimRxedBeaconCntDuringHB; + + /* Time stamp of the last beacon received from the BSS to which STA is connected. */ + uint64_t lastBeaconTimeStamp; + /* RX Beacon count for the current BSS to which STA is connected. */ + uint32_t currentBssBeaconCnt; + uint8_t bcon_dtim_period; + + uint32_t bcnLen; + uint8_t *beacon; /* Used to store last beacon / probe response before assoc. */ + + uint32_t assocReqLen; + uint8_t *assocReq; /* Used to store association request frame sent out while associating. */ + + uint32_t assocRspLen; + uint8_t *assocRsp; /* Used to store association response received while associating */ + tAniSirDph dph; + void **parsedAssocReq; /* Used to store parsed assoc req from various requesting station */ + uint32_t RICDataLen; /* Used to store the Ric data received in the assoc response */ + uint8_t *ricData; +#ifdef FEATURE_WLAN_ESE + uint32_t tspecLen; /* Used to store the TSPEC IEs received in the assoc response */ + uint8_t *tspecIes; +#endif + uint32_t encryptType; + + bool bTkipCntrMeasActive; /* Used to keep record of TKIP counter measures start/stop */ + + uint8_t gLimProtectionControl; /* used for 11n protection */ + + uint8_t gHTNonGFDevicesPresent; + + /* protection related config cache */ + tCfgProtection cfgProtection; + + /* Number of legacy STAs associated */ + tLimProtStaParams gLim11bParams; + + /* Number of 11A STAs associated */ + tLimProtStaParams gLim11aParams; + + /* Number of non-ht non-legacy STAs associated */ + tLimProtStaParams gLim11gParams; + + /* Number of nonGf STA associated */ + tLimProtStaParams gLimNonGfParams; + + /* Number of HT 20 STAs associated */ + tLimProtStaParams gLimHt20Params; + + /* Number of Lsig Txop not supported STAs associated */ + tLimProtStaParams gLimLsigTxopParams; + + /* Number of STAs that do not support short preamble */ + tLimNoShortParams gLimNoShortParams; + + /* Number of STAs that do not support short slot time */ + tLimNoShortSlotParams gLimNoShortSlotParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOlbcParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOverlap11gParams; + + tLimProtStaParams gLimOverlap11aParams; + tLimProtStaParams gLimOverlapHt20Params; + tLimProtStaParams gLimOverlapNonGfParams; + + /* cache for each overlap */ + tCacheParams protStaCache[LIM_PROT_STA_CACHE_SIZE]; + + uint8_t privacy; + tAniAuthType authType; + tSirKeyMaterial WEPKeyMaterial[MAX_WEP_KEYS]; + + 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; /* 11E */ + uint8_t limWmeEnabled:1; /* WME */ + uint8_t limWsmEnabled:1; /* WSM */ + uint8_t limHcfEnabled:1; + uint8_t lim11dEnabled:1; +#ifdef WLAN_FEATURE_11W + uint8_t limRmfEnabled:1; /* 11W */ +#endif + uint32_t lim11hEnable; + + int8_t maxTxPower; /* MIN (Regulatory and local power constraint) */ + enum QDF_OPMODE pePersona; + int8_t txMgmtPower; + bool is11Rconnection; + +#ifdef FEATURE_WLAN_ESE + bool isESEconnection; + tEsePEContext eseContext; +#endif + bool isFastTransitionEnabled; + bool isFastRoamIniFeatureEnabled; + tSirNoAParam p2pNoA; + tSirP2PNoaAttr p2pGoPsUpdate; + uint32_t defaultAuthFailureTimeout; + tSirP2PNoaStart p2pGoPsNoaStartInd; + + /* EDCA QoS parameters + * 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. + */ + tSirMacEdcaParamRecord gLimEdcaParams[MAX_NUM_AC]; /* used locally */ + tSirMacEdcaParamRecord gLimEdcaParamsBC[MAX_NUM_AC]; /* used for broadcast */ + tSirMacEdcaParamRecord gLimEdcaParamsActive[MAX_NUM_AC]; + + 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; + uint8_t ch_center_freq_seg1; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + tLimWiderBWChannelSwitchInfo gLimWiderBWChannelSwitch; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmpsvalue; + bool send_smps_action; + uint8_t spectrumMgtEnabled; + /* *********************11H related**************************** */ + tLimSpecMgmtInfo gLimSpecMgmt; + /* CB Primary/Secondary Channel Switch Info */ + tLimChannelSwitchInfo gLimChannelSwitch; + /* *********************End 11H related**************************** */ + + /*Flag to Track Status/Indicate HBFailure on this session */ + bool LimHBFailureStatus; + uint32_t gLimPhyMode; + uint8_t amsduSupportedInBA; + uint8_t txLdpcIniFeatureEnabled; + /** + * Following is the place holder for free peer index pool. + * A non-zero value indicates that peer index is available + * for assignment. + */ + uint8_t *gpLimPeerIdxpool; + uint8_t freePeerIdxHead; + uint8_t freePeerIdxTail; + uint16_t gLimNumOfCurrentSTAs; +#ifdef FEATURE_WLAN_TDLS + /* TDLS parameters to check whether TDLS + * and TDLS channel switch is allowed in the + * AP network + */ + uint32_t peerAIDBitmap[2]; + bool tdls_prohibited; + bool tdls_chan_swit_prohibited; + 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; + uint8_t isCoalesingInIBSSAllowed; + + tSirHTConfig htConfig; + struct sir_vht_config vht_config; + /* + * Place holder for StartBssReq message + * received by SME state machine + */ + uint8_t gLimCurrentBssUapsd; + + /* 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. + */ + uint8_t gUapsdPerAcBitmask; + + /* 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. + */ + uint8_t gUapsdPerAcTriggerEnableMask; + + /* 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. + */ + uint8_t gUapsdPerAcDeliveryEnableMask; + + /* Flag to skip CSA IE processing when CSA + * offload is enabled. + */ + uint8_t csaOffloadEnable; + + /* 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 partiular AC is not admitted + * If bit is set to 1: That particular AC is admitted + */ + uint8_t gAcAdmitMask[SIR_MAC_DIRECTION_DIRECT]; + + /* Power Save Off load Parameters */ + tPowersaveoffloadInfo pmmOffloadInfo; + /* SMPS mode */ + uint8_t smpsMode; + + uint8_t chainMask; + + /* Flag to indicate Chan Sw announcement is required */ + uint8_t dfsIncludeChanSwIe; + + /* Flag to indicate Chan Wrapper Element is required */ + uint8_t dfsIncludeChanWrapperIe; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + + bool isCiscoVendorAP; + + tSirAddIeParams addIeParams; + + uint8_t *pSchProbeRspTemplate; + /* Beginning portion of the beacon frame to be written to TFP */ + uint8_t *pSchBeaconFrameBegin; + /* Trailing portion of the beacon frame to be written to TFP */ + uint8_t *pSchBeaconFrameEnd; + /* Size of the beginning portion */ + uint16_t schBeaconOffsetBegin; + /* Size of the trailing portion */ + uint16_t schBeaconOffsetEnd; + bool isOSENConnection; + /* DSCP to UP mapping for HS 2.0 */ + tSirQosMapSet QosMapSet; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool bRoamSynchInProgress; +#endif + + /* Fast Transition (FT) */ + tftPEContext ftPEContext; + bool isNonRoamReassoc; + uint8_t is_key_installed; + /* timer for resetting protection fileds at regular intervals */ + qdf_mc_timer_t protection_fields_reset_timer; + /* timer to decrement CSA/ECSA count */ + qdf_mc_timer_t ap_ecsa_timer; + void *mac_ctx; + /* + * variable to store state of various protection struct like + * gLimOlbcParams, gLimOverlap11gParams, gLimOverlapHt20Params etc + */ + uint16_t old_protection_state; + tSirMacAddr prev_ap_bssid; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* tells if Q2Q IE, from another MDM device in AP MCC mode was recvd */ + bool sap_advertise_avoid_ch_ie; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#ifdef FEATURE_WLAN_ESE + uint8_t is_ese_version_ie_present; +#endif + uint8_t sap_dot11mc; + bool is_vendor_specific_vhtcaps; + uint8_t vendor_specific_vht_ie_sub_type; + bool vendor_vht_sap; + /* HS 2.0 Indication */ + tDot11fIEhs20vendor_ie hs20vendor_ie; + /* flag to indicate country code in beacon */ + uint8_t country_info_present; + uint8_t nss; + bool nss_forced_1x1; + bool add_bss_failed; + /* To hold OBSS Scan IE Parameters */ + struct obss_scanparam obss_ht40_scanparam; + uint8_t vdev_nss; + /* Supported NSS is intersection of self and peer 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 ignore_assoc_disallowed; + bool send_p2p_conf_frame; + bool process_ho_fail; + /* Number of STAs that do not support ECSA capability */ + 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; +#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 + bool enable_bcast_probe_rsp; + uint8_t ht_client_cnt; + bool force_24ghz_in_ht20; + bool ch_switch_in_progress; + bool he_with_wep_tkip; +#ifdef WLAN_FEATURE_FILS_SK + struct pe_fils_session *fils_info; + struct qdf_mac_addr dst_mac; + struct qdf_mac_addr src_mac; + uint16_t hlp_data_len; + uint8_t *hlp_data; +#endif + /* previous auth frame's sequence number */ + uint16_t prev_auth_seq_num; + 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 fw_roaming_started; + bool recvd_deauth_while_roaming; + bool recvd_disassoc_while_roaming; + bool deauth_disassoc_rc; + enum wmi_obss_color_collision_evt_type obss_color_collision_dec_evt; + bool is_session_obss_color_collision_det_enabled; + int8_t def_max_tx_pwr; +#ifdef WLAN_SUPPORT_TWT + uint8_t peer_twt_requestor; + uint8_t peer_twt_responder; +#endif + bool enable_session_twt_support; +} tPESession, *tpPESession; + +struct session_params { + uint16_t session_id; +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +/** + * pe_create_session() - creates a new PE session given the BSSID + * + * @pMac: pointer to global adapter context + * @bssid: BSSID of the new session + * @sessionId: session ID is returned here, if session is created. + * @numSta: number of stations + * @bssType: bss type of new session to do conditional memory allocation. + * + * 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. + */ +tpPESession pe_create_session(tpAniSirGlobal pMac, + uint8_t *bssid, + uint8_t *sessionId, + uint16_t numSta, tSirBssType bssType); + +/** + * pe_find_session_by_bssid() - looks up the PE session given the BSSID. + * + * @pMac: 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. + */ +tpPESession pe_find_session_by_bssid(tpAniSirGlobal pMac, uint8_t *bssid, + uint8_t *sessionId); + +/** + * pe_find_session_by_bss_idx() - looks up the PE session given the bssIdx. + * + * @pMac: pointer to global adapter context + * @bssIdx: bss index of the session + * + * This function returns the session context if the session + * corresponding to the given bssIdx is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_bss_idx(tpAniSirGlobal pMac, uint8_t bssIdx); + +/** + * pe_find_session_by_peer_sta() - looks up the PE session given the Peer + * Station Address. + * + * @pMac: 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. + */ +tpPESession pe_find_session_by_peer_sta(tpAniSirGlobal pMac, uint8_t *sa, + uint8_t *sessionId); + +/** + * pe_find_session_by_session_id() - looks up the PE session given the session + * ID. + * + * @pMac: 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. + */ +tpPESession pe_find_session_by_session_id(tpAniSirGlobal pMac, + uint8_t sessionId); + +/** + * pe_find_session_by_bssid() - looks up the PE session given staid. + * + * @pMac: pointer to global adapter context + * @staid: StaId 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 StaId is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_sta_id(tpAniSirGlobal pMac, uint8_t staid, + uint8_t *sessionId); + +/** + * pe_delete_session() - deletes the PE session given the session ID. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID to delete. + * + * Return: void + */ +void pe_delete_session(tpAniSirGlobal pMac, tpPESession psessionEntry); + + +/** + * pe_find_session_by_sme_session_id() - looks up the PE session for given sme + * session id + * @mac_ctx: pointer to global adapter context + * @sme_session_id: sme session id + * + * looks up the PE session for given sme session id + * + * Return: pe session entry for given sme session if found else NULL + */ +tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx, + uint8_t sme_session_id); +uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx); +#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(tpPESession 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 + * @ibss_ssid: SSID of the session for IBSS sessions + * @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(tpAniSirGlobal mac_ctx, + tpPESession session, + tSirMacSSid *ibss_ssid, + 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(tpAniSirGlobal mac_ctx, tpPESession 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(tpAniSirGlobal mac_ctx, tpPESession session); + +#endif /* #if !defined( __LIM_SESSION_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_trace.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..e4228b071a01d83bd42763dbad556128ae9da701 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_trace.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2013-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 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" +#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_DEFERRED(data) (data & 0x80000000) +#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)) + +enum { + 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_TX_CFG_MSG, + TRACE_CODE_RX_CFG_MSG, + TRACE_CODE_RX_MGMT_DROP, + + TRACE_CODE_TIMER_ACTIVATE, + TRACE_CODE_TIMER_DEACTIVATE, + TRACE_CODE_INFO_LOG +}; + +void lim_trace_init(tpAniSirGlobal pMac); +void limTraceReset(tpAniSirGlobal pMac); +void limTraceUpdateMgmtStat(tpAniSirGlobal pMac, uint8_t subtype); +void lim_trace_dumpMgmtStat(tpAniSirGlobal pMac, uint8_t subtype); +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 *pMac, tp_qdf_trace_record pRecord, + uint16_t recIndex); +void mac_trace_msg_tx(tpAniSirGlobal pMac, uint8_t session, uint32_t data); +void mac_trace_msg_rx(tpAniSirGlobal pMac, uint8_t session, uint32_t data); + +void mac_trace_msg_rx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data); +void mac_trace_msg_tx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data); +#endif /* endof LIM_TRACE_RECORD MACRO */ + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_api.h new file mode 100644 index 0000000000000000000000000000000000000000..d20f4db670f1a60aa89280c7a3fbc918d7e09584 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_api.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +/**========================================================================= + + \file rrm_api.h + + \brief RRM APIs + + ========================================================================*/ + +/* $Header$ */ + +#ifndef __RRM_API_H__ +#define __RRM_API_H__ + +#define RRM_MIN_TX_PWR_CAP 13 +#define RRM_MAX_TX_PWR_CAP 19 + +#define RRM_BCN_RPT_NO_BSS_INFO 0 +#define RRM_BCN_RPT_MIN_RPT 1 + +uint8_t rrm_get_min_of_max_tx_power(tpAniSirGlobal pMac, int8_t regMax, + int8_t apTxPower); + +QDF_STATUS rrm_initialize(tpAniSirGlobal pMac); + +QDF_STATUS rrm_cleanup(tpAniSirGlobal pMac); + +QDF_STATUS rrm_process_link_measurement_request(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest + *pLinkReq, + tpPESession + pSessionEntry); + +QDF_STATUS rrm_process_radio_measurement_request(tpAniSirGlobal pMac, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest + *pRRMReq, + tpPESession + pSessionEntry); + +QDF_STATUS rrm_process_neighbor_report_response(tpAniSirGlobal pMac, + tDot11fNeighborReportResponse + *pNeighborRep, + tpPESession + pSessionEntry); + +QDF_STATUS rrm_send_set_max_tx_power_req(tpAniSirGlobal pMac, + int8_t txPower, + tpPESession pSessionEntry); + +int8_t rrm_get_mgmt_tx_power(tpAniSirGlobal pMac, + tpPESession pSessionEntry); + +void rrm_cache_mgmt_tx_power(tpAniSirGlobal pMac, + int8_t txPower, tpPESession pSessionEntry); + +tpRRMCaps rrm_get_capabilities(tpAniSirGlobal pMac, + tpPESession pSessionEntry); + +void rrm_get_start_tsf(tpAniSirGlobal pMac, uint32_t *pStartTSF); + +void rrm_update_start_tsf(tpAniSirGlobal pMac, uint32_t startTSF[2]); + +QDF_STATUS rrm_set_max_tx_power_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ); + +QDF_STATUS +rrm_process_neighbor_report_req(tpAniSirGlobal pMac, + tpSirNeighborReportReqInd pNeighborReq); + +QDF_STATUS +rrm_process_beacon_report_xmit(tpAniSirGlobal pMac, + tpSirBeaconReportXmitInd pBcnReport); + +void lim_update_rrm_capability(tpAniSirGlobal mac_ctx, + tpSirSmeJoinReq join_req); +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_global.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_global.h new file mode 100644 index 0000000000000000000000000000000000000000..fe4ac201b9a633582e1d6adadda8c51bee0efd88 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_global.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +#if !defined(__RRMGLOBAL_H) +#define __RRMGLOBAL_H + +/**========================================================================= + + \file rrm_global.h + + \brief Definitions for SME APIs + + ========================================================================*/ + +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; + +typedef struct sSirChannelInfo { + uint8_t regulatoryClass; + uint8_t channelNum; +} tSirChannelInfo, *tpSirChannelInfo; + +typedef struct sSirBeaconReportReqInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_REQ_IND */ + uint16_t length; + tSirMacAddr bssId; + uint16_t measurementDuration[SIR_ESE_MAX_MEAS_IE_REQS]; /* ms */ + uint16_t randomizationInterval; /* ms */ + tSirChannelInfo channelInfo; + /* 0: wildcard */ + tSirMacAddr macaddrBssid; + /* 0:Passive, 1: Active, 2: table mode */ + uint8_t fMeasurementtype[SIR_ESE_MAX_MEAS_IE_REQS]; + tAniSSID ssId; /* May be wilcard. */ + uint16_t uDialogToken; + tSirChannelList channelList; /* From AP channel report. */ + tRrmMsgReqSource msgSource; +} tSirBeaconReportReqInd, *tpSirBeaconReportReqInd; + +typedef struct sSirBeaconReportXmitInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_RESP_XMIT_IND */ + uint16_t length; + tSirMacAddr bssId; + uint16_t uDialogToken; + uint8_t fMeasureDone; + uint16_t duration; + uint8_t regClass; + uint8_t numBssDesc; + tpSirBssDescription 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; + uint16_t numNeighborReports; + tSirMacAddr bssId; /* For the session. */ + tSirNeighborBssDescription sNeighborBssDescription[1]; +} tSirNeighborReportInd, *tpSirNeighborReportInd; + +typedef struct sRRMBeaconReportRequestedIes { + uint8_t num; + uint8_t *pElementIds; +} 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 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; + +/** + * rrm_beacon_report_last_beacon_params - Last Beacon Report Indication params + * @last_beacon_ind: flag for whether last beacon indication is required + * @report_id: Report ID of the corresponding Beacon Report Request + * @frag_id: Current fragment's Fragment ID + * @num_frags: Total number of fragments in the Beacon Report + */ +struct rrm_beacon_report_last_beacon_params { + uint8_t last_beacon_ind; + uint8_t report_id; + uint8_t frag_id; + uint8_t num_frags; +}; + +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; + +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; + tpRRMReq pCurrentReq; +} 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/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_api.h new file mode 100644 index 0000000000000000000000000000000000000000..9744040a4bc10d1bc57e80a3100eb38000160e09 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_api.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2011-2015, 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. + */ + +/* + * + * 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(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* fill in the default local edca parameter into gLimEdcaParams[] */ +void sch_set_default_edca_params(tpAniSirGlobal pMac, tpPESession psessionE); + +/* update only local qos params */ +void sch_qos_update_local(tpAniSirGlobal pMac, tpPESession psessionEntry); + +/* update the edca profile parameters */ +void sch_edca_profile_update(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* / Set the fixed fields in a beacon frame */ +QDF_STATUS sch_set_fixed_beacon_fields(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* / Process the scheduler messages */ +void sch_process_message(tpAniSirGlobal pMac, + struct scheduler_msg *pSchMsg); + +/** + * sch_process_pre_beacon_ind() - Process the PreBeacon Indication from the Lim + * @pMac: pointer to mac structure + * @msg: schedular msg + * @reason: beaon update reason + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +QDF_STATUS sch_process_pre_beacon_ind(tpAniSirGlobal pMac, + struct scheduler_msg *msg, + enum sir_bcn_update_reason reason); + +/* / Post a message to the scheduler message queue */ +QDF_STATUS sch_post_message(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg); + +void sch_beacon_process(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry); + +QDF_STATUS sch_beacon_edca_process(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *edca, + tpPESession psessionEntry); + +void sch_generate_tim(tpAniSirGlobal, uint8_t **, uint16_t *, uint8_t); + +void sch_set_beacon_interval(tpAniSirGlobal pMac, tpPESession psessionEntry); + +/** + * 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: beaon update reason + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +QDF_STATUS sch_send_beacon_req(tpAniSirGlobal mac_ctx, uint8_t *bcn_payload, + uint16_t size, tpPESession session, + enum sir_bcn_update_reason reason); + + +QDF_STATUS lim_update_probe_rsp_template_ie_bitmap_beacon1(tpAniSirGlobal, + tDot11fBeacon1 *, + tpPESession + psessionEntry); +void lim_update_probe_rsp_template_ie_bitmap_beacon2(tpAniSirGlobal, + tDot11fBeacon2 *, + uint32_t *, + tDot11fProbeResponse *); +void set_probe_rsp_ie_bitmap(uint32_t *, uint32_t); +uint32_t lim_send_probe_rsp_template_to_hal(tpAniSirGlobal, + tpPESession, + uint32_t *); + +int sch_gen_timing_advert_frame(tpAniSirGlobal pMac, 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(tpAniSirGlobal mac_ctx, + uint8_t session_id, + uint8_t *rx_pkt_info, + tSchBeaconStruct *bcn); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_global.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_global.h new file mode 100644 index 0000000000000000000000000000000000000000..03e9cf2cbec9e51a5dc927291ad6b9eca63e9c2b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_global.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013-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. + */ + +/* + * + * + * 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" + +#define TIM_IE_SIZE 0xB + +/* ----------------------- Beacon processing ------------------------ */ + +/* / Beacon structure */ +#define tSchBeaconStruct tSirProbeRespBeacon +#define tpSchBeaconStruct struct sSirProbeRespBeacon * + +/* ------------------------------------------------------------------- */ + +/* ****************** MISC defs ********************************* */ + +struct schMisc { + uint16_t gSchBeaconInterval; + + /* --------- STA ONLY state ----------- */ + + /* / flag to indicate that beacon template has been updated */ + uint8_t fBeaconChanged; + + uint16_t p2pIeOffset; + + /* CSA and ECSA Switch Count Offsets to be sent to FW */ + uint32_t csa_count_offset; + uint32_t ecsa_count_offset; +}; + +/* ****************** MISC defs ********************************* */ + +/* / Global SCH structure */ +typedef struct sAniSirSch { + /* / The scheduler object */ + struct schMisc schObject; +} tAniSirSch, *tpAniSirSch; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h new file mode 100644 index 0000000000000000000000000000000000000000..86f6017fb087503e4769406c789c3a09b0108151 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c new file mode 100644 index 0000000000000000000000000000000000000000..8d59d9eb20173bbc73f426d36757bfb3b6b9a910 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c @@ -0,0 +1,1084 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.h" /* wlan_cfg_get_int() */ +#include "lim_trace.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_types.h" +#include "lim_admit_control.h" + +#define ADMIT_CONTROL_LOGLEVEL LOGD +#define ADMIT_CONTROL_POLICY_LOGLEVEL LOGD + +/* 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 QDF_STATUS +lim_calculate_svc_int(tpAniSirGlobal, tSirMacTspecIE *, uint32_t *); +static QDF_STATUS +lim_validate_tspec_edca(tpAniSirGlobal, tSirMacTspecIE *, tpPESession); +static QDF_STATUS +lim_validate_tspec(tpAniSirGlobal, tSirMacTspecIE *, tpPESession); +static void +lim_compute_mean_bw_used(tpAniSirGlobal, uint32_t *, uint32_t, tpLimTspecInfo, + tpPESession); +static void lim_get_available_bw(tpAniSirGlobal, uint32_t *, uint32_t *, uint32_t, + uint32_t); +static QDF_STATUS lim_admit_policy_oversubscription(tpAniSirGlobal, + tSirMacTspecIE *, + tpLimAdmitPolicyInfo, + tpLimTspecInfo, + tpPESession); +static QDF_STATUS lim_tspec_find_by_sta_addr(tpAniSirGlobal, uint8_t *, + tSirMacTspecIE *, tpLimTspecInfo, + tpLimTspecInfo *); +static QDF_STATUS lim_validate_access_policy(tpAniSirGlobal, uint8_t, uint16_t, + tpPESession); + +/** ------------------------------------------------------------- + \fn lim_calculate_svc_int + \brief TSPEC validation and servcie interval determination + \param tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \param uint32_t *pSvcInt + \return QDF_STATUS - status of the comparison + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_calculate_svc_int(tpAniSirGlobal pMac, + tSirMacTspecIE *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(tpAniSirGlobal mac_ctx, + tSirMacTspecIE *tspec, tpPESession 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 tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_validate_tspec(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, tpPESession psessionEntry) +{ + QDF_STATUS retval = QDF_STATUS_SUCCESS; + + switch (pTspec->tsinfo.traffic.accessPolicy) { + case SIR_MAC_ACCESSPOLICY_EDCA: + retval = lim_validate_tspec_edca(pMac, pTspec, psessionEntry); +#ifdef WLAN_DEBUG + if (retval != QDF_STATUS_SUCCESS) + pe_warn("EDCA tspec invalid"); +#endif + 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 tpAniSirGlobal pMac + \param uint32_t *pBw + \param uint32_t phyMode + \param tpLimTspecInfo pTspecInfo + \return void + -------------------------------------------------------------*/ + +static void +lim_compute_mean_bw_used(tpAniSirGlobal pMac, + uint32_t *pBw, + uint32_t phyMode, + tpLimTspecInfo pTspecInfo, tpPESession psessionEntry) +{ + uint32_t ctspec; + *pBw = 0; + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (pTspecInfo->inuse) { + tpDphHashNode pSta = + dph_get_hash_entry(pMac, pTspecInfo->assocId, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + /* 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 tpAniSirGlobal pMac + \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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal mac_ctx, + tSirMacTspecIE *tspec, + tpLimAdmitPolicyInfo admit_policy, + tpLimTspecInfo tspec_info, + tpPESession 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 tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +static QDF_STATUS lim_admit_policy(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, + tpPESession psessionEntry) +{ + QDF_STATUS retval = QDF_STATUS_E_FAILURE; + tpLimAdmitPolicyInfo pAdmitPolicy = &pMac->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(pMac, pTspec, + &pMac->lim. + admitPolicyInfo, + &pMac->lim.tspecInfo[0], + psessionEntry); +#ifdef WLAN_DEBUG + if (retval != QDF_STATUS_SUCCESS) + pe_err("rejected by BWFactor policy"); +#endif + 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 tpAniSirGlobal pMac + \param tpLimTspecInfo pInfo + \return void + -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- */ +/* delete the specified tspec */ +static void lim_tspec_delete(tpAniSirGlobal pMac, tpLimTspecInfo pInfo) +{ + if (pInfo == NULL) + 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 tpAniSirGlobal pMac + \param \param uint8_t *pAddr + \param tSirMacTspecIE *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(tpAniSirGlobal pMac, + uint8_t *pAddr, + tSirMacTspecIE *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 + ((uint8_t *) pTspecIE, (uint8_t *) &pTspecList->tspec, + sizeof(tSirMacTspecIE)))) { + *ppInfo = pTspecList; + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_find_by_assoc_id + \brief find tspec with matchin staid and Tspec + \param tpAniSirGlobal pMac + \param uint32_t staid + \param tSirMacTspecIE *pTspecIE + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS +lim_tspec_find_by_assoc_id(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTspecIE *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 + ((uint8_t *) pTspecIE, (uint8_t *) &pTspecList->tspec, + sizeof(tSirMacTspecIE)))) { + *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 tpAniSirGlobal pMac + \param tSirMacTSInfo *pTsInfo + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return QDF_STATUS - status of the comparison + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_find_tspec(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *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 tpAniSirGlobal pMac + \param uint8_t *pAddr + \param uint16_t assocId + \param tSirMacTspecIE *pTspec + \param uint32_t interval + \param tpLimTspecInfo *ppInfo + + \return QDF_STATUS - status of the comparison + -------------------------------------------------------------*/ + +QDF_STATUS lim_tspec_add(tpAniSirGlobal pMac, + uint8_t *pAddr, + uint16_t assocId, + tSirMacTspecIE *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo) +{ + tpLimTspecInfo pTspecList = &pMac->lim.tspecInfo[0]; + *ppInfo = NULL; + + /* validate the assocId */ + if (assocId >= pMac->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(pMac, 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 = &pMac->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 tpAniSirGlobal pMac + \param uint8_t accessPolicy + \param uint16_t assocId + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_validate_access_policy(tpAniSirGlobal pMac, + uint8_t accessPolicy, + uint16_t assocId, tpPESession psessionEntry) +{ + QDF_STATUS retval = QDF_STATUS_E_FAILURE; + tpDphHashNode pSta = + dph_get_hash_entry(pMac, assocId, &psessionEntry->dph.dphHashTable); + + if ((pSta == NULL) || (!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 staId: %d lle: %d wme: %d wsm: %d", + accessPolicy, pSta->staIndex, pSta->lleEnabled, + pSta->wmeEnabled, pSta->wsmEnabled); + + return retval; +} + +/** + * lim_admit_control_add_ts() - Check if STA can be admitted + * @pMac: 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 + * @psessionEntry: 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(tpAniSirGlobal pMac, uint8_t *pAddr, + tSirAddtsReqInfo *pAddts, tSirMacQosCapabilityStaIE *pQos, + uint16_t assocId, uint8_t alloc, tSirMacScheduleIE *pSch, + uint8_t *pTspecIdx, tpPESession psessionEntry) +{ + 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(pMac, assocId, &pAddts->tspec, + &pMac->lim.tspecInfo[0], &pTspecInfo) + : lim_tspec_find_by_sta_addr(pMac, pAddr, &pAddts->tspec, + &pMac->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(pMac, &pAddts->tspec, psessionEntry) != + 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(pMac, &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(pMac, &pAddts->tspec, psessionEntry) != QDF_STATUS_SUCCESS) { + pe_warn("tspec rejected by admit control policy"); + return QDF_STATUS_E_FAILURE; + } + /* fill in a schedule if requested */ + if (pSch != NULL) { + 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 + (pMac, (uint8_t) pAddts->tspec.tsinfo.traffic.accessPolicy, assocId, + psessionEntry) != 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 + (pMac, 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 tpAniSirGlobal pMac + \param uint16_t assocId + \param tSirMacTSInfo *pTsInfo + \param uint8_t *pTsStatus + \param uint8_t *ptspecIdx + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS +lim_admit_control_delete_ts(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *pTsInfo, + uint8_t *pTsStatus, uint8_t *ptspecIdx) +{ + tpLimTspecInfo pTspecInfo = NULL; + + if (pTsStatus != NULL) + *pTsStatus = 0; + + if (lim_find_tspec + (pMac, assocId, pTsInfo, &pMac->lim.tspecInfo[0], + &pTspecInfo) == QDF_STATUS_SUCCESS) { + if (pTspecInfo != NULL) { + pe_debug("Tspec entry: %d found", pTspecInfo->idx); + + *ptspecIdx = pTspecInfo->idx; + lim_tspec_delete(pMac, 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 tpAniSirGlobal pMac + \param uint16_t assocId + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS lim_admit_control_delete_sta(tpAniSirGlobal pMac, uint16_t assocId) +{ + tpLimTspecInfo pTspecInfo = &pMac->lim.tspecInfo[0]; + int ctspec; + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (assocId == pTspecInfo->assocId) { + lim_tspec_delete(pMac, 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 tpAniSirGlobal pMac + \return QDF_STATUS - status + -------------------------------------------------------------*/ +QDF_STATUS lim_admit_control_init(tpAniSirGlobal pMac) +{ + qdf_mem_zero(pMac->lim.tspecInfo, + LIM_NUM_TSPEC_MAX * sizeof(tLimTspecInfo)); + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_update_admit_policy + \brief Set the admit control policy based on CFG parameters + \param tpAniSirGlobal pMac + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS lim_update_admit_policy(tpAniSirGlobal pMac) +{ + uint32_t val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_ADMIT_POLICY, &val) != QDF_STATUS_SUCCESS) { + pe_err("Unable to get CFG_ADMIT_POLICY"); + return QDF_STATUS_E_FAILURE; + } + pMac->lim.admitPolicyInfo.type = (uint8_t) val; + if (wlan_cfg_get_int(pMac, WNI_CFG_ADMIT_BWFACTOR, &val) != QDF_STATUS_SUCCESS) { + pe_err("Unable to get CFG_ADMIT_BWFACTOR"); + return QDF_STATUS_E_FAILURE; + } + pMac->lim.admitPolicyInfo.bw_factor = (uint8_t) val; + + pe_debug("LIM: AdmitPolicy: %d bw_factor: %d", + pMac->lim.admitPolicyInfo.type, + pMac->lim.admitPolicyInfo.bw_factor); + + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_send_hal_msg_add_ts + \brief Send halMsg_AddTs to HAL + \param tpAniSirGlobal pMac + \param uint16_t staIdx + \param uint8_t tspecIdx + \param tSirMacTspecIE 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(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId, uint16_t tsm_interval) +#else +QDF_STATUS +lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, tSirMacTspecIE tspecIE, uint8_t sessionId) +#endif +{ + struct scheduler_msg msg = {0}; + tpAddTsParams pAddTsParam; + + tpPESession psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + + if (psessionEntry == NULL) { + pe_err("Unable to get Session for session Id: %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + + pAddTsParam = qdf_mem_malloc(sizeof(tAddTsParams)); + if (NULL == pAddTsParam) { + pe_err("AllocateMemory() failed"); + return QDF_STATUS_E_NOMEM; + } + + pAddTsParam->staIdx = staIdx; + pAddTsParam->tspecIdx = tspecIdx; + qdf_mem_copy(&pAddTsParam->tspec, &tspecIE, sizeof(tSirMacTspecIE)); + pAddTsParam->sessionId = sessionId; + pAddTsParam->sme_session_id = psessionEntry->smeSessionId; + +#ifdef FEATURE_WLAN_ESE + pAddTsParam->tsm_interval = tsm_interval; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pMac->roam.configParam.isRoamOffloadEnabled && + psessionEntry->is11Rconnection) + pAddTsParam->setRICparams = 1; +#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(pMac, false); + MTRACE(mac_trace_msg_tx(pMac, sessionId, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + pe_warn("wma_post_ctrl_msg() failed"); + SET_LIM_PROCESS_DEFD_MESGS(pMac, 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 tpAniSirGlobal pMac + \param uint16_t staIdx + \param uint8_t tspecIdx + \param tSirAddtsReqInfo addts + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS +lim_send_hal_msg_del_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirDeltsReqInfo delts, uint8_t sessionId, uint8_t *bssId) +{ + struct scheduler_msg msg = {0}; + tpDelTsParams pDelTsParam; + tpPESession psessionEntry = NULL; + + pDelTsParam = qdf_mem_malloc(sizeof(tDelTsParams)); + if (NULL == pDelTsParam) { + pe_err("AllocateMemory() failed"); + return QDF_STATUS_E_NOMEM; + } + + msg.type = WMA_DEL_TS_REQ; + msg.bodyptr = pDelTsParam; + msg.bodyval = 0; + + /* filling message parameters. */ + pDelTsParam->staIdx = staIdx; + pDelTsParam->tspecIdx = tspecIdx; + qdf_mem_copy(&pDelTsParam->bssId, bssId, sizeof(tSirMacAddr)); + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + if (psessionEntry == NULL) { + pe_err("Session does Not exist with given sessionId: %d", + sessionId); + goto err; + } + pDelTsParam->sessionId = psessionEntry->smeSessionId; + pDelTsParam->userPrio = delts.wmeTspecPresent ? + delts.tspec.tsinfo.traffic.userPrio : + delts.tsinfo.traffic.userPrio; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pMac->roam.configParam.isRoamOffloadEnabled && + psessionEntry->is11Rconnection) { + qdf_mem_copy(&pDelTsParam->delTsInfo, &delts, + sizeof(tSirDeltsReqInfo)); + pDelTsParam->setRICparams = 1; + } +#endif + MTRACE(mac_trace_msg_tx(pMac, sessionId, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(pMac, &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 tpAniSirGlobal pMac + \param struct scheduler_msg *limMsg + -------------------------------------------------------------*/ +void lim_process_hal_add_ts_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsg) +{ + tpAddTsParams pAddTsRspMsg = NULL; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + tpPESession psessionEntry = NULL; + + /* Need to process all the deferred messages enqueued + * since sending the WMA_ADD_TS_REQ. + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + + if (NULL == limMsg->bodyptr) { + pe_err("Received WMA_ADD_TS_RSP with NULL"); + goto end; + } + + pAddTsRspMsg = (tpAddTsParams) (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 */ + psessionEntry = pe_find_session_by_session_id(pMac, pAddTsRspMsg->sessionId); + + if (psessionEntry == NULL) { + pe_err("Session does Not exist with given sessionId: %d", + pAddTsRspMsg->sessionId); + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + psessionEntry, pAddTsRspMsg->tspec, + pMac->lim.gLimAddtsReq.sessionId, + pMac->lim.gLimAddtsReq.transactionId); + 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(pMac, rspReqd, eSIR_SME_SUCCESS, + psessionEntry, pAddTsRspMsg->tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + 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, psessionEntry->bssId); + + /* 090803: Add the SME Session ID */ + lim_send_delts_req_action_frame(pMac, peerMacAddr, rspReqd, + &pAddTsRspMsg->tspec.tsinfo, + &pAddTsRspMsg->tspec, psessionEntry); + + /* Delete TSPEC */ + /* 090803: Pull the hash table from the session */ + pSta = dph_lookup_assoc_id(pMac, pAddTsRspMsg->staIdx, &assocId, + &psessionEntry->dph.dphHashTable); + if (pSta != NULL) + lim_admit_control_delete_ts(pMac, assocId, + &pAddTsRspMsg->tspec.tsinfo, + NULL, + (uint8_t *) &pAddTsRspMsg-> + tspecIdx); + + /* Send SME_ADDTS_RSP */ + /* 090803: Use the smesessionId and smetransactionId from the PE session context */ + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + psessionEntry, pAddTsRspMsg->tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + goto end; + } + +end: + if (pAddTsRspMsg != NULL) + qdf_mem_free(pAddTsRspMsg); + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..8308724135652052fc1849c1c3f3545677565b52 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2011-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. + */ + +/* + * + * 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 "cfg_api.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" + +#define LIM_START_PEER_IDX 1 + +/** + * lim_init_peer_idxpool() -- initializes peer index pool + * @pMac: mac context + * @pSessionEntry: session entry + * + * This function is called while starting a BSS at AP + * to initialize AID pool. This may also be called while + * starting/joining an IBSS if 'Association' is allowed + * in IBSS. + * + * Return: None + */ + +void lim_init_peer_idxpool(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + uint8_t i; + uint8_t maxAssocSta = pMac->lim.maxStation; + + pSessionEntry->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(pSessionEntry)) { + pSessionEntry->freePeerIdxHead = DPH_STA_HASH_INDEX_PEER + 1; + } else +#endif +#ifdef QCA_IBSS_SUPPORT + if (LIM_IS_IBSS_ROLE(pSessionEntry)) { + pSessionEntry->freePeerIdxHead = LIM_START_PEER_IDX; + } else +#endif + { + pSessionEntry->freePeerIdxHead = LIM_START_PEER_IDX; + } + + for (i = pSessionEntry->freePeerIdxHead; i < maxAssocSta; i++) { + pSessionEntry->gpLimPeerIdxpool[i] = i + 1; + } + pSessionEntry->gpLimPeerIdxpool[i] = 0; + + pSessionEntry->freePeerIdxTail = i; + +} + +/** + * 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 pMac - Pointer to Global MAC structure + * @return peerIdx - assigned peer Station IDx for STA + */ + +uint16_t lim_assign_peer_idx(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + uint16_t peerId; + + /* 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(pMac) >= pMac->lim.gLimAssocStaLimit) { + /* too many associations already active */ + return 0; + } + + /* return head of free list */ + + if (pSessionEntry->freePeerIdxHead) { + peerId = pSessionEntry->freePeerIdxHead; + pSessionEntry->freePeerIdxHead = + pSessionEntry->gpLimPeerIdxpool[pSessionEntry-> + freePeerIdxHead]; + if (pSessionEntry->freePeerIdxHead == 0) + pSessionEntry->freePeerIdxTail = 0; + pSessionEntry->gLimNumOfCurrentSTAs++; + return peerId; + } + + return 0; /* no more free peer index */ +} + +/** + * lim_release_peer_idx() + * + ***FUNCTION: + * This function is called when a STA context is removed + * at AP (or at a STA in IBSS mode or TDLS) to return peer Index + * to free pool. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param peerIdx - peer station index that need to return to free pool + * + * @return None + */ + +void +lim_release_peer_idx(tpAniSirGlobal pMac, uint16_t peerIdx, + tpPESession pSessionEntry) +{ + pSessionEntry->gLimNumOfCurrentSTAs--; + + /* insert at tail of free list */ + if (pSessionEntry->freePeerIdxTail) { + pSessionEntry->gpLimPeerIdxpool[pSessionEntry-> + freePeerIdxTail] = + (uint8_t) peerIdx; + pSessionEntry->freePeerIdxTail = (uint8_t) peerIdx; + } else { + pSessionEntry->freePeerIdxTail = + pSessionEntry->freePeerIdxHead = (uint8_t) peerIdx; + } + pSessionEntry->gpLimPeerIdxpool[(uint8_t) peerIdx] = 0; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c new file mode 100644 index 0000000000000000000000000000000000000000..e32c90698d3851e950851586bdfdd68ec2de2eab --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c @@ -0,0 +1,2836 @@ +/* + * 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_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 "cfg_api.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_ibss_peer_mgmt.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 "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" + +static void __lim_init_bss_vars(tpAniSirGlobal pMac) +{ + qdf_mem_zero((void *)pMac->lim.gpSession, + sizeof(*pMac->lim.gpSession) * pMac->lim.maxBssId); + + /* This is for testing purposes only, be default should always be off */ + pMac->lim.gpLimMlmSetKeysReq = NULL; +} + +static void __lim_init_stats_vars(tpAniSirGlobal pMac) +{ + pMac->lim.gLimNumBeaconsRcvd = 0; + pMac->lim.gLimNumBeaconsIgnored = 0; + + pMac->lim.gLimNumDeferredMsgs = 0; + + /* / Variable to keep track of number of currently associated STAs */ + pMac->lim.gLimNumOfAniSTAs = 0; /* count of ANI peers */ + + /* Heart-Beat interval value */ + pMac->lim.gLimHeartBeatCount = 0; + + qdf_mem_zero(pMac->lim.gLimHeartBeatApMac[0], + sizeof(tSirMacAddr)); + qdf_mem_zero(pMac->lim.gLimHeartBeatApMac[1], + sizeof(tSirMacAddr)); + pMac->lim.gLimHeartBeatApMacIndex = 0; + + /* Statistics to keep track of no. beacons rcvd in heart beat interval */ + qdf_mem_zero(pMac->lim.gLimHeartBeatBeaconStats, + sizeof(pMac->lim.gLimHeartBeatBeaconStats)); + +#ifdef WLAN_DEBUG + /* Debug counters */ + pMac->lim.numTot = 0; + pMac->lim.numBbt = 0; + pMac->lim.numProtErr = 0; + pMac->lim.numLearn = 0; + pMac->lim.numLearnIgnore = 0; + pMac->lim.numSme = 0; + qdf_mem_zero(pMac->lim.numMAC, sizeof(pMac->lim.numMAC)); + pMac->lim.gLimNumAssocReqDropInvldState = 0; + pMac->lim.gLimNumAssocReqDropACRejectTS = 0; + pMac->lim.gLimNumAssocReqDropACRejectSta = 0; + pMac->lim.gLimNumReassocReqDropInvldState = 0; + pMac->lim.gLimNumHashMissIgnored = 0; + pMac->lim.gLimUnexpBcnCnt = 0; + pMac->lim.gLimBcnSSIDMismatchCnt = 0; + pMac->lim.gLimNumLinkEsts = 0; + pMac->lim.gLimNumRxCleanup = 0; + pMac->lim.gLim11bStaAssocRejectCount = 0; +#endif +} + +static void __lim_init_states(tpAniSirGlobal pMac) +{ + /* Counts Heartbeat failures */ + pMac->lim.gLimHBfailureCntInLinkEstState = 0; + pMac->lim.gLimProbeFailureAfterHBfailedCnt = 0; + pMac->lim.gLimHBfailureCntInOtherStates = 0; + pMac->lim.gLimRspReqd = 0; + pMac->lim.gLimPrevSmeState = eLIM_SME_OFFLINE_STATE; + + /* / MLM State visible across all Sirius modules */ + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, NO_SESSION, eLIM_MLM_IDLE_STATE)); + pMac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + + /* / Previous MLM State */ + pMac->lim.gLimPrevMlmState = eLIM_MLM_OFFLINE_STATE; + + /** + * Initialize state to eLIM_SME_OFFLINE_STATE + */ + pMac->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(&pMac->lim.gLimNoShortParams, sizeof(tLimNoShortParams)); + qdf_mem_zero(&pMac->lim.gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams)); + + pMac->lim.gLimPhyMode = 0; + pMac->lim.gLimProbeRespDisableFlag = 0; /* control over probe resp */ +} + +static void __lim_init_vars(tpAniSirGlobal pMac) +{ + /* Place holder for Measurement Req/Rsp/Ind related info */ + + + /* Deferred Queue Parameters */ + qdf_mem_zero(&pMac->lim.gLimDeferredMsgQ, sizeof(tSirAddtsReq)); + + /* addts request if any - only one can be outstanding at any time */ + qdf_mem_zero(&pMac->lim.gLimAddtsReq, sizeof(tSirAddtsReq)); + pMac->lim.gLimAddtsSent = 0; + pMac->lim.gLimAddtsRspTimerCount = 0; + + /* protection related config cache */ + qdf_mem_zero(&pMac->lim.cfgProtection, sizeof(tCfgProtection)); + pMac->lim.gLimProtectionControl = 0; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + + /* WMM Related Flag */ + pMac->lim.gUapsdEnable = 0; + + /* QoS-AC Downgrade: Initially, no AC is admitted */ + pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] = 0; + pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] = 0; + + /* dialogue token List head/tail for Action frames request sent. */ + pMac->lim.pDialogueTokenHead = NULL; + pMac->lim.pDialogueTokenTail = NULL; + + qdf_mem_zero(&pMac->lim.tspecInfo, + sizeof(tLimTspecInfo) * LIM_NUM_TSPEC_MAX); + + /* admission control policy information */ + qdf_mem_zero(&pMac->lim.admitPolicyInfo, sizeof(tLimAdmitPolicyInfo)); +} + +static void __lim_init_assoc_vars(tpAniSirGlobal pMac) +{ + pMac->lim.gLimAssocStaLimit = 0; + pMac->lim.gLimIbssStaLimit = 0; + /* Place holder for current authentication request */ + /* being handled */ + pMac->lim.gpLimMlmAuthReq = NULL; + + /* / MAC level Pre-authentication related globals */ + pMac->lim.gLimPreAuthChannelNumber = 0; + pMac->lim.gLimPreAuthType = eSIR_OPEN_SYSTEM; + qdf_mem_zero(&pMac->lim.gLimPreAuthPeerAddr, sizeof(tSirMacAddr)); + pMac->lim.gLimNumPreAuthContexts = 0; + qdf_mem_zero(&pMac->lim.gLimPreAuthTimerTable, + sizeof(tLimPreAuthTable)); + + /* Placed holder to deauth reason */ + pMac->lim.gLimDeauthReasonCode = 0; + + /* Place holder for Pre-authentication node list */ + pMac->lim.pLimPreAuthList = NULL; + + /* One cache for each overlap and associated case. */ + qdf_mem_zero(pMac->lim.protStaOverlapCache, + sizeof(tCacheParams) * LIM_PROT_STA_OVERLAP_CACHE_SIZE); + qdf_mem_zero(pMac->lim.protStaCache, + sizeof(tCacheParams) * LIM_PROT_STA_CACHE_SIZE); + + pMac->lim.pSessionEntry = NULL; + pMac->lim.reAssocRetryAttempt = 0; + +} + +static void __lim_init_ht_vars(tpAniSirGlobal pMac) +{ + pMac->lim.htCapabilityPresentInBeacon = 0; + pMac->lim.gHTGreenfield = 0; + pMac->lim.gHTShortGI40Mhz = 0; + pMac->lim.gHTShortGI20Mhz = 0; + pMac->lim.gHTMaxAmsduLength = 0; + pMac->lim.gHTDsssCckRate40MHzSupport = 0; + pMac->lim.gHTPSMPSupport = 0; + pMac->lim.gHTLsigTXOPProtection = 0; + pMac->lim.gHTMIMOPSState = eSIR_HT_MIMO_PS_STATIC; + pMac->lim.gHTAMpduDensity = 0; + + pMac->lim.gMaxAmsduSizeEnabled = false; + pMac->lim.gHTMaxRxAMpduFactor = 0; + pMac->lim.gHTServiceIntervalGranularity = 0; + pMac->lim.gHTControlledAccessOnly = 0; + pMac->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + pMac->lim.gHTPCOActive = 0; + + pMac->lim.gHTPCOPhase = 0; + pMac->lim.gHTSecondaryBeacon = 0; + pMac->lim.gHTDualCTSProtection = 0; + pMac->lim.gHTSTBCBasicMCS = 0; +} + +static QDF_STATUS __lim_init_config(tpAniSirGlobal pMac) +{ + uint32_t val1, val2, val3; + uint16_t val16; + uint8_t val8; + tSirMacHTCapabilityInfo *pHTCapabilityInfo; + tSirMacHTInfoField1 *pHTInfoField1; + tSirMacHTParametersInfo *pAmpduParamInfo; + + /* 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 + */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val1) + != QDF_STATUS_SUCCESS){ + pe_err("cfg get assoc sta limit failed"); + return QDF_STATUS_E_FAILURE; + } + + pMac->lim.gLimAssocStaLimit = val1; + pMac->lim.gLimIbssStaLimit = val1; + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve HT Cap CFG"); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_CHANNEL_BONDING_MODE, &val2) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve Channel Bonding CFG"); + return QDF_STATUS_E_FAILURE; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + + /* 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) */ + pHTCapabilityInfo->supportedChannelWidthSet = val2 ? + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE : + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, *(uint16_t *) pHTCapabilityInfo) + != QDF_STATUS_SUCCESS) { + pe_err("could not update HT Cap Info CFG"); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD1, &val1) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve HT INFO Field1 CFG"); + return QDF_STATUS_E_FAILURE; + } + + val8 = (uint8_t) val1; + pHTInfoField1 = (tSirMacHTInfoField1 *) &val8; + pHTInfoField1->recommendedTxWidthSet = + (uint8_t) pHTCapabilityInfo->supportedChannelWidthSet; + if (cfg_set_int(pMac, WNI_CFG_HT_INFO_FIELD1, *(uint8_t *) pHTInfoField1) + != QDF_STATUS_SUCCESS) { + pe_err("could not update HT Info Field"); + return QDF_STATUS_E_FAILURE; + } + + /* WNI_CFG_HEART_BEAT_THRESHOLD */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, &val1) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve WNI_CFG_HEART_BEAT_THRESHOLD CFG"); + return QDF_STATUS_E_FAILURE; + } + if (!val1) { + pMac->sys.gSysEnableLinkMonitorMode = 0; + } else { + /* No need to activate the timer during init time. */ + pMac->sys.gSysEnableLinkMonitorMode = 1; + } + + /* WNI_CFG_MAX_RX_AMPDU_FACTOR */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve HT AMPDU Param"); + return QDF_STATUS_E_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_RX_AMPDU_FACTOR, &val2) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve AMPDU Factor CFG"); + return QDF_STATUS_E_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MPDU_DENSITY, &val3) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve MPDU Density CFG"); + return QDF_STATUS_E_FAILURE; + } + + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->maxRxAMPDUFactor = (uint8_t) val2; + pAmpduParamInfo->mpduDensity = (uint8_t)val3; + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != QDF_STATUS_SUCCESS) { + pe_err("cfg get short preamble failed"); + return QDF_STATUS_E_FAILURE; + } + + /* WNI_CFG_SHORT_PREAMBLE - this one is not updated in + lim_handle_cf_gparam_update do we want to update this? */ + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val1) != QDF_STATUS_SUCCESS) { + pe_err("cfg get short preamble failed"); + return QDF_STATUS_E_FAILURE; + } + + /* 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(pMac, NULL); + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + (uint32_t *) &pMac->lim.disableLDPCWithTxbfAP)) { + pe_err("cfg get disableLDPCWithTxbfAP failed"); + return QDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_TDLS + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_TDLS_BUF_STA_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSBufStaEnabled)) { + pe_err("cfg get LimTDLSBufStaEnabled failed"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + (uint32_t *) &pMac->lim.gLimTDLSUapsdMask)) { + pe_err("cfg get LimTDLSUapsdMask failed"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSOffChannelEnabled)) { + pe_err("cfg get LimTDLSUapsdMask failed"); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_TDLS_WMM_MODE_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSWmmMode)) { + pe_err("cfg get LimTDLSWmmMode failed"); + return QDF_STATUS_E_FAILURE; + } +#endif + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(pMac, + WNI_CFG_OBSS_DETECTION_OFFLOAD, + (uint32_t *)&pMac->lim. + global_obss_offload_enabled)) { + pe_err("cfg get obss_detection_offloaded failed"); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_OBSS_COLOR_COLLISION_OFFLOAD, + (uint32_t *) &pMac->lim. + global_obss_color_collision_det_offload)) { + pe_err("cfg get obss_color_collision_offload failed"); + return QDF_STATUS_E_FAILURE; + } + + 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(tpAniSirGlobal pMac) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + pe_debug("enter"); + + if (pMac->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) { + pMac->lim.gLimSmeState = eLIM_SME_IDLE_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, NO_SESSION, + pMac->lim.gLimSmeState)); + + /* Initialize MLM state machine */ + if (QDF_STATUS_SUCCESS != lim_init_mlm(pMac)) { + 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", + pMac->lim.gLimSmeState); + retCode = QDF_STATUS_E_FAILURE; + } + + pMac->lim.req_id = + ucfg_scan_register_requester(pMac->psoc, + "LIM", + lim_process_rx_scan_handler, + pMac); + 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 pMac - Pointer to global MAC structure + * @return None + */ + +QDF_STATUS lim_initialize(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pMac->lim.mgmtFrameSessionId = NO_SESSION; + pMac->lim.tdls_frm_session_id = NO_SESSION; + pMac->lim.deferredMsgCnt = 0; + pMac->lim.retry_packet_cnt = 0; + pMac->lim.ibss_retry_cnt = 0; + pMac->lim.deauthMsgCnt = 0; + pMac->lim.disassocMsgCnt = 0; + + if (QDF_IS_STATUS_ERROR(qdf_mutex_create( + &pMac->lim.lkPeGlobalLock))) { + pe_err("lim lock init failed!"); + return QDF_STATUS_E_FAILURE; + } + + __lim_init_assoc_vars(pMac); + __lim_init_vars(pMac); + __lim_init_states(pMac); + __lim_init_stats_vars(pMac); + __lim_init_bss_vars(pMac); + __lim_init_ht_vars(pMac); + + /* Initializations for maintaining peers in IBSS */ + lim_ibss_init(pMac); + + rrm_initialize(pMac); + + if (QDF_IS_STATUS_ERROR(qdf_mutex_create( + &pMac->lim.lim_frame_register_lock))) { + pe_err("lim lock init failed!"); + qdf_mutex_destroy(&pMac->lim.lkPeGlobalLock); + return QDF_STATUS_E_FAILURE; + } + + qdf_list_create(&pMac->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(pMac); + 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 pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_cleanup(tpAniSirGlobal pMac) +{ + 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( + &pMac->lim.gLimMgmtFrameRegistratinQueue, + &lst_node) == QDF_STATUS_SUCCESS) { + qdf_mem_free(lst_node); + } + qdf_list_destroy(&pMac->lim.gLimMgmtFrameRegistratinQueue); + qdf_mutex_destroy(&pMac->lim.lim_frame_register_lock); + + pe_deregister_mgmt_rx_frm_callback(pMac); + + qdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + + /* free up preAuth table */ + if (pMac->lim.gLimPreAuthTimerTable.pTable != NULL) { + for (i = 0; i < pMac->lim.gLimPreAuthTimerTable.numEntry; i++) + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable[i]); + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable); + pMac->lim.gLimPreAuthTimerTable.pTable = NULL; + pMac->lim.gLimPreAuthTimerTable.numEntry = 0; + } + + if (NULL != pMac->lim.pDialogueTokenHead) { + lim_delete_dialogue_token_list(pMac); + } + + if (NULL != pMac->lim.pDialogueTokenTail) { + qdf_mem_free(pMac->lim.pDialogueTokenTail); + pMac->lim.pDialogueTokenTail = NULL; + } + + if (pMac->lim.gpLimMlmSetKeysReq != NULL) { + qdf_mem_zero(pMac->lim.gpLimMlmSetKeysReq, + sizeof(tLimMlmSetKeysReq)); + qdf_mem_free(pMac->lim.gpLimMlmSetKeysReq); + pMac->lim.gpLimMlmSetKeysReq = NULL; + } + + if (pMac->lim.gpLimMlmAuthReq != NULL) { + qdf_mem_free(pMac->lim.gpLimMlmAuthReq); + pMac->lim.gpLimMlmAuthReq = NULL; + } + + if (pMac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq) { + qdf_mem_free(pMac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq); + pMac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + } + + if (pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) { + qdf_mem_free(pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq); + pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } + + /* Now, finally reset the deferred message queue pointers */ + lim_reset_deferred_msg_q(pMac); + + rrm_cleanup(pMac); + + lim_ft_cleanup_all_ft_sessions(pMac); + + ucfg_scan_unregister_requester(pMac->psoc, pMac->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) +{ + tHalHandle hal; + tpAniSirGlobal mac; + uint16_t len = 0; + char *buf = *buf_ptr; + + hal = cds_get_context(QDF_MODULE_ID_PE); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + + 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_CONVERGENCE +static void lim_nan_register_callbacks(tpAniSirGlobal 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); +} +#endif + +/* + * pe_shutdown_notifier_cb - Shutdown notifier callback + * @ctx: Pointer to Global MAC structure + * + * Return: None + */ +static void pe_shutdown_notifier_cb(void *ctx) +{ + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)ctx; + tpPESession 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); + } + } +} + +#ifdef WLAN_FEATURE_11W +/** + * is_mgmt_protected - check RMF enabled for the peer + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address + * + * The function check the mgmt frame protection enabled or not + * for station mode and AP mode + * + * Return: true, if the connection is RMF enabled. + */ +static bool is_mgmt_protected(uint32_t vdev_id, + const uint8_t *peer_mac_addr) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tpPESession session; + bool protected = false; + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return false; + + session = pe_find_session_by_sme_session_id(mac_ctx, + vdev_id); + if (!session) { + /* couldn't find session */ + pe_err("Session not found for vdev_id: %d", vdev_id); + return false; + } + + if (LIM_IS_AP_ROLE(session)) { + 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; + } + } else if (session->limRmfEnabled && + session->is_key_installed) { + protected = true; + } + + return protected; +} +#else +/** + * is_mgmt_protected - check RMF enabled for the peer + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address + * + * The function check the mgmt frame protection enabled or not + * for station mode and AP mode + * + * Return: true, if the connection is RMF enabled. + */ +static bool is_mgmt_protected(uint32_t vdev_id, + const uint8_t *peer_mac_addr) +{ + return false; +} +#endif + +static void p2p_register_callbacks(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal 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; +} + +/** ------------------------------------------------------------- + \fn pe_open + \brief will be called in Open sequence from mac_open + \param tpAniSirGlobal pMac + \param tHalOpenParameters *pHalOpenParam + \return QDF_STATUS + -------------------------------------------------------------*/ + +QDF_STATUS pe_open(tpAniSirGlobal pMac, 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; + + pMac->lim.maxBssId = cds_cfg->max_bssid; + pMac->lim.maxStation = cds_cfg->max_station; + qdf_spinlock_create(&pMac->sys.bbt_mgmt_lock); + + if ((pMac->lim.maxBssId == 0) || (pMac->lim.maxStation == 0)) { + pe_err("max number of Bssid or Stations cannot be zero!"); + return QDF_STATUS_E_FAILURE; + } + + pMac->lim.limTimers.gpLimCnfWaitTimer = + qdf_mem_malloc(sizeof(TX_TIMER) * (pMac->lim.maxStation + 1)); + if (NULL == pMac->lim.limTimers.gpLimCnfWaitTimer) { + pe_err("gpLimCnfWaitTimer memory allocate failed!"); + return QDF_STATUS_E_NOMEM; + } + + pMac->lim.gpSession = + qdf_mem_malloc(sizeof(tPESession) * pMac->lim.maxBssId); + if (NULL == pMac->lim.gpSession) { + pe_err("gpSession memory allocate failed!"); + status = QDF_STATUS_E_NOMEM; + goto pe_open_psession_fail; + } + + status = lim_initialize(pMac); + 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(pMac)); +#endif + lim_register_debug_callback(); +#ifdef WLAN_FEATURE_NAN_CONVERGENCE + lim_nan_register_callbacks(pMac); +#endif + p2p_register_callbacks(pMac); + lim_register_sap_bcn_callback(pMac); + + if (!QDF_IS_STATUS_SUCCESS( + cds_shutdown_notifier_register(pe_shutdown_notifier_cb, pMac))) { + pe_err("%s: Shutdown notifier register failed", __func__); + } + + return status; /* status here will be QDF_STATUS_SUCCESS */ + +pe_open_lock_fail: + qdf_mem_free(pMac->lim.gpSession); + pMac->lim.gpSession = NULL; +pe_open_psession_fail: + qdf_mem_free(pMac->lim.limTimers.gpLimCnfWaitTimer); + pMac->lim.limTimers.gpLimCnfWaitTimer = NULL; + + return status; +} + +/** ------------------------------------------------------------- + \fn pe_close + \brief will be called in close sequence from mac_close + \param tpAniSirGlobal pMac + \return QDF_STATUS + -------------------------------------------------------------*/ + +QDF_STATUS pe_close(tpAniSirGlobal pMac) +{ + uint8_t i; + + if (ANI_DRIVER_TYPE(pMac) == QDF_DRIVER_TYPE_MFG) + return QDF_STATUS_SUCCESS; + + lim_cleanup(pMac); + lim_unregister_sap_bcn_callback(pMac); + + if (pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) { + qdf_mem_free(pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq); + pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } + + qdf_spinlock_destroy(&pMac->sys.bbt_mgmt_lock); + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) + pe_delete_session(pMac, &pMac->lim.gpSession[i]); + } + qdf_mem_free(pMac->lim.limTimers.gpLimCnfWaitTimer); + pMac->lim.limTimers.gpLimCnfWaitTimer = NULL; + + qdf_mem_free(pMac->lim.gpSession); + pMac->lim.gpSession = NULL; + if (!QDF_IS_STATUS_SUCCESS + (qdf_mutex_destroy(&pMac->lim.lkPeGlobalLock))) { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn pe_start + \brief will be called in start sequence from mac_start + \param tpAniSirGlobal pMac + \return QDF_STATUS_SUCCESS on success, other QDF_STATUS on error + -------------------------------------------------------------*/ + +QDF_STATUS pe_start(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + status = lim_start(pMac); + 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(pMac)) { + pe_err("lim init config failed!"); + /* We need to undo everything in lim_start */ + lim_cleanup_mlm(pMac); + return QDF_STATUS_E_FAILURE; + } + /* Initialize the configurations needed by PE */ + lim_register_hal_ind_call_back(pMac); + return status; +} + +/** ------------------------------------------------------------- + \fn pe_stop + \brief will be called in stop sequence from mac_stop + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +void pe_stop(tpAniSirGlobal pMac) +{ + lim_cleanup_mlm(pMac); + pe_debug(" PE STOP: Set LIM state to eLIM_MLM_OFFLINE_STATE"); + SET_LIM_MLM_STATE(pMac, eLIM_MLM_OFFLINE_STATE); + return; +} + +static void pe_free_nested_messages(struct scheduler_msg *msg) +{ + switch (msg->type) { + case WMA_SET_LINK_STATE_RSP: + pe_debug("pe_free_nested_messages: WMA_SET_LINK_STATE_RSP"); + qdf_mem_free(((tpLinkStateParams) msg->bodyptr)->callbackArg); + break; + 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 tpAniSirGlobal pMac + \param struct scheduler_msg pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(tpAniSirGlobal pMac, struct scheduler_msg *pMsg) +{ + if (pMsg != NULL) { + if (NULL != 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(tpAniSirGlobal 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(tpAniSirGlobal 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) +{ + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (mac_ctx == NULL) + return QDF_STATUS_E_FAILURE; + + if (ANI_DRIVER_TYPE(mac_ctx) == QDF_DRIVER_TYPE_MFG) + return QDF_STATUS_SUCCESS; + + /* + * If the Message to be handled is for CFG Module call the CFG Msg + * Handler and for all the other cases post it to LIM + */ + if (SIR_CFG_PARAM_UPDATE_IND != msg->type && IS_CFG_MSG(msg->type)) + cfg_process_mb_msg(mac_ctx, msg->bodyptr); + else + 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(tpAniSirGlobal 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)) { +#ifdef WLAN_DEBUG + 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); +#endif + 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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + uint8_t *rx_pkt_info) +{ + uint8_t session_id; + uint8_t *body; + const uint8_t *ssid_ie; + uint16_t frame_len; + struct mgmt_beacon_probe_filter *filter; + tpSirMacCapabilityInfo bcn_caps; + tSirMacSSid bcn_ssid; + + 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 < SIR_MAX_SUPPORTED_BSS; + session_id++) { + if (sir_compare_mac_addr(filter->sta_bssid[session_id], + hdr->bssId)) { + return true; + } + } + } + + /* + * If any IBSS session exists and beacon is has IBSS capability set + * and SSID matches the IBSS SSID, allow the frame + */ + if (filter->num_ibss_sessions) { + body = 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 false; + + bcn_caps = (tpSirMacCapabilityInfo) + (body + SIR_MAC_B_PR_CAPAB_OFFSET); + if (!bcn_caps->ibss) + return false; + + ssid_ie = wlan_get_ie_ptr_from_eid(SIR_MAC_SSID_EID, + body + SIR_MAC_B_PR_SSID_OFFSET, + frame_len); + + if (!ssid_ie) + return false; + + bcn_ssid.length = ssid_ie[1]; + qdf_mem_copy(&bcn_ssid.ssId, + &ssid_ie[2], + bcn_ssid.length); + + for (session_id = 0; session_id < SIR_MAX_SUPPORTED_BSS; + session_id++) { + if (filter->ibss_ssid[session_id].length == + bcn_ssid.length && + (!qdf_mem_cmp(filter->ibss_ssid[session_id].ssId, + bcn_ssid.ssId, bcn_ssid.length))) { + return true; + } + } + } + + return false; +} + +static QDF_STATUS pe_handle_probe_req_frames(tpAniSirGlobal 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); + + if (!QDF_IS_STATUS_SUCCESS(status)) + pe_err_rl("Failed to post probe req frame to Scan Queue"); + + 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) +{ + tpAniSirGlobal pMac; + tpSirMacMgmtHdr mHdr; + struct scheduler_msg msg = {0}; + cds_pkt_t *pVosPkt; + QDF_STATUS qdf_status; + uint8_t *pRxPacketInfo; + int ret; + + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == pMac) { + /* cannot log a failure without a valid pMac */ + qdf_nbuf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + pVosPkt = qdf_mem_malloc_atomic(sizeof(*pVosPkt)); + if (!pVosPkt) { + pe_debug_rl("Failed to allocate rx packet"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_NOMEM; + } + + ret = wma_form_rx_packet(buf, mgmt_rx_params, pVosPkt); + if (ret) { + pe_err_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, false); + + 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(pMac, 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(pMac, 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(pMac, 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(pMac, + &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(pMac); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void pe_register_mgmt_rx_frm_callback(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal pMac, + tSirSmeReadyReq *ready_req) +{ + QDF_STATUS status; + + status = wma_register_roaming_callbacks( + ready_req->csr_roam_synch_cb, + ready_req->pe_roam_synch_cb); + if (status != QDF_STATUS_SUCCESS) + pe_err("Registering roaming callbacks with WMA failed"); +} + +/** + * lim_is_system_in_scan_state() + * + ***FUNCTION: + * This function is called by various MAC software modules to + * determine if System is in Scan/Learn state + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return true - System is in Scan/Learn state + * false - System is NOT in Scan/Learn state + */ + +uint8_t lim_is_system_in_scan_state(tpAniSirGlobal pMac) +{ + switch (pMac->lim.gLimSmeState) { + case eLIM_SME_CHANNEL_SCAN_STATE: + case eLIM_SME_NORMAL_CHANNEL_SCAN_STATE: + case eLIM_SME_LINK_EST_WT_SCAN_STATE: + case eLIM_SME_WT_SCAN_STATE: + /* System is in Learn mode */ + return true; + + default: + /* System is NOT in Learn mode */ + return false; + } +} /*** end lim_is_system_in_scan_state() ***/ + +/** + *\brief 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. + * + * param pMac - global mac structure + * param channel - channel number indicated in Beacon, Probe Response + * return - none + */ + +void +lim_received_hb_handler(tpAniSirGlobal pMac, uint8_t channelId, + tpPESession psessionEntry) +{ + if ((channelId == 0) + || (channelId == psessionEntry->currentOperChannel)) + psessionEntry->LimRxedBeaconCntDuringHB++; + + psessionEntry->pmmOffloadInfo.bcnmiss = false; +} /*** lim_init_wds_info_params() ***/ + +/** ------------------------------------------------------------- + \fn lim_update_overlap_sta_param + \brief Updates overlap cache and param data structure + \param tpAniSirGlobal pMac + \param tSirMacAddr bssId + \param tpLimProtStaParams pStaParams + \return None + -------------------------------------------------------------*/ +void +lim_update_overlap_sta_param(tpAniSirGlobal pMac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams) +{ + int i; + + if (!pStaParams->numSta) { + qdf_mem_copy(pMac->lim.protStaOverlapCache[0].addr, + bssId, sizeof(tSirMacAddr)); + pMac->lim.protStaOverlapCache[0].active = true; + + pStaParams->numSta = 1; + + return; + } + + for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) { + if (pMac->lim.protStaOverlapCache[i].active) { + if (!qdf_mem_cmp + (pMac->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(pMac->lim.protStaOverlapCache[i].addr, + bssId, sizeof(tSirMacAddr)); + pMac->lim.protStaOverlapCache[i].active = true; + + pStaParams->numSta++; + } +} + +/** + * lim_ibss_enc_type_matched + * + ***FUNCTION: + * This function compares the encryption type of the peer with self + * while operating in IBSS mode and detects mismatch. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pBeacon - Parsed Beacon Frame structure + * @param pSession - Pointer to the PE session + * + * @return true if encryption type is matched; false otherwise + */ +static bool lim_ibss_enc_type_matched(tpSchBeaconStruct pBeacon, + tpPESession pSession) +{ + if (!pBeacon || !pSession) + return false; + + /* Open case */ + if (pBeacon->capabilityInfo.privacy == 0 + && pSession->encryptType == eSIR_ED_NONE) + return true; + + /* WEP case */ + if (pBeacon->capabilityInfo.privacy == 1 && pBeacon->wpaPresent == 0 + && pBeacon->rsnPresent == 0 + && (pSession->encryptType == eSIR_ED_WEP40 + || pSession->encryptType == eSIR_ED_WEP104)) + return true; + + /* WPA-None case */ + if (pBeacon->capabilityInfo.privacy == 1 && pBeacon->wpaPresent == 1 + && pBeacon->rsnPresent == 0 + && ((pSession->encryptType == eSIR_ED_CCMP) || + (pSession->encryptType == eSIR_ED_GCMP) || + (pSession->encryptType == eSIR_ED_GCMP_256) || + (pSession->encryptType == eSIR_ED_TKIP))) + return true; + + return false; +} + +/** + * lim_handle_ibs_scoalescing() + * + ***FUNCTION: + * This function is called upon receiving Beacon/Probe Response + * while operating in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pRxPacketInfo - Pointer to RX packet info structure + * + * @return Status whether to process or ignore received Beacon Frame + */ + +QDF_STATUS +lim_handle_ibss_coalescing(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + uint8_t *pRxPacketInfo, tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + QDF_STATUS retCode; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + /* Ignore the beacon when any of the conditions below is met: + 1. The beacon claims no IBSS network + 2. SSID in the beacon does not match SSID of self station + 3. Operational channel in the beacon does not match self station + 4. Encyption type in the beacon does not match with self station + */ + if ((!pBeacon->capabilityInfo.ibss) || + lim_cmp_ssid(&pBeacon->ssId, psessionEntry) || + (psessionEntry->currentOperChannel != pBeacon->channelNumber)) + retCode = QDF_STATUS_E_INVAL; + else if (lim_ibss_enc_type_matched(pBeacon, psessionEntry) != true) { + pe_debug("peer privacy: %d peer wpa: %d peer rsn: %d self encType: %d", + pBeacon->capabilityInfo.privacy, + pBeacon->wpaPresent, pBeacon->rsnPresent, + psessionEntry->encryptType); + retCode = QDF_STATUS_E_INVAL; + } else { + uint32_t ieLen; + uint16_t tsfLater; + uint8_t *pIEs; + + ieLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + tsfLater = WMA_GET_RX_TSF_LATER(pRxPacketInfo); + pIEs = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + pe_debug("BEFORE Coalescing tsfLater val: %d", tsfLater); + retCode = + lim_ibss_coalesce(pMac, pHdr, pBeacon, pIEs, ieLen, tsfLater, + psessionEntry); + } + return retCode; +} /*** end lim_handle_ibs_scoalescing() ***/ + +/** + * 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(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + tpPESession session) +{ + if (!bcn || !session) + return false; + + pe_debug("Beacon/Probe:: Privacy: %d WPA Present: %d RSN Present: %d", + bcn->capabilityInfo.privacy, bcn->wpaPresent, bcn->rsnPresent); + pe_debug("session:: Privacy: %d EncyptionType: %d OSEN: %d WPS: %d", + SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps), + session->encryptType, session->isOSENConnection, + session->wps_registration); + + /* + * 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 wont match and + * driver may end up sending probe request without + * WPS IE during WPS registration process. + */ + if (session->isOSENConnection || + session->wps_registration) + return true; + + return false; +} + +/** + * lim_detect_change_in_ap_capabilities() + * + ***FUNCTION: + * This function is called while SCH is processing + * received Beacon from AP on STA to detect any + * change in AP's capabilities. If there any change + * is detected, Roaming is informed of such change + * so that it can trigger reassociation. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * Notification is enabled for STA product only since + * it is not a requirement on BP side. + * + * @param pMac Pointer to Global MAC structure + * @param pBeacon Pointer to parsed Beacon structure + * @return None + */ + +void +lim_detect_change_in_ap_capabilities(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpPESession psessionEntry) +{ + uint8_t len; + tSirSmeApNewCaps apNewCaps; + uint8_t newChannel; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool security_caps_matched = true; + + apNewCaps.capabilityInfo = + lim_get_u16((uint8_t *) &pBeacon->capabilityInfo); + newChannel = (uint8_t) pBeacon->channelNumber; + + security_caps_matched = lim_enc_type_matched(pMac, pBeacon, + psessionEntry); + if ((false == psessionEntry->limSentCapsChangeNtf) && + (((!lim_is_null_ssid(&pBeacon->ssId)) && + lim_cmp_ssid(&pBeacon->ssId, psessionEntry)) || + ((SIR_MAC_GET_ESS(apNewCaps.capabilityInfo) != + SIR_MAC_GET_ESS(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_PRIVACY(apNewCaps.capabilityInfo) != + SIR_MAC_GET_PRIVACY(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_QOS(apNewCaps.capabilityInfo) != + SIR_MAC_GET_QOS(psessionEntry->limCurrentBssCaps)) || + ((newChannel != psessionEntry->currentOperChannel) && + (newChannel != 0)) || + (false == security_caps_matched) + ))) { + if (false == psessionEntry->fWaitForProbeRsp) { + /* 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 (true == psessionEntry->fIgnoreCapsChange) { + pe_debug("Ignoring the Capability change as it is false alarm"); + return; + } + psessionEntry->fWaitForProbeRsp = true; + pe_warn("AP capabilities are not matching, sending directed probe request"); + status = + lim_send_probe_req_mgmt_frame(pMac, &psessionEntry->ssId, + psessionEntry->bssId, + psessionEntry->currentOperChannel, + psessionEntry->selfMacAddr, + psessionEntry->dot11mode, + NULL, NULL); + + if (QDF_STATUS_SUCCESS != status) { + pe_err("send ProbeReq failed"); + psessionEntry->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; + + qdf_mem_copy(apNewCaps.bssId.bytes, + psessionEntry->bssId, QDF_MAC_ADDR_SIZE); + if (newChannel != psessionEntry->currentOperChannel) { + pe_err("Channel Change from %d --> %d Ignoring beacon!", + psessionEntry->currentOperChannel, newChannel); + 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(apNewCaps.capabilityInfo) == 0) && + (pBeacon->rsnPresent || pBeacon->wpaPresent)) { + pe_err("BSS Caps (Privacy) bit 0 in beacon, but WPA or RSN IE present, Ignore Beacon!"); + return; + } else + apNewCaps.channelId = psessionEntry->currentOperChannel; + qdf_mem_copy((uint8_t *) &apNewCaps.ssId, + (uint8_t *) &pBeacon->ssId, + pBeacon->ssId.length + 1); + + psessionEntry->fIgnoreCapsChange = false; + psessionEntry->fWaitForProbeRsp = false; + psessionEntry->limSentCapsChangeNtf = true; + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_AP_CAPS_CHANGED, + (uint32_t *) &apNewCaps, + len, psessionEntry->smeSessionId); + } else if (true == psessionEntry->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("capabilities in probe response are" + "matching with the current setting," + "Ignoring subsequent capability" + "mismatch"); + psessionEntry->fIgnoreCapsChange = true; + psessionEntry->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(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + tSirSmeApNewCaps apNewCaps; + uint32_t nShortSlot; + uint32_t val = 0; + uint32_t phyMode; + + /* Check Admin mode first. If it is disabled just return */ + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val) + != QDF_STATUS_SUCCESS) { + pe_err("cfg get WNI_CFG_11G_SHORT_SLOT_TIME failed"); + return QDF_STATUS_E_FAILURE; + } + if (val == false) + 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(pMac, &phyMode, psessionEntry); + if ((phyMode == WNI_CFG_PHY_MODE_11A) + || (phyMode == WNI_CFG_PHY_MODE_11B)) + return QDF_STATUS_SUCCESS; + + apNewCaps.capabilityInfo = + 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(apNewCaps.capabilityInfo); + + if (nShortSlot != psessionEntry->shortSlotTimeSupported) { + /* Short slot time capability of AP has changed. Adopt to it. */ + pe_debug("Shortslot capability of AP changed: %d", + nShortSlot); + ((tpSirMacCapabilityInfo) & psessionEntry-> + limCurrentBssCaps)->shortSlotTime = (uint16_t) nShortSlot; + psessionEntry->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(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + 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 = psessionEntry; + msg.bodyval = 0; + pe_err("Heartbeat failure from Fw"); + + status = lim_post_msg_api(pMac, &msg); + + if (status != QDF_STATUS_SUCCESS) { + pe_err("posting message: %X to LIM failed, reason: %d", + msg.type, status); + } +} + +/** + * lim_ps_offload_handle_missed_beacon_ind(): handles missed beacon indication + * @pMac : global mac context + * @pMsg: 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(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + tpSirSmeMissedBeaconInd pSirMissedBeaconInd = + (tpSirSmeMissedBeaconInd) pMsg->bodyptr; + tpPESession psessionEntry = + pe_find_session_by_bss_idx(pMac, pSirMissedBeaconInd->bssIdx); + + if (!psessionEntry) { + pe_err("session does not exist for given BSSId"); + return; + } + + /* Set Beacon Miss in Powersave Offload */ + psessionEntry->pmmOffloadInfo.bcnmiss = true; + pe_err("Received Heart Beat Failure"); + + /* Do AP probing immediately */ + lim_send_heart_beat_timeout_ind(pMac, psessionEntry); + return; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * lim_fill_join_rsp_ht_caps() - Fill the HT caps in join response + * @session: PE Session + * @join_rsp: Join response buffer to be filled up. + * + * Return: None + */ +void lim_fill_join_rsp_ht_caps(tpPESession session, tpSirSmeJoinRsp join_rsp) +{ + tSirSmeHTProfile *ht_profile; + + if (session == NULL) { + pe_err("Invalid Session"); + return; + } + if (join_rsp == NULL) { + pe_err("Invalid Join Response"); + return; + } + + if (session->cc_switch_mode == QDF_MCC_TO_SCC_SWITCH_DISABLE) + return; + + ht_profile = &join_rsp->HTProfile; + ht_profile->htSupportedChannelWidthSet = + session->htSupportedChannelWidthSet; + ht_profile->htRecommendedTxWidthSet = + session->htRecommendedTxWidthSet; + ht_profile->htSecondaryChannelOffset = + session->htSecondaryChannelOffset; + ht_profile->dot11mode = session->dot11mode; + ht_profile->htCapability = session->htCapability; + ht_profile->vhtCapability = session->vhtCapability; + ht_profile->apCenterChan = session->ch_center_freq_seg0; + ht_profile->apChanWidth = session->ch_width; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * 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(tpAniSirGlobal 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_fill_bss_descr(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_offload_synch_ind_ptr, + tpSirBssDescription bss_desc_ptr) +{ + uint32_t ie_len = 0; + tpSirProbeRespBeacon parsed_frm_ptr; + tpSirMacMgmtHdr mac_hdr; + uint8_t *bcn_proberesp_ptr; + + bcn_proberesp_ptr = (uint8_t *)roam_offload_synch_ind_ptr + + roam_offload_synch_ind_ptr->beaconProbeRespOffset; + mac_hdr = (tpSirMacMgmtHdr)bcn_proberesp_ptr; + parsed_frm_ptr = + (tpSirProbeRespBeacon) qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == parsed_frm_ptr) { + pe_err("fail to allocate memory for frame"); + return QDF_STATUS_E_NOMEM; + } + + if (roam_offload_synch_ind_ptr->beaconProbeRespLength <= + SIR_MAC_HDR_LEN_3A) { + pe_err("%s: very few bytes in synchInd beacon / probe resp frame! length: %d", + __func__, roam_offload_synch_ind_ptr->beaconProbeRespLength); + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_E_FAILURE; + } + + pe_debug("LFR3:Beacon/Prb Rsp: %d", roam_offload_synch_ind_ptr->isBeacon); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + bcn_proberesp_ptr, roam_offload_synch_ind_ptr->beaconProbeRespLength); + if (roam_offload_synch_ind_ptr->isBeacon) { + if (sir_parse_beacon_ie(pMac, parsed_frm_ptr, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET], + roam_offload_synch_ind_ptr->beaconProbeRespLength - + SIR_MAC_HDR_LEN_3A) != QDF_STATUS_SUCCESS || + !parsed_frm_ptr->ssidPresent) { + pe_err("Parse error Beacon, length: %d", + roam_offload_synch_ind_ptr->beaconProbeRespLength); + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_E_FAILURE; + } + } else { + if (sir_convert_probe_frame2_struct(pMac, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A], + roam_offload_synch_ind_ptr->beaconProbeRespLength - + SIR_MAC_HDR_LEN_3A, parsed_frm_ptr) != QDF_STATUS_SUCCESS || + !parsed_frm_ptr->ssidPresent) { + pe_err("Parse error ProbeResponse, length: %d", + roam_offload_synch_ind_ptr->beaconProbeRespLength); + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_E_FAILURE; + } + } + + /* + * For probe response, unpack core parses beacon interval, capabilities, + * timestamp. For beacon IEs, these fields are not parsed. + */ + if (roam_offload_synch_ind_ptr->isBeacon) + sir_parse_bcn_fixed_fields(pMac, parsed_frm_ptr, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A]); + + /* 24 byte MAC header and 12 byte to ssid IE */ + if (roam_offload_synch_ind_ptr->beaconProbeRespLength > + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { + ie_len = roam_offload_synch_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + } + /* + * Length of BSS desription is without length of + * length itself and length of pointer + * that holds ieFields + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + bss_desc_ptr->length = (uint16_t) (offsetof(tSirBssDescription, + ieFields[0]) - + sizeof(bss_desc_ptr->length) + ie_len); + + bss_desc_ptr->fProbeRsp = !roam_offload_synch_ind_ptr->isBeacon; + /* Copy Timestamp */ + bss_desc_ptr->scansystimensec = qdf_get_monotonic_boottime_ns(); + if (parsed_frm_ptr->dsParamsPresent) { + bss_desc_ptr->channelId = parsed_frm_ptr->channelNumber; + } else if (parsed_frm_ptr->HTInfo.present) { + bss_desc_ptr->channelId = 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->channelId = + cds_freq_to_chan(roam_offload_synch_ind_ptr->chan_freq); + } + bss_desc_ptr->channelIdSelf = bss_desc_ptr->channelId; + + bss_desc_ptr->nwType = lim_get_nw_type(pMac, bss_desc_ptr->channelId, + SIR_MAC_MGMT_FRAME, + parsed_frm_ptr); + + bss_desc_ptr->sinr = 0; + 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); + + if (qdf_is_macaddr_zero((struct qdf_mac_addr *)mac_hdr->bssId)) { + pe_debug("bssid is 0 in beacon/probe update it with bssId %pM in sync ind", + roam_offload_synch_ind_ptr->bssid.bytes); + qdf_mem_copy(mac_hdr->bssId, + roam_offload_synch_ind_ptr->bssid.bytes, + sizeof(tSirMacAddr)); + } + + qdf_mem_copy((uint8_t *) &bss_desc_ptr->bssId, + (uint8_t *) mac_hdr->bssId, + sizeof(tSirMacAddr)); + bss_desc_ptr->received_time = + (uint64_t)qdf_mc_timer_get_system_time(); + 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); + } + pe_debug("LFR3: BssDescr Info:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + bss_desc_ptr->bssId, sizeof(tSirMacAddr)); + pe_debug("chan: %d rssi: %d", bss_desc_ptr->channelId, + bss_desc_ptr->rssi); + if (ie_len) { + qdf_mem_copy(&bss_desc_ptr->ieFields, + bcn_proberesp_ptr + + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET), + ie_len); + } + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_SUCCESS; +} + +#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(tpPESession session_ptr, + roam_offload_synch_ind *roam_sync_ind_ptr) +{ + if (session_ptr->hlp_data && session_ptr->hlp_data_len) { + cds_copy_hlp_info(&session_ptr->dst_mac, + &session_ptr->src_mac, + session_ptr->hlp_data_len, + session_ptr->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->hlp_data); + session_ptr->hlp_data = NULL; + session_ptr->hlp_data_len = 0; + } +} +#else +static inline void lim_copy_and_free_hlp_data_from_session( + tpPESession session_ptr, + roam_offload_synch_ind + *roam_sync_ind_ptr) +{} +#endif + +/** + * pe_roam_synch_callback() - PE level callback for roam synch propagation + * @mac_ctx: MAC Context + * @roam_sync_ind_ptr: Roam synch indication buffer pointer + * @bss_desc: BSS Descriptor pointer + * @reason: Reason for calling callback which decides the action to be taken. + * + * 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: Success or Failure status + */ +QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_sync_ind_ptr, + tpSirBssDescription bss_desc, enum sir_roam_op_code reason) +{ + tpPESession session_ptr; + tpPESession ft_session_ptr; + uint8_t session_id; + tpDphHashNode curr_sta_ds; + uint16_t aid; + tpAddBssParams add_bss_params; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t join_rsp_len; + + if (!roam_sync_ind_ptr) { + pe_err("LFR3:roam_sync_ind_ptr is NULL"); + return status; + } + session_ptr = pe_find_session_by_sme_session_id(mac_ctx, + roam_sync_ind_ptr->roamedVdevId); + if (session_ptr == NULL) { + 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; + } + + pe_debug("LFR3: PE callback reason: %d", reason); + switch (reason) { + case SIR_ROAMING_START: + session_ptr->fw_roaming_started = true; + return QDF_STATUS_SUCCESS; + case SIR_ROAMING_ABORT: + session_ptr->fw_roaming_started = false; + /* + * 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: + session_ptr->fw_roaming_started = false; + break; + default: + return status; + } + + pe_debug("LFR3:Received WMA_ROAM_OFFLOAD_SYNCH_IND LFR3:auth: %d vdevId: %d", + roam_sync_ind_ptr->authStatus, roam_sync_ind_ptr->roamedVdevId); + lim_print_mac_addr(mac_ctx, roam_sync_ind_ptr->bssid.bytes, + QDF_TRACE_LEVEL_DEBUG); + /* + * 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; + } + status = lim_roam_fill_bss_descr(mac_ctx, roam_sync_ind_ptr, bss_desc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("LFR3:Failed to fill Bss Descr"); + return status; + } + status = QDF_STATUS_E_FAILURE; + ft_session_ptr = pe_create_session(mac_ctx, bss_desc->bssId, + &session_id, mac_ctx->lim.maxStation, + eSIR_INFRASTRUCTURE_MODE); + if (ft_session_ptr == NULL) { + pe_err("LFR3:Cannot create PE Session"); + lim_print_mac_addr(mac_ctx, bss_desc->bssId, LOGE); + return status; + } + /* Update the beacon/probe filter in mac_ctx */ + lim_set_bcn_probe_filter(mac_ctx, ft_session_ptr, NULL, 0); + + sir_copy_mac_addr(ft_session_ptr->selfMacAddr, session_ptr->selfMacAddr); + sir_copy_mac_addr(roam_sync_ind_ptr->self_mac.bytes, + session_ptr->selfMacAddr); + 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; + + /* Assign default configured nss value in the new session */ + if (IS_5G_CH(ft_session_ptr->currentOperChannel)) + ft_session_ptr->vdev_nss = mac_ctx->vdev_type_nss_5g.sta; + else + ft_session_ptr->vdev_nss = mac_ctx->vdev_type_nss_2g.sta; + + ft_session_ptr->nss = ft_session_ptr->vdev_nss; + + /* Next routine will update nss and vdev_nss with AP's capabilities */ + lim_fill_ft_session(mac_ctx, bss_desc, ft_session_ptr, session_ptr); + + /* Next routine may update nss based on dot11Mode */ + lim_ft_prepare_add_bss_req(mac_ctx, false, ft_session_ptr, bss_desc); + roam_sync_ind_ptr->add_bss_params = + (tpAddBssParams) ft_session_ptr->ftPEContext.pAddBssReq; + add_bss_params = ft_session_ptr->ftPEContext.pAddBssReq; + lim_delete_tdls_peers(mac_ctx, session_ptr); + curr_sta_ds = dph_lookup_hash_entry(mac_ctx, session_ptr->bssId, + &aid, &session_ptr->dph.dphHashTable); + if (curr_sta_ds == NULL) { + pe_err("LFR3:failed to lookup hash entry"); + ft_session_ptr->bRoamSynchInProgress = false; + return status; + } + session_ptr->limSmeState = eLIM_SME_IDLE_STATE; + lim_cleanup_rx_path(mac_ctx, curr_sta_ds, session_ptr); + lim_delete_dph_hash_entry(mac_ctx, curr_sta_ds->staAddr, + aid, session_ptr); + pe_delete_session(mac_ctx, session_ptr); + session_ptr = NULL; + curr_sta_ds = dph_add_hash_entry(mac_ctx, + roam_sync_ind_ptr->bssid.bytes, DPH_STA_HASH_INDEX_PEER, + &ft_session_ptr->dph.dphHashTable); + if (curr_sta_ds == NULL) { + pe_err("LFR3:failed to add hash entry for"); + lim_print_mac_addr(mac_ctx, + add_bss_params->staContext.staMac, LOGE); + ft_session_ptr->bRoamSynchInProgress = false; + return status; + } + + add_bss_params->bssIdx = roam_sync_ind_ptr->roamedVdevId; + ft_session_ptr->bssIdx = (uint8_t) add_bss_params->bssIdx; + + curr_sta_ds->bssId = add_bss_params->bssIdx; + curr_sta_ds->staIndex = + add_bss_params->staContext.staIdx; + rrm_cache_mgmt_tx_power(mac_ctx, + add_bss_params->txMgmtPower, ft_session_ptr); + mac_ctx->roam.reassocRespLen = roam_sync_ind_ptr->reassocRespLength; + mac_ctx->roam.pReassocResp = + qdf_mem_malloc(mac_ctx->roam.reassocRespLen); + if (NULL == mac_ctx->roam.pReassocResp) { + pe_err("LFR3:assoc resp mem alloc failed"); + ft_session_ptr->bRoamSynchInProgress = false; + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(mac_ctx->roam.pReassocResp, + (uint8_t *)roam_sync_ind_ptr + + roam_sync_ind_ptr->reassocRespOffset, + mac_ctx->roam.reassocRespLen); + + pe_debug("LFR3:the reassoc resp frame data:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + mac_ctx->roam.pReassocResp, + mac_ctx->roam.reassocRespLen); + ft_session_ptr->bRoamSynchInProgress = true; + + lim_process_assoc_rsp_frame(mac_ctx, mac_ctx->roam.pReassocResp, + LIM_REASSOC, 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; + lim_init_tdls_data(mac_ctx, ft_session_ptr); + join_rsp_len = ft_session_ptr->RICDataLen + + sizeof(tSirSmeJoinRsp) - sizeof(uint8_t); + +#ifdef FEATURE_WLAN_ESE + join_rsp_len += ft_session_ptr->tspecLen; + pe_debug("tspecLen: %d", ft_session_ptr->tspecLen); +#endif + + roam_sync_ind_ptr->join_rsp = qdf_mem_malloc(join_rsp_len); + if (NULL == roam_sync_ind_ptr->join_rsp) { + pe_err("LFR3:mem alloc failed"); + ft_session_ptr->bRoamSynchInProgress = false; + if (mac_ctx->roam.pReassocResp) + qdf_mem_free(mac_ctx->roam.pReassocResp); + mac_ctx->roam.pReassocResp = NULL; + return QDF_STATUS_E_NOMEM; + } + + pe_debug("Session RicLength: %d", ft_session_ptr->RICDataLen); + if (ft_session_ptr->ricData != NULL) { + roam_sync_ind_ptr->join_rsp->parsedRicRspLen = + ft_session_ptr->RICDataLen; + qdf_mem_copy(roam_sync_ind_ptr->join_rsp->frames, + ft_session_ptr->ricData, + roam_sync_ind_ptr->join_rsp->parsedRicRspLen); + 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 != NULL) { + roam_sync_ind_ptr->join_rsp->tspecIeLen = + ft_session_ptr->tspecLen; + qdf_mem_copy(roam_sync_ind_ptr->join_rsp->frames + + roam_sync_ind_ptr->join_rsp->parsedRicRspLen, + ft_session_ptr->tspecIes, + roam_sync_ind_ptr->join_rsp->tspecIeLen); + qdf_mem_free(ft_session_ptr->tspecIes); + ft_session_ptr->tspecIes = NULL; + ft_session_ptr->tspecLen = 0; + } +#endif + + roam_sync_ind_ptr->join_rsp->vht_channel_width = + ft_session_ptr->ch_width; + roam_sync_ind_ptr->join_rsp->staId = curr_sta_ds->staIndex; + roam_sync_ind_ptr->join_rsp->timingMeasCap = curr_sta_ds->timingMeasCap; + roam_sync_ind_ptr->join_rsp->nss = curr_sta_ds->nss; + roam_sync_ind_ptr->join_rsp->max_rate_flags = + lim_get_max_rate_flags(mac_ctx, curr_sta_ds); + lim_set_tdls_flags(roam_sync_ind_ptr, ft_session_ptr); + roam_sync_ind_ptr->join_rsp->aid = ft_session_ptr->limAID; + lim_fill_join_rsp_ht_caps(ft_session_ptr, roam_sync_ind_ptr->join_rsp); + ft_session_ptr->limPrevSmeState = ft_session_ptr->limSmeState; + ft_session_ptr->limSmeState = eLIM_SME_LINK_EST_STATE; + ft_session_ptr->bRoamSynchInProgress = false; + if (mac_ctx->roam.pReassocResp) + qdf_mem_free(mac_ctx->roam.pReassocResp); + mac_ctx->roam.pReassocResp = NULL; + + if (roam_sync_ind_ptr->authStatus == CSR_ROAM_AUTH_STATUS_AUTHENTICATED) + ft_session_ptr->is_key_installed = true; + + return QDF_STATUS_SUCCESS; +} +#endif + +static bool lim_is_beacon_miss_scenario(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo) +{ + tpSirMacMgmtHdr pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + uint8_t sessionId; + tpPESession psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->bssId, &sessionId); + + if (psessionEntry && psessionEntry->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 droped 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. + - Drop INFRA Beacons and Probe Responses in IBSS Mode + - Drop the Probe Request in IBSS mode, if STA did not send out the last beacon + + \param pMac - global mac structure + \return - none + \sa + ----------------------------------------------------------------- */ + +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + uint32_t subType) +{ + uint32_t framelen; + uint8_t *pBody; + tSirMacCapabilityInfo capabilityInfo; + tpSirMacMgmtHdr pHdr = NULL; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + + /* + * + * 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(pMac, pRxPacketInfo)) { + MTRACE(mac_trace(pMac, TRACE_CODE_INFO_LOG, 0, + eLOG_NODROP_MISSED_BEACON_SCENARIO)); + return eMGMT_DROP_NO_DROP; + } + if (lim_is_system_in_scan_state(pMac)) + return eMGMT_DROP_NO_DROP; + else if (WMA_IS_RX_IN_SCAN(pRxPacketInfo)) + return eMGMT_DROP_SCAN_MODE_FRAME; + + 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 enque the frame. */ + if (capabilityInfo.ess) + return eMGMT_DROP_INFRA_BCN_IN_IBSS; + + } else if ((subType == SIR_MAC_MGMT_PROBE_REQ) && + (!WMA_GET_RX_BEACON_SENT(pRxPacketInfo))) { + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + psessionEntry = pe_find_session_by_bssid(pMac, + pHdr->bssId, + &sessionId); + if ((psessionEntry && !LIM_IS_IBSS_ROLE(psessionEntry)) || + (!psessionEntry)) + return eMGMT_DROP_NO_DROP; + + /* Drop the Probe Request in IBSS mode, if STA did not send out the last beacon */ + /* In IBSS, the node which sends out the beacon, is supposed to respond to ProbeReq */ + return eMGMT_DROP_NOT_LAST_IBSS_BCN; + } else if (subType == SIR_MAC_MGMT_AUTH) { + uint16_t curr_seq_num = 0; + struct tLimPreAuthNode *auth_node; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + psessionEntry = pe_find_session_by_bssid(pMac, pHdr->bssId, + &sessionId); + if (!psessionEntry) + return eMGMT_DROP_NO_DROP; + + curr_seq_num = ((pHdr->seqControl.seqNumHi << 4) | + (pHdr->seqControl.seqNumLo)); + auth_node = lim_search_pre_auth_list(pMac, 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)) { + uint16_t assoc_id; + dphHashTableClass *dph_table; + tDphHashNode *sta_ds; + qdf_time_t *timestamp; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + psessionEntry = pe_find_session_by_bssid(pMac, pHdr->bssId, + &sessionId); + if (!psessionEntry) + return eMGMT_DROP_NO_DROP; + dph_table = &psessionEntry->dph.dphHashTable; + sta_ds = dph_lookup_hash_entry(pMac, pHdr->sa, &assoc_id, + dph_table); + if (!sta_ds) { + if (subType == SIR_MAC_MGMT_ASSOC_REQ) + return eMGMT_DROP_NO_DROP; + else + return eMGMT_DROP_EXCESSIVE_MGMT_FRAME; + } + + if (subType == SIR_MAC_MGMT_ASSOC_REQ) + timestamp = &sta_ds->last_assoc_received_time; + else + timestamp = &sta_ds->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); + return eMGMT_DROP_EXCESSIVE_MGMT_FRAME; + } + + *timestamp = qdf_get_system_timestamp(); + + } + + return eMGMT_DROP_NO_DROP; +} + +void lim_update_lost_link_info(tpAniSirGlobal mac, tpPESession session, + int32_t rssi) +{ + struct sir_lost_link_info *lost_link_info; + struct scheduler_msg mmh_msg = {0}; + + if ((NULL == mac) || (NULL == session)) { + pe_err("parameter NULL"); + return; + } + if (!LIM_IS_STA_ROLE(session)) + return; + + lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info)); + if (NULL == lost_link_info) { + pe_err("lost_link_info allocation failure"); + 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, ePROT); +} + +QDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (psPe) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_acquire(&psPe->lkPeGlobalLock))) { + status = QDF_STATUS_SUCCESS; + } + } + return status; +} + +QDF_STATUS pe_release_global_lock(tAniSirLim *psPe) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (psPe) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_release(&psPe->lkPeGlobalLock))) { + status = QDF_STATUS_SUCCESS; + } + } + return status; +} + +/** + * 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(tpAniSirGlobal mac_ptr, + struct sir_create_session *msg) +{ + tpPESession psession_entry; + uint8_t session_id; + + psession_entry = pe_create_session(mac_ptr, msg->bss_id.bytes, + &session_id, + mac_ptr->lim.maxStation, + eSIR_MONITOR_MODE); + if (psession_entry == NULL) { + pe_err("Monitor mode: Session Can not be created"); + lim_print_mac_addr(mac_ptr, msg->bss_id.bytes, LOGE); + return; + } + psession_entry->vhtCapability = 1; +} + +/** + * 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 + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_update_ext_cap_ie(tpAniSirGlobal mac_ctx, + uint8_t *ie_data, uint8_t *local_ie_buf, uint16_t *local_ie_len) +{ + 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; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &dot11mode); + 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); + 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; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..95c3e55be4af8ce8e8016c2151e95df16f028e4e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c @@ -0,0 +1,4926 @@ +/* + * 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. + */ + +/* + * 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_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_sta_hash_api.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#include "qdf_types.h" +#include "wma_types.h" +#include "lim_types.h" +#include "wlan_utility.h" + +#ifdef FEATURE_WLAN_TDLS +#define IS_TDLS_PEER(type) ((type) == STA_ENTRY_TDLS_PEER) +#else +#define IS_TDLS_PEER(type) 0 +#endif + +/** + * 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, tpPESession session_entry) +{ + return qdf_mem_cmp(rx_ssid, &session_entry->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 pMac - 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(tpAniSirGlobal pMac, + tSirAssocReq *pAssocReq, + tSirMacCapabilityInfo *pLocalCapabs, + tpPESession psessionEntry) +{ + uint32_t val; + + if (LIM_IS_AP_ROLE(psessionEntry) && + (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(psessionEntry) && + (pLocalCapabs->shortSlotTime == 1)) { + if (wlan_cfg_get_int + (pMac, WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + &val) != QDF_STATUS_SUCCESS) { + pe_err("error getting WNI_CFG_FORCE_SHORT_SLOT_ASSOC_ONLY"); + return false; + } + if (val) { + 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(tpAniSirGlobal pMac, tSirMacRateSet rxRateSet, + tpPESession psessionEntry) +{ + tSirMacRateSet *pRateSet, basicRate; + uint8_t i, j, k, match; + + pRateSet = qdf_mem_malloc(sizeof(tSirMacRateSet)); + if (NULL == pRateSet) { + pe_err("call to AllocateMemory failed for RATESET"); + return false; + } + + /* Copy operational rate set from session Entry */ + qdf_mem_copy(pRateSet->rate, (psessionEntry->rateSet.rate), + psessionEntry->rateSet.numRates); + + pRateSet->numRates = psessionEntry->rateSet.numRates; + + /* Extract BSS basic rateset from operational rateset */ + for (i = 0, j = 0; + ((i < pRateSet->numRates) && (i < SIR_MAC_RATESET_EID_MAX)); 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_RATESET_EID_MAX)); 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(tpAniSirGlobal pMac, uint8_t *supportedMCSSet) +{ + uint8_t basicMCSSet[SIZE_OF_BASIC_MCS_SET] = { 0 }; + uint32_t cfgLen = 0; + uint8_t i; + uint8_t validBytes; + uint8_t lastByteMCSMask = 0x1f; + + cfgLen = WNI_CFG_BASIC_MCS_SET_LEN; + if (wlan_cfg_get_str(pMac, WNI_CFG_BASIC_MCS_SET, + (uint8_t *) basicMCSSet, + (uint32_t *) &cfgLen) != 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 + +/** + * is_non_rsn_cipher()- API to check whether cipher suit is rsn or not + * @cipher_suite: cipher suit + * + * Return: True in case non ht cipher else false + */ +static inline bool is_non_rsn_cipher(uint8_t cipher_suite) +{ + uint8_t cipher_mask; + + cipher_mask = cipher_suite & SECURITY_SUITE_TYPE_MASK; + if ((cipher_mask == SECURITY_SUITE_TYPE_CCMP) || + (cipher_mask == SECURITY_SUITE_TYPE_GCMP) || + (cipher_mask == SECURITY_SUITE_TYPE_GCMP_256)) + return false; + + return true; +} + +/** + * lim_check_rx_rsn_ie_match()- validate received rsn ie with supported cipher + * suites. + * @mac_ctx: pointer to global mac structure + * @rx_rsn_ie: received rsn IE pointer + * @session_entry: pe session entry + * @sta_is_ht: peer station HT capability + * @pmf_connection: set to true if this is pmf connection + * + * This function is called during Association/Reassociation + * frame handling to determine whether received RSN in + * Assoc/Reassoc request frames include supported cipher suites or not. + * + * Return: QDF_STATUS_SUCCESS if ALL supported cipher suites are present in the + * received rsn IE else failure status. + */ + +uint8_t lim_check_rx_rsn_ie_match(tpAniSirGlobal mac_ctx, + tDot11fIERSN * const rx_rsn_ie, + tpPESession session_entry, uint8_t sta_is_ht, + bool *pmf_connection) +{ + tDot11fIERSN *rsn_ie; + uint8_t i, j, match, only_non_ht_cipher = 1; +#ifdef WLAN_FEATURE_11W + bool we_are_pmf_capable; + bool we_require_pmf; + bool they_are_pmf_capable; + bool they_require_pmf; +#endif + + /* RSN IE should be received from PE */ + rsn_ie = &session_entry->gStartBssRSNIe; + + if (!rx_rsn_ie) { + pe_debug("Rx RSN IE is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Check groupwise cipher suite */ + for (i = 0; i < sizeof(rx_rsn_ie->gp_cipher_suite); i++) + if (rsn_ie->gp_cipher_suite[i] != + rx_rsn_ie->gp_cipher_suite[i]) { + pe_debug("Invalid groupwise cipher suite"); + return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; + } + + /* + * For each Pairwise cipher suite check whether we support + * received pairwise + */ + match = 0; + for (i = 0; i < rx_rsn_ie->pwise_cipher_suite_count; i++) { + for (j = 0; j < rsn_ie->pwise_cipher_suite_count; j++) { + if (!qdf_mem_cmp(&rx_rsn_ie->pwise_cipher_suites[i], + &rsn_ie->pwise_cipher_suites[j], + sizeof(rsn_ie->pwise_cipher_suites[j]))) { + match = 1; + break; + } + } + + if (sta_is_ht) +#ifdef ANI_LITTLE_BYTE_ENDIAN + only_non_ht_cipher = is_non_rsn_cipher( + rx_rsn_ie->pwise_cipher_suites[i][3]); +#else + only_non_ht_cipher = is_non_rsn_cipher( + rx_rsn_ie->pwise_cipher_suites[i][0]); +#endif + } + + if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { + pe_debug("Invalid pairwise cipher suite"); + return eSIR_MAC_INVALID_PAIRWISE_CIPHER_STATUS; + } + /* + * Check RSN capabilities + * Bit 0 of First Byte - PreAuthentication Capability + */ + if (((rx_rsn_ie->RSN_Cap[0] >> 0) & 0x1) == true) { + /* this is supported by AP only */ + pe_debug("Invalid RSN information element capabilities"); + return eSIR_MAC_INVALID_RSN_IE_CAPABILITIES_STATUS; + } + + *pmf_connection = false; + +#ifdef WLAN_FEATURE_11W + we_are_pmf_capable = session_entry->pLimStartBssReq->pmfCapable; + we_require_pmf = session_entry->pLimStartBssReq->pmfRequired; + they_are_pmf_capable = (rx_rsn_ie->RSN_Cap[0] >> 7) & 0x1; + they_require_pmf = (rx_rsn_ie->RSN_Cap[0] >> 6) & 0x1; + + if ((they_require_pmf && they_are_pmf_capable && !we_are_pmf_capable) || + (we_require_pmf && !they_are_pmf_capable)) { + pe_debug("Association fail, robust management frames policy" + " violation they_require_pmf =%d" + " theyArePMFCapable %d weArePMFCapable %d" + " weRequirePMF %d theyArePMFCapable %d", + they_require_pmf, they_are_pmf_capable, + we_are_pmf_capable, we_require_pmf, + they_are_pmf_capable); + return eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION; + } + + if (they_are_pmf_capable && we_are_pmf_capable) + *pmf_connection = true; + + pe_debug("weAreCapable %d, weRequire %d, theyAreCapable %d," + " theyRequire %d, PMFconnection %d", + we_are_pmf_capable, we_require_pmf, they_are_pmf_capable, + they_require_pmf, *pmf_connection); +#endif + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_check_rx_wpa_ie_match() - to check supported cipher suites + * + * @mac: pointer to global mac structure + * @rx_wpaie: Received WPA IE in (Re)Assco req + * @session_entry: pointer to PE session + * @sta_is_ht: peer station is HT + * + * This function is called during Association/Reassociation + * frame handling to determine whether received RSN in + * Assoc/Reassoc request frames include supported cipher suites or not. + * + * Return: Success if ALL supported cipher suites are present in the + * received wpa IE else failure status. + */ + +uint8_t +lim_check_rx_wpa_ie_match(tpAniSirGlobal mac, tDot11fIEWPA rx_wpaie, + tpPESession session_entry, uint8_t sta_is_ht) +{ + tDot11fIEWPA *wpa_ie; + uint8_t i, j, match, only_non_ht_cipher = 1; + + /* WPA IE should be received from PE */ + wpa_ie = &session_entry->gStartBssWPAIe; + + /* Check groupwise cipher suite */ + for (i = 0; i < 4; i++) { + if (wpa_ie->multicast_cipher[i] != rx_wpaie.multicast_cipher[i]) { + pe_debug("Invalid groupwise cipher suite"); + return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; + } + } + + /* + * For each Pairwise cipher suite check whether we support + * received pairwise + */ + match = 0; + for (i = 0; i < rx_wpaie.unicast_cipher_count; i++) { + for (j = 0; j < wpa_ie->unicast_cipher_count; j++) { + if (!qdf_mem_cmp(rx_wpaie.unicast_ciphers[i], + wpa_ie->unicast_ciphers[j], 4)) { + match = 1; + break; + } + } + + if ((sta_is_ht) +#ifdef ANI_LITTLE_BYTE_ENDIAN + && + ((rx_wpaie. + unicast_ciphers[i][3] & SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#else + && + ((rx_wpaie. + unicast_ciphers[i][0] & SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#endif + { + only_non_ht_cipher = 0; + } + + } + + if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { + pe_debug("Invalid pairwise cipher suite"); + return eSIR_MAC_CIPHER_SUITE_REJECTED_STATUS; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_cleanup_rx_path() + * + ***FUNCTION: + * This function is called to cleanup STA state at SP & RFP. + * + ***LOGIC: + * 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. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pStaDs Pointer to the per STA data structure + * initialized by LIM and maintained at DPH + * + * @return None + */ + +QDF_STATUS +lim_cleanup_rx_path(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + pe_debug("Cleanup Rx Path for AID: %d" + "psessionEntry->limSmeState: %d, mlmState: %d", + pStaDs->assocId, psessionEntry->limSmeState, + pStaDs->mlmStaContext.mlmState); + + psessionEntry->isCiscoVendorAP = false; + + if (pMac->lim.gLimAddtsSent) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_ADDTS_RSP_TIMER)); + tx_timer_deactivate(&pMac->lim.limTimers.gLimAddtsRspTimer); + pe_debug("Reset gLimAddtsSent flag and send addts timeout to SME"); + lim_process_sme_addts_rsp_timeout(pMac, + pMac->lim.gLimAddtsRspTimerCount); + } + + if (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_ASSOC_CNF_STATE) { + lim_deactivate_and_change_per_sta_id_timer(pMac, eLIM_CNF_WAIT_TIMER, + pStaDs->assocId); + + if (!pStaDs->mlmStaContext.updateContext) { + /** + * There is no context at Polaris to delete. + * Release our assigned AID back to the free pool + */ + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_del_sta(pMac, pStaDs, false, psessionEntry); + lim_release_peer_idx(pMac, pStaDs->assocId, + psessionEntry); + } + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + + return retCode; + } + } + /* delete all tspecs associated with this sta. */ + lim_admit_control_delete_sta(pMac, pStaDs->assocId); + + /** + * Make STA hash entry invalid at eCPU so that DPH + * does not process any more data packets and + * releases those BDs + */ + pStaDs->valid = 0; + lim_send_sme_tsm_ie_ind(pMac, psessionEntry, 0, 0, 0); + /* Any roaming related changes should be above this line */ + if (lim_is_roam_synch_in_progress(psessionEntry)) + return QDF_STATUS_SUCCESS; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + if (LIM_IS_STA_ROLE(psessionEntry)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + psessionEntry->limMlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + /* Deactivating probe after heart beat timer */ + lim_deactivate_and_change_timer(pMac, eLIM_PROBE_AFTER_HB_TIMER); + lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); + } +#ifdef WLAN_DEBUG + /* increment a debug count */ + pMac->lim.gLimNumRxCleanup++; +#endif + /* Do DEL BSS or DEL STA only if ADD BSS was success */ + if (!psessionEntry->add_bss_failed) { + if (psessionEntry->limSmeState == eLIM_SME_JOIN_FAILURE_STATE) { + retCode = + lim_del_bss(pMac, pStaDs, psessionEntry->bssIdx, + psessionEntry); + } else + retCode = lim_del_sta(pMac, + pStaDs, true, psessionEntry); + } + + return retCode; + +} /*** end lim_cleanup_rx_path() ***/ + +/** + * lim_send_del_sta_cnf() - Send Del sta confirmation + * @pMac: Pointer to Global MAC structure + * @sta_dsaddr: sta ds address + * @staDsAssocId: sta ds association id + * @mlmStaContext: MLM station context + * @statusCode: Status code + * @psessionEntry: Session entry + * + * This function is called to send appropriate CNF message to SME. + * + * Return: None + */ +void +lim_send_del_sta_cnf(tpAniSirGlobal pMac, struct qdf_mac_addr sta_dsaddr, + uint16_t staDsAssocId, tLimMlmStaContext mlmStaContext, + tSirResultCodes statusCode, tpPESession psessionEntry) +{ + tLimMlmDisassocCnf mlmDisassocCnf; + tLimMlmDeauthCnf mlmDeauthCnf; + tLimMlmPurgeStaInd mlmPurgeStaInd; + + pe_debug("Sessionid: %d staDsAssocId: %d Trigger: %d statusCode: %d sta_dsaddr: "MAC_ADDRESS_STR, + psessionEntry->peSessionId, staDsAssocId, + mlmStaContext.cleanupTrigger, statusCode, + MAC_ADDR_ARRAY(sta_dsaddr.bytes)); + + if (LIM_IS_STA_ROLE(psessionEntry)) { + /* Set BSSID at CFG to null */ + tSirMacAddr nullAddr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + sir_copy_mac_addr(nullAddr, psessionEntry->bssId); + + /* Free up buffer allocated for JoinReq held by */ + /* MLM state machine */ + if (psessionEntry->pLimMlmJoinReq) { + qdf_mem_free(psessionEntry->pLimMlmJoinReq); + psessionEntry->pLimMlmJoinReq = NULL; + } + + psessionEntry->limAID = 0; + } + + if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DISASSOC) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DISASSOC) || + (mlmStaContext.cleanupTrigger == + eLIM_PROMISCUOUS_MODE_DISASSOC)) { + /** + * Host or LMM driven Disassociation. + * Issue Disassoc Confirm to SME. + */ + pe_debug("Lim Posting DISASSOC_CNF to Sme. Trigger: %d", + mlmStaContext.cleanupTrigger); + + qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + mlmDisassocCnf.resultCode = statusCode; + mlmDisassocCnf.disassocTrigger = mlmStaContext.cleanupTrigger; + /* Update PE session Id */ + mlmDisassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlmDisassocCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DEAUTH) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DEAUTH)) { + /** + * Host or LMM driven Deauthentication. + * Issue Deauth Confirm to SME. + */ + pe_debug("Lim Posting DEAUTH_CNF to Sme. Trigger: %d", + mlmStaContext.cleanupTrigger); + qdf_copy_macaddr(&mlmDeauthCnf.peer_macaddr, &sta_dsaddr); + mlmDeauthCnf.resultCode = statusCode; + mlmDeauthCnf.deauthTrigger = mlmStaContext.cleanupTrigger; + /* PE session Id */ + mlmDeauthCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DEAUTH_CNF, + (uint32_t *) &mlmDeauthCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_PEER_ENTITY_DISASSOC) || + (mlmStaContext.cleanupTrigger == eLIM_PEER_ENTITY_DEAUTH)) { + /** + * Received Disassociation/Deauthentication from peer. + * Issue Purge Ind to SME. + */ + pe_debug("Lim Posting PURGE_STA_IND to Sme. Trigger: %d", + mlmStaContext.cleanupTrigger); + 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 = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + 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; + uint16_t smetransactionId; + + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + + psessionEntry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->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, statusCode: %d," + "sessionId: %d", + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry->peSessionId); + + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry, smesessionId, + smetransactionId); + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + } else { + qdf_mem_free(psessionEntry->pLimJoinReq); + psessionEntry->pLimJoinReq = NULL; + + pe_debug("Lim Posting eWNI_SME_JOIN_RSP to SME." + "resultCode: %d,statusCode: %d," + "sessionId: %d", + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry->peSessionId); + + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_JOIN_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry, smesessionId, + smetransactionId); + + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + } + + } else if (mlmStaContext.cleanupTrigger == eLIM_DUPLICATE_ENTRY) { + /** + * LIM driven Disassociation. + * Issue Disassoc Confirm to SME. + */ + pe_debug("Lim Posting DISASSOC_CNF to Sme. Trigger: %d", + mlmStaContext.cleanupTrigger); + + qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + mlmDisassocCnf.resultCode = statusCode; + mlmDisassocCnf.disassocTrigger = eLIM_DUPLICATE_ENTRY; + /* Update PE session Id */ + mlmDisassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlmDisassocCnf); + } + + if (NULL != psessionEntry && !LIM_IS_AP_ROLE(psessionEntry)) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = 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(tpAniSirGlobal 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 eSirMacStatusCodes result_code, + tpPESession 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: " MAC_ADDRESS_STR, + session_entry->peSessionId, auth_type, sub_type, + add_pre_auth_context, sta_id, delete_sta, result_code, + MAC_ADDR_ARRAY(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); + } + } + + if (delete_sta == false) { + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS, + 1, peer_addr, sub_type, 0, session_entry); + pe_warn("received Re/Assoc req when max associated STAs reached from"); + lim_print_mac_addr(mac_ctx, peer_addr, LOGW); + lim_send_sme_max_assoc_exceeded_ntf(mac_ctx, peer_addr, + session_entry->smeSessionId); + return; + } + + sta_ds = dph_get_hash_entry(mac_ctx, sta_id, + &session_entry->dph.dphHashTable); + + if (sta_ds == NULL) { + 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); + + /* + * 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, 0, session_entry); + + if (session_entry->parsedAssocReq[sta_ds->assocId] != NULL) { + uint8_t *assoc_req_frame; + + assoc_req_frame = (uint8_t *)((tpSirAssocReq) (session_entry-> + parsedAssocReq[sta_ds->assocId]))->assocReqFrame; + /* + *Assoction confirmation is complete, + *free the copy of association request frame. + */ + if (assoc_req_frame) { + qdf_mem_free(assoc_req_frame); + assoc_req_frame = NULL; + } + + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i = 0; + + pe_debug("(%d) A HT 20 STA is disassociated. Addr is %pM", + session_entry->gLimHt20Params.numSta, 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(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t phy_mode; + tHalBitVal erp_enabled = eHAL_CLEAR; + enum band_info rf_band = BAND_UNKNOWN; + uint32_t i; + + if (NULL == 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 ((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 %pM", + session_entry->gLim11aParams.numSta, 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 ((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 %pM", + session_entry->gLim11bParams.numSta, 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 ((BAND_2G == rf_band) && + session_entry->htCapability && + !sta_ds->mlmStaContext.htCapability) { + pe_debug("(%d) A 11g STA is disassociated. Addr is %pM", + session_entry->gLim11bParams.numSta, 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 %pM", + session_entry->gLimNonGfParams.numSta, 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 %pM", + session_entry->gLimLsigTxopParams.numSta, + 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(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i; + + if (sta_ds->shortPreambleEnabled == eHAL_CLEAR) { + pe_debug("(%d) A non-short preamble STA is disassociated. Addr is %pM", + session_entry->gLimNoShortParams.numNonShortPreambleSta, + 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(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession 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 %pM", + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta, + sta_ds->staAddr); + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val); + + 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; + } +} + +/** + * 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 + * + * 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(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, + tDot11fIEVHTCaps *peer_vht_caps, + tpPESession session_entry, + uint8_t nss) +{ + uint32_t val; + uint32_t self_sta_dot11mode = 0; + uint16_t mcs_map_mask = MCSMAPMASK1x1; + uint16_t mcs_map_mask2x2 = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); + + if (!IS_DOT11_MODE_VHT(self_sta_dot11mode)) + return QDF_STATUS_SUCCESS; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RX_MCS_MAP, &val) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve VHT RX MCS MAP"); + goto error; + } + rates->vhtRxMCSMap = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TX_MCS_MAP, &val) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve VHT TX MCS MAP"); + goto error; + } + rates->vhtTxMCSMap = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + &val) != QDF_STATUS_SUCCESS) { + pe_err("couldn't retrieve VHT RX Supported data rate MAP"); + goto error; + } + rates->vhtRxHighestDataRate = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + &val) != QDF_STATUS_SUCCESS) { + pe_err("couldn't retrieve VHT RX Supported data rate MAP"); + goto error; + } + rates->vhtTxHighestDataRate = (uint16_t) val; + + 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 && + !mac_ctx->roam.configParam.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 && + !mac_ctx->roam.configParam.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 == NULL) || (!peer_vht_caps->present)) + return QDF_STATUS_SUCCESS; + + rates->vhtTxHighestDataRate = + QDF_MIN(rates->vhtTxHighestDataRate, + peer_vht_caps->txSupDataRate); + 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("enable2x2 - %d nss %d vhtRxMCSMap - %x vhtTxMCSMap - %x", + mac_ctx->roam.configParam.enable2x2, nss, + rates->vhtRxMCSMap, rates->vhtTxMCSMap); + + if (NULL != session_entry) { + session_entry->supported_nss_1x1 = + ((rates->vhtTxMCSMap & VHT_MCS_1x1) == + VHT_MCS_1x1) ? true : false; + pe_debug("VHT supported nss 1x1: %d", + session_entry->supported_nss_1x1); + } + + return QDF_STATUS_SUCCESS; +error: + + return QDF_STATUS_E_FAILURE; +} + +/** + * 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 + * + * 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(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, uint8_t *supported_mcs_set, + uint8_t basic_only, tpPESession session_entry, + struct sDot11fIEVHTCaps *vht_caps, + struct sDot11fIEhe_cap *he_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; + + is_arate = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); + 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 == WNI_CFG_DOT11_MODE_ALL) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11A) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11N) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11G) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11B)) { + val = WNI_CFG_SUPPORTED_RATES_11B_LEN; + wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11B, + (uint8_t *) &temp_rate_set.rate, &val); + temp_rate_set.numRates = (uint8_t) val; + } 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 = WNI_CFG_SUPPORTED_RATES_11A_LEN; + wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11A, + (uint8_t *) &temp_rate_set2.rate, &val); + temp_rate_set2.numRates = (uint8_t) val; + } 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((uint8_t *) rates, sizeof(tSirSupportedRates)); + 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_RATESET_EID_MAX); 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 = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + rates->supportedMCSSet, + &val) != 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 != NULL) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + rates->supportedMCSSet[i] &= + supported_mcs_set[i]; + } + + pe_debug("MCS Rate Set Bitmap: "); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + pe_debug("%x ", rates->supportedMCSSet[i]); + } + lim_populate_vht_mcs_set(mac_ctx, rates, vht_caps, + session_entry, session_entry->nss); + lim_populate_he_mcs_set(mac_ctx, rates, he_caps, + session_entry, session_entry->nss); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11AX +/** + * lim_calculate_he_nss() - function to calculate new nss from he rates + * @rates: supported rtes struct object + * @session: pe session entry + * This function calculates nss from rx_he_mcs_map_lt_80 within rates struct + * object and assigns new value to nss within pe_session + * + * Return: None + */ +static void lim_calculate_he_nss(tpSirSupportedRates rates, tpPESession session) +{ + HE_GET_NSS(rates->rx_he_mcs_map_lt_80, session->nss); +} +#else +static void lim_calculate_he_nss(tpSirSupportedRates rates, tpPESession session) +{ +} +#endif + +QDF_STATUS +lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, uint8_t *pSupportedMCSSet, + uint8_t basicOnly, tpPESession psessionEntry, + tDot11fIEVHTCaps *pVHTCaps, tDot11fIEhe_cap *he_caps) +{ + tSirMacRateSet tempRateSet; + tSirMacRateSet tempRateSet2; + uint32_t i, j, val, min, isArate = 0; + + /* copy operational rate set from psessionEntry */ + if (psessionEntry->rateSet.numRates <= SIR_MAC_RATESET_EID_MAX) { + qdf_mem_copy((uint8_t *) tempRateSet.rate, + (uint8_t *) (psessionEntry->rateSet.rate), + psessionEntry->rateSet.numRates); + tempRateSet.numRates = psessionEntry->rateSet.numRates; + } else { + pe_err("more than SIR_MAC_RATESET_EID_MAX rates"); + return QDF_STATUS_E_FAILURE; + } + if ((psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11G) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11A) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11N)) { + if (psessionEntry->extRateSet.numRates <= + SIR_MAC_RATESET_EID_MAX) { + qdf_mem_copy((uint8_t *) tempRateSet2.rate, + (uint8_t *) (psessionEntry->extRateSet. + rate), + psessionEntry->extRateSet.numRates); + tempRateSet2.numRates = + psessionEntry->extRateSet.numRates; + } else { + pe_err("psessionEntry->extRateSet.numRates more than SIR_MAC_RATESET_EID_MAX rates"); + return QDF_STATUS_E_FAILURE; + } + } else + tempRateSet2.numRates = 0; + if ((tempRateSet.numRates + tempRateSet2.numRates) > + SIR_MAC_RATESET_EID_MAX) { + pe_err("more than 12 rates in CFG"); + 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 + */ + { + uint8_t aRateIndex = 0; + uint8_t bRateIndex = 0; + + qdf_mem_zero((uint8_t *) pRates, sizeof(tSirSupportedRates)); + for (i = 0; i < tempRateSet.numRates; i++) { + min = 0; + val = 0xff; + isArate = 0; + for (j = 0; + (j < tempRateSet.numRates) + && (j < SIR_MAC_RATESET_EID_MAX); j++) { + if ((uint32_t) (tempRateSet.rate[j] & 0x7f) < + val) { + val = tempRateSet.rate[j] & 0x7f; + min = j; + } + } + if (sirIsArate(tempRateSet.rate[min] & 0x7f)) + isArate = 1; + /* + * 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) { + if (tempRateSet.rate[min] & 0x80) { + if (isArate) + pRates->llaRates[aRateIndex++] = + tempRateSet.rate[min]; + else + pRates->llbRates[bRateIndex++] = + tempRateSet.rate[min]; + } + } else { + if (isArate) + pRates->llaRates[aRateIndex++] = + tempRateSet.rate[min]; + else + pRates->llbRates[bRateIndex++] = + tempRateSet.rate[min]; + } + tempRateSet.rate[min] = 0xff; + } + } + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + pRates->supportedMCSSet, + &val) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve supportedMCSSet"); + return QDF_STATUS_E_FAILURE; + } + if (psessionEntry->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 != NULL) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + pRates->supportedMCSSet[i] &= + pSupportedMCSSet[i]; + } + pe_debug("MCS Rate Set Bitmap: "); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + pe_debug("%x ", pRates->supportedMCSSet[i]); + + if (pRates->supportedMCSSet[0] == 0) { + pe_debug("Incorrect MCS 0 - 7. They must be supported"); + pRates->supportedMCSSet[0] = 0xFF; + } + + psessionEntry->supported_nss_1x1 = + ((pRates->supportedMCSSet[1] != 0) ? false : true); + pe_debug("HT supported nss 1x1: %d", + psessionEntry->supported_nss_1x1); + } + lim_populate_vht_mcs_set(pMac, pRates, pVHTCaps, + psessionEntry, psessionEntry->nss); + + lim_populate_he_mcs_set(pMac, pRates, he_caps, + psessionEntry, psessionEntry->nss); + + if (IS_DOT11_MODE_HE(psessionEntry->dot11mode) && he_caps) { + lim_calculate_he_nss(pRates, psessionEntry); + } else if (IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) { + if ((pRates->vhtRxMCSMap & MCSMAPMASK2x2) == MCSMAPMASK2x2) + psessionEntry->nss = NSS_1x1_MODE; + } else if (pRates->supportedMCSSet[1] == 0) { + psessionEntry->nss = NSS_1x1_MODE; + } + pe_debug("nss: %d", psessionEntry->nss); + + 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 + * + * 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 + * or Beacon/Probe Response from peer in IBSS. + * + * 1. It makes the intersection between our own rate Sat + * and extemcded 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(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tSirMacRateSet *oper_rate_set, + tSirMacRateSet *ext_rate_set, + uint8_t *supported_mcs_set, + tpPESession session_entry, + tDot11fIEVHTCaps *vht_caps, + tDot11fIEhe_cap *he_caps) +{ + tSirMacRateSet temp_rate_set; + tSirMacRateSet temp_rate_set2; + uint32_t i, j, val, min, is_arate; + uint32_t phy_mode; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + tpSirSupportedRates rates; + uint8_t a_rate_index = 0; + uint8_t b_rate_index = 0; + + 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; + } else { + temp_rate_set2.numRates = 0; + } + + /* + * absolute sum of both num_rates should be less than 12. following + * 16-bit sum avoids false codition where 8-bit arthematic overflow + * might have caused total sum to be less than 12 + */ + if (((uint16_t)temp_rate_set.numRates + + (uint16_t)temp_rate_set2.numRates) > 12) { + 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_RATESET_EID_MAX); 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_RATESET_EID_MAX); 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_RATESET_EID_MAX) && + ((i + j) < SIR_MAC_RATESET_EID_MAX)); 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((uint8_t *) rates, sizeof(tSirSupportedRates)); + for (i = 0; (i < temp_rate_set2.numRates && + i < SIR_MAC_RATESET_EID_MAX); i++) { + for (j = 0; (j < temp_rate_set.numRates && + j < SIR_MAC_RATESET_EID_MAX); 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 = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, &val) != 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; i++) + sta_ds->supportedRates.supportedMCSSet[i] = + mcs_set[i] & supported_mcs_set[i]; + + pe_debug("lim_populate_matching_rate_set: MCS Rate Set Bitmap" + " from CFG and DPH : "); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { + pe_debug("%x %x ", mcs_set[i], + sta_ds->supportedRates.supportedMCSSet[i]); + } + } + lim_populate_vht_mcs_set(mac_ctx, &sta_ds->supportedRates, vht_caps, + session_entry, session_entry->nss); + lim_populate_he_mcs_set(mac_ctx, &sta_ds->supportedRates, he_caps, + session_entry, session_entry->nss); + /* + * 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.reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + + 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; +} +#else +static void lim_update_he_stbc_capable(tpAddStaParams add_sta_params) +{} +#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(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, uint8_t update_entry, tpPESession 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; + tLimIbssPeerNode *peer_node; /* for IBSS mode */ + const uint8_t *p2p_ie = NULL; + tDot11fIEVHTCaps vht_caps; + + sir_copy_mac_addr(sta_mac, session_entry->selfMacAddr); + + pe_debug("sessionid: %d update_entry = %d limsystemrole = %d", + session_entry->smeSessionId, update_entry, + GET_LIM_SYSTEM_ROLE(session_entry)); + + add_sta_params = qdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == add_sta_params) { + pe_err("Unable to allocate memory during ADD_STA"); + return QDF_STATUS_E_NOMEM; + } + + if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_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; + + pe_debug(MAC_ADDRESS_STR ": Subtype(Assoc/Reassoc): %d", + MAC_ADDR_ARRAY(*sta_Addr), sta_ds->mlmStaContext.subType); + + 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((uint8_t *) &add_sta_params->supportedRates, + (uint8_t *) &sta_ds->supportedRates, + sizeof(tSirSupportedRates)); + + add_sta_params->assocId = sta_ds->assocId; + + add_sta_params->wmmEnabled = sta_ds->qosMode; + add_sta_params->listenInterval = sta_ds->mlmStaContext.listenInterval; + add_sta_params->shortPreambleSupported = sta_ds->shortPreambleEnabled; + 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; + + pe_debug("Assoc ID: %d wmmEnabled: %d listenInterval: %d" + " shortPreambleSupported: %d", add_sta_params->assocId, + add_sta_params->wmmEnabled, add_sta_params->listenInterval, + add_sta_params->shortPreambleSupported); + /* This will indicate HAL to "allocate" a new STA index */ +#ifdef FEATURE_WLAN_TDLS + /* + * As there is corner case in-between add_sta and change_sta,if del_sta + * for other staIdx happened, firmware return wrong staIdx + * (recently removed staIdx). Until we get a confirmation from the + * firmware team it is now return correct staIdx for same sta_mac_addr + * for update case, we want to get around it by passing valid staIdx + * given by add_sta time. + */ + if ((STA_ENTRY_TDLS_PEER == sta_ds->staType) && (true == update_entry)) + add_sta_params->staIdx = sta_ds->staIndex; + else +#endif + add_sta_params->staIdx = STA_INVALID_IDX; + add_sta_params->staType = sta_ds->staType; + + add_sta_params->updateSta = update_entry; + + add_sta_params->status = QDF_STATUS_SUCCESS; + add_sta_params->respReqd = 1; + + /* Update VHT/HT Capability */ + if (LIM_IS_AP_ROLE(session_entry) || + LIM_IS_IBSS_ROLE(session_entry)) { + add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; + add_sta_params->vhtCapable = + sta_ds->mlmStaContext.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; + } + + pe_debug("StaIdx: %d updateSta: %d htcapable: %d vhtCapable: %d", + add_sta_params->staIdx, add_sta_params->updateSta, + add_sta_params->htCapable, add_sta_params->vhtCapable); + + /* + * 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) { + pe_debug("setting SMPS intolrent vdev_param"); + 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); + + add_sta_params->greenFieldCapable = sta_ds->htGreenfield; + add_sta_params->maxAmpduDensity = sta_ds->htAMpduDensity; + add_sta_params->maxAmpduSize = sta_ds->htMaxRxAMpduFactor; + add_sta_params->fDsssCckMode40Mhz = sta_ds->htDsssCckRate40MHzSupport; + add_sta_params->fShortGI20Mhz = sta_ds->htShortGI20Mhz; + add_sta_params->fShortGI40Mhz = sta_ds->htShortGI40Mhz; + add_sta_params->lsigTxopProtection = sta_ds->htLsigTXOPProtection; + add_sta_params->maxAmsduSize = sta_ds->htMaxAmsduLength; + add_sta_params->ch_width = sta_ds->htSupportedChannelWidthSet; + add_sta_params->mimoPS = sta_ds->htMIMOPSState; + + pe_debug("greenFieldCapable: %d maxAmpduDensity: %d maxAmpduDensity: %d", + add_sta_params->greenFieldCapable, + add_sta_params->maxAmpduDensity, add_sta_params->maxAmpduSize); + + pe_debug("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d fShortGI40Mhz: %d", + add_sta_params->fDsssCckMode40Mhz, + add_sta_params->fShortGI20Mhz, add_sta_params->fShortGI40Mhz); + + pe_debug("lsigTxopProtection: %d maxAmsduSize: %d txChannelWidth: %d mimoPS: %d", + add_sta_params->lsigTxopProtection, + add_sta_params->maxAmsduSize, add_sta_params->ch_width, + add_sta_params->mimoPS); + + 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; + } + + pe_debug("TxChWidth %d vhtTxBFCap %d, su_bfer %d", + add_sta_params->ch_width, add_sta_params->vhtTxBFCapable, + add_sta_params->enable_su_tx_bformer); +#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 + && mac_ctx->lim.disableLDPCWithTxbfAP) { + 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 != NULL) { + 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(add_sta_params, assoc_req); + + } else if (LIM_IS_IBSS_ROLE(session_entry)) { + + /* + * in IBSS mode, use peer node as the source of ht_caps + * and vht_caps + */ + peer_node = lim_ibss_peer_find(mac_ctx, *sta_Addr); + if (!peer_node) { + pe_err("Can't find IBSS peer node for ADD_STA"); + return QDF_STATUS_E_NOENT; + } + + if (peer_node->atimIePresent) { + add_sta_params->atimIePresent = + peer_node->atimIePresent; + add_sta_params->peerAtimWindowLength = + peer_node->peerAtimWindowLength; + } + + add_sta_params->ht_caps = + (peer_node->htSupportedChannelWidthSet << + SIR_MAC_HT_CAP_CHWIDTH40_S) | + (peer_node->htGreenfield << + SIR_MAC_HT_CAP_GREENFIELD_S) | + (peer_node->htShortGI20Mhz << + SIR_MAC_HT_CAP_SHORTGI20MHZ_S) | + (peer_node->htShortGI40Mhz << + SIR_MAC_HT_CAP_SHORTGI40MHZ_S) | + (SIR_MAC_TXSTBC << + SIR_MAC_HT_CAP_TXSTBC_S) | + (SIR_MAC_RXSTBC << + SIR_MAC_HT_CAP_RXSTBC_S) | + (peer_node->htMaxAmsduLength << + SIR_MAC_HT_CAP_MAXAMSDUSIZE_S) | + (peer_node->htDsssCckRate40MHzSupport << + SIR_MAC_HT_CAP_DSSSCCK40_S); + + add_sta_params->vht_caps = + lim_populate_vht_caps(peer_node->VHTCaps); + } +#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); + } + pe_debug("Sta type is TDLS_PEER, ht_caps: 0x%x, vht_caps: 0x%x", + add_sta_params->ht_caps, + add_sta_params->vht_caps); + } +#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; + pe_debug("uAPSD = 0x%x, maxSpLen = %d", + add_sta_params->uAPSD, add_sta_params->maxSPLen); + } +#ifdef WLAN_FEATURE_11W + add_sta_params->rmfEnabled = sta_ds->rmfEnabled; + pe_debug("PMF enabled %d", add_sta_params->rmfEnabled); +#endif + + pe_debug("htLdpcCapable: %d vhtLdpcCapable: %d " + "p2pCapableSta: %d", + add_sta_params->htLdpcCapable, add_sta_params->vhtLdpcCapable, + add_sta_params->p2pCapableSta); + + 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. + */ + if (add_sta_params->respReqd) + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, false); + + add_sta_params->nwType = session_entry->nwType; + + if (!(add_sta_params->htCapable || add_sta_params->vhtCapable)) { + 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->htConfig.ht_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; + } + + lim_update_he_stbc_capable(add_sta_params); + + 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 for assocId %d", sta_ds->assocId); + 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) { + if (add_sta_params->respReqd) + 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 pMac - Pointer to Global MAC structure + * @param pStaDs - 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(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, bool fRespReqd, tpPESession psessionEntry) +{ + tpDeleteStaParams pDelStaParams = NULL; + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + pDelStaParams = qdf_mem_malloc(sizeof(tDeleteStaParams)); + if (NULL == pDelStaParams) { + pe_err("Unable to allocate memory during ADD_STA"); + 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(pMac->psoc) && + LIM_IS_AP_ROLE(psessionEntry) && + (pStaDs->staType == STA_ENTRY_PEER) && + !pStaDs->mlmStaContext.vhtCapability && + (psessionEntry->nss == 2)) { + psessionEntry->ht_client_cnt--; + if (psessionEntry->ht_client_cnt == 0) { + pe_debug("clearing SMPS intolrent vdev_param"); + wma_cli_set_command(psessionEntry->smeSessionId, + (int)WMI_VDEV_PARAM_SMPS_INTOLERANT, + 0, VDEV_CMD); + } + } + /* */ + /* DPH contains the STA index only for "peer" STA entries. */ + /* LIM global contains "self" STA index */ + /* Thus, */ + /* if( STA role ) */ + /* get STA index from LIM global */ + /* else */ + /* get STA index from DPH */ + /* */ + +#ifdef FEATURE_WLAN_TDLS + if (LIM_IS_STA_ROLE(psessionEntry) && + (pStaDs->staType != STA_ENTRY_TDLS_PEER)) +#else + if (LIM_IS_STA_ROLE(psessionEntry)) +#endif + pDelStaParams->staIdx = psessionEntry->staId; + + else + pDelStaParams->staIdx = pStaDs->staIndex; + + pDelStaParams->assocId = pStaDs->assocId; + pStaDs->valid = 0; + + if (!fRespReqd) + pDelStaParams->respReqd = 0; + else { + if (!(IS_TDLS_PEER(pStaDs->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(pStaDs)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + SET_LIM_STA_CONTEXT_MLM_STATE(pStaDs, + eLIM_MLM_WT_DEL_STA_RSP_STATE); + } + if (LIM_IS_STA_ROLE(psessionEntry)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + + psessionEntry->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(pMac, false); + + pDelStaParams->respReqd = 1; + } + + /* Update PE session ID */ + pDelStaParams->sessionId = psessionEntry->peSessionId; + pDelStaParams->smesessionId = psessionEntry->smeSessionId; + + pDelStaParams->staType = pStaDs->staType; + qdf_mem_copy((uint8_t *) pDelStaParams->staMac, + (uint8_t *) pStaDs->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 STAID: %X and AssocID: %d MAC : " + MAC_ADDRESS_STR, pDelStaParams->sessionId, + pDelStaParams->staIdx, pDelStaParams->assocId, + MAC_ADDR_ARRAY(pStaDs->staAddr)); + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + if (fRespReqd) + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pe_err("Posting DELETE_STA_REQ to HAL failed, reason=%X", + retCode); + qdf_mem_free(pDelStaParams); + } + + return retCode; +} + + +/** + * 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 pMac - Pointer to Global MAC structure + * @param pStaDs - 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(tpAniSirGlobal pMac, uint16_t staIdx, uint8_t updateSta, + tpPESession psessionEntry) +{ + tpAddStaParams pAddStaParams = NULL; + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + tSirMacAddr staMac; + uint32_t listenInterval = WNI_CFG_LISTEN_INTERVAL_STADEF; + uint32_t ampduLenExponent = 0; + /*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, selfTxWidth = 0; + uint32_t val; + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfStaDot11Mode); + wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO_SUPPORTED_CHAN_WIDTH_SET, + &selfTxWidth); + pe_debug("cfgDot11Mode: %d selfTxWidth: %d", + (int)selfStaDot11Mode, (int)selfTxWidth); + pe_debug("Roam Channel Bonding Mode %d", + (int)pMac->roam.configParam.uCfgDot11Mode); + + sir_copy_mac_addr(staMac, psessionEntry->selfMacAddr); + pe_debug(MAC_ADDRESS_STR ": ", MAC_ADDR_ARRAY(staMac)); + pAddStaParams = qdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == pAddStaParams) { + pe_err("Unable to allocate memory during ADD_STA"); + 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, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->assocId = psessionEntry->limAID; + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = QDF_STATUS_SUCCESS; + pAddStaParams->respReqd = 1; + + /* Update PE session ID */ + pAddStaParams->sessionId = psessionEntry->peSessionId; + + /* Update SME session ID */ + pAddStaParams->smesessionId = psessionEntry->smeSessionId; + + pAddStaParams->maxTxPower = psessionEntry->maxTxPower; + + /* This will indicate HAL to "allocate" a new STA index */ + pAddStaParams->staIdx = staIdx; + pAddStaParams->updateSta = updateSta; + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != + QDF_STATUS_SUCCESS) { + pe_err("Couldn't get SHORT_PREAMBLE, set default"); + pAddStaParams->shortPreambleSupported = 1; + } else { + pAddStaParams->shortPreambleSupported = val; + } + + lim_populate_own_rate_set(pMac, &pAddStaParams->supportedRates, NULL, false, + psessionEntry, NULL, NULL); + if (IS_DOT11_MODE_HT(selfStaDot11Mode)) { + pAddStaParams->htCapable = true; +#ifdef DISABLE_GF_FOR_INTEROP + if ((psessionEntry->pLimJoinReq != NULL) + && (!psessionEntry->pLimJoinReq->bssDescription. + aniIndicator)) { + pe_err("Turning off Greenfield, when adding self entry"); + pAddStaParams->greenFieldCapable = + WNI_CFG_GREENFIELD_CAPABILITY_DISABLE; + } else +#endif + { + pAddStaParams->greenFieldCapable = + lim_get_ht_capability(pMac, eHT_GREENFIELD, + psessionEntry); + pAddStaParams->ch_width = + pMac->roam.configParam.channelBondingMode5GHz; + pAddStaParams->mimoPS = + lim_get_ht_capability(pMac, eHT_MIMO_POWER_SAVE, + psessionEntry); + pAddStaParams->rifsMode = + lim_get_ht_capability(pMac, eHT_RIFS_MODE, + psessionEntry); + pAddStaParams->lsigTxopProtection = + lim_get_ht_capability(pMac, eHT_LSIG_TXOP_PROTECTION, + psessionEntry); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(pMac, eHT_MPDU_DENSITY, + psessionEntry); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(pMac, eHT_MAX_RX_AMPDU_FACTOR, + psessionEntry); + pAddStaParams->maxAmsduSize = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_LENGTH, + psessionEntry); + pAddStaParams->max_amsdu_num = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_NUM, + psessionEntry); + pAddStaParams->fDsssCckMode40Mhz = + lim_get_ht_capability(pMac, eHT_DSSS_CCK_MODE_40MHZ, + psessionEntry); + pAddStaParams->fShortGI20Mhz = + psessionEntry->htConfig.ht_sgi20; + pAddStaParams->fShortGI40Mhz = + psessionEntry->htConfig.ht_sgi40; + pe_debug("greenFieldCapable: %d maxAmpduDensity: %d " + "maxAmpduSize: %d", + pAddStaParams->greenFieldCapable, + pAddStaParams->maxAmpduDensity, + pAddStaParams->maxAmpduSize); + + pe_debug("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d " + "fShortGI40Mhz: %d lsigTxopProtection: %d", + pAddStaParams->fDsssCckMode40Mhz, + pAddStaParams->fShortGI20Mhz, + pAddStaParams->fShortGI40Mhz, + pAddStaParams->lsigTxopProtection); + + pe_debug("maxAmsduSize: %d txChannelWidth: %d mimoPS: %d rifsMode %d", + pAddStaParams->maxAmsduSize, + pAddStaParams->ch_width, + pAddStaParams->mimoPS, pAddStaParams->rifsMode); + } + } + pAddStaParams->vhtCapable = IS_DOT11_MODE_VHT(selfStaDot11Mode); + if (pAddStaParams->vhtCapable) { + pAddStaParams->ch_width = + psessionEntry->ch_width; + pe_debug("VHT WIDTH SET %d", pAddStaParams->ch_width); + } + pAddStaParams->vhtTxBFCapable = + psessionEntry->vht_config.su_beam_formee; + pAddStaParams->enable_su_tx_bformer = + psessionEntry->vht_config.su_beam_former; + pe_debug("vhtCapable: %d vhtTxBFCapable %d, su_bfer %d", + pAddStaParams->vhtCapable, pAddStaParams->vhtTxBFCapable, + pAddStaParams->enable_su_tx_bformer); + + /* In 11ac mode, the hardware is capable of supporting 128K AMPDU size */ + if (IS_DOT11_MODE_VHT(selfStaDot11Mode)) { + if (wlan_cfg_get_int + (pMac, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &duLenExponent) + != QDF_STATUS_SUCCESS) { + pe_err("Couldn't get WNI_CFG_VHT_AMPDU_LEN_EXPONENT"); + } + pAddStaParams->maxAmpduSize = (uint8_t) ampduLenExponent; + } + pAddStaParams->vhtTxMUBformeeCapable = + psessionEntry->vht_config.mu_beam_formee; + pAddStaParams->enableVhtpAid = psessionEntry->enableVhtpAid; + pAddStaParams->enableAmpduPs = psessionEntry->enableAmpduPs; + pAddStaParams->enableHtSmps = (psessionEntry->enableHtSmps && + (!psessionEntry->supported_nss_1x1)); + pAddStaParams->htSmpsconfig = psessionEntry->htSmpsvalue; + pAddStaParams->send_smps_action = + psessionEntry->send_smps_action; + + /* For Self STA get the LDPC capability from session i.e config.ini */ + pAddStaParams->htLdpcCapable = + (psessionEntry->txLdpcIniFeatureEnabled & 0x01); + pAddStaParams->vhtLdpcCapable = + ((psessionEntry->txLdpcIniFeatureEnabled >> 1) & 0x01); + + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != + QDF_STATUS_SUCCESS) + pe_err("Couldn't get LISTEN_INTERVAL"); + + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + if (QDF_P2P_CLIENT_MODE == psessionEntry->pePersona) { + pAddStaParams->p2pCapableSta = 1; + } + + pe_debug(" StaIdx: %d updateSta = %d htcapable = %d ", + pAddStaParams->staIdx, pAddStaParams->updateSta, + pAddStaParams->htCapable); + + pe_debug("htLdpcCapable: %d vhtLdpcCapable: %d " + "p2pCapableSta: %d", + pAddStaParams->htLdpcCapable, pAddStaParams->vhtLdpcCapable, + pAddStaParams->p2pCapableSta); + + if (psessionEntry->isNonRoamReassoc) { + pAddStaParams->nonRoamReassoc = 1; + psessionEntry->isNonRoamReassoc = 0; + } + pe_debug("sessionid: %d Assoc ID: %d listenInterval = %d " + "shortPreambleSupported: %d", + psessionEntry->smeSessionId, pAddStaParams->assocId, + pAddStaParams->listenInterval, + pAddStaParams->shortPreambleSupported); + + if (IS_DOT11_MODE_HE(selfStaDot11Mode)) + lim_add_self_he_cap(pAddStaParams, psessionEntry); + + msgQ.type = WMA_ADD_STA_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pAddStaParams; + msgQ.bodyval = 0; + + pe_debug(MAC_ADDRESS_STR ":Sessionid %d : " + "Sending WMA_ADD_STA_REQ. (aid %d)", + MAC_ADDR_ARRAY(pAddStaParams->staMac), + pAddStaParams->sessionId, pAddStaParams->assocId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &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; +} + +/** + * limTeardownInfraBSS() + * + ***FUNCTION: + * This function is called by various LIM functions to teardown + * an established Infrastructure BSS + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_teardown_infra_bss(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + /** + * Send Broadcast Disassociate frame with + * 'leaving BSS' reason. + */ + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON, + bcAddr, psessionEntry, false); +} /*** end lim_teardown_infra_bss() ***/ + +/** + * lim_handle_cnf_wait_timeout() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue to handle + * various confirmation failure cases. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to a sta descriptor + * @return None + */ + +void lim_handle_cnf_wait_timeout(tpAniSirGlobal pMac, uint16_t staId) +{ + tpDphHashNode pStaDs; + tpPESession psessionEntry = NULL; + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + pStaDs = dph_get_hash_entry(pMac, staId, &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + pe_err("No STA context in SIR_LIM_CNF_WAIT_TIMEOUT"); + return; + } + + switch (pStaDs->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", + pStaDs->assocId); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOGD); + + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext.subType, + true, + pStaDs->mlmStaContext.authType, + pStaDs->assocId, true, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + } + break; + + default: + pe_warn("Received CNF_WAIT_TIMEOUT in state %d", + pStaDs->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(tpAniSirGlobal mac_ctx, tSirMacAddr sta_addr, + uint16_t sta_id, tpPESession 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 (NULL == session_entry) { + pe_err("NULL session_entry"); + return; + } + + beacon_params.bssIdx = session_entry->bssIdx; + sta_ds = dph_lookup_hash_entry(mac_ctx, sta_addr, &aid, + &session_entry->dph.dphHashTable); + + if (sta_ds == NULL) { + pe_err("sta_ds is NULL"); + return; + } + + pe_debug("Deleting DPH Hash entry for STAID: %X", sta_id); + /* + * 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) || LIM_IS_IBSS_ROLE(session_entry)) { + if (LIM_IS_AP_ROLE(session_entry)) { + if (session_entry->gLimProtectionControl != + WNI_CFG_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); + } + } + + if (LIM_IS_IBSS_ROLE(session_entry)) + lim_ibss_decide_protection_on_delete(mac_ctx, sta_ds, + &beacon_params, session_entry); + + 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); + +#ifdef WLAN_FEATURE_11W + if (sta_ds->rmfEnabled) { + pe_debug("delete pmf timer sta-idx:%d assoc-id:%d", + sta_ds->staIndex, sta_ds->assocId); + tx_timer_delete(&sta_ds->pmfSaQueryTimer); + } +#endif + } + + 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_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(tpAniSirGlobal mac_ctx, + tSirProbeRespBeacon *beacon_probe_rsp, tpSirMacMgmtHdr header, + tpPESession session_entry) +{ + tSirMacSSid current_ssid; + tLimMlmJoinCnf mlm_join_cnf; + uint32_t val = 0; + uint32_t *noa_duration_from_beacon = NULL; + uint32_t *noa2_duration_from_beacon = NULL; + uint32_t noa; + uint32_t total_num_noa_desc = 0; + + 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"); +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimBcnSSIDMismatchCnt++; +#endif + return; + } + + if (!LIM_IS_STA_ROLE(session_entry)) + return; + + pe_debug("Received Beacon/PR with matching BSSID:%pM PESessionID %d", + session_entry->bssId, session_entry->peSessionId); + + /* 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->pePersona && + 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 */ + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, &val) == + QDF_STATUS_SUCCESS) { + session_entry->defaultAuthFailureTimeout = val; + cfg_set_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + val + noa); + } + } else { + session_entry->defaultAuthFailureTimeout = 0; + } + + + /* + * Check if MBO Association disallowed subattr is present and post + * failure status to LIM if present + */ + if (!session_entry->ignore_assoc_disallowed && + beacon_probe_rsp->assoc_disallowed) { + pe_err("Connection fails due to assoc disallowed reason(%d):%pM PESessionID %d", + beacon_probe_rsp->assoc_disallowed_reason, + session_entry->bssId, + session_entry->peSessionId); + mlm_join_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + 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 = eSIR_MAC_SUCCESS_STATUS; + /* 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 ((IS_DOT11_MODE_VHT(session_entry->dot11mode)) && + 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)); + } +} + +/** + * 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 pMac 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(tpAniSirGlobal pMac, + uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct) +{ + qdf_mem_zero((uint8_t *) beaconStruct, sizeof(tSirProbeRespBeacon)); + + pe_debug("lim_extract_ap_capabilities: The IE's being received are:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + pIE, ieLen); + /* 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(pMac, 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 pMac - Pointer to Global MAC structure + * @param pStaDs - 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(tpAniSirGlobal pMac, tpDphHashNode pStaDs, uint16_t bssIdx, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBssParams = NULL; + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + pDelBssParams = qdf_mem_malloc(sizeof(tDeleteBssParams)); + if (NULL == pDelBssParams) { + pe_err("Unable to allocate memory during ADD_BSS"); + return QDF_STATUS_E_NOMEM; + } + + pDelBssParams->sessionId = psessionEntry->peSessionId; /* update PE session Id */ + + /* DPH was storing the AssocID in staID field, */ + /* staID is actually assigned by HAL when AddSTA message is sent. */ + if (pStaDs != NULL) { + pDelBssParams->bssIdx = pStaDs->bssId; + pStaDs->valid = 0; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + } else + pDelBssParams->bssIdx = bssIdx; + psessionEntry->limMlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_BSS_RSP_STATE)); + + if ((psessionEntry->peSessionId == + pMac->lim.limTimers.gLimJoinFailureTimer.sessionId) + && (true == + tx_timer_running(&pMac->lim.limTimers.gLimJoinFailureTimer))) { + lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); + } + + pDelBssParams->status = QDF_STATUS_SUCCESS; + pDelBssParams->respReqd = 1; + qdf_mem_copy(pDelBssParams->bssid, psessionEntry->bssId, + sizeof(tSirMacAddr)); + pDelBssParams->smesessionId = psessionEntry->smeSessionId; + pe_debug("Sessionid %d : Sending HAL_DELETE_BSS_REQ " + "for bss idx: %X BSSID:" MAC_ADDRESS_STR, + pDelBssParams->sessionId, pDelBssParams->bssIdx, + MAC_ADDR_ARRAY(psessionEntry->bssId)); + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + pe_debug("process_ho_fail = %d", psessionEntry->process_ho_fail); + if (psessionEntry->process_ho_fail) + msgQ.type = WMA_DELETE_BSS_HO_FAIL_REQ; + else + msgQ.type = WMA_DELETE_BSS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pDelBssParams; + msgQ.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pe_err("Posting DELETE_BSS_REQ to HAL failed, reason=%X", + retCode); + qdf_mem_free(pDelBssParams); + } + + 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. + * @psessionEntry : session entry. + * + * Return : void + */ +static void lim_update_vhtcaps_assoc_resp(tpAniSirGlobal mac_ctx, + tpAddBssParams pAddBssParams, + tDot11fIEVHTCaps *vht_caps, tpPESession psessionEntry) +{ + 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->reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + + pAddBssParams->staContext.maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + pAddBssParams->staContext.vht_caps); + + pe_debug("Updating VHT caps in assoc Response"); +} + +/** + * 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_oper: VHT Operations to update. + * @psessionEntry : session entry. + * + * Return : void + */ +static void lim_update_vht_oper_assoc_resp(tpAniSirGlobal mac_ctx, + tpAddBssParams pAddBssParams, + tDot11fIEVHTOperation *vht_oper, tpPESession psessionEntry) +{ + if (vht_oper->chanWidth && + psessionEntry->ch_width) { + pAddBssParams->ch_width = vht_oper->chanWidth + 1; + + pAddBssParams->ch_center_freq_seg0 = + vht_oper->chanCenterFreqSeg1; + + pAddBssParams->ch_center_freq_seg1 = + vht_oper->chanCenterFreqSeg2; + } + pe_debug("Updating VHT Operation in assoc Response"); +} + +#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, tpPESession 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, + tpPESession session) +{ +} +#endif + +/** + * limSendAddBss() + * + ***FUNCTION: + * + ***LOGIC: + * 1) LIM receives eWNI_SME_JOIN_REQ + * 2) For a valid eWNI_SME_JOIN_REQ, LIM sends + * SIR_HAL_ADD_BSS_REQ to HAL + * + ***ASSUMPTIONS: + * JOIN REQ parameters are saved in pMac->lim.gLimMlmJoinReq + * ADD BSS parameters can be obtained from two sources: + * 1) pMac->lim.gLimMlmJoinReq + * 2) beaconStruct, passed as parameter + * So, if a reqd parameter is found in bssDescriptions + * then it is given preference over beaconStruct + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * pAssocRsp contains the structured assoc/reassoc Response got from AP + * beaconstruct Has the ProbeRsp/Beacon structured details + * bssDescription bssDescription passed to PE from the SME + * @return None + */ + +QDF_STATUS lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + tpSirBssDescription bssDescription, + uint8_t updateEntry, tpPESession psessionEntry) +{ + struct scheduler_msg msgQ = {0}; + tpAddBssParams pAddBssParams = NULL; + uint32_t retCode; + tpDphHashNode pStaDs = NULL; + uint8_t chanWidthSupp = 0; + bool is_vht_cap_in_vendor_ie = false; + uint32_t enableTxBF20MHz; + tDot11fIEVHTCaps *vht_caps = NULL; + tDot11fIEVHTOperation *vht_oper = NULL; + tAddStaParams *sta_context; + uint32_t listen_interval = WNI_CFG_LISTEN_INTERVAL_STADEF; + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + pe_err("Unable to allocate memory during ADD_BSS"); + retCode = QDF_STATUS_E_NOMEM; + goto returnFailure; + } + + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(pAddBssParams->selfMacAddr, + psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); + + pe_debug("sessionid: %d updateEntry: %d limsystemrole: %d", + psessionEntry->smeSessionId, updateEntry, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + pe_debug("BSSID: " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pAddBssParams->bssId)); + + pAddBssParams->bssType = eSIR_INFRASTRUCTURE_MODE; + + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + /* Update PE session ID */ + pAddBssParams->sessionId = psessionEntry->peSessionId; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = pAssocRsp->supportedRates.numRates; + qdf_mem_copy(pAddBssParams->rateSet.rate, + pAssocRsp->supportedRates.rate, + pAssocRsp->supportedRates.numRates); + + if (IS_DOT11_MODE_11B(psessionEntry->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->llaCoexist = + (uint8_t) psessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) psessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) psessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) psessionEntry->beaconParams.ht20Coexist; + + pe_debug("BSS Type %d Beacon Interval: %d dtimPeriod: %d " + "cfpCount: %d", pAddBssParams->bssType, + pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, + pAddBssParams->cfParamSet.cfpCount); + + pe_debug("cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining: %d " + "numRates: %d", pAddBssParams->cfParamSet.cfpPeriod, + pAddBssParams->cfParamSet.cfpMaxDuration, + pAddBssParams->cfParamSet.cfpDurRemaining, + pAddBssParams->rateSet.numRates); + + pe_debug("nwType:%d shortSlotTimeSupported: %d llaCoexist: %d " + "llbCoexist: %d llgCoexist: %d ht20Coexist: %d", + pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, + pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, + pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); + + pAddBssParams->dot11_mode = psessionEntry->dot11mode; + pe_debug("dot11_mode: %d", pAddBssParams->dot11_mode); + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) + chanWidthSupp = lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + psessionEntry); + + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pAssocRsp->HTCaps.present)) { + pAddBssParams->htCapable = pAssocRsp->HTCaps.present; + pe_debug("htCapable: %d", pAddBssParams->htCapable); + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pAssocRsp->HTInfo.opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pAssocRsp->HTInfo.dualCTSProtection; + + if ((pAssocRsp->HTCaps.supportedChannelWidthSet) + && (chanWidthSupp)) { + pAddBssParams->ch_width = (uint8_t) + pAssocRsp->HTInfo.recommendedTxWidthSet; + if (pAssocRsp->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + else if (pAssocRsp->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pAssocRsp->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pAssocRsp->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = pAssocRsp->HTInfo.rifsMode; + + pe_debug("htOperMode: %d dualCTSProtection: %d txChannelWidth: %d center_freq_0: %d", + pAddBssParams->htOperMode, + pAddBssParams->dualCTSProtection, + pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0); + + pe_debug("llnNonGFCoexist: %d " + "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d", + pAddBssParams->llnNonGFCoexist, + pAddBssParams->fLsigTXOPProtectionFullSupport, + pAddBssParams->fRIFSMode); + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + pe_debug("currentOperChannel %d", pAddBssParams->currentOperChannel); + if (psessionEntry->vhtCapability && (pAssocRsp->VHTCaps.present)) { + pAddBssParams->vhtCapable = pAssocRsp->VHTCaps.present; + vht_caps = &pAssocRsp->VHTCaps; + vht_oper = &pAssocRsp->VHTOperation; + } else if (psessionEntry->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 != NULL) + lim_update_vht_oper_assoc_resp(pMac, pAddBssParams, + vht_oper, psessionEntry); + if (vht_caps != NULL) + lim_update_vhtcaps_assoc_resp(pMac, pAddBssParams, + vht_caps, psessionEntry); + } + + pe_debug("vhtCapable %d TxChannelWidth %d center_freq_0 %d center_freq_1 %d", + pAddBssParams->vhtCapable, pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0, + pAddBssParams->ch_center_freq_seg1); + + if (lim_is_session_he_capable(psessionEntry) && + (pAssocRsp->he_cap.present)) { + lim_add_bss_he_cap(pAddBssParams, pAssocRsp); + lim_add_bss_he_cfg(pAddBssParams, psessionEntry); + } + /* + * 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)); + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listen_interval) != + QDF_STATUS_SUCCESS) + pe_err("Couldn't get LISTEN_INTERVAL"); + pAddBssParams->staContext.listenInterval = listen_interval; + + /* Fill Assoc id from the dph table */ + pStaDs = dph_lookup_hash_entry(pMac, pAddBssParams->staContext.bssId, + &pAddBssParams->staContext.assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + pe_err("Couldn't get assoc id for " "MAC ADDR: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + pAddBssParams->staContext.staMac)); + return QDF_STATUS_E_FAILURE; + } + + pAddBssParams->staContext.uAPSD = + psessionEntry->gUapsdPerAcBitmask; + + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pAssocRsp->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + + pe_debug("StaContext: " MAC_ADDRESS_STR + " shortPreambleSupported: %d", + MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), + pAddBssParams->staContext.shortPreambleSupported); + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && pBeaconStruct->HTCaps.present) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pAssocRsp->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pAssocRsp->HTCaps.lsigTXOPProtection; + pe_debug("StaCtx: htCap %d GFcap %d lsigTxopProtn %d", + pAddBssParams->staContext.htCapable, + pAddBssParams->staContext.greenFieldCapable, + pAddBssParams->staContext.lsigTxopProtection); + if (psessionEntry->htConfig.ht_tx_stbc) + pAddBssParams->staContext.stbc_capable = + pAssocRsp->HTCaps.rxSTBC; + + if (psessionEntry->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE(pBeaconStruct-> + vendor_vht_ie.VHTCaps))) { + pAddBssParams->staContext.vhtCapable = 1; + pAddBssParams->staContext.vhtSupportedRxNss = + pStaDs->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 != NULL) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + psessionEntry->vht_config.su_beam_formee) + sta_context->vhtTxBFCapable = 1; + + if ((vht_caps != NULL) && vht_caps->muBeamformerCap && + psessionEntry->vht_config.mu_beam_formee) + sta_context->vhtTxMUBformeeCapable = 1; + + if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && + psessionEntry->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 (lim_is_session_he_capable(psessionEntry) && + pAssocRsp->he_cap.present) { + lim_intersect_ap_he_caps(psessionEntry, + pAddBssParams, + NULL, + pAssocRsp); + lim_update_he_stbc_capable(&pAddBssParams->staContext); + } + + /* + * in limExtractApCapability function intersection of FW + * advertised channel width and AP advertised channel + * width has been taken into account for calculating + * psessionEntry->ch_width + */ + if (chanWidthSupp && + ((pAssocRsp->HTCaps.supportedChannelWidthSet) || + (pBeaconStruct->HTCaps.supportedChannelWidthSet))) { + pAddBssParams->staContext.ch_width = + psessionEntry->ch_width; + } else { + sta_context->ch_width = CH_WIDTH_20MHZ; + if ((QDF_IS_STATUS_SUCCESS( + wlan_cfg_get_int(pMac, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + &enableTxBF20MHz))) && + (false == enableTxBF20MHz)) + sta_context->vhtTxBFCapable = 0; + } + + pe_debug("StaCtx: vhtCap %d ChBW %d TxBF %d", + pAddBssParams->staContext.vhtCapable, + pAddBssParams->staContext.ch_width, + sta_context->vhtTxBFCapable); + pe_debug("StaContext su_tx_bfer %d", + sta_context->enable_su_tx_bformer); + + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) + pAssocRsp->HTCaps.mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pAssocRsp->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pAssocRsp->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pAssocRsp->HTCaps.dsssCckMode40MHz; + /* + * 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 (psessionEntry->htConfig.ht_sgi20) { + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t)pAssocRsp->HTCaps.shortGI20MHz; + } else { + pAddBssParams->staContext.fShortGI20Mhz = false; + } + + if (psessionEntry->htConfig.ht_sgi40) { + 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 + && pMac->lim.disableLDPCWithTxbfAP) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + if (psessionEntry->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 != NULL && + (psessionEntry->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 (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pAssocRsp->HTInfo.rifsMode; + + pe_debug("StaCtx: ChBW %d mimoPS %d maxAmsduSize %d", + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.mimoPS, + pAddBssParams->staContext.maxAmsduSize); + + pe_debug("maxAmpduDens %d CckMode40Mhz %d SGI20Mhz %d", + pAddBssParams->staContext.maxAmpduDensity, + pAddBssParams->staContext.fDsssCckMode40Mhz, + pAddBssParams->staContext.fShortGI20Mhz); + + pe_debug("SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d", + pAddBssParams->staContext.fShortGI40Mhz, + pAddBssParams->staContext.maxAmpduSize, + pAddBssParams->staContext.htLdpcCapable, + pAddBssParams->staContext.vhtLdpcCapable); + } + pAddBssParams->staContext.smesessionId = + psessionEntry->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) + && (psessionEntry->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 ((psessionEntry->limWmeEnabled && pAssocRsp->wmeEdcaPresent) || + (psessionEntry->limQosEnabled && pAssocRsp->edcaPresent)) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ + pStaDs = dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + qdf_mem_copy((uint8_t *) &pAddBssParams->staContext. + supportedRates, + (uint8_t *)&pStaDs->supportedRates, + sizeof(tSirSupportedRates)); + } else + pe_err("could not Update the supported rates"); + pAddBssParams->staContext.encryptType = psessionEntry->encryptType; + + pAddBssParams->maxTxPower = psessionEntry->maxTxPower; + pe_debug("maxTxPower: %d", pAddBssParams->maxTxPower); + /* FIXME_GEN4 - Any other value that can be used for initialization? */ + pAddBssParams->status = QDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + /* update persona */ + pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; + + if (QDF_P2P_CLIENT_MODE == psessionEntry->pePersona) + pAddBssParams->staContext.p2pCapableSta = 1; + + pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; + + pAddBssParams->extSetStaKeyParamValid = 0; + pe_debug("extSetStaKeyParamValid: %d", + pAddBssParams->extSetStaKeyParamValid); + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + /* Set a new state for MLME */ + if (eLIM_MLM_WT_ASSOC_RSP_STATE == psessionEntry->limMlmState) + psessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE; + else + psessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->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); + + pe_debug("staContext wmmEnabled: %d encryptType: %d " + "p2pCapableSta: %d", + pAddBssParams->staContext.wmmEnabled, + pAddBssParams->staContext.encryptType, + pAddBssParams->staContext.p2pCapableSta); + + pe_debug("bSpectrumMgtEnabled: %d halPersona: %d setting " + "LimMlm state to %d", + pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, + psessionEntry->limMlmState); + if (psessionEntry->isNonRoamReassoc) + pAddBssParams->nonRoamReassoc = 1; + pAddBssParams->nss = psessionEntry->nss; + pe_debug("nss value: %d", pAddBssParams->nss); + + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + 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, psessionEntry); + + msgQ.type = WMA_ADD_BSS_REQ; + /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ + msgQ.reserved = 0; + msgQ.bodyptr = pAddBssParams; + msgQ.bodyval = 0; + + pe_debug("SessionId: %d Sending WMA_ADD_BSS_REQ", + psessionEntry->peSessionId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + qdf_mem_free(pAddBssParams); + pe_err("Posting ADD_BSS_REQ to HAL failed, reason=%X", + retCode); + goto returnFailure; + + } else + return retCode; + +returnFailure: + /* Clean-up will be done by the caller... */ + return retCode; +} + +QDF_STATUS lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession psessionEntry) +{ + struct scheduler_msg msgQ = {0}; + tpAddBssParams pAddBssParams = NULL; + uint32_t retCode; + tSchBeaconStruct *pBeaconStruct; + uint8_t chanWidthSupp = 0; + tDot11fIEVHTOperation *vht_oper = NULL; + tDot11fIEVHTCaps *vht_caps = NULL; + uint32_t listen_interval = WNI_CFG_LISTEN_INTERVAL_STADEF; + + tpSirBssDescription bssDescription = + &psessionEntry->pLimJoinReq->bssDescription; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + pe_err("Unable to allocate memory during ADD_BSS"); + return QDF_STATUS_E_NOMEM; + } + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + pe_err("Unable to allocate memory during ADD_BSS"); + retCode = QDF_STATUS_E_NOMEM; + goto returnFailure; + } + + lim_extract_ap_capabilities(pMac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, pBeaconStruct, + psessionEntry); + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(pAddBssParams->selfMacAddr, + psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); + pe_debug("sessionid: %d updateEntry = %d limsystemrole = %d", + psessionEntry->smeSessionId, updateEntry, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + pe_debug("BSSID: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pAddBssParams->bssId)); + /* Incorrect BSS Type which caused UMA Descriptor to be overwritten on + * top of an already established Infra link. This lead to issues in + * concurrent data transfer. + */ + + pAddBssParams->bssType = psessionEntry->bssType; /* eSIR_INFRASTRUCTURE_MODE; */ + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + qdf_mem_copy(pAddBssParams->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) psessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) psessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) psessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) psessionEntry->beaconParams.ht20Coexist; + + pe_debug("BSS Type %d Beacon Interval: %d dtimPeriod: %d " + "cfpCount: %d", pAddBssParams->bssType, + pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, + pAddBssParams->cfParamSet.cfpCount); + + pe_debug("cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining: %d" + " numRates: %d", pAddBssParams->cfParamSet.cfpPeriod, + pAddBssParams->cfParamSet.cfpMaxDuration, + pAddBssParams->cfParamSet.cfpDurRemaining, + pAddBssParams->rateSet.numRates); + + pe_debug("nwType:%d shortSlotTimeSupported: %d" + "llaCoexist: %d llbCoexist: %d llgCoexist: %d ht20Coexist: %d", + pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, + pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, + pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pBeaconStruct->HTCaps.present)) { + pAddBssParams->htCapable = pBeaconStruct->HTCaps.present; + pe_debug("htCapable: %d", pAddBssParams->htCapable); + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pBeaconStruct->HTInfo. + opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pBeaconStruct->HTInfo.dualCTSProtection; + + chanWidthSupp = + lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + psessionEntry); + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) + && (chanWidthSupp)) { + pAddBssParams->ch_width = + (uint8_t) pBeaconStruct->HTInfo. + recommendedTxWidthSet; + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pBeaconStruct->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pBeaconStruct->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = + pBeaconStruct->HTInfo.rifsMode; + + pe_debug("htOperMode: %d dualCTSProtection: %d txChannelWidthSet: %d center_freq_seg0: %d", + pAddBssParams->htOperMode, + pAddBssParams->dualCTSProtection, + pAddBssParams->txChannelWidthSet, + pAddBssParams->ch_center_freq_seg0); + + pe_debug("llnNonGFCoexist: %d " + "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d", + pAddBssParams->llnNonGFCoexist, + pAddBssParams->fLsigTXOPProtectionFullSupport, + pAddBssParams->fRIFSMode); + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + pe_debug("currentOperChannel %d", + pAddBssParams->currentOperChannel); + + if (psessionEntry->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"); + } + + + if ((vht_oper != NULL) && + vht_oper->chanWidth && + chanWidthSupp) { + pAddBssParams->ch_center_freq_seg0 = + vht_oper->chanCenterFreqSeg1; + pAddBssParams->ch_center_freq_seg1 = + vht_oper->chanCenterFreqSeg2; + } + /* + * in limExtractApCapability function intersection of FW + * advertised channel width and AP advertised channel width has + * been taken into account for calculating + * psessionEntry->ch_width + */ + pAddBssParams->ch_width = + psessionEntry->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(psessionEntry) && + pBeaconStruct->he_cap.present) { + lim_update_bss_he_capable(pMac, pAddBssParams); + lim_add_bss_he_cfg(pAddBssParams, psessionEntry); + } + pe_debug("vhtCapable %d vhtTxChannelWidthSet %d center_freq_seg0 - %d, center_freq_seg1 - %d", + pAddBssParams->vhtCapable, pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0, + pAddBssParams->ch_center_freq_seg1); + /* + * 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)); + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listen_interval) != + QDF_STATUS_SUCCESS) + pe_err("Couldn't get LISTEN_INTERVAL"); + pAddBssParams->staContext.listenInterval = listen_interval; + pAddBssParams->staContext.assocId = 0; + pAddBssParams->staContext.uAPSD = 0; + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + + pe_debug("StaCtx: " MAC_ADDRESS_STR " shortPreamble: %d", + MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), + pAddBssParams->staContext.shortPreambleSupported); + + pAddBssParams->dot11_mode = psessionEntry->dot11mode; + pe_debug("dot11_mode:%d", pAddBssParams->dot11_mode); + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pBeaconStruct->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pBeaconStruct->HTCaps.lsigTXOPProtection; + pe_debug("StaCtx: htCap %d GFCap %d lsigTxopProtn %d", + pAddBssParams->staContext.htCapable, + pAddBssParams->staContext.greenFieldCapable, + pAddBssParams->staContext.lsigTxopProtection); + if (psessionEntry->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 != NULL) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + psessionEntry->vht_config.su_beam_formee) + pAddBssParams->staContext.vhtTxBFCapable = 1; + + if ((vht_caps != NULL) && vht_caps->muBeamformerCap && + psessionEntry->vht_config.mu_beam_formee) + pAddBssParams->staContext.vhtTxMUBformeeCapable + = 1; + + if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && + psessionEntry->vht_config.su_beam_former) + pAddBssParams->staContext.enable_su_tx_bformer + = 1; + + pe_debug("StaContext: su_tx_bfer %d", + pAddBssParams->staContext.enable_su_tx_bformer); + } + if (lim_is_session_he_capable(psessionEntry) && + pBeaconStruct->he_cap.present) + lim_intersect_ap_he_caps(psessionEntry, pAddBssParams, + pBeaconStruct, NULL); + + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = + (uint8_t) pBeaconStruct->HTInfo. + recommendedTxWidthSet; + if ((vht_oper != NULL) && + pAddBssParams->staContext.vhtCapable && + vht_oper->chanWidth) + pAddBssParams->staContext.ch_width = + vht_oper->chanWidth + 1; + pe_debug("StaCtx: vhtCap %d ch_bw %d TxBF %d", + pAddBssParams->staContext.vhtCapable, + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.vhtTxBFCapable); + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pBeaconStruct->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pBeaconStruct->HTCaps.dsssCckMode40MHz; + /* + * 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 (true == psessionEntry->htConfig.ht_sgi20) + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t)pBeaconStruct->HTCaps.shortGI20MHz; + else + pAddBssParams->staContext.fShortGI20Mhz = + false; + + if (true == psessionEntry->htConfig.ht_sgi40) + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; + else + pAddBssParams->staContext.fShortGI40Mhz = false; + + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + if (pAddBssParams->staContext.vhtTxBFCapable + && pMac->lim.disableLDPCWithTxbfAP) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + if (psessionEntry->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; + pe_debug("VHT Caps are in vendor Specific IE"); + } + if (vht_caps != NULL && + (psessionEntry->txLdpcIniFeatureEnabled & 0x2)) + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + else + pAddBssParams->staContext.vhtLdpcCapable = 0; + } + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pBeaconStruct->HTInfo.rifsMode; + pe_debug("StaContext ChannelWidth: %d mimoPS: %d maxAmsduSize: %d", + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.mimoPS, + pAddBssParams->staContext.maxAmsduSize); + + pe_debug("maxAmpduDensity %d Cck40Mhz %d SGI20Mhz %d", + pAddBssParams->staContext.maxAmpduDensity, + pAddBssParams->staContext.fDsssCckMode40Mhz, + pAddBssParams->staContext.fShortGI20Mhz); + + pe_debug("SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d", + pAddBssParams->staContext.fShortGI40Mhz, + pAddBssParams->staContext.maxAmpduSize, + pAddBssParams->staContext.htLdpcCapable, + pAddBssParams->staContext.vhtLdpcCapable); + } + /* + * If WMM IE or 802.11E IE is not present + * and AP is HT AP then enable WMM + */ + if ((psessionEntry->limWmeEnabled && (pBeaconStruct->wmeEdcaPresent || + pAddBssParams->staContext.htCapable)) || + (psessionEntry->limQosEnabled && + (pBeaconStruct->edcaPresent || + pAddBssParams->staContext.htCapable))) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, psessionEntry, + &pBeaconStruct->VHTCaps, + &pBeaconStruct->he_cap); + + pAddBssParams->staContext.encryptType = psessionEntry->encryptType; + + pAddBssParams->maxTxPower = psessionEntry->maxTxPower; + pe_debug("maxTxPower: %d", pAddBssParams->maxTxPower); + + pAddBssParams->status = QDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + + pAddBssParams->staContext.smesessionId = psessionEntry->smeSessionId; + pAddBssParams->staContext.sessionId = psessionEntry->peSessionId; + pAddBssParams->sessionId = psessionEntry->peSessionId; + + pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; /* update persona */ + + pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; + + pAddBssParams->extSetStaKeyParamValid = 0; + pe_debug("extSetStaKeyParamValid: %d", + pAddBssParams->extSetStaKeyParamValid); + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + pAddBssParams->nss = psessionEntry->nss; + pe_debug("nss value: %d", pAddBssParams->nss); + + /* Set a new state for MLME */ + psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + pe_debug("staContext wmmEnabled: %d encryptType: %d " + "p2pCapableSta: %d", + pAddBssParams->staContext.wmmEnabled, + pAddBssParams->staContext.encryptType, + pAddBssParams->staContext.p2pCapableSta); + + pe_debug("bSpectrumMgtEnabled: %d halPersona: %d setting " + "LimMlm state to %d", + pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, + psessionEntry->limMlmState); + + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + 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; + } + + msgQ.type = WMA_ADD_BSS_REQ; + /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ + msgQ.reserved = 0; + msgQ.bodyptr = pAddBssParams; + msgQ.bodyval = 0; + + pe_debug("SessionId:%d Sending WMA_ADD_BSS_REQ", + psessionEntry->peSessionId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + qdf_mem_free(pAddBssParams); + pe_err("Posting ADD_BSS_REQ to HAL failed, reason=%X", + retCode); + goto returnFailure; + + } else { + qdf_mem_free(pBeaconStruct); + return retCode; + } + +returnFailure: + /* Clean-up will be done by the caller... */ + qdf_mem_free(pBeaconStruct); + return retCode; +} + +/** + * lim_prepare_and_send_del_sta_cnf() - prepares and send del sta cnf + * + * @pMac: mac global context + * @pStaDs: sta dph node + * @statusCode: status code + * @psessionEntry: 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(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tSirResultCodes statusCode, + tpPESession psessionEntry) +{ + uint16_t staDsAssocId = 0; + struct qdf_mac_addr sta_dsaddr; + tLimMlmStaContext mlmStaContext; + + if (pStaDs == NULL) { + pe_err("pStaDs is NULL"); + return; + } + staDsAssocId = pStaDs->assocId; + qdf_mem_copy((uint8_t *) sta_dsaddr.bytes, + pStaDs->staAddr, QDF_MAC_ADDR_SIZE); + + mlmStaContext = pStaDs->mlmStaContext; + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); + + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, pStaDs->assocId, + psessionEntry); + + if (LIM_IS_STA_ROLE(psessionEntry)) { + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + } + lim_send_del_sta_cnf(pMac, sta_dsaddr, staDsAssocId, mlmStaContext, + statusCode, psessionEntry); +} + +/** ------------------------------------------------------------- + \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 tpAniSirGlobal pMac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +void lim_init_pre_auth_timer_table(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable) +{ + uint32_t cfgValue; + uint32_t authNodeIdx; + + tLimPreAuthNode **pAuthNode = pPreAuthTimerTable->pTable; + + /* Get AUTH_RSP Timers value */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + &cfgValue) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve AUTH_RSP timeout value"); + return; + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + for (authNodeIdx = 0; authNodeIdx < pPreAuthTimerTable->numEntry; + authNodeIdx++) { + if (tx_timer_create(pMac, &(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 Retrives a free Pre Auth node from Pre Auth Table. + \param tpAniSirGlobal pMac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_acquire_free_pre_auth_node(tpAniSirGlobal pMac, + 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 tpAniSirGlobal pMac + \param tpLimPreAuthTable pAuthTable + \param uint32_t authNodeIdx + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_get_pre_auth_node_from_index(tpAniSirGlobal pMac, + tpLimPreAuthTable pAuthTable, + uint32_t authNodeIdx) +{ + if ((authNodeIdx >= pAuthTable->numEntry) + || (pAuthTable->pTable == NULL)) { + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tSirAssocReq *assoc, + tpPESession psessionEntry) +{ + int8_t localMaxTxPower; + uint32_t localPwrConstraint; + + localMaxTxPower = + cfg_get_regulatory_max_transmit_power(pMac, + psessionEntry->currentOperChannel); + + if (wlan_cfg_get_int + (pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + &localPwrConstraint) != QDF_STATUS_SUCCESS) { + pe_err("Unable to get Local Power Constraint from cfg"); + return QDF_STATUS_E_FAILURE; + } + localMaxTxPower -= (int8_t) localPwrConstraint; + + /** + * 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; +} + +/** ------------------------------------------------------------- + \fn lim_fill_rx_highest_supported_rate + \brief Fills in the Rx Highest Supported Data Rate field from + \ the 'supported MCS set' field in HT capability element. + \param tpAniSirGlobal pMac + \param tpSirSupportedRates pRates + \param uint8_t* pSupportedMCSSet + \return none + -------------------------------------------------------------*/ +void lim_fill_rx_highest_supported_rate(tpAniSirGlobal pMac, + 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; +} + +#ifdef WLAN_FEATURE_11W +/** ------------------------------------------------------------- + \fn lim_send_sme_unprotected_mgmt_frame_ind + \brief Forwards the unprotected management frame to SME. + \param tpAniSirGlobal pMac + \param frameType - 802.11 frame type + \param frame - frame buffer + \param sessionId - id for the current session + \param psessionEntry - PE session context + \return none + -------------------------------------------------------------*/ +void lim_send_sme_unprotected_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + tpPESession psessionEntry) +{ + struct scheduler_msg mmhMsg = {0}; + tSirSmeUnprotMgmtFrameInd *pSirSmeMgmtFrame = NULL; + uint16_t length; + + length = sizeof(tSirSmeUnprotMgmtFrameInd) + frameLen; + + pSirSmeMgmtFrame = qdf_mem_malloc(length); + if (NULL == pSirSmeMgmtFrame) { + pe_err("Memory allocation failed"); + 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(pMac, &mmhMsg, ePROT); + return; +} +#endif + +#ifdef FEATURE_WLAN_ESE +/** ------------------------------------------------------------- + \fn lim_send_sme_tsm_ie_ind + \brief Forwards the TSM IE information to SME. + \param tpAniSirGlobal pMac + \param psessionEntry - PE session context + \param tid - traffic id + \param state - tsm state (enabled/disabled) + \param measurementInterval - measurement interval + \return none + -------------------------------------------------------------*/ +void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t tid, uint8_t state, uint16_t measInterval) +{ + struct scheduler_msg mmhMsg = {0}; + tpSirSmeTsmIEInd pSirSmeTsmIeInd = NULL; + + if (!pMac || !psessionEntry) + return; + + pSirSmeTsmIeInd = qdf_mem_malloc(sizeof(tSirSmeTsmIEInd)); + if (NULL == pSirSmeTsmIeInd) { + pe_err("AllocateMemory failed for tSirSmeTsmIEInd"); + return; + } + + pSirSmeTsmIeInd->sessionId = psessionEntry->smeSessionId; + pSirSmeTsmIeInd->tsmIe.tsid = tid; + pSirSmeTsmIeInd->tsmIe.state = state; + pSirSmeTsmIeInd->tsmIe.msmt_interval = measInterval; + + mmhMsg.type = eWNI_SME_TSM_IE_IND; + mmhMsg.bodyptr = pSirSmeTsmIeInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} +#endif /* FEATURE_WLAN_ESE */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..6b11583668dc3261ce1559abd249dea3e6ff830b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h @@ -0,0 +1,224 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.h" + +#include "lim_types.h" + +#define SIZE_OF_NOA_DESCRIPTOR 13 +#define MAX_NOA_PERIOD_IN_MICROSECS 3000000 + +uint32_t lim_cmp_ssid(tSirMacSSid *, tpPESession); +uint8_t lim_compare_capabilities(tpAniSirGlobal, + tSirAssocReq *, + tSirMacCapabilityInfo *, tpPESession); +uint8_t lim_check_rx_basic_rates(tpAniSirGlobal, tSirMacRateSet, tpPESession); +uint8_t lim_check_rx_rsn_ie_match(tpAniSirGlobal mac_ctx, + tDot11fIERSN * const rx_rsn_ie, + tpPESession session_entry, uint8_t sta_is_ht, + bool *pmf_connection); +uint8_t lim_check_rx_wpa_ie_match(tpAniSirGlobal, tDot11fIEWPA, tpPESession, + uint8_t); +uint8_t lim_check_mcs_set(tpAniSirGlobal pMac, uint8_t *supportedMCSSet); +void limPostDummyToTmRing(tpAniSirGlobal, tpDphHashNode); +void limPostPacketToTdRing(tpAniSirGlobal, tpDphHashNode, uint8_t); +QDF_STATUS lim_cleanup_rx_path(tpAniSirGlobal, tpDphHashNode, tpPESession); +void lim_reject_association(tpAniSirGlobal, tSirMacAddr, uint8_t, + uint8_t, tAniAuthType, uint16_t, uint8_t, + enum eSirMacStatusCodes, tpPESession); + +QDF_STATUS lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, + tDot11fIEVHTCaps *pVHTCaps, + tDot11fIEhe_cap *he_caps); + +QDF_STATUS lim_populate_own_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, + tDot11fIEVHTCaps *pVHTCaps, + tDot11fIEhe_cap *he_caps); + +QDF_STATUS +lim_populate_matching_rate_set(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tSirMacRateSet *pOperRateSet, + tSirMacRateSet *pExtRateSet, + uint8_t *pSupportedMCSSet, + tpPESession psessionEntry, + tDot11fIEVHTCaps *pVHTCaps, + tDot11fIEhe_cap *he_caps); + +QDF_STATUS lim_add_sta(tpAniSirGlobal, tpDphHashNode, uint8_t, tpPESession); +QDF_STATUS lim_del_bss(tpAniSirGlobal, tpDphHashNode, uint16_t, tpPESession); +QDF_STATUS lim_del_sta(tpAniSirGlobal, tpDphHashNode, bool, tpPESession); +QDF_STATUS lim_add_sta_self(tpAniSirGlobal, uint16_t, uint8_t, tpPESession); + +void lim_teardown_infra_bss(tpAniSirGlobal, tpPESession); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_restore_pre_reassoc_state(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +void lim_post_reassoc_failure(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +bool lim_is_reassoc_in_progress(tpAniSirGlobal, tpPESession); + +void lim_handle_add_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry); +void lim_handle_del_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry); +void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, tpPESession psessionEntry); +QDF_STATUS lim_add_ft_sta_self(tpAniSirGlobal pMac, uint16_t assocId, + tpPESession psessionEntry); +#else +static inline void lim_restore_pre_reassoc_state(tpAniSirGlobal mac_ctx, + tSirResultCodes res_code, uint16_t prot_status, + tpPESession pe_session) +{} +static inline void lim_post_reassoc_failure(tpAniSirGlobal mac_ctx, + tSirResultCodes res_code, uint16_t prot_status, + tpPESession pe_session) +{} +static inline void lim_handle_add_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{} +static inline void lim_handle_del_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{} +static inline void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, tpPESession psessionEntry) +{} +static inline bool lim_is_reassoc_in_progress(tpAniSirGlobal mac_ctx, + tpPESession pe_session) +{ + return false; +} +static inline QDF_STATUS lim_add_ft_sta_self(tpAniSirGlobal pMac, + uint16_t assocId, tpPESession psessionEntry) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline bool lim_is_roam_synch_in_progress(tpPESession pe_session) +{ + return pe_session->bRoamSynchInProgress; +} +#else +static inline bool lim_is_roam_synch_in_progress(tpPESession pe_session) +{ + return false; +} +#endif + +void +lim_send_del_sta_cnf(tpAniSirGlobal pMac, struct qdf_mac_addr sta_dsaddr, + uint16_t staDsAssocId, tLimMlmStaContext mlmStaContext, + tSirResultCodes statusCode, tpPESession psessionEntry); + +void lim_handle_cnf_wait_timeout(tpAniSirGlobal pMac, uint16_t staId); +void lim_delete_dph_hash_entry(tpAniSirGlobal, tSirMacAddr, uint16_t, tpPESession); +void lim_check_and_announce_join_success(tpAniSirGlobal, + tSirProbeRespBeacon *, + tpSirMacMgmtHdr, tpPESession); +void lim_update_re_assoc_globals(tpAniSirGlobal pMac, + tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry); + +void lim_update_assoc_sta_datas(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry); + +QDF_STATUS lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + tpSirBssDescription bssDescription, + uint8_t updateEntry, tpPESession psessionEntry); +QDF_STATUS lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession psessionEntry); + +void lim_prepare_and_send_del_sta_cnf(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tSirResultCodes statusCode, tpPESession); +QDF_STATUS lim_extract_ap_capabilities(tpAniSirGlobal pMac, uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct); +void lim_init_pre_auth_timer_table(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable); +tpLimPreAuthNode lim_acquire_free_pre_auth_node(tpAniSirGlobal pMac, + tpLimPreAuthTable + pPreAuthTimerTable); +tpLimPreAuthNode lim_get_pre_auth_node_from_index(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tSirAssocReq *assoc); + +/* Util API to check if the txpower supported by STA is within range */ +QDF_STATUS lim_is_dot11h_power_capabilities_in_range(tpAniSirGlobal pMac, + tSirAssocReq *assoc, + tpPESession); +/* API to fill in RX Highest Supported data Rate */ +void lim_fill_rx_highest_supported_rate(tpAniSirGlobal pMac, + uint16_t *rxHighestRate, + uint8_t *pSupportedMCSSet); +#ifdef WLAN_FEATURE_11W +void lim_send_sme_unprotected_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + tpPESession psessionEntry); +#endif + +#ifdef FEATURE_WLAN_ESE +void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t tid, uint8_t state, uint16_t measInterval); +#else +static inline void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, + tpPESession psessionEntry, uint8_t tid, + uint8_t state, uint16_t measInterval) +{} +#endif /* FEATURE_WLAN_ESE */ + +QDF_STATUS lim_populate_vht_mcs_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + tDot11fIEVHTCaps *pPeerVHTCaps, + tpPESession psessionEntry, + uint8_t nss); + +#endif /* __LIM_ASSOC_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c new file mode 100644 index 0000000000000000000000000000000000000000..3f6357d2d91bcea21e31fd40272d2408a02235ba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c @@ -0,0 +1,1106 @@ +/* + * 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. + */ + +/**========================================================================= + + \brief implementation for PE 11r VoWiFi FT Protocol + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wmm_apsd.h" +#include "wma.h" + +extern void lim_send_set_sta_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq * pMlmSetKeysReq, + uint16_t staIdx, + uint8_t defWEPIdx, + tpPESession sessionEntry, bool sendRsp); + +/*-------------------------------------------------------------------------- + Initialize the FT variables. + ------------------------------------------------------------------------*/ +void lim_ft_open(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (psessionEntry) + qdf_mem_zero(&psessionEntry->ftPEContext, sizeof(tftPEContext)); +} + +void lim_ft_cleanup_all_ft_sessions(tpAniSirGlobal pMac) +{ + /* Wrapper function to cleanup all FT sessions */ + int i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (true == pMac->lim.gpSession[i].valid) { + /* The session is valid, may have FT data */ + lim_ft_cleanup(pMac, &pMac->lim.gpSession[i]); + } + } +} + +void lim_ft_cleanup(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (NULL == psessionEntry) { + pe_err("psessionEntry is NULL"); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + + if (NULL != psessionEntry->ftPEContext.pFTPreAuthReq) { + pe_debug("Freeing pFTPreAuthReq: %pK", + psessionEntry->ftPEContext.pFTPreAuthReq); + if (NULL != + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription); + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq); + psessionEntry->ftPEContext.pFTPreAuthReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddBssReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + psessionEntry->ftPEContext.pAddBssReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddStaReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddStaReq); + psessionEntry->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + qdf_mem_zero(&psessionEntry->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(tpAniSirGlobal pMac, + uint8_t updateEntry, tpPESession pftSessionEntry, + tpSirBssDescription bssDescription) +{ + tpAddBssParams pAddBssParams = NULL; + tAddStaParams *sta_ctx; + uint8_t chanWidthSupp = 0; + tSchBeaconStruct *pBeaconStruct; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pftSessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + pe_err("Unable to allocate memory for creating ADD_BSS"); + return; + } + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + qdf_mem_free(pBeaconStruct); + pe_err("Unable to allocate memory for creating ADD_BSS"); + return; + } + + lim_extract_ap_capabilities(pMac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, pBeaconStruct, + pftSessionEntry); + + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(pAddBssParams->selfMacAddr, pftSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + pAddBssParams->bssType = pftSessionEntry->bssType; + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->reassocReq = true; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + qdf_mem_copy(pAddBssParams->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) pftSessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) pftSessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) pftSessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) pftSessionEntry->beaconParams.ht20Coexist; +#ifdef WLAN_FEATURE_11W + pAddBssParams->rmfEnabled = pftSessionEntry->limRmfEnabled; +#endif + + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + pAddBssParams->htCapable = pBeaconStruct->HTCaps.present; + 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)); + + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pBeaconStruct->HTInfo. + opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pBeaconStruct->HTInfo.dualCTSProtection; + + chanWidthSupp = lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + pftSessionEntry); + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + else if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pBeaconStruct->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pBeaconStruct->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = + pBeaconStruct->HTInfo.rifsMode; + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + pftSessionEntry->htSecondaryChannelOffset = + pBeaconStruct->HTInfo.secondaryChannelOffset; + sta_ctx = &pAddBssParams->staContext; + + if (pftSessionEntry->vhtCapability && + pftSessionEntry->vhtCapabilityPresentInBeacon) { + pAddBssParams->vhtCapable = pBeaconStruct->VHTCaps.present; + if (pBeaconStruct->VHTOperation.chanWidth && chanWidthSupp) { + pAddBssParams->ch_width = + pBeaconStruct->VHTOperation.chanWidth + 1; + pAddBssParams->ch_center_freq_seg0 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + pAddBssParams->ch_center_freq_seg1 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + } + pAddBssParams->staContext.vht_caps = + ((pBeaconStruct->VHTCaps.maxMPDULen << + SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (pBeaconStruct->VHTCaps.supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (pBeaconStruct->VHTCaps.ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (pBeaconStruct->VHTCaps.shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (pBeaconStruct->VHTCaps.shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (pBeaconStruct->VHTCaps.txSTBC << + SIR_MAC_VHT_CAP_TXSTBC) | + (pBeaconStruct->VHTCaps.rxSTBC << + SIR_MAC_VHT_CAP_RXSTBC) | + (pBeaconStruct->VHTCaps.suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (pBeaconStruct->VHTCaps.suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (pBeaconStruct->VHTCaps.csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (pBeaconStruct->VHTCaps.numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (pBeaconStruct->VHTCaps.muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (pBeaconStruct->VHTCaps.muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (pBeaconStruct->VHTCaps.vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (pBeaconStruct->VHTCaps.htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (pBeaconStruct->VHTCaps.maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (pBeaconStruct->VHTCaps.vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (pBeaconStruct->VHTCaps.rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (pBeaconStruct->VHTCaps.txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (pBeaconStruct->VHTCaps.reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + } else { + pAddBssParams->vhtCapable = 0; + } + + pe_debug("SIR_HAL_ADD_BSS_REQ with channel: %d", + pAddBssParams->currentOperChannel); + + /* 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.shortPreambleSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + pAddBssParams->staContext.encryptType = + pftSessionEntry->encryptType; +#ifdef WLAN_FEATURE_11W + pAddBssParams->staContext.rmfEnabled = + pftSessionEntry->limRmfEnabled; +#endif + + if (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pBeaconStruct->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pBeaconStruct->HTCaps.lsigTXOPProtection; + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + if (pftSessionEntry->vhtCapability && + IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)) { + pAddBssParams->staContext.vhtCapable = 1; + if ((pBeaconStruct->VHTCaps.suBeamFormerCap || + pBeaconStruct->VHTCaps.muBeamformerCap) && + pftSessionEntry->vht_config.su_beam_formee) + sta_ctx->vhtTxBFCapable + = 1; + if (pBeaconStruct->VHTCaps.suBeamformeeCap && + pftSessionEntry->vht_config.su_beam_former) + sta_ctx->enable_su_tx_bformer = 1; + } + if (lim_is_session_he_capable(pftSessionEntry) && + pBeaconStruct->he_cap.present) + lim_intersect_ap_he_caps(pftSessionEntry, + pAddBssParams, pBeaconStruct, NULL); + + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + sta_ctx->ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + if (pAddBssParams->staContext.vhtCapable && + pBeaconStruct->VHTOperation.chanWidth) + sta_ctx->ch_width = + pBeaconStruct->VHTOperation.chanWidth + + 1; + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pBeaconStruct->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pBeaconStruct->HTCaps.dsssCckMode40MHz; + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI20MHz; + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pBeaconStruct->HTInfo.rifsMode; + } + + if ((pftSessionEntry->limWmeEnabled + && pBeaconStruct->wmeEdcaPresent) + || (pftSessionEntry->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) + && (pftSessionEntry->isOSENConnection)) + pAddBssParams->staContext.wpa_rsn = 1; + /* Update the rates */ + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, pftSessionEntry, + &pBeaconStruct->VHTCaps, + &pBeaconStruct->he_cap); + } + + pAddBssParams->maxTxPower = pftSessionEntry->maxTxPower; + +#ifdef WLAN_FEATURE_11W + if (pftSessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + pAddBssParams->status = QDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + + pAddBssParams->staContext.sessionId = pftSessionEntry->peSessionId; + pAddBssParams->staContext.smesessionId = pftSessionEntry->smeSessionId; + pAddBssParams->sessionId = pftSessionEntry->peSessionId; + + /* Set a new state for MLME */ + if (!lim_is_roam_synch_in_progress(pftSessionEntry)) { + pftSessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + pftSessionEntry->peSessionId, + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE)); + } + pAddBssParams->halPersona = (uint8_t) pftSessionEntry->pePersona; + + pftSessionEntry->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_fill_dot11mode() - to fill 802.11 mode in FT session + * @mac_ctx: pointer to mac ctx + * @pftSessionEntry: FT session + * @psessionEntry: PE session + * + * 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(tpAniSirGlobal mac_ctx, + tpPESession pftSessionEntry, tpPESession psessionEntry) +{ + uint32_t self_dot11_mode; + + if (psessionEntry->ftPEContext.pFTPreAuthReq && + !mac_ctx->roam.configParam.isRoamOffloadEnabled) { + pftSessionEntry->dot11mode = + psessionEntry->ftPEContext.pFTPreAuthReq->dot11mode; + } else { + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_dot11_mode); + pe_debug("selfDot11Mode: %d", self_dot11_mode); + pftSessionEntry->dot11mode = self_dot11_mode; + } +} +#elif defined(WLAN_FEATURE_HOST_ROAM) +/** + * lim_fill_dot11mode() - to fill 802.11 mode in FT session + * @mac_ctx: pointer to mac ctx + * @pftSessionEntry: FT session + * @psessionEntry: PE session + * + * This API fills FT session's dot11mode either from pe session. + * + * Return: none + */ +static void lim_fill_dot11mode(tpAniSirGlobal mac_ctx, + tpPESession pftSessionEntry, tpPESession psessionEntry) +{ + pftSessionEntry->dot11mode = + psessionEntry->ftPEContext.pFTPreAuthReq->dot11mode; +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/*------------------------------------------------------------------ + * + * Setup the new session for the pre-auth AP. + * Return the newly created session entry. + * + *------------------------------------------------------------------*/ +void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, tpPESession psessionEntry) +{ + uint8_t currentBssUapsd; + int8_t localPowerConstraint; + int8_t regMax; + tSchBeaconStruct *pBeaconStruct; + ePhyChanBondState cbEnabledMode; + struct lim_max_tx_pwr_attr tx_pwr_attr = {0}; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + pe_err("No memory for creating lim_fill_ft_session"); + return; + } + + /* Retrieve the session that was already created and update the entry */ + pftSessionEntry->limWmeEnabled = psessionEntry->limWmeEnabled; + pftSessionEntry->limQosEnabled = psessionEntry->limQosEnabled; + pftSessionEntry->limWsmEnabled = psessionEntry->limWsmEnabled; + pftSessionEntry->lim11hEnable = psessionEntry->lim11hEnable; + pftSessionEntry->isOSENConnection = psessionEntry->isOSENConnection; + + /* Fields to be filled later */ + pftSessionEntry->pLimJoinReq = NULL; + pftSessionEntry->smeSessionId = psessionEntry->smeSessionId; + pftSessionEntry->transactionId = 0; + + lim_extract_ap_capabilities(pMac, (uint8_t *) pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + pBeaconStruct); + + pftSessionEntry->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + qdf_mem_copy(pftSessionEntry->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pftSessionEntry->extRateSet.numRates = + pBeaconStruct->extendedRates.numRates; + qdf_mem_copy(pftSessionEntry->extRateSet.rate, + pBeaconStruct->extendedRates.rate, + pftSessionEntry->extRateSet.numRates); + + pftSessionEntry->ssId.length = pBeaconStruct->ssId.length; + qdf_mem_copy(pftSessionEntry->ssId.ssId, pBeaconStruct->ssId.ssId, + pftSessionEntry->ssId.length); + lim_fill_dot11mode(pMac, pftSessionEntry, psessionEntry); + + pe_debug("dot11mode: %d", pftSessionEntry->dot11mode); + pftSessionEntry->vhtCapability = + (IS_DOT11_MODE_VHT(pftSessionEntry->dot11mode) + && IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)); + pftSessionEntry->htCapability = + (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) + && pBeaconStruct->HTCaps.present); + + /* Copy The channel Id to the session Table */ + pftSessionEntry->limReassocChannelId = pbssDescription->channelId; + pftSessionEntry->currentOperChannel = pbssDescription->channelId; + + pftSessionEntry->limRFBand = lim_get_rf_band( + pftSessionEntry->currentOperChannel); + + if (pftSessionEntry->limRFBand == BAND_2G) { + cbEnabledMode = pMac->roam.configParam.channelBondingMode24GHz; + } else { + cbEnabledMode = pMac->roam.configParam.channelBondingMode5GHz; + } + pftSessionEntry->htSupportedChannelWidthSet = + (pBeaconStruct->HTInfo.present) ? + (cbEnabledMode && pBeaconStruct->HTInfo.recommendedTxWidthSet) : 0; + pftSessionEntry->htRecommendedTxWidthSet = + pftSessionEntry->htSupportedChannelWidthSet; + + if (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) && + pBeaconStruct->VHTOperation.present && + pftSessionEntry->vhtCapability) { + pftSessionEntry->vhtCapabilityPresentInBeacon = 1; + } else { + pftSessionEntry->vhtCapabilityPresentInBeacon = 0; + } + if (pftSessionEntry->htRecommendedTxWidthSet) { + pftSessionEntry->ch_width = CH_WIDTH_40MHZ; + if (pftSessionEntry->vhtCapabilityPresentInBeacon && + pBeaconStruct->VHTOperation.chanWidth) { + pftSessionEntry->ch_width = + pBeaconStruct->VHTOperation.chanWidth + 1; + pftSessionEntry->ch_center_freq_seg0 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + pftSessionEntry->ch_center_freq_seg1 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + } else { + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pftSessionEntry->ch_center_freq_seg0 = + pbssDescription->channelId + 2; + else if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pftSessionEntry->ch_center_freq_seg0 = + pbssDescription->channelId - 2; + else + pe_warn("Invalid sec ch offset"); + } + } else { + pftSessionEntry->ch_width = CH_WIDTH_20MHZ; + pftSessionEntry->ch_center_freq_seg0 = 0; + pftSessionEntry->ch_center_freq_seg1 = 0; + } + + sir_copy_mac_addr(pftSessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + sir_copy_mac_addr(pftSessionEntry->limReAssocbssId, + pbssDescription->bssId); + sir_copy_mac_addr(pftSessionEntry->prev_ap_bssid, psessionEntry->bssId); + + /* Store beaconInterval */ + pftSessionEntry->beaconParams.beaconInterval = + pbssDescription->beaconInterval; + pftSessionEntry->bssType = psessionEntry->bssType; + + pftSessionEntry->statypeForBss = STA_ENTRY_PEER; + pftSessionEntry->nwType = pbssDescription->nwType; + + + if (pftSessionEntry->bssType == eSIR_INFRASTRUCTURE_MODE) { + pftSessionEntry->limSystemRole = eLIM_STA_ROLE; + } else { + /* Throw an error & return & make sure to delete the session */ + pe_warn("Invalid bss type"); + } + + pftSessionEntry->limCurrentBssCaps = pbssDescription->capabilityInfo; + pftSessionEntry->limReassocBssCaps = pbssDescription->capabilityInfo; + if (pMac->roam.configParam.shortSlotTime && + SIR_MAC_GET_SHORT_SLOT_TIME(pftSessionEntry->limReassocBssCaps)) { + pftSessionEntry->shortSlotTimeSupported = true; + } + + regMax = cfg_get_regulatory_max_transmit_power(pMac, + pftSessionEntry-> + currentOperChannel); + localPowerConstraint = regMax; + lim_extract_ap_capability(pMac, (uint8_t *) pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + &pftSessionEntry->limCurrentBssQosCaps, + &pftSessionEntry->limCurrentBssPropCap, ¤tBssUapsd, + &localPowerConstraint, pftSessionEntry); + + pftSessionEntry->limReassocBssQosCaps = + pftSessionEntry->limCurrentBssQosCaps; + pftSessionEntry->limReassocBssPropCap = + pftSessionEntry->limCurrentBssPropCap; + + pftSessionEntry->is11Rconnection = psessionEntry->is11Rconnection; +#ifdef FEATURE_WLAN_ESE + pftSessionEntry->isESEconnection = psessionEntry->isESEconnection; + pftSessionEntry->is_ese_version_ie_present = + pBeaconStruct->is_ese_ver_ie_present; +#endif + pftSessionEntry->isFastTransitionEnabled = + psessionEntry->isFastTransitionEnabled; + + pftSessionEntry->isFastRoamIniFeatureEnabled = + psessionEntry->isFastRoamIniFeatureEnabled; + + tx_pwr_attr.reg_max = regMax; + tx_pwr_attr.ap_tx_power = localPowerConstraint; + tx_pwr_attr.ini_tx_power = pMac->roam.configParam.nTxPowerCap; + tx_pwr_attr.frequency = + wlan_reg_get_channel_freq(pMac->pdev, + pftSessionEntry->currentOperChannel); + +#ifdef FEATURE_WLAN_ESE + pftSessionEntry->maxTxPower = + lim_get_max_tx_power(pMac, &tx_pwr_attr); +#else + pftSessionEntry->maxTxPower = QDF_MIN(regMax, (localPowerConstraint)); +#endif + + pe_debug("Reg max: %d local pwr: %d, ini tx pwr: %d max tx pwr: %d", + regMax, localPowerConstraint, + pMac->roam.configParam.nTxPowerCap, + pftSessionEntry->maxTxPower); + if (!lim_is_roam_synch_in_progress(psessionEntry)) { + pftSessionEntry->limPrevSmeState = pftSessionEntry->limSmeState; + pftSessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + MTRACE(mac_trace(pMac, + TRACE_CODE_SME_STATE, + pftSessionEntry->peSessionId, + pftSessionEntry->limSmeState)); + } + pftSessionEntry->encryptType = psessionEntry->encryptType; +#ifdef WLAN_FEATURE_11W + pftSessionEntry->limRmfEnabled = psessionEntry->limRmfEnabled; +#endif + if ((pftSessionEntry->limRFBand == BAND_2G) && + (pftSessionEntry->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ)) + lim_init_obss_params(pMac, pftSessionEntry); + + pftSessionEntry->enableHtSmps = psessionEntry->enableHtSmps; + pftSessionEntry->htSmpsvalue = psessionEntry->htSmpsvalue; + /* + * 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 + */ + pftSessionEntry->supported_nss_1x1 = true; + pe_debug("FT enable smps: %d mode: %d supported nss 1x1: %d", + pftSessionEntry->enableHtSmps, + pftSessionEntry->htSmpsvalue, + pftSessionEntry->supported_nss_1x1); + + qdf_mem_free(pBeaconStruct); +} +#endif + +/*------------------------------------------------------------------ + * + * This function is called to process the update key request from SME + * + *------------------------------------------------------------------*/ +bool lim_process_ft_update_key(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tAddBssParams *pAddBssParams; + tSirFTUpdateKeyInfo *pKeyInfo; + uint32_t val = 0; + tpPESession psessionEntry; + uint8_t sessionId; + + /* Sanity Check */ + if (pMac == NULL || pMsgBuf == NULL) { + return false; + } + + pKeyInfo = (tSirFTUpdateKeyInfo *) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, pKeyInfo->bssid.bytes, + &sessionId); + if (NULL == psessionEntry) { + pe_err("%s: Unable to find session for the following bssid", + __func__); + lim_print_mac_addr(pMac, pKeyInfo->bssid.bytes, LOGE); + return false; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return false; + } + + if (NULL == psessionEntry->ftPEContext.pAddBssReq) { + /* AddBss Req is NULL, save the keys to configure them later. */ + tpLimMlmSetKeysReq pMlmSetKeysReq = + &psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParam; + + qdf_mem_zero(pMlmSetKeysReq, sizeof(tLimMlmSetKeysReq)); + qdf_copy_macaddr(&pMlmSetKeysReq->peer_macaddr, + &pKeyInfo->bssid); + pMlmSetKeysReq->sessionId = psessionEntry->peSessionId; + pMlmSetKeysReq->smesessionId = psessionEntry->smeSessionId; + pMlmSetKeysReq->edType = pKeyInfo->keyMaterial.edType; + pMlmSetKeysReq->numKeys = pKeyInfo->keyMaterial.numKeys; + qdf_mem_copy((uint8_t *) &pMlmSetKeysReq->key, + (uint8_t *) &pKeyInfo->keyMaterial.key, + sizeof(tSirKeys)); + + psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParamValid = true; + + if (psessionEntry->ftPEContext.pAddStaReq == NULL) { + pe_err("pAddStaReq is NULL"); + lim_send_set_sta_key_req(pMac, pMlmSetKeysReq, 0, 0, + psessionEntry, false); + psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParamValid = false; + } + } else { + pAddBssParams = psessionEntry->ftPEContext.pAddBssReq; + + /* Store the key information in the ADD BSS parameters */ + pAddBssParams->extSetStaKeyParamValid = 1; + pAddBssParams->extSetStaKeyParam.encType = + pKeyInfo->keyMaterial.edType; + qdf_mem_copy((uint8_t *) &pAddBssParams->extSetStaKeyParam.key, + (uint8_t *) &pKeyInfo->keyMaterial.key, + sizeof(tSirKeys)); + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) { + pe_warn("Unable to read WNI_CFG_SINGLE_TID_RC"); + } + + pAddBssParams->extSetStaKeyParam.singleTidRc = val; + pe_debug("Key valid: %d keyLength: %d", + pAddBssParams->extSetStaKeyParamValid, + pAddBssParams->extSetStaKeyParam.key[0].keyLength); + + pAddBssParams->extSetStaKeyParam.staIdx = 0; + + pe_debug("BSSID: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pKeyInfo->bssid.bytes)); + + qdf_copy_macaddr(&pAddBssParams->extSetStaKeyParam.peer_macaddr, + &pKeyInfo->bssid); + + pAddBssParams->extSetStaKeyParam.sendRsp = false; + + } + return true; +} + +static void +lim_ft_send_aggr_qos_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, + tpAggrAddTsParams aggrQosRsp, uint8_t smesessionId) +{ + tpSirAggrQosRsp rsp; + int i = 0; + + if (!rspReqd) { + return; + } + rsp = qdf_mem_malloc(sizeof(tSirAggrQosRsp)); + if (NULL == rsp) { + pe_err("AllocateMemory failed for tSirAggrQosRsp"); + 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 < SIR_QOS_NUM_AC_MAX; i++) { + if ((1 << i) & aggrQosRsp->tspecIdx) { + if (QDF_IS_STATUS_SUCCESS(aggrQosRsp->status[i])) + rsp->aggrInfo.aggrRsp[i].status = + eSIR_MAC_SUCCESS_STATUS; + else + rsp->aggrInfo.aggrRsp[i].status = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + rsp->aggrInfo.aggrRsp[i].tspec = aggrQosRsp->tspec[i]; + } + } + lim_send_sme_aggr_qos_rsp(pMac, rsp, smesessionId); + return; +} + +void lim_process_ft_aggr_qo_s_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsg) +{ + tpAggrAddTsParams pAggrQosRspMsg = NULL; + tAddTsParams addTsParam = { 0 }; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + tpPESession psessionEntry = NULL; + int i = 0; + + pe_debug(" Received AGGR_QOS_RSP from HAL"); + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pAggrQosRspMsg = (tpAggrAddTsParams) (limMsg->bodyptr); + if (NULL == pAggrQosRspMsg) { + pe_err("NULL pAggrQosRspMsg"); + return; + } + psessionEntry = + pe_find_session_by_session_id(pMac, pAggrQosRspMsg->sessionId); + if (NULL == psessionEntry) { + pe_err("Cant find session entry for %s", __func__); + if (pAggrQosRspMsg != NULL) { + qdf_mem_free(pAggrQosRspMsg); + } + return; + } + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) { + if ((((1 << i) & pAggrQosRspMsg->tspecIdx)) && + (pAggrQosRspMsg->status[i] != QDF_STATUS_SUCCESS)) { + sir_copy_mac_addr(peerMacAddr, psessionEntry->bssId); + addTsParam.staIdx = pAggrQosRspMsg->staIdx; + addTsParam.sessionId = pAggrQosRspMsg->sessionId; + addTsParam.tspec = pAggrQosRspMsg->tspec[i]; + addTsParam.tspecIdx = pAggrQosRspMsg->tspecIdx; + lim_send_delts_req_action_frame(pMac, peerMacAddr, rspReqd, + &addTsParam.tspec.tsinfo, + &addTsParam.tspec, + psessionEntry); + pSta = + dph_lookup_assoc_id(pMac, addTsParam.staIdx, &assocId, + &psessionEntry->dph.dphHashTable); + if (pSta != NULL) { + lim_admit_control_delete_ts(pMac, assocId, + &addTsParam.tspec. + tsinfo, NULL, + (uint8_t *) & + addTsParam.tspecIdx); + } + } + } + lim_ft_send_aggr_qos_rsp(pMac, rspReqd, pAggrQosRspMsg, + psessionEntry->smeSessionId); + if (pAggrQosRspMsg != NULL) { + qdf_mem_free(pAggrQosRspMsg); + } + return; +} + +QDF_STATUS lim_process_ft_aggr_qos_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + struct scheduler_msg msg = {0}; + tSirAggrQosReq *aggrQosReq = (tSirAggrQosReq *) pMsgBuf; + tpAggrAddTsParams pAggrAddTsParam; + tpPESession psessionEntry = NULL; + tpLimTspecInfo tspecInfo; + uint8_t ac; + tpDphHashNode pSta; + uint16_t aid; + uint8_t sessionId; + int i; + + pAggrAddTsParam = qdf_mem_malloc(sizeof(tAggrAddTsParams)); + if (NULL == pAggrAddTsParam) { + pe_err("AllocateMemory() failed"); + return QDF_STATUS_E_NOMEM; + } + + psessionEntry = pe_find_session_by_bssid(pMac, aggrQosReq->bssid.bytes, + &sessionId); + + if (psessionEntry == NULL) { + 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(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + qdf_mem_free(pAggrAddTsParam); + return QDF_STATUS_E_FAILURE; + } + + pSta = dph_lookup_hash_entry(pMac, aggrQosReq->bssid.bytes, &aid, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + pe_err("Station context not found - ignoring AddTsRsp"); + qdf_mem_free(pAggrAddTsParam); + return QDF_STATUS_E_FAILURE; + } + + pAggrAddTsParam->staIdx = psessionEntry->staId; + /* Fill in the sessionId specific to PE */ + pAggrAddTsParam->sessionId = sessionId; + pAggrAddTsParam->tspecIdx = aggrQosReq->aggrInfo.tspecIdx; + pAggrAddTsParam->vdev_id = psessionEntry->smeSessionId; + + for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) { + if (aggrQosReq->aggrInfo.tspecIdx & (1 << i)) { + tSirMacTspecIE *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(pMac, + psessionEntry, + &pTspec-> + tsinfo, + SET_UAPSD_MASK); + } else { + lim_set_tspec_uapsd_mask_per_session(pMac, + psessionEntry, + &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) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + lim_set_active_edca_params(pMac, + psessionEntry->gLimEdcaParams, + psessionEntry); + + lim_send_edca_params(pMac, + psessionEntry->gLimEdcaParamsActive, + pSta->bssId, false); + + if (QDF_STATUS_SUCCESS != + lim_tspec_add(pMac, pSta->staAddr, pSta->assocId, + pTspec, 0, &tspecInfo)) { + pe_err("Adding entry in lim Tspec Table failed"); + pMac->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 (!pMac->roam.configParam.isRoamOffloadEnabled || + (pMac->roam.configParam.isRoamOffloadEnabled && + !psessionEntry->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(pMac, false); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + pe_warn("wma_post_ctrl_msg() failed"); + SET_LIM_PROCESS_DEFD_MESGS(pMac, 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(pMac, true, pAggrAddTsParam, + psessionEntry->smeSessionId); + if (pAggrAddTsParam != NULL) { + qdf_mem_free(pAggrAddTsParam); + } + } +#endif + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c new file mode 100644 index 0000000000000000000000000000000000000000..40368a4651bc1de96f0ab3d7dfbbda97b896e915 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c @@ -0,0 +1,805 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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" + +/** + * lim_ft_cleanup_pre_auth_info() - Cleanup preauth related information + * @pMac: Global MAC Context + * @psessionEntry: 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(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tpPESession pReAssocSessionEntry = NULL; + uint8_t sessionId = 0; + + if (!psessionEntry) { + pe_err("psessionEntry is NULL"); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq) { + pReAssocSessionEntry = + pe_find_session_by_bssid(pMac, + psessionEntry->ftPEContext. + pFTPreAuthReq->preAuthbssId, + &sessionId); + + if (psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription); + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq); + psessionEntry->ftPEContext.pFTPreAuthReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddBssReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + psessionEntry->ftPEContext.pAddBssReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddStaReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddStaReq); + psessionEntry->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + qdf_mem_zero(&psessionEntry->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) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + FL("Deleting Preauth session(%d)"), + pReAssocSessionEntry->peSessionId); + pe_delete_session(pMac, pReAssocSessionEntry); + } + } +} + +/* + * lim_process_ft_pre_auth_req() - process ft pre auth req + * + * @mac_ctx: global mac ctx + * @msg: pointer to message + * + * 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 + */ +int lim_process_ft_pre_auth_req(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + int buf_consumed = false; + tpPESession session; + uint8_t session_id; + tpSirFTPreAuthReq ft_pre_auth_req = (tSirFTPreAuthReq *) msg->bodyptr; + + if (NULL == 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 == NULL) { + pe_err("Unable to find session for the bssid" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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->currentOperChannel != + session->ftPEContext.pFTPreAuthReq->preAuthchannelNum) + || 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 + * @pMac: Global MAC Context + * @status: Status Code + * @data: pre-auth data + * @psessionEntry: PE Session + * + * This routine will trigger the sending of authentication frame + * to the peer. + * + * Return: None + */ +void lim_perform_ft_pre_auth(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + tSirMacAuthFrameBody authFrame; + unsigned int session_id; + eCsrAuthType auth_type; + + if (NULL == psessionEntry) { + pe_err("psessionEntry is NULL"); + return; + } + session_id = psessionEntry->smeSessionId; + auth_type = + pMac->roam.roamSession[session_id].connectedProfile.AuthType; + + if (psessionEntry->is11Rconnection && + psessionEntry->ftPEContext.pFTPreAuthReq) { + /* Only 11r assoc has FT IEs */ + if ((auth_type != eCSR_AUTH_TYPE_OPEN_SYSTEM) && + (psessionEntry->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(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + pe_debug("Entered wait auth2 state for FT (old session %pK)", + psessionEntry); + if (psessionEntry->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; + + pMac->lim.limTimers.g_lim_periodic_auth_retry_timer.sessionId = + psessionEntry->peSessionId; + + /* Start timer here to come back to operating channel */ + pMac->lim.limTimers.gLimFTPreAuthRspTimer.sessionId = + psessionEntry->peSessionId; + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimFTPreAuthRspTimer)) { + pe_err("FT Auth Rsp Timer Start Failed"); + goto preauth_fail; + } + MTRACE(mac_trace(pMac, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_FT_PREAUTH_RSP_TIMER)); + + pe_debug("FT Auth Rsp Timer Started"); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + pMac->lim.pSessionEntry, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +#endif + if (psessionEntry->ftPEContext.pFTPreAuthReq) + lim_send_auth_mgmt_frame(pMac, &authFrame, + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + LIM_NO_WEP_IN_FC, psessionEntry); + + return; + +preauth_fail: + lim_handle_ft_pre_auth_rsp(pMac, QDF_STATUS_E_FAILURE, NULL, 0, psessionEntry); + return; +} + +/** + * lim_ft_setup_auth_session() - Fill the FT Session + * @pMac: Global MAC Context + * @psessionEntry: 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(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tpPESession pftSessionEntry = NULL; + uint8_t sessionId = 0; + + pftSessionEntry = + pe_find_session_by_bssid(pMac, psessionEntry->limReAssocbssId, + &sessionId); + if (pftSessionEntry == NULL) { + pe_err("No session found for bssid"); + lim_print_mac_addr(pMac, psessionEntry->limReAssocbssId, LOGE); + return QDF_STATUS_E_FAILURE; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return QDF_STATUS_E_FAILURE; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq && + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription) { + lim_fill_ft_session(pMac, + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription, pftSessionEntry, + psessionEntry); + + lim_ft_prepare_add_bss_req(pMac, false, pftSessionEntry, + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_ft_process_pre_auth_result() - Process the Auth frame + * @pMac: Global MAC context + * @psessionEntry: PE Session + * + * Return: None + */ +static void lim_ft_process_pre_auth_result(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + if (NULL == psessionEntry || + NULL == psessionEntry->ftPEContext.pFTPreAuthReq) + return; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + + if (psessionEntry->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) { + psessionEntry->ftPEContext.ftPreAuthStatus = + lim_ft_setup_auth_session(pMac, psessionEntry); + } + /* Post the FT Pre Auth Response to SME */ + lim_post_ft_pre_auth_rsp(pMac, + psessionEntry->ftPEContext.ftPreAuthStatus, + psessionEntry->ftPEContext.saved_auth_rsp, + psessionEntry->ftPEContext.saved_auth_rsp_length, + psessionEntry); +} + +/** + * lim_handle_ft_pre_auth_rsp() - Handle the Auth response + * @pMac: Global MAC Context + * @status: Status Code + * @auth_rsp: Auth Response + * @auth_rsp_length: Auth response length + * @psessionEntry: 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(tpAniSirGlobal pMac, QDF_STATUS status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + tpPESession psessionEntry) +{ + tpPESession pftSessionEntry = NULL; + uint8_t sessionId = 0; + tpSirBssDescription pbssDescription = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, + psessionEntry, (uint16_t) status, 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + + /* Save the status of pre-auth */ + psessionEntry->ftPEContext.ftPreAuthStatus = status; + + /* Save the auth rsp, so we can send it to + * SME once we resume link + */ + psessionEntry->ftPEContext.saved_auth_rsp_length = 0; + if ((auth_rsp != NULL) && (auth_rsp_length < MAX_FTIE_SIZE)) { + qdf_mem_copy(psessionEntry->ftPEContext.saved_auth_rsp, + auth_rsp, auth_rsp_length); + psessionEntry->ftPEContext.saved_auth_rsp_length = + auth_rsp_length; + } + + if (!psessionEntry->ftPEContext.pFTPreAuthReq || + !psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription) { + pe_err("pFTPreAuthReq or pbssDescription is NULL"); + return; + } + + /* Create FT session for the re-association at this point */ + if (psessionEntry->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) { + pbssDescription = + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription; + pftSessionEntry = + pe_create_session(pMac, pbssDescription->bssId, + &sessionId, pMac->lim.maxStation, + psessionEntry->bssType); + if (pftSessionEntry == NULL) { + pe_err("Session not created for pre-auth 11R AP"); + status = QDF_STATUS_E_FAILURE; + psessionEntry->ftPEContext.ftPreAuthStatus = status; + goto send_rsp; + } + + pftSessionEntry->smeSessionId = psessionEntry->smeSessionId; + sir_copy_mac_addr(pftSessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + sir_copy_mac_addr(pftSessionEntry->limReAssocbssId, + pbssDescription->bssId); + + /* Update the beacon/probe filter in mac_ctx */ + lim_set_bcn_probe_filter(pMac, + pftSessionEntry, + NULL, 0); + + if (pftSessionEntry->bssType == eSIR_INFRASTRUCTURE_MODE) + pftSessionEntry->limSystemRole = eLIM_STA_ROLE; + else + pe_err("Invalid bss type"); + + pftSessionEntry->limPrevSmeState = pftSessionEntry->limSmeState; + qdf_mem_copy(&(pftSessionEntry->htConfig), + &(psessionEntry->htConfig), + sizeof(psessionEntry->htConfig)); + pftSessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + + if (IS_5G_CH(psessionEntry->ftPEContext.pFTPreAuthReq-> + preAuthchannelNum)) + pftSessionEntry->vdev_nss = pMac->vdev_type_nss_5g.sta; + else + pftSessionEntry->vdev_nss = pMac->vdev_type_nss_2g.sta; + + pe_debug("created session (%pK) with id = %d", + pftSessionEntry, pftSessionEntry->peSessionId); + + /* Update the ReAssoc BSSID of the current session */ + sir_copy_mac_addr(psessionEntry->limReAssocbssId, + pbssDescription->bssId); + lim_print_mac_addr(pMac, psessionEntry->limReAssocbssId, LOGD); + } +send_rsp: + if ((psessionEntry->currentOperChannel != + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthchannelNum) || + lim_is_in_mcc(pMac)) { + /* Need to move to the original AP channel */ + lim_process_abort_scan_ind(pMac, psessionEntry->smeSessionId, + psessionEntry->ftPEContext.pFTPreAuthReq->scan_id, + pMac->lim.req_id | PREAUTH_REQUESTOR_ID); + } else { + pe_debug("Pre auth on same channel as connected AP channel %d\ + and no mcc pe sessions exist", + psessionEntry->ftPEContext.pFTPreAuthReq-> + preAuthchannelNum); + lim_ft_process_pre_auth_result(pMac, psessionEntry); + } +} + +/* + * 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(tpAniSirGlobal mac_ctx) +{ + tpPESession 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.limTimers.gLimFTPreAuthRspTimer.sessionId); + if (NULL == 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 (NULL == session->ftPEContext.pFTPreAuthReq) { + /* Auth Rsp might already be posted to SME and ftcleanup done */ + pe_err("pFTPreAuthReq is NULL sessionId: %d", + mac_ctx->lim.limTimers.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_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(tpAniSirGlobal mac_ctx, + QDF_STATUS status, + uint8_t *auth_rsp, + uint16_t auth_rsp_length, + tpPESession session) +{ + tpSirFTPreAuthRsp ft_pre_auth_rsp; + struct scheduler_msg mmh_msg = {0}; + uint16_t rsp_len = sizeof(tSirFTPreAuthRsp); + + ft_pre_auth_rsp = (tpSirFTPreAuthRsp) qdf_mem_malloc(rsp_len); + if (NULL == ft_pre_auth_rsp) { + pe_err("Failed to allocate memory"); + QDF_ASSERT(ft_pre_auth_rsp != NULL); + return; + } + + pe_debug("Auth Rsp = %pK", ft_pre_auth_rsp); + 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(ft_pre_auth_rsp); + return; + } + ft_pre_auth_rsp->smeSessionId = session->smeSessionId; + /* The bssid of the AP we are sending Auth1 to. */ + if (session->ftPEContext.pFTPreAuthReq) + sir_copy_mac_addr(ft_pre_auth_rsp->preAuthbssId, + session->ftPEContext.pFTPreAuthReq->preAuthbssId); + } + + ft_pre_auth_rsp->messageType = eWNI_SME_FT_PRE_AUTH_RSP; + ft_pre_auth_rsp->length = (uint16_t) rsp_len; + ft_pre_auth_rsp->status = status; + + /* Attach the auth response now back to SME */ + ft_pre_auth_rsp->ft_ies_length = 0; + if ((auth_rsp != NULL) && (auth_rsp_length < MAX_FTIE_SIZE)) { + /* Only 11r assoc has FT IEs */ + qdf_mem_copy(ft_pre_auth_rsp->ft_ies, + auth_rsp, auth_rsp_length); + ft_pre_auth_rsp->ft_ies_length = auth_rsp_length; + } + + if (status != QDF_STATUS_SUCCESS) { + /* + * Ensure that on Pre-Auth failure the cached Pre-Auth Req and + * other allocated memory is freed up before returning. + */ + pe_debug("Pre-Auth Failed, Cleanup!"); + lim_ft_cleanup(mac_ctx, session); + } + + mmh_msg.type = ft_pre_auth_rsp->messageType; + mmh_msg.bodyptr = ft_pre_auth_rsp; + mmh_msg.bodyval = 0; + + pe_debug("Posted Auth Rsp to SME with status of 0x%x", status); +#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_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tSirFTPreAuthReq *ft_preauth_req) +{ + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev; + uint8_t session_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (session_entry == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Session entry is NULL")); + return QDF_STATUS_E_FAILURE; + } + + session_id = session_entry->smeSessionId; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(req, sizeof(*req)); + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, + session_id, WLAN_OSIF_ID); + if (vdev == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("vdev object is NULL")); + qdf_mem_free(req); + return QDF_STATUS_E_FAILURE; + } + + ucfg_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 = ucfg_scan_get_scan_id(mac_ctx->psoc); + if (!req->scan_req.scan_id) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + qdf_mem_free(req); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Invalid scan ID")); + return QDF_STATUS_E_FAILURE; + } + ft_preauth_req->scan_id = req->scan_req.scan_id; + req->scan_req.vdev_id = session_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 = + cds_chan_to_freq(ft_preauth_req->preAuthchannelNum); + + req->scan_req.dwell_time_active = LIM_FT_PREAUTH_SCAN_TIME; + req->scan_req.dwell_time_passive = LIM_FT_PREAUTH_SCAN_TIME; + + status = ucfg_scan_start(req); + if (status != QDF_STATUS_SUCCESS) + /* Don't free req here, ucfg_scan_start will do free */ + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Issue scan req failed")); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + return status; +} + +/** + * lim_preauth_scan_event_handler() - Process firmware preauth scan events + * + * @mac_ctx:Pointer to global MAC structure + * @event: Scan event + * @session_id: session entry + * @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(tpAniSirGlobal mac_ctx, + enum sir_scan_event_type event, + uint8_t session_id, + uint32_t scan_id) +{ + tpPESession session_entry; + + if (event == SIR_SCAN_EVENT_COMPLETED) { + session_entry = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer.sessionId); + } else { + session_entry = pe_find_session_by_sme_session_id(mac_ctx, + session_id); + } + + if (session_entry == NULL) { + pe_err("SmeSessionId:%d PeSessionId:%d does not exist", + session_id, + mac_ctx->lim.limTimers.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. + */ + lim_ft_process_pre_auth_result(mac_ctx, session_entry); + 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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..f05ac50db164714e26d77544a368d4a3c5becd5f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c @@ -0,0 +1,1789 @@ +/* + * 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. + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "sir_common.h" +#include "wni_cfg.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" /* sch_set_fixed_beacon_fields for IBSS coalesce */ +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_types.h" + +/** + * ibss_peer_find + * + ***FUNCTION: + * This function is called while adding a context at + * DPH & Polaris for a peer in IBSS. + * If peer is found in the list, capabilities from the + * returned BSS description are used at DPH node & Polaris. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the peer + * + * @return Pointer to peer node if found, else NULL + */ + +static tLimIbssPeerNode *ibss_peer_find(tpAniSirGlobal pMac, + tSirMacAddr macAddr) +{ + tLimIbssPeerNode *pTempNode = pMac->lim.gLimIbssPeerList; + + while (pTempNode != NULL) { + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) + break; + pTempNode = pTempNode->next; + } + return pTempNode; +} /*** end ibss_peer_find() ***/ + +/** + * ibss_peer_add + * + ***FUNCTION: + * This is called on a STA in IBSS upon receiving Beacon/ + * Probe Response from a peer. + * + ***LOGIC: + * Node is always added to the front of the list + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pPeerNode - Pointer to peer node to be added to the list. + * + * @return None + */ + +static QDF_STATUS +ibss_peer_add(tpAniSirGlobal pMac, tLimIbssPeerNode *pPeerNode) +{ +#ifdef ANI_SIR_IBSS_PEER_CACHING + uint32_t numIbssPeers = (2 * pMac->lim.maxStation); + + if (pMac->lim.gLimNumIbssPeers >= numIbssPeers) { + /** + * Reached max number of peers to be maintained. + * Delete last entry & add new entry at the beginning. + */ + tLimIbssPeerNode *pTemp, *pPrev; + + pTemp = pPrev = pMac->lim.gLimIbssPeerList; + while (pTemp->next != NULL) { + pPrev = pTemp; + pTemp = pTemp->next; + } + if (pTemp->beacon) { + qdf_mem_free(pTemp->beacon); + } + + qdf_mem_free(pTemp); + pPrev->next = NULL; + } else +#endif + pMac->lim.gLimNumIbssPeers++; + + pPeerNode->next = pMac->lim.gLimIbssPeerList; + pMac->lim.gLimIbssPeerList = pPeerNode; + + return QDF_STATUS_SUCCESS; + +} /*** end limAddIbssPeerToList() ***/ + +/** + * ibss_peer_collect + * + ***FUNCTION: + * This is called to collect IBSS peer information + * from received Beacon/Probe Response frame from it. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pBD - Pointer to received BD + * @param pPeer - Pointer to IBSS peer node + * + * @return None + */ + +static void +ibss_peer_collect(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + tpSirMacMgmtHdr pHdr, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + qdf_mem_copy(pPeer->peerMacAddr, pHdr->sa, sizeof(tSirMacAddr)); + + pPeer->capabilityInfo = pBeacon->capabilityInfo; + pPeer->extendedRatesPresent = pBeacon->extendedRatesPresent; + pPeer->edcaPresent = pBeacon->edcaPresent; + pPeer->wmeEdcaPresent = pBeacon->wmeEdcaPresent; + pPeer->wmeInfoPresent = pBeacon->wmeInfoPresent; + + if (pBeacon->IBSSParams.present) { + pPeer->atimIePresent = pBeacon->IBSSParams.present; + pPeer->peerAtimWindowLength = pBeacon->IBSSParams.atim; + } + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && + (pBeacon->HTCaps.present)) { + pPeer->htCapable = pBeacon->HTCaps.present; + qdf_mem_copy((uint8_t *) pPeer->supportedMCSSet, + (uint8_t *) pBeacon->HTCaps.supportedMCSSet, + sizeof(pPeer->supportedMCSSet)); + pPeer->htGreenfield = (uint8_t) pBeacon->HTCaps.greenField; + pPeer->htSupportedChannelWidthSet = + (uint8_t) pBeacon->HTCaps.supportedChannelWidthSet; + pPeer->htMIMOPSState = + (tSirMacHTMIMOPowerSaveState) pBeacon->HTCaps.mimoPowerSave; + pPeer->htMaxAmsduLength = + (uint8_t) pBeacon->HTCaps.maximalAMSDUsize; + pPeer->htAMpduDensity = pBeacon->HTCaps.mpduDensity; + pPeer->htDsssCckRate40MHzSupport = + (uint8_t) pBeacon->HTCaps.dsssCckMode40MHz; + pPeer->htShortGI20Mhz = (uint8_t) pBeacon->HTCaps.shortGI20MHz; + pPeer->htShortGI40Mhz = (uint8_t) pBeacon->HTCaps.shortGI40MHz; + pPeer->htMaxRxAMpduFactor = pBeacon->HTCaps.maxRxAMPDUFactor; + pPeer->htSecondaryChannelOffset = + pBeacon->HTInfo.secondaryChannelOffset; + pPeer->htLdpcCapable = (uint8_t) pBeacon->HTCaps.advCodingCap; + } + + /* Collect peer VHT capabilities based on the received beacon from the peer */ + if (pBeacon->VHTCaps.present) { + pPeer->vhtSupportedChannelWidthSet = + pBeacon->VHTOperation.chanWidth; + pPeer->vhtCapable = pBeacon->VHTCaps.present; + + /* Collect VHT capabilities from beacon */ + qdf_mem_copy((uint8_t *) &pPeer->VHTCaps, + (uint8_t *) &pBeacon->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + pPeer->erpIePresent = pBeacon->erpPresent; + + qdf_mem_copy((uint8_t *) &pPeer->supportedRates, + (uint8_t *) &pBeacon->supportedRates, + pBeacon->supportedRates.numRates + 1); + if (pPeer->extendedRatesPresent) + qdf_mem_copy((uint8_t *) &pPeer->extendedRates, + (uint8_t *) &pBeacon->extendedRates, + pBeacon->extendedRates.numRates + 1); + else + pPeer->extendedRates.numRates = 0; + + pPeer->next = NULL; +} /*** end ibss_peer_collect() ***/ + +/* handle change in peer qos/wme capabilities */ +static void +ibss_sta_caps_update(tpAniSirGlobal pMac, + tLimIbssPeerNode *pPeerNode, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tpDphHashNode pStaDs; + + pPeerNode->beaconHBCount++; /* Update beacon count. */ + + /* if the peer node exists, update its qos capabilities */ + pStaDs = dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) + return; + + /* Update HT Capabilities */ + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) { + pStaDs->mlmStaContext.htCapability = pPeerNode->htCapable; + if (pPeerNode->htCapable) { + pStaDs->htGreenfield = pPeerNode->htGreenfield; + pStaDs->htSupportedChannelWidthSet = + pPeerNode->htSupportedChannelWidthSet; + pStaDs->htSecondaryChannelOffset = + pPeerNode->htSecondaryChannelOffset; + pStaDs->htMIMOPSState = pPeerNode->htMIMOPSState; + pStaDs->htMaxAmsduLength = pPeerNode->htMaxAmsduLength; + pStaDs->htAMpduDensity = pPeerNode->htAMpduDensity; + pStaDs->htDsssCckRate40MHzSupport = + pPeerNode->htDsssCckRate40MHzSupport; + pStaDs->htShortGI20Mhz = pPeerNode->htShortGI20Mhz; + pStaDs->htShortGI40Mhz = pPeerNode->htShortGI40Mhz; + pStaDs->htMaxRxAMpduFactor = + pPeerNode->htMaxRxAMpduFactor; + /* In the future, may need to check for "delayedBA" */ + /* For now, it is IMMEDIATE BA only on ALL TID's */ + pStaDs->baPolicyFlag = 0xFF; + pStaDs->htLdpcCapable = pPeerNode->htLdpcCapable; + } + } + if (IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) { + pStaDs->mlmStaContext.vhtCapability = pPeerNode->vhtCapable; + if (pPeerNode->vhtCapable) { + pStaDs->vhtSupportedChannelWidthSet = + pPeerNode->vhtSupportedChannelWidthSet; + + /* If in 11AC mode and if session requires 11AC mode, consider peer's */ + /* max AMPDU length factor */ + pStaDs->htMaxRxAMpduFactor = + pPeerNode->VHTCaps.maxAMPDULenExp; + pStaDs->vhtLdpcCapable = + (uint8_t) pPeerNode->VHTCaps.ldpcCodingCap; + } + } + /* peer is 11e capable but is not 11e enabled yet */ + /* some STA's when joining Airgo IBSS, assert qos capability even when */ + /* they don't support qos. however, they do not include the edca parameter */ + /* set. so let's check for edcaParam in addition to the qos capability */ + if (pPeerNode->capabilityInfo.qos && (psessionEntry->limQosEnabled) + && pPeerNode->edcaPresent) { + pStaDs->qosMode = 1; + pStaDs->wmeEnabled = 0; + if (!pStaDs->lleEnabled) { + pStaDs->lleEnabled = 1; + /* dphSetACM(pMac, pStaDs); */ + } + return; + } + /* peer is not 11e capable now but was 11e enabled earlier */ + else if (pStaDs->lleEnabled) { + pStaDs->qosMode = 0; + pStaDs->lleEnabled = 0; + } + /* peer is wme capable but is not wme enabled yet */ + if (pPeerNode->wmeInfoPresent && psessionEntry->limWmeEnabled) { + pStaDs->qosMode = 1; + pStaDs->lleEnabled = 0; + if (!pStaDs->wmeEnabled) { + pStaDs->wmeEnabled = 1; + } + return; + } + /* When the peer device supports EDCA parameters, then we were not + considering. Added this code when we saw that one of the Peer Device + was advertising WMM param where we were not honouring that. CR# 210756 + */ + if (pPeerNode->wmeEdcaPresent && psessionEntry->limWmeEnabled) { + pStaDs->qosMode = 1; + pStaDs->lleEnabled = 0; + if (!pStaDs->wmeEnabled) { + pStaDs->wmeEnabled = 1; + } + return; + } + /* peer is not wme capable now but was wme enabled earlier */ + else if (pStaDs->wmeEnabled) { + pStaDs->qosMode = 0; + pStaDs->wmeEnabled = 0; + } + +} + +static void +ibss_sta_rates_update(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + lim_populate_matching_rate_set(pMac, pStaDs, &pPeer->supportedRates, + &pPeer->extendedRates, + pPeer->supportedMCSSet, psessionEntry, + &pPeer->VHTCaps, NULL); + pStaDs->mlmStaContext.capabilityInfo = pPeer->capabilityInfo; +} /*** end ibss_sta_info_update() ***/ + +/** + * ibss_sta_info_update + * + ***FUNCTION: + * This is called to program both SW & Polaris context + * for peer in IBSS. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to DPH node + * @param pPeer - Pointer to IBSS peer node + * + * @return None + */ + +static void +ibss_sta_info_update(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + pStaDs->staType = STA_ENTRY_PEER; + ibss_sta_caps_update(pMac, pPeer, psessionEntry); + ibss_sta_rates_update(pMac, pStaDs, pPeer, psessionEntry); +} /*** end ibss_sta_info_update() ***/ + +static void ibss_coalesce_free(tpAniSirGlobal pMac) +{ + if (pMac->lim.ibssInfo.pHdr != NULL) + qdf_mem_free(pMac->lim.ibssInfo.pHdr); + if (pMac->lim.ibssInfo.pBeacon != NULL) + qdf_mem_free(pMac->lim.ibssInfo.pBeacon); + + pMac->lim.ibssInfo.pHdr = NULL; + pMac->lim.ibssInfo.pBeacon = NULL; +} + +/* + * save the beacon params for use when adding the bss + */ +static void +ibss_coalesce_save(tpAniSirGlobal pMac, + tpSirMacMgmtHdr pHdr, tpSchBeaconStruct pBeacon) +{ + /* get rid of any saved info */ + ibss_coalesce_free(pMac); + + pMac->lim.ibssInfo.pHdr = qdf_mem_malloc(sizeof(*pHdr)); + if (NULL == pMac->lim.ibssInfo.pHdr) { + pe_err("ibbs-save: Failed malloc pHdr"); + return; + } + pMac->lim.ibssInfo.pBeacon = qdf_mem_malloc(sizeof(*pBeacon)); + if (NULL == pMac->lim.ibssInfo.pBeacon) { + pe_err("ibbs-save: Failed malloc pBeacon"); + ibss_coalesce_free(pMac); + return; + } + + qdf_mem_copy(pMac->lim.ibssInfo.pHdr, pHdr, sizeof(*pHdr)); + qdf_mem_copy(pMac->lim.ibssInfo.pBeacon, pBeacon, sizeof(*pBeacon)); +} + +/* + * tries to add a new entry to dph hash node + * if necessary, an existing entry is eliminated + */ +static QDF_STATUS +ibss_dph_entry_add(tpAniSirGlobal pMac, + tSirMacAddr peerAddr, + tpDphHashNode *ppSta, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tpDphHashNode pStaDs; + + *ppSta = NULL; + + pStaDs = + dph_lookup_hash_entry(pMac, peerAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* Trying to add context for already existing STA in IBSS */ + pe_err("STA exists already"); + lim_print_mac_addr(pMac, peerAddr, LOGE); + return QDF_STATUS_E_FAILURE; + } + + /** + * Assign an AID, delete context existing with that + * AID and then add an entry to hash table maintained + * by DPH module. + */ + peerIdx = lim_assign_peer_idx(pMac, psessionEntry); + + pStaDs = + dph_get_hash_entry(pMac, peerIdx, &psessionEntry->dph.dphHashTable); + if (pStaDs) { + (void)lim_del_sta(pMac, pStaDs, false /*asynchronous */, + psessionEntry); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, peerIdx, + psessionEntry); + } + + pStaDs = + dph_add_hash_entry(pMac, peerAddr, peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + pe_err("could not add hash entry at DPH for peerIdx/aid: %d MACaddr:", + peerIdx); + lim_print_mac_addr(pMac, peerAddr, LOGE); + return QDF_STATUS_E_FAILURE; + } + + *ppSta = pStaDs; + return QDF_STATUS_SUCCESS; +} + +/* send a status change notification */ +static void +ibss_status_chg_notify(tpAniSirGlobal pMac, tSirMacAddr peerAddr, + uint16_t staIndex, uint16_t status, uint8_t sessionId) +{ + + tLimIbssPeerNode *peerNode; + uint8_t *beacon = NULL; + uint16_t bcnLen = 0; + + peerNode = ibss_peer_find(pMac, peerAddr); + if (peerNode != NULL) { + if (peerNode->beacon == NULL) + peerNode->beaconLen = 0; + beacon = peerNode->beacon; + bcnLen = peerNode->beaconLen; + peerNode->beacon = NULL; + peerNode->beaconLen = 0; + } + + lim_send_sme_ibss_peer_ind(pMac, peerAddr, staIndex, + beacon, bcnLen, status, sessionId); + + if (beacon != NULL) { + qdf_mem_free(beacon); + } +} + +static void ibss_bss_add(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tLimMlmStartReq mlmStartReq; + uint32_t cfg; + tpSirMacMgmtHdr pHdr = (tpSirMacMgmtHdr) pMac->lim.ibssInfo.pHdr; + tpSchBeaconStruct pBeacon = + (tpSchBeaconStruct) pMac->lim.ibssInfo.pBeacon; + uint8_t numExtRates = 0; + + if ((pHdr == NULL) || (pBeacon == NULL)) { + pe_err("Unable to add BSS (no cached BSS info)"); + return; + } + + qdf_mem_copy(psessionEntry->bssId, pHdr->bssId, sizeof(tSirMacAddr)); + + sir_copy_mac_addr(pHdr->bssId, psessionEntry->bssId); + + /* Copy beacon interval from sessionTable */ + cfg = psessionEntry->beaconParams.beaconInterval; + if (cfg != pBeacon->beaconInterval) + psessionEntry->beaconParams.beaconInterval = + pBeacon->beaconInterval; + + /* This function ibss_bss_add (and hence the below code) is only called during ibss coalescing. We need to + * adapt to peer's capability with respect to short slot time. Changes have been made to lim_apply_configuration() + * so that the IBSS doesn't blindly start with short slot = 1. If IBSS start is part of coalescing then it will adapt + * to peer's short slot using code below. + */ + /* If cfg is already set to current peer's capability then no need to set it again */ + if (psessionEntry->shortSlotTimeSupported != + pBeacon->capabilityInfo.shortSlotTime) { + psessionEntry->shortSlotTimeSupported = + pBeacon->capabilityInfo.shortSlotTime; + } + qdf_mem_copy((uint8_t *) &psessionEntry->pLimStartBssReq-> + operationalRateSet, (uint8_t *) &pBeacon->supportedRates, + pBeacon->supportedRates.numRates); + + /** + * WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET CFG needs to be reset, when + * there is no extended rate IE present in beacon. This is especially important when + * supportedRateSet IE contains all the extended rates as well and STA decides to coalesce. + * In this IBSS coalescing scenario LIM will tear down the BSS and Add a new one. So LIM needs to + * reset this CFG, just in case CSR originally had set this CFG when IBSS was started from the local profile. + * If IBSS was started by CSR from the BssDescription, then it would reset this CFG before StartBss is issued. + * The idea is that the count of OpRateSet and ExtendedOpRateSet rates should not be more than 12. + */ + + if (pBeacon->extendedRatesPresent) + numExtRates = pBeacon->extendedRates.numRates; + if (cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + (uint8_t *) &pBeacon->extendedRates.rate, + numExtRates) != QDF_STATUS_SUCCESS) { + pe_err("could not update ExtendedOperRateset at CFG"); + return; + } + + /* + * Each IBSS node will advertise its own HT Capabilities instead of adapting to the Peer's capabilities + * If we don't do this then IBSS may not go back to full capabilities when the STA with lower capabilities + * leaves the IBSS. e.g. when non-CB STA joins an IBSS and then leaves, the IBSS will be stuck at non-CB mode + * even though all the nodes are capable of doing CB. + * so it is decided to leave the self HT capabilties intact. This may change if some issues are found in interop. + */ + qdf_mem_zero((void *)&mlmStartReq, sizeof(mlmStartReq)); + + qdf_mem_copy(mlmStartReq.bssId, pHdr->bssId, sizeof(tSirMacAddr)); + mlmStartReq.rateSet.numRates = + psessionEntry->pLimStartBssReq->operationalRateSet.numRates; + qdf_mem_copy(&mlmStartReq.rateSet.rate[0], + &psessionEntry->pLimStartBssReq->operationalRateSet. + rate[0], mlmStartReq.rateSet.numRates); + mlmStartReq.bssType = eSIR_IBSS_MODE; + mlmStartReq.beaconPeriod = pBeacon->beaconInterval; + mlmStartReq.nwType = psessionEntry->pLimStartBssReq->nwType; /* psessionEntry->nwType is also OK???? */ + mlmStartReq.htCapable = psessionEntry->htCapability; + mlmStartReq.htOperMode = pMac->lim.gHTOperMode; + mlmStartReq.dualCTSProtection = pMac->lim.gHTDualCTSProtection; + mlmStartReq.txChannelWidthSet = psessionEntry->htRecommendedTxWidthSet; + + /* reading the channel num from session Table */ + mlmStartReq.channelNumber = psessionEntry->currentOperChannel; + + mlmStartReq.cbMode = psessionEntry->pLimStartBssReq->cbMode; + + /* Copy the SSID for RxP filtering based on SSID. */ + qdf_mem_copy((uint8_t *) &mlmStartReq.ssId, + (uint8_t *) &psessionEntry->pLimStartBssReq->ssId, + psessionEntry->pLimStartBssReq->ssId.length + 1); + + pe_debug("invoking ADD_BSS as part of coalescing!"); + if (lim_mlm_add_bss(pMac, &mlmStartReq, psessionEntry) != + eSIR_SME_SUCCESS) { + pe_err("AddBss failure"); + return; + } + /* Update fields in Beacon */ + if (sch_set_fixed_beacon_fields(pMac, psessionEntry) != QDF_STATUS_SUCCESS) { + pe_err("Unable to set fixed Beacon fields"); + return; + } + +} + +/* delete the current BSS */ +static void ibss_bss_delete(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + QDF_STATUS status; + + pe_debug("Initiating IBSS Delete BSS"); + if (psessionEntry->limMlmState != eLIM_MLM_BSS_STARTED_STATE) { + pe_warn("Incorrect LIM MLM state for delBss: %d", + psessionEntry->limMlmState); + return; + } + status = lim_del_bss(pMac, NULL, psessionEntry->bssIdx, psessionEntry); + if (status != QDF_STATUS_SUCCESS) + pe_err("delBss failed for bss: %d", + psessionEntry->bssIdx); +} + +/** + * lim_ibss_init + * + ***FUNCTION: + * This function is called while starting an IBSS + * to initialize list used to maintain IBSS peers. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_ibss_init(tpAniSirGlobal pMac) +{ + pMac->lim.gLimIbssCoalescingHappened = 0; + pMac->lim.gLimIbssPeerList = NULL; + pMac->lim.gLimNumIbssPeers = 0; + + /* ibss info - params for which ibss to join while coalescing */ + qdf_mem_zero(&pMac->lim.ibssInfo, sizeof(tAniSirLimIbss)); +} /*** end lim_ibss_init() ***/ + +/** + * lim_ibss_delete_all_peers + * + ***FUNCTION: + * This function is called to delete all peers. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +static void lim_ibss_delete_all_peers(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tLimIbssPeerNode *pCurrNode, *pTempNode; + tpDphHashNode pStaDs; + uint16_t peerIdx; + + pCurrNode = pTempNode = pMac->lim.gLimIbssPeerList; + + while (pCurrNode != NULL) { + if (!pMac->lim.gLimNumIbssPeers) { + pe_err("Number of peers in the list is zero and node present"); + return; + } + /* Delete the dph entry for the station + * Since it is called to remove all peers, just delete from dph, + * no need to do any beacon related params i.e., dont call lim_delete_dph_hash_entry + */ + pStaDs = + dph_lookup_hash_entry(pMac, pCurrNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs) { + + ibss_status_chg_notify(pMac, pCurrNode->peerMacAddr, + pStaDs->staIndex, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + psessionEntry->smeSessionId); + lim_release_peer_idx(pMac, peerIdx, psessionEntry); + dph_delete_hash_entry(pMac, pStaDs->staAddr, peerIdx, + &psessionEntry->dph.dphHashTable); + } + + pTempNode = pCurrNode->next; + + /* TODO :Sessionize this code */ + /* Fix CR 227642: PeerList should point to the next node since the current node is being + * freed in the next line. In ibss_peerfind in ibss_status_chg_notify above, we use this + * peer list to find the next peer. So this list needs to be updated with the no of peers left + * after each iteration in this while loop since one by one peers are deleted (freed) in this + * loop causing the lim.gLimIbssPeerList to point to some freed memory. + */ + pMac->lim.gLimIbssPeerList = pTempNode; + + if (pCurrNode->beacon) { + qdf_mem_free(pCurrNode->beacon); + } + qdf_mem_free(pCurrNode); + if (pMac->lim.gLimNumIbssPeers > 0) /* be paranoid */ + pMac->lim.gLimNumIbssPeers--; + pCurrNode = pTempNode; + } + + if (pMac->lim.gLimNumIbssPeers) + pe_err("Number of peers: %d in the list is non-zero", + pMac->lim.gLimNumIbssPeers); + + pMac->lim.gLimNumIbssPeers = 0; + pMac->lim.gLimIbssPeerList = NULL; + +} + +/** + * lim_ibss_delete() - This function is called while tearing down an IBSS + * + * @pMac: Pointer to Global MAC structure + * @psessionEntry: Pointer to session entry + * + * Return: none + */ + +void lim_ibss_delete(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + lim_ibss_delete_all_peers(pMac, psessionEntry); + ibss_coalesce_free(pMac); +} + +/** ------------------------------------------------------------- + \fn lim_ibss_set_protection + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_set_protection(tpAniSirGlobal pMac, uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + if (!pMac->lim.cfgProtection.fromllb) { + pe_err("protection from 11b is disabled"); + return; + } + + if (enable) { + psessionEntry->gLim11bParams.protectionEnabled = true; + if (false == + psessionEntry->beaconParams. + llbCoexist /*pMac->lim.llbCoexist */) { + pe_debug("=> IBSS: Enable Protection"); + pBeaconParams->llbCoexist = + psessionEntry->beaconParams.llbCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } + } else if (true == + psessionEntry->beaconParams. + llbCoexist /*pMac->lim.llbCoexist */) { + psessionEntry->gLim11bParams.protectionEnabled = false; + pe_debug("===> IBSS: Disable protection"); + pBeaconParams->llbCoexist = + psessionEntry->beaconParams.llbCoexist = false; + pBeaconParams->paramChangeBitmap |= PARAM_llBCOEXIST_CHANGED; + } + return; +} + +/** ------------------------------------------------------------- + \fn lim_ibss_update_protection_params + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_update_protection_params(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tLimProtStaCacheType protStaCacheType, + tpPESession psessionEntry) +{ + uint32_t i; + + pe_debug("STA is associated Addr :"); + lim_print_mac_addr(pMac, peerMacAddr, LOGD); + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (pMac->lim.protStaCache[i].active) { + pe_debug("Addr:"); + lim_print_mac_addr + (pMac, pMac->lim.protStaCache[i].addr, LOGD); + + if (!qdf_mem_cmp(pMac->lim.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 (!pMac->lim.protStaCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + pe_err("No space in ProtStaCache"); + return; + } + + qdf_mem_copy(pMac->lim.protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr)); + + pMac->lim.protStaCache[i].protStaCacheType = protStaCacheType; + pMac->lim.protStaCache[i].active = true; + if (eLIM_PROT_STA_CACHE_TYPE_llB == protStaCacheType) { + psessionEntry->gLim11bParams.numSta++; + } else if (eLIM_PROT_STA_CACHE_TYPE_llG == protStaCacheType) { + psessionEntry->gLim11gParams.numSta++; + } +} + +/** ------------------------------------------------------------- + \fn lim_ibss_decide_protection + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_decide_protection(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + enum band_info rfBand = BAND_UNKNOWN; + uint32_t phyMode; + tLimProtStaCacheType protStaCacheType = + eLIM_PROT_STA_CACHE_TYPE_INVALID; + + pBeaconParams->paramChangeBitmap = 0; + + if (NULL == pStaDs) { + pe_err("pStaDs is NULL"); + return; + } + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (BAND_2G == rfBand) { + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* We are 11G or 11n. Check if we need protection from 11b Stations. */ + if ((phyMode == WNI_CFG_PHY_MODE_11G) + || (psessionEntry->htCapability)) { + /* As we found in the past, it is possible that a 11n STA sends + * Beacon with HT IE but not ERP IE. So the absence of ERP IE + * in the Beacon is not enough to conclude that STA is 11b. + */ + if ((pStaDs->erpEnabled == eHAL_CLEAR) && + (!pStaDs->mlmStaContext.htCapability)) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + pe_err("Enable protection from 11B"); + lim_ibss_set_protection(pMac, true, + pBeaconParams, + psessionEntry); + } + } + } + lim_ibss_update_protection_params(pMac, pStaDs->staAddr, protStaCacheType, + psessionEntry); + return; +} + +/** + * lim_ibss_peer_find() + * + ***FUNCTION: + * This function is called while adding a context at + * DPH & Polaris for a peer in IBSS. + * If peer is found in the list, capabilities from the + * returned BSS description are used at DPH node & Polaris. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the peer + * + * @return Pointer to peer node if found, else NULL + */ +tLimIbssPeerNode *lim_ibss_peer_find(tpAniSirGlobal pMac, tSirMacAddr macAddr) +{ + return ibss_peer_find(pMac, macAddr); +} + +/** + * lim_ibss_sta_add() + * + ***FUNCTION: + * This function is called to add an STA context in IBSS role + * whenever a data frame is received from/for a STA that failed + * hash lookup at DPH. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param peerAdddr MAC address of the peer being added + * @return retCode Indicates success or failure return code + * @return + */ + +QDF_STATUS +lim_ibss_sta_add(tpAniSirGlobal pMac, void *pBody, tpPESession psessionEntry) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + tpDphHashNode pStaDs; + tLimIbssPeerNode *pPeerNode; + tLimMlmStates prevState; + tSirMacAddr *pPeerAddr = (tSirMacAddr *) pBody; + tUpdateBeaconParams beaconParams; + + qdf_mem_zero((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams)); + + if (pBody == 0) { + pe_err("Invalid IBSS AddSta"); + return QDF_STATUS_E_FAILURE; + } + + pe_debug("Rx Add-Ibss-Sta for MAC:"); + lim_print_mac_addr(pMac, *pPeerAddr, LOGD); + + pPeerNode = ibss_peer_find(pMac, *pPeerAddr); + if (NULL != pPeerNode) { + retCode = + ibss_dph_entry_add(pMac, *pPeerAddr, &pStaDs, + psessionEntry); + if (QDF_STATUS_SUCCESS == retCode) { + prevState = pStaDs->mlmStaContext.mlmState; + pStaDs->erpEnabled = pPeerNode->erpIePresent; + + ibss_sta_info_update(pMac, pStaDs, pPeerNode, + psessionEntry); + pe_debug("initiating ADD STA for the IBSS peer"); + retCode = + lim_add_sta(pMac, pStaDs, false, psessionEntry); + if (retCode != QDF_STATUS_SUCCESS) { + pe_err("ibss-sta-add failed (reason %x)", + retCode); + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + pStaDs->mlmStaContext.mlmState = prevState; + dph_delete_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, + &psessionEntry->dph. + dphHashTable); + } else { + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_ibss_decide_protection(pMac, pStaDs, + &beaconParams, + psessionEntry); + + if (beaconParams.paramChangeBitmap) { + pe_debug("---> Update Beacon Params"); + sch_set_fixed_beacon_fields(pMac, + psessionEntry); + beaconParams.bssIdx = + psessionEntry->bssIdx; + lim_send_beacon_params(pMac, &beaconParams, + psessionEntry); + } + } + } else { + pe_err("hashTblAdd failed reason: %x", retCode); + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + } + } else { + retCode = QDF_STATUS_E_FAILURE; + } + + return retCode; +} + +/** + * lim_ibss_search_and_delete_peer()- to cleanup the IBSS + * peer from lim ibss peer list + * + * @mac_ptr: Pointer to Global MAC structure + * @session_entry: Session entry + * @mac_addr: Mac Address of the IBSS peer + * + * This function is called to cleanup the IBSS peer from + * lim ibss peer list + * + * Return: None + * + */ +static void +lim_ibss_search_and_delete_peer(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirMacAddr mac_addr) +{ + tLimIbssPeerNode *temp_node, *prev_node; + tLimIbssPeerNode *temp_next_node = NULL; + + prev_node = temp_node = mac_ctx->lim.gLimIbssPeerList; + + pe_debug(" PEER ADDR :" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac_addr)); + + /** Compare Peer */ + while (NULL != temp_node) { + temp_next_node = temp_node->next; + + /* Delete the STA with MAC address */ + if (!qdf_mem_cmp((uint8_t *) mac_addr, + (uint8_t *) &temp_node->peerMacAddr, + sizeof(tSirMacAddr))) { + if (temp_node == + mac_ctx->lim.gLimIbssPeerList) { + mac_ctx->lim.gLimIbssPeerList = + temp_node->next; + prev_node = + mac_ctx->lim.gLimIbssPeerList; + } else + prev_node->next = temp_node->next; + if (temp_node->beacon) + qdf_mem_free(temp_node->beacon); + + qdf_mem_free(temp_node); + mac_ctx->lim.gLimNumIbssPeers--; + + temp_node = temp_next_node; + break; + } + prev_node = temp_node; + temp_node = temp_next_node; + } + /* + * if it is the last peer walking out, we better + * we set IBSS state to inactive. + */ + if (0 == mac_ctx->lim.gLimNumIbssPeers) { + pe_debug("Last STA from IBSS walked out"); + session_entry->limIbssActive = false; + } +} + +/** + * lim_ibss_delete_peer()- to delete IBSS peer + * + * @mac_ptr: Pointer to Global MAC structure + * @session_entry: Session entry + * @mac_addr: Mac Address of the IBSS peer + * + * This function is called delete IBSS peer. + * + * Return: None + * + */ +static void +lim_ibss_delete_peer(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirMacAddr mac_addr) +{ + tpDphHashNode sta = NULL; + uint16_t peer_idx = 0; + + pe_debug("Delete peer :" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac_addr)); + + sta = dph_lookup_hash_entry(mac_ctx, mac_addr, + &peer_idx, + &session_entry->dph. + dphHashTable); + + if (!sta) { + pe_err("DPH Entry for STA %pM is missing", + mac_addr); + return; + } + + if (STA_INVALID_IDX != sta->staIndex) { + lim_del_sta(mac_ctx, sta, + true, session_entry); + } else { + /* + * This mean ADD STA failed, thus remove the sta from + * from database and no need to send del sta to firmware + * and peer departed indication to upper layer. + */ + lim_delete_dph_hash_entry(mac_ctx, sta->staAddr, + peer_idx, session_entry); + lim_release_peer_idx(mac_ctx, + peer_idx, session_entry); + lim_ibss_search_and_delete_peer(mac_ctx, + session_entry, mac_addr); + } + +} + +void lim_process_ibss_del_sta_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg, + tpPESession pe_session) +{ + tpDphHashNode sta_ds = NULL; + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) lim_msg->bodyptr; + tSirResultCodes status = eSIR_SME_SUCCESS; + + if (!del_sta_params) { + pe_err("del_sta_params is NULL"); + return; + } + if (!LIM_IS_IBSS_ROLE(pe_session)) { + pe_err("Session %d is not IBSS role", del_sta_params->assocId); + status = eSIR_SME_REFUSED; + 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); + status = eSIR_SME_REFUSED; + goto skip_event; + } + + if (QDF_STATUS_SUCCESS != del_sta_params->status) { + pe_err("DEL STA failed!"); + status = eSIR_SME_REFUSED; + goto skip_event; + } + pe_debug("Deleted STA associd %d staId %d MAC " MAC_ADDRESS_STR, + sta_ds->assocId, sta_ds->staIndex, + MAC_ADDR_ARRAY(sta_ds->staAddr)); + + lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, + del_sta_params->assocId, pe_session); + lim_release_peer_idx(mac_ctx, + del_sta_params->assocId, pe_session); + + ibss_status_chg_notify(mac_ctx, + del_sta_params->staMac, + sta_ds->staIndex, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + pe_session->smeSessionId); + + lim_ibss_search_and_delete_peer(mac_ctx, + pe_session, del_sta_params->staMac); + +skip_event: + qdf_mem_free(del_sta_params); + lim_msg->bodyptr = NULL; +} + +/* handle the response from HAL for an ADD STA request */ +QDF_STATUS +lim_ibss_add_sta_rsp(tpAniSirGlobal pMac, void *msg, tpPESession psessionEntry) +{ + tpDphHashNode pStaDs; + uint16_t peerIdx; + tpAddStaParams pAddStaParams = (tpAddStaParams) msg; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (pAddStaParams == NULL) { + pe_err("IBSS: ADD_STA_RSP with no body!"); + return QDF_STATUS_E_FAILURE; + } + + pStaDs = + dph_lookup_hash_entry(pMac, pAddStaParams->staMac, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + pe_err("IBSS: ADD_STA_RSP for unknown MAC addr: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pAddStaParams->staMac)); + qdf_mem_free(pAddStaParams); + return QDF_STATUS_E_FAILURE; + } + + if (pAddStaParams->status != QDF_STATUS_SUCCESS) { + pe_err("IBSS: ADD_STA_RSP error: %x for MAC:"MAC_ADDRESS_STR, + pAddStaParams->status, + MAC_ADDR_ARRAY(pAddStaParams->staMac)); + lim_ibss_delete_peer(pMac, + psessionEntry, pAddStaParams->staMac); + qdf_mem_free(pAddStaParams); + return QDF_STATUS_E_FAILURE; + } + + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->valid = 1; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + + pe_debug("IBSS: sending IBSS_NEW_PEER msg to SME!"); + + ibss_status_chg_notify(pMac, pAddStaParams->staMac, + pStaDs->staIndex, + eWNI_SME_IBSS_NEW_PEER_IND, + psessionEntry->smeSessionId); + + qdf_mem_free(pAddStaParams); + + return QDF_STATUS_SUCCESS; +} + +void lim_ibss_del_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBss = (tpDeleteBssParams) msg; + + pe_debug("IBSS: DEL_BSS_RSP Rcvd during coalescing!"); + + if (pDelBss == NULL) { + pe_err("IBSS: DEL_BSS_RSP(coalesce) with no body!"); + goto end; + } + + if (pDelBss->status != QDF_STATUS_SUCCESS) { + pe_err("IBSS: DEL_BSS_RSP(coalesce) error: %x Bss: %d", + pDelBss->status, pDelBss->bssIdx); + goto end; + } + /* Delete peer entries. */ + lim_ibss_delete_all_peers(pMac, psessionEntry); + + /* add the new bss */ + ibss_bss_add(pMac, psessionEntry); + +end: + if (pDelBss != NULL) + qdf_mem_free(pDelBss); +} + +void lim_ibss_add_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession pSessionEntry) +{ + uint8_t infoLen; + tSirSmeNewBssInfo newBssInfo; + + tpAddBssParams pAddBss = (tpAddBssParams) msg; + + tpSirMacMgmtHdr pHdr = (tpSirMacMgmtHdr) pMac->lim.ibssInfo.pHdr; + tpSchBeaconStruct pBeacon = + (tpSchBeaconStruct) pMac->lim.ibssInfo.pBeacon; + + if ((pHdr == NULL) || (pBeacon == NULL)) { + pe_err("Unable to handle AddBssRspWhenCoalescing (no cached BSS info)"); + goto end; + } + /* Inform Host of IBSS coalescing */ + infoLen = sizeof(tSirMacAddr) + sizeof(tSirMacChanNum) + + sizeof(uint8_t) + pBeacon->ssId.length + 1; + + qdf_mem_zero((void *)&newBssInfo, sizeof(newBssInfo)); + qdf_mem_copy(newBssInfo.bssId.bytes, pHdr->bssId, QDF_MAC_ADDR_SIZE); + newBssInfo.channelNumber = (tSirMacChanNum) pAddBss->currentOperChannel; + qdf_mem_copy((uint8_t *) &newBssInfo.ssId, + (uint8_t *) &pBeacon->ssId, pBeacon->ssId.length + 1); + + pe_debug("Sending JOINED_NEW_BSS notification to SME"); + + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_JOINED_NEW_BSS, + (uint32_t *) &newBssInfo, + infoLen, pSessionEntry->smeSessionId); + { + /* Configure beacon and send beacons to HAL */ + lim_send_beacon_ind(pMac, pSessionEntry, REASON_DEFAULT); + } + +end: + ibss_coalesce_free(pMac); +} + +void lim_ibss_del_bss_rsp(tpAniSirGlobal pMac, void *msg, tpPESession psessionEntry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) msg; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (pDelBss == NULL) { + pe_err("IBSS: DEL_BSS_RSP with no body!"); + rc = eSIR_SME_REFUSED; + goto end; + } + + psessionEntry = pe_find_session_by_session_id(pMac, pDelBss->sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + goto end; + } + + /* + * If delBss was issued as part of IBSS Coalescing, gLimIbssCoalescingHappened flag will be true. + * BSS has to be added again in this scenario, so this case needs to be handled separately. + * If delBss was issued as a result of trigger from SME_STOP_BSS Request, then limSme state changes to + * 'IDLE' and gLimIbssCoalescingHappened flag will be false. In this case STOP BSS RSP has to be sent to SME. + */ + if (true == pMac->lim.gLimIbssCoalescingHappened) { + + lim_ibss_del_bss_rsp_when_coalescing(pMac, msg, psessionEntry); + return; + } + + if (pDelBss->status != QDF_STATUS_SUCCESS) { + pe_err("IBSS: DEL_BSS_RSP error: %x Bss: %d", + pDelBss->status, pDelBss->bssIdx); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + + if (lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + psessionEntry->selfMacAddr, NULL, + NULL) != QDF_STATUS_SUCCESS) { + pe_err("IBSS: DEL_BSS_RSP setLinkState failed"); + rc = eSIR_SME_REFUSED; + goto end; + } + + lim_ibss_delete(pMac, psessionEntry); + + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + psessionEntry->limSystemRole = eLIM_STA_ROLE; + + /* Change the short slot operating mode to Default (which is 1 for now) so that when IBSS starts next time with Libra + * as originator, it picks up the default. This enables us to remove hard coding of short slot = 1 from lim_apply_configuration + */ + psessionEntry->shortSlotTimeSupported = WNI_CFG_SHORT_SLOT_TIME_STADEF; + +end: + if (pDelBss != NULL) + qdf_mem_free(pDelBss); + /* Delete PE session once BSS is deleted */ + if (NULL != psessionEntry) { + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, rc, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } +} + +/** + * lim_ibss_coalesce() + * + ***FUNCTION: + * This function is called upon receiving Beacon/Probe Response + * while operating in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pBD - Pointer to received BD + * + * @return Status whether to process or ignore received Beacon Frame + */ + +QDF_STATUS +lim_ibss_coalesce(tpAniSirGlobal pMac, + tpSirMacMgmtHdr pHdr, + tpSchBeaconStruct pBeacon, + uint8_t *pIEs, + uint32_t ieLen, uint16_t fTsfLater, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tSirMacAddr currentBssId; + tLimIbssPeerNode *pPeerNode; + tpDphHashNode pStaDs; + tUpdateBeaconParams beaconParams; + + qdf_mem_zero((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams)); + + sir_copy_mac_addr(currentBssId, psessionEntry->bssId); + + pe_debug("Current BSSID :" MAC_ADDRESS_STR " Received BSSID :" + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(currentBssId), + MAC_ADDR_ARRAY(pHdr->bssId)); + + /* Check for IBSS Coalescing only if Beacon is from different BSS */ + if (qdf_mem_cmp(currentBssId, pHdr->bssId, sizeof(tSirMacAddr)) + && psessionEntry->isCoalesingInIBSSAllowed) { + /* + * If STA entry is already available in the LIM hash table, then it is + * possible that the peer may have left and rejoined within the heartbeat + * timeout. In the offloaded case with 32 peers, the HB timeout is whopping + * 128 seconds. In that case, the FW will not let any frames come in until + * atleast the last sequence number is received before the peer is left + * Hence, if the coalescing peer is already there in the peer list and if + * the BSSID matches then, invoke delSta() to cleanup the entries. We will + * let the peer coalesce when we receive next beacon from the peer + */ + pPeerNode = ibss_peer_find(pMac, pHdr->sa); + if (NULL != pPeerNode) { + lim_ibss_delete_peer(pMac, psessionEntry, + pHdr->sa); + pe_warn("Peer attempting to reconnect before HB timeout, deleted"); + return QDF_STATUS_E_INVAL; + } + + if (!fTsfLater) { /* No Coalescing happened. */ + pe_warn("No Coalescing happened"); + return QDF_STATUS_E_INVAL; + } + /* + * IBSS Coalescing happened. + * save the received beacon, and delete the current BSS. The rest of the + * processing will be done in the delBss response processing + */ + pMac->lim.gLimIbssCoalescingHappened = true; + ibss_coalesce_save(pMac, pHdr, pBeacon); + pe_debug("IBSS Coalescing happened Delete BSSID :" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(currentBssId)); + ibss_bss_delete(pMac, psessionEntry); + return QDF_STATUS_SUCCESS; + } else { + if (qdf_mem_cmp + (currentBssId, pHdr->bssId, sizeof(tSirMacAddr))) + return QDF_STATUS_E_INVAL; + } + + /* STA in IBSS mode and SSID matches with ours */ + pPeerNode = ibss_peer_find(pMac, pHdr->sa); + if (pPeerNode == NULL) { + /* Peer not in the list - Collect BSS description & add to the list */ + uint32_t frameLen; + QDF_STATUS retCode; + + /* + * Limit the Max number of IBSS Peers allowed as the max + * number of STA's allowed + * pMac->lim.gLimNumIbssPeers will be increamented after exiting + * this function. so we will add additional 1 to compare against + * pMac->lim.gLimIbssStaLimit + */ + if ((pMac->lim.gLimNumIbssPeers + 1) >= + pMac->lim.gLimIbssStaLimit) { + /*Print every 100th time */ + if (pMac->lim.ibss_retry_cnt % 100 == 0) { + pe_debug("**** MAX STA LIMIT HAS REACHED ****"); + } + pMac->lim.ibss_retry_cnt++; + return QDF_STATUS_E_NOSPC; + } + pe_debug("IBSS Peer node does not exist, adding it"); + frameLen = + sizeof(tLimIbssPeerNode) + ieLen - sizeof(uint32_t); + + pPeerNode = qdf_mem_malloc((uint16_t) frameLen); + if (NULL == pPeerNode) { + pe_err("alloc fail %d bytes storing IBSS peer info", + frameLen); + return QDF_STATUS_E_NOMEM; + } + + pPeerNode->beacon = NULL; + pPeerNode->beaconLen = 0; + + ibss_peer_collect(pMac, pBeacon, pHdr, pPeerNode, + psessionEntry); + pPeerNode->beacon = qdf_mem_malloc(ieLen); + if (NULL == pPeerNode->beacon) { + pe_err("Unable to allocate memory to store beacon"); + } else { + qdf_mem_copy(pPeerNode->beacon, pIEs, ieLen); + pPeerNode->beaconLen = (uint16_t) ieLen; + } + ibss_peer_add(pMac, pPeerNode); + + pStaDs = + dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* / DPH node already exists for the peer */ + pe_warn("DPH Node present for just learned peer"); + lim_print_mac_addr(pMac, pPeerNode->peerMacAddr, LOGD); + ibss_sta_info_update(pMac, pStaDs, pPeerNode, + psessionEntry); + return QDF_STATUS_SUCCESS; + } + retCode = + lim_ibss_sta_add(pMac, pPeerNode->peerMacAddr, psessionEntry); + if (retCode != QDF_STATUS_SUCCESS) { + pe_err("lim-ibss-sta-add failed reason: %x", retCode); + lim_print_mac_addr(pMac, pPeerNode->peerMacAddr, LOGE); + return retCode; + } + /* Decide protection mode */ + pStaDs = + dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_ibss_decide_protection(pMac, pStaDs, &beaconParams, + psessionEntry); + + if (beaconParams.paramChangeBitmap) { + pe_err("beaconParams.paramChangeBitmap=1 ---> Update Beacon Params"); + sch_set_fixed_beacon_fields(pMac, psessionEntry); + beaconParams.bssIdx = psessionEntry->bssIdx; + lim_send_beacon_params(pMac, &beaconParams, psessionEntry); + } + } else + ibss_sta_caps_update(pMac, pPeerNode, psessionEntry); + + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE) + return QDF_STATUS_SUCCESS; + + /* Received Beacon from same IBSS we're */ + /* currently part of. Inform Roaming algorithm */ + /* if not already that IBSS is active. */ + if (psessionEntry->limIbssActive == false) { + limResetHBPktCount(psessionEntry); + pe_warn("Partner joined our IBSS, Sending IBSS_ACTIVE Notification to SME"); + psessionEntry->limIbssActive = true; + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_IBSS_ACTIVE, NULL, 0, + psessionEntry->smeSessionId); + } + + return QDF_STATUS_SUCCESS; +} /*** end lim_handle_ibs_scoalescing() ***/ + +/** + * lim_ibss_heart_beat_handle() - handle IBSS hearbeat failure + * + * @mac_ctx: global mac context + * @session: PE session entry + * + * Hanlde IBSS hearbeat failure. + * + * Return: None. + */ +void lim_ibss_heart_beat_handle(tpAniSirGlobal mac_ctx, tpPESession session) +{ + tLimIbssPeerNode *tempnode, *prevnode; + tLimIbssPeerNode *temp_next = NULL; + uint16_t peer_idx = 0; + tpDphHashNode stads = 0; + uint32_t threshold = 0; + uint16_t sta_idx = 0; + + /* + * MLM BSS is started and if PE in scanmode then MLM state will be + * waiting for probe resp. If Heart beat timeout triggers during this + * corner case then we need to reactivate HeartBeat timer. + */ + if (session->limMlmState != eLIM_MLM_BSS_STARTED_STATE) + return; + + /* If LinkMonitor is Disabled */ + if (!mac_ctx->sys.gSysEnableLinkMonitorMode) + return; + + prevnode = tempnode = mac_ctx->lim.gLimIbssPeerList; + threshold = (mac_ctx->lim.gLimNumIbssPeers / 4) + 1; + + /* Monitor the HeartBeat with the Individual PEERS in the IBSS */ + while (tempnode != NULL) { + temp_next = tempnode->next; + if (tempnode->beaconHBCount) { + /* There was a beacon for this peer during heart beat */ + tempnode->beaconHBCount = 0; + tempnode->heartbeatFailure = 0; + prevnode = tempnode; + tempnode = temp_next; + continue; + } + + /* There wasnt any beacon received during heartbeat timer. */ + tempnode->heartbeatFailure++; + pe_err("Heartbeat fail: %d thres: %d", + tempnode->heartbeatFailure, mac_ctx->lim.gLimNumIbssPeers); + if (tempnode->heartbeatFailure >= threshold) { + /* Remove this entry from the list. */ + stads = dph_lookup_hash_entry(mac_ctx, + tempnode->peerMacAddr, &peer_idx, + &session->dph.dphHashTable); + if (stads) { + sta_idx = stads->staIndex; + + (void)lim_del_sta(mac_ctx, stads, false, + session); + lim_delete_dph_hash_entry(mac_ctx, + stads->staAddr, peer_idx, session); + lim_release_peer_idx(mac_ctx, peer_idx, + session); + /* Send indication. */ + ibss_status_chg_notify(mac_ctx, + tempnode->peerMacAddr, sta_idx, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + session->smeSessionId); + } + if (tempnode == mac_ctx->lim.gLimIbssPeerList) { + mac_ctx->lim.gLimIbssPeerList = tempnode->next; + prevnode = mac_ctx->lim.gLimIbssPeerList; + } else { + prevnode->next = tempnode->next; + } + + if (tempnode->beacon) + qdf_mem_free(tempnode->beacon); + qdf_mem_free(tempnode); + mac_ctx->lim.gLimNumIbssPeers--; + + /* we deleted current node, so prevNode remains same. */ + tempnode = temp_next; + continue; + } + prevnode = tempnode; + tempnode = temp_next; + } + + /* + * General IBSS Activity Monitor, + * check if in IBSS Mode we are received any Beacons + */ + if (mac_ctx->lim.gLimNumIbssPeers) { + if (session->LimRxedBeaconCntDuringHB < + MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL) + mac_ctx->lim.gLimHeartBeatBeaconStats[ + session->LimRxedBeaconCntDuringHB]++; + else + mac_ctx->lim.gLimHeartBeatBeaconStats[0]++; + + /* Reset number of beacons received */ + limResetHBPktCount(session); + return; + } else { + pe_warn("Heartbeat Failure"); + mac_ctx->lim.gLimHBfailureCntInLinkEstState++; + + if (session->limIbssActive == true) { + /* + * We don't receive Beacon frames from any + * other STA in IBSS. Announce IBSS inactive + * to Roaming algorithm + */ + pe_warn("Alone in IBSS"); + session->limIbssActive = false; + + lim_send_sme_wm_status_change_ntf(mac_ctx, + eSIR_SME_IBSS_INACTIVE, NULL, 0, + session->smeSessionId); + } + } +} + +/** + * lim_ibss_decide_protection_on_delete() - decides protection related info. + * + * @mac_ctx: global mac context + * @stads: station hash node + * @bcn_param: beacon parameters + * @session: PE session entry + * + * Decides all the protection related information. + * + * Return: None + */ +void lim_ibss_decide_protection_on_delete(tpAniSirGlobal mac_ctx, + tpDphHashNode stads, + tpUpdateBeaconParams bcn_param, + tpPESession session) +{ + uint32_t phymode; + tHalBitVal erpenabled = eHAL_CLEAR; + enum band_info rfband = BAND_UNKNOWN; + uint32_t i; + + if (NULL == stads) + return; + + lim_get_rf_band_new(mac_ctx, &rfband, session); + if (BAND_2G != rfband) + return; + + lim_get_phy_mode(mac_ctx, &phymode, session); + erpenabled = stads->erpEnabled; + /* we are HT or 11G and 11B station is getting deleted. */ + if (((phymode == WNI_CFG_PHY_MODE_11G) || + session->htCapability) && (erpenabled == eHAL_CLEAR)) { + pe_err("%d A legacy STA is disassociated Addr is", + session->gLim11bParams.numSta); + lim_print_mac_addr(mac_ctx, stads->staAddr, LOGE); + if (session->gLim11bParams.numSta == 0) { + pe_err("No 11B STA exists. Disable protection"); + lim_ibss_set_protection(mac_ctx, false, + bcn_param, session); + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!mac_ctx->lim.protStaCache[i].active) + continue; + if (!qdf_mem_cmp(mac_ctx->lim.protStaCache[i].addr, + stads->staAddr, sizeof(tSirMacAddr))) { + session->gLim11bParams.numSta--; + mac_ctx->lim.protStaCache[i].active = false; + break; + } + } + + } +} + +/** ----------------------------------------------------------------- + \fn __lim_ibss_peer_inactivity_handler + \brief Internal function. Deletes FW indicated peer which is inactive + \ + \param tpAniSirGlobal pMac + \param tpPESession psessionEntry + \param tpSirIbssPeerInactivityInd peerInactivityInd + \return None + -----------------------------------------------------------------*/ +static void +__lim_ibss_peer_inactivity_handler(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSirIbssPeerInactivityInd peerInactivityInd) +{ + if (psessionEntry->limMlmState != eLIM_MLM_BSS_STARTED_STATE) { + return; + } + + /* delete the peer for which heartbeat is observed */ + lim_ibss_delete_peer(pMac, psessionEntry, + peerInactivityInd->peer_addr.bytes); +} + +/** ------------------------------------------------------------- + \fn lim_process_ibss_peer_inactivity + \brief Peer inactivity message handler + \ + \param tpAniSirGlobal pMac + \param void* buf + \return None + -------------------------------------------------------------*/ +void lim_process_ibss_peer_inactivity(tpAniSirGlobal pMac, void *buf) +{ + /* + * --------------- HEARTBEAT OFFLOAD CASE ------------------ + * This message handler is executed when the firmware identifies + * inactivity from one or more peer devices. We will come here + * for every inactive peer device + */ + uint8_t i; + + tSirIbssPeerInactivityInd *peerInactivityInd = + (tSirIbssPeerInactivityInd *) buf; + + /* + * If IBSS is not started or heartbeat offload is not enabled + * we should not handle this request + */ + if (eLIM_STA_IN_IBSS_ROLE != pMac->lim.gLimSystemRole && + !IS_IBSS_HEARTBEAT_OFFLOAD_FEATURE_ENABLE) { + return; + } + + /** If LinkMonitor is Disabled */ + if (!pMac->sys.gSysEnableLinkMonitorMode) { + return; + } + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (true == pMac->lim.gpSession[i].valid && + eSIR_IBSS_MODE == pMac->lim.gpSession[i].bssType) { + __lim_ibss_peer_inactivity_handler(pMac, + &pMac->lim.gpSession[i], + peerInactivityInd); + break; + } + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h new file mode 100644 index 0000000000000000000000000000000000000000..bc2ae06295c005fe91597397f831dc01423dfa9e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011-2012, 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 lim_ibss_peer_mgmt.h contains prototypes for + * the utility functions LIM uses to maintain peers in IBSS. + * Author: Chandra Modumudi + * Date: 03/12/04 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "sir_common.h" +#include "lim_utils.h" + +void lim_ibss_init(tpAniSirGlobal); +void lim_ibss_delete(tpAniSirGlobal, tpPESession psessionEntry); +QDF_STATUS lim_ibss_coalesce(tpAniSirGlobal, tpSirMacMgmtHdr, + tpSchBeaconStruct, uint8_t *, uint32_t, uint16_t, + tpPESession); +QDF_STATUS lim_ibss_sta_add(tpAniSirGlobal, void *, tpPESession); +QDF_STATUS lim_ibss_add_sta_rsp(tpAniSirGlobal, void *, tpPESession); + +/** + * lim_process_ibss_del_sta_rsp()- Handle ibss delete + * peer resp from firmware + * + * @mac_ptr: Pointer to Global MAC structure + * @lim_msg: delete sta response + * @pe_session: pe session + * + * Return: None + * + */ +void lim_process_ibss_del_sta_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg, + tpPESession pe_session); +tLimIbssPeerNode *lim_ibss_peer_find(tpAniSirGlobal pMac, tSirMacAddr macAddr); +void lim_ibss_del_bss_rsp(tpAniSirGlobal, void *, tpPESession); +void lim_ibss_del_bss_rsp_when_coalescing(tpAniSirGlobal, void *, tpPESession); +void lim_ibss_add_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession pSessionEntry); +void lim_ibss_decide_protection_on_delete(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession pSessionEntry); +void lim_ibss_heart_beat_handle(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_process_ibss_peer_inactivity(tpAniSirGlobal pMac, void *buf); diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c new file mode 100644 index 0000000000000000000000000000000000000000..b0534fad6f68d19a2ff24e773a5935b75ce16759 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c @@ -0,0 +1,557 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.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" + +/** + * lim_delete_sta_util - utility function for deleting station context + * + * @mac_ctx: global MAC context + * @msg: pointer to delte station context + * @session_entry: PE session entry + * + * utility function called to clear up station context. + * + * Return: None. + */ +static void lim_delete_sta_util(tpAniSirGlobal mac_ctx, tpDeleteStaContext msg, + tpPESession session_entry) +{ + tpDphHashNode stads; + + pe_debug("Deleting station: staId: %d, reasonCode: %d", + msg->staId, msg->reasonCode); + + if (LIM_IS_IBSS_ROLE(session_entry)) { + return; + } + + stads = dph_lookup_assoc_id(mac_ctx, msg->staId, &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; + + /* check and see if same staId. This is to avoid the scenario + * where we're trying to delete a staId we just added. + */ + if (stads->staIndex != msg->staId) { + pe_err("staid mismatch: %d vs %d", stads->staIndex, msg->staId); + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) { + pe_debug("Delete Station staId: %d, assocId: %d", + msg->staId, 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 staId: %d, assocId: %d", + msg->staId, msg->assocId); + return; + } else { + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + 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, + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE); + } else { +#endif + /* TearDownLink with AP */ + tLimMlmDeauthInd mlm_deauth_ind; + + pe_debug("Delete Station (staId: %d, assocId: %d)", + msg->staId, 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 = " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg->bssId)); + return; + } + + stads->mlmStaContext.disassocReason = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg) +{ + tpDeleteStaContext msg = (tpDeleteStaContext) lim_msg->bodyptr; + tpPESession session_entry; + tpDphHashNode sta_ds; + + if (NULL == msg) { + pe_err("Invalid body pointer in message"); + return; + } + session_entry = pe_find_session_by_sme_session_id(mac_ctx, msg->vdev_id); + if (NULL == 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: + if (LIM_IS_STA_ROLE(session_entry) && !msg->is_tdls) { + if (!((session_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (session_entry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (session_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE))) { + pe_err("Do not process in limMlmState %s(%x) limSmeState %s(%x)", + lim_mlm_state_str(session_entry->limMlmState), + session_entry->limMlmState, + lim_sme_state_str(session_entry->limSmeState), + session_entry->limSmeState); + qdf_mem_free(msg); + return; + } + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (NULL == sta_ds) { + pe_err("Dph entry not found"); + qdf_mem_free(msg); + return; + } + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + msg->addr2, session_entry, false); + lim_tear_down_link_with_ap(mac_ctx, + session_entry->peSessionId, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON); + /* 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"); + lim_print_mac_addr(mac_ctx, msg->addr2, LOGE); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON, + msg->addr2, session_entry, false); + break; + + case HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT: + if (session_entry->limMlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) { + pe_err("BTM request received in state %s", + lim_mlm_state_str(session_entry->limMlmState)); + qdf_mem_free(msg); + lim_msg->bodyptr = NULL; + return; + } + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + session_entry->bssId, session_entry, false); + lim_tear_down_link_with_ap(mac_ctx, session_entry->peSessionId, + eSIR_MAC_UNSPEC_FAILURE_REASON); + 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(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpPESession 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 = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + sta_ds->mlmStaContext.cleanupTrigger = eLIM_LINK_MONITORING_DISASSOC; + qdf_mem_copy(&mlm_disassoc_ind.peerMacAddr, sta_ds->staAddr, + sizeof(tSirMacAddr)); + mlm_disassoc_ind.reasonCode = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + 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->roam.configParam.enable_fatal_event) + 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() ***/ + +/** + * lim_tear_down_link_with_ap() + * + ***FUNCTION: + * This function is called when heartbeat (beacon reception) + * fails on STA + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void +lim_tear_down_link_with_ap(tpAniSirGlobal pMac, uint8_t sessionId, + tSirMacReasonCodes reasonCode) +{ + tpDphHashNode pStaDs = NULL; + + /* tear down the following sessionEntry */ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + /** + * Heart beat failed for upto threshold value + * and AP did not respond for Probe request. + * Trigger link tear down. + */ + psessionEntry->pmmOffloadInfo.bcnmiss = false; + + pe_info("No ProbeRsp from AP after HB failure. Tearing down link"); + + /* Announce loss of link to Roaming algorithm */ + /* and cleanup by sending SME_DISASSOC_REQ to SME */ + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + + if (pStaDs != NULL) { + tLimMlmDeauthInd mlmDeauthInd; + +#ifdef FEATURE_WLAN_TDLS + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(pMac, psessionEntry); +#endif + + pStaDs->mlmStaContext.disassocReason = reasonCode; + pStaDs->mlmStaContext.cleanupTrigger = + eLIM_LINK_MONITORING_DEAUTH; + /* / Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + pStaDs->staAddr, sizeof(tSirMacAddr)); + + /* + * if send_deauth_before_con 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 (pMac->roam.configParam.send_deauth_before_con && + eSIR_BEACON_MISSED == reasonCode) { + int apCount = pMac->lim.gLimHeartBeatApMacIndex; + + if (pMac->lim.gLimHeartBeatApMacIndex) + pMac->lim.gLimHeartBeatApMacIndex = 0; + else + pMac->lim.gLimHeartBeatApMacIndex = 1; + + pe_debug("HB Failure on MAC " + MAC_ADDRESS_STR" Store it on Index %d", + MAC_ADDR_ARRAY(pStaDs->staAddr), apCount); + + sir_copy_mac_addr(pMac->lim.gLimHeartBeatApMac[apCount], + pStaDs->staAddr); + } + + mlmDeauthInd.reasonCode = + (uint8_t) pStaDs->mlmStaContext.disassocReason; + mlmDeauthInd.deauthTrigger = + pStaDs->mlmStaContext.cleanupTrigger; + + if (LIM_IS_STA_ROLE(psessionEntry)) + lim_post_sme_message(pMac, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + if (pMac->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HB_FAILURE, + false, false); + + lim_send_sme_deauth_ind(pMac, pStaDs, psessionEntry); + } +} /*** 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(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + uint8_t curr_chan; + tpSirAddie scan_ie = NULL; + +#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 */ + + /* Ensure HB Status for the session has been reseted */ + session->LimHBFailureStatus = false; + + if (LIM_IS_STA_ROLE(session) && + (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + (session->limSmeState != eLIM_SME_WT_DISASSOC_STATE) && + (session->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + 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++; + + /* + * Check if connected on the DFS channel, if not connected on + * DFS channel then only send the probe request otherwise tear + * down the link + */ + curr_chan = session->currentOperChannel; + if (!lim_isconnected_on_dfs_channel(mac_ctx, curr_chan)) { + /* Detected continuous Beacon Misses */ + session->LimHBFailureStatus = true; + + /*Reset the HB packet count before sending probe*/ + limResetHBPktCount(session); + /** + * Send Probe Request frame to AP to see if + * it is still around. Wait until certain + * timeout for Probe Response from AP. + */ + pe_debug("HB missed from AP. Sending Probe Req"); + /* for searching AP, we don't include any more IE */ + if (session->pLimJoinReq != NULL) { + scan_ie = &session->pLimJoinReq->addIEScan; + lim_send_probe_req_mgmt_frame(mac_ctx, + &session->ssId, + session->bssId, curr_chan, + session->selfMacAddr, + session->dot11mode, + &scan_ie->length, scan_ie->addIEdata); + } else { + lim_send_probe_req_mgmt_frame(mac_ctx, + &session->ssId, + session->bssId, curr_chan, + session->selfMacAddr, + session->dot11mode, NULL, NULL); + } + } else { + pe_debug("HB missed from AP on DFS channel"); + /* + * Connected on DFS channel so should not send the + * probe request tear down the link directly + */ + lim_tear_down_link_with_ap(mac_ctx, + session->peSessionId, + eSIR_BEACON_MISSED); + } + } 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); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..6a7f880f0af28704f4e48342e1f202c8da245b74 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c @@ -0,0 +1,2335 @@ +/* + * 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. + */ + +/* + * 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" + +#define BA_DEFAULT_TX_BUFFER_SIZE 64 + +static last_processed_msg rrm_link_action_frm; + +/* Note: The test passes if the STAUT stops sending any frames, and no further + frames are transmitted on this channel by the station when the AP has sent + the last 6 beacons, with the channel switch information elements as seen + with the sniffer.*/ +#define SIR_CHANSW_TX_STOP_MAX_COUNT 6 +/**----------------------------------------------------------------- + \fn lim_stop_tx_and_switch_channel + \brief Stops the transmission if channel switch mode is silent and + starts the channel switch timer. + + \param pMac + \return NONE + -----------------------------------------------------------------*/ +void lim_stop_tx_and_switch_channel(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + + if (NULL == psessionEntry) { + pe_err("Session: %d not active", sessionId); + return; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq) { + pe_debug("Avoid Switch Channel req during pre auth"); + return; + } + + pe_debug("Channel switch Mode: %d", + psessionEntry->gLimChannelSwitch.switchMode); + + if (psessionEntry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT + || psessionEntry->gLimChannelSwitch.switchCount <= + SIR_CHANSW_TX_STOP_MAX_COUNT) { + /* Freeze the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_STOP_TX); + + } else { + /* Resume the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + } + + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId = sessionId; + /* change the channel immediately only if + * the channel switch count is 0 + */ + if (psessionEntry->gLimChannelSwitch.switchCount == 0) { + lim_process_channel_switch_timeout(pMac); + return; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, sessionId, + eLIM_CHANNEL_SWITCH_TIMER)); + + if (tx_timer_activate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + TX_SUCCESS) { + pe_err("tx_timer_activate failed"); + } + return; +} + +/**------------------------------------------------------------ + \fn lim_start_channel_switch + \brief Switches the channel if switch count == 0, otherwise + starts the timer for channel switch and stops BG scan + and heartbeat timer tempororily. + + \param pMac + \param psessionEntry + \return NONE + ------------------------------------------------------------*/ +QDF_STATUS lim_start_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + pe_debug("Starting the channel switch"); + + /*If channel switch is already running and it is on a different session, just return */ + /*This need to be removed for MCC */ + if ((lim_is_chan_switch_running(pMac) && + psessionEntry->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) || psessionEntry->csaOffloadEnable) { + pe_warn("Ignoring channel switch on session: %d", + psessionEntry->peSessionId); + return QDF_STATUS_SUCCESS; + } + + /* Deactivate and change reconfigure the timeout value */ + /* lim_deactivate_and_change_timer(pMac, eLIM_CHANNEL_SWITCH_TIMER); */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, psessionEntry->peSessionId, + eLIM_CHANNEL_SWITCH_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + QDF_STATUS_SUCCESS) { + pe_err("tx_timer_deactivate failed!"); + return QDF_STATUS_E_FAILURE; + } + + if (tx_timer_change(&pMac->lim.limTimers.gLimChannelSwitchTimer, + psessionEntry->gLimChannelSwitch.switchTimeoutValue, + 0) != TX_SUCCESS) { + pe_err("tx_timer_change failed"); + return QDF_STATUS_E_FAILURE; + } + + /* Follow the channel switch, forget about the previous quiet. */ + /* If quiet is running, chance is there to resume tx on its timeout. */ + /* so stop timer for a safer side. */ + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_BEGIN) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer) != + TX_SUCCESS) { + pe_err("tx_timer_deactivate failed"); + return QDF_STATUS_E_FAILURE; + } + } else if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_BSS_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietBssTimer) + != TX_SUCCESS) { + pe_err("tx_timer_deactivate failed"); + return QDF_STATUS_E_FAILURE; + } + } + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* Prepare for 11h channel switch */ + lim_prepare_for11h_channel_switch(pMac, psessionEntry); + + /** Dont add any more statements here as we posted finish scan request + * to HAL, wait till we get the response + */ + return QDF_STATUS_SUCCESS; +} + +/** + * __lim_process_channel_switch_action_frame() - to process channel switch + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * + * This routine will be called to process channel switch action frame + * + * Return: None + */ + +static void __lim_process_channel_switch_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fChannelSwitch *chnl_switch_frame; + uint16_t bcn_period; + uint32_t val, frame_len, status; + tLimChannelSwitchInfo *ch_switch_params; + struct sDot11fIEWiderBWChanSwitchAnn *wbw_chnlswitch_ie = NULL; + struct sLimWiderBWChannelSwitch *lim_wbw_chnlswitch_info = NULL; + struct sDot11fIEsec_chan_offset_ele *sec_chnl_offset = 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 Channel switch action frame"); + if (!session->lim11hEnable) + return; + + chnl_switch_frame = qdf_mem_malloc(sizeof(*chnl_switch_frame)); + if (NULL == chnl_switch_frame) { + pe_err("AllocateMemory failed"); + return; + } + + /* Unpack channel switch frame */ + status = dot11f_unpack_channel_switch(mac_ctx, body_ptr, frame_len, + chnl_switch_frame, false); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to unpack and parse (0x%08x, %d bytes)", + status, frame_len); + qdf_mem_free(chnl_switch_frame); + return; + } else if (DOT11F_WARNED(status)) { + pe_warn("warning: unpack 11h-CHANSW Req(0x%08x, %d bytes)", + status, frame_len); + } + + if (qdf_mem_cmp((uint8_t *) &session->bssId, + (uint8_t *) &mac_hdr->sa, sizeof(tSirMacAddr))) { + pe_warn("Rcvd action frame not from our BSS, dropping"); + qdf_mem_free(chnl_switch_frame); + return; + } + /* copy the beacon interval from session */ + val = session->beaconParams.beaconInterval; + ch_switch_params = &session->gLimChannelSwitch; + bcn_period = (uint16_t)val; + ch_switch_params->primaryChannel = + chnl_switch_frame->ChanSwitchAnn.newChannel; + ch_switch_params->switchCount = + chnl_switch_frame->ChanSwitchAnn.switchCount; + ch_switch_params->switchTimeoutValue = + SYS_MS_TO_TICKS(bcn_period) * + session->gLimChannelSwitch.switchCount; + ch_switch_params->switchMode = + chnl_switch_frame->ChanSwitchAnn.switchMode; + + /* Only primary channel switch element is present */ + ch_switch_params->state = eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + ch_switch_params->ch_width = CH_WIDTH_20MHZ; + + if (chnl_switch_frame->WiderBWChanSwitchAnn.present + && session->vhtCapability) { + wbw_chnlswitch_ie = &chnl_switch_frame->WiderBWChanSwitchAnn; + session->gLimWiderBWChannelSwitch.newChanWidth = + wbw_chnlswitch_ie->newChanWidth; + session->gLimWiderBWChannelSwitch.newCenterChanFreq0 = + wbw_chnlswitch_ie->newCenterChanFreq0; + session->gLimWiderBWChannelSwitch.newCenterChanFreq1 = + wbw_chnlswitch_ie->newCenterChanFreq1; + } + pe_debug("Rcv Chnl Swtch Frame: Timeout in %d ticks", + session->gLimChannelSwitch.switchTimeoutValue); + if (session->htSupportedChannelWidthSet) { + sec_chnl_offset = &chnl_switch_frame->sec_chan_offset_ele; + if (sec_chnl_offset->secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel + 2; + } else if (sec_chnl_offset->secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel - 2; + + } + if (session->vhtCapability && + chnl_switch_frame->WiderBWChanSwitchAnn.present) { + wbw_chnlswitch_ie = + &chnl_switch_frame->WiderBWChanSwitchAnn; + ch_switch_params->ch_width = + wbw_chnlswitch_ie->newChanWidth + 1; + lim_wbw_chnlswitch_info = + &session->gLimWiderBWChannelSwitch; + ch_switch_params->ch_center_freq_seg0 = + lim_wbw_chnlswitch_info->newCenterChanFreq0; + ch_switch_params->ch_center_freq_seg1 = + lim_wbw_chnlswitch_info->newCenterChanFreq1; + + } + } + + if (CH_WIDTH_20MHZ == ch_switch_params->ch_width) { + session->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + session->htRecommendedTxWidthSet = + session->htSupportedChannelWidthSet; + } + + if (QDF_STATUS_SUCCESS != lim_start_channel_switch(mac_ctx, session)) + pe_err("Could not start channel switch"); + + qdf_mem_free(chnl_switch_frame); + 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(tpAniSirGlobal mac_ctx, + uint8_t *rx_packet_info, tpPESession session_entry) +{ + + tpSirMacMgmtHdr hdr; + uint8_t *body; + tDot11fext_channel_switch_action_frame *ext_channel_switch_frame; + uint32_t frame_len; + uint32_t status; + uint8_t target_channel; + + 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 (NULL == ext_channel_switch_frame) { + pe_err("AllocateMemory failed"); + 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); + } + + target_channel = + ext_channel_switch_frame->ext_chan_switch_ann_action.new_channel; + + /* 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->currentOperChannel != target_channel) && + ((wlan_reg_get_channel_state(mac_ctx->pdev, target_channel) == + CHANNEL_STATE_ENABLE) || + (wlan_reg_get_channel_state(mac_ctx->pdev, target_channel) == + CHANNEL_STATE_DFS && + !policy_mgr_concurrent_open_sessions_running( + mac_ctx->psoc))))) { + pe_err("Channel: %d is not valid", target_channel); + return; + } + + if ((eLIM_STA_ROLE == session_entry->limSystemRole) || + (eLIM_P2P_DEVICE_CLIENT == session_entry->limSystemRole)) { + + 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 (NULL == ext_cng_chan_ind) { + pe_err("AllocateMemory failed for 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_channel = target_channel; + + 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, ePROT); + } + 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(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession 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; + uint8_t oper_mode; + uint8_t cb_mode; + uint8_t ch_bw = 0; + uint8_t skip_opmode_update = false; + + 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 (NULL == operating_mode_frm) { + pe_err("AllocateMemory failed"); + 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 == NULL) { + pe_err("Station context not found"); + goto end; + } + + if (CHAN_ENUM_14 >= session->currentOperChannel) + cb_mode = mac_ctx->roam.configParam.channelBondingMode24GHz; + else + cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz; + /* + * Do not update the channel bonding mode if channel bonding + * mode is disabled in INI. + */ + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode) { + pe_debug("channel bonding disabled"); + goto update_nss; + } + + if (sta_ptr->htSupportedChannelWidthSet) { + if (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ < + sta_ptr->vhtSupportedChannelWidthSet) + oper_mode = eHT_CHANNEL_WIDTH_160MHZ; + else + oper_mode = sta_ptr->vhtSupportedChannelWidthSet + 1; + } else { + oper_mode = eHT_CHANNEL_WIDTH_20MHZ; + } + + if ((oper_mode == eHT_CHANNEL_WIDTH_80MHZ) && + (operating_mode_frm->OperatingMode.chanWidth > + eHT_CHANNEL_WIDTH_80MHZ)) + skip_opmode_update = true; + + if (!skip_opmode_update && (oper_mode != + operating_mode_frm->OperatingMode.chanWidth)) { + uint32_t fw_vht_ch_wd = wma_get_vht_ch_width(); + + pe_debug("received Chanwidth: %d staIdx: %d", + (operating_mode_frm->OperatingMode.chanWidth), + sta_ptr->staIndex); + + 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]); + + if (operating_mode_frm->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_160MHZ + && (fw_vht_ch_wd >= eHT_CHANNEL_WIDTH_160MHZ)) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_bw = eHT_CHANNEL_WIDTH_160MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_80MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_bw = eHT_CHANNEL_WIDTH_80MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_40MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_bw = eHT_CHANNEL_WIDTH_40MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_20MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + ch_bw = eHT_CHANNEL_WIDTH_20MHZ; + } + lim_check_vht_op_mode_change(mac_ctx, session, ch_bw, + sta_ptr->staIndex, mac_hdr->sa); + } + +update_nss: + if (sta_ptr->vhtSupportedRxNss != + (operating_mode_frm->OperatingMode.rxNSS + 1)) { + sta_ptr->vhtSupportedRxNss = + operating_mode_frm->OperatingMode.rxNSS + 1; + lim_set_nss_change(mac_ctx, session, sta_ptr->vhtSupportedRxNss, + sta_ptr->staIndex, 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(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession 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 (NULL == gid_mgmt_frame) { + pe_err("AllocateMemory failed"); + 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("received Gid Management Action Frame staIdx: %d", + sta_ptr->staIndex); + + 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, staIdx = %d", + sta_ptr->staIndex); + 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, staIdx: %d", + sta_ptr->staIndex); + goto out; + } + while (!(*mem_cur & 1)) { + *mem_cur >>= 1; + ++membership; + } + if (*mem_cur) { + pe_err("rcved frame with mult group ID set, staIdx: %d", + sta_ptr->staIndex); + 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, sta_ptr->staIndex); +out: + qdf_mem_free(gid_mgmt_frame); + return; +} + +static void +__lim_process_add_ts_req(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ +} + +/** + * __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(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession 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 == NULL) { + 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 == eSIR_MAC_SUCCESS_STATUS)) { + /* 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); + + /* deactivate the response timer */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_ADDTS_RSP_TIMER); + + if (addts.status != eSIR_MAC_SUCCESS_STATUS) { + 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, + session->transactionId); + + /* 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(tSirMacESETSMIE)); + 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 != NULL) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + sta_ds_ptr->bssId, 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) < MAX_NUM_AC))) { +#ifdef FEATURE_WLAN_ESE + retval = lim_send_hal_msg_add_ts(mac_ctx, + sta_ptr->staIndex, tspec_info->idx, + addts.tspec, session->peSessionId, + addts.tsmIE.msmt_interval); +#else + retval = lim_send_hal_msg_add_ts(mac_ctx, + sta_ptr->staIndex, 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, + session->transactionId); + 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"); + /* + * Use the smesessionId and smetransactionId from the PE + * session context + */ + lim_send_sme_addts_rsp(mac_ctx, true, eSIR_SME_SUCCESS, + session, addts.tspec, session->smeSessionId, + session->transactionId); + } + /* 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(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + QDF_STATUS retval; + tSirDeltsReqInfo delts; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ptr; + uint32_t frame_len; + uint16_t aid; + uint8_t *body_ptr; + uint8_t ts_status; + tSirMacTSInfo *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 == NULL) { + 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) >= MAX_NUM_AC) { + 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, + sta_ptr->staIndex, 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 != NULL) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + sta_ds_ptr->bssId, 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(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession 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_CH(rx_pkt_info), session, + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info)); +} + +#ifdef ANI_SUPPORT_11H +static void +__lim_process_basic_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, pMeasReqFrame, + peerMacAddr, psessionEntry) != + QDF_STATUS_SUCCESS) { + pe_err("fail to send Basic Meas report"); + return; + } +} +static void +__lim_process_cca_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, pMeasReqFrame, + peerMacAddr, psessionEntry) != + QDF_STATUS_SUCCESS) { + pe_err("fail to send CCA Meas report"); + return; + } +} +static void +__lim_process_rpi_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, pMeasReqFrame, + peerMacAddr, psessionEntry) != + QDF_STATUS_SUCCESS) { + pe_err("fail to send RPI Meas report"); + return; + } +} +static void +__lim_process_measurement_request_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + 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 (NULL == pMeasReqFrame) { + pe_err("AllocateMemory failed"); + return; + } + + if (sir_convert_meas_req_frame2_struct(pMac, 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(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + __lim_process_cca_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + __lim_process_rpi_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + default: + pe_warn("Unknown Measurement Type: %d", + pMeasReqFrame->measReqIE.measType); + break; + } +} /*** end limProcessMeasurementRequestFrame ***/ +static void +__lim_process_tpc_request_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + 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 (NULL == pTpcReqFrame) { + pe_err("AllocateMemory failed"); + return; + } + if (sir_convert_tpc_req_frame2_struct(pMac, pBody, pTpcReqFrame, frameLen) != + QDF_STATUS_SUCCESS) { + pe_warn("Rcv invalid TPC Req Action Frame"); + return; + } + if (lim_send_tpc_report_frame(pMac, + pTpcReqFrame, + pHdr->sa, psessionEntry) != QDF_STATUS_SUCCESS) { + pe_err("fail to send TPC Report Frame"); + return; + } +} +#endif + +static void +__lim_process_sm_power_save_update(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + + 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(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + pe_err("STA context not found - ignoring UpdateSM PSave Mode from"); + lim_print_mac_addr(pMac, pHdr->sa, LOGE); + return; + } + + /**Unpack the received frame */ + nStatus = dot11f_unpack_sm_power_save(pMac, 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(pMac, pSta->staIndex, pSta->htMIMOPSState, + pSta->staAddr, psessionEntry->smeSessionId); +} + + +static void +__lim_process_radio_measure_request(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + 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 (psessionEntry == NULL) { + return; + } + + curr_seq_num = ((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo); + if (curr_seq_num == pMac->rrm.rrmPEContext.prev_rrm_report_seq_num && + pMac->rrm.rrmPEContext.pCurrentReq) { + 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 */ + pMac->rrm.rrmPEContext.prev_rrm_report_seq_num = curr_seq_num; + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, (uint8_t *)pHdr, + frameLen + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(pRxPacketInfo), psessionEntry, + WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo)); + + frm = qdf_mem_malloc(sizeof(*frm)); + if (frm == NULL) { + pe_err("Failed to alloc memory for tDot11fRadioMeasurementRequest"); + return; + } + + /**Unpack the received frame */ + nStatus = dot11f_unpack_radio_measurement_request(pMac, 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("There were warnings while unpacking a Radio Measure request (0x%08x, %d bytes):", + nStatus, frameLen); + } + /* Call rrm function to handle the request. */ + + rrm_process_radio_measurement_request(pMac, pHdr->sa, frm, + psessionEntry); +err: + qdf_mem_free(frm); +} + +static QDF_STATUS +__lim_process_link_measurement_req(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + 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 (psessionEntry == NULL) { + return QDF_STATUS_E_FAILURE; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_link_measurement_request(pMac, 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); + } + /* Call rrm function to handle the request. */ + + return rrm_process_link_measurement_request(pMac, pRxPacketInfo, &frm, + psessionEntry); + +} + +static void +__lim_process_neighbor_report(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + 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 (NULL == pFrm) { + pe_err("Unable to allocate memory"); + return; + } + + if (psessionEntry == NULL) { + qdf_mem_free(pFrm); + return; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_neighbor_report_response(pMac, 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(pMac, pFrm, psessionEntry); + + qdf_mem_free(pFrm); +} + + +#ifdef WLAN_FEATURE_11W +/** + * limProcessSAQueryRequestActionFrame + * + ***FUNCTION: + * This function is called by lim_process_action_frame() upon + * SA query request Action frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param psessionEntry - PE session entry + * + * @return None + */ +static void __lim_process_sa_query_request_action_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + uint32_t frame_len; + uint8_t transId[2]; + + /* Prima --- Below Macro not available in prima + pHdr = SIR_MAC_BD_TO_MPDUHEADER(pBd); + pBody = SIR_MAC_BD_TO_MPDUDATA(pBd); */ + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frame_len = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (frame_len < sizeof(struct sDot11fSaQueryReq)) { + pe_err("Invalid frame length"); + return; + } + /* If this is an unprotected SA Query Request, then ignore it. */ + if (pHdr->fc.wep == 0) + return; + + /* 11w offload is enabled then firmware should not fwd this frame */ + if (LIM_IS_STA_ROLE(psessionEntry) && pMac->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], &pBody[2], 2); + + /* Send 11w SA query response action frame */ + if (lim_send_sa_query_response_frame(pMac, + transId, + pHdr->sa, + psessionEntry) != 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 pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param psessionEntry - PE session entry + * @return None + */ +static void __lim_process_sa_query_response_action_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint32_t frame_len; + uint8_t *pBody; + tpDphHashNode pSta; + uint16_t aid; + uint16_t transId; + uint8_t retryNum; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + frame_len = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + pe_debug("SA Query Response received"); + + if (frame_len < sizeof(struct sDot11fSaQueryRsp)) { + pe_err("Invalid frame length"); + return; + } + /* When a station, supplicant handles SA Query Response. + * Forward to SME to HDD to wpa_supplicant. + */ + if (LIM_IS_STA_ROLE(psessionEntry)) { + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, + (uint8_t *)pHdr, + frame_len + sizeof(tSirMacMgmtHdr), + 0, + WMA_GET_RX_CH(pRxPacketInfo), + psessionEntry, + WMA_GET_RX_RSSI_NORMALIZED( + pRxPacketInfo)); + return; + } + + /* If this is an unprotected SA Query Response, then ignore it. */ + if (pHdr->fc.wep == 0) + return; + + pSta = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pSta) + return; + + pe_debug("SA Query Response source addr: %0x:%0x:%0x:%0x:%0x:%0x", + pHdr->sa[0], pHdr->sa[1], pHdr->sa[2], pHdr->sa[3], + pHdr->sa[4], pHdr->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, &pBody[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) { + 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; + } +} +#endif + +#ifdef WLAN_FEATURE_11W +/** + * 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 pMac - Global MAC structure + * @param psessionEntry - 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(tpAniSirGlobal pMac, tpPESession psessionEntry, + tpSirMacMgmtHdr pHdr, uint8_t category) +{ + uint16_t aid; + tpDphHashNode pStaDs; + bool rmfConnection = false; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) + if (pStaDs->rmfEnabled) + rmfConnection = true; + } else if (psessionEntry->limRmfEnabled) + rmfConnection = true; + + if (rmfConnection && (pHdr->fc.wep == 0)) { + pe_err("Dropping unprotected Action category: %d frame since RMF is enabled", + category); + return true; + } else + return false; +} +#endif + +/** + * 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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11faddba_req *addba_req; + uint32_t frame_len, status; + QDF_STATUS qdf_status; + uint8_t peer_id; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *peer, *pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + pe_err("pdev is NULL"); + 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(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + body_ptr, frame_len); + + addba_req = qdf_mem_malloc(sizeof(*addba_req)); + if (NULL == addba_req) { + pe_err("memory allocation failed"); + 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); + } + + peer = cdp_peer_get_ref_by_addr(soc, pdev, mac_hdr->sa, &peer_id, + PEER_DEBUG_ID_WMA_ADDBA_REQ); + if (!peer) { + pe_err("PEER [%pM] not found", mac_hdr->sa); + goto error; + } + + qdf_status = cdp_addba_requestprocess(soc, peer, + addba_req->DialogToken.token, + addba_req->addba_param_set.tid, + addba_req->ba_timeout.timeout, + addba_req->addba_param_set.buff_size, + addba_req->ba_start_seq_ctrl.ssn); + + cdp_peer_release_ref(soc, peer, PEER_DEBUG_ID_WMA_ADDBA_REQ); + + if (QDF_STATUS_SUCCESS == 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); + } else { + pe_err("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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fdelba_req *delba_req; + uint32_t frame_len, status; + QDF_STATUS qdf_status; + uint8_t peer_id; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *peer, *pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + pe_err("pdev is NULL"); + 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(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + body_ptr, frame_len); + + delba_req = qdf_mem_malloc(sizeof(*delba_req)); + if (NULL == delba_req) { + pe_err("memory allocation failed"); + 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); + } + + peer = cdp_peer_get_ref_by_addr(soc, pdev, mac_hdr->sa, &peer_id, + PEER_DEBUG_ID_WMA_DELBA_REQ); + if (!peer) { + pe_err("PEER [%pM] not found", mac_hdr->sa); + goto error; + } + + qdf_status = cdp_delba_process(soc, peer, + delba_req->delba_param_set.tid, delba_req->Reason.code); + + cdp_peer_release_ref(soc, peer, PEER_DEBUG_ID_WMA_DELBA_REQ); + + if (QDF_STATUS_SUCCESS != qdf_status) + pe_err("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(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + uint8_t *body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + tpSirMacActionFrameHdr action_hdr = (tpSirMacActionFrameHdr) body_ptr; +#ifdef WLAN_FEATURE_11W + tpSirMacMgmtHdr mac_hdr_11w = WMA_GET_RX_MAC_HEADER(rx_pkt_info); +#endif + tpSirMacMgmtHdr mac_hdr = NULL; + int8_t rssi; + uint32_t frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + tpSirMacVendorSpecificFrameHdr vendor_specific; + uint8_t oui[] = { 0x00, 0x00, 0xf0 }; + uint8_t dpp_oui[] = { 0x50, 0x6F, 0x9A, 0x1A }; + tpSirMacVendorSpecificPublicActionFrameHdr pub_action; + + if (frame_len < sizeof(*action_hdr)) { + pe_debug("frame_len %d less than Action Frame Hdr size", + frame_len); + return; + } + +#ifdef WLAN_FEATURE_11W + if (lim_is_robust_mgmt_action_frame(action_hdr->category) && + lim_drop_unprotected_action_frame(mac_ctx, session, + mac_hdr_11w, action_hdr->category)) + return; +#endif + + switch (action_hdr->category) { + case SIR_MAC_ACTION_QOS_MGMT: + if ((session->limQosEnabled) || + (action_hdr->actionID == SIR_MAC_QOS_MAP_CONFIGURE)) { + switch (action_hdr->actionID) { + case SIR_MAC_QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_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 SIR_MAC_ACTION_SPECTRUM_MGMT: + switch (action_hdr->actionID) { +#ifdef ANI_SUPPORT_11H + case SIR_MAC_ACTION_MEASURE_REQUEST_ID: + if (session->lim11hEnable) + __lim_process_measurement_request_frame(mac_ctx, + rx_pkt_info, + session); + break; + case SIR_MAC_ACTION_TPC_REQUEST_ID: + 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 + case SIR_MAC_ACTION_CHANNEL_SWITCH_ID: + if (LIM_IS_STA_ROLE(session)) + __lim_process_channel_switch_action_frame( + mac_ctx, rx_pkt_info, session); + break; + default: + pe_warn("Spectrum mgmt action id: %d not handled", + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_WME: + if (!session->limWmeEnabled) { + pe_warn("WME mode disabled - dropping frame: %d", + action_hdr->actionID); + break; + } + switch (action_hdr->actionID) { + case SIR_MAC_QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_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 SIR_MAC_ACTION_HT: + /** Type of HT Action to be performed*/ + switch (action_hdr->actionID) { + case SIR_MAC_SM_POWER_SAVE: + 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 SIR_MAC_ACTION_WNM: + pe_debug("WNM Action category: %d action: %d", + action_hdr->category, action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_WNM_BSS_TM_QUERY: + case SIR_MAC_WNM_BSS_TM_REQUEST: + case SIR_MAC_WNM_BSS_TM_RESPONSE: + case SIR_MAC_WNM_NOTIF_REQUEST: + case SIR_MAC_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->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, rssi); + break; + default: + pe_debug("Action ID: %d not handled in WNM category", + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_RRM: + /* 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 SIR_MAC_RRM_RADIO_MEASURE_REQ: + __lim_process_radio_measure_request(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case SIR_MAC_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 SIR_MAC_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 { + /* 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 SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY: + 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; + } + + /* Check if it is a vendor specific action frame. */ + if (LIM_IS_STA_ROLE(session) && + (!qdf_mem_cmp(session->selfMacAddr, + &mac_hdr->da[0], sizeof(tSirMacAddr))) + && IS_WES_MODE_ENABLED(mac_ctx) + && !qdf_mem_cmp(vendor_specific->Oui, oui, 3)) { + 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->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, + WMA_GET_RX_RSSI_NORMALIZED( + rx_pkt_info)); + } else { + pe_debug("Dropping the vendor specific action frame" + "beacause of (WES Mode not enabled " + "(WESMODE: %d) or OUI mismatch " + "(%02x %02x %02x) or not received with" + "SelfSta address) system role: %d", + IS_WES_MODE_ENABLED(mac_ctx), + vendor_specific->Oui[0], + vendor_specific->Oui[1], + vendor_specific->Oui[2], + GET_LIM_SYSTEM_ROLE(session)); + } + break; + case SIR_MAC_ACTION_PUBLIC_USAGE: + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + + switch (action_hdr->actionID) { + case SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID: + lim_process_ext_channel_switch_action_frame(mac_ctx, + rx_pkt_info, session); + break; + case SIR_MAC_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; + } + /* Fall through to send the frame to supplicant */ + case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY: + case SIR_MAC_ACTION_2040_BSS_COEXISTENCE: + case SIR_MAC_ACTION_GAS_INITIAL_REQUEST: + case SIR_MAC_ACTION_GAS_INITIAL_RESPONSE: + case SIR_MAC_ACTION_GAS_COMEBACK_REQUEST: + case SIR_MAC_ACTION_GAS_COMEBACK_RESPONSE: + /* + * 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->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), session, + WMA_GET_RX_RSSI_NORMALIZED( + rx_pkt_info)); + break; + default: + pe_debug("Unhandled public action frame: %d", + action_hdr->actionID); + break; + } + break; + +#ifdef WLAN_FEATURE_11W + case SIR_MAC_ACTION_SA_QUERY: + pe_debug("SA Query Action category: %d action: %d", + action_hdr->category, action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_SA_QUERY_REQ: + /**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 SIR_MAC_SA_QUERY_RSP: + /**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; +#endif + case SIR_MAC_ACTION_VHT: + if (!session->vhtCapability) + break; + switch (action_hdr->actionID) { + case SIR_MAC_VHT_OPMODE_NOTIFICATION: + __lim_process_operating_mode_action_frame(mac_ctx, + rx_pkt_info, session); + break; + case SIR_MAC_VHT_GID_NOTIFICATION: + /* 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 SIR_MAC_ACTION_FST: { + tpSirMacMgmtHdr hdr; + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + + pe_debug("Received FST MGMT action frame"); + /* 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->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, + WMA_GET_RX_RSSI_NORMALIZED( + rx_pkt_info)); + break; + } + case SIR_MAC_ACTION_PROT_DUAL_PUB: + pe_debug("Rcvd Protected Dual of Public Action: %d", + action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_PDPA_GAS_INIT_REQ: + case SIR_MAC_PDPA_GAS_INIT_RSP: + case SIR_MAC_PDPA_GAS_COMEBACK_REQ: + case SIR_MAC_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->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), session, rssi); + break; + default: + pe_debug("Unhandled - Protected Dual Public Action"); + break; + } + break; + case SIR_MAC_ACTION_BLKACK: + pe_debug("Rcvd Block Ack for %pM; action: %d", + session->selfMacAddr, action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_ADDBA_REQ: + lim_process_addba_req(mac_ctx, rx_pkt_info, session); + break; + case SIR_MAC_DELBA_REQ: + lim_process_delba_req(mac_ctx, rx_pkt_info, session); + break; + default: + pe_err("Unhandle BA action frame"); + break; + } + break; + default: + pe_warn("Action category: %d not handled", + action_hdr->category); + break; + } +} + +/** + * 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 pMac - Pointer to Global MAC structure + * @param *pBd - A pointer to Buffer descriptor + associated PDUs + * @return None + */ +void lim_process_action_frame_no_session(tpAniSirGlobal pMac, 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); + uint8_t dpp_oui[] = { 0x50, 0x6F, 0x9A, 0x1A }; + tpSirMacActionFrameHdr action_hdr = (tpSirMacActionFrameHdr) pBody; + tpSirMacVendorSpecificPublicActionFrameHdr vendor_specific; + + pe_debug("Received an Action frame -- no session"); + + 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 SIR_MAC_ACTION_PUBLIC_USAGE: + switch (action_hdr->actionID) { + case SIR_MAC_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; + } + /* + * Check if it is a DPP public action frame and fall + * thru, else drop the frame. + */ + if (qdf_mem_cmp(vendor_specific->Oui, dpp_oui, 4)) { + pe_debug("Unhandled 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]); + break; + } + /* Fall through to send the frame to supplicant */ + case SIR_MAC_ACTION_GAS_INITIAL_REQUEST: + case SIR_MAC_ACTION_GAS_INITIAL_RESPONSE: + case SIR_MAC_ACTION_GAS_COMEBACK_REQUEST: + case SIR_MAC_ACTION_GAS_COMEBACK_RESPONSE: + /* + * Forward the GAS frames to wpa_supplicant + * type is ACTION + */ + lim_send_sme_mgmt_frame_ind(pMac, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(pBd), NULL, + WMA_GET_RX_RSSI_NORMALIZED(pBd)); + break; + default: + pe_warn("Unhandled public action frame: %x", + action_hdr->actionID); + break; + } + break; + default: + pe_warn("Unhandled action frame without session: %x", + action_hdr->category); + break; + + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..c99d507f85269aa1bf30723863b2fe9eba5350bd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c @@ -0,0 +1,2607 @@ +/* + * 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. + */ + +/* + * 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_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_sta_hash_api.h" +#include "lim_admit_control.h" +#include "cds_packet.h" +#include "lim_session_utils.h" + +#include "qdf_types.h" +#include "cds_utils.h" +#include "wlan_utility.h" + +/** + * 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(tpAniSirGlobal 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; + + 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]; + pe_debug("Rcv assoc_req: chnl: %d numOfChnl: %d", + first_ch_no, chn_count); + 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; + if (BAND_5G == lim_get_rf_band(first_ch_no)) + channel_offset = SIR_11A_FREQUENCY_OFFSET; + else if (BAND_2G == lim_get_rf_band(first_ch_no)) + 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); +} + +/** + * lim_check_sta_in_pe_entries() - checks if sta exists in any dph tables. + * @mac_ctx: Pointer to Global MAC structure + * @hdr: A pointer to the MAC header + * @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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + uint16_t sessionid, + bool *dup_entry) +{ + uint8_t i; + uint16_t assoc_id = 0; + tpDphHashNode sta_ds = NULL; + tpPESession session = NULL; + + *dup_entry = false; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if ((&mac_ctx->lim.gpSession[i] != NULL) && + (mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].pePersona == QDF_SAP_MODE)) { + session = &mac_ctx->lim.gpSession[i]; + sta_ds = dph_lookup_hash_entry(mac_ctx, hdr->sa, + &assoc_id, &session->dph.dphHashTable); + if (sta_ds +#ifdef WLAN_FEATURE_11W + && (!sta_ds->rmfEnabled || + (sessionid != session->peSessionId)) +#endif + ) { + 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:%pM in mlmState %d", + sta_ds->sta_deletion_in_progress, + sta_ds->staAddr, + sta_ds->mlmStaContext.mlmState); + *dup_entry = true; + return QDF_STATUS_E_AGAIN; + } + sta_ds->sta_deletion_in_progress = true; + pe_err("Sending Disassoc and Deleting existing STA entry:" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(session->selfMacAddr)); + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *) hdr->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 = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + 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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession 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, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_tkip() - checks TKIP counter measure is active + * @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 TKIP counter measure is active + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_tkip(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, uint8_t sub_type) +{ + /* + * If TKIP counter measures active send Assoc Rsp frame to station + * with eSIR_MAC_MIC_FAILURE_REASON + */ + if (!(session->bTkipCntrMeasActive && LIM_IS_AP_ROLE(session))) + return true; + + pe_err("Assoc Req rejected: TKIP counter measure is active"); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_MAC_MIC_FAILURE_REASON, 1, + hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_assoc_req_parse_error() - checks for error in frame parsing + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession session, + tpSirAssocReq assoc_req, + uint8_t sub_type, uint8_t *frm_body, + uint32_t frame_len) +{ + QDF_STATUS status; + + if (sub_type == LIM_ASSOC) + status = sir_convert_assoc_req_frame2_struct(mac_ctx, frm_body, + frame_len, assoc_req); + else + status = sir_convert_reassoc_req_frame2_struct(mac_ctx, + frm_body, frame_len, assoc_req); + + if (status == QDF_STATUS_SUCCESS) + return true; + + pe_warn("Assoc Req rejected: frame parsing error. source addr:" + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(hdr->sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_capab() - checks for capab match + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type, tSirMacCapabilityInfo *local_cap) +{ + uint16_t temp; + + if (cfg_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" + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->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, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_ssid() - checks for SSID match + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (lim_cmp_ssid(&assoc_req->ssId, session) != true) + return true; + + pe_err("%s Req with ssid wrong(Rcvd: %.*s self: %.*s) from " + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + assoc_req->ssId.length, assoc_req->ssId.ssId, + session->ssId.length, session->ssId.ssId, + MAC_ADDR_ARRAY(hdr->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, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_rates() - checks for supported rates + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession 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_RATESET_EID_MAX); i++) { + basic_rates.rate[i] = assoc_req->supportedRates.rate[i]; + basic_rates.numRates++; + } + + for (j = 0; (j < assoc_req->extendedRates.numRates) + && (i < SIR_MAC_RATESET_EID_MAX); 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, soruce addr: %s" + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->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, + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS, 1, + hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_11g_only() - checks for non 11g STA + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == WNI_CFG_DOT11_MODE_11G_ONLY) && + (assoc_req->HTCaps.present)) { + pe_err("SOFTAP was in 11G only mode, rejecting legacy STA: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_11n_only() - checks for non 11n STA + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == WNI_CFG_DOT11_MODE_11N_ONLY) && + (!assoc_req->HTCaps.present)) { + pe_err("SOFTAP was in 11N only mode, rejecting legacy STA: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_11ac_only() - checks for non 11ac STA + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession 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 == WNI_CFG_DOT11_MODE_11AC_ONLY) && + ((vht_caps == NULL) || ((vht_caps != NULL) && (!vht_caps->present)))) { + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + 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 + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == WNI_CFG_DOT11_MODE_11AX_ONLY) && + !assoc_req->he_cap.present) { + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + 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 + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession session, + tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + uint32_t val; + 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); + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(mac_ctx, + WNI_CFG_HE_OPS_BASIC_MCS_NSS, &val)) + val = WNI_CFG_HE_OPS_BASIC_MCS_NSS_DEF; + basic_mcs = (uint16_t)val; + final_mcs = HE_INTERSECT_MCS(sta_mcs, basic_mcs); + if (final_mcs != basic_mcs) { + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + pe_err("STA did not support basic MCS required by SAP"); + return false; + } + } + return true; +} +#else +static bool lim_chk_11ax_only(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + return true; +} + +static bool lim_check_11ax_basic_mcs(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession 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 + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession 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 " + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + } + if (!assoc_req->supportedChannelsPresent) { + pe_warn("LIM Info: Missing Supported channel IE in %s Req from " + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->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 " + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->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 " + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + } + /* IEs are valid, use them if needed */ + } + } /* if(assoc.capabilityInfo.spectrumMgt) */ + else { + /* + * As per the capabiities, 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 + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession 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 " + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->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, + eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_is_11b_sta_supported() - checks if STA is 11b + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession 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) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_ONLY_POLICY, + &cfg_11g_only) != QDF_STATUS_SUCCESS) { + pe_err("couldn't get 11g-only flag"); + return false; + } + + 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, + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + + pe_warn("Rejecting Re/Assoc req from 11b STA:"); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGW); + +#ifdef WLAN_DEBUG + mac_ctx->lim.gLim11bStaAssocRejectCount++; +#endif + 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(tpAniSirGlobal mac_ctx, tpPESession 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; + */ + } +} + +/** + * 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 + * @hdr: pointer to the MAC head + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @pmf_connection: flag indicating pmf connection + * + * 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(tpPESession session, tpAniSirGlobal mac_ctx, + uint8_t sub_type, tpSirMacMgmtHdr hdr, + tpSirAssocReq assoc_req, bool *pmf_connection) +{ + uint32_t ret; + tDot11fIEWPA dot11f_ie_wpa = {0}; + tDot11fIERSN dot11f_ie_rsn = {0}; + QDF_STATUS status = QDF_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_err("RSN enabled auth, Re/Assoc req from STA: " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(hdr->sa)); + + if (assoc_req->rsnPresent) { + if (!(assoc_req->rsn.length)) { + pe_warn("Re/Assoc rejected from: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + /* + * rcvd Assoc req frame with RSN IE but + * length is zero + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_INVALID_IE_STATUS, 1, + hdr->sa, sub_type, 0, session); + 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, eSIR_MAC_INVALID_IE_STATUS, 1, + hdr->sa, sub_type, 0, session); + 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_rx_rsn_ie_match(mac_ctx, + &dot11f_ie_rsn, session, + assoc_req->HTCaps.present, + pmf_connection); + if (QDF_STATUS_SUCCESS != status) { + pe_warn("Re/Assoc rejected from: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + + lim_send_assoc_rsp_mgmt_frame(mac_ctx, status, + 1, hdr->sa, sub_type, + 0, session); + return false; + } + } else { + pe_warn("Re/Assoc rejected from: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + + /* + * rcvd Assoc req frame with RSN IE but + * IE version is wrong + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_UNSUPPORTED_RSN_IE_VERSION_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + } else if (assoc_req->wpaPresent) { + if (!(assoc_req->wpa.length)) { + pe_warn("Re/Assoc rejected from: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + + /* rcvd Assoc req frame with invalid WPA IE length */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_INVALID_IE_STATUS, 1, + hdr->sa, sub_type, 0, session); + 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, eSIR_MAC_INVALID_IE_STATUS, 1, + hdr->sa, sub_type, 0, session); + return false; + } + + /* check the groupwise and pairwise cipher suites*/ + status = lim_check_rx_wpa_ie_match(mac_ctx, dot11f_ie_wpa, + session, assoc_req->HTCaps.present); + if (QDF_STATUS_SUCCESS != status) { + pe_warn("Re/Assoc rejected from: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + + /* + * rcvd Assoc req frame with WPA IE + * but there is mismatch + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, status, 1, + hdr->sa, sub_type, 0, session); + return false; + } + + } + return true; + +} + +/** + * lim_chk_n_process_wpa_rsn_ie() - wpa ie related checks + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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 + * + * wpa ie related checks + * + * Return: true if no error, false otherwise + */ +static bool lim_chk_n_process_wpa_rsn_ie(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession session, + tpSirAssocReq assoc_req, + uint8_t sub_type, bool *pmf_connection) +{ + 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 == NULL) { + /* 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, + hdr, assoc_req, pmf_connection); + } 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 + * @hdr: pointer to the MAC head + * @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 + * + * Process assoc req for no sta ctx present + * + * Return: true of no error, false otherwise + */ +static bool lim_process_assoc_req_no_sta_ctx(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, tpPESession session, + tpSirAssocReq assoc_req, uint8_t sub_type, + struct tLimPreAuthNode *sta_pre_auth_ctx, + tpDphHashNode sta_ds, tAniAuthType *auth_type) +{ + /* Requesting STA is not currently associated */ + if (pe_get_current_stas_count(mac_ctx) == + mac_ctx->lim.gLimAssocStaLimit) { + /* + * Maximum number of STAs that AP can handle reached. + * Send Association response to peer MAC entity + */ + pe_err("Max Sta count reached : %d", + mac_ctx->lim.maxStation); + lim_reject_association(mac_ctx, hdr->sa, sub_type, false, + (tAniAuthType) 0, 0, false, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + return false; + } + /* Check if STA is pre-authenticated. */ + if ((sta_pre_auth_ctx == NULL) || (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, + eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON, + hdr->sa, session, false); + + pe_warn("rcvd %s req, sessionid: %d, without pre-auth ctx" + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, MAC_ADDR_ARRAY(hdr->sa)); + return false; + } + /* Delete 'pre-auth' context of STA */ + *auth_type = sta_pre_auth_ctx->authType; + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + /* All is well. Assign AID (after else part) */ + return true; +} + +/** + * lim_process_assoc_req_sta_ctx() - process assoc req for sta context present + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, tpPESession 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) +{ + /* STA context does exist for this STA */ + if (sta_ds->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) { + /* + * Requesting STA is in some 'transient' state? Ignore the + * Re/Assoc Req frame by incrementing debug counter & logging + * error. + */ + if (sub_type == LIM_ASSOC) { +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumAssocReqDropInvldState++; +#endif + pe_debug("received Assoc req in state: %X from", + sta_ds->mlmStaContext.mlmState); + } else { +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumReassocReqDropInvldState++; +#endif + pe_debug("received ReAssoc req in state: %X from", + sta_ds->mlmStaContext.mlmState); + } + lim_print_mac_addr(mac_ctx, hdr->sa, LOGD); + lim_print_mlm_state(mac_ctx, LOGD, + (tLimMlmStates) sta_ds->mlmStaContext.mlmState); + return false; + } + + /* STA sent assoc req frame while already in 'associated' state */ + +#ifdef WLAN_FEATURE_11W + 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, + eSIR_MAC_TRY_AGAIN_LATER, 1, hdr->sa, + sub_type, sta_ds, session); + lim_send_sa_query_request_frame(mac_ctx, + (uint8_t *) &(sta_ds->pmfSaQueryCurrentTransId), + hdr->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, + eSIR_MAC_TRY_AGAIN_LATER, 1, + hdr->sa, sub_type, 0, session); + 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; + } + } +#endif + + /* 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; + } else { + /* + * 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, hdr->sa); + } else { + *auth_type = sta_ds->mlmStaContext.authType; + } + + *update_ctx = true; + if (dph_init_sta_state(mac_ctx, hdr->sa, peer_idx, true, + &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 + * @hdr: pointer to the MAC head + * @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(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession 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, hdr->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, + eSIR_MAC_QAP_NO_BANDWIDTH_REASON, + 1, hdr->sa, sub_type, 0, session); +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumAssocReqDropACRejectTS++; +#endif + return false; + } + } else if (lim_admit_control_add_sta(mac_ctx, hdr->sa, false) + != QDF_STATUS_SUCCESS) { + pe_warn("AdmitControl: Sta rejected"); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_QAP_NO_BANDWIDTH_REASON, 1, + hdr->sa, sub_type, 0, session); +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumAssocReqDropACRejectSta++; +#endif + return false; + } + /* else all ok */ + pe_debug("AdmitControl: Sta OK!"); + } + return true; +} + +/** + * lim_update_sta_ds() - updates ds dph entry + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @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 + * @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 + * + * Updates ds dph entry + * + * Return: true of no error, false otherwise + */ +static bool lim_update_sta_ds(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type, tpDphHashNode sta_ds, + tAniAuthType auth_type, + bool *assoc_req_copied, uint16_t peer_idx, + tHalBitVal qos_mode, bool pmf_connection) +{ + tHalBitVal wme_mode, wsm_mode; + uint8_t *ht_cap_ie = NULL; +#ifdef WLAN_FEATURE_11W + tPmfSaQueryTimerId timer_id; + uint32_t retry_interval; +#endif + 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 != NULL) { + tmp_assoc_req = session->parsedAssocReq[sta_ds->assocId]; + if (tmp_assoc_req != NULL) { + if (tmp_assoc_req->assocReqFrame) { + qdf_mem_free(tmp_assoc_req->assocReqFrame); + tmp_assoc_req->assocReqFrame = NULL; + tmp_assoc_req->assocReqFrameLength = 0; + } + qdf_mem_free(tmp_assoc_req); + tmp_assoc_req = NULL; + } + + session->parsedAssocReq[sta_ds->assocId] = assoc_req; + *assoc_req_copied = true; + } + + sta_ds->mlmStaContext.htCapability = assoc_req->HTCaps.present; + if ((vht_caps != NULL) && 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); + sta_ds->qos.addtsPresent = + (assoc_req->addtsPresent == 0) ? false : true; + sta_ds->qos.addts = assoc_req->addtsReq; + sta_ds->qos.capability = assoc_req->qosCapability; + sta_ds->versionPresent = 0; + /* + * 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->staType = STA_ENTRY_PEER; + + /* + * 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; + + /* + * The following count will be used to knock-off the station if it + * doesn't come back to receive the buffered data. The AP will wait + * for numTimSent number of beacons after sending TIM information for + * the station, before assuming that the station is no more associated + * and disassociates it + */ + + /* timWaitCount used by PMM for monitoring the STA's in PS for LINK */ + sta_ds->timWaitCount = + (uint8_t) GET_TIM_WAIT_COUNT(assoc_req->listenInterval); + + /* Init the Current successful MPDU's tranfered to this STA count = 0 */ + sta_ds->curTxMpduCnt = 0; + + if (IS_DOT11_MODE_HT(session->dot11mode) && + assoc_req->HTCaps.present && assoc_req->wmeInfoPresent) { + 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->htConfig.ht_sgi20) { + 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->htConfig.ht_sgi40) { + 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; + /* + * 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 = + (sta_ds->htSupportedChannelWidthSet) ? + session->htSecondaryChannelOffset : 0; + if (assoc_req->operMode.present) { + enum phy_ch_width ch_width; + + ch_width = assoc_req->operMode.chanWidth; + if (session->ch_width < ch_width) + ch_width = session->ch_width; + + sta_ds->vhtSupportedChannelWidthSet = + (uint8_t) ((ch_width == CH_WIDTH_80MHZ) ? + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ : + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ); + sta_ds->htSupportedChannelWidthSet = + (uint8_t) (ch_width ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ); + } else if ((vht_caps != NULL) && vht_caps->present) { + /* + * Check if STA has enabled it's channel bonding mode. + * If channel bonding mode is enabled, we decide based + * on SAP's current configuration. else, we set it to + * VHT20. + */ + sta_ds->vhtSupportedChannelWidthSet = + (uint8_t) ((sta_ds->htSupportedChannelWidthSet + == eHT_CHANNEL_WIDTH_20MHZ) ? + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ : + session->ch_width - 1); + sta_ds->htMaxRxAMpduFactor = + vht_caps->maxAMPDULenExp; + } + /* Lesser among the AP and STA bandwidth of operation. */ + sta_ds->htSupportedChannelWidthSet = + (sta_ds->htSupportedChannelWidthSet < + session->htSupportedChannelWidthSet) ? + sta_ds->htSupportedChannelWidthSet : + session->htSupportedChannelWidthSet; + + if (!sta_ds->htSupportedChannelWidthSet) + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + + sta_ds->baPolicyFlag = 0xFF; + sta_ds->htLdpcCapable = + (uint8_t) assoc_req->HTCaps.advCodingCap; + } + + if ((vht_caps != NULL) && vht_caps->present && + assoc_req->wmeInfoPresent) { + sta_ds->vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + } + + 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 (!assoc_req->wmeInfoPresent) { + sta_ds->mlmStaContext.htCapability = 0; + sta_ds->mlmStaContext.vhtCapability = 0; + } + + if (sta_ds->mlmStaContext.vhtCapability && vht_caps) { + 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); + } + + lim_intersect_sta_he_caps(assoc_req, 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) != QDF_STATUS_SUCCESS) { + /* Could not update hash table entry at DPH with rateset */ + pe_err("Couldn't update hash entry for aid: %d MacAddr: " + MAC_ADDRESS_STR, + peer_idx, MAC_ADDR_ARRAY(hdr->sa)); + + /* Release AID */ + lim_release_peer_idx(mac_ctx, peer_idx, session); + + lim_reject_association(mac_ctx, hdr->sa, + sub_type, true, auth_type, peer_idx, false, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + pe_err("Delete dph hash entry"); + if (dph_delete_hash_entry(mac_ctx, hdr->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.vhtRxMCSMap & 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; + +#ifdef WLAN_FEATURE_11W + 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; + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retry_interval) != QDF_STATUS_SUCCESS) { + pe_err("Couldn't get PMF SA Query retry interval value"); + lim_reject_association(mac_ctx, hdr->sa, sub_type, true, + auth_type, peer_idx, false, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + return false; + } + if (WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN > retry_interval) { + retry_interval = WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF; + } + if (sta_ds->rmfEnabled && + 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, hdr->sa, sub_type, + true, auth_type, peer_idx, false, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + return false; + } + if (sta_ds->rmfEnabled) + pe_debug("Created pmf timer sta-idx:%d assoc-id:%d", + sta_ds->staIndex, sta_ds->assocId); +#endif + + 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"); + } + 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(tpAniSirGlobal mac_ctx, tpPESession 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, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + 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 staId: %d", + sta_ds->assocId, sta_ds->staIndex); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + 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, + eSIR_MAC_WME_REFUSED_STATUS, + 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; +} + +/** + * 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 + * @tmp_assoc_req: pointer to tmp ASSOC/REASSOC Request frame + * @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 + */ +static void lim_process_assoc_cleanup(tpAniSirGlobal mac_ctx, + tpPESession session, + tpSirAssocReq assoc_req, + tpDphHashNode sta_ds, + bool *assoc_req_copied) +{ + tpSirAssocReq tmp_assoc_req; + + if (assoc_req != NULL) { + if (assoc_req->assocReqFrame) { + qdf_mem_free(assoc_req->assocReqFrame); + assoc_req->assocReqFrame = NULL; + assoc_req->assocReqFrameLength = 0; + } + + qdf_mem_free(assoc_req); + /* to avoid double free */ + if (*assoc_req_copied && session->parsedAssocReq) + session->parsedAssocReq[sta_ds->assocId] = NULL; + } + + /* If it is not duplicate Assoc request then only make to Null */ + if ((sta_ds != NULL) && + (sta_ds->mlmStaContext.mlmState != eLIM_MLM_WT_ADD_STA_RSP_STATE)) { + if (session->parsedAssocReq != NULL) { + tmp_assoc_req = + session->parsedAssocReq[sta_ds->assocId]; + if (tmp_assoc_req != NULL) { + if (tmp_assoc_req->assocReqFrame) { + qdf_mem_free( + tmp_assoc_req->assocReqFrame); + tmp_assoc_req->assocReqFrame = NULL; + tmp_assoc_req->assocReqFrameLength = 0; + } + qdf_mem_free(tmp_assoc_req); + session->parsedAssocReq[sta_ds->assocId] = NULL; + } + } + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + uint8_t sub_type, tpPESession session) +{ + bool pmf_connection = false, assoc_req_copied = false; + uint8_t update_ctx, *frm_body; + uint16_t peer_idx, assoc_id = 0; + uint32_t frame_len; + uint32_t phy_mode; + tHalBitVal qos_mode; + tpSirMacMgmtHdr hdr; + struct tLimPreAuthNode *sta_pre_auth_ctx; + tAniAuthType auth_type; + tSirMacCapabilityInfo local_cap; + tpDphHashNode sta_ds = NULL; + tpSirAssocReq assoc_req; + bool dup_entry = false; + QDF_STATUS status; + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + + limGetQosMode(session, &qos_mode); + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_debug("Rcvd: %s Req Frame sessionid: %d systemrole: %d MlmState: %d from: " + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, MAC_ADDR_ARRAY(hdr->sa)); + + if (LIM_IS_STA_ROLE(session)) { + pe_err("Rcvd unexpected ASSOC REQ, sessionid: %d sys sub_type: %d for role: %d from: " + MAC_ADDRESS_STR, + session->peSessionId, sub_type, + GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(hdr->sa)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + WMA_GET_RX_MPDU_DATA(rx_pkt_info), + frame_len); + return; + } + if (session->limMlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE) { + pe_err("drop ASSOC REQ on sessionid: %d " + "role: %d from: "MAC_ADDRESS_STR" in limMlmState: %d", + session->peSessionId, + GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(hdr->sa), + eLIM_MLM_WT_DEL_BSS_RSP_STATE); + 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 (NULL != sta_ds) { + 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: " + MAC_ADDRESS_STR, session->peSessionId, + sub_type, GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(hdr->sa)); + return; + } else if (!sta_ds->rmfEnabled && (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, + eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS, + sta_ds->assocId, sta_ds->staAddr, + sub_type, sta_ds, session); + pe_err("Rejecting reassoc req from STA"); + return; + } else if (!sta_ds->rmfEnabled) { + /* + * 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); + 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: " + MAC_ADDRESS_STR, + session->peSessionId, sub_type, + session->limSystemRole, + MAC_ADDR_ARRAY(hdr->sa)); + return; + } + } + + status = lim_check_sta_in_pe_entries(mac_ctx, hdr, 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. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, hdr->sa, + sub_type, 0, session); + return; + } + + /* Get pointer to Re/Association Request frame body */ + frm_body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + if (lim_is_group_addr(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" + MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, MAC_ADDR_ARRAY(hdr->sa)); + return; + } + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *) frm_body, frame_len); + + if (false == lim_chk_sa_da(mac_ctx, hdr, session, sub_type)) + return; + + if (false == lim_chk_tkip(mac_ctx, hdr, session, sub_type)) + return; + + /* 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); + return; + } + 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); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_STATUS, 1, hdr->sa, + sub_type, 0, session); + return; + } + } + /* Allocate memory for the Assoc Request frame */ + assoc_req = qdf_mem_malloc(sizeof(*assoc_req)); + if (NULL == assoc_req) { + pe_err("Allocate Memory failed in assoc_req"); + return; + } + + /* Parse Assoc Request frame */ + if (false == lim_chk_assoc_req_parse_error(mac_ctx, hdr, session, + assoc_req, sub_type, frm_body, frame_len)) + goto error; + + assoc_req->assocReqFrame = qdf_mem_malloc(frame_len); + if (NULL == assoc_req->assocReqFrame) { + pe_err("Memory alloc failed for the assoc req, len: %d", + frame_len); + goto error; + } + + qdf_mem_copy((uint8_t *) assoc_req->assocReqFrame, + (uint8_t *) frm_body, frame_len); + assoc_req->assocReqFrameLength = frame_len; + + if (false == lim_chk_capab(mac_ctx, hdr, session, assoc_req, + sub_type, &local_cap)) + goto error; + + update_ctx = false; + + if (false == lim_chk_ssid(mac_ctx, hdr, session, assoc_req, sub_type)) + goto error; + + if (false == lim_chk_rates(mac_ctx, hdr, session, assoc_req, sub_type)) + goto error; + + if (false == lim_chk_11g_only(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + if (false == lim_chk_11n_only(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + if (false == lim_chk_11ac_only(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + if (false == lim_chk_11ax_only(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + if (false == lim_check_11ax_basic_mcs(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + /* Spectrum Management (11h) specific checks */ + lim_process_for_spectrum_mgmt(mac_ctx, hdr, session, + assoc_req, sub_type, local_cap); + + if (false == lim_chk_mcs(mac_ctx, hdr, session, assoc_req, sub_type)) + goto error; + + if (false == lim_chk_is_11b_sta_supported(mac_ctx, hdr, 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 (false == lim_chk_n_process_wpa_rsn_ie(mac_ctx, hdr, session, + assoc_req, sub_type, &pmf_connection)) + goto error; + + /* Extract 'associated' context for STA, if any. */ + sta_ds = dph_lookup_hash_entry(mac_ctx, hdr->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, hdr->sa); + + if (sta_ds == NULL) { + if (false == lim_process_assoc_req_no_sta_ctx(mac_ctx, hdr, + session, assoc_req, sub_type, sta_pre_auth_ctx, + sta_ds, &auth_type)) + goto error; + } else { + if (false == lim_process_assoc_req_sta_ctx(mac_ctx, hdr, + session, assoc_req, sub_type, sta_pre_auth_ctx, + sta_ds, peer_idx, &auth_type, &update_ctx)) + goto error; + goto sendIndToSme; + } + + /* check if sta is allowed per QoS AC rules */ + if (false == lim_chk_wmm(mac_ctx, hdr, session, + assoc_req, sub_type, qos_mode)) + goto error; + + /* STA is Associated ! */ + pe_debug("Received: %s Req successful from " MAC_ADDRESS_STR, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->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) + */ + + peer_idx = lim_assign_peer_idx(mac_ctx, session); + + if (!peer_idx) { + /* Could not assign AID. Reject association */ + pe_err("PeerIdx not avaialble. Reject associaton"); + lim_reject_association(mac_ctx, hdr->sa, sub_type, + true, auth_type, peer_idx, false, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + goto error; + } + + /* Add an entry to hash table maintained by DPH module */ + + sta_ds = dph_add_hash_entry(mac_ctx, hdr->sa, peer_idx, + &session->dph.dphHashTable); + + if (sta_ds == NULL) { + /* Could not add hash table entry at DPH */ + pe_err("couldn't add hash entry at DPH for aid: %d MacAddr:" + MAC_ADDRESS_STR, peer_idx, MAC_ADDR_ARRAY(hdr->sa)); + + /* Release AID */ + lim_release_peer_idx(mac_ctx, peer_idx, session); + + lim_reject_association(mac_ctx, hdr->sa, sub_type, + true, auth_type, peer_idx, false, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + goto error; + } + +sendIndToSme: + if (false == lim_update_sta_ds(mac_ctx, hdr, session, assoc_req, + sub_type, sta_ds, auth_type, + &assoc_req_copied, peer_idx, qos_mode, + pmf_connection)) + goto error; + + + /* 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 != true) { + if (false == lim_update_sta_ctx(mac_ctx, session, assoc_req, + sub_type, sta_ds, update_ctx)) + goto error; + } + + /* 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->staIndex, + sta_ds->htMIMOPSState, sta_ds->staAddr, + session->smeSessionId); + } + + return; + +error: + lim_process_assoc_cleanup(mac_ctx, session, assoc_req, sta_ds, + &assoc_req_copied); + return; +} + +#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(tpAniSirGlobal mac_ctx, + tpSirAssocReq assoc_req, tpLimMlmAssocInd assoc_ind, + const uint8_t *wpsie) +{ + if (assoc_req->wapiPresent && (NULL == wpsie)) { + pe_debug("Received WAPI IE length in Assoc Req is %d", + assoc_req->wapi.length); + assoc_ind->wapiIE.wapiIEdata[0] = SIR_MAC_WAPI_EID; + 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; +} +#endif + +/** + * lim_fill_assoc_ind_vht_info() - Updates VHT 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_vht_info(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tpSirAssocReq assoc_req, + tpLimMlmAssocInd assoc_ind, + tpDphHashNode sta_ds) +{ + uint8_t chan; + uint8_t i; + bool nw_type_11b = true; + + if (session_entry->limRFBand == 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; + 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; + 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; + 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; + return; + } + + assoc_ind->chan_info.info = MODE_11NA_HT20; + return; + } + + assoc_ind->chan_info.info = MODE_11A; + return; +} + +static 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; +} + +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_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: None + */ +void lim_send_mlm_assoc_ind(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpPESession session_entry) +{ + tpLimMlmAssocInd assoc_ind = NULL; + tpSirAssocReq assoc_req; + uint16_t temp, rsn_len; + uint32_t phy_mode; + uint8_t sub_type; + const uint8_t *wpsie = NULL; + uint8_t maxidx, i; + uint32_t tmp; + + if (!session_entry->parsedAssocReq) { + pe_err(" Parsed Assoc req is NULL"); + return; + } + + /* 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; + } + + /* 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: %s sub_type: %d Associd: %d staAddr: " + MAC_ADDRESS_STR, session_entry->peSessionId, + assoc_req->ssId.ssId, sub_type, sta_ds->assocId, + MAC_ADDR_ARRAY(sta_ds->staAddr)); + + if (sub_type == LIM_ASSOC || sub_type == LIM_REASSOC) { + temp = sizeof(tLimMlmAssocInd); + + assoc_ind = qdf_mem_malloc(temp); + if (NULL == assoc_ind) { + lim_release_peer_idx(mac_ctx, sta_ds->assocId, + session_entry); + pe_err("AllocateMemory failed for assoc_ind"); + return; + } + qdf_mem_copy((uint8_t *) assoc_ind->peerMacAddr, + (uint8_t *) sta_ds->staAddr, 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->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 && (NULL == 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] = SIR_MAC_RSN_EID; + 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 && (NULL == wpsie)) { + rsn_len = assoc_ind->rsnIE.length; + if ((rsn_len + assoc_req->wpa.length) + >= SIR_MAC_MAX_IE_LENGTH) { + pe_err("rsnIEdata index out of bounds: %d", + rsn_len); + qdf_mem_free(assoc_ind); + return; + } + 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; + } +#ifdef FEATURE_WLAN_WAPI + lim_fill_assoc_ind_wapi_info(mac_ctx, assoc_req, assoc_ind, + wpsie); +#endif + + 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 < SIR_MAC_MAX_IE_LENGTH) { + assoc_ind->addIE.addIEdata[rsn_len] = + SIR_MAC_HT_CAPABILITIES_EID; + 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) { + if (wlan_cfg_get_int (mac_ctx, + (uint16_t) WNI_CFG_WME_ENABLED, &tmp) + != QDF_STATUS_SUCCESS) + pe_err("wlan_cfg_get_int failed for id: %d", + WNI_CFG_WME_ENABLED); + + /* check whether AP is enabled with WMM */ + if (tmp) + assoc_ind->WmmStaInfoPresent = 1; + else + assoc_ind->WmmStaInfoPresent = 0; + /* + * 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->beaconPtr = session_entry->beacon; + assoc_ind->beaconLength = session_entry->bcnLen; + + assoc_ind->chan_info.chan_id = + session_entry->currentOperChannel; + assoc_ind->chan_info.mhz = + cds_chan_to_freq(session_entry->currentOperChannel); + assoc_ind->chan_info.band_center_freq1 = + cds_chan_to_freq(session_entry->currentOperChannel); + 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 = 0xff; + assoc_ind->max_ext_idx = 0xff; + assoc_ind->max_mcs_idx = 0xff; + 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; + maxidx = 0; + for (i = 0; i < 8; i++) { + if (assoc_req->HTCaps.supportedMCSSet[0] & + (1 << i)) + maxidx = i; + } + assoc_ind->max_mcs_idx = maxidx; + } + 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; + + /* updates VHT information in assoc indication */ + qdf_mem_copy(&assoc_ind->vht_caps, &assoc_req->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_fill_assoc_ind_vht_info(mac_ctx, session_entry, assoc_req, + assoc_ind, sta_ds); + assoc_ind->he_caps_present = assoc_req->he_cap.present; + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_IND, + (uint32_t *) assoc_ind); + qdf_mem_free(assoc_ind); + } + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..2ef646a5e64c0fb843f7560f3ce70cdc6ad98595 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c @@ -0,0 +1,1077 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_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_sta_hash_api.h" +#include "lim_send_messages.h" +#include "lim_process_fils.h" + +extern QDF_STATUS sch_beacon_edca_process(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *edca, tpPESession psessionEntry); + +/** + * 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(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession 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; + /* + * FIXME_AMPDU + * In the future, may need to check for + * "assoc.HTCaps.delayedBA" + * For now, it is IMMEDIATE BA only on ALL TID's + */ + sta_ds->baPolicyFlag = 0xFF; + + /* Check if we have support for gShortGI20Mhz and + * gShortGI40Mhz from ini file + */ + if (session_entry->htConfig.ht_sgi20) + sta_ds->htShortGI20Mhz = + (uint8_t)assoc_rsp->HTCaps.shortGI20MHz; + else + sta_ds->htShortGI20Mhz = false; + + if (session_entry->htConfig.ht_sgi40) + 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(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession session_entry) +{ + uint32_t phy_mode; + bool qos_mode; + tDot11fIEVHTCaps *vht_caps = NULL; + tDot11fIEhe_cap *he_cap = NULL; + + 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; + else if (assoc_rsp->vendor_vht_ie.VHTCaps.present) + vht_caps = &assoc_rsp->vendor_vht_ie.VHTCaps; + + if (IS_DOT11_MODE_VHT(session_entry->dot11mode)) { + if ((vht_caps != NULL) && 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 (assoc_rsp->VHTOperation.present) + sta_ds->vhtSupportedChannelWidthSet = + assoc_rsp->VHTOperation.chanWidth; + else + sta_ds->vhtSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } + } + } + + if (IS_DOT11_MODE_HE(session_entry->dot11mode)) + lim_update_stads_he_caps(sta_ds, assoc_rsp, session_entry); + + if (lim_is_sta_he_capable(sta_ds)) + he_cap = &assoc_rsp->he_cap; + + if (lim_populate_peer_rate_set(mac_ctx, &sta_ds->supportedRates, + assoc_rsp->HTCaps.supportedMCSSet, + false, session_entry, + vht_caps, he_cap) != QDF_STATUS_SUCCESS) { + pe_err("could not get rateset and extended rate set"); + return; + } + sta_ds->vhtSupportedRxNss = + ((sta_ds->supportedRates.vhtRxMCSMap & 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; + + 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; + + 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; + } +#ifdef WLAN_FEATURE_11W + if (session_entry->limRmfEnabled) + sta_ds->rmfEnabled = 1; +#endif +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->ricData != NULL) { + 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 (NULL == session_entry->ricData) { + pe_err("No memory for RIC data"); + 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 { + pe_debug("Ric is not present"); + 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(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->tspecIes != NULL) { + 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 (NULL == session_entry->tspecIes) { + pe_err("Tspec IE:Fail to allocate memory"); + 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; + pe_debug("Tspec EID *NOT* present in assoc rsp"); + } + 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(tpAniSirGlobal mac_ctx, + tpPESession 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_err("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) == + EDCA_AC_VO) { + tsm_ctx->tid = + assoc_rsp->TSPECInfo[cnt].user_priority; + qdf_mem_copy(&tsm_ctx->tsmInfo, + &assoc_rsp->tsmIE, sizeof(tSirMacESETSMIE)); + 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 capablities. + * + * Return: None + */ +static void lim_update_stads_ext_cap(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp, + tpDphHashNode sta_ds) +{ + struct s_ext_cap *ext_cap; + + if (!assoc_rsp->ExtCap.present) { + sta_ds->timingMeasCap = 0; +#ifdef FEATURE_WLAN_TDLS + session_entry->tdls_prohibited = false; + session_entry->tdls_chan_swit_prohibited = 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); +#ifdef FEATURE_WLAN_TDLS + session_entry->tdls_prohibited = ext_cap->tdls_prohibited; + session_entry->tdls_chan_swit_prohibited = + 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(tpAniSirGlobal mac_ctx) +{ + mac_ctx->lim.reAssocRetryAttempt = 0; + if ((NULL != mac_ctx->lim.pSessionEntry) + && (NULL != + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq)) { + qdf_mem_free( + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq); + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq = NULL; + } + lim_deactivate_and_change_timer(mac_ctx, eLIM_REASSOC_FAIL_TIMER); +} + +#ifdef WLAN_FEATURE_11W +static void lim_handle_assoc_reject_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tpSirAssocRsp assoc_rsp, + tSirMacAddr source_addr) +{ + struct sir_rssi_disallow_lst ap_info = {{0}}; + uint32_t timeout_value = + assoc_rsp->TimeoutInterval.timeoutValue; + + if (!(session_entry->limRmfEnabled && + assoc_rsp->statusCode == eSIR_MAC_TRY_AGAIN_LATER && + (assoc_rsp->TimeoutInterval.present && + (assoc_rsp->TimeoutInterval.timeoutType == + SIR_MAC_TI_TYPE_ASSOC_COMEBACK)))) + return; + + /* + * Add to rssi reject list, which takes care of retry + * delay too. Fill the RSSI as 0, so the only param + * which will allow the bssid to connect is retry delay. + */ + ap_info.retry_delay = timeout_value; + qdf_mem_copy(ap_info.bssid.bytes, source_addr, + QDF_MAC_ADDR_SIZE); + ap_info.expected_rssi = LIM_MIN_RSSI; + lim_assoc_rej_add_to_rssi_based_reject_list(mac_ctx, + &ap_info); + + pe_debug("ASSOC res with eSIR_MAC_TRY_AGAIN_LATER recvd. Add to time reject list(rssi reject in mac_ctx %d", + timeout_value); +} +#else +static void lim_handle_assoc_reject_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tpSirAssocRsp assoc_rsp, + tSirMacAddr source_addr) +{ +} +#endif + +/** + * 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 + * @sub_type - Indicates whether it is Association Response (=0) or + * Reassociation Response (=1) frame + * + * This function is called by limProcessMessageQueue() upon + * Re/Association Response frame reception. + * + * Return: None + */ + +void +lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, uint8_t subtype, tpPESession session_entry) +{ + uint8_t *body; + uint16_t caps, ie_len; + uint32_t frame_len; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr hdr = NULL; + tSirMacCapabilityInfo mac_capab; + tpDphHashNode sta_ds; + tpSirAssocRsp assoc_rsp; + tLimMlmAssocCnf assoc_cnf; + tSchBeaconStruct *beacon; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t sme_sessionid = 0; + struct csr_roam_session *roam_session; +#endif + tSirMacEdcaParamRecord mu_edca_set[MAX_NUM_AC]; + + /* Initialize status code to success. */ + if (lim_is_roam_synch_in_progress(session_entry)) + hdr = (tpSirMacMgmtHdr) mac_ctx->roam.pReassocResp; + else + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + sme_sessionid = session_entry->smeSessionId; +#endif + assoc_cnf.resultCode = eSIR_SME_SUCCESS; + /* Update PE session Id */ + assoc_cnf.sessionId = session_entry->peSessionId; + if (hdr == NULL) { + pe_err("LFR3: Reassoc response packet header is NULL"); + return; + } + + pe_debug("received Re/Assoc: %d resp on sessionid: %d systemrole: %d" + " and mlmstate: %d RSSI: %d from "MAC_ADDRESS_STR, subtype, + session_entry->peSessionId, GET_LIM_SYSTEM_ROLE(session_entry), + session_entry->limMlmState, + (uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info)), + MAC_ADDR_ARRAY(hdr->sa)); + + beacon = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == beacon) { + pe_err("Unable to allocate memory"); + return; + } + + 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)); + qdf_mem_free(beacon); + return; + } + if (lim_is_roam_synch_in_progress(session_entry)) { + hdr = (tpSirMacMgmtHdr) mac_ctx->roam.pReassocResp; + frame_len = mac_ctx->roam.reassocRespLen - SIR_MAC_HDR_LEN_3A; + } else { + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + } + if (((subtype == LIM_ASSOC) && + (session_entry->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE)) || + ((subtype == LIM_REASSOC) && + !lim_is_roam_synch_in_progress(session_entry) && + ((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 "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + 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 "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdr->sa)); + qdf_mem_free(beacon); + return; + } + } + + assoc_rsp = qdf_mem_malloc(sizeof(*assoc_rsp)); + if (NULL == assoc_rsp) { + pe_err("Allocate Memory failed in AssocRsp"); + qdf_mem_free(beacon); + return; + } + /* Get pointer to Re/Association Response frame body */ + if (lim_is_roam_synch_in_progress(session_entry)) + body = mac_ctx->roam.pReassocResp + 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_len, assoc_rsp) == QDF_STATUS_E_FAILURE) { + qdf_mem_free(assoc_rsp); + pe_err("Parse error Assoc resp subtype: %d" "length: %d", + frame_len, subtype); + qdf_mem_free(beacon); + 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->statusCode; + if (session_entry->assocRsp != NULL) { + 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_len) { + session_entry->assocRsp = qdf_mem_malloc(frame_len); + if (NULL == session_entry->assocRsp) { + pe_err("Unable to allocate memory for assoc res,len: %d", + frame_len); + } else { + /* + * Store the Assoc response. This is sent + * to csr/hdd in join cnf response. + */ + qdf_mem_copy(session_entry->assocRsp, body, frame_len); + session_entry->assocRspLen = frame_len; + } + } + + lim_update_ric_data(mac_ctx, session_entry, assoc_rsp); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + roam_session = + &mac_ctx->roam.roamSession[sme_sessionid]; + if (assoc_rsp->FTInfo.R0KH_ID.present) { + roam_session->ftSmeContext.r0kh_id_len = + assoc_rsp->FTInfo.R0KH_ID.num_PMK_R0_ID; + qdf_mem_copy(roam_session->ftSmeContext.r0kh_id, + assoc_rsp->FTInfo.R0KH_ID.PMK_R0_ID, + roam_session->ftSmeContext.r0kh_id_len); + } else { + roam_session->ftSmeContext.r0kh_id_len = 0; + qdf_mem_zero(roam_session->ftSmeContext.r0kh_id, + SIR_ROAM_R0KH_ID_MAX_LEN); + } +#endif + +#ifdef FEATURE_WLAN_ESE + lim_update_ese_tspec(mac_ctx, session_entry, assoc_rsp); +#endif + + if (assoc_rsp->capabilityInfo.ibss) { + /* + * Received Re/Association Response from peer + * with IBSS capability set. + * Ignore the frame and wait until Re/assoc + * failure timeout. + */ + pe_err("received Re/AssocRsp frame with IBSS capability"); + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + return; + } + + if (cfg_get_capability_info(mac_ctx, &caps, session_entry) + != QDF_STATUS_SUCCESS) { + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + pe_err("could not retrieve Capabilities"); + return; + } + lim_copy_u16((uint8_t *) &mac_capab, caps); + + /* 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); + + lim_handle_assoc_reject_status(mac_ctx, session_entry, assoc_rsp, + hdr->sa); + + if (eSIR_MAC_XS_FRAME_LOSS_POOR_CHANNEL_RSSI_STATUS == + assoc_rsp->statusCode && + assoc_rsp->rssi_assoc_rej.present) { + struct sir_rssi_disallow_lst ap_info = {{0}}; + + 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.expected_rssi = assoc_rsp->rssi_assoc_rej.delta_rssi + + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + lim_assoc_rej_add_to_rssi_based_reject_list(mac_ctx, + &ap_info); + } + if (assoc_rsp->statusCode != eSIR_MAC_SUCCESS_STATUS) { + /* + *Re/Association response was received + * either with failure code. + */ + pe_err("received Re/AssocRsp frame failure code: %d", + assoc_rsp->statusCode); + /* + * 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 = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + 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 doesnot match"); + assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + hdr->sa, session_entry, false); + goto assocReject; + } + + /* + * Association Response received with success code + * Set the link state to POSTASSOC now that we have received + * assoc/reassoc response + * NOTE: for BTAMP case, it is being handled in + * lim_process_mlm_assoc_req + */ + if (!lim_is_roam_synch_in_progress(session_entry)) { + if (lim_set_link_state + (mac_ctx, eSIR_LINK_POSTASSOC_STATE, + session_entry->bssId, + session_entry->selfMacAddr, NULL, + NULL) != QDF_STATUS_SUCCESS) { + pe_err("Set link state to POSTASSOC failed"); + qdf_mem_free(beacon); + qdf_mem_free(assoc_rsp); + return; + } + } + + if (assoc_rsp->QosMapSet.present) + qdf_mem_copy(&session_entry->QosMapSet, + &assoc_rsp->QosMapSet, sizeof(tSirQosMapSet)); + else + qdf_mem_zero(&session_entry->QosMapSet, sizeof(tSirQosMapSet)); + + if (assoc_rsp->obss_scanparams.present) + lim_update_obss_scanparams(session_entry, + &assoc_rsp->obss_scanparams); + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + session_entry, assoc_rsp->statusCode ? QDF_STATUS_E_FAILURE : + QDF_STATUS_SUCCESS, assoc_rsp->statusCode); + + 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; + } + + 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"); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGE); + assoc_cnf.resultCode = + eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, hdr->sa, + session_entry, false); + goto assocReject; + } + if ((session_entry->limMlmState == + eLIM_MLM_WT_FT_REASSOC_RSP_STATE) || + lim_is_roam_synch_in_progress(session_entry)) { + pe_debug("Sending self sta"); + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, + session_entry); + 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(session_entry)) { + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + sta_ds->bssId, false); + lim_add_ft_sta_self(mac_ctx, + (assoc_rsp->aid & 0x3FFF), + session_entry); + } + 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; + + if (lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry) + != QDF_STATUS_SUCCESS) { + pe_err("Could not cleanup the rx path"); + goto assocReject; + } + } + qdf_mem_free(beacon); + return; + } + pe_debug("Successfully Associated with BSS " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 == NULL) { + /* Could not add hash table entry */ + pe_err("could not get hash entry at DPH"); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGE); + 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); + 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); + + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, session_entry); + /* + * Extract the AP capabilities from the beacon that + * was received earlier + */ + ie_len = lim_get_ielen_from_bss_description( + &session_entry->pLimJoinReq->bssDescription); + lim_extract_ap_capabilities(mac_ctx, + (uint8_t *) session_entry->pLimJoinReq->bssDescription.ieFields, + ie_len, + beacon); + + if (lim_is_session_he_capable(session_entry) && + assoc_rsp->mu_edca_present) { + pe_debug("Send MU EDCA params to FW"); + mu_edca_set[EDCA_AC_BE] = assoc_rsp->mu_edca.acbe; + mu_edca_set[EDCA_AC_BK] = assoc_rsp->mu_edca.acbk; + mu_edca_set[EDCA_AC_VI] = assoc_rsp->mu_edca.acvi; + mu_edca_set[EDCA_AC_VO] = assoc_rsp->mu_edca.acvo; + lim_send_edca_params(mac_ctx, mu_edca_set, + sta_ds->bssId, true); + + } + + 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; + + if (mac_ctx->lim.gLimProtectionControl != + WNI_CFG_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->pLimJoinReq->bssDescription, true, + session_entry)) { + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + return; + } else { + pe_err("could not update the bss entry"); + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + } + +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:" + MAC_ADDRESS_STR, + session_entry->limMlmState, + session_entry->peSessionId, + assoc_cnf.resultCode, MAC_ADDR_ARRAY(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); + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..51ec06b159e74a939a758bfa79a34c8b77c5476b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c @@ -0,0 +1,1646 @@ +/* + * 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. + */ + +/* + * + * 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_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" + +/** + * 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 + * SIR_MAC_CHALLENGE_TEXT_EID by parser + * - + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param *auth - Pointer to extracted auth frame body + * + * @return 0 or 1 (Valid) + */ + +static inline unsigned int is_auth_valid(tpAniSirGlobal pMac, + tpSirMacAuthFrameBody auth, + tpPESession sessionEntry) +{ + unsigned int valid = 1; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_1) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3)) && + (LIM_IS_STA_ROLE(sessionEntry))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (LIM_IS_AP_ROLE(sessionEntry))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (auth->type != SIR_MAC_CHALLENGE_TEXT_EID) && + (auth->authAlgoNumber != eSIR_SHARED_KEY)) + valid = 0; + + return valid; +} + +static void lim_process_auth_shared_system_algo(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + tpPESession 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 if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_PRIVACY_ENABLED, &val) != QDF_STATUS_SUCCESS) + pe_warn("couldnt retrieve Privacy option"); + cfg_privacy_opt_imp = (uint8_t) val; + if (!cfg_privacy_opt_imp) { + pe_err("rx Auth frame for unsupported auth algorithm %d " + MAC_ADDRESS_STR, + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + 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 == NULL) { + pe_warn("Max preauth-nodes reached"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + 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 ", + auth_node, auth_node->authNodeIdx); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + /* / 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"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + + /* + * 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 = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + 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"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = eSIR_MAC_TRY_AGAIN_LATER; + 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 = eSIR_MAC_SUCCESS_STATUS; + auth_frame->type = SIR_MAC_CHALLENGE_TEXT_EID; + 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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + tpPESession 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 == NULL) { + pe_warn("Max pre-auth nodes reached "); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + return; + } + pe_debug("Alloc new data: %pK peer", auth_node); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + 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(); + 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 = eSIR_MAC_SUCCESS_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); +} + +#ifdef WLAN_FEATURE_SAE +/** + * 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(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession pe_session) +{ + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + uint8_t *body_ptr; + + 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 SAE Auth frame type %d subtype %d", + mac_hdr->fc.type, mac_hdr->fc.subType); + + if (pe_session->limMlmState != eLIM_MLM_WT_SAE_AUTH_STATE) + pe_err("received SAE auth response in unexpected state %x", + pe_session->limMlmState); + + lim_send_sme_mgmt_frame_ind(mac_ctx, mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(rx_pkt_info), pe_session, + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info)); +} +#else +static inline void lim_process_sae_auth_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession pe_session) +{} +#endif + +static void lim_process_auth_frame_type1(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + uint8_t *rx_pkt_info, uint16_t curr_seq_num, + tSirMacAuthFrameBody *auth_frame, tpPESession pe_session) +{ + tpDphHashNode sta_ds_ptr = NULL; + struct tLimPreAuthNode *auth_node; + uint32_t maxnum_preauth; + uint16_t associd = 0; + + /* AuthFrame 1 */ + sta_ds_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, + &associd, &pe_session->dph.dphHashTable); + if (sta_ds_ptr) { + tLimMlmDisassocReq *pMlmDisassocReq = NULL; + tLimMlmDeauthReq *pMlmDeauthReq = NULL; + bool isConnected = true; + + pMlmDisassocReq = + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (pMlmDisassocReq && + (!qdf_mem_cmp((uint8_t *) mac_hdr->sa, (uint8_t *) + &pMlmDisassocReq->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + pe_debug("TODO:Ack for disassoc frame is pending Issue delsta for " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + pMlmDisassocReq->peer_macaddr.bytes)); + lim_process_disassoc_ack_timeout(mac_ctx); + isConnected = false; + } + pMlmDeauthReq = + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (pMlmDeauthReq && + (!qdf_mem_cmp((uint8_t *) mac_hdr->sa, (uint8_t *) + &pMlmDeauthReq->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + pe_debug("TODO:Ack for deauth frame is pending Issue delsta for " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + pMlmDeauthReq->peer_macaddr.bytes)); + lim_process_deauth_ack_timeout(mac_ctx); + isConnected = false; + } + + /* + * pStaDS != NULL and isConnected = 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 (isConnected +#ifdef WLAN_FEATURE_11W + && !sta_ds_ptr->rmfEnabled +#endif + ) { + pe_err("STA is already connected but received auth frame" + "Send the Deauth and lim Delete Station Context" + "(staId: %d, associd: %d) ", + sta_ds_ptr->staIndex, associd); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *) mac_hdr->sa, + pe_session, false); + lim_trigger_sta_deletion(mac_ctx, sta_ds_ptr, + pe_session); + 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 (NULL == 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 (NULL != sta_ds_ptr +#ifdef WLAN_FEATURE_11W + && !sta_ds_ptr->rmfEnabled +#endif + ) { + pe_debug("lim Delete Station Context staId: %d associd: %d", + sta_ds_ptr->staIndex, associd); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *)auth_node->peerMacAddr, + pe_session, false); + lim_trigger_sta_deletion(mac_ctx, sta_ds_ptr, + pe_session); + return; + } + } + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_MAX_NUM_PRE_AUTH, + (uint32_t *) &maxnum_preauth) != QDF_STATUS_SUCCESS) + pe_warn("could not retrieve MaxNumPreAuth"); + + 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 = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + 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)) { + + if (lim_get_session_by_macaddr(mac_ctx, mac_hdr->sa)) { + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_WME_INVALID_PARAMS_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + 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 " + MAC_ADDRESS_STR, + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + 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 " + MAC_ADDRESS_STR, + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + 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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + uint8_t *plainbody, + uint8_t *body_ptr, uint16_t frame_len, + tpPESession pe_session) +{ + uint8_t key_id, cfg_privacy_opt_imp; + uint32_t val, key_length = 8; + uint8_t defaultkey[SIR_MAC_KEY_LENGTH]; + struct tLimPreAuthNode *auth_node; + uint8_t *encr_auth_frame; + + /* 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 == + eSIR_MAC_SUCCESS_STATUS) && + (pe_session->ftPEContext.pFTPreAuthReq != NULL) && + (!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: %pM", + pe_session->limSmeState, mac_hdr->sa); + pe_session->ftPEContext.saved_auth_rsp_length = 0; + + if ((body_ptr != NULL) && (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", + pe_session->limMlmState); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + } + 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" + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authStatusCode == + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS) { + /* + * 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" + MAC_ADDRESS_STR, + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + } + + if (rx_auth_frm_body->authStatusCode != eSIR_MAC_SUCCESS_STATUS) { + /* + * Authentication failure. + * Return Auth confirm with received failure code to SME + */ + pe_err("rx Auth frame from peer with failure code %d " + MAC_ADDRESS_STR, + rx_auth_frm_body->authStatusCode, + MAC_ADDR_ARRAY(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 == NULL) { + pe_warn("Max pre-auth nodes reached"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + return; + } + + pe_debug("Alloc new data: %pK peer", auth_node); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + 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)) + val = pe_session->privacy; + else if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_PRIVACY_ENABLED, + &val) != QDF_STATUS_SUCCESS) + pe_warn("couldnt retrieve Privacy option"); + cfg_privacy_opt_imp = (uint8_t) val; + 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 " + MAC_ADDRESS_STR, + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + 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 != SIR_MAC_CHALLENGE_TEXT_EID) { + pe_err("rx auth frm with invalid challenge txtie"); + return; + } + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_WEP_DEFAULT_KEYID, + &val) != QDF_STATUS_SUCCESS) + pe_warn("could not retrieve Default key_id"); + key_id = (uint8_t) val; + val = SIR_MAC_KEY_LENGTH; + if (LIM_IS_AP_ROLE(pe_session)) { + tpSirKeys key_ptr = + &pe_session->WEPKeyMaterial[key_id].key[0]; + qdf_mem_copy(defaultkey, key_ptr->key, + key_ptr->keyLength); + } else if (wlan_cfg_get_str(mac_ctx, + (uint16_t)(WNI_CFG_WEP_DEFAULT_KEY_1 + key_id), + defaultkey, &val) != QDF_STATUS_SUCCESS) { + /* Couldnt get Default key from CFG. */ + 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 = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + 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, + eSIR_MAC_UNSPEC_FAILURE_REASON, + 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 = + eSIR_MAC_SUCCESS_STATUS; + ((tpSirMacAuthFrameBody)plainbody)->type = + SIR_MAC_CHALLENGE_TEXT_EID; + ((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) { + pe_err("failed to allocate memory"); + 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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + tpPESession 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 " + MAC_ADDRESS_STR, + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + 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) || + LIM_IS_IBSS_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 " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + 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 == NULL) { + pe_warn("received AuthFrame3 from peer that has no preauth context " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + 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 " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS; + + 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 != + eSIR_MAC_SUCCESS_STATUS) { + /* + * 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 " + MAC_ADDRESS_STR, + rx_auth_frm_body->authStatusCode, + MAC_ADDR_ARRAY(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 autheticated + * 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 = + eSIR_MAC_SUCCESS_STATUS; + 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 "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + 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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tpPESession 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 " + MAC_ADDRESS_STR, + pe_session->limMlmState, + MAC_ADDR_ARRAY(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" + MAC_ADDRESS_STR, + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(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 "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 " + MAC_ADDRESS_STR, + rx_auth_frm_body->authTransactionSeqNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authStatusCode == eSIR_MAC_SUCCESS_STATUS) { + /* + * 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 == NULL) { + pe_warn("Max pre-auth nodes reached"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + return; + } + pe_debug("Alloc new data: %pK peer", auth_node); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + 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 "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 alogirthm 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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession 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 val, key_length = 8; + tSirMacAuthFrameBody *rx_auth_frm_body, *rx_auth_frame, *auth_frame; + tpSirMacMgmtHdr mac_hdr; + struct tLimPreAuthNode *auth_node; + + /* 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: %pM", + mac_hdr->sa); + return; + } + + if (lim_is_group_addr(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: %pM", + mac_hdr->sa); + return; + } + curr_seq_num = (mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo); + + pe_debug("Sessionid: %d System role: %d limMlmState: %d: Auth response Received BSSID: "MAC_ADDRESS_STR" RSSI: %d", + pe_session->peSessionId, GET_LIM_SYSTEM_ROLE(pe_session), + pe_session->limMlmState, MAC_ADDR_ARRAY(mac_hdr->bssId), + (uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info))); + + if (pe_session->prev_auth_seq_num == curr_seq_num && + mac_hdr->fc.retry) { + pe_debug("auth frame, seq num: %d is already processed, drop it", + curr_seq_num); + return; + } + + /* save seq number in pe_session */ + pe_session->prev_auth_seq_num = curr_seq_num; + + 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_debug("auth_alg %d ", auth_alg); + + /* Restore default failure timeout */ + if (QDF_P2P_CLIENT_MODE == pe_session->pePersona && + pe_session->defaultAuthFailureTimeout) { + pe_debug("Restore default failure timeout"); + cfg_set_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + pe_session->defaultAuthFailureTimeout); + } + + rx_auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!rx_auth_frame) { + pe_err("failed to allocate memory"); + return; + } + + auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!auth_frame) { + pe_err("failed to allocate memory"); + goto free; + } + + plainbody = qdf_mem_malloc(LIM_ENCR_AUTH_BODY_LEN); + if (!plainbody) { + pe_err("failed to allocate memory for 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 TKIP counter measures enabled then issue Deauth + * frame to station + */ + if (pe_session->bTkipCntrMeasActive && + LIM_IS_AP_ROLE(pe_session)) { + pe_err("Tkip counter enabled, send deauth to: %pM", + mac_hdr->sa); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_MIC_FAILURE_REASON, + mac_hdr->sa, pe_session, false); + goto free; + } + 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 = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + /* Log error */ + pe_err("rx Auth frm with wep bit set role: %d %pM", + GET_LIM_SYSTEM_ROLE(pe_session), 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", + frame_len); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGE); + goto free; + } + if (LIM_IS_AP_ROLE(pe_session)) { + val = pe_session->privacy; + } else if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &val) != QDF_STATUS_SUCCESS) { + /* + * Accept Authentication frame only if Privacy is + * implemented, if Could not get Privacy option + * from CFG then Log fatal error + */ + pe_warn("could not retrieve Privacy option"); + } + cfg_privacy_opt_imp = (uint8_t) val; + + if (!cfg_privacy_opt_imp) { + pe_err("received Authentication frame3 from peer that while privacy option is turned OFF " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + 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 + */ + auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (auth_node == NULL) { + pe_err("rx Auth frame with no preauth ctx with WEP bit set " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + 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 " + MAC_ADDRESS_STR, + auth_node->mlmState, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + + 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)) { + tpSirKeys key_ptr; + + key_ptr = &pe_session->WEPKeyMaterial[key_id].key[0]; + qdf_mem_copy(defaultkey, key_ptr->key, + key_ptr->keyLength); + val = key_ptr->keyLength; + } else if (wlan_cfg_get_str(mac_ctx, + (uint16_t) (WNI_CFG_WEP_DEFAULT_KEY_1 + key_id), + defaultkey, &val) != QDF_STATUS_SUCCESS) { + 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 = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + 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: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + 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) && (LIM_IS_STA_ROLE(pe_session))) { + lim_process_sae_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; + + pe_debug("Received Auth frame with type: %d seqnum: %d status: %d %d", + (uint32_t) rx_auth_frm_body->authAlgoNumber, + (uint32_t) rx_auth_frm_body->authTransactionSeqNumber, + (uint32_t) rx_auth_frm_body->authStatusCode, + (uint32_t) mac_ctx->lim.gLimNumPreAuthContexts); + + 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; + } + + + 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: %pM", + rx_auth_frm_body->authTransactionSeqNumber, + 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); +} + +/*---------------------------------------------------------------------- + * + * 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. + * + * !!!! This is going to be renoved for the next checkin. We will be creating + * the session before sending out the Auth. Thus when auth response + * is received we will have a session in progress. !!!!! + ***---------------------------------------------------------------------- + */ +QDF_STATUS lim_process_auth_frame_no_session(tpAniSirGlobal pMac, uint8_t *pBd, + void *body) +{ + tpSirMacMgmtHdr pHdr; + tpPESession psessionEntry = NULL; + uint8_t *pBody; + uint16_t frameLen; + tSirMacAuthFrameBody rxAuthFrame; + tSirMacAuthFrameBody *pRxAuthFrameBody = NULL; + QDF_STATUS ret_status = QDF_STATUS_E_FAILURE; + int i; + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + pBody = WMA_GET_RX_MPDU_DATA(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + pe_debug("Auth Frame Received: BSSID " MAC_ADDRESS_STR " (RSSI %d)", + MAC_ADDR_ARRAY(pHdr->bssId), + (uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(pBd))); + + /* 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 < pMac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (pMac->lim.gpSession[i].valid == true && + pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession == + true) { + /* Found the session */ + psessionEntry = &pMac->lim.gpSession[i]; + pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession = + false; + } + } + + if (psessionEntry == NULL) { + pe_debug("cannot find session id in FT pre-auth phase"); + return QDF_STATUS_E_FAILURE; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq == NULL) { + pe_err("Error: No FT"); + /* No FT in progress. */ + return QDF_STATUS_E_FAILURE; + } + + if (frameLen == 0) { + pe_err("Error: Frame len = 0"); + return QDF_STATUS_E_FAILURE; + } + lim_print_mac_addr(pMac, pHdr->bssId, LOGD); + lim_print_mac_addr(pMac, + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + LOGD); + pe_debug("seqControl: 0x%X", + ((pHdr->seqControl.seqNumHi << 8) | + (pHdr->seqControl.seqNumLo << 4) | + (pHdr->seqControl.fragNum))); + + /* Check that its the same bssId we have for preAuth */ + if (qdf_mem_cmp + (psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + pHdr->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 == + psessionEntry->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)", psessionEntry, + psessionEntry); + return QDF_STATUS_SUCCESS; + } else { + pe_warn("Auth rsp not yet posted to SME" + " (session %pK, FT session %pK)", psessionEntry, + psessionEntry); + psessionEntry->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = + true; + } + + /* Stopping timer now, that we have our unicast from the AP */ + /* of our choice. */ + lim_deactivate_and_change_timer(pMac, eLIM_FT_PREAUTH_RSP_TIMER); + + /* Save off the auth resp. */ + if ((sir_convert_auth_frame2_struct(pMac, pBody, frameLen, &rxAuthFrame) != + QDF_STATUS_SUCCESS)) { + pe_err("failed to convert Auth frame to struct"); + lim_handle_ft_pre_auth_rsp(pMac, QDF_STATUS_E_FAILURE, NULL, 0, + psessionEntry); + return QDF_STATUS_E_FAILURE; + } + pRxAuthFrameBody = &rxAuthFrame; + + pe_debug("Received Auth frame with type: %d seqnum: %d status: %d %d", + (uint32_t) pRxAuthFrameBody->authAlgoNumber, + (uint32_t) pRxAuthFrameBody->authTransactionSeqNumber, + (uint32_t) pRxAuthFrameBody->authStatusCode, + (uint32_t) pMac->lim.gLimNumPreAuthContexts); + switch (pRxAuthFrameBody->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_2: + if (pRxAuthFrameBody->authStatusCode != eSIR_MAC_SUCCESS_STATUS) { + pe_err("Auth status code received is %d", + (uint32_t) pRxAuthFrameBody->authStatusCode); + if (eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS == + pRxAuthFrameBody->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) pRxAuthFrameBody->authTransactionSeqNumber); + break; + } + + /* Send the Auth response to SME */ + lim_handle_ft_pre_auth_rsp(pMac, ret_status, pBody, frameLen, psessionEntry); + + return ret_status; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..c1d61e5146f434d4c23513cd9654efb76e53b516 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c @@ -0,0 +1,139 @@ +/* + * 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_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 "cfg_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_prop_exts_utils.h" +#include "lim_ser_des_utils.h" + +/** + * 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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + tSchBeaconStruct *bcn_ptr; + + mac_ctx->lim.gLimNumBeaconsRcvd++; + + /* + * here is it required to increment session specific heartBeat + * beacon counter + */ + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + pe_debug("Received Beacon frame with length: %d from", + WMA_GET_RX_MPDU_LEN(rx_pkt_info)); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG2); + + /* Expect Beacon in any state as Scan is independent of LIM state */ + bcn_ptr = qdf_mem_malloc(sizeof(*bcn_ptr)); + if (NULL == bcn_ptr) { + pe_err("Unable to allocate memory"); + 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; + } + + /* + * 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) { + if (session->beacon != NULL) { + qdf_mem_free(session->beacon); + session->beacon = NULL; + session->bcnLen = 0; + } + session->bcnLen = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + session->beacon = qdf_mem_malloc(session->bcnLen); + if (NULL == session->beacon) { + pe_err("fail to alloc mem to store bcn"); + } else { + /* + * Store the Beacon/ProbeRsp. This is sent to + * csr/hdd in join cnf response. + */ + qdf_mem_copy(session->beacon, + WMA_GET_RX_MPDU_DATA(rx_pkt_info), + session->bcnLen); + } + lim_check_and_announce_join_success(mac_ctx, bcn_ptr, + mac_hdr, session); + } + qdf_mem_free(bcn_ptr); + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c new file mode 100644 index 0000000000000000000000000000000000000000..c72369ba8796a26594f66a9ec7e4879ae8aa0802 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c @@ -0,0 +1,387 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.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(tpAniSirGlobal pMac, tpPESession psessionEntry); + +/** ------------------------------------------------------------- + \fn lim_set_cfg_protection + \brief sets lim global cfg cache from the config. + \param tpAniSirGlobal pMac + \return None + -------------------------------------------------------------*/ +void lim_set_cfg_protection(tpAniSirGlobal pMac, tpPESession pesessionEntry) +{ + uint32_t val = 0; + + if (pesessionEntry != NULL && LIM_IS_AP_ROLE(pesessionEntry)) { + if (pesessionEntry->gLimProtectionControl == + WNI_CFG_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 { + if (wlan_cfg_get_int(pMac, WNI_CFG_FORCE_POLICY_PROTECTION, &val) + != QDF_STATUS_SUCCESS) { + pe_err("reading WNI_CFG_FORCE_POLICY_PROTECTION cfg failed"); + return; + } else + pMac->lim.gLimProtectionControl = (uint8_t) val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROTECTION_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + pe_err("reading protection cfg failed"); + return; + } + + if (pMac->lim.gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + qdf_mem_zero((void *)&pMac->lim.cfgProtection, + sizeof(tCfgProtection)); + else { + pMac->lim.cfgProtection.fromlla = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llA) & 1; + pMac->lim.cfgProtection.fromllb = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llB) & 1; + pMac->lim.cfgProtection.fromllg = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llG) & 1; + pMac->lim.cfgProtection.ht20 = + (val >> WNI_CFG_PROTECTION_ENABLED_HT_20) & 1; + pMac->lim.cfgProtection.nonGf = + (val >> WNI_CFG_PROTECTION_ENABLED_NON_GF) & 1; + pMac->lim.cfgProtection.lsigTxop = + (val >> WNI_CFG_PROTECTION_ENABLED_LSIG_TXOP) & 1; + pMac->lim.cfgProtection.rifs = + (val >> WNI_CFG_PROTECTION_ENABLED_RIFS) & 1; + pMac->lim.cfgProtection.obss = + (val >> WNI_CFG_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 pMac - Pointer to Global MAC structure + * @param cfgId - ID of CFG parameter that got updated + * @return None + */ +void lim_handle_param_update(tpAniSirGlobal pMac, 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(pMac, &msg); + +#ifdef WLAN_DEBUG + if (status != QDF_STATUS_SUCCESS) + pe_err("Failed lim_post_msg_api %u", status); +#endif + break; + } + default: + break; + } +} + +/** + * lim_handle_cf_gparam_update() + * + ***FUNCTION: + * This function is called by lim_process_messages() to + * whenever SIR_CFG_PARAM_UPDATE_IND message is posted + * to LIM (due to a set operation on a CFG parameter). + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param cfgId - ID of CFG parameter that got updated + * @return None + */ + +void lim_handle_cf_gparam_update(tpAniSirGlobal pMac, uint32_t cfgId) +{ + uint32_t val1, val2; + uint16_t val16; + tSirMacHTParametersInfo *pAmpduParamInfo; + + pe_debug("Handling CFG parameter id %X update", cfgId); + + switch (cfgId) { + case WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT: + if (pMac->lim.gLimMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) { + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, + eLIM_ASSOC_FAIL_TIMER); + } + + break; + + case WNI_CFG_PROTECTION_ENABLED: + lim_set_cfg_protection(pMac, NULL); + break; + + case WNI_CFG_MPDU_DENSITY: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve HT AMPDU Param CFG"); + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MPDU_DENSITY, &val2) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve MPDU Density CFG"); + break; + } + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->mpduDensity = (uint8_t) val2; +#ifdef WLAN_DEBUG + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != QDF_STATUS_SUCCESS) + pe_err("could not update HT AMPDU Param CFG"); +#endif + break; + case WNI_CFG_MAX_RX_AMPDU_FACTOR: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve HT AMPDU Param CFG"); + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_RX_AMPDU_FACTOR, &val2) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve AMPDU Factor CFG"); + break; + } + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->maxRxAMPDUFactor = (uint8_t) val2; +#ifdef WLAN_DEBUG + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != QDF_STATUS_SUCCESS) + pe_err("could not update HT AMPDU Param CFG"); +#endif + break; + + case WNI_CFG_DOT11_MODE: + if (wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &val1) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve Dot11 Mode CFG"); + break; + } + break; + + case WNI_CFG_ASSOC_STA_LIMIT: + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val1) != + QDF_STATUS_SUCCESS) { + pe_err("Unable to get WNI_CFG_ASSOC_STA_LIMIT"); + break; + } + pMac->lim.gLimAssocStaLimit = (uint16_t) val1; + break; + default: + break; + } +} /*** end lim_handle_cf_gparam_update() ***/ + +/** + * 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 pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_apply_configuration(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t val = 0, phyMode; + + pe_debug("Applying config"); + + psessionEntry->limSentCapsChangeNtf = false; + + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + lim_update_config(pMac, psessionEntry); + + lim_get_short_slot_from_phy_mode(pMac, psessionEntry, phyMode, + &psessionEntry->shortSlotTimeSupported); + + lim_set_cfg_protection(pMac, psessionEntry); + + /* Added for BT - AMP Support */ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + /* This check is required to ensure the beacon generation is not done + as a part of join request for a BT-AMP station */ + + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) { + pe_debug("Initializing BT-AMP beacon generation"); + sch_set_beacon_interval(pMac, psessionEntry); + sch_set_fixed_beacon_fields(pMac, psessionEntry); + } + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_SCAN_IN_POWERSAVE, &val) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve WNI_CFG_SCAN_IN_POWERSAVE"); + return; + } +} /*** 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(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != QDF_STATUS_SUCCESS) + pe_err("cfg get short preamble failed"); + psessionEntry->beaconParams.fShortPreamble = (val) ? 1 : 0; + + /* In STA case this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, WNI_CFG_WME_ENABLED, &val) != + QDF_STATUS_SUCCESS) + pe_err("cfg get wme enabled failed"); + psessionEntry->limWmeEnabled = (val) ? 1 : 0; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_WSM_ENABLED, &val) != QDF_STATUS_SUCCESS) + pe_err("cfg get wsm enabled failed"); + psessionEntry->limWsmEnabled = (val) ? 1 : 0; + + if ((!psessionEntry->limWmeEnabled) && (psessionEntry->limWsmEnabled)) { + pe_err("Can't enable WSM without WME"); + psessionEntry->limWsmEnabled = 0; + } + /* In STA , this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(psessionEntry) || LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != + QDF_STATUS_SUCCESS) + pe_err("cfg get qos enabled failed"); + psessionEntry->limQosEnabled = (val) ? 1 : 0; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_HCF_ENABLED, &val) != QDF_STATUS_SUCCESS) + pe_err("cfg get hcf enabled failed"); + psessionEntry->limHcfEnabled = (val) ? 1 : 0; + + /* AP: WSM should enable HCF as well, for STA enable WSM only after */ + /* association response is received */ + if (psessionEntry->limWsmEnabled && LIM_IS_AP_ROLE(psessionEntry)) + psessionEntry->limHcfEnabled = 1; + + if (wlan_cfg_get_int(pMac, WNI_CFG_11D_ENABLED, &val) != QDF_STATUS_SUCCESS) + pe_err("cfg get 11d enabled failed"); + psessionEntry->lim11dEnabled = (val) ? 1 : 0; + + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val) != QDF_STATUS_SUCCESS) { + pe_err("cfg get assoc sta limit failed"); + } + pMac->lim.gLimAssocStaLimit = (uint16_t) val; + + pe_debug("Updated Lim shadow state based on CFG"); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..6be886272273c9ff3989edaf8b2408c88c221c76 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c @@ -0,0 +1,580 @@ +/* + * 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. + */ + +/* + * + * 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" + +/** + * lim_process_deauth_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Deauthentication frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Buffer descriptor + associated PDUs + * @return None + */ + +void +lim_process_deauth_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + uint8_t *pBody; + uint16_t reasonCode; + tpSirMacMgmtHdr pHdr; + tpPESession pRoamSessionEntry = NULL; + uint8_t roamSessionId; +#ifdef WLAN_FEATURE_11W + uint32_t frameLen; +#endif + 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(psessionEntry) && + ((eLIM_SME_WT_DISASSOC_STATE == psessionEntry->limSmeState) || + (eLIM_SME_WT_DEAUTH_STATE == psessionEntry->limSmeState))) { + /*Every 15th deauth frame will be logged in kmsg */ + if (!(pMac->lim.deauthMsgCnt & 0xF)) { + pe_debug("received Deauth frame in DEAUTH_WT_STATE" + "(already processing previously received DEAUTH frame)" + "Dropping this.. Deauth Failed %d", + ++pMac->lim.deauthMsgCnt); + } else { + pMac->lim.deauthMsgCnt++; + } + return; + } + + if (lim_is_group_addr(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 (lim_is_group_addr(pHdr->da) && !lim_is_addr_bc(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(pMac, + pHdr->da, psessionEntry)) { + pe_err("rx frame doesn't have valid a1 address, drop it"); + return; + } +#ifdef WLAN_FEATURE_11W + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (psessionEntry->limRmfEnabled + && (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(psessionEntry) && pMac->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(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, + psessionEntry); + return; + } +#endif + + /* Get reasonCode from Deauthentication frame body */ + reasonCode = sir_read_u16(pBody); + + pe_debug("Received Deauth frame for Addr: " MAC_ADDRESS_STR + "(mlm state = %s, sme state = %d systemrole = %d " + "RSSI = %d) with reason code %d [%s] from " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pHdr->da), + lim_mlm_state_str(psessionEntry->limMlmState), + psessionEntry->limSmeState, + GET_LIM_SYSTEM_ROLE(psessionEntry), frame_rssi, + reasonCode, lim_dot11_reason_str(reasonCode), + MAC_ADDR_ARRAY(pHdr->sa)); + + if (pMac->roam.configParam.enable_fatal_event && + (reasonCode != eSIR_MAC_UNSPEC_FAILURE_REASON && + reasonCode != eSIR_MAC_DEAUTH_LEAVING_BSS_REASON && + reasonCode != eSIR_MAC_DISASSOC_LEAVING_BSS_REASON)) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DISCONNECT, + false, false); + } + + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_FRAME_EVENT, + psessionEntry, 0, reasonCode); + + if (lim_check_disassoc_deauth_ack_pending(pMac, (uint8_t *) pHdr->sa)) { + pe_debug("Ignore the Deauth received, while waiting for ack of " + "disassoc/deauth"); + lim_clean_up_disassoc_deauth_req(pMac, (uint8_t *) pHdr->sa, 1); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + /* 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 " + MAC_ADDRESS_STR, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + + break; + } + } else if (LIM_IS_STA_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON: + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + case eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON: + case eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON: + case eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON: + /* 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 " + MAC_ADDRESS_STR, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + + break; + } + } else { + /* Received Deauth frame in either IBSS */ + /* or un-known role. Log and ignore it */ + pe_err("received Deauth frame with reasonCode %d in role %d from " + MAC_ADDRESS_STR, reasonCode, + GET_LIM_SYSTEM_ROLE(psessionEntry), + MAC_ADDR_ARRAY(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(pMac, psessionEntry->limReAssocbssId, + &roamSessionId); + + if (lim_is_reassoc_in_progress(pMac, psessionEntry) || + lim_is_reassoc_in_progress(pMac, pRoamSessionEntry) || + psessionEntry->fw_roaming_started) { + /* + * 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 (psessionEntry->fw_roaming_started && + IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) { + 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. + */ + psessionEntry->recvd_deauth_while_roaming = true; + psessionEntry->deauth_disassoc_rc = reasonCode; + return; + } + if (!IS_REASSOC_BSSID(pMac, pHdr->sa, psessionEntry)) { + pe_debug("Rcv Deauth from unknown/different " + "AP while ReAssoc. Ignore " MAC_ADDRESS_STR + "limReAssocbssId : " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHdr->sa), + MAC_ADDR_ARRAY(psessionEntry->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(pMac, pHdr->sa, psessionEntry)) { + pe_debug("received DeAuth from the New AP to " + "which ReAssoc is sent " MAC_ADDRESS_STR + "psessionEntry->bssId: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHdr->sa), + MAC_ADDR_ARRAY(psessionEntry->bssId)); + + lim_restore_pre_reassoc_state(pMac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + psessionEntry); + 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(psessionEntry)) { + if (!IS_CURRENT_BSSID(pMac, pHdr->bssId, psessionEntry)) { + pe_err("received DeAuth from an AP other " + "than we're trying to join. Ignore. " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pHdr->sa)); + + if (lim_search_pre_auth_list(pMac, pHdr->sa)) { + pe_debug("Preauth entry exist. Deleting"); + lim_delete_pre_auth_node(pMac, pHdr->sa); + } + return; + } + } + + lim_perform_deauth(pMac, psessionEntry, reasonCode, pHdr->sa, + frame_rssi); + + +} /*** end lim_process_deauth_frame() ***/ + +void lim_perform_deauth(tpAniSirGlobal mac_ctx, tpPESession pe_session, + uint16_t rc, tSirMacAddr addr, int32_t frame_rssi) +{ + tLimMlmDeauthInd mlmDeauthInd; + tLimMlmAssocCnf mlmAssocCnf; + uint16_t aid; + tpDphHashNode sta_ds; + + sta_ds = dph_lookup_hash_entry(mac_ctx, addr, &aid, + &pe_session->dph.dphHashTable); + if (sta_ds == NULL) { + 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 " MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(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 " MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(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 " MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(addr)); + if (lim_search_pre_auth_list(mac_ctx, addr)) + lim_delete_pre_auth_node(mac_ctx, addr); + + 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)); + + /* Deactive 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" MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(addr)); + return; + + case eLIM_MLM_IDLE_STATE: + case eLIM_MLM_LINK_ESTABLISHED_STATE: +#ifdef FEATURE_WLAN_TDLS + if ((NULL != sta_ds) + && (STA_ENTRY_TDLS_PEER == sta_ds->staType)) { + pe_err("received Deauth frame in state %X with " + "reason code %d from Tdls peer" + MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(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 " MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(addr)); + break; + + case eLIM_MLM_WT_FT_REASSOC_RSP_STATE: + pe_err("received Deauth frame in FT state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(addr)); + break; + + default: + pe_err("received Deauth frame in state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR, + pe_session->limMlmState, rc, + MAC_ADDR_ARRAY(addr)); + return; + } + break; + + case eLIM_STA_IN_IBSS_ROLE: + break; + + case eLIM_AP_ROLE: + break; + + default: + return; + } /* end switch (pMac->lim.gLimSystemRole) */ + + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + if (NULL == 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:%pM in mlmState %d", + sta_ds->sta_deletion_in_progress, addr, + sta_ds->mlmStaContext.mlmState); + return; + } + sta_ds->mlmStaContext.disassocReason = (tSirMacReasonCodes) 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) { + 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, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + 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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..99ca91f7ac7b6966bc5765252e53defb9bcab682 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c @@ -0,0 +1,397 @@ +/* + * 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. + */ + +/* + * + * This file lim_process_disassoc_frame.cc contains the code + * for processing Disassocation 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" + +/** + * 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 pStaDs set to '0'. + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Rx packet info structure + * @return None + */ +void +lim_process_disassoc_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + uint8_t *pBody; + uint16_t aid, reasonCode; + tpSirMacMgmtHdr pHdr; + tpDphHashNode pStaDs; + 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 (lim_is_group_addr(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 (lim_is_group_addr(pHdr->da) && !lim_is_addr_bc(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(pMac, + pHdr->da, psessionEntry)) { + pe_err("rx frame doesn't have valid a1 address, drop it"); + return; + } + + if (LIM_IS_STA_ROLE(psessionEntry) && + ((eLIM_SME_WT_DISASSOC_STATE == psessionEntry->limSmeState) || + (eLIM_SME_WT_DEAUTH_STATE == psessionEntry->limSmeState))) { + if (!(pMac->lim.disassocMsgCnt & 0xF)) { + pe_debug("received Disassoc frame in %s" + "already processing previously received Disassoc frame, dropping this %d", + lim_sme_state_str(psessionEntry->limSmeState), + ++pMac->lim.disassocMsgCnt); + } else { + pMac->lim.disassocMsgCnt++; + } + return; + } +#ifdef WLAN_FEATURE_11W + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (psessionEntry->limRmfEnabled + && (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(psessionEntry) && pMac->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(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frame_len + + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, + psessionEntry); + return; + } +#endif + + if (frame_len < 2) { + pe_err("frame len less than 2"); + return; + } + + /* Get reasonCode from Disassociation frame body */ + reasonCode = sir_read_u16(pBody); + + pe_debug("Received Disassoc frame for Addr: " MAC_ADDRESS_STR + "(mlm state=%s, sme state=%d RSSI=%d)," + "with reason code %d [%s] from " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHdr->da), + lim_mlm_state_str(psessionEntry->limMlmState), + psessionEntry->limSmeState, frame_rssi, reasonCode, + lim_dot11_reason_str(reasonCode), MAC_ADDR_ARRAY(pHdr->sa)); + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_FRAME_EVENT, + psessionEntry, 0, reasonCode); + + if (pMac->roam.configParam.enable_fatal_event && + (reasonCode != eSIR_MAC_UNSPEC_FAILURE_REASON && + reasonCode != eSIR_MAC_DEAUTH_LEAVING_BSS_REASON && + reasonCode != eSIR_MAC_DISASSOC_LEAVING_BSS_REASON)) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DISCONNECT, + false, false); + } + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + /** + * Disassociating STA is not associated. + * Log error. + */ + pe_err("received Disassoc frame from STA that does not have context" + "reasonCode=%d, addr " MAC_ADDRESS_STR, + reasonCode, MAC_ADDR_ARRAY(pHdr->sa)); + return; + } + + if (lim_check_disassoc_deauth_ack_pending(pMac, (uint8_t *) pHdr->sa)) { + pe_err("Ignore the DisAssoc received, while waiting for ack of disassoc/deauth"); + lim_clean_up_disassoc_deauth_req(pMac, (uint8_t *) pHdr->sa, 1); + return; + } + + if (pMac->lim.disassocMsgCnt != 0) { + pMac->lim.disassocMsgCnt = 0; + } + + /** If we are in the Wait for ReAssoc Rsp state */ + if (lim_is_reassoc_in_progress(pMac, psessionEntry)) { + /* + * 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 (psessionEntry->fw_roaming_started && + IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) { + pe_debug("Dropping disassoc frame from connected AP"); + psessionEntry->recvd_disassoc_while_roaming = true; + psessionEntry->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(pMac, pHdr->sa, psessionEntry)) { + 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(pMac, pHdr->sa, psessionEntry)) { + pe_debug("received Disassoc from the New AP to which ReAssoc is sent"); + lim_restore_pre_reassoc_state(pMac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + psessionEntry); + return; + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON: + case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON: + case eSIR_MAC_MIC_FAILURE_REASON: + case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON: + case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON: + case eSIR_MAC_RSN_IE_MISMATCH_REASON: + case eSIR_MAC_1X_AUTH_FAILURE_REASON: + /* Valid reasonCode in received Disassociation frame */ + break; + + default: + /* Invalid reasonCode in received Disassociation frame */ + pe_warn("received Disassoc frame with invalid reasonCode: %d from " MAC_ADDRESS_STR, + reasonCode, MAC_ADDR_ARRAY(pHdr->sa)); + break; + } + } else if (LIM_IS_STA_ROLE(psessionEntry) && + ((psessionEntry->limSmeState != eLIM_SME_WT_JOIN_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_AUTH_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_ASSOC_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_REASSOC_STATE))) { + switch (reasonCode) { + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON: + /* Valid reasonCode in received Disassociation frame */ + /* as long as we're not about to channel switch */ + if (psessionEntry->gLimChannelSwitch.state != + eLIM_CHANNEL_SWITCH_IDLE) { + pe_err("Ignoring disassoc frame due to upcoming channel switch, from "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHdr->sa)); + return; + } + break; + + default: + break; + } + } else { + /* Received Disassociation frame in either IBSS */ + /* or un-known role. Log and ignore it */ + pe_err("received Disassoc frame with invalid reasonCode: %d in role:" + "%d in sme state: %d from " MAC_ADDRESS_STR, reasonCode, + GET_LIM_SYSTEM_ROLE(psessionEntry), psessionEntry->limSmeState, + MAC_ADDR_ARRAY(pHdr->sa)); + + return; + } + + if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE) || + pStaDs->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:%pM in mlmState %d", + pStaDs->sta_deletion_in_progress, pHdr->sa, + pStaDs->mlmStaContext.mlmState); + return; + } + pStaDs->sta_deletion_in_progress = true; + lim_disassoc_tdls_peers(pMac, psessionEntry, pHdr->sa); + if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) { + /** + * Requesting STA is in some 'transient' state? + * Log error. + */ + if (pStaDs->mlmStaContext.mlmState == + eLIM_MLM_WT_ASSOC_CNF_STATE) + pStaDs->mlmStaContext.updateContext = 1; + + pe_err("received Disassoc frame from peer that is in state: %X, addr "MAC_ADDRESS_STR, + pStaDs->mlmStaContext.mlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + + } /* if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */ + + lim_perform_disassoc(pMac, frame_rssi, reasonCode, + psessionEntry, pHdr->sa); + +} /*** end lim_process_disassoc_frame() ***/ + +#ifdef FEATURE_WLAN_TDLS +void lim_disassoc_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession 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 == NULL) { + 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(tpAniSirGlobal mac_ctx, int32_t frame_rssi, + uint16_t rc, tpPESession pe_session, tSirMacAddr addr) +{ + tLimMlmDisassocInd mlmDisassocInd; + uint16_t aid; + tpDphHashNode sta_ds; + + sta_ds = dph_lookup_hash_entry(mac_ctx, addr, &aid, + &pe_session->dph.dphHashTable); + if (sta_ds == NULL) { + pe_debug("Hash entry not found"); + return; + } + sta_ds->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DISASSOC; + sta_ds->mlmStaContext.disassocReason = (tSirMacReasonCodes) 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_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) { + 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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c new file mode 100644 index 0000000000000000000000000000000000000000..d6903626cc2ccdd68ac1d7710db160be9d4d1377 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c @@ -0,0 +1,1879 @@ +/* + * 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. + */ + +#include "lim_process_fils.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#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) +{ + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + ("%s : length %d"), type, len); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, 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 -EINVAL; +} + +/** + * 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_crypto_type(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_CRYPTO_TYPE; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + default: + return FILS_SHA256_CRYPTO_TYPE; + } +} + +/** + * 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_PKM_LEN; + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_PKM_LEN; + default: + return FILS_SHA256_PKM_LEN; + } +} + +/** + * 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 interation; + uint8_t crypto_digest_len = lim_get_crypto_digest_len(type); + uint8_t tmp_hash[SHA384_DIGEST_SIZE] = {0}; + + 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 (interation = 1; i < keylen; interation++) { + remain_len = keylen - i; + qdf_mem_copy(count, &interation, sizeof(interation)); + + 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_default_hmac_sha256_kdf()- This API calculates key data using default kdf + * defined in RFC4306. + * @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 + * + * This API creates default KDF as defined in RFC4306 + * PRF+ (K,S) = T1 | T2 | T3 | T4 | ... + * T1 = PRF (K, S | 0x01) + * T2 = PRF (K, T1 | S | 0x02) + * T3 = PRF (K, T2 | S | 0x03) + * T4 = PRF (K, T3 | S | 0x04) + * + * for every iteration its creates 32 bit of hash + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_default_hmac_sha256_kdf(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 tmp_hash[SHA256_DIGEST_SIZE] = {0}; + uint8_t count = 1; + uint8_t *addr[4]; + uint32_t len[4]; + uint32_t current_position = 0, remaining_data = SHA256_DIGEST_SIZE; + + addr[0] = tmp_hash; + len[0] = SHA256_DIGEST_SIZE; + addr[1] = label; + len[1] = strlen(label) + 1; + addr[2] = optional_data; + len[2] = optional_data_len; + addr[3] = &count; + len[3] = 1; + + if (keylen == 0 || + (keylen > (MAX_PRF_INTERATIONS_COUNT * SHA256_DIGEST_SIZE))) { + pe_err("invalid key length %d", keylen); + return QDF_STATUS_E_FAILURE; + } + + /* Create T1 */ + if (qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, secret, secret_len, 3, + &addr[1], &len[1], tmp_hash) < 0) { + pe_err("failed to get hmac hash"); + return QDF_STATUS_E_FAILURE; + } + + /* Update hash from tmp_hash */ + qdf_mem_copy(key + current_position, tmp_hash, remaining_data); + current_position += remaining_data; + + for (count = 2; current_position < keylen; count++) { + remaining_data = keylen - current_position; + if (remaining_data > SHA256_DIGEST_SIZE) + remaining_data = SHA256_DIGEST_SIZE; + + /* Create T-n */ + if (qdf_get_hmac_hash(FILS_SHA256_CRYPTO_TYPE, secret, + secret_len, 4, addr, len, tmp_hash) < 0) { + pe_err("failed to get hmac hash"); + return QDF_STATUS_E_FAILURE; + } + /* Update hash from tmp_hash */ + qdf_mem_copy(key + current_position, tmp_hash, remaining_data); + current_position += remaining_data; + } + 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(tpPESession 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) { + pe_err("failed to alloc memory"); + 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) { + pe_err("failed to alloc memory"); + 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_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(tpPESession 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->selfMacAddr, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + + if (qdf_get_hmac_hash(lim_get_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_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(tpPESession 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->selfMacAddr, 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_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_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(tpPESession 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[MAX_ICK_LEN + MAX_KEK_LEN + MAX_TK_LEN] = {0}; + uint8_t key_data_len; + uint8_t ick_len; + uint8_t kek_len; + uint8_t tk_len = lim_get_tk_len(pe_session->encryptType); + uint8_t *buf; + + if (!fils_info) + return; + + ick_len = lim_get_ick_len(fils_info->akm); + kek_len = lim_get_kek_len(fils_info->akm); + + key_data_len = ick_len + kek_len + tk_len; + + data_len = 2 * SIR_FILS_NONCE_LENGTH + 2 * QDF_MAC_ADDR_SIZE; + data = qdf_mem_malloc(data_len); + if (!data) { + pe_err("failed to alloc memory"); + return; + } + + /* Update data */ + buf = data; + qdf_mem_copy(buf, pe_session->selfMacAddr, 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); + 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; + 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(tpPESession 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_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(tpPESession pe_session) +{ + uint8_t nounce[2 * SIR_FILS_NONCE_LENGTH] = {0}; + uint8_t nounce_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; + + /* Snounce */ + qdf_mem_copy(nounce, pe_session->fils_info->fils_nonce, + SIR_FILS_NONCE_LENGTH); + /* anounce */ + qdf_mem_copy(nounce + 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) { + pe_err("failed to alloc memory"); + return; + } + + addr[0] = fils_info->fils_rmsk; + len[0] = fils_info->fils_rmsk_len; + lim_fils_data_dump("Nonce", nounce, nounce_len); + if (qdf_get_hmac_hash(lim_get_crypto_type(fils_info->akm), nounce, + nounce_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(tpPESession 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) { + pe_err("failed to alloc memory"); + 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); + lim_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(tpPESession 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(FILS_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(tpAniSirGlobal mac_ctx, + tpPESession 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; +} + +QDF_STATUS lim_create_fils_rik(uint8_t *rrk, uint8_t rrk_len, + uint8_t *rik, uint32_t *rik_len) +{ + uint8_t optional_data[SIR_FILS_OPTIONAL_DATA_LEN]; + uint8_t label[] = SIR_FILS_RIK_LABEL; + + if (!rrk || !rik) { + pe_err("FILS rrk/rik NULL"); + return QDF_STATUS_E_FAILURE; + } + + optional_data[0] = HMAC_SHA256_128; + /* basic validation */ + if (rrk_len <= 0) { + pe_err("invalid r_rk length %d", rrk_len); + return QDF_STATUS_E_FAILURE; + } + lim_copy_u16_be(&optional_data[1], rrk_len); + if (lim_default_hmac_sha256_kdf(rrk, rrk_len, label, + optional_data, sizeof(optional_data), + rik, rrk_len) + != QDF_STATUS_SUCCESS) { + pe_err("failed to create rik"); + return QDF_STATUS_E_FAILURE; + } + *rik_len = rrk_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * 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; + + 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) { + pe_err("failed to allocate memory"); + 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; + pe_err("failed to alloc memory"); + return -EINVAL; + } + status = lim_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(FILS_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(tpPESession 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); + + /* ***Nounce*** */ + /* Add element id */ + *body = SIR_MAX_ELEMENT_ID; + body++; + /* Add nounce 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 */ + cds_rand_get_bytes(0, 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 nounce 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 */ + cds_rand_get_bytes(0, 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); + + /* 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_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(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + tSirMacAuthFrameBody *rx_auth_frm_body) +{ + int i; + uint32_t ret; + bool pmkid_found = false; + tDot11fIERSN dot11f_ie_rsn = {0}; + + 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; + } + + 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(pe_session); + lim_generate_key_auth(pe_session); + lim_generate_ap_key_auth(pe_session); + return true; +} + +/** + * lim_update_fils_config()- This API update fils session info to csr config + * from join request. + * @session: PE session + * @sme_join_req: pointer to join request + * + * Return: None + */ +void lim_update_fils_config(tpPESession session, + tpSirSmeJoinReq sme_join_req) +{ + struct pe_fils_session *csr_fils_info; + struct cds_fils_connection_info *fils_config_info; + + fils_config_info = &sme_join_req->fils_con_info; + csr_fils_info = session->fils_info; + + if (!csr_fils_info) + return; + + if (fils_config_info->is_fils_connection == false) + return; + + csr_fils_info->is_fils_connection = + fils_config_info->is_fils_connection; + csr_fils_info->keyname_nai_length = + fils_config_info->key_nai_length; + csr_fils_info->fils_rrk_len = + fils_config_info->r_rk_length; + csr_fils_info->akm = fils_config_info->akm_type; + csr_fils_info->auth = fils_config_info->auth_type; + csr_fils_info->sequence_number = fils_config_info->sequence_number; + if (fils_config_info->key_nai_length > FILS_MAX_KEYNAME_NAI_LENGTH) { + pe_err("Restricting the key_nai_length of %d to max %d", + fils_config_info->key_nai_length, + FILS_MAX_KEYNAME_NAI_LENGTH); + fils_config_info->key_nai_length = FILS_MAX_KEYNAME_NAI_LENGTH; + } + csr_fils_info->keyname_nai_data = + qdf_mem_malloc(fils_config_info->key_nai_length); + if (!csr_fils_info->keyname_nai_data) { + pe_err("failed to alloc memory"); + return; + } + qdf_mem_copy(csr_fils_info->keyname_nai_data, + fils_config_info->keyname_nai, + fils_config_info->key_nai_length); + csr_fils_info->fils_rrk = + qdf_mem_malloc(fils_config_info->r_rk_length); + if (!csr_fils_info->fils_rrk) { + pe_err("failed to alloc memory"); + qdf_mem_free(csr_fils_info->keyname_nai_data); + return; + } + + if (fils_config_info->r_rk_length <= FILS_MAX_RRK_LENGTH) + qdf_mem_copy(csr_fils_info->fils_rrk, + fils_config_info->r_rk, + fils_config_info->r_rk_length); + + qdf_mem_copy(csr_fils_info->fils_pmkid, + fils_config_info->pmkid, PMKID_LEN); + csr_fils_info->rsn_ie_len = sme_join_req->rsnIE.length; + qdf_mem_copy(csr_fils_info->rsn_ie, + sme_join_req->rsnIE.rsnIEdata, + sme_join_req->rsnIE.length); + + csr_fils_info->fils_pmk_len = fils_config_info->pmk_len; + if (fils_config_info->pmk_len) { + csr_fils_info->fils_pmk = + qdf_mem_malloc(fils_config_info->pmk_len); + if (!csr_fils_info->fils_pmk) { + qdf_mem_free(csr_fils_info->keyname_nai_data); + qdf_mem_free(csr_fils_info->fils_rrk); + pe_err("failed to alloc memory"); + return; + } + qdf_mem_copy(csr_fils_info->fils_pmk, fils_config_info->pmk, + fils_config_info->pmk_len); + } + pe_debug("fils=%d nai-len=%d rrk_len=%d akm=%d auth=%d pmk_len=%d", + fils_config_info->is_fils_connection, + fils_config_info->key_nai_length, + fils_config_info->r_rk_length, + fils_config_info->akm_type, + fils_config_info->auth_type, + fils_config_info->pmk_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 + */ +uint32_t lim_create_fils_auth_data(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, + tpPESession session) +{ + uint32_t frame_len = 0; + int32_t wrapped_data_len; + + if (!session->fils_info) + return 0; + + /* 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) { + frame_len += session->fils_info->rsn_ie_len; + /* FILS nounce */ + frame_len += SIR_FILS_NONCE_LENGTH + EXTENDED_IE_HEADER_LEN; + /* FILS Session */ + frame_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 create warpped data"); + return 0; + } + frame_len += wrapped_data_len + EXTENDED_IE_HEADER_LEN; + } + return frame_len; +} + +void populate_fils_connect_params(tpAniSirGlobal mac_ctx, + tpPESession session, + tpSirSmeJoinRsp sme_join_rsp) +{ + struct fils_join_rsp_params *fils_join_rsp; + struct pe_fils_session *fils_info = session->fils_info; + + 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; + } + + sme_join_rsp->fils_join_rsp = qdf_mem_malloc(sizeof(*fils_join_rsp)); + if (!sme_join_rsp->fils_join_rsp) { + pe_err("fils_join_rsp malloc fails!"); + pe_delete_fils_info(session); + return; + } + + fils_join_rsp = sme_join_rsp->fils_join_rsp; + fils_join_rsp->fils_pmk = qdf_mem_malloc(fils_info->fils_pmk_len); + if (!fils_join_rsp->fils_pmk) { + pe_err("fils_pmk malloc fails!"); + qdf_mem_free(fils_join_rsp); + pe_delete_fils_info(session); + return; + } + + fils_join_rsp->fils_pmk_len = fils_info->fils_pmk_len; + qdf_mem_copy(fils_join_rsp->fils_pmk, fils_info->fils_pmk, + fils_info->fils_pmk_len); + + qdf_mem_copy(fils_join_rsp->fils_pmkid, fils_info->fils_pmkid, + IEEE80211_PMKID_LEN); + + fils_join_rsp->kek_len = fils_info->kek_len; + qdf_mem_copy(fils_join_rsp->kek, fils_info->kek, fils_info->kek_len); + + fils_join_rsp->tk_len = fils_info->tk_len; + qdf_mem_copy(fils_join_rsp->tk, fils_info->tk, fils_info->tk_len); + + fils_join_rsp->gtk_len = fils_info->gtk_len; + qdf_mem_copy(fils_join_rsp->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_join_rsp->dst_mac, &fils_join_rsp->src_mac, + &fils_join_rsp->hlp_data_len, + fils_join_rsp->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(tpAniSirGlobal 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; +} + +bool lim_verify_fils_params_assoc_rsp(tpAniSirGlobal mac_ctx, + tpPESession 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 = assoc_rsp->fils_key_auth; + tDot11fIEfils_kde fils_kde = assoc_rsp->fils_kde; + 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; + } + + /* 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); + goto verify_fils_params_fails; + } + + /* Verify the Key Delivery Element presence */ + if (!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, fils_kde.kde_list, + fils_kde.num_kde_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("KDE parsing fails"); + goto verify_fils_params_fails; + } + return true; + +verify_fils_params_fails: + assoc_cnf->resultCode = eSIR_SME_ASSOC_REFUSED; + assoc_cnf->protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + 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(tpAniSirGlobal 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 (NULL == 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 == SIR_MAC_REQUEST_EID_MAX && + 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 u8 *kek, unsigned int kek_len, + const u8 *own_mac, const u8 *bssid, + const u8 *snonce, const u8 *anonce, + const u8 *data, size_t data_len, u8 *plain_text, + size_t plain_text_len, u8 *out) +{ + u8 v[AES_BLOCK_SIZE]; + const u8 *aad[6]; + size_t aad_len[6]; + u8 *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 == NULL || bssid == NULL || snonce == NULL || + anonce == NULL || data_len == 0 || plain_text_len == 0 || + out == NULL) { + 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 == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Failed to allocate memory")); + 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(tpAniSirGlobal mac_ctx, + tpPESession 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->selfMacAddr, 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 u8 *kek, unsigned int kek_len, + const u8 *own_mac, const u8 *bssid, + const u8 *snonce, const u8 *anonce, + const u8 *data, size_t data_len, u8 *ciphered_text, + size_t ciphered_text_len, u8 *plain_text) +{ + const u8 *aad[6]; + size_t aad_len[6]; + u8 *buf; + size_t buf_len; + u8 v[AES_BLOCK_SIZE]; + u8 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 == NULL || bssid == NULL || snonce == NULL || + anonce == NULL || data_len == 0 || ciphered_text_len == 0 || + plain_text == NULL) { + 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 == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Failed to allocate memory")); + 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(tpAniSirGlobal mac_ctx, + tpPESession 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; + + 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->selfMacAddr, 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; +} + +void lim_update_fils_rik(tpPESession pe_session, + tSirRoamOffloadScanReq *req_buffer) +{ + struct pe_fils_session *pe_fils_info = pe_session->fils_info; + struct roam_fils_params *roam_fils_params = + &req_buffer->roam_fils_params; + + /* + * If it is first connection, LIM session entries will not be + * set with FILS. However in RSO, CSR filled the RRK, realm + * info and is_fils_connection to true in req_buffer, RIK + * can be created with RRK and send all the FILS info to fw + */ + if ((!lim_is_fils_connection(pe_session) || + !pe_fils_info) && (req_buffer->is_fils_connection)) { + if (roam_fils_params->rrk_length > FILS_MAX_RRK_LENGTH) { + pe_debug("FILS rrk len(%d) max (%d)", + roam_fils_params->rrk_length, + FILS_MAX_RRK_LENGTH); + return; + } + + lim_create_fils_rik(roam_fils_params->rrk, + roam_fils_params->rrk_length, + roam_fils_params->rik, + &roam_fils_params->rik_length); + pe_debug("Fils created rik len %d", + roam_fils_params->rik_length); + return; + } + + if (!pe_fils_info) { + pe_debug("No FILS info available in the session"); + return; + } + if ((pe_fils_info->fils_rik_len > FILS_MAX_RIK_LENGTH) || + !pe_fils_info->fils_rik) { + pe_err("Fils rik len(%d) max %d", pe_fils_info->fils_rik_len, + FILS_MAX_RIK_LENGTH); + return; + } + + roam_fils_params->rik_length = pe_fils_info->fils_rik_len; + qdf_mem_copy(roam_fils_params->rik, pe_fils_info->fils_rik, + roam_fils_params->rik_length); + pe_debug("fils rik len %d", roam_fils_params->rik_length); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..5f7974773be3fb57904c443b10f73a89edf2f025 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c @@ -0,0 +1,2363 @@ +/* + * 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 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 "cfg_api.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 "lim_ibss_peer_mgmt.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 + + +void lim_log_session_states(tpAniSirGlobal pMac); +static void lim_process_normal_hdd_msg(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg, uint8_t rsp_reqd); + +#ifdef WLAN_FEATURE_SAE +/** + * lim_process_sae_msg() - Process SAE message + * @mac: Global MAC pointer + * @body: Buffer pointer + * + * Return: None + */ +static void lim_process_sae_msg(tpAniSirGlobal mac, struct sir_sae_msg *body) +{ + struct sir_sae_msg *sae_msg = body; + tpPESession session; + + if (!sae_msg) { + pe_err("SAE msg is NULL"); + return; + } + + session = pe_find_session_by_sme_session_id(mac, + sae_msg->session_id); + if (session == NULL) { + pe_err("SAE:Unable to find session"); + return; + } + + if (session->pePersona != QDF_STA_MODE) { + pe_err("SAE:Not supported in this mode %d", + session->pePersona); + return; + } + + pe_debug("SAE:status %d limMlmState %d pePersona %d", + sae_msg->sae_status, session->limMlmState, + session->pePersona); + switch (session->limMlmState) { + case eLIM_MLM_WT_SAE_AUTH_STATE: + /* SAE authentication is completed. Restore from auth state */ + if (tx_timer_running(&mac->lim.limTimers.sae_auth_timer)) + lim_deactivate_and_change_timer(mac, + eLIM_AUTH_SAE_TIMER); + /* success */ + if (sae_msg->sae_status == IEEE80211_STATUS_SUCCESS) + lim_restore_from_auth_state(mac, + eSIR_SME_SUCCESS, + eSIR_MAC_SUCCESS_STATUS, + session); + else + lim_restore_from_auth_state(mac, + eSIR_SME_AUTH_REFUSED, + eSIR_MAC_UNSPEC_FAILURE_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; + } +} +#else +static inline void lim_process_sae_msg(tpAniSirGlobal mac, void *body) +{} +#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(tpAniSirGlobal 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) { + pe_err("Fail to allocate memory"); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + 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, ePROT); + 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(tpAniSirGlobal 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) { + pe_err("Fail to allocate memory"); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + 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_err("Send eWNI_SME_SET_HW_MODE_RESP to SME"); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + 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(tpAniSirGlobal 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) { + pe_err("Fail to allocate memory"); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + 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, ePROT); + 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(tpAniSirGlobal 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; + + 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) { + pe_err("Scan IE Update fails due to malloc failure"); + return; + } + + if (lim_update_ext_cap_ie(mac_ctx, + (uint8_t *)set_ie_params->ie_data, + local_ie_buf, &local_ie_len)) { + 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) { + pe_err("fail to alloc wma_ie_params"); + goto scan_ie_send_fail; + } + wma_ie_params->vdev_id = set_ie_params->session_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); +} + +/** + * lim_process_hw_mode_trans_ind() - Process set HW mode transition indication + * @mac: Global MAC pointer + * @body: Set HW mode response in sir_hw_mode_trans_ind format + * + * Process the set HW mode transition indication and post the message + * to SME to invoke the HDD callback + * command list + * + * Return: None + */ +static void lim_process_hw_mode_trans_ind(tpAniSirGlobal mac, void *body) +{ + struct sir_hw_mode_trans_ind *ind, *param; + uint32_t len, i; + struct scheduler_msg msg = {0}; + + ind = (struct sir_hw_mode_trans_ind *)body; + if (!ind) { + pe_err("Set HW mode trans ind param is NULL"); + return; + } + + len = sizeof(*param); + + param = qdf_mem_malloc(len); + if (!param) { + pe_err("Fail to allocate memory"); + return; + } + + param->old_hw_mode_index = ind->old_hw_mode_index; + param->new_hw_mode_index = ind->new_hw_mode_index; + param->num_vdev_mac_entries = ind->num_vdev_mac_entries; + + for (i = 0; i < ind->num_vdev_mac_entries; i++) { + param->vdev_mac_map[i].vdev_id = + ind->vdev_mac_map[i].vdev_id; + param->vdev_mac_map[i].mac_id = + ind->vdev_mac_map[i].mac_id; + } + + /* TODO: Update this HW mode info in any UMAC params, if needed */ + + msg.type = eWNI_SME_HW_MODE_TRANS_IND; + msg.bodyptr = param; + msg.bodyval = 0; + pe_err("Send eWNI_SME_HW_MODE_TRANS_IND to SME"); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** ------------------------------------------------------------- + \fn def_msg_decision + \brief The function decides whether to defer a message or not in limProcessMessage function + \param tpAniSirGlobal pMac + \param struct scheduler_msg limMsg + \param tSirMacTspecIE *ppInfo + \return none + -------------------------------------------------------------*/ + +static uint8_t def_msg_decision(tpAniSirGlobal 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) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + 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 (!lim_is_system_in_scan_state(mac_ctx) && + !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_ADD_BSS_RSP) && + (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) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("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(tpAniSirGlobal 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 (NULL == result) { + pe_err("Memory allocation failed"); + 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 = WMA_GET_RX_CH(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, ePROT); +} + + +static void +__lim_ext_scan_forward_bcn_probe_rsp(tpAniSirGlobal 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; + tSirBssDescription *bssdescr; + + result = qdf_mem_malloc(sizeof(*result) + ie_len); + if (NULL == result) { + pe_err("Memory allocation failed"); + 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 = WMA_GET_RX_CH(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 = (tSirBssDescription *) qdf_mem_malloc(frame_len); + + if (NULL == bssdescr) { + pe_err("qdf_mem_malloc(length=%d) failed", frame_len); + 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, ePROT); +} + +static void +__lim_process_ext_scan_beacon_probe_rsp(tpAniSirGlobal 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 (NULL == frame) { + pe_err("Memory allocation failed"); + 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, psessionEntry 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, psessionEntry 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(tpAniSirGlobal pMac, struct scheduler_msg *pMsg, + tpPESession psessionEntry) +{ + uint8_t *pRxPacketInfo; + + lim_get_b_dfrom_rx_packet(pMac, 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 (psessionEntry == NULL) { + sch_beacon_process(pMac, pRxPacketInfo, NULL); + } else if ((psessionEntry->limSmeState == eLIM_SME_LINK_EST_STATE) || + (psessionEntry->limSmeState == eLIM_SME_NORMAL_STATE)) { + sch_beacon_process(pMac, pRxPacketInfo, psessionEntry); + } else + lim_process_beacon_frame(pMac, pRxPacketInfo, psessionEntry); + + 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.channel = scan_entry->channel.chan_idx; + + 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( + tpAniSirGlobal 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(sizeof(cds_pkt_t)); + if (!pkt_l) { + pe_err("Failed to allocate pkt"); + return QDF_STATUS_E_FAILURE; + } + + status = wma_ds_peek_rx_packet_info( + pkt_l, (void *)&rx_pkt_info_l, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed to get Rx Pkt meta"); + goto free; + } + + bcn_l = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!bcn_l) { + pe_err("Failed to allocate bcn struct"); + 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) +{ + tpAniSirGlobal 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) { + pe_err("Failed to get 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] == + scan_entry->channel.chan_idx)) { + 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 pMac - Pointer to Global MAC structure + * @param pMsg of type struct scheduler_msg - Pointer to the message structure + * @return None + */ + +uint32_t lim_defer_msg(tpAniSirGlobal pMac, struct scheduler_msg *pMsg) +{ + uint32_t retCode = TX_SUCCESS; + + retCode = lim_write_deferred_msg_q(pMac, pMsg); + + if (retCode == TX_SUCCESS) { + MTRACE(mac_trace_msg_rx + (pMac, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(pMsg->type, LIM_MSG_DEFERRED))); + } else { + pe_err("Dropped lim message (0x%X) Message %s", pMsg->type, lim_msg_str(pMsg->type)); + MTRACE(mac_trace_msg_rx + (pMac, 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(tpAniSirGlobal mac_ctx, + void *rx_pkt_buffer, tpPESession 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 (lim_is_group_addr(mac_hdr->addr2)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("Ignoring A2 Invalid Packet received for MC/BC:")); + lim_print_mac_addr(mac_ctx, mac_hdr->addr2, LOGD); + return; + } + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("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; +} + +/** + * 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(tpAniSirGlobal mac_ctx, uint8_t *buff_desc, + tpPESession 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; + 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 != NULL) { + 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)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL + ("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) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("rcvd frame match with registered frame params")); + /* 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), mgmt_frame->sessionId, + WMA_GET_RX_CH(buff_desc), session_entry, + WMA_GET_RX_RSSI_NORMALIZED(buff_desc)); + + 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 pMac - Pointer to Global MAC structure + * @param pMsg of type struct scheduler_msg - Pointer to the message structure + * @return None + */ + +static void +lim_handle80211_frames(tpAniSirGlobal pMac, struct scheduler_msg *limMsg, + uint8_t *pDeferMsg) +{ + uint8_t *pRxPacketInfo = NULL; + tSirMacFrameCtl fc; + tpSirMacMgmtHdr pHdr = NULL; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + bool isFrmFt = false; + uint8_t channel; + bool is_hw_sbs_capable = false; + + *pDeferMsg = false; + lim_get_b_dfrom_rx_packet(pMac, limMsg->bodyptr, + (uint32_t **) &pRxPacketInfo); + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + isFrmFt = WMA_GET_RX_FT_DONE(pRxPacketInfo); + channel = WMA_GET_RX_CH(pRxPacketInfo); + fc = pHdr->fc; + + is_hw_sbs_capable = + policy_mgr_is_hw_sbs_capable(pMac->psoc); + if (IS_5G_CH(channel) && + (!is_hw_sbs_capable || + (is_hw_sbs_capable && wlan_reg_is_dfs_ch(pMac->pdev, channel))) && + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + psessionEntry = pe_find_session_by_bssid(pMac, + pHdr->bssId, &sessionId); + if (psessionEntry && + (QDF_SAP_MODE == psessionEntry->pePersona)) { + 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 (pMac->fEnableDebugLog & 0x1) { + if ((fc.type == SIR_MAC_MGMT_FRAME) && + (fc.subType != SIR_MAC_MGMT_PROBE_REQ) && + (fc.subType != SIR_MAC_MGMT_PROBE_RSP) && + (fc.subType != SIR_MAC_MGMT_BEACON)) { + 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)); + } + } +#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(pMac, + 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 */ + psessionEntry = pe_find_session_by_bssid(pMac, pHdr->bssId, + &sessionId); + if (psessionEntry == NULL) { + if (fc.subType == SIR_MAC_MGMT_AUTH) { + pe_debug("ProtVersion %d, Type %d, Subtype %d rateIndex=%d", + fc.protVer, fc.type, fc.subType, + WMA_GET_RX_MAC_RATE_IDX(pRxPacketInfo)); + lim_print_mac_addr(pMac, pHdr->bssId, LOGD); + if (lim_process_auth_frame_no_session + (pMac, 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)) { + + psessionEntry = pe_find_session_by_peer_sta(pMac, + pHdr->sa, &sessionId); + if (psessionEntry == NULL) { + pe_debug("session does not exist for bssId"); + lim_print_mac_addr(pMac, pHdr->sa, LOGD); + goto end; + } else { + pe_debug("SessionId:%d exists for given Bssid", + psessionEntry->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) { + psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->da, &sessionId); + } + } + + /* Check if frame is registered by HDD */ + if (lim_check_mgmt_registered_frames(pMac, pRxPacketInfo, psessionEntry)) { + pe_debug("Received frame is passed to SME"); + 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(pMac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); +#ifdef WLAN_DEBUG + pMac->lim.numProtErr++; +#endif + goto end; + } + +/* Chance of crashing : to be done BT-AMP ........happens when broadcast probe req is received */ + +#ifdef WLAN_DEBUG + pMac->lim.numMAC[fc.type][fc.subType]++; +#endif + + 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(psessionEntry)) + lim_process_assoc_req_frame(pMac, + pRxPacketInfo, + LIM_ASSOC, + psessionEntry); + else { + pe_err("unexpected message received %X", + limMsg->type); + lim_print_msg_name(pMac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_ASSOC_RSP: + lim_process_assoc_rsp_frame(pMac, pRxPacketInfo, + LIM_ASSOC, + psessionEntry); + break; + + case SIR_MAC_MGMT_REASSOC_REQ: + /* Make sure the role supports Reassociation */ + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_process_assoc_req_frame(pMac, + pRxPacketInfo, + LIM_REASSOC, + psessionEntry); + } else { + pe_err("unexpected message received %X", + limMsg->type); + lim_print_msg_name(pMac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_REASSOC_RSP: + lim_process_assoc_rsp_frame(pMac, pRxPacketInfo, + LIM_REASSOC, + psessionEntry); + break; + + case SIR_MAC_MGMT_PROBE_REQ: + lim_process_probe_req_frame_multiple_bss(pMac, + pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_PROBE_RSP: + if (psessionEntry) + lim_process_probe_rsp_frame(pMac, + pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_BEACON: + __lim_handle_beacon(pMac, limMsg, psessionEntry); + break; + + case SIR_MAC_MGMT_DISASSOC: + lim_process_disassoc_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_AUTH: + lim_process_auth_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_DEAUTH: + lim_process_deauth_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_ACTION: + if (psessionEntry == NULL) + lim_process_action_frame_no_session(pMac, + pRxPacketInfo); + else { + if (WMA_GET_RX_UNKNOWN_UCAST + (pRxPacketInfo)) + lim_handle_unknown_a2_index_frames + (pMac, pRxPacketInfo, + psessionEntry); + else + lim_process_action_frame(pMac, + pRxPacketInfo, + psessionEntry); + } + 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(pMac, pHdr, + psessionEntry, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +end: + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); + return; +} /*** end lim_handle80211_frames() ***/ + +void lim_process_abort_scan_ind(tpAniSirGlobal 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) { + pe_debug("failed to alloc scan cancel request"); + 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 = ucfg_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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + struct sPESession *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 == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "OBSS Scan not started: session id is NULL"); + return; + } + if (session->htSupportedChannelWidthSet == + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "OBSS Scan Start Req: session id %d" + "htSupportedChannelWidthSet %d", + session->peSessionId, + session->htSupportedChannelWidthSet); + lim_send_ht40_obss_scanind(mac_ctx, session); + } else { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "OBSS Scan not started: channel width - %d session %d", + session->htSupportedChannelWidthSet, + session->peSessionId); + } + return; +} + +/** + * 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(tpAniSirGlobal 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; + tpPESession session_entry = NULL; + uint8_t defer_msg = false; + tLinkStateParams *link_state_param; + uint16_t pkt_len = 0; + cds_pkt_t *body_ptr = NULL; + QDF_STATUS qdf_status; + struct scheduler_msg new_msg = {0}; + uint8_t session_id; + +#ifdef FEATURE_WLAN_TDLS + tSirTdlsInd *tdls_ind = NULL; + tpDphHashNode sta_ds = NULL; +#endif + if (msg == NULL) { + 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; + } + +#ifdef WLAN_DEBUG + mac_ctx->lim.numTot++; +#endif + /* + * 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_CFG_PARAM_UPDATE_IND && + 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_CFG_PARAM_UPDATE_IND: + if (!lim_is_system_in_scan_state(mac_ctx)) { + lim_handle_cf_gparam_update(mac_ctx, msg->bodyval); + break; + } + /* System is in DFS (Learn) mode. + * Defer processing this message + */ + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + if (!(mac_ctx->lim.deferredMsgCnt & 0xF)) + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(mac_ctx); + lim_print_msg_name(mac_ctx, LOGE, msg->type); + } + break; + case WMA_SWITCH_CHANNEL_RSP: + lim_process_switch_channel_rsp(mac_ctx, msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef ANI_SIR_IBSS_PEER_CACHING + case WMA_IBSS_STA_ADD: + lim_ibss_sta_add(mac_ctx, msg->bodyptr); + break; +#endif + case SIR_BB_XPORT_MGMT_MSG: + /* These messages are from Peer MAC entity. */ +#ifdef WLAN_DEBUG + mac_ctx->lim.numBbt++; +#endif + /* 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 == NULL) { + 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, false); + + 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) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGD, + FL("Defer Msg type=%x"), msg->type); + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + 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. Asumption 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_RESET_AP_CAPS_CHANGED: + 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_SETCONTEXT_REQ: + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + case eWNI_SME_ASSOC_CNF: + case eWNI_SME_ADDTS_REQ: + case eWNI_SME_DELTS_REQ: + case eWNI_SME_GET_ASSOC_STAS_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: +#if defined FEATURE_WLAN_ESE + case eWNI_SME_ESE_ADJACENT_AP_REPORT: +#endif + case eWNI_SME_FT_UPDATE_KEY: + case eWNI_SME_FT_PRE_AUTH_REQ: + case eWNI_SME_FT_AGGR_QOS_REQ: + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: + case eWNI_SME_GET_STATISTICS_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_ROAM_INVOKE: + /* fall through */ + case eWNI_SME_ROAM_SCAN_OFFLOAD_REQ: + case eWNI_SME_SET_ADDBA_ACCEPT: + case eWNI_SME_UPDATE_EDCA_PROFILE: + /* 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; +#ifdef FEATURE_WLAN_TDLS + case SIR_HAL_TDLS_IND: + tdls_ind = (tpSirTdlsInd) msg->bodyptr; + session_entry = pe_find_session_by_sta_id(mac_ctx, + tdls_ind->staIdx, &session_id); + if (session_entry == NULL) { + pe_debug("No session exist for given bssId"); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + sta_ds = dph_get_hash_entry(mac_ctx, tdls_ind->assocId, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + pe_debug("No sta_ds exist for given staId"); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + + if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + pe_err("rcvd TDLS IND from FW with RC %d", + tdls_ind->reasonCode); + lim_send_sme_tdls_del_sta_ind(mac_ctx, sta_ds, + session_entry, tdls_ind->reasonCode); + } + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif + 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 != NULL) && (session_entry->valid) + && (session_entry->pePersona == + QDF_P2P_GO_MODE)) { /* Save P2P attr for Go */ + qdf_mem_copy( + &session_entry->p2pGoPsUpdate, + msg->bodyptr, + sizeof(tSirP2PNoaAttr)); + pe_debug("bssId" + MAC_ADDRESS_STR + " ctWin=%d oppPsFlag=%d", + MAC_ADDR_ARRAY( + 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_DEL_TS_IND: + lim_process_del_ts_ind(mac_ctx, msg); + break; + case SIR_LIM_BEACON_GEN_IND: + if (mac_ctx->lim.gLimSystemRole != eLIM_AP_ROLE) + sch_process_pre_beacon_ind(mac_ctx, + msg, REASON_DEFAULT); + break; + case SIR_LIM_DELETE_STA_CONTEXT_IND: + lim_delete_sta_context(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_DEAUTH_ACK_TIMEOUT: + case SIR_LIM_AUTH_RETRY_TIMEOUT: + case SIR_LIM_AUTH_SAE_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 (NULL == msg->bodyptr) + pe_err("Can't Process HB TO - bodyptr is Null"); + else { + session_entry = (tpPESession) msg->bodyptr; + pe_err("SIR_LIM_HEART_BEAT_TIMEOUT, Session %d", + ((tpPESession) msg->bodyptr)->peSessionId); + limResetHBPktCount(session_entry); + lim_handle_heart_beat_timeout_for_session(mac_ctx, + session_entry); + } + break; + case SIR_LIM_PROBE_HB_FAILURE_TIMEOUT: + lim_handle_heart_beat_failure_timeout(mac_ctx); + 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_RETRY_INTERRUPT_MSG: + /* Message from ISR upon TFP's max retry limit interrupt */ + break; + case SIR_LIM_INV_KEY_INTERRUPT_MSG: + /* Message from ISR upon SP's Invalid session key interrupt */ + break; + case SIR_LIM_KEY_ID_INTERRUPT_MSG: + /* Message from ISR upon SP's Invalid key ID interrupt */ + break; + case SIR_LIM_REPLAY_THRES_INTERRUPT_MSG: + /* Message from ISR upon SP's Replay threshold interrupt */ + break; + case SIR_LIM_CHANNEL_SWITCH_TIMEOUT: + lim_process_channel_switch_timeout(mac_ctx); + break; + case SIR_LIM_QUIET_TIMEOUT: + lim_process_quiet_timeout(mac_ctx); + break; + case SIR_LIM_QUIET_BSS_TIMEOUT: + lim_process_quiet_bss_timeout(mac_ctx); + break; + case SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT: + lim_handle_update_olbc_cache(mac_ctx); + break; + case WMA_ADD_BSS_RSP: + lim_process_mlm_add_bss_rsp(mac_ctx, msg); + break; + case WMA_HIDDEN_SSID_RESTART_RSP: + lim_process_mlm_update_hidden_ssid_rsp(mac_ctx, msg); + 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); + break; + case WMA_CSA_OFFLOAD_EVENT: + 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_GET_STATISTICS_RSP: + lim_send_sme_pe_statistics_rsp(mac_ctx, msg->type, + (void *)msg->bodyptr); + 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 != NULL) { + 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_qo_s_rsp(mac_ctx, msg); + break; + case WMA_SET_LINK_STATE_RSP: + link_state_param = (tLinkStateParams *) msg->bodyptr; + session_entry = link_state_param->session; + if (link_state_param->ft +#if defined WLAN_FEATURE_ROAM_OFFLOAD + && !session_entry->bRoamSynchInProgress +#endif + ) + lim_send_reassoc_req_with_ft_ies_mgmt_frame(mac_ctx, + session_entry->pLimMlmReassocReq, + session_entry); + if (link_state_param->callback) + link_state_param->callback(mac_ctx, + link_state_param->callbackArg, + link_state_param->status); + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; + case WMA_RX_CHN_STATUS_EVENT: + lim_process_rx_channel_status_event(mac_ctx, msg->bodyptr); + break; + case WMA_IBSS_PEER_INACTIVITY_IND: + lim_process_ibss_peer_inactivity(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + 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_sme_session_id( + mac_ctx, vdev_id); + if (session_entry == NULL) + continue; + session_entry->sap_advertise_avoid_ch_ie = + (uint8_t)msg->bodyval; + /* + * if message comes for DFS channel, no need to update: + * 1) We wont 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(mac_ctx->pdev, + session_entry->currentOperChannel) + != CHANNEL_STATE_DFS) { + beacon_params.bssIdx = session_entry->bssIdx; + 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_HW_MODE_TRANS_IND: + lim_process_hw_mode_trans_ind(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_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 WMA_SEND_BCN_RSP: + lim_send_bcn_rsp(mac_ctx, (tpSendbeaconParams)msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_ROAM_BLACKLIST_MSG: + lim_add_roam_blacklist_ap(mac_ctx, + (struct roam_blacklist_event *) + msg->bodyptr); + 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. + * + * @pMac: Pointer to Global MAC structure + * @return None + */ + +static void lim_process_deferred_message_queue(tpAniSirGlobal pMac) +{ + struct scheduler_msg limMsg = {0}; + struct scheduler_msg *readMsg; + uint16_t size; + + /* + ** check any deferred messages need to be processed + **/ + size = pMac->lim.gLimDeferredMsgQ.size; + if (size > 0) { + while ((readMsg = lim_read_deferred_msg_q(pMac)) != NULL) { + qdf_mem_copy((uint8_t *) &limMsg, + (uint8_t *) readMsg, + sizeof(struct scheduler_msg)); + size--; + lim_process_messages(pMac, &limMsg); + + if ((lim_is_system_in_scan_state(pMac)) + || (true != GET_LIM_PROCESS_DEFD_MESGS(pMac)) + || pMac->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(tpAniSirGlobal 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)) && + (!(lim_is_system_in_scan_state(mac_ctx))) && + (true == 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(tpAniSirGlobal 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 defered 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) || + (lim_is_system_in_scan_state(mac_ctx))) && 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) { +#ifdef WLAN_DEBUG + mac_ctx->lim.numSme++; +#endif + 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 distinquish + * and send response to host + */ + if (rsp_reqd) + mac_ctx->lim.gLimRspReqd = true; +#ifdef WLAN_DEBUG + mac_ctx->lim.numSme++; +#endif + 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 sAniSirGlobal *pMac, + tpPESession psessionEntry) +{ + tSirMacHTCapabilityInfo macHTCapabilityInfo; + tSirMacHTParametersInfo macHTParametersInfo; + tSirMacHTInfoField1 macHTInfoField1; + tSirMacHTInfoField2 macHTInfoField2; + tSirMacHTInfoField3 macHTInfoField3; + uint32_t cfgValue; + uint8_t *ptr; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &cfgValue) != + QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve WNI_CFG_HT_CAP_INFO value"); + return; + } + ptr = (uint8_t *) &macHTCapabilityInfo; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTLsigTXOPProtection = + (uint8_t) macHTCapabilityInfo.lsigTXOPProtection; + pMac->lim.gHTMIMOPSState = + (tSirMacHTMIMOPowerSaveState) macHTCapabilityInfo.mimoPowerSave; + pMac->lim.gHTGreenfield = (uint8_t) macHTCapabilityInfo.greenField; + pMac->lim.gHTMaxAmsduLength = + (uint8_t) macHTCapabilityInfo.maximalAMSDUsize; + pMac->lim.gHTShortGI20Mhz = (uint8_t) macHTCapabilityInfo.shortGI20MHz; + pMac->lim.gHTShortGI40Mhz = (uint8_t) macHTCapabilityInfo.shortGI40MHz; + pMac->lim.gHTPSMPSupport = (uint8_t) macHTCapabilityInfo.psmp; + pMac->lim.gHTDsssCckRate40MHzSupport = + (uint8_t) macHTCapabilityInfo.dsssCckMode40MHz; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &cfgValue) != + QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve WNI_CFG_HT_PARAM_INFO value"); + return; + } + ptr = (uint8_t *) &macHTParametersInfo; + *ptr = (uint8_t) (cfgValue & 0xff); + pMac->lim.gHTAMpduDensity = (uint8_t) macHTParametersInfo.mpduDensity; + pMac->lim.gHTMaxRxAMpduFactor = + (uint8_t) macHTParametersInfo.maxRxAMPDUFactor; + + /* Get HT IE Info */ + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD1, &cfgValue) != + QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve WNI_CFG_HT_INFO_FIELD1 value"); + return; + } + ptr = (uint8_t *) &macHTInfoField1; + *((uint8_t *) ptr) = (uint8_t) (cfgValue & 0xff); + pMac->lim.gHTServiceIntervalGranularity = + (uint8_t) macHTInfoField1.serviceIntervalGranularity; + pMac->lim.gHTControlledAccessOnly = + (uint8_t) macHTInfoField1.controlledAccessOnly; + pMac->lim.gHTRifsMode = (uint8_t) macHTInfoField1.rifsMode; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD2, &cfgValue) != + QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve WNI_CFG_HT_INFO_FIELD2 value"); + return; + } + ptr = (uint8_t *) &macHTInfoField2; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTOperMode = (tSirMacHTOperatingMode) macHTInfoField2.opMode; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD3, &cfgValue) != + QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve WNI_CFG_HT_INFO_FIELD3 value"); + return; + } + ptr = (uint8_t *) &macHTInfoField3; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTPCOActive = (uint8_t) macHTInfoField3.pcoActive; + pMac->lim.gHTPCOPhase = (uint8_t) macHTInfoField3.pcoPhase; + pMac->lim.gHTSecondaryBeacon = + (uint8_t) macHTInfoField3.secondaryBeacon; + pMac->lim.gHTDualCTSProtection = + (uint8_t) macHTInfoField3.dualCTSProtection; + pMac->lim.gHTSTBCBasicMCS = (uint8_t) macHTInfoField3.basicSTBCMCS; + + /* 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 sessionEntry = 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 (psessionEntry != NULL) { + psessionEntry->htCapability = + IS_DOT11_MODE_HT(psessionEntry->dot11mode); + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) macHTInfoField3.lsigTXOPProtectionFullSupport; + lim_init_obss_params(pMac, psessionEntry); + } +} + +void lim_log_session_states(tpAniSirGlobal mac_ctx) +{ +#ifdef WLAN_DEBUG + int i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGD, + FL("sysRole(%d) Session (%d)"), + mac_ctx->lim.gLimSystemRole, i); + QDF_TRACE(QDF_MODULE_ID_PE, LOGD, + FL("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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..586409b765ba656adf4ec6654c58a8f1571432e5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c @@ -0,0 +1,725 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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 "cfg_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 "rrm_api.h" +static void lim_handle_sme_reaasoc_result(tpAniSirGlobal, tSirResultCodes, + uint16_t, tpPESession); +/** + * 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(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + uint8_t channel, sec_ch_offset; + struct tLimPreAuthNode *auth_node; + tLimMlmReassocReq *reassoc_req; + tLimMlmReassocCnf reassoc_cnf; + tpPESession session; + + if (msg == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + reassoc_req = (tLimMlmReassocReq *) msg; + session = pe_find_session_by_session_id(mac_ctx, + reassoc_req->sessionId); + if (NULL == 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 " MAC_ADDRESS_STR, + reassoc_req->sessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, MAC_ADDR_ARRAY(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("unexpect msg state: %X role: %d MAC" MAC_ADDRESS_STR, + session->limMlmState, GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(reassoc_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + reassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + 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 = eSIR_MAC_UNSPEC_FAILURE_STATUS; + + goto end; + } + /* assign the sessionId to the timer object */ + mac_ctx->lim.limTimers.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)); + + /* Derive channel from BSS description and store it at CFG. */ + channel = session->limReassocChannelId; + sec_ch_offset = session->reAssocHtSecondaryChannelOffset; + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session); + + /* store the channel switch sessionEntry in the lim global var */ + session->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_REASSOC; + + /* Switch channel to the new Operating channel for Reassoc */ + lim_set_channel(mac_ctx, channel, + session->ch_center_freq_seg0, + session->ch_center_freq_seg1, + session->ch_width, + session->maxTxPower, + session->peSessionId, 0, 0); + + return; +end: + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio 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 + * @pMac: Global MAC Context + * @resultCode: Result code + * @protStatusCode: Protocol Status Code + * @psessionEntry: 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(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint16_t protStatusCode, + tpPESession psessionEntry) +{ + tpDphHashNode pStaDs = NULL; + uint8_t smesessionId; + uint16_t smetransactionId; + + if (psessionEntry == NULL) { + pe_err("psessionEntry is NULL"); + return; + } + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + if (resultCode != eSIR_SME_SUCCESS) { + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + pStaDs->mlmStaContext.disassocReason = + eSIR_MAC_UNSPEC_FAILURE_REASON; + pStaDs->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + pStaDs->mlmStaContext.resultCode = resultCode; + pStaDs->mlmStaContext.protStatusCode = protStatusCode; + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + /* Cleanup if add bss failed */ + if (psessionEntry->add_bss_failed) { + dph_delete_hash_entry(pMac, + pStaDs->staAddr, pStaDs->assocId, + &psessionEntry->dph.dphHashTable); + goto error; + } + return; + } + } +error: + /* Delete the session if REASSOC failure occurred. */ + if (resultCode != eSIR_SME_SUCCESS) { + if (NULL != psessionEntry) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + } + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP, resultCode, + protStatusCode, psessionEntry, smesessionId, smetransactionId); +} + +/** + * 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(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpPESession session; + tLimMlmReassocCnf *lim_mlm_reassoc_cnf; + + if (msg_buf == NULL) { + 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 == NULL) { + 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 + + pe_debug("Rcv MLM_REASSOC_CNF with result code: %d", + lim_mlm_reassoc_cnf->resultCode); + 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)); + + /* 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, + session->transactionId); + } else if (lim_mlm_reassoc_cnf->resultCode + == 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, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session, session->smeSessionId, + session->transactionId); + } 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, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session); + } + + if (session->pLimReAssocReq) { + qdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } +} + +/** + * lim_process_sta_mlm_add_bss_rsp_ft() - Handle the ADD BSS response + * @pMac: Global MAC context + * @limMsgQ: ADD BSS Parameters + * @psessionEntry: PE Session + * + * Function to handle WMA_ADD_BSS_RSP, in FT reassoc state. + * Send ReAssociation Request. + * + *Return: None + */ +void lim_process_sta_mlm_add_bss_rsp_ft(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tpDphHashNode pStaDs = NULL; + tpAddStaParams pAddStaParams = NULL; + uint32_t listenInterval = WNI_CFG_LISTEN_INTERVAL_STADEF; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + uint32_t selfStaDot11Mode = 0; + + /* Sanity Checks */ + + if (pAddBssParams == NULL) { + pe_err("Invalid parameters"); + goto end; + } + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE != + psessionEntry->limMlmState) { + goto end; + } + + pStaDs = dph_add_hash_entry(pMac, pAddBssParams->bssId, + DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + pe_err("could not add hash entry at DPH for"); + lim_print_mac_addr(pMac, pAddBssParams->staContext.staMac, + LOGE); + goto end; + } + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress != true) { +#endif + pMac->lim.limTimers.gLimReassocFailureTimer.sessionId = + psessionEntry->peSessionId; + /* / Start reassociation failure timer */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate + (&pMac->lim.limTimers.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 = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + pMac->lim.pSessionEntry = psessionEntry; + if (NULL == pMac->lim.pSessionEntry->pLimMlmReassocRetryReq) { + /* Take a copy of reassoc request for retrying */ + pMac->lim.pSessionEntry->pLimMlmReassocRetryReq = + qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == + pMac->lim.pSessionEntry->pLimMlmReassocRetryReq) + goto end; + qdf_mem_copy(pMac->lim.pSessionEntry-> + pLimMlmReassocRetryReq, + psessionEntry->pLimMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + pMac->lim.reAssocRetryAttempt = 0; + lim_send_reassoc_req_with_ft_ies_mgmt_frame(pMac, + psessionEntry-> + pLimMlmReassocReq, + psessionEntry); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } else { + pe_debug("LFR3:Do not activate timer and dont send the reassoc"); + } +#endif + psessionEntry->limPrevMlmState = psessionEntry->limMlmState; + psessionEntry->limMlmState = eLIM_MLM_WT_FT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE)); + pe_debug("Set the mlm state: %d session: %d", + psessionEntry->limMlmState, psessionEntry->peSessionId); + + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + + /* Success, handle below */ + pStaDs->bssId = pAddBssParams->bssIdx; + /* STA Index(genr by HAL) for the BSS entry is stored here */ + pStaDs->staIndex = pAddBssParams->staContext.staIdx; + + rrm_cache_mgmt_tx_power(pMac, pAddBssParams->txMgmtPower, + psessionEntry); + + pAddStaParams = qdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == pAddStaParams) { + pe_err("Unable to allocate memory during ADD_STA"); + goto end; + } + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + qdf_mem_copy((uint8_t *) pAddStaParams->staMac, + (uint8_t *) psessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *) pAddStaParams->bssId, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = QDF_STATUS_SUCCESS; + pAddStaParams->respReqd = 1; + + /* Update PE session ID */ + pAddStaParams->sessionId = psessionEntry->peSessionId; + pAddStaParams->smesessionId = psessionEntry->smeSessionId; + + /* This will indicate HAL to "allocate" a new STA index */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress != true) +#endif + pAddStaParams->staIdx = STA_INVALID_IDX; + pAddStaParams->updateSta = false; + + pAddStaParams->shortPreambleSupported = + (uint8_t) psessionEntry->beaconParams.fShortPreamble; + lim_populate_peer_rate_set(pMac, &pAddStaParams->supportedRates, NULL, + false, psessionEntry, NULL, NULL); + + if (psessionEntry->htCapability) { + pAddStaParams->htCapable = psessionEntry->htCapability; + pAddStaParams->vhtCapable = psessionEntry->vhtCapability; + pAddStaParams->ch_width = psessionEntry->ch_width; + pAddStaParams->greenFieldCapable = + lim_get_ht_capability(pMac, eHT_GREENFIELD, + psessionEntry); + pAddStaParams->mimoPS = + lim_get_ht_capability(pMac, eHT_MIMO_POWER_SAVE, + psessionEntry); + pAddStaParams->rifsMode = + lim_get_ht_capability(pMac, eHT_RIFS_MODE, + psessionEntry); + pAddStaParams->lsigTxopProtection = + lim_get_ht_capability(pMac, eHT_LSIG_TXOP_PROTECTION, + psessionEntry); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(pMac, eHT_MPDU_DENSITY, + psessionEntry); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(pMac, eHT_MAX_RX_AMPDU_FACTOR, + psessionEntry); + pAddStaParams->maxAmsduSize = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_LENGTH, + psessionEntry); + pAddStaParams->max_amsdu_num = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_NUM, + psessionEntry); + pAddStaParams->fDsssCckMode40Mhz = + lim_get_ht_capability(pMac, eHT_DSSS_CCK_MODE_40MHZ, + psessionEntry); + pAddStaParams->fShortGI20Mhz = + lim_get_ht_capability(pMac, eHT_SHORT_GI_20MHZ, + psessionEntry); + pAddStaParams->fShortGI40Mhz = + lim_get_ht_capability(pMac, eHT_SHORT_GI_40MHZ, + psessionEntry); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != + QDF_STATUS_SUCCESS) + pe_err("Couldn't get LISTEN_INTERVAL"); + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfStaDot11Mode); + pAddStaParams->encryptType = psessionEntry->encryptType; + pAddStaParams->maxTxPower = psessionEntry->maxTxPower; + + /* Lets save this for when we receive the Reassoc Rsp */ + psessionEntry->ftPEContext.pAddStaReq = pAddStaParams; + + if (pAddBssParams != NULL) { + qdf_mem_free(pAddBssParams); + pAddBssParams = NULL; + limMsgQ->bodyptr = NULL; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress) { + pe_debug("LFR3:Prep and save AddStaReq for post-assoc-rsp"); + lim_process_assoc_rsp_frame(pMac, pMac->roam.pReassocResp, + LIM_REASSOC, psessionEntry); + } +#endif + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (psessionEntry != NULL) + if (psessionEntry->pLimMlmReassocReq != NULL) { + qdf_mem_free(psessionEntry->pLimMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + } + + if (pAddBssParams != NULL) { + qdf_mem_free(pAddBssParams); + pAddBssParams = NULL; + limMsgQ->bodyptr = NULL; + } + + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE session Id */ + if (psessionEntry != NULL) + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + else + mlmReassocCnf.sessionId = 0; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_process_mlm_ft_reassoc_req() - Handle the Reassoc request + * @pMac: Global MAC context + * @pMsgBuf: Buffer which holds the data + * @psessionEntry: PE Session + * + * This function handles the Reassoc Req from SME + * + * Return: None + */ +void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tpPESession psessionEntry) +{ + uint8_t smeSessionId = 0; + uint16_t transactionId = 0; + uint8_t chanNum = 0; + tLimMlmReassocReq *pMlmReassocReq; + uint16_t caps; + uint32_t val; + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode; + uint32_t teleBcnEn = 0; + + chanNum = psessionEntry->currentOperChannel; + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smeSessionId, + &transactionId); + psessionEntry->smeSessionId = smeSessionId; + psessionEntry->transactionId = transactionId; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_REASSOCIATING, + psessionEntry, 0, 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("psessionEntry is not in STA mode"); + return; + } + + if (NULL == psessionEntry->ftPEContext.pAddBssReq) { + pe_err("pAddBssReq is NULL"); + return; + } + pMlmReassocReq = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == pMlmReassocReq) { + pe_err("call to AllocateMemory failed for mlmReassocReq"); + return; + } + + qdf_mem_copy(pMlmReassocReq->peerMacAddr, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + if (wlan_cfg_get_int(pMac, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &pMlmReassocReq->reassocFailureTimeout) + != QDF_STATUS_SUCCESS) { + /** + * Could not get ReassocFailureTimeout value + * from CFG. Log error. + */ + pe_err("could not retrieve ReassocFailureTimeout value"); + qdf_mem_free(pMlmReassocReq); + return; + } + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != + QDF_STATUS_SUCCESS) { + /** + * Could not get Capabilities value + * from CFG. Log error. + */ + pe_err("could not get Capabilities value"); + qdf_mem_free(pMlmReassocReq); + return; + } + + lim_update_caps_info_for_bss(pMac, &caps, + psessionEntry->pLimReAssocReq->bssDescription.capabilityInfo); + pe_debug("Capabilities info FT Reassoc: 0x%X", caps); + + pMlmReassocReq->capabilityInfo = caps; + + /* Update PE sessionId */ + pMlmReassocReq->sessionId = psessionEntry->peSessionId; + + /* If telescopic beaconing is enabled, set listen interval + to WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(pMac, WNI_CFG_TELE_BCN_WAKEUP_EN, &teleBcnEn) != + QDF_STATUS_SUCCESS) { + pe_err("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN"); + qdf_mem_free(pMlmReassocReq); + return; + } + + if (teleBcnEn) { + if (wlan_cfg_get_int(pMac, WNI_CFG_TELE_BCN_MAX_LI, &val) != + QDF_STATUS_SUCCESS) { + /** + * Could not get ListenInterval value + * from CFG. Log error. + */ + pe_err("could not retrieve ListenInterval"); + qdf_mem_free(pMlmReassocReq); + return; + } + } else { + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &val) != + QDF_STATUS_SUCCESS) { + /** + * Could not get ListenInterval value + * from CFG. Log error. + */ + pe_err("could not retrieve ListenInterval"); + qdf_mem_free(pMlmReassocReq); + return; + } + } + if (lim_set_link_state + (pMac, eSIR_LINK_PREASSOC_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, NULL) != QDF_STATUS_SUCCESS) { + qdf_mem_free(pMlmReassocReq); + return; + } + + pMlmReassocReq->listenInterval = (uint16_t) val; + psessionEntry->pLimMlmReassocReq = pMlmReassocReq; + + /* we need to defer the message until we get response back from HAL */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + msgQ.type = SIR_HAL_ADD_BSS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = psessionEntry->ftPEContext.pAddBssReq; + msgQ.bodyval = 0; + + pe_debug("Sending SIR_HAL_ADD_BSS_REQ"); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + pe_err("Posting ADD_BSS_REQ to HAL failed, reason: %X", + retCode); + } + + psessionEntry->ftPEContext.pAddBssReq = NULL; + return; +} + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..1485cecb55d10fc18ced2331d52d33f2a31d2982 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -0,0 +1,2557 @@ +/* + * 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. + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sir_params.h" +#include "cfg_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 "wlan_reg_services_api.h" +#include "lim_process_fils.h" + +static void lim_process_mlm_start_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_join_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_auth_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_assoc_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_disassoc_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_deauth_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_set_keys_req(tpAniSirGlobal, uint32_t *); + +/* MLM Timeout event handler templates */ +static void lim_process_auth_rsp_timeout(tpAniSirGlobal, uint32_t); +static void lim_process_periodic_join_probe_req_timer(tpAniSirGlobal); +static void lim_process_auth_retry_timer(tpAniSirGlobal); + +/** + * lim_process_sae_auth_timeout() - This function is called to process sae + * auth timeout + * @mac_ctx: Pointer to Global MAC structure + * + * @Return: None + */ +static void lim_process_sae_auth_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.sae_auth_timer.sessionId); + if (session == NULL) { + 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: + /* + * SAE authentication is not completed. Restore from + * auth state. + */ + if (session->pePersona == QDF_STA_MODE) + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + eSIR_MAC_UNSPEC_FAILURE_REASON, 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + switch (msg->type) { + case LIM_MLM_START_REQ: + lim_process_mlm_start_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_JOIN_REQ: + lim_process_mlm_join_req(mac_ctx, msg->bodyptr); + break; + 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_REASSOC_REQ: + lim_process_mlm_reassoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_DISASSOC_REQ: + lim_process_mlm_disassoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_DEAUTH_REQ: + lim_process_mlm_deauth_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_SETKEYS_REQ: + lim_process_mlm_set_keys_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_DEAUTH_ACK_TIMEOUT: + lim_process_deauth_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 LIM_MLM_TSPEC_REQ: + default: + break; + } /* switch (msg->type) */ +} + +/** + * lim_change_channel_with_callback() - change channel and register callback + * @mac_ctx: global MAC context + * @new_chan: new channel to switch + * @callback: Callback function + * @cbdata: callback data + * @session_entry: PE session pointer + * + * This function is called to change channel and perform off channel operation + * if required. The caller registers a callback to be called at the end of the + * channel change. + * + * Return: None + */ +void +lim_change_channel_with_callback(tpAniSirGlobal mac_ctx, uint8_t new_chan, + CHANGE_CHANNEL_CALLBACK callback, + uint32_t *cbdata, tpPESession session_entry) +{ + pe_debug("Switching channel to %d", new_chan); + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + + mac_ctx->lim.gpchangeChannelCallback = callback; + mac_ctx->lim.gpchangeChannelData = cbdata; + + lim_send_switch_chnl_params(mac_ctx, new_chan, 0, 0, + CH_WIDTH_20MHZ, session_entry->maxTxPower, + session_entry->peSessionId, false, 0, 0); + + return; +} + +/** + * mlm_add_sta() - MLM add sta + * @mac_ctx: global MAC context + * @sta_param: Add sta params + * @bssid: BSSID + * @ht_capable: HT capability + * @session_entry: PE session entry + * + * This function is called to update station parameters + * + * Return: None + */ +static void mlm_add_sta(tpAniSirGlobal mac_ctx, tpAddStaParams sta_param, + uint8_t *bssid, uint8_t ht_capable, tpPESession session_entry) +{ + uint32_t val; + uint32_t self_dot11mode = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_dot11mode); + sta_param->staType = STA_ENTRY_SELF; /* Identifying self */ + + qdf_mem_copy(sta_param->bssId, bssid, sizeof(tSirMacAddr)); + qdf_mem_copy(sta_param->staMac, session_entry->selfMacAddr, + sizeof(tSirMacAddr)); + + /* Configuration related parameters to be changed to support BT-AMP */ + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, + &val)) + pe_warn("Couldn't get LISTEN_INTERVAL"); + sta_param->listenInterval = (uint16_t) val; + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(mac_ctx, WNI_CFG_SHORT_PREAMBLE, + &val)) + pe_warn("Couldn't get SHORT_PREAMBLE"); + sta_param->shortPreambleSupported = (uint8_t) val; + + sta_param->assocId = 0; /* Is SMAC OK with this? */ + sta_param->wmmEnabled = 0; + sta_param->uAPSD = 0; + sta_param->maxSPLen = 0; + sta_param->us32MaxAmpduDuration = 0; + sta_param->maxAmpduSize = 0; /* 0: 8k, 1: 16k,2: 32k,3: 64k, 4:128k */ + + /* For Self STA get the LDPC capability from config.ini */ + sta_param->htLdpcCapable = + (session_entry->txLdpcIniFeatureEnabled & 0x01); + sta_param->vhtLdpcCapable = + ((session_entry->txLdpcIniFeatureEnabled >> 1) & 0x01); + + if (IS_DOT11_MODE_HT(session_entry->dot11mode)) { + sta_param->htCapable = ht_capable; + sta_param->greenFieldCapable = + lim_get_ht_capability(mac_ctx, eHT_GREENFIELD, + session_entry); + sta_param->ch_width = + lim_get_ht_capability(mac_ctx, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, session_entry); + sta_param->mimoPS = + (tSirMacHTMIMOPowerSaveState)lim_get_ht_capability( + mac_ctx, eHT_MIMO_POWER_SAVE, session_entry); + sta_param->rifsMode = + lim_get_ht_capability(mac_ctx, eHT_RIFS_MODE, + session_entry); + sta_param->lsigTxopProtection = + lim_get_ht_capability(mac_ctx, eHT_LSIG_TXOP_PROTECTION, + session_entry); + sta_param->maxAmpduDensity = + lim_get_ht_capability(mac_ctx, eHT_MPDU_DENSITY, + session_entry); + sta_param->maxAmsduSize = + lim_get_ht_capability(mac_ctx, eHT_MAX_AMSDU_LENGTH, + session_entry); + sta_param->max_amsdu_num = + lim_get_ht_capability(mac_ctx, eHT_MAX_AMSDU_NUM, + session_entry); + sta_param->fDsssCckMode40Mhz = + lim_get_ht_capability(mac_ctx, eHT_DSSS_CCK_MODE_40MHZ, + session_entry); + sta_param->fShortGI20Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_20MHZ, + session_entry); + sta_param->fShortGI40Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_40MHZ, + session_entry); + } + if (session_entry->vhtCapability) { + sta_param->vhtCapable = true; + sta_param->vhtTxBFCapable = + session_entry->vht_config.su_beam_formee; + sta_param->vhtTxMUBformeeCapable = + session_entry->vht_config.mu_beam_formee; + sta_param->enable_su_tx_bformer = + session_entry->vht_config.su_beam_former; + } + + if (lim_is_session_he_capable(session_entry)) + lim_add_self_he_cap(sta_param, session_entry); + + /* + * Since this is Self-STA, need to populate Self MAX_AMPDU_SIZE + * capabilities + */ + if (IS_DOT11_MODE_VHT(self_dot11mode)) { + val = 0; /* Default 8K AMPDU size */ + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &val)) + pe_err("Couldn't get WNI_CFG_VHT_AMPDU_LEN_EXPONENT"); + sta_param->maxAmpduSize = (uint8_t) val; + } + sta_param->enableVhtpAid = session_entry->enableVhtpAid; + sta_param->enableAmpduPs = session_entry->enableAmpduPs; + sta_param->enableHtSmps = session_entry->enableHtSmps; + sta_param->htSmpsconfig = session_entry->htSmpsvalue; + sta_param->send_smps_action = session_entry->send_smps_action; + + lim_populate_own_rate_set(mac_ctx, &sta_param->supportedRates, NULL, + false, session_entry, NULL, NULL); + + pe_debug("GF: %d, ChnlWidth: %d, MimoPS: %d, lsigTXOP: %d, dsssCCK: %d," + " SGI20: %d, SGI40%d", sta_param->greenFieldCapable, + sta_param->ch_width, sta_param->mimoPS, + sta_param->lsigTxopProtection, sta_param->fDsssCckMode40Mhz, + sta_param->fShortGI20Mhz, sta_param->fShortGI40Mhz); + + if (QDF_P2P_GO_MODE == session_entry->pePersona) + sta_param->p2pCapableSta = 1; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tLimMlmStartReq *mlm_start_req, tpPESession session) +{ + struct scheduler_msg msg_buf = {0}; + tpAddBssParams addbss_param = NULL; + uint32_t retcode; + bool is_ch_dfs = false; + + /* Package WMA_ADD_BSS_REQ message parameters */ + addbss_param = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == addbss_param) { + pe_err("Unable to allocate memory during ADD_BSS"); + /* Respond to SME with LIM_MLM_START_CNF */ + return eSIR_SME_RESOURCES_UNAVAILABLE; + } + + /* Fill in tAddBssParams members */ + qdf_mem_copy(addbss_param->bssId, mlm_start_req->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(addbss_param->selfMacAddr, + session->selfMacAddr, sizeof(tSirMacAddr)); + + addbss_param->bssType = mlm_start_req->bssType; + if (mlm_start_req->bssType == eSIR_IBSS_MODE) + addbss_param->operMode = BSS_OPERATIONAL_MODE_STA; + else if (mlm_start_req->bssType == eSIR_INFRA_AP_MODE) + addbss_param->operMode = BSS_OPERATIONAL_MODE_AP; + else if (mlm_start_req->bssType == eSIR_NDI_MODE) + addbss_param->operMode = BSS_OPERATIONAL_MODE_NDI; + + addbss_param->shortSlotTimeSupported = session->shortSlotTimeSupported; + addbss_param->beaconInterval = mlm_start_req->beaconPeriod; + addbss_param->dtimPeriod = mlm_start_req->dtimPeriod; + addbss_param->wps_state = mlm_start_req->wps_state; + addbss_param->cfParamSet.cfpCount = mlm_start_req->cfParamSet.cfpCount; + addbss_param->cfParamSet.cfpPeriod = + mlm_start_req->cfParamSet.cfpPeriod; + addbss_param->cfParamSet.cfpMaxDuration = + mlm_start_req->cfParamSet.cfpMaxDuration; + addbss_param->cfParamSet.cfpDurRemaining = + mlm_start_req->cfParamSet.cfpDurRemaining; + + addbss_param->rateSet.numRates = mlm_start_req->rateSet.numRates; + if (addbss_param->rateSet.numRates > SIR_MAC_RATESET_EID_MAX) { + pe_warn("num of sup rates %d exceeding the limit %d, resetting", + addbss_param->rateSet.numRates, + SIR_MAC_RATESET_EID_MAX); + addbss_param->rateSet.numRates = SIR_MAC_RATESET_EID_MAX; + } + qdf_mem_copy(addbss_param->rateSet.rate, mlm_start_req->rateSet.rate, + addbss_param->rateSet.numRates); + + addbss_param->nwType = mlm_start_req->nwType; + addbss_param->htCapable = mlm_start_req->htCapable; + addbss_param->vhtCapable = session->vhtCapability; + if (lim_is_session_he_capable(session)) { + lim_update_bss_he_capable(mac_ctx, addbss_param); + lim_decide_he_op(mac_ctx, addbss_param, session); + lim_update_usr_he_cap(mac_ctx, session); + } + + addbss_param->ch_width = session->ch_width; + addbss_param->ch_center_freq_seg0 = + session->ch_center_freq_seg0; + addbss_param->ch_center_freq_seg1 = + session->ch_center_freq_seg1; + addbss_param->htOperMode = mlm_start_req->htOperMode; + addbss_param->dualCTSProtection = mlm_start_req->dualCTSProtection; + addbss_param->txChannelWidthSet = mlm_start_req->txChannelWidthSet; + + addbss_param->currentOperChannel = mlm_start_req->channelNumber; +#ifdef WLAN_FEATURE_11W + addbss_param->rmfEnabled = session->limRmfEnabled; +#endif + + /* Update PE sessionId */ + addbss_param->sessionId = mlm_start_req->sessionId; + + /* Send the SSID to HAL to enable SSID matching for IBSS */ + addbss_param->ssId.length = mlm_start_req->ssId.length; + if (addbss_param->ssId.length > SIR_MAC_MAX_SSID_LENGTH) { + pe_err("Invalid ssid length %d, max length allowed %d", + addbss_param->ssId.length, + SIR_MAC_MAX_SSID_LENGTH); + qdf_mem_free(addbss_param); + return eSIR_SME_INVALID_PARAMETERS; + } + qdf_mem_copy(addbss_param->ssId.ssId, + mlm_start_req->ssId.ssId, addbss_param->ssId.length); + addbss_param->bHiddenSSIDEn = mlm_start_req->ssidHidden; + pe_debug("TRYING TO HIDE SSID %d", addbss_param->bHiddenSSIDEn); + /* CR309183. Disable Proxy Probe Rsp. Host handles Probe Requests. Until FW fixed. */ + addbss_param->bProxyProbeRespEn = 0; + addbss_param->obssProtEnabled = mlm_start_req->obssProtEnabled; + + addbss_param->maxTxPower = session->maxTxPower; + + mlm_add_sta(mac_ctx, &addbss_param->staContext, + addbss_param->bssId, addbss_param->htCapable, + session); + + addbss_param->status = QDF_STATUS_SUCCESS; + addbss_param->respReqd = 1; + + /* 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)); + + /* pass on the session persona to hal */ + addbss_param->halPersona = session->pePersona; + + if (session->ch_width == CH_WIDTH_160MHZ) { + is_ch_dfs = true; + } else if (session->ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state(mac_ctx->pdev, + mlm_start_req->channelNumber) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state(mac_ctx->pdev, + session->ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + if (wlan_reg_get_channel_state(mac_ctx->pdev, + mlm_start_req->channelNumber) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } + + addbss_param->bSpectrumMgtEnabled = + session->spectrumMgtEnabled || is_ch_dfs; + addbss_param->extSetStaKeyParamValid = 0; + + addbss_param->dot11_mode = session->dot11mode; + addbss_param->nss = session->nss; + addbss_param->cac_duration_ms = mlm_start_req->cac_duration_ms; + addbss_param->dfs_regdomain = mlm_start_req->dfs_regdomain; + addbss_param->beacon_tx_rate = session->beacon_tx_rate; + if (QDF_IBSS_MODE == addbss_param->halPersona) { + addbss_param->nss_2g = mac_ctx->vdev_type_nss_2g.ibss; + addbss_param->nss_5g = mac_ctx->vdev_type_nss_5g.ibss; + addbss_param->tx_aggregation_size = + mac_ctx->roam.configParam.tx_aggregation_size; + addbss_param->tx_aggregation_size_be = + mac_ctx->roam.configParam.tx_aggregation_size_be; + addbss_param->tx_aggregation_size_bk = + mac_ctx->roam.configParam.tx_aggregation_size_bk; + addbss_param->tx_aggregation_size_vi = + mac_ctx->roam.configParam.tx_aggregation_size_vi; + addbss_param->tx_aggregation_size_vo = + mac_ctx->roam.configParam.tx_aggregation_size_vo; + addbss_param->rx_aggregation_size = + mac_ctx->roam.configParam.rx_aggregation_size; + } + pe_debug("dot11_mode:%d nss value:%d", + addbss_param->dot11_mode, addbss_param->nss); + + if (cds_is_5_mhz_enabled()) { + addbss_param->ch_width = CH_WIDTH_5MHZ; + addbss_param->staContext.ch_width = CH_WIDTH_5MHZ; + } else if (cds_is_10_mhz_enabled()) { + addbss_param->ch_width = CH_WIDTH_10MHZ; + addbss_param->staContext.ch_width = CH_WIDTH_10MHZ; + } + + msg_buf.type = WMA_ADD_BSS_REQ; + msg_buf.reserved = 0; + msg_buf.bodyptr = addbss_param; + msg_buf.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, session->peSessionId, msg_buf.type)); + + pe_debug("Sending WMA_ADD_BSS_REQ..."); + retcode = wma_post_ctrl_msg(mac_ctx, &msg_buf); + if (QDF_STATUS_SUCCESS != retcode) { + pe_err("Posting ADD_BSS_REQ to HAL failed, reason=%X", + retcode); + qdf_mem_free(addbss_param); + return eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + + return eSIR_SME_SUCCESS; +} + +/** + * lim_process_mlm_start_req() - process MLM_START_REQ message + * + * @mac_ctx: global MAC context + * @msg_buf: Pointer to MLM message buffer + * + * This function is called to process MLM_START_REQ message + * from SME + * 1) MLME receives LIM_MLM_START_REQ from LIM + * 2) MLME sends WMA_ADD_BSS_REQ to HAL + * 3) MLME changes state to eLIM_MLM_WT_ADD_BSS_RSP_STATE + * MLME now waits for HAL to send WMA_ADD_BSS_RSP + * + * Return: None + */ +static void lim_process_mlm_start_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmStartReq *mlm_start_req; + tLimMlmStartCnf mlm_start_cnf; + tpPESession session = NULL; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mlm_start_req = (tLimMlmStartReq *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + mlm_start_req->sessionId); + if (NULL == 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; + + /* Free up buffer allocated for LimMlmScanReq */ + qdf_mem_free(msg_buf); + + /* + * 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_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); +} + +/** + * lim_post_join_set_link_state_callback()- registered callback to perform post + * peer creation operations + * + * @mac: pointer to global mac structure + * @callback_arg: registered callback argument + * @status: peer creation status + * + * this is registered callback function during association to perform + * post peer creation operation based on the peer creation status + * + * Return: none + */ +static void lim_post_join_set_link_state_callback(tpAniSirGlobal mac, + void *callback_arg, bool status) +{ + uint8_t chan_num, sec_chan_offset; + struct session_params *session_cb_param = + (struct session_params *)callback_arg; + tLimMlmJoinCnf mlm_join_cnf; + + tpPESession session_entry = pe_find_session_by_session_id(mac, + session_cb_param->session_id); + if (!session_entry) { + pe_err("sessionId:%d does not exist", + session_cb_param->session_id); + qdf_mem_free(session_cb_param); + return; + } + + qdf_mem_free(session_cb_param); + pe_debug("Sessionid %d set link state(%d) cb status: %d", + session_entry->peSessionId, session_entry->limMlmState, + status); + + if (!status) { + pe_err("failed to find pe session for session id:%d", + session_entry->peSessionId); + goto failure; + } + + chan_num = session_entry->currentOperChannel; + sec_chan_offset = session_entry->htSecondaryChannelOffset; + /* + * store the channel switch session_entry in the lim + * global variable + */ + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_JOIN; + session_entry->pLimMlmReassocRetryReq = NULL; + pe_debug("[lim_process_mlm_join_req]: suspend link success(%d) " + "on sessionid: %d setting channel to: %d with ch_width :%d " + "and maxtxPower: %d", status, session_entry->peSessionId, + session_entry->currentOperChannel, + session_entry->ch_width, + session_entry->maxTxPower); + lim_set_channel(mac, session_entry->currentOperChannel, + session_entry->ch_center_freq_seg0, + session_entry->ch_center_freq_seg1, + session_entry->ch_width, + session_entry->maxTxPower, + session_entry->peSessionId, 0, 0); + return; + +failure: + MTRACE(mac_trace(mac, TRACE_CODE_MLM_STATE, session_entry->peSessionId, + session_entry->limMlmState)); + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + mlm_join_cnf.resultCode = eSIR_SME_PEER_CREATE_FAILED; + mlm_join_cnf.sessionId = session_entry->peSessionId; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac, LIM_MLM_JOIN_CNF, (uint32_t *) &mlm_join_cnf); +} + +/** + * lim_process_mlm_post_join_suspend_link() - This function is called after the + * suspend link while joining off channel. + * + * @mac_ctx: Pointer to Global MAC structure + * @status: status of suspend link. + * @ctx: passed while calling suspend link(session) + * + * This function does following: + * Check for suspend state. + * If success, proceed with setting link state to receive the + * probe response/beacon from intended AP. + * Switch to the APs channel. + * On an error case, send the MLM_JOIN_CNF with error status. + * + * @Return None + */ +static void +lim_process_mlm_post_join_suspend_link(tpAniSirGlobal mac_ctx, + QDF_STATUS status, + uint32_t *ctx) +{ + tLimMlmJoinCnf mlm_join_cnf; + tpPESession session = (tpPESession) ctx; + tSirLinkState lnk_state; + struct session_params *pe_session_param = NULL; + + if (QDF_STATUS_SUCCESS != status) { + pe_err("Sessionid %d Suspend link(NOTIFY_BSS) failed. Still proceeding with join", + session->peSessionId); + } + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.limTimers.gLimJoinFailureTimer.sessionId = + session->peSessionId; + + lnk_state = eSIR_LINK_PREASSOC_STATE; + pe_debug("[lim_process_mlm_join_req]: lnk_state: %d", + lnk_state); + + pe_session_param = qdf_mem_malloc(sizeof(struct session_params)); + if (pe_session_param) { + pe_session_param->session_id = session->peSessionId; + } else { + pe_err("insufficient memory"); + goto error; + } + if (lim_set_link_state(mac_ctx, lnk_state, + session->pLimMlmJoinReq->bssDescription.bssId, + session->selfMacAddr, + lim_post_join_set_link_state_callback, + pe_session_param) != QDF_STATUS_SUCCESS) { + pe_err("SessionId:%d lim_set_link_state to eSIR_LINK_PREASSOC_STATE Failed!!", + session->peSessionId); + lim_print_mac_addr(mac_ctx, + session->pLimMlmJoinReq->bssDescription.bssId, LOGE); + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + qdf_mem_free(pe_session_param); + goto error; + } + + return; +error: + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlm_join_cnf.sessionId = session->peSessionId; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); +} + +/** + * 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 + */ +static void lim_process_mlm_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + tLimMlmJoinCnf mlmjoin_cnf; + uint8_t sessionid; + tpPESession session; + + sessionid = ((tpLimMlmJoinReq) msg)->sessionId; + + session = pe_find_session_by_session_id(mac_ctx, sessionid); + if (NULL == session) { + pe_err("SessionId:%d does not exist", sessionid); + goto error; + } + + if (!LIM_IS_AP_ROLE(session) && + ((session->limMlmState == eLIM_MLM_IDLE_STATE) || + (session->limMlmState == eLIM_MLM_JOINED_STATE)) && + (SIR_MAC_GET_ESS + (((tpLimMlmJoinReq) msg)->bssDescription.capabilityInfo) != + SIR_MAC_GET_IBSS(((tpLimMlmJoinReq) msg)->bssDescription. + capabilityInfo))) { + /* Hold onto Join request parameters */ + + session->pLimMlmJoinReq = (tpLimMlmJoinReq) msg; + if (is_lim_session_off_channel(mac_ctx, sessionid)) { + pe_debug("SessionId:%d LimSession is on OffChannel", + sessionid); + /* suspend link */ + pe_debug("Suspend link, sessionid %d is off channel", + sessionid); + lim_process_mlm_post_join_suspend_link(mac_ctx, + QDF_STATUS_SUCCESS, (uint32_t *)session); + } else { + pe_debug("No need to Suspend link"); + /* + * No need to Suspend link as LimSession is not + * off channel, calling + * lim_process_mlm_post_join_suspend_link with + * status as SUCCESS. + */ + pe_debug("SessionId:%d Join req on current chan", + sessionid); + lim_process_mlm_post_join_suspend_link(mac_ctx, + QDF_STATUS_SUCCESS, (uint32_t *)session); + } + return; + } else { + /** + * Should not have received JOIN req in states other than + * Idle state or on AP. + * Return join confirm with invalid parameters code. + */ + pe_err("Session:%d Unexpected Join req, role %d state %X", + session->peSessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + } + +error: + qdf_mem_free(msg); + if (session != NULL) + session->pLimMlmJoinReq = NULL; + mlmjoin_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlmjoin_cnf.sessionId = sessionid; + mlmjoin_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *)&mlmjoin_cnf); + +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + bool flag = false; + + /* + * Expect Auth request only when: + * 1. STA joined/associated with a BSS or + * 2. STA is in IBSS mode + * and 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))) || + (LIM_IS_IBSS_ROLE(session) && + (session->limMlmState == + eLIM_MLM_BSS_STARTED_STATE))) && + (!lim_is_group_addr(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)) + && lim_is_auth_algo_supported(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->authType, session)); + + return flag; +} + +/** + * lim_is_preauth_ctx_exisits() - 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(tpAniSirGlobal mac_ctx, + tpPESession 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 != NULL) && + (mac_ctx->lim.gpLimMlmAuthReq->authType == + stads->mlmStaContext.authType)) && + (!qdf_mem_cmp(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + curr_bssid, sizeof(tSirMacAddr)))) || + ((preauth_node != NULL) && + (preauth_node->authType == + mac_ctx->lim.gpLimMlmAuthReq->authType))); + + return fl; +} + +#ifdef WLAN_FEATURE_SAE +/** + * 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(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct sir_sae_info *sae_info; + struct scheduler_msg msg = {0}; + + sae_info = qdf_mem_malloc(sizeof(*sae_info)); + if (sae_info == NULL) { + pe_err("Memory allocation failed"); + 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_mem_copy(sae_info->peer_mac_addr.bytes, + session->bssId, + QDF_MAC_ADDR_SIZE); + + 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 %.*s "MAC_ADDRESS_STR"", + sae_info->vdev_id, + sae_info->ssid.length, + sae_info->ssid.ssId, + MAC_ADDR_ARRAY(sae_info->peer_mac_addr.bytes)); + + 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; + } + session->limMlmState = eLIM_MLM_WT_SAE_AUTH_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + mac_ctx->lim.limTimers.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.limTimers.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(tpAniSirGlobal mac_ctx, + tpPESession 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(tpAniSirGlobal 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; + tpPESession session; + + if (msg == NULL) { + 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 (NULL == session) { + pe_err("SessionId:%d does not exist", session_id); + qdf_mem_free(msg); + mac_ctx->lim.gpLimMlmAuthReq = NULL; + return; + } + + pe_debug("Process Auth Req sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR + " with authtype %d", session_id, + GET_LIM_SYSTEM_ROLE(session), session->limMlmState, + MAC_ADDR_ARRAY(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. + */ + 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: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)); + mlm_auth_cnf.resultCode = (tSirResultCodes) + eSIR_MAC_SUCCESS_STATUS; + goto end; + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_MAX_NUM_PRE_AUTH, + (uint32_t *) &num_preauth_ctx) != QDF_STATUS_SUCCESS) + pe_warn("Could not retrieve NumPreAuthLimit from CFG"); + + 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; + + 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; + goto end; + } else { + pe_debug("lim_process_mlm_auth_req_sae is successful"); + lim_diag_event_report(mac_ctx, + WLAN_PE_DIAG_AUTH_ALGO_NUM, + session, QDF_STATUS_SUCCESS, + eSIR_AUTH_TYPE_SAE); + 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; + } + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_ALGO_NUM, session, + QDF_STATUS_SUCCESS, auth_frame_body.authAlgoNumber); + + /* Prepare & send Authentication frame */ + auth_frame_body.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; + auth_frame_body.authStatusCode = 0; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_START_EVENT, session, + QDF_STATUS_SUCCESS, auth_frame_body.authStatusCode); +#endif + mac_ctx->auth_ack_status = LIM_AUTH_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.limTimers.gLimAuthFailureTimer.sessionId = session_id; + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.limTimers.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.limTimers.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.limTimers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) + pe_err("could not activate Auth Retry timer"); + } + + 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); +} + +/** + * 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(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tSirMacAddr curr_bssId; + tLimMlmAssocReq *mlm_assoc_req; + tLimMlmAssocCnf mlm_assoc_cnf; + tpPESession session_entry; + + if (msg_buf == NULL) { + 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 == NULL) { + 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= " + MAC_ADDRESS_STR, session_entry->limMlmState, + GET_LIM_SYSTEM_ROLE(session_entry), + MAC_ADDR_ARRAY(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 = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + /* map the session entry pointer to the AssocFailureTimer */ + mac_ctx->lim.limTimers.gLimAssocFailureTimer.sessionId = + mlm_assoc_req->sessionId; + 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("SessionId:%d Sending Assoc_Req Frame", + session_entry->peSessionId); + + /* 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.limTimers.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 assocReq */ + 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(tpAniSirGlobal 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; + tpPESession session; + extern bool send_disassoc_frame; + tLimMlmStates mlm_state; + tSirSmeDisassocRsp *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 (NULL == session) { + pe_err("session does not exist for given sessionId %d", + mlm_disassocreq->sessionId); + mlm_disassoccnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + pe_debug("Process DisAssoc Req on sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR, + mlm_disassocreq->sessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_disassocreq->peer_macaddr.bytes)); + + 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 id"); + lim_print_mac_addr(mac_ctx, + mlm_disassocreq->peer_macaddr.bytes, LOGW); + + /* + * Disassociation response due to host triggered + * disassociation + */ + sme_disassoc_rsp = + qdf_mem_malloc(sizeof(tSirSmeDisassocRsp)); + if (NULL == sme_disassoc_rsp) { + pe_err("memory allocation failed for disassoc rsp"); + qdf_mem_free(mlm_disassocreq); + return; + } + + pe_debug("send disassoc rsp with ret code %d for" MAC_ADDRESS_STR, + eSIR_SME_DEAUTH_STATUS, + MAC_ADDR_ARRAY( + mlm_disassocreq->peer_macaddr.bytes)); + + sme_disassoc_rsp->messageType = eWNI_SME_DISASSOC_RSP; + sme_disassoc_rsp->length = sizeof(tSirSmeDisassocRsp); + sme_disassoc_rsp->sessionId = + mlm_disassocreq->sessionId; + sme_disassoc_rsp->transactionId = 0; + sme_disassoc_rsp->statusCode = 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; + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_AP_ROLE: + case eLIM_P2P_DEVICE_GO: + if (true == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + pe_err("CAC timer is running, drop disassoc from going out"); + mlm_disassoccnf.resultCode = eSIR_SME_SUCCESS; + goto end; + } + 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 == NULL) || + (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= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mlm_disassocreq->peer_macaddr.bytes)); + if (stads != NULL) + 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 = (tSirMacReasonCodes) + 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 != + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON)) { + 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 { + /* 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)) { + 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(tpAniSirGlobal 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(tpAniSirGlobal 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.limTimers.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); + } else { + if (tx_timer_running( + &mac_ctx->lim.limTimers.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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDisassocReq *mlm_disassoc_req; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mlm_disassoc_req = (tLimMlmDisassocReq *) msg_buf; + pe_debug("Process disassoc req, sessionID %d from: "MAC_ADDRESS_STR, + mlm_disassoc_req->sessionId, + MAC_ADDR_ARRAY(mlm_disassoc_req->peer_macaddr.bytes)); + + 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(tpAniSirGlobal mac_ctx, + QDF_STATUS suspend_status, uint32_t *msg_buf) +{ + uint16_t aid; + tSirMacAddr curr_bssId; + tpDphHashNode sta_ds; + struct tLimPreAuthNode *auth_node; + tLimMlmDeauthReq *mlm_deauth_req; + tLimMlmDeauthCnf mlm_deauth_cnf; + tpPESession session; + tSirSmeDeauthRsp *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 (NULL == session) { + pe_err("session does not exist for given sessionId %d", + mlm_deauth_req->sessionId); + qdf_mem_free(mlm_deauth_req); + return; + } + pe_debug("Process Deauth Req on sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR, + mlm_deauth_req->sessionId, + GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_deauth_req->peer_macaddr.bytes)); + 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: "MAC_ADDRESS_STR + " CFG BSSID Addr : "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + mlm_deauth_req->peer_macaddr.bytes), + MAC_ADDR_ARRAY(curr_bssId)); + /* + * Deauthentication response to host triggered + * deauthentication + */ + sme_deauth_rsp = + qdf_mem_malloc(sizeof(tSirSmeDeauthRsp)); + if (NULL == sme_deauth_rsp) { + pe_err("memory allocation failed for deauth rsp"); + qdf_mem_free(mlm_deauth_req); + return; + } + + pe_debug("send deauth rsp with ret code %d for" MAC_ADDRESS_STR, + eSIR_SME_DEAUTH_STATUS, + MAC_ADDR_ARRAY( + mlm_deauth_req->peer_macaddr.bytes)); + + sme_deauth_rsp->messageType = + eWNI_SME_DEAUTH_RSP; + sme_deauth_rsp->length = + sizeof(tSirSmeDeauthRsp); + sme_deauth_rsp->statusCode = + eSIR_SME_DEAUTH_STATUS; + sme_deauth_rsp->sessionId = + mlm_deauth_req->sessionId; + sme_deauth_rsp->transactionId = 0; + + 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 " + MAC_ADDRESS_STR, + session->limMlmState, + MAC_ADDR_ARRAY( + 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; + case eLIM_STA_IN_IBSS_ROLE: + pe_err("received MLM_DEAUTH_REQ IBSS Mode"); + mlm_deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + case eLIM_AP_ROLE: + case eLIM_P2P_DEVICE_GO: + if (true == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + pe_err("CAC timer is running, drop disassoc from going out"); + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + 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 == NULL) { + /* 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 == NULL) { + /* + * Received DEAUTH REQ for a STA that is neither + * Associated nor Pre-authenticated. Log error, + * Prepare and Send LIM_MLM_DEAUTH_CNF + */ + pe_warn("received MLM_DEAUTH_REQ in mlme state %d for STA that " + "does not have context, Addr=" + MAC_ADDRESS_STR, + session->limMlmState, + MAC_ADDR_ARRAY( + 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->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="MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mlm_deauth_req->peer_macaddr.bytes)); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* sta_ds->mlmStaContext.rxPurgeReq = 1; */ + sta_ds->mlmStaContext.disassocReason = (tSirMacReasonCodes) + mlm_deauth_req->reasonCode; + sta_ds->mlmStaContext.cleanupTrigger = mlm_deauth_req->deauthTrigger; + + 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; + + /* + * 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; + /* Send Deauthentication frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, mlm_deauth_req->reasonCode, + mlm_deauth_req->peer_macaddr.bytes, + session, true); + 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 + * + * @mac_ctx: mac_ctx + * + * wrapper function around lim_send_deauth_cnf + * + * Return: void + */ +void lim_process_deauth_ack_timeout(tpAniSirGlobal mac_ctx) +{ + lim_send_deauth_cnf(mac_ctx); +} + +/* + * 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 + */ +static void +lim_process_mlm_deauth_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDeauthReq *mlm_deauth_req; + tpPESession session; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mlm_deauth_req = (tLimMlmDeauthReq *) msg_buf; + pe_debug("Process Deauth Req on sessionID %d from: " + MAC_ADDRESS_STR, + mlm_deauth_req->sessionId, + MAC_ADDR_ARRAY(mlm_deauth_req->peer_macaddr.bytes)); + + session = pe_find_session_by_session_id(mac_ctx, + mlm_deauth_req->sessionId); + if (NULL == 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); +} + +/** + * lim_process_mlm_set_keys_req() - This function is called to process + * MLM_SETKEYS_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_SETKEYS_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + uint16_t aid; + uint16_t sta_idx = 0; + uint32_t default_key_id = 0; + struct qdf_mac_addr curr_bssid; + tpDphHashNode sta_ds; + tLimMlmSetKeysReq *mlm_set_keys_req; + tLimMlmSetKeysCnf mlm_set_keys_cnf; + tpPESession session; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mlm_set_keys_req = (tLimMlmSetKeysReq *) msg_buf; + if (mac_ctx->lim.gpLimMlmSetKeysReq != NULL) { + qdf_mem_zero(mac_ctx->lim.gpLimMlmSetKeysReq, + sizeof(*mlm_set_keys_req)); + qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); + mac_ctx->lim.gpLimMlmSetKeysReq = NULL; + } + /* Hold onto the SetKeys request parameters */ + mac_ctx->lim.gpLimMlmSetKeysReq = (void *)mlm_set_keys_req; + session = pe_find_session_by_session_id(mac_ctx, + mlm_set_keys_req->sessionId); + if (NULL == session) { + pe_err("session does not exist for given sessionId"); + qdf_mem_zero(mlm_set_keys_req->key, + sizeof(mlm_set_keys_req->key)); + mlm_set_keys_req->numKeys = 0; + qdf_mem_free(mlm_set_keys_req); + mac_ctx->lim.gpLimMlmSetKeysReq = NULL; + return; + } + + pe_debug("Received MLM_SETKEYS_REQ with parameters:" + "AID [%d], ED Type [%d], # Keys [%d] & Peer MAC Addr - ", + mlm_set_keys_req->aid, mlm_set_keys_req->edType, + mlm_set_keys_req->numKeys); + lim_print_mac_addr(mac_ctx, mlm_set_keys_req->peer_macaddr.bytes, LOGD); + qdf_mem_copy(curr_bssid.bytes, session->bssId, QDF_MAC_ADDR_SIZE); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + /* + * In case of TDLS, peerMac address need not be BssId. Skip this + * check if TDLS is enabled. + */ +#ifndef FEATURE_WLAN_TDLS + if ((!qdf_is_macaddr_broadcast( + &mlm_set_keys_req->peer_macaddr)) && + (!qdf_is_macaddr_equal(&mlm_set_keys_req->peer_macaddr, + &curr_bssid))) { + pe_debug("Received MLM_SETKEYS_REQ with invalid BSSID" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mlm_set_keys_req-> + peer_macaddr.bytes)); + /* + * Prepare and Send LIM_MLM_SETKEYS_CNF with error code + */ + mlm_set_keys_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } +#endif + break; + case eLIM_STA_IN_IBSS_ROLE: + /* + * update the IBSS PE session encrption type based on the + * key type + */ + session->encryptType = mlm_set_keys_req->edType; + break; + default: + break; + } + + /* + * Use the "unicast" parameter to determine if the "Group Keys" + * are being set. + * mlm_set_keys_req->key.unicast = 0 -> Multicast/broadcast + * mlm_set_keys_req->key.unicast - 1 -> Unicast keys are being set + */ + if (qdf_is_macaddr_broadcast(&mlm_set_keys_req->peer_macaddr)) { + pe_debug("Trying to set Group Keys...%d", + mlm_set_keys_req->sessionId); + /* + * When trying to set Group Keys for any security mode other + * than WEP, use the STA Index corresponding to the AP... + */ + switch (mlm_set_keys_req->edType) { + case eSIR_ED_CCMP: + case eSIR_ED_GCMP: + case eSIR_ED_GCMP_256: +#ifdef WLAN_FEATURE_11W + case eSIR_ED_AES_128_CMAC: + case eSIR_ED_AES_GMAC_128: + case eSIR_ED_AES_GMAC_256: +#endif + sta_idx = session->staId; + break; + default: + break; + } + } else { + pe_debug("Trying to set Unicast Keys..."); + /* + * Check if there exists a context for the + * peer entity for which keys need to be set. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, + mlm_set_keys_req->peer_macaddr.bytes, &aid, + &session->dph.dphHashTable); + if ((sta_ds == NULL) || + ((sta_ds->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + !LIM_IS_AP_ROLE(session))) { + /* + * Received LIM_MLM_SETKEYS_REQ for STA that does not + * have context or in some transit state. + */ + pe_debug("Invalid MLM_SETKEYS_REQ, Addr = " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mlm_set_keys_req-> + peer_macaddr.bytes)); + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + mlm_set_keys_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } else { + sta_idx = sta_ds->staIndex; + } + } + + if ((mlm_set_keys_req->numKeys == 0) + && (mlm_set_keys_req->edType != eSIR_ED_NONE)) { + /* + * Broadcast/Multicast Keys (for WEP!!) are NOT sent + * via this interface!! This indicates to HAL that the WEP Keys + * need to be extracted from the CFG and applied to hardware + */ + default_key_id = 0xff; + } else if (mlm_set_keys_req->key[0].keyId && + ((mlm_set_keys_req->edType == eSIR_ED_WEP40) || + (mlm_set_keys_req->edType == eSIR_ED_WEP104))) { + /* + * If the Key Id is non zero and encryption mode is WEP, + * the key index is coming from the upper layers so that key + * only need to be used as the default tx key, This is being + * used only in case of WEP mode in HAL + */ + default_key_id = mlm_set_keys_req->key[0].keyId; + } else { + default_key_id = 0; + } + pe_debug("Trying to set keys for STA Index [%d], using default_key_id [%d]", + sta_idx, default_key_id); + + if (qdf_is_macaddr_broadcast(&mlm_set_keys_req->peer_macaddr)) { + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_SET_BSS_KEY_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + pe_debug("Trying to set Group Keys...%d", + session->peSessionId); + /* Package WMA_SET_BSSKEY_REQ message parameters */ + lim_send_set_bss_key_req(mac_ctx, mlm_set_keys_req, session); + + return; + } else { + /* + * Package WMA_SET_STAKEY_REQ / WMA_SET_STA_BCASTKEY_REQ message + * parameters + */ + lim_send_set_sta_key_req(mac_ctx, mlm_set_keys_req, sta_idx, + (uint8_t) default_key_id, session, + true); + return; + } +end: + mlm_set_keys_cnf.sessionId = mlm_set_keys_req->sessionId; + lim_post_sme_set_keys_cnf(mac_ctx, mlm_set_keys_req, &mlm_set_keys_cnf); +} + +void lim_process_join_failure_timeout(tpAniSirGlobal mac_ctx) +{ + tLimMlmJoinCnf mlm_join_cnf; + uint32_t len; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + tpPESession session; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimJoinFailureTimer.sessionId); + if (NULL == 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 + + 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 " + MAC_ADDRESS_STR, + session->peSessionId, MAC_ADDR_ARRAY(session->bssId)); + + mlm_join_cnf.resultCode = eSIR_SME_JOIN_TIMEOUT_RESULT_CODE; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + 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(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + tSirMacSSid ssid; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer.sessionId); + if (NULL == session) { + pe_err("session does not exist for given SessionId: %d", + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer. + sessionId); + return; + } + + if ((true == + tx_timer_running(&mac_ctx->lim.limTimers.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; + lim_send_probe_req_mgmt_frame(mac_ctx, &ssid, + session->pLimMlmJoinReq->bssDescription.bssId, + session->currentOperChannel /*chanNum */, + session->selfMacAddr, session->dot11mode, + &session->pLimJoinReq->addIEScan.length, + session->pLimJoinReq->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.limTimers.gLimPeriodicJoinProbeReqTimer) != + TX_SUCCESS) { + pe_warn("could not activate Periodic Join req failure timer"); + return; + } + } +} + +/** + * lim_process_auth_retry_timer()- function to Retry Auth + * @mac_ctx:pointer to global mac + * + * Return: void + */ + +static void lim_process_auth_retry_timer(tpAniSirGlobal mac_ctx) +{ + tpPESession session_entry; + + session_entry = + pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer.sessionId); + if (NULL == session_entry) { + pe_err("session does not exist for given SessionId: %d", + mac_ctx->lim.limTimers. + g_lim_periodic_auth_retry_timer.sessionId); + return; + } + + if (tx_timer_running(&mac_ctx->lim.limTimers.gLimAuthFailureTimer) && + (session_entry->limMlmState == eLIM_MLM_WT_AUTH_FRAME2_STATE) && + (LIM_AUTH_ACK_RCD_SUCCESS != mac_ctx->auth_ack_status)) { + tSirMacAuthFrameBody auth_frame; + + /* + * Send the auth retry only in case we have received ack failure + * else just restart the retry timer. + */ + if (LIM_AUTH_ACK_RCD_FAILURE == mac_ctx->auth_ack_status) { + /* Prepare & send Authentication frame */ + auth_frame.authAlgoNumber = + (uint8_t) mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_frame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_1; + auth_frame.authStatusCode = 0; + pe_debug("Retry Auth"); + mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD; + 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); + } + + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + + /* Activate Auth Retry timer */ + if (tx_timer_activate + (&mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) { + pe_err("could not activate Auth Retry failure timer"); + return; + } + } + return; +} /*** lim_process_auth_retry_timer() ***/ + +void lim_process_auth_failure_timeout(tpAniSirGlobal mac_ctx) +{ + /* fetch the sessionEntry based on the sessionId */ + tpPESession session; +#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.limTimers.gLimAuthFailureTimer.sessionId); + if (NULL == 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->pePersona + && session->defaultAuthFailureTimeout) + cfg_set_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + session->defaultAuthFailureTimeout); + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + eSIR_MAC_UNSPEC_FAILURE_REASON, session); + 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(tpAniSirGlobal mac_ctx, uint32_t auth_idx) +{ + struct tLimPreAuthNode *auth_node; + tpPESession session; + uint8_t session_id; + + auth_node = lim_get_pre_auth_node_from_index(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable, auth_idx); + if (NULL == auth_node) { + pe_warn("Invalid auth node"); + return; + } + + session = pe_find_session_by_bssid(mac_ctx, auth_node->peerMacAddr, + &session_id); + if (NULL == 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) || LIM_IS_IBSS_ROLE(session)) { + if (auth_node->mlmState != eLIM_MLM_WT_AUTH_FRAME3_STATE) { + pe_err("received AUTH rsp timeout in unexpected " + "state for MAC address: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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(tpAniSirGlobal mac_ctx, + uint32_t msg_type) +{ + + tLimMlmAssocCnf mlm_assoc_cnf; + tpPESession session; +#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 sessionEntry + */ + uint8_t session_id; + + if (msg_type == LIM_ASSOC) + session_id = + mac_ctx->lim.limTimers.gLimAssocFailureTimer.sessionId; + else + session_id = + mac_ctx->lim.limTimers.gLimReassocFailureTimer.sessionId; + + session = pe_find_session_by_session_id(mac_ctx, session_id); + if (NULL == 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. + */ + pe_debug("Sessionid: %d try sending deauth on channel %d to BSSID: " + MAC_ADDRESS_STR, session->peSessionId, + session->currentOperChannel, + MAC_ADDR_ARRAY(session->bssId)); + lim_send_deauth_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_REASON, + 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); + /* + * 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 "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(session->bssId)); + lim_delete_pre_auth_node(mac_ctx, + session->bssId); + } + + mlm_assoc_cnf.resultCode = eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE; + mlm_assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* 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, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session); + } +} + +/** + * lim_set_channel() - set channel api for lim + * + * @mac_ctx: Pointer to Global MAC structure + * @channel: power save state + * @ch_center_freq_seg0: center freq seq 0 + * @ch_center_freq_seg1: center freq seq 1 + * @ch_width: channel width + * @max_tx_power: max tx power + * @pe_session_id: pe session id + * + * set channel api for lim + * + * @Return: None + */ +void lim_set_channel(tpAniSirGlobal mac_ctx, uint8_t channel, + uint8_t ch_center_freq_seg0, uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, int8_t max_tx_power, + uint8_t pe_session_id, uint32_t cac_duration_ms, + uint32_t dfs_regdomain) +{ + tpPESession pe_session; + + pe_session = pe_find_session_by_session_id(mac_ctx, pe_session_id); + + if (NULL == pe_session) { + pe_err("Invalid PE session: %d", pe_session_id); + return; + } + lim_send_switch_chnl_params(mac_ctx, channel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + max_tx_power, pe_session_id, false, + cac_duration_ms, dfs_regdomain); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..e993b0f7ca2b187b5457620ecc0f43d7cfd6f1a1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -0,0 +1,3245 @@ +/* + * 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. + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "cfg_api.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_ibss_peer_mgmt.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" + +#define MAX_SUPPORTED_PEERS_WEP 16 + +void lim_process_mlm_join_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_auth_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_start_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_assoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_assoc_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_reassoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_set_keys_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_disassoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_disassoc_cnf(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_deauth_ind(tpAniSirGlobal, tLimMlmDeauthInd *); +void lim_process_mlm_deauth_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_purge_sta_ind(tpAniSirGlobal, uint32_t *); +void lim_get_session_info(tpAniSirGlobal pMac, uint8_t *, uint8_t *, + uint16_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 pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void +lim_process_mlm_rsp_messages(tpAniSirGlobal pMac, uint32_t msgType, + uint32_t *pMsgBuf) +{ + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + MTRACE(mac_trace(pMac, TRACE_CODE_TX_LIM_MSG, 0, msgType)); + switch (msgType) { + case LIM_MLM_AUTH_CNF: + lim_process_mlm_auth_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_ASSOC_CNF: + lim_process_mlm_assoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_START_CNF: + lim_process_mlm_start_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_JOIN_CNF: + lim_process_mlm_join_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_ASSOC_IND: + lim_process_mlm_assoc_ind(pMac, pMsgBuf); + break; + case LIM_MLM_REASSOC_CNF: + lim_process_mlm_reassoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DISASSOC_CNF: + lim_process_mlm_disassoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DISASSOC_IND: + lim_process_mlm_disassoc_ind(pMac, pMsgBuf); + break; + case LIM_MLM_PURGE_STA_IND: + lim_process_mlm_purge_sta_ind(pMac, pMsgBuf); + break; + case LIM_MLM_DEAUTH_CNF: + lim_process_mlm_deauth_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DEAUTH_IND: + lim_process_mlm_deauth_ind(pMac, (tLimMlmDeauthInd *)pMsgBuf); + break; + case LIM_MLM_SETKEYS_CNF: + lim_process_mlm_set_keys_cnf(pMac, pMsgBuf); + 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 pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_start_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpPESession psessionEntry = NULL; + tLimMlmStartCnf *pLimMlmStartCnf; + uint8_t smesessionId; + uint16_t smetransactionId; + uint8_t channelId; + uint8_t send_bcon_ind = false; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pLimMlmStartCnf = (tLimMlmStartCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pLimMlmStartCnf->sessionId); + if (psessionEntry == NULL) { + pe_err("Session does Not exist with given sessionId"); + return; + } + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + + if (psessionEntry->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", + psessionEntry->limSmeState); + return; + } + if (((tLimMlmStartCnf *) pMsgBuf)->resultCode == eSIR_SME_SUCCESS) { + + /* + * Update global SME state so that Beacon Generation + * module starts writing Beacon frames into TFP's + * Beacon file register. + */ + psessionEntry->limSmeState = eLIM_SME_NORMAL_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + if (psessionEntry->bssType == eSIR_INFRA_AP_MODE) + pe_debug("*** Started BSS in INFRA AP SIDE***"); + else if (psessionEntry->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(pMac, psessionEntry); + psessionEntry = NULL; + pe_err("Start BSS Failed"); + } + /* Send response to Host */ + lim_send_sme_start_bss_rsp(pMac, eWNI_SME_START_BSS_RSP, + ((tLimMlmStartCnf *)pMsgBuf)->resultCode, + psessionEntry, smesessionId, smetransactionId); + if ((psessionEntry != NULL) && + (((tLimMlmStartCnf *) pMsgBuf)->resultCode == + eSIR_SME_SUCCESS)) { + channelId = psessionEntry->pLimStartBssReq->channelId; + + /* 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 + */ + + if (!(LIM_IS_IBSS_ROLE(psessionEntry) || + (LIM_IS_AP_ROLE(psessionEntry)))) + return; + if (psessionEntry->ch_width == CH_WIDTH_160MHZ) { + send_bcon_ind = false; + } else if (psessionEntry->ch_width == CH_WIDTH_80P80MHZ) { + if ((wlan_reg_get_channel_state(pMac->pdev, channelId) + != CHANNEL_STATE_DFS) && + (wlan_reg_get_channel_state(pMac->pdev, + psessionEntry->ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) != + CHANNEL_STATE_DFS)) + send_bcon_ind = true; + } else { + if (wlan_reg_get_channel_state(pMac->pdev, channelId) + != CHANNEL_STATE_DFS) + send_bcon_ind = true; + } + if (send_bcon_ind) { + /* Configure beacon and send beacons to HAL */ + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("Start Beacon with ssid %s Ch %d"), + psessionEntry->ssId.ssId, + psessionEntry->currentOperChannel); + lim_send_beacon_ind(pMac, + psessionEntry, REASON_DEFAULT); + lim_enable_obss_detection_config(pMac, psessionEntry); + lim_send_obss_color_collision_cfg(pMac, psessionEntry, + OBSS_COLOR_COLLISION_DETECTION); + } + } +} + +/*** 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(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmJoinCnf *join_cnf; + tpPESession session_entry; + + join_cnf = (tLimMlmJoinCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + join_cnf->sessionId); + if (session_entry == NULL) { + pe_err("SessionId:%d does not exist", join_cnf->sessionId); + return; + } + + 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) { + pe_debug("***SessionId:%d Joined ESS ***", + join_cnf->sessionId); + /* Setup hardware upfront */ + if (lim_sta_send_add_bss_pre_assoc(mac_ctx, false, + 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 psessionEntry + * 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(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + tLimMlmAssocReq *assoc_req; + uint32_t val; + uint16_t caps; + uint32_t tele_bcn = 0; + tpSirMacCapabilityInfo cap_info; + + /* Successful MAC based authentication. Trigger Association with BSS */ + pe_debug("SessionId: %d Authenticated with BSS", + session_entry->peSessionId); + + if (NULL == session_entry->pLimJoinReq) { + 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 (NULL == 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 (wlan_cfg_get_int(mac_ctx, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &assoc_req->assocFailureTimeout) + != QDF_STATUS_SUCCESS) { + /* Could not get AssocFailureTimeout value from CFG.*/ + pe_err("could not retrieve AssocFailureTimeout value"); + } + + if (cfg_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->pLimJoinReq->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->pLimJoinReq->bssDescription.capabilityInfo & + LIM_RRM_BIT_MASK)) + caps &= (~LIM_RRM_BIT_MASK); + + /* Clear short preamble bit if AP does not support it */ + if (!(session_entry->pLimJoinReq->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->pLimJoinReq->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); + pe_debug("Capabilities to be used in AssocReq=0x%X," + "privacy bit=%x shortSlotTime %x", caps, + cap_info->privacy, + cap_info->shortSlotTime); + + /* + * If telescopic beaconing is enabled, set listen interval to + * WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_WAKEUP_EN, &tele_bcn) + != QDF_STATUS_SUCCESS) + pe_err("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN"); + + val = WNI_CFG_LISTEN_INTERVAL_STADEF; + if (tele_bcn) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_MAX_LI, &val) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve ListenInterval"); + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, + &val) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve ListenInterval"); + } +#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; + /* 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_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(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + tAniAuthType auth_type, auth_mode; + tLimMlmAuthReq *auth_req; + tLimMlmAuthCnf *auth_cnf; + tpPESession session_entry; + + if (msg == NULL) { + 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 == NULL) { + 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_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) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATION_TYPE, + (uint32_t *) &auth_type) != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve AuthType value"); + } + } else { + auth_type = mac_ctx->lim.gLimPreAuthType; + } + + if ((auth_type == eSIR_AUTO_SWITCH) && + (auth_cnf->authType == eSIR_SHARED_KEY) && + ((eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS == + auth_cnf->protStatusCode) || + (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 (NULL == 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; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + (uint32_t *) &auth_req->authFailureTimeout) + != QDF_STATUS_SUCCESS) { + pe_err("Fail:retrieve AuthFailureTimeout"); + } + 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)); + /* + * 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(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tpPESession session_entry; + tLimMlmAssocCnf *assoc_cnf; + + if (msg == NULL) { + 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 == NULL) { + 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); + } +} + +/** + * lim_fill_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 + * + * This function is called to initialzie the association + * indication strucutre to process association indication. + * + * Return: None + */ + +static void +lim_fill_assoc_ind_params(tpAniSirGlobal mac_ctx, + tpLimMlmAssocInd assoc_ind, tSirSmeAssocInd *sme_assoc_ind, + tpPESession session_entry) +{ + sme_assoc_ind->length = sizeof(tSirSmeAssocInd); + sme_assoc_ind->sessionId = session_entry->smeSessionId; + + /* Required for indicating the frames to upper layer */ + sme_assoc_ind->assocReqLength = assoc_ind->assocReqLength; + sme_assoc_ind->assocReqPtr = assoc_ind->assocReqPtr; + + sme_assoc_ind->beaconPtr = session_entry->beacon; + sme_assoc_ind->beaconLength = session_entry->bcnLen; + + /* Fill in peerMacAddr */ + qdf_mem_copy(sme_assoc_ind->peerMacAddr, assoc_ind->peerMacAddr, + 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 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(tSirSmeChanInfo)); + /* 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->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; + + 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; +} + +/** + * lim_process_mlm_assoc_ind() + * + ***FUNCTION: + * This function is called to processes MLM_ASSOC_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_assoc_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint32_t len; + struct scheduler_msg msg = {0}; + tSirSmeAssocInd *pSirSmeAssocInd; + tpDphHashNode pStaDs = 0; + tpPESession psessionEntry; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + psessionEntry = pe_find_session_by_session_id(pMac, + ((tpLimMlmAssocInd) pMsgBuf)-> + sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionId"); + return; + } + /* / Inform Host of STA association */ + len = sizeof(tSirSmeAssocInd); + pSirSmeAssocInd = qdf_mem_malloc(len); + if (NULL == pSirSmeAssocInd) { + pe_err("call to AllocateMemory failed for eWNI_SME_ASSOC_IND"); + return; + } + + pSirSmeAssocInd->messageType = eWNI_SME_ASSOC_IND; + lim_fill_assoc_ind_params(pMac, (tpLimMlmAssocInd) pMsgBuf, + pSirSmeAssocInd, + psessionEntry); + msg.type = eWNI_SME_ASSOC_IND; + msg.bodyptr = pSirSmeAssocInd; + msg.bodyval = 0; + pStaDs = dph_get_hash_entry(pMac, + ((tpLimMlmAssocInd) pMsgBuf)->aid, + &psessionEntry->dph.dphHashTable); + if (!pStaDs) { + pe_err("MLM AssocInd: Station context no longer valid (aid %d)", + ((tpLimMlmAssocInd) pMsgBuf)->aid); + qdf_mem_free(pSirSmeAssocInd); + + return; + } + pSirSmeAssocInd->staId = pStaDs->staIndex; + pSirSmeAssocInd->reassocReq = pStaDs->mlmStaContext.subType; + pSirSmeAssocInd->timingMeasCap = pStaDs->timingMeasCap; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, msg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ASSOC_IND_EVENT, psessionEntry, 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(pMac, + (uint16_t) ((tpLimMlmAssocInd) pMsgBuf)->aid, + psessionEntry); + + pMac->lim.sme_msg_callback(pMac, &msg); +} /*** end lim_process_mlm_assoc_ind() ***/ + +/** + * lim_process_mlm_disassoc_ind() + * + ***FUNCTION: + * This function is called to processes MLM_DISASSOC_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_disassoc_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tLimMlmDisassocInd *pMlmDisassocInd; + tpPESession psessionEntry; + + pMlmDisassocInd = (tLimMlmDisassocInd *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDisassocInd->sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->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(psessionEntry)) */ +} /*** 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(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmDisassocCnf *disassoc_cnf; + tpPESession session_entry; + + disassoc_cnf = (tLimMlmDisassocCnf *) msg; + + session_entry = + pe_find_session_by_session_id(mac_ctx, disassoc_cnf->sessionId); + if (session_entry == NULL) { + 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 + * Disassocate 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, result_code, + disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry->transactionId, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry)) { + lim_send_sme_disassoc_ntf(mac_ctx, disassoc_cnf->peerMacAddr, + result_code, disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry->transactionId, 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(tpAniSirGlobal mac_ctx, + tLimMlmDeauthInd *deauth_ind) +{ + tpPESession 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:" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(deauth_ind->peerMacAddr)); + return; + } + role = GET_LIM_SYSTEM_ROLE(session); + pe_debug("*** Received Deauthentication from staId=%d role=%d***", + deauth_ind->aid, role); + 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 pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_deauth_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint16_t aid; + tSirResultCodes resultCode; + tLimMlmDeauthCnf *pMlmDeauthCnf; + tpPESession psessionEntry; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pMlmDeauthCnf = (tLimMlmDeauthCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDeauthCnf->sessionId); + if (psessionEntry == NULL) { + 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(psessionEntry) ? pMlmDeauthCnf->aid : 1; + if (LIM_IS_STA_ROLE(psessionEntry)) { + /* Deauth Confirm from MLM */ + if ((psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && psessionEntry->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", + psessionEntry->limSmeState); + return; + } + if (pMlmDeauthCnf->resultCode == eSIR_SME_SUCCESS) { + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + pe_debug("*** Deauthenticated with BSS ***"); + } else + psessionEntry->limSmeState = + psessionEntry->limPrevSmeState; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + if (pMac->lim.gLimRspReqd) + pMac->lim.gLimRspReqd = false; + } + /* On STA or on BASIC AP, send SME_DEAUTH_RSP to host */ + lim_send_sme_deauth_ntf(pMac, pMlmDeauthCnf->peer_macaddr.bytes, + resultCode, + pMlmDeauthCnf->deauthTrigger, + aid, psessionEntry->smeSessionId, + psessionEntry->transactionId); +} /*** 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 pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_purge_sta_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirResultCodes resultCode; + tpLimMlmPurgeStaInd pMlmPurgeStaInd; + tpPESession psessionEntry; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pMlmPurgeStaInd = (tpLimMlmPurgeStaInd) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmPurgeStaInd->sessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given bssId"); + return; + } + /* Purge STA indication from MLM */ + resultCode = (tSirResultCodes) pMlmPurgeStaInd->reasonCode; + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + default: /* eLIM_AP_ROLE */ + if (LIM_IS_STA_ROLE(psessionEntry) && + (psessionEntry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (psessionEntry->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", + psessionEntry->limSmeState); + break; + } + pe_debug("*** Cleanup completed for staId=%d ***", + pMlmPurgeStaInd->aid); + if (LIM_IS_STA_ROLE(psessionEntry)) { + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + } + if (pMlmPurgeStaInd->purgeTrigger == eLIM_PEER_ENTITY_DEAUTH) { + lim_send_sme_deauth_ntf(pMac, + pMlmPurgeStaInd->peerMacAddr, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + } else + lim_send_sme_disassoc_ntf(pMac, + pMlmPurgeStaInd->peerMacAddr, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + psessionEntry->smeSessionId, + psessionEntry->transactionId, + psessionEntry); + } /* end switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) */ +} /*** 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 pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_set_keys_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + /* Prepare and send SME_SETCONTEXT_RSP message */ + tLimMlmSetKeysCnf *pMlmSetKeysCnf; + tpPESession psessionEntry; + uint16_t aid; + tpDphHashNode sta_ds; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pMlmSetKeysCnf = (tLimMlmSetKeysCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmSetKeysCnf->sessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given sessionId"); + return; + } + psessionEntry->is_key_installed = 0; + pe_debug("Received MLM_SETKEYS_CNF with resultCode = %d", + pMlmSetKeysCnf->resultCode); + /* if the status is success keys are installed in the + * Firmware so we can set the protection bit + */ + if (eSIR_SME_SUCCESS == pMlmSetKeysCnf->resultCode) { + if (pMlmSetKeysCnf->key_len_nonzero) + psessionEntry->is_key_installed = 1; + if (LIM_IS_AP_ROLE(psessionEntry)) { + sta_ds = dph_lookup_hash_entry(pMac, + pMlmSetKeysCnf->peer_macaddr.bytes, + &aid, &psessionEntry->dph.dphHashTable); + if (sta_ds != NULL && pMlmSetKeysCnf->key_len_nonzero) + sta_ds->is_key_installed = 1; + } + } + pe_debug("is_key_installed = %d", psessionEntry->is_key_installed); + + lim_send_sme_set_context_rsp(pMac, + pMlmSetKeysCnf->peer_macaddr, + 1, + (tSirResultCodes) pMlmSetKeysCnf->resultCode, + psessionEntry, psessionEntry->smeSessionId, + psessionEntry->transactionId); +} /*** end lim_process_mlm_set_keys_cnf() ***/ + +/** + * lim_join_result_callback() - Callback to handle join rsp + * @mac: Pointer to Global MAC structure + * @param: callback argument + * @status: status + * + * This callback function is used to delete PE session + * entry and send join response to sme. + * + * Return: None + */ +static void lim_join_result_callback(tpAniSirGlobal mac, void *param, + bool status) +{ + join_params *link_state_params = (join_params *) param; + tpPESession session; + uint8_t sme_session_id; + uint16_t sme_trans_id; + + if (!link_state_params) { + pe_err("Link state params is NULL"); + return; + } + session = pe_find_session_by_session_id(mac, link_state_params-> + pe_session_id); + if (!session) { + qdf_mem_free(link_state_params); + return; + } + sme_session_id = session->smeSessionId; + sme_trans_id = session->transactionId; + lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_JOIN_RSP, + link_state_params->result_code, + link_state_params->prot_status_code, + session, sme_session_id, sme_trans_id); + pe_delete_session(mac, session); + qdf_mem_free(link_state_params); +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tSirResultCodes result_code, uint16_t prot_status_code, + tpPESession session_entry) +{ + tpDphHashNode sta_ds = NULL; + uint8_t sme_session_id; + uint16_t sme_trans_id; + join_params *param = NULL; + + if (session_entry == NULL) { + pe_err("psessionEntry is NULL"); + return; + } + sme_session_id = session_entry->smeSessionId; + sme_trans_id = session_entry->transactionId; + /* + * When associations is failed , delete the session created + * and pass NULL to limsendsmeJoinReassocRsp() + */ + if (result_code != eSIR_SME_SUCCESS) { + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds != NULL) { + sta_ds->mlmStaContext.disassocReason = + eSIR_MAC_UNSPEC_FAILURE_REASON; + sta_ds->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + sta_ds->mlmStaContext.resultCode = result_code; + sta_ds->mlmStaContext.protStatusCode = 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_cleanup_rx_path(mac_ctx, sta_ds, session_entry); + qdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + /* Cleanup if add bss failed */ + if (session_entry->add_bss_failed) { + dph_delete_hash_entry(mac_ctx, + sta_ds->staAddr, sta_ds->assocId, + &session_entry->dph.dphHashTable); + goto error; + } + return; + } + qdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + } +error: + /* Delete the session if JOIN failure occurred. + * if the peer is not created, then there is no + * need to send down the set link state which will + * try to delete the peer. Instead a join response + * failure should be sent to the upper layers. + */ + if (result_code != eSIR_SME_SUCCESS && + result_code != eSIR_SME_PEER_CREATE_FAILED) { + param = qdf_mem_malloc(sizeof(join_params)); + if (param != NULL) { + param->result_code = result_code; + param->prot_status_code = prot_status_code; + param->pe_session_id = session_entry->peSessionId; + } + if (lim_set_link_state + (mac_ctx, eSIR_LINK_DOWN_STATE, session_entry->bssId, + session_entry->selfMacAddr, lim_join_result_callback, + param) != QDF_STATUS_SUCCESS) { + qdf_mem_free(param); + pe_err("Failed to set the LinkState"); + } + return; + } + + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_JOIN_RSP, result_code, + prot_status_code, session_entry, sme_session_id, sme_trans_id); +} + +/** + * 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 pMac 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(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry) +{ + /* 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 deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_process_ap_mlm_add_sta_rsp(pMac, limMsgQ, psessionEntry); + return; + } + lim_process_sta_mlm_add_sta_rsp(pMac, limMsgQ, psessionEntry); +} + +/** + * 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg, tpPESession session_entry) +{ + tLimMlmAssocCnf mlm_assoc_cnf; + tpDphHashNode sta_ds; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + tpAddStaParams add_sta_params = (tpAddStaParams) msg->bodyptr; + tpPESession ft_session = NULL; + uint8_t ft_session_id; + + if (NULL == 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 staIdx: %d limMlmState: %d", + add_sta_params->staIdx, + session_entry->limMlmState); + + 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 = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + session_entry->staId = add_sta_params->staIdx; + 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; + } + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) { + /* check if we have keys(PTK)to install in case of 11r */ + tpftPEContext ft_ctx = &session_entry->ftPEContext; + + ft_session = pe_find_session_by_bssid(mac_ctx, + session_entry->limReAssocbssId, &ft_session_id); + if (ft_session != NULL && + ft_ctx->PreAuthKeyInfo.extSetStaKeyParamValid + == true) { + tpLimMlmSetKeysReq pMlmStaKeys = + &ft_ctx->PreAuthKeyInfo.extSetStaKeyParam; + lim_send_set_sta_key_req(mac_ctx, pMlmStaKeys, + 0, 0, ft_session, false); + ft_ctx->PreAuthKeyInfo.extSetStaKeyParamValid = + false; + } + } + /* + * 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 (NULL != 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)); + /* + * Storing the self StaIndex(Generated by HAL) in + * session context, instead of storing it in DPH Hash + * entry for Self STA. + * DPH entry for the self STA stores the sta index for + * the BSS entry to which the STA is associated + */ + session_entry->staId = add_sta_params->staIdx; + +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumLinkEsts++; +#endif +#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); + } 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 = eSIR_MAC_UNSPEC_FAILURE_STATUS; + } +end: + if (NULL != 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(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry) +{ + /* 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 deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pMac->sys.gSysFrameCount[SIR_MAC_MGMT_FRAME][SIR_MAC_MGMT_DEAUTH] = 0; + + if (LIM_IS_AP_ROLE(psessionEntry) && + (psessionEntry->statypeForBss == STA_ENTRY_SELF)) { + lim_process_ap_mlm_del_bss_rsp(pMac, limMsgQ, psessionEntry); + return; + } + lim_process_sta_mlm_del_bss_rsp(pMac, limMsgQ, psessionEntry); + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + if (QDF_STATUS_SUCCESS != + lim_send_exclude_unencrypt_ind(pMac, true, psessionEntry)) { + pe_err("Could not send down Exclude Unencrypted Indication!"); + } + } +#endif +} + +void lim_process_sta_mlm_del_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBssParams = (tpDeleteBssParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + tSirResultCodes statusCode = eSIR_SME_SUCCESS; + + if (NULL == pDelBssParams) { + pe_err("Invalid body pointer in message"); + goto end; + } + if (QDF_STATUS_SUCCESS == pDelBssParams->status) { + pe_debug("STA received the DEL_BSS_RSP for BSSID: %X", + pDelBssParams->bssIdx); + if (lim_set_link_state + (pMac, eSIR_LINK_IDLE_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != QDF_STATUS_SUCCESS) { + pe_err("Failure in setting link state to IDLE"); + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (pStaDs == NULL) { + pe_err("DPH Entry for STA 1 missing"); + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != + pStaDs->mlmStaContext.mlmState) { + pe_err("Received unexpected WMA_DEL_BSS_RSP in state %X", + pStaDs->mlmStaContext.mlmState); + statusCode = eSIR_SME_REFUSED; + goto end; + } + pe_debug("STA AssocID %d MAC", pStaDs->assocId); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOGD); + } else { + pe_err("DEL BSS failed!"); + statusCode = eSIR_SME_STOP_BSS_FAILURE; + } +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelBssParams); + limMsgQ->bodyptr = NULL; + } + if (pStaDs == NULL) + return; + if ((LIM_IS_STA_ROLE(psessionEntry)) && + (psessionEntry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE && + psessionEntry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) && + pStaDs->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(pMac, pStaDs, psessionEntry); + return; + } + lim_prepare_and_send_del_sta_cnf(pMac, pStaDs, statusCode, psessionEntry); + return; +} + +void lim_process_ap_mlm_del_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + QDF_STATUS status; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) limMsgQ->bodyptr; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (psessionEntry == NULL) { + pe_err("Session entry passed is NULL"); + if (pDelBss != NULL) { + qdf_mem_free(pDelBss); + limMsgQ->bodyptr = NULL; + } + return; + } + + if (pDelBss == NULL) { + pe_err("BSS: DEL_BSS_RSP with no body!"); + rc = eSIR_SME_REFUSED; + goto end; + } + pMac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, NO_SESSION, + pMac->lim.gLimMlmState)); + + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != psessionEntry->limMlmState) { + pe_err("Received unexpected WMA_DEL_BSS_RSP in state %X", + psessionEntry->limMlmState); + rc = eSIR_SME_REFUSED; + goto end; + } + if (pDelBss->status != QDF_STATUS_SUCCESS) { + pe_err("BSS: DEL_BSS_RSP error (%x) Bss %d", + pDelBss->status, pDelBss->bssIdx); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + status = lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + psessionEntry->selfMacAddr, NULL, NULL); + if (status != QDF_STATUS_SUCCESS) { + rc = eSIR_SME_REFUSED; + 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_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + /* Initialize number of associated stations during cleanup */ + psessionEntry->gLimNumOfCurrentSTAs = 0; +end: + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, rc, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + pe_delete_session(pMac, psessionEntry); + + if (pDelBss != NULL) { + qdf_mem_free(pDelBss); + limMsgQ->bodyptr = NULL; + } +} + +/** + * 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(tpAniSirGlobal 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 deffered flag. + */ + tpPESession session_entry; + tpDeleteStaParams del_sta_params; + + del_sta_params = (tpDeleteStaParams) msg->bodyptr; + if (NULL == 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 (NULL == 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_IBSS_ROLE(session_entry)) { + lim_process_ibss_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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg, + tpPESession session_entry) +{ + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) msg->bodyptr; + tpDphHashNode sta_ds; + tSirResultCodes status_code = eSIR_SME_SUCCESS; + + if (msg->bodyptr == NULL) { + 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 == NULL) { + 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_warn("AP received the DEL_STA_RSP for assocID: %X", + del_sta_params->assocId); + 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 staId %d assocId %d", + lim_mlm_state_str(sta_ds->mlmStaContext.mlmState), + sta_ds->staIndex, sta_ds->assocId); + status_code = eSIR_SME_REFUSED; + goto end; + } + + pe_debug("Deleted STA AssocID %d staId %d MAC", + sta_ds->assocId, sta_ds->staIndex); + lim_print_mac_addr(mac_ctx, sta_ds->staAddr, LOGD); + 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, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + 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(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry) +{ + tSirResultCodes statusCode = eSIR_SME_SUCCESS; + tpDeleteStaParams pDelStaParams = (tpDeleteStaParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = NULL; + + if (NULL == 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(pMac, limMsgQ, psessionEntry); + return; + } +#endif + if (QDF_STATUS_SUCCESS != pDelStaParams->status) + pe_err("Del STA failed! Status:%d, proceeding with Del BSS", + pDelStaParams->status); + + pStaDs = dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + pe_err("DPH Entry for STA %X missing", + pDelStaParams->assocId); + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (eLIM_MLM_WT_DEL_STA_RSP_STATE != psessionEntry->limMlmState) { + pe_err("Received unexpected WDA_DELETE_STA_RSP in state %s", + lim_mlm_state_str(psessionEntry->limMlmState)); + statusCode = eSIR_SME_REFUSED; + goto end; + } + pe_debug("STA AssocID %d MAC", pStaDs->assocId); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOGD); + /* + * we must complete all cleanup related to delSta before + * calling limDelBSS. + */ + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + /* Proceed to do DelBSS even if DelSta resulted in failure */ + statusCode = (tSirResultCodes)lim_del_bss(pMac, pStaDs, 0, + psessionEntry); + return; +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +void lim_process_ap_mlm_add_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry) +{ + tpAddStaParams pAddStaParams = (tpAddStaParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = NULL; + + if (NULL == pAddStaParams) { + pe_err("Invalid body pointer in message"); + goto end; + } + + pStaDs = + dph_get_hash_entry(pMac, pAddStaParams->assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + pe_err("DPH Entry for STA %X missing", pAddStaParams->assocId); + goto end; + } + + if (eLIM_MLM_WT_ADD_STA_RSP_STATE != pStaDs->mlmStaContext.mlmState) { + pe_err("Received unexpected WMA_ADD_STA_RSP in state %X", + pStaDs->mlmStaContext.mlmState); + goto end; + } + if (QDF_STATUS_SUCCESS != pAddStaParams->status) { + pe_err("Error! rcvd delSta rsp from HAL with status %d", + pAddStaParams->status); + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext.subType, + true, pStaDs->mlmStaContext.authType, + pStaDs->assocId, true, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + goto end; + } + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->nss = pAddStaParams->nss; + /* if the AssocRsp frame is not acknowledged, then keep alive timer will take care of the state */ + pStaDs->valid = 1; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_ASSOC_CNF_STATE; + pe_debug("AddStaRsp Success.STA AssocID %d staId %d MAC", + pStaDs->assocId, pStaDs->staIndex); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOGD); + + /* 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 + */ + lim_send_mlm_assoc_ind(pMac, pStaDs, psessionEntry); + /* fall though to reclaim the original Add STA Response message */ +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pAddStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +/** + * lim_process_ap_mlm_add_bss_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Init other remaining LIM variables + * > Init the AID pool, for that BSSID + * > Init the Pre-AUTH list, for that BSSID + * > Create LIM timers, specific to that BSSID + * > Init DPH related parameters that are specific to that BSSID + * > TODO - When do we do the actual change channel? + * + ***LOGIC: + * SME sends eWNI_SME_START_BSS_REQ to LIM + * LIM sends LIM_MLM_START_REQ to MLME + * MLME sends WMA_ADD_BSS_REQ to HAL + * HAL responds with WMA_ADD_BSS_RSP to MLME + * MLME responds with LIM_MLM_START_CNF to LIM + * LIM responds with eWNI_SME_START_BSS_RSP to SME + * + ***ASSUMPTIONS: + * struct scheduler_msg.body is allocated by MLME during + * lim_process_mlm_start_req + * struct scheduler_msg.body will now be freed by this routine + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param struct scheduler_msg The MsgQ header, which contains + * the response buffer + * + * @return None + */ +static void lim_process_ap_mlm_add_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ) +{ + tLimMlmStartCnf mlmStartCnf; + tpPESession psessionEntry; + uint8_t isWepEnabled = false; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + + if (NULL == pAddBssParams) { + pe_err("Encountered NULL Pointer"); + goto end; + } + /* TBD: free the memory before returning, do it for all places where lookup fails. */ + psessionEntry = pe_find_session_by_session_id(pMac, + pAddBssParams->sessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given sessionId"); + if (NULL != pAddBssParams) { + qdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } + return; + } + /* Update PE session Id */ + mlmStartCnf.sessionId = pAddBssParams->sessionId; + if (QDF_STATUS_SUCCESS == pAddBssParams->status) { + pe_debug("WMA_ADD_BSS_RSP returned with QDF_STATUS_SUCCESS"); + if (lim_set_link_state + (pMac, eSIR_LINK_AP_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != QDF_STATUS_SUCCESS) + goto end; + /* Set MLME state */ + psessionEntry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + psessionEntry->chainMask = pAddBssParams->chainMask; + psessionEntry->smpsMode = pAddBssParams->smpsMode; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + if (eSIR_IBSS_MODE == pAddBssParams->bssType) { + /** IBSS is 'active' when we receive + * Beacon frames from other STAs that are part of same IBSS. + * Mark internal state as inactive until then. + */ + psessionEntry->limIbssActive = false; + psessionEntry->statypeForBss = STA_ENTRY_PEER; /* to know session created for self/peer */ + limResetHBPktCount(psessionEntry); + } + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + + if (eSIR_INFRA_AP_MODE == pAddBssParams->bssType) + psessionEntry->limSystemRole = eLIM_AP_ROLE; + else + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + sch_edca_profile_update(pMac, psessionEntry); + lim_init_pre_auth_list(pMac); + /* Check the SAP security configuration.If configured to + * WEP then max clients supported is 16 + */ + if (psessionEntry->privacy) { + if ((psessionEntry->gStartBssRSNIe.present) + || (psessionEntry->gStartBssWPAIe.present)) + pe_debug("WPA/WPA2 SAP configuration"); + else { + if (pMac->lim.gLimAssocStaLimit > + MAX_SUPPORTED_PEERS_WEP) { + pe_debug("WEP SAP Configuration"); + pMac->lim.gLimAssocStaLimit = + MAX_SUPPORTED_PEERS_WEP; + isWepEnabled = true; + } + } + } + lim_init_peer_idxpool(pMac, psessionEntry); + + /* Start OLBC timer */ + if (tx_timer_activate + (&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer) != + TX_SUCCESS) { + pe_err("tx_timer_activate failed"); + } + + /* Apply previously set configuration at HW */ + lim_apply_configuration(pMac, psessionEntry); + + /* In lim_apply_configuration gLimAssocStaLimit is assigned from cfg. + * So update the value to 16 in case SoftAP is configured in WEP. + */ + if ((pMac->lim.gLimAssocStaLimit > MAX_SUPPORTED_PEERS_WEP) + && (isWepEnabled)) + pMac->lim.gLimAssocStaLimit = MAX_SUPPORTED_PEERS_WEP; + psessionEntry->staId = pAddBssParams->staContext.staIdx; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + } else { + pe_err("WMA_ADD_BSS_REQ failed with status %d", + pAddBssParams->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + lim_post_sme_message(pMac, LIM_MLM_START_CNF, (uint32_t *) &mlmStartCnf); +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } +} + +/** + * lim_process_ibss_mlm_add_bss_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Init other remaining LIM variables + * > Init the AID pool, for that BSSID + * > Init the Pre-AUTH list, for that BSSID + * > Create LIM timers, specific to that BSSID + * > Init DPH related parameters that are specific to that BSSID + * > TODO - When do we do the actual change channel? + * + ***LOGIC: + * SME sends eWNI_SME_START_BSS_REQ to LIM + * LIM sends LIM_MLM_START_REQ to MLME + * MLME sends WMA_ADD_BSS_REQ to HAL + * HAL responds with WMA_ADD_BSS_RSP to MLME + * MLME responds with LIM_MLM_START_CNF to LIM + * LIM responds with eWNI_SME_START_BSS_RSP to SME + * + ***ASSUMPTIONS: + * struct scheduler_msg.body is allocated by MLME during + * lim_process_mlm_start_req + * struct scheduler_msg.body will now be freed by this routine + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param struct scheduler_msg The MsgQ header, which contains + * the response buffer + * + * @return None + */ +static void +lim_process_ibss_mlm_add_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry) +{ + tLimMlmStartCnf mlmStartCnf; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + + if (NULL == pAddBssParams) { + pe_err("Invalid body pointer in message"); + goto end; + } + if (QDF_STATUS_SUCCESS == pAddBssParams->status) { + pe_debug("WMA_ADD_BSS_RSP returned with QDF_STATUS_SUCCESS"); + + if (lim_set_link_state + (pMac, eSIR_LINK_IBSS_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != QDF_STATUS_SUCCESS) + goto end; + /* Set MLME state */ + psessionEntry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + /** IBSS is 'active' when we receive + * Beacon frames from other STAs that are part of same IBSS. + * Mark internal state as inactive until then. + */ + psessionEntry->limIbssActive = false; + limResetHBPktCount(psessionEntry); + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + psessionEntry->statypeForBss = STA_ENTRY_SELF; + sch_edca_profile_update(pMac, psessionEntry); + if (0 == psessionEntry->freePeerIdxHead) + lim_init_peer_idxpool(pMac, psessionEntry); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(pMac, psessionEntry); + psessionEntry->staId = pAddBssParams->staContext.staIdx; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + /* If ADD BSS was issued as part of IBSS coalescing, don't send the message to SME, as that is internal to LIM */ + if (true == pMac->lim.gLimIbssCoalescingHappened) { + lim_ibss_add_bss_rsp_when_coalescing(pMac, limMsgQ->bodyptr, + psessionEntry); + goto end; + } + } else { + pe_err("WMA_ADD_BSS_REQ failed with status %d", + pAddBssParams->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + /* Send this message to SME, when ADD_BSS is initiated by SME */ + /* If ADD_BSS is done as part of coalescing, this won't happen. */ + /* Update PE session Id */ + mlmStartCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, LIM_MLM_START_CNF, (uint32_t *) &mlmStartCnf); +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } +} + +#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(tpPESession 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(tpPESession session_entry, + tAniAuthType *auth_mode) +{ } +#endif + +/** + * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request + * @mac_ctx: Pointer to mac context + * @msg: message sent to HDD + * @session_entry: PE session handle + * + * 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 + */ +static void +lim_process_sta_add_bss_rsp_pre_assoc(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg, tpPESession session_entry) +{ + tpAddBssParams pAddBssParams = (tpAddBssParams) msg->bodyptr; + tAniAuthType cfgAuthType, authMode; + tLimMlmAuthReq *pMlmAuthReq; + tpDphHashNode pStaDs = NULL; + + if (NULL == pAddBssParams) { + pe_err("Invalid body pointer in message"); + goto joinFailure; + } + if (QDF_STATUS_SUCCESS == pAddBssParams->status) { + pStaDs = dph_add_hash_entry(mac_ctx, + pAddBssParams->staContext.staMac, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + pe_err("could not add hash entry at DPH for"); + lim_print_mac_addr(mac_ctx, + pAddBssParams->staContext.staMac, LOGE); + goto joinFailure; + } + session_entry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + /* Success, handle below */ + pStaDs->bssId = pAddBssParams->bssIdx; + /* STA Index(genr by HAL) for the BSS entry is stored here */ + pStaDs->staIndex = pAddBssParams->staContext.staIdx; + /* Trigger Authentication with AP */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATION_TYPE, + (uint32_t *) &cfgAuthType) != QDF_STATUS_SUCCESS) { + pe_warn("could not retrieve AuthType"); + } + /* 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 (NULL == pMlmAuthReq) { + pe_err("Allocate Memory failed for mlmAuthReq"); + return; + } + sir_copy_mac_addr(pMlmAuthReq->peerMacAddr, + session_entry->bssId); + + pMlmAuthReq->authType = authMode; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + (uint32_t *) &pMlmAuthReq->authFailureTimeout) + != QDF_STATUS_SUCCESS) { + pe_warn("Fail: retrieve AuthFailureTimeout value"); + } + 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; + /* remember staId in case of assoc timeout/failure handling */ + session_entry->staId = pAddBssParams->staContext.staIdx; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + pe_debug("SessionId:%d lim_post_mlm_message " + "LIM_MLM_AUTH_REQ with limSmeState: %d", + session_entry->peSessionId, session_entry->limSmeState); + 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, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session_entry); + } + +} + +/** + * lim_process_sta_mlm_add_bss_rsp() - Process ADD BSS 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_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Now, send an ADD_STA to HAL and ADD the "local" STA itself + * + * MLME had sent WMA_ADD_BSS_REQ to HAL + * HAL responded with WMA_ADD_BSS_RSP to MLME + * MLME now sends WMA_ADD_STA_REQ to HAL + * ASSUMPTIONS: + * struct scheduler_msg.body is allocated by MLME during + * lim_process_mlm_join_req + * struct scheduler_msg.body will now be freed by this routine + * + * Return: None + */ +static void +lim_process_sta_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg, tpPESession session_entry) +{ + tpAddBssParams add_bss_params = (tpAddBssParams) msg->bodyptr; + tLimMlmAssocCnf mlm_assoc_cnf; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + uint32_t sub_type = LIM_ASSOC; + tpDphHashNode sta_ds = NULL; + uint16_t sta_idx = STA_INVALID_IDX; + uint8_t update_sta = false; + + mlm_assoc_cnf.resultCode = eSIR_SME_SUCCESS; + + if (eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE == + session_entry->limMlmState) { + pe_debug("SessionId: %d lim_process_sta_add_bss_rsp_pre_assoc", + session_entry->peSessionId); + lim_process_sta_add_bss_rsp_pre_assoc(mac_ctx, msg, + session_entry); + goto end; + } + 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)) { + sta_idx = session_entry->staId; + update_sta = true; + } + } + + if (add_bss_params == 0) + goto end; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session_entry->bRoamSynchInProgress) + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "LFR3:lim_process_sta_mlm_add_bss_rsp"); +#endif + + if (QDF_STATUS_SUCCESS == add_bss_params->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, msg, + session_entry); + goto end; + } + + /* 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; + /* Now, send WMA_ADD_STA_REQ */ + pe_debug("SessionId: %d On STA: ADD_BSS was successful", + session_entry->peSessionId); + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + pe_err("Session:%d Fail to add Self Entry for STA", + session_entry->peSessionId); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } else { + session_entry->bssIdx = + (uint8_t) add_bss_params->bssIdx; + /* Success, handle below */ + sta_ds->bssId = add_bss_params->bssIdx; + /* + * STA Index(genr by HAL) for the BSS + * entry is stored here + */ + sta_ds->staIndex = add_bss_params->staContext.staIdx; + /* 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, + sta_ds->bssId, false); + rrm_cache_mgmt_tx_power(mac_ctx, + add_bss_params->txMgmtPower, session_entry); + if (lim_add_sta_self(mac_ctx, sta_idx, 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 = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* 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; + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, + session_entry->bssId, + session_entry->selfMacAddr, + NULL, NULL) != QDF_STATUS_SUCCESS) + pe_err("Failed to set the LinkState"); + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, msg_type, + (uint32_t *) &mlm_assoc_cnf); + } +end: + if (0 != msg->bodyptr) { + qdf_mem_free(add_bss_params); + msg->bodyptr = NULL; + } +} + +/** + * lim_process_mlm_add_bss_rsp() - Processes ADD BSS 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_ADD_BSS_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 + * + *LOGIC: + * WMA_ADD_BSS_RSP can be received by MLME while the LIM is + * in the following two states: + * 1) As AP, LIM state = eLIM_SME_WT_START_BSS_STATE + * 2) As STA, LIM state = eLIM_SME_WT_JOIN_STATE + * Based on these two states, this API will determine where to + * route the message to + * + * Return None + */ +void lim_process_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + tLimMlmStartCnf mlm_start_cnf; + tpPESession session_entry; + tpAddBssParams add_bss_param = (tpAddBssParams) (msg->bodyptr); + tSirBssType bss_type; + + if (NULL == add_bss_param) { + pe_err("Encountered NULL Pointer"); + 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 deffered + * flag. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + /* Validate SME/LIM/MLME state */ + session_entry = pe_find_session_by_session_id(mac_ctx, + add_bss_param->sessionId); + if (session_entry == NULL) { + pe_err("SessionId:%d Session Doesn't exist", + add_bss_param->sessionId); + if (NULL != add_bss_param) { + qdf_mem_free(add_bss_param); + msg->bodyptr = NULL; + } + return; + } + + bss_type = session_entry->bssType; + /* update PE session Id */ + mlm_start_cnf.sessionId = session_entry->peSessionId; + if (eSIR_IBSS_MODE == bss_type) { + lim_process_ibss_mlm_add_bss_rsp(mac_ctx, msg, session_entry); + } else if (eSIR_NDI_MODE == session_entry->bssType) { + lim_process_ndi_mlm_add_bss_rsp(mac_ctx, msg, 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; + if (0 != msg->bodyptr) { + qdf_mem_free(add_bss_param); + msg->bodyptr = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); + } else + lim_process_ap_mlm_add_bss_rsp(mac_ctx, msg); + } else { + /* Called while processing assoc response */ + lim_process_sta_mlm_add_bss_rsp(mac_ctx, msg, + session_entry); + } + } + +#ifdef WLAN_FEATURE_11W + 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"); + } + } +#endif +} + +void lim_process_mlm_update_hidden_ssid_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + tpPESession session_entry; + tpHalHiddenSsidVdevRestart hidden_ssid_vdev_restart; + struct scheduler_msg message = {0}; + QDF_STATUS status; + + hidden_ssid_vdev_restart = (tpHalHiddenSsidVdevRestart)(msg->bodyptr); + + if (NULL == hidden_ssid_vdev_restart) { + pe_err("NULL msg pointer"); + return; + } + + session_entry = pe_find_session_by_session_id(mac_ctx, + hidden_ssid_vdev_restart->pe_session_id); + + if (session_entry == NULL) { + pe_err("SessionId:%d Session Doesn't exist", + hidden_ssid_vdev_restart->pe_session_id); + goto free_req; + } + /* Update beacon */ + sch_set_fixed_beacon_fields(mac_ctx, session_entry); + lim_send_beacon_ind(mac_ctx, session_entry, REASON_DEFAULT); + + message.type = eWNI_SME_HIDDEN_SSID_RESTART_RSP; + message.bodyval = hidden_ssid_vdev_restart->sessionId; + 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); + +free_req: + if (NULL != hidden_ssid_vdev_restart) { + qdf_mem_free(hidden_ssid_vdev_restart); + msg->bodyptr = NULL; + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + uint8_t resp_reqd = 1; + struct sLimMlmSetKeysCnf mlm_set_key_cnf; + uint8_t session_id = 0; + uint8_t sme_session_id; + tpPESession session_entry; + uint16_t key_len; + uint16_t result_status; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + qdf_mem_zero((void *)&mlm_set_key_cnf, sizeof(tLimMlmSetKeysCnf)); + if (NULL == msg->bodyptr) { + pe_err("msg bodyptr is NULL"); + return; + } + session_id = ((tpSetStaKeyParams) msg->bodyptr)->sessionId; + sme_session_id = ((tpSetBssKeyParams) msg->bodyptr)->smesessionId; + session_entry = pe_find_session_by_session_id(mac_ctx, session_id); + if (session_entry == NULL) { + pe_err("session does not exist for given session_id"); + qdf_mem_zero(msg->bodyptr, sizeof(tSetStaKeyParams)); + 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, + sme_session_id, 0); + return; + } + if (eLIM_MLM_WT_SET_STA_KEY_STATE != session_entry->limMlmState) { + pe_err("Received unexpected [Mesg Id - %d] in state %X", + msg->type, session_entry->limMlmState); + resp_reqd = 0; + } else { + mlm_set_key_cnf.resultCode = + (uint16_t)(((tpSetStaKeyParams) msg->bodyptr)->status); + } + + result_status = (uint16_t)(((tpSetStaKeyParams) msg->bodyptr)->status); + key_len = ((tpSetStaKeyParams)msg->bodyptr)->key[0].keyLength; + + 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_mem_zero(msg->bodyptr, sizeof(tSetStaKeyParams)); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + /* Restore MLME state */ + session_entry->limMlmState = session_entry->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, session_entry->limMlmState)); + if (resp_reqd) { + tpLimMlmSetKeysReq lpLimMlmSetKeysReq = + (tpLimMlmSetKeysReq) mac_ctx->lim.gpLimMlmSetKeysReq; + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + if (NULL != lpLimMlmSetKeysReq) { + qdf_copy_macaddr(&mlm_set_key_cnf.peer_macaddr, + &lpLimMlmSetKeysReq->peer_macaddr); + /* + * Free the buffer cached for the global + * mac_ctx->lim.gpLimMlmSetKeysReq + */ + qdf_mem_zero(mac_ctx->lim.gpLimMlmSetKeysReq, + sizeof(tLimMlmSetKeysReq)); + qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); + mac_ctx->lim.gpLimMlmSetKeysReq = NULL; + } + mlm_set_key_cnf.sessionId = session_id; + lim_post_sme_message(mac_ctx, LIM_MLM_SETKEYS_CNF, + (uint32_t *) &mlm_set_key_cnf); + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + struct sLimMlmSetKeysCnf set_key_cnf; + uint16_t result_status; + uint8_t session_id = 0; + uint8_t sme_session_id; + tpPESession session_entry; + tpLimMlmSetKeysReq set_key_req; + uint16_t key_len; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + qdf_mem_zero((void *)&set_key_cnf, sizeof(tLimMlmSetKeysCnf)); + if (NULL == msg->bodyptr) { + pe_err("msg bodyptr is null"); + return; + } + session_id = ((tpSetBssKeyParams) msg->bodyptr)->sessionId; + sme_session_id = ((tpSetBssKeyParams) msg->bodyptr)->smesessionId; + session_entry = pe_find_session_by_session_id(mac_ctx, session_id); + if (session_entry == NULL) { + pe_err("session does not exist for given sessionId [%d]", + session_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, + sme_session_id, 0); + return; + } + if (eLIM_MLM_WT_SET_BSS_KEY_STATE == session_entry->limMlmState) { + result_status = + (uint16_t)(((tpSetBssKeyParams)msg->bodyptr)->status); + key_len = ((tpSetBssKeyParams)msg->bodyptr)->key[0].keyLength; + } else { + /* + * BCAST key also uses tpSetStaKeyParams. + * Done this way for readabilty. + */ + result_status = + (uint16_t)(((tpSetStaKeyParams)msg->bodyptr)->status); + key_len = ((tpSetStaKeyParams)msg->bodyptr)->key[0].keyLength; + } + + if (result_status == eSIR_SME_SUCCESS && key_len) + set_key_cnf.key_len_nonzero = true; + else + set_key_cnf.key_len_nonzero = false; + + /* Validate MLME state */ + if (eLIM_MLM_WT_SET_BSS_KEY_STATE != session_entry->limMlmState && + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE != + session_entry->limMlmState) { + pe_err("Received unexpected [Mesg Id - %d] in state %X", + msg->type, session_entry->limMlmState); + } else { + set_key_cnf.resultCode = result_status; + } + qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + /* Restore MLME state */ + session_entry->limMlmState = session_entry->limPrevMlmState; + + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_MLM_STATE, session_entry->peSessionId, + session_entry->limMlmState)); + set_key_req = + (tpLimMlmSetKeysReq) mac_ctx->lim.gpLimMlmSetKeysReq; + set_key_cnf.sessionId = session_id; + + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + if (NULL != set_key_req) { + qdf_copy_macaddr(&set_key_cnf.peer_macaddr, + &set_key_req->peer_macaddr); + /* + * Free the buffer cached for the + * global mac_ctx->lim.gpLimMlmSetKeysReq + */ + qdf_mem_zero(mac_ctx->lim.gpLimMlmSetKeysReq, + sizeof(tLimMlmSetKeysReq)); + qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); + mac_ctx->lim.gpLimMlmSetKeysReq = 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 pMac - Pointer to Global MAC structure. + * @param psessionEntry - session related information. + * @param status - channel switch success/failure. + * + * @return None + */ +static void lim_process_switch_channel_re_assoc_req(tpAniSirGlobal pMac, + tpPESession psessionEntry, + QDF_STATUS status) +{ + tLimMlmReassocCnf mlmReassocCnf; + tLimMlmReassocReq *pMlmReassocReq; + + pMlmReassocReq = + (tLimMlmReassocReq *) (psessionEntry->pLimMlmReassocReq); + if (pMlmReassocReq == NULL) { + 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 + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&pMac->lim.limTimers.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(pMac, pMlmReassocReq, psessionEntry); + return; +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq != NULL) { + /* Update PE session Id */ + mlmReassocCnf.sessionId = pMlmReassocReq->sessionId; + qdf_mem_free(pMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + } else { + mlmReassocCnf.sessionId = 0; + } + + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + + +/** + * lim_process_switch_channel_join_req() -Initiates probe request + * + * @mac_ctx - A pointer to Global MAC structure + * @sessionEntry - 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( + tpAniSirGlobal mac_ctx, tpPESession session_entry, + QDF_STATUS status) +{ + tSirMacSSid ssId; + tLimMlmJoinCnf join_cnf; + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Change channel failed!!"); + goto error; + } + + if ((NULL == session_entry) || (NULL == session_entry->pLimMlmJoinReq) + || (NULL == session_entry->pLimJoinReq)) { + pe_err("invalid pointer!!"); + goto error; + } + + session_entry->limPrevMlmState = session_entry->limMlmState; + session_entry->limMlmState = eLIM_MLM_WT_JOIN_BEACON_STATE; + pe_debug("Sessionid %d prev lim state %d new lim state %d " + "systemrole = %d", session_entry->peSessionId, + session_entry->limPrevMlmState, + session_entry->limMlmState, GET_LIM_SYSTEM_ROLE(session_entry)); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session_entry); + + /* + * If send_deauth_before_con is enabled, Send Deauth first to AP if last + * disconnection was caused by HB failure. + */ + if (mac_ctx->roam.configParam.send_deauth_before_con) { + 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 %d to BSSID: "MAC_ADDRESS_STR, apCount, + session_entry->peSessionId, session_entry->currentOperChannel, + MAC_ADDR_ARRAY(session_entry->pLimMlmJoinReq->bssDescription. + bssId)); + + lim_send_deauth_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_REASON, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry, false); + + qdf_mem_zero(mac_ctx->lim.gLimHeartBeatApMac[apCount], + sizeof(tSirMacAddr)); + break; + } + } + } + + /* 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.limTimers.gLimPeriodicJoinProbeReqTimer.sessionId = + session_entry->peSessionId; + pe_debug("Sessionid: %d Send Probe req on channel %d ssid:%.*s " + "BSSID: " MAC_ADDRESS_STR, session_entry->peSessionId, + session_entry->currentOperChannel, ssId.length, ssId.ssId, + MAC_ADDR_ARRAY( + 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.limTimers.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; + } + /* include additional IE if there is */ + lim_send_probe_req_mgmt_frame(mac_ctx, &ssId, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry->currentOperChannel, session_entry->selfMacAddr, + session_entry->dot11mode, + &session_entry->pLimJoinReq->addIEScan.length, + session_entry->pLimJoinReq->addIEScan.addIEdata); + + if (session_entry->pePersona == QDF_P2P_CLIENT_MODE) { + /* Activate Join Periodic Probe Req timer */ + if (tx_timer_activate + (&mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + pe_err("Periodic JoinReq timer activate failed"); + goto error; + } + } + return; +error: + if (NULL != session_entry) { + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + if (session_entry->pLimJoinReq) { + qdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + } + join_cnf.sessionId = session_entry->peSessionId; + } else { + join_cnf.sessionId = 0; + } + join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, (uint32_t *)&join_cnf); +} + +/** + * lim_process_switch_channel_rsp() + * + ***FUNCTION: + * This function is called to process switchChannelRsp message from HAL. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param body - message body. + * + * @return None + */ +void lim_process_switch_channel_rsp(tpAniSirGlobal pMac, void *body) +{ + tpSwitchChannelParams pChnlParams = NULL; + QDF_STATUS status; + uint16_t channelChangeReasonCode; + uint8_t peSessionId; + tpPESession psessionEntry; + /* 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 deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pChnlParams = (tpSwitchChannelParams) body; + status = pChnlParams->status; + peSessionId = pChnlParams->peSessionId; + + psessionEntry = pe_find_session_by_session_id(pMac, peSessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given sessionId"); + goto free; + } + psessionEntry->ch_switch_in_progress = false; + /* HAL fills in the tx power used for mgmt frames in this field. */ + /* Store this value to use in TPC report IE. */ + rrm_cache_mgmt_tx_power(pMac, pChnlParams->txMgmtPower, psessionEntry); + channelChangeReasonCode = psessionEntry->channelChangeReasonCode; + /* initialize it back to invalid id */ + psessionEntry->chainMask = pChnlParams->chainMask; + psessionEntry->smpsMode = pChnlParams->smpsMode; + psessionEntry->channelChangeReasonCode = 0xBAD; + pe_debug("channelChangeReasonCode %d", channelChangeReasonCode); + switch (channelChangeReasonCode) { + case LIM_SWITCH_CHANNEL_REASSOC: + lim_process_switch_channel_re_assoc_req(pMac, psessionEntry, status); + break; + case LIM_SWITCH_CHANNEL_JOIN: + lim_process_switch_channel_join_req(pMac, psessionEntry, status); + break; + + case LIM_SWITCH_CHANNEL_OPERATION: + /* + * 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 (pMac->lim.gpchangeChannelCallback) { + pe_debug("Channel changed hence invoke registered call back"); + pMac->lim.gpchangeChannelCallback(pMac, status, + pMac->lim. + gpchangeChannelData, + psessionEntry); + } + /* If MCC upgrade/DBS downgrade happended during channel switch, + * the policy manager connection table needs to be updated. + */ + policy_mgr_update_connection_info(pMac->psoc, + psessionEntry->smeSessionId); + if (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) { + pe_debug("Send p2p operating channel change conf action frame once first beacon is received on new channel"); + psessionEntry->send_p2p_conf_frame = true; + } + break; + case LIM_SWITCH_CHANNEL_SAP_DFS: + { + /* 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(pMac, psessionEntry, + pChnlParams); + /* If MCC upgrade/DBS downgrade happended during channel switch, + * the policy manager connection table needs to be updated. + */ + policy_mgr_update_connection_info(pMac->psoc, + psessionEntry->smeSessionId); + policy_mgr_set_do_hw_mode_change_flag(pMac->psoc, true); + } + break; + default: + break; + } +free: + qdf_mem_free(body); +} + +QDF_STATUS lim_send_beacon_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, + enum sir_bcn_update_reason reason) +{ + tBeaconGenParams *pBeaconGenParams = NULL; + struct scheduler_msg limMsg = {0}; + /** Allocate the Memory for Beacon Pre Message and for Stations in PoweSave*/ + if (!psessionEntry) { + pe_err("Error:Unable to get the PESessionEntry"); + return QDF_STATUS_E_INVAL; + } + pBeaconGenParams = qdf_mem_malloc(sizeof(*pBeaconGenParams)); + if (!pBeaconGenParams) { + pe_err("Unable to allocate memory during sending beaconPreMessage"); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy((void *)pBeaconGenParams->bssId, + (void *)psessionEntry->bssId, QDF_MAC_ADDR_SIZE); + limMsg.bodyptr = pBeaconGenParams; + return sch_process_pre_beacon_ind(pMac, &limMsg, reason); +} + +void lim_process_rx_channel_status_event(tpAniSirGlobal mac_ctx, void *buf) +{ + struct lim_channel_status *chan_status = buf; + + if (NULL == chan_status) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_ERROR, + "%s: ACS evt report buf NULL", __func__); + return; + } + + if (mac_ctx->sap.acs_with_more_param) + lim_add_channel_status_info(mac_ctx, chan_status, + chan_status->channel_id); + else + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_WARN, + "%s: Error evt report", __func__); + + qdf_mem_free(buf); + + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..d44c8f7b80b4062c28347ecddcdbe2884607230f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c @@ -0,0 +1,673 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.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(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, tpPESession psessionEntry); + +/** + * lim_get_wpspbc_sessions() - to get wps pbs sessions + * @mac_ctx: Pointer to Global MAC structure + * @addr: probe request source MAC address + * @uuid_e: A pointer to UUIDE element of WPS IE in WPS PBC probe request + * @session: A pointer to station PE session + * + * This function is called to query the WPS PBC overlap. This function + * check WPS PBC probe request link list for PBC overlap + * + * @return None + */ + +void lim_get_wpspbc_sessions(tpAniSirGlobal mac_ctx, struct qdf_mac_addr addr, + uint8_t *uuid_e, eWPSPBCOverlap *overlap, + tpPESession session) +{ + int count = 0; + tSirWPSPBCSession *pbc; + uint32_t cur_time; + + cur_time = (uint32_t) (qdf_mc_timer_get_system_ticks() / + QDF_TICKS_PER_SECOND); + qdf_zero_macaddr(&addr); + qdf_mem_zero((uint8_t *) uuid_e, SIR_WPS_UUID_LEN); + for (pbc = session->pAPWPSPBCSession; pbc; pbc = pbc->next) { + if (cur_time > pbc->timestamp + SIR_WPS_PBC_WALK_TIME) + break; + count++; + if (count > 1) + break; + qdf_copy_macaddr(&addr, &pbc->addr); + qdf_mem_copy((uint8_t *) uuid_e, (uint8_t *) pbc->uuid_e, + SIR_WPS_UUID_LEN); + } + if (count > 1) + /* Overlap */ + *overlap = eSAP_WPSPBC_OVERLAP_IN120S; + else if (count == 0) + /* no WPS probe request in 120 second */ + *overlap = eSAP_WPSPBC_NO_WPSPBC_PROBE_REQ_IN120S; + else + /* One WPS probe request in 120 second */ + *overlap = eSAP_WPSPBC_ONE_WPSPBC_PROBE_REQ_IN120S; + + pe_debug("overlap: %d", *overlap); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + addr.bytes, QDF_MAC_ADDR_SIZE); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + uuid_e, SIR_WPS_UUID_LEN); + return; +} + +/** + * lim_remove_timeout_pbc_sessions() - remove pbc probe req entries. + * @pMac - 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(tpAniSirGlobal pMac, + 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_remove_pbc_sessions() - Remove PBC sessions + * @mac: Pointer to Global MAC structure + * @remove_mac: MAC Address of STA in WPS Session to be removed + * @session_entry: session entry + * + * Return: none + */ +void lim_remove_pbc_sessions(tpAniSirGlobal mac, struct qdf_mac_addr remove_mac, + tpPESession session_entry) +{ + tSirWPSPBCSession *pbc, *prev = NULL; + + prev = pbc = session_entry->pAPWPSPBCSession; + + while (pbc) { + if (qdf_is_macaddr_equal(&pbc->addr, &remove_mac)) { + prev->next = pbc->next; + if (pbc == session_entry->pAPWPSPBCSession) + session_entry->pAPWPSPBCSession = pbc->next; + qdf_mem_free(pbc); + return; + } + prev = pbc; + pbc = pbc->next; + } +} + +/** + * 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 pMac 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 psessionEntry A pointer to station PE session + * + * @return None + */ + +static void lim_update_pbc_session_entry(tpAniSirGlobal pMac, + uint8_t *addr, uint8_t *uuid_e, + tpPESession psessionEntry) +{ + 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 reques 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 = psessionEntry->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 + psessionEntry->pAPWPSPBCSession = pbc->next; + break; + } + prev = pbc; + pbc = pbc->next; + } + + if (!pbc) { + pbc = qdf_mem_malloc(sizeof(tSirWPSPBCSession)); + if (NULL == pbc) { + pe_err("memory allocate failed!"); + 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 = psessionEntry->pAPWPSPBCSession; + psessionEntry->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(pMac, 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 pMac Pointer to Global MAC structure + * @param psessionEntry A pointer to station PE session + * + * @return None + */ + +void lim_wpspbc_close(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + lim_remove_timeout_pbc_sessions(pMac, psessionEntry->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; +} + +/** + * 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 ponter 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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + uint8_t *body_ptr; + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + tSirProbeReq probe_req; + tAniSSID ssid; + + /* Don't send probe responses if disabled */ + if (mac_ctx->lim.gLimProbeRespDisableFlag) + return; + + /* + * Don't send probe response if P2P go is scanning till scan + * come to idle state. + */ + if ((session->pePersona == QDF_P2P_GO_MODE) && + mac_ctx->lim.gpLimRemainOnChanReq) { + pe_debug("GO is scanning, don't send probersp on diff chnl"); + return; + } + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + if (LIM_IS_AP_ROLE(session) || + (LIM_IS_IBSS_ROLE(session) && + (WMA_GET_RX_BEACON_SENT(rx_pkt_info)))) { + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_debug("Received Probe Request: %d bytes from", + frame_len); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + /* 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; + } + } + + /* 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: " + MAC_ADDRESS_STR, frame_len, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + if (session->pePersona == 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 is: "); + lim_print_mac_addr(mac_ctx, + mac_hdr->sa, LOGD); + return; + } + } + 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 { + lim_update_pbc_session_entry(mac_ctx, + mac_hdr->sa, + probe_req.probeReqWscIeInfo.UUID_E.uuid, + session); + } + } + ssid.length = session->ssId.length; + /* Copy the SSID from sessio entry to local variable */ + qdf_mem_copy(ssid.ssId, session->ssId.ssId, + session->ssId.length); + + /* + * 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, + mac_hdr->sa, &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } else if (session->pePersona == + 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, + mac_hdr->sa, + &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } + } else { + pe_debug("Ignore ProbeReq frm with unmatch SSID received from"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, + LOGD); + } + } 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 + */ + return; + lim_send_probe_rsp_mgmt_frame(mac_ctx, mac_hdr->sa, + &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } +multipleSSIDcheck: + pe_debug("Ignore ProbeReq frm with unmatch SSID rcved from"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + } else { + /* Ignore received Probe Request frame */ + pe_debug("Ignoring Probe Request frame received from"); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGD); + } + 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 pMac Pointer to Global MAC structure + * @param *pBd A pointer to Buffer descriptor + associated PDUs + * @param psessionEntry A pointer to PE session + * + * @return None + */ + +static void +lim_indicate_probe_req_to_hdd(tpAniSirGlobal pMac, uint8_t *pBd, + tpPESession psessionEntry) +{ + 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(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, WMA_GET_RX_CH(pBd), + psessionEntry, + WMA_GET_RX_RSSI_NORMALIZED(pBd)); +} /*** 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(tpAniSirGlobal mac_ctx, + uint8_t *buf_descr, tpPESession session) +{ + uint8_t i; + + if (session != NULL) { + 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 == NULL) + continue; + if (LIM_IS_AP_ROLE(session)) + lim_indicate_probe_req_to_hdd(mac_ctx, + buf_descr, session); + if (LIM_IS_AP_ROLE(session) || + LIM_IS_IBSS_ROLE(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 psessionEntry A pointer to PE session + * + * @return None + */ +void +lim_send_sme_probe_req_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, tpPESession psessionEntry) +{ + tSirSmeProbeReqInd *pSirSmeProbeReqInd; + struct scheduler_msg msgQ = {0}; + + pSirSmeProbeReqInd = qdf_mem_malloc(sizeof(tSirSmeProbeReqInd)); + if (NULL == pSirSmeProbeReqInd) { + /* Log error */ + pe_err("call to AllocateMemory failed for eWNI_SME_PROBE_REQ_IND"); + 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(tSirSmeProbeReq); + pSirSmeProbeReqInd->sessionId = psessionEntry->smeSessionId; + + qdf_mem_copy(pSirSmeProbeReqInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.peer_macaddr.bytes, + peerMacAddr, QDF_MAC_ADDR_SIZE); + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->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); + + if (lim_sys_process_mmh_msg_api(pMac, &msgQ, ePROT) != QDF_STATUS_SUCCESS) + pe_err("couldnt send the probe req to hdd"); + +} /*** end lim_send_sme_probe_req_ind() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..fb3d0f59b7e0cd23c6f40e64eca52b15a19aa329 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c @@ -0,0 +1,300 @@ +/* + * 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_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 "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(tpAniSirGlobal 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_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(tpAniSirGlobal mac_ctx, uint8_t *rx_Packet_info, + tpPESession session_entry) +{ + uint8_t *body; + uint32_t frame_len = 0; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr header; + tSirProbeRespBeacon *probe_rsp; + uint8_t qos_enabled = false; + uint8_t wme_enabled = false; + + if (!session_entry) { + pe_err("session_entry is NULL"); + return; + } + pe_debug("SessionId: %d ProbeRsp Frame is received", + session_entry->peSessionId); + + probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == 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); + + pe_debug("Rx Probe Response with length = %d from "MAC_ADDRESS_STR, + WMA_GET_RX_MPDU_LEN(rx_Packet_info), + MAC_ADDR_ARRAY(header->sa)); + + /* 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); + qdf_mem_free(probe_rsp); + return; + } + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("Probe Resp Frame Received: BSSID " + MAC_ADDRESS_STR " (RSSI %d)"), + MAC_ADDR_ARRAY(header->bssId), + (uint) abs((int8_t)WMA_GET_RX_RSSI_NORMALIZED(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); + qdf_mem_free(probe_rsp); + return; + } + + 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 != NULL) { + qdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + session_entry->bcnLen = 0; + } + session_entry->bcnLen = + WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info); + session_entry->beacon = + qdf_mem_malloc(session_entry->bcnLen); + if (NULL == session_entry->beacon) { + pe_err("No Memory to store beacon"); + } else { + /* + * Store the Beacon/ProbeRsp. + * This is sent to csr/hdd in join cnf response. + */ + qdf_mem_copy(session_entry->beacon, + WMA_GET_RX_MPDU_DATA + (rx_Packet_info), + session_entry->bcnLen); + } + /* STA in WT_JOIN_BEACON_STATE */ + lim_check_and_announce_join_success(mac_ctx, probe_rsp, + header, + session_entry); + } else if (session_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) { + tpDphHashNode sta_ds = NULL; + /* + * 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))) { + qdf_mem_free(probe_rsp); + return; + } + if (!LIM_IS_CONNECTION_ACTIVE(session_entry)) { + pe_warn("Recved Probe Resp from AP,AP-alive"); + if (probe_rsp->HTInfo.present) + lim_received_hb_handler(mac_ctx, + probe_rsp->HTInfo.primaryChannel, + session_entry); + else + lim_received_hb_handler(mac_ctx, + (uint8_t)probe_rsp->channelNumber, + session_entry); + } + if (LIM_IS_STA_ROLE(session_entry) && + !wma_is_csa_offload_enabled()) { + if (probe_rsp->channelSwitchPresent) { + /* + * 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_update_channel_switch(mac_ctx, + probe_rsp, + session_entry); + } else if (session_entry->gLimSpecMgmt.dot11hChanSwState + == eLIM_11H_CHANSW_RUNNING) { + lim_cancel_dot11h_channel_switch( + mac_ctx, session_entry); + } + } + /* + * 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)) { + if (sch_beacon_edca_process(mac_ctx, + &probe_rsp->edcaParams, + session_entry) != QDF_STATUS_SUCCESS) { + pe_err("EDCA param process error"); + } else if (sta_ds != NULL) { + /* + * 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, + sta_ds->bssId, false); + } else { + pe_err("SelfEntry missing in Hash"); + } + } + if (session_entry->fWaitForProbeRsp == true) { + pe_warn("Check probe resp for caps change"); + lim_detect_change_in_ap_capabilities( + mac_ctx, probe_rsp, session_entry); + } + } else { + if (LIM_IS_IBSS_ROLE(session_entry) && + (session_entry->limMlmState == + eLIM_MLM_BSS_STARTED_STATE)) + lim_handle_ibss_coalescing(mac_ctx, probe_rsp, + rx_Packet_info, session_entry); + } + qdf_mem_free(probe_rsp); + + /* Ignore Probe Response frame in all other states */ + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..150ef6cda1b4427c762b8cd4cac7d61a1d3492ce --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -0,0 +1,6253 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.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_ibss_peer_mgmt.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" + +/* + * This overhead is time for sending NOA start to host in case of GO/sending + * NULL data & receiving ACK in case of P2P Client and starting actual scanning + * with init scan req/rsp plus in case of concurrency, taking care of sending + * null data and receiving ACK to/from AP/Also SetChannel with calibration + * is taking around 7ms . + */ +#define SCAN_MESSAGING_OVERHEAD 20 /* in msecs */ +#define JOIN_NOA_DURATION 2000 /* in msecs */ +#define OEM_DATA_NOA_DURATION 60 /* in msecs */ +#define DEFAULT_PASSIVE_MAX_CHANNEL_TIME 110 /* in msecs */ + +#define CONV_MS_TO_US 1024 /* conversion factor from ms to us */ + +#define BEACON_INTERVAL_THRESHOLD 50 /* in msecs */ +#define STA_BURST_SCAN_DURATION 120 /* in msecs */ + +/* SME REQ processing function templates */ +static bool __lim_process_sme_sys_ready_ind(tpAniSirGlobal, uint32_t *); +static bool __lim_process_sme_start_bss_req(tpAniSirGlobal, + struct scheduler_msg *pMsg); +static void __lim_process_sme_join_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_reassoc_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_disassoc_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_disassoc_cnf(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_deauth_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_set_context_req(tpAniSirGlobal, uint32_t *); +static bool __lim_process_sme_stop_bss_req(tpAniSirGlobal, + struct scheduler_msg *pMsg); +static void __lim_process_send_disassoc_frame(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf); +static void lim_process_sme_channel_change_request(tpAniSirGlobal pMac, + uint32_t *pMsg); +static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_sme_dfs_csa_ie_request(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_nss_update_request(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_set_ie_req(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_start_bss_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, + uint16_t srcDataLen); + +static void lim_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen); +static bool lim_update_ibss_prop_add_ies(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + tSirModifyIE *pModifyIE); +static void lim_process_modify_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_process_update_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_process_ext_change_channel(tpAniSirGlobal mac_ctx, + uint32_t *msg); + +/** + * 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(tpAniSirGlobal 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) { + pe_err("qdf_mem_malloc failed"); + status = QDF_STATUS_E_NOMEM; + /* Free the active command list + * Probably the malloc is going to fail there as well?! + */ + 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) { + pe_err("HW mode resp failed"); + 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, ePROT); + 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(tpAniSirGlobal 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) { + pe_err("failed to allocate memory"); + status = QDF_STATUS_E_NOMEM; + /* Free the active command list + * Probably the malloc is going to fail there as well?! + */ + 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) { + pe_err("Dual mac config resp failed"); + 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, ePROT); + return status; +} + +/** + * 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(tpAniSirGlobal 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) { + pe_err("failed to allocate memory"); + 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) { + pe_err("antenna mode resp failed"); + 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, ePROT); + return status; +} + +/** + * __lim_is_sme_assoc_cnf_valid() + * + ***FUNCTION: + * This function is called by __lim_process_sme_assoc_cnf_new() upon + * receiving SME_ASSOC_CNF. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMeasReq Pointer to Received ASSOC_CNF message + * @return true When received SME_ASSOC_CNF is formatted + * correctly + * false otherwise + */ + +static inline uint8_t __lim_is_sme_assoc_cnf_valid(tpSirSmeAssocCnf pAssocCnf) +{ + if (qdf_is_macaddr_group(&pAssocCnf->peer_macaddr)) + return false; + else + return true; +} /*** end __lim_is_sme_assoc_cnf_valid() ***/ + +/** + * __lim_get_sme_join_req_size_for_alloc() + * + ***FUNCTION: + * This function is called in various places to get IE length + * from tSirBssDescription structure + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBssDescr + * @return Total IE length + */ + +static uint16_t __lim_get_sme_join_req_size_for_alloc(uint8_t *pBuf) +{ + uint16_t len = 0; + + if (!pBuf) + return len; + + pBuf += sizeof(uint16_t); + len = lim_get_u16(pBuf); + return len; +} + +/** + * __lim_is_defered_msg_for_learn() - message handling in SME learn state + * @pMac: Global MAC context + * @pMsg: Pointer to message posted from SME to LIM. + * + * Has role only if 11h is enabled. Not used on STA side. + * Defers the message if SME is in learn state and brings + * the LIM back to normal mode. + * + * Return: true - If defered false - Otherwise + */ + +static bool __lim_is_defered_msg_for_learn(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + if (lim_is_system_in_scan_state(pMac)) { + if (lim_defer_msg(pMac, pMsg) != TX_SUCCESS) { + pe_err("Could not defer Msg: %d", pMsg->type); + return false; + } + pe_debug("Defer the message, in learn mode type: %d", + pMsg->type); + return true; + } + return false; +} + +/** + * __lim_is_defered_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 defered otherwise return false. + */ +static bool +__lim_is_defered_msg_for_radar(tpAniSirGlobal 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 + * @pMac: Global MAC context + * @pMsgBuf: 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(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + struct scheduler_msg msg = {0}; + tSirSmeReadyReq *ready_req = (tSirSmeReadyReq *) pMsgBuf; + + msg.type = WMA_SYS_READY_IND; + msg.reserved = 0; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + + if (ANI_DRIVER_TYPE(pMac) != QDF_DRIVER_TYPE_MFG) { + ready_req->pe_roam_synch_cb = pe_roam_synch_callback; + pe_register_mgmt_rx_frm_callback(pMac); + pe_register_callbacks_with_wma(pMac, ready_req); + pMac->lim.sme_msg_callback = ready_req->sme_msg_cb; + pMac->lim.stop_roaming_callback = ready_req->stop_roaming_cb; + } + + pe_debug("sending WMA_SYS_READY_IND msg to HAL"); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(pMac, &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(tpAniSirGlobal mac_ctx, tpPESession session, + tpSirSmeStartBssReq sme_start_bss_req) +{ + session->limSystemRole = eLIM_AP_ROLE; + session->privacy = sme_start_bss_req->privacy; + session->fwdWPSPBCProbeReq = sme_start_bss_req->fwdWPSPBCProbeReq; + session->authType = sme_start_bss_req->authType; + /* Store the DTIM period */ + session->dtimPeriod = (uint8_t) sme_start_bss_req->dtimPeriod; + /* Enable/disable UAPSD */ + session->apUapsdEnable = sme_start_bss_req->apUapsdEnable; + if (session->pePersona == QDF_P2P_GO_MODE) { + session->proxyProbeRspEn = 0; + } else { + /* + * 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; + session->sap_dot11mc = sme_start_bss_req->sap_dot11mc; + session->vendor_vht_sap = + sme_start_bss_req->vendor_vht_sap; + lim_get_short_slot_from_phy_mode(mac_ctx, session, session->gLimPhyMode, + &session->shortSlotTimeSupported); + session->isCoalesingInIBSSAllowed = + sme_start_bss_req->isCoalesingInIBSSAllowed; + + session->beacon_tx_rate = sme_start_bss_req->beacon_tx_rate; + +} + +/** + * __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(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + uint16_t size; + uint32_t val = 0; + QDF_STATUS ret_status; + tSirMacChanNum channel_number; + tLimMlmStartReq *mlm_start_req = NULL; + tpSirSmeStartBssReq sme_start_bss_req = NULL; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + /* Flag Used in case of IBSS to Auto generate BSSID. */ + uint32_t auto_gen_bssid = false; + uint8_t session_id; + tpPESession session = NULL; + uint8_t sme_session_id = 0xFF; + uint16_t sme_transaction_id = 0xFF; + uint32_t chanwidth; + struct vdev_type_nss *vdev_type_nss; + QDF_STATUS cfg_get_wmi_dfs_master_param = QDF_STATUS_SUCCESS; + +/* 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 */ + + pe_debug("Received START_BSS_REQ"); + size = sizeof(tSirSmeStartBssReq); + sme_start_bss_req = qdf_mem_malloc(size); + if (NULL == sme_start_bss_req) { + pe_err("Allocate Memory fail for LimStartBssReq"); + /* Send failure response to host */ + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + qdf_mem_copy(sme_start_bss_req, msg_buf, sizeof(tSirSmeStartBssReq)); + sme_session_id = sme_start_bss_req->sessionId; + sme_transaction_id = sme_start_bss_req->transactionId; + + 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)) { + pe_warn("Received invalid eWNI_SME_START_BSS_REQ"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } + + /* + * 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, + sme_start_bss_req->bssid.bytes, &session_id); + if (session != NULL) { + 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, + sme_start_bss_req->bssid.bytes, + &session_id, mac_ctx->lim.maxStation, + sme_start_bss_req->bssType); + if (session == NULL) { + 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, + &sme_start_bss_req->ssId, + sme_start_bss_req->channelId); + } + + if (QDF_NDI_MODE != sme_start_bss_req->bssPersona) { + /* Probe resp add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.probeRespData_buff, + &session->addIeParams.probeRespDataLen, + sme_start_bss_req->addIeParams. + probeRespData_buff, + sme_start_bss_req->addIeParams. + probeRespDataLen); + + /* Probe Beacon add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.probeRespBCNData_buff, + &session->addIeParams.probeRespBCNDataLen, + sme_start_bss_req->addIeParams. + probeRespBCNData_buff, + sme_start_bss_req->addIeParams. + probeRespBCNDataLen); + + /* Assoc resp IE */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.assocRespData_buff, + &session->addIeParams.assocRespDataLen, + sme_start_bss_req->addIeParams. + assocRespData_buff, + sme_start_bss_req->addIeParams. + assocRespDataLen); + } + /* Store the session related params in newly created session */ + session->pLimStartBssReq = sme_start_bss_req; + + /* Store SME session Id in sessionTable */ + session->smeSessionId = sme_start_bss_req->sessionId; + + session->transactionId = sme_start_bss_req->transactionId; + + qdf_mem_copy(&(session->htConfig), + &(sme_start_bss_req->htConfig), + sizeof(session->htConfig)); + + qdf_mem_copy(&(session->vht_config), + &(sme_start_bss_req->vht_config), + sizeof(session->vht_config)); + + sir_copy_mac_addr(session->selfMacAddr, + sme_start_bss_req->self_macaddr.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->bssType = sme_start_bss_req->bssType; + + session->nwType = sme_start_bss_req->nwType; + + session->beaconParams.beaconInterval = + sme_start_bss_req->beaconInterval; + + /* Store the channel number in session Table */ + session->currentOperChannel = + sme_start_bss_req->channelId; + + /* Store Persona */ + session->pePersona = sme_start_bss_req->bssPersona; + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("PE PERSONA=%d"), session->pePersona); + + /* Update the phymode */ + session->gLimPhyMode = sme_start_bss_req->nwType; + + session->maxTxPower = + cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + /* Store the dot 11 mode in to the session Table */ + session->dot11mode = sme_start_bss_req->dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + session->cc_switch_mode = + sme_start_bss_req->cc_switch_mode; +#endif + session->htCapability = + IS_DOT11_MODE_HT(session->dot11mode); + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + + pe_debug("HT[%d], VHT[%d]", + session->htCapability, session->vhtCapability); + + if (IS_DOT11_MODE_HE(session->dot11mode)) { + lim_update_session_he_capable(mac_ctx, session); + lim_copy_bss_he_cap(session, sme_start_bss_req); + } + + session->txLdpcIniFeatureEnabled = + sme_start_bss_req->txLdpcIniFeatureEnabled; +#ifdef WLAN_FEATURE_11W + session->limRmfEnabled = + sme_start_bss_req->pmfCapable ? 1 : 0; + pe_debug("Session RMF enabled: %d", session->limRmfEnabled); +#endif + + 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)); + + if (IS_5G_CH(session->currentOperChannel)) + vdev_type_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_type_nss = &mac_ctx->vdev_type_nss_2g; + + switch (sme_start_bss_req->bssType) { + case eSIR_INFRA_AP_MODE: + lim_configure_ap_start_bss_session(mac_ctx, session, + sme_start_bss_req); + if (session->pePersona == QDF_SAP_MODE) + session->vdev_nss = vdev_type_nss->sap; + else + session->vdev_nss = vdev_type_nss->p2p_go; + break; + case eSIR_IBSS_MODE: + session->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + lim_get_short_slot_from_phy_mode(mac_ctx, session, + session->gLimPhyMode, + &session->shortSlotTimeSupported); + + /* + * initialize to "OPEN". + * will be updated upon key installation + */ + session->encryptType = eSIR_ED_NONE; + session->vdev_nss = vdev_type_nss->ibss; + + break; + case eSIR_NDI_MODE: + 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; + } + + pe_debug("persona - %d, nss - %d", + session->pePersona, session->vdev_nss); + session->nss = session->vdev_nss; + if (!mac_ctx->roam.configParam.enable2x2) + session->nss = 1; + /* + * Allocate memory for the array of + * parsed (Re)Assoc request structure + */ + if (sme_start_bss_req->bssType == eSIR_INFRA_AP_MODE) { + session->parsedAssocReq = + qdf_mem_malloc(session->dph.dphHashTable. + size * sizeof(tpSirAssocReq)); + if (NULL == session->parsedAssocReq) { + pe_warn("AllocateMemory() failed"); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + } + + if (!sme_start_bss_req->channelId && + sme_start_bss_req->bssType != eSIR_NDI_MODE) { + pe_err("Received invalid eWNI_SME_START_BSS_REQ"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } + channel_number = sme_start_bss_req->channelId; +#ifdef QCA_HT_2040_COEX + if (sme_start_bss_req->obssEnabled) + 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; + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("cbMode %u"), sme_start_bss_req->cbMode); + if (lim_is_session_he_capable(session) || + session->vhtCapability || session->htCapability) { + chanwidth = sme_start_bss_req->vht_channel_width; + pe_debug("vht_channel_width %u htSupportedChannelWidthSet %d", + sme_start_bss_req->vht_channel_width, + session->htSupportedChannelWidthSet); + session->ch_width = chanwidth; + if (session->htSupportedChannelWidthSet) { + session->ch_center_freq_seg0 = + sme_start_bss_req->center_freq_seg0; + session->ch_center_freq_seg1 = + sme_start_bss_req->center_freq_seg1; + } else { + session->ch_center_freq_seg0 = 0; + session->ch_center_freq_seg1 = 0; + } + } + + if (session->vhtCapability && + (session->ch_width > CH_WIDTH_80MHZ)) { + session->nss = 1; + pe_debug("nss set to [%d]", session->nss); + } + pe_debug("vht su tx bformer %d", + session->vht_config.su_beam_former); + + /* 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_IBSS_ROLE(session) || + LIM_IS_NDI_ROLE(session)) { + session->gLimProtectionControl = + sme_start_bss_req->protEnabled; + /* + * each byte will have the following info + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * reserved reserved RIFS Lsig n-GF ht20 11g 11b + */ + qdf_mem_copy((void *)&session->cfgProtection, + (void *)&sme_start_bss_req->ht_capab, + sizeof(uint16_t)); + /* 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 (NULL == mlm_start_req) { + pe_err("Allocate Memory failed for mlmStartReq"); + 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->obssProtEnabled = + sme_start_bss_req->obssProtEnabled; + + mlm_start_req->bssType = session->bssType; + + /* Fill PE session Id from the session Table */ + mlm_start_req->sessionId = session->peSessionId; + + if (mlm_start_req->bssType == eSIR_INFRA_AP_MODE || + mlm_start_req->bssType == eSIR_NDI_MODE) { + /* + * Copy the BSSId from sessionTable to + * mlmStartReq struct + */ + sir_copy_mac_addr(mlm_start_req->bssId, session->bssId); + } else { + /* ibss mode */ + mac_ctx->lim.gLimIbssCoalescingHappened = false; + + ret_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_IBSS_AUTO_BSSID, + &auto_gen_bssid); + if (ret_status != QDF_STATUS_SUCCESS) { + pe_err("Get Auto Gen BSSID fail,Status: %d", + ret_status); + ret_code = eSIR_LOGE_EXCEPTION; + goto free; + } + + if (!auto_gen_bssid) { + /* + * We're not auto generating BSSID. + * Instead, get it from session entry + */ + sir_copy_mac_addr(mlm_start_req->bssId, + session->bssId); + /* + * Start IBSS group BSSID + * Auto Generating BSSID. + */ + auto_gen_bssid = ((mlm_start_req->bssId[0] & + 0x01) ? true : false); + } + + if (auto_gen_bssid) { + /* + * if BSSID is not any uc id. + * then use locally generated BSSID. + * Autogenerate the BSSID + */ + lim_get_random_bssid(mac_ctx, + mlm_start_req->bssId); + mlm_start_req->bssId[0] = 0x02; + + /* + * Copy randomly generated BSSID + * to the session Table + */ + sir_copy_mac_addr(session->bssId, + mlm_start_req->bssId); + } + } + /* store the channel num in mlmstart req structure */ + mlm_start_req->channelNumber = session->currentOperChannel; + mlm_start_req->cbMode = sme_start_bss_req->cbMode; + 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; + + } else { + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_DTIM_PERIOD, &val) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve DTIM Period"); + mlm_start_req->dtimPeriod = (uint8_t) val; + } + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_CFP_PERIOD, &val) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve Beacon interval"); + mlm_start_req->cfParamSet.cfpPeriod = (uint8_t) val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_CFP_MAX_DURATION, &val) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve CFPMaxDuration"); + mlm_start_req->cfParamSet.cfpMaxDuration = (uint16_t) val; + + /* + * 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(channel_number); + + /* Initialize 11h Enable Flag */ + session->lim11hEnable = 0; + if (mlm_start_req->bssType != eSIR_IBSS_MODE && + (CHAN_HOP_ALL_BANDS_ENABLE || + BAND_5G == session->limRFBand)) { + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_11H_ENABLED, &val) != QDF_STATUS_SUCCESS) + pe_err("Fail to get WNI_CFG_11H_ENABLED"); + else + session->lim11hEnable = val; + + if (session->lim11hEnable && + (eSIR_INFRA_AP_MODE == + mlm_start_req->bssType)) { + cfg_get_wmi_dfs_master_param = + wlan_cfg_get_int(mac_ctx, + WNI_CFG_DFS_MASTER_ENABLED, + &val); + session->lim11hEnable = val; + } + if (cfg_get_wmi_dfs_master_param != QDF_STATUS_SUCCESS) + /* Failed get CFG WNI_CFG_DFS_MASTER_ENABLED */ + pe_err("Get Fail, CFG DFS ENABLE"); + } + + if (!session->lim11hEnable) { + if (cfg_set_int(mac_ctx, + WNI_CFG_LOCAL_POWER_CONSTRAINT, 0) != + QDF_STATUS_SUCCESS) + /* + * Failed to set the CFG param + * WNI_CFG_LOCAL_POWER_CONSTRAINT + */ + pe_err("Set LOCAL_POWER_CONSTRAINT failed"); + } + + mlm_start_req->beacon_tx_rate = session->beacon_tx_rate; + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_START_BSS_STATE; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + lim_post_mlm_message(mac_ctx, LIM_MLM_START_REQ, + (uint32_t *) mlm_start_req); + 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 != NULL) && + (session->pLimStartBssReq == sme_start_bss_req)) { + session->pLimStartBssReq = NULL; + } + if (NULL != sme_start_bss_req) + qdf_mem_free(sme_start_bss_req); + if (NULL != mlm_start_req) + qdf_mem_free(mlm_start_req); + if (NULL != session) { + pe_delete_session(mac_ctx, session); + session = NULL; + } + lim_send_sme_start_bss_rsp(mac_ctx, eWNI_SME_START_BSS_RSP, ret_code, + session, sme_session_id, sme_transaction_id); +} + +/** + * __lim_process_sme_start_bss_req() - Call handler to start BSS + * + * @pMac: Global MAC context + * @pMsg: Message pointer + * + * Wrapper for the function __lim_handle_sme_start_bss_request + * This message will be defered 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 defered the message. + */ +static bool __lim_process_sme_start_bss_req(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + if (__lim_is_defered_msg_for_learn(pMac, pMsg) || + __lim_is_defered_msg_for_radar(pMac, pMsg)) { + /** + * If message defered, buffer is not consumed yet. + * So return false + */ + return false; + } + + __lim_handle_sme_start_bss_request(pMac, (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 pMac Pointer to Global MAC structure + * @param *data Pointer to bssid buffer + * @return None + */ +void lim_get_random_bssid(tpAniSirGlobal pMac, uint8_t *data) +{ + uint32_t random[2]; + + random[0] = tx_time_get(); + random[0] |= (random[0] << 15); + random[1] = random[0] >> 1; + qdf_mem_copy(data, (uint8_t *) random, sizeof(tSirMacAddr)); +} + +#ifdef WLAN_FEATURE_SAE + +/** + * lim_update_sae_config()- This API update SAE session info to csr config + * from join request. + * @session: PE session + * @sme_join_req: pointer to join request + * + * Return: None + */ +static void lim_update_sae_config(tpPESession session, + tpSirSmeJoinReq sme_join_req) +{ + session->sae_pmk_cached = sme_join_req->sae_pmk_cached; + + pe_debug("pmk_cached %d for BSSID=" MAC_ADDRESS_STR, + session->sae_pmk_cached, + MAC_ADDR_ARRAY(sme_join_req->bssDescription.bssId)); +} +#else +static inline void lim_update_sae_config(tpPESession session, + tpSirSmeJoinReq sme_join_req) +{} +#endif + + +/** + * __lim_process_sme_join_req() - process SME_JOIN_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_JOIN_REQ message + * from HDD or upper layer application. + * + * Return: None + */ +static void +__lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpSirSmeJoinReq sme_join_req = NULL; + tLimMlmJoinReq *mlm_join_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + uint32_t val = 0; + uint16_t n_size; + uint8_t session_id; + tpPESession session = NULL; + uint8_t sme_session_id = 0; + uint16_t sme_transaction_id = 0; + int8_t local_power_constraint = 0, reg_max = 0; + uint16_t ie_len; + const uint8_t *vendor_ie; + tSirBssDescription *bss_desc; + struct lim_max_tx_pwr_attr tx_pwr_attr = {0}; + + if (!mac_ctx || !msg_buf) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("JOIN REQ with invalid data")); + return; + } + +/* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + /* + * Not sending any session, since it is not created yet. + * The response whould have correct state. + */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_REQ_EVENT, NULL, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* + * Expect Join request in idle state. + * Reassociate request is expected in link established state. + */ + + /* Global SME and LIM states are not defined yet for BT-AMP Support */ + if (mac_ctx->lim.gLimSmeState == eLIM_SME_IDLE_STATE) { + n_size = __lim_get_sme_join_req_size_for_alloc((uint8_t *) + msg_buf); + + sme_join_req = qdf_mem_malloc(n_size); + if (NULL == sme_join_req) { + pe_err("AllocateMemory failed for sme_join_req"); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + (void)qdf_mem_copy((void *)sme_join_req, (void *)msg_buf, + n_size); + + if (!lim_is_sme_join_req_valid(mac_ctx, sme_join_req)) { + /* Received invalid eWNI_SME_JOIN_REQ */ + /* Log the event */ + pe_warn("SessionId:%d JOIN REQ with invalid data", + sme_join_req->sessionId); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* + * 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, sme_join_req); + + bss_desc = &sme_join_req->bssDescription; + /* check for the existence of start BSS session */ + session = pe_find_session_by_bssid(mac_ctx, bss_desc->bssId, + &session_id); + + if (session != NULL) { + pe_err("Session(%d) Already exists for BSSID: " + MAC_ADDRESS_STR " in limSmeState = %X", + session_id, + MAC_ADDR_ARRAY(bss_desc->bssId), + session->limSmeState); + + if (session->limSmeState == eLIM_SME_LINK_EST_STATE && + session->smeSessionId == sme_join_req->sessionId) { + /* + * Received eWNI_SME_JOIN_REQ for same + * BSS as currently associated. + * Log the event and send success + */ + pe_warn("SessionId: %d", session_id); + pe_warn("JOIN_REQ for current joined BSS"); + /* Send Join success response to host */ + ret_code = eSIR_SME_ALREADY_JOINED_A_BSS; + session = NULL; + goto end; + } else { + pe_err("JOIN_REQ not for current joined BSS"); + ret_code = eSIR_SME_REFUSED; + session = NULL; + goto end; + } + } else { + /* + * Session Entry does not exist for given BSSId + * Try to Create a new session + */ + session = pe_create_session(mac_ctx, bss_desc->bssId, + &session_id, mac_ctx->lim.maxStation, + eSIR_INFRASTRUCTURE_MODE); + if (session == NULL) { + pe_err("Session Can not be created"); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } else { + pe_debug("SessionId:%d New session created", + session_id); + } + + /* Update the beacon/probe filter in mac_ctx */ + lim_set_bcn_probe_filter(mac_ctx, session, + &sme_join_req->ssId, + bss_desc->channelId); + } + session->max_amsdu_num = sme_join_req->max_amsdu_num; + session->enable_session_twt_support = + sme_join_req->enable_session_twt_support; + /* + * Store Session related parameters + */ + + /* store the smejoin req handle in session table */ + session->pLimJoinReq = sme_join_req; + + /* Store SME session Id in sessionTable */ + session->smeSessionId = sme_join_req->sessionId; + + /* Store SME transaction Id in session Table */ + session->transactionId = sme_join_req->transactionId; + + /* Store beaconInterval */ + session->beaconParams.beaconInterval = + bss_desc->beaconInterval; + + qdf_mem_copy(&(session->htConfig), &(sme_join_req->htConfig), + sizeof(session->htConfig)); + + qdf_mem_copy(&(session->vht_config), + &(sme_join_req->vht_config), + sizeof(session->vht_config)); + + /* Copying of bssId is already done, while creating session */ + sir_copy_mac_addr(session->selfMacAddr, + sme_join_req->selfMacAddr); + session->bssType = sme_join_req->bsstype; + + session->statypeForBss = STA_ENTRY_PEER; + session->limWmeEnabled = sme_join_req->isWMEenabled; + session->limQosEnabled = sme_join_req->isQosEnabled; + session->wps_registration = sme_join_req->wps_registration; + session->he_with_wep_tkip = sme_join_req->he_with_wep_tkip; + + session->enable_bcast_probe_rsp = + sme_join_req->enable_bcast_probe_rsp; + + /* Store vendor specific IE for CISCO AP */ + ie_len = (bss_desc->length + sizeof(bss_desc->length) - + GET_FIELD_OFFSET(tSirBssDescription, 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 (NULL != vendor_ie) { + pe_debug("Cisco vendor OUI present"); + session->isCiscoVendorAP = true; + } else { + session->isCiscoVendorAP = false; + } + + /* Copy the dot 11 mode in to the session table */ + + session->dot11mode = sme_join_req->dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + session->cc_switch_mode = sme_join_req->cc_switch_mode; +#endif + session->nwType = bss_desc->nwType; + session->enableAmpduPs = sme_join_req->enableAmpduPs; + session->enableHtSmps = sme_join_req->enableHtSmps; + session->htSmpsvalue = sme_join_req->htSmps; + session->send_smps_action = + sme_join_req->send_smps_action; + /* + * 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 + */ + session->supported_nss_1x1 = true; + /*Store Persona */ + session->pePersona = sme_join_req->staPersona; + pe_debug("enable Smps: %d mode: %d send action: %d supported nss 1x1: %d pePersona %d cbMode %d", + session->enableHtSmps, + session->htSmpsvalue, + session->send_smps_action, + session->supported_nss_1x1, + session->pePersona, + sme_join_req->cbMode); + + /*Store Persona */ + session->pePersona = sme_join_req->staPersona; + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("PE PERSONA=%d cbMode %u nwType: %d dot11mode: %d force_24ghz_in_ht20 %d"), + session->pePersona, sme_join_req->cbMode, + session->nwType, session->dot11mode, + sme_join_req->force_24ghz_in_ht20); + + /* Copy The channel Id to the session Table */ + session->currentOperChannel = bss_desc->channelId; + + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + if (session->vhtCapability) { + if (session->pePersona == QDF_STA_MODE) { + session->vht_config.su_beam_formee = + sme_join_req->vht_config.su_beam_formee; + } else { + session->vht_config.su_beam_formee = 0; + } + session->enableVhtpAid = + sme_join_req->enableVhtpAid; + session->enableVhtGid = + sme_join_req->enableVhtGid; + pe_debug("vht su bformer [%d]", + session->vht_config.su_beam_former); + } + + pe_debug("vhtCapability: %d su_beam_formee: %d txbf_csn_value: %d su_tx_bformer %d", + session->vhtCapability, + session->vht_config.su_beam_formee, + session->vht_config.csnof_beamformer_antSup, + session->vht_config.su_beam_former); + /*Phy mode */ + session->gLimPhyMode = bss_desc->nwType; + handle_ht_capabilityand_ht_info(mac_ctx, session); + session->force_24ghz_in_ht20 = + sme_join_req->force_24ghz_in_ht20; + /* cbMode is already merged value of peer and self - + * done by csr in csr_get_cb_mode_from_ies */ + session->htSupportedChannelWidthSet = + (sme_join_req->cbMode) ? 1 : 0; + session->htRecommendedTxWidthSet = + session->htSupportedChannelWidthSet; + session->htSecondaryChannelOffset = sme_join_req->cbMode; + + if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY == sme_join_req->cbMode) { + session->ch_center_freq_seg0 = + session->currentOperChannel - 2; + session->ch_width = CH_WIDTH_40MHZ; + } else if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY == + sme_join_req->cbMode) { + session->ch_center_freq_seg0 = + session->currentOperChannel + 2; + session->ch_width = CH_WIDTH_40MHZ; + } else { + session->ch_center_freq_seg0 = 0; + session->ch_width = CH_WIDTH_20MHZ; + } + + if (IS_DOT11_MODE_HE(session->dot11mode)) { + lim_update_session_he_capable(mac_ctx, session); + lim_copy_join_req_he_cap(session, sme_join_req); + } + + + /* Record if management frames need to be protected */ +#ifdef WLAN_FEATURE_11W + if ((eSIR_ED_AES_128_CMAC == + sme_join_req->MgmtEncryptionType) || + (eSIR_ED_AES_GMAC_128 == sme_join_req->MgmtEncryptionType) || + (eSIR_ED_AES_GMAC_256 == sme_join_req->MgmtEncryptionType)) + session->limRmfEnabled = 1; + else + session->limRmfEnabled = 0; +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + session->rssi = bss_desc->rssi; +#endif + + /* Copy the SSID from smejoinreq to session entry */ + session->ssId.length = sme_join_req->ssId.length; + qdf_mem_copy(session->ssId.ssId, sme_join_req->ssId.ssId, + session->ssId.length); + + /* + * Determin 11r or ESE connection based on input from SME + * which inturn is dependent on the profile the user wants + * to connect to, So input is coming from supplicant + */ + session->is11Rconnection = sme_join_req->is11Rconnection; +#ifdef FEATURE_WLAN_ESE + session->isESEconnection = sme_join_req->isESEconnection; +#endif + session->isFastTransitionEnabled = + sme_join_req->isFastTransitionEnabled; + + session->isFastRoamIniFeatureEnabled = + sme_join_req->isFastRoamIniFeatureEnabled; + session->txLdpcIniFeatureEnabled = + sme_join_req->txLdpcIniFeatureEnabled; + + lim_update_fils_config(session, sme_join_req); + lim_update_sae_config(session, sme_join_req); + if (session->bssType == eSIR_INFRASTRUCTURE_MODE) { + session->limSystemRole = eLIM_STA_ROLE; + } else { + /* + * Throw an error and return and make + * sure to delete the session. + */ + pe_err("recvd JOIN_REQ with invalid bss type %d", + session->bssType); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + if (sme_join_req->addIEScan.length) + qdf_mem_copy(&session->pLimJoinReq->addIEScan, + &sme_join_req->addIEScan, sizeof(tSirAddie)); + + if (sme_join_req->addIEAssoc.length) + qdf_mem_copy(&session->pLimJoinReq->addIEAssoc, + &sme_join_req->addIEAssoc, sizeof(tSirAddie)); + + val = sizeof(tLimMlmJoinReq) + + session->pLimJoinReq->bssDescription.length + 2; + mlm_join_req = qdf_mem_malloc(val); + if (NULL == mlm_join_req) { + pe_err("AllocateMemory failed for mlmJoinReq"); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + /* PE SessionId is stored as a part of JoinReq */ + mlm_join_req->sessionId = session->peSessionId; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_JOIN_FAILURE_TIMEOUT, + (uint32_t *) &mlm_join_req->joinFailureTimeout) != + QDF_STATUS_SUCCESS) { + pe_err("couldn't retrieve JoinFailureTimer value" + " setting to default value"); + mlm_join_req->joinFailureTimeout = + WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF; + } + + /* copy operational rate from session */ + qdf_mem_copy((void *)&session->rateSet, + (void *)&sme_join_req->operationalRateSet, + sizeof(tSirMacRateSet)); + qdf_mem_copy((void *)&session->extRateSet, + (void *)&sme_join_req->extendedRateSet, + sizeof(tSirMacRateSet)); + /* + * 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_join_req->operationalRateSet, + (void *)&session->rateSet, + sizeof(tSirMacRateSet)); + + session->encryptType = sme_join_req->UCEncryptionType; + + session->supported_nss_1x1 = sme_join_req->supported_nss_1x1; + session->vdev_nss = sme_join_req->vdev_nss; + session->nss = sme_join_req->nss; + session->nss_forced_1x1 = sme_join_req->nss_forced_1x1; + + pe_debug("nss %d, vdev_nss %d, supported_nss_1x1 %d", + session->nss, + session->vdev_nss, + session->supported_nss_1x1); + + mlm_join_req->bssDescription.length = + session->pLimJoinReq->bssDescription.length; + + qdf_mem_copy((uint8_t *) &mlm_join_req->bssDescription.bssId, + (uint8_t *) + &session->pLimJoinReq->bssDescription.bssId, + session->pLimJoinReq->bssDescription.length + 2); + + session->limCurrentBssCaps = + session->pLimJoinReq->bssDescription.capabilityInfo; + + reg_max = cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + local_power_constraint = reg_max; + + lim_extract_ap_capability(mac_ctx, + (uint8_t *) + session->pLimJoinReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description( + &session->pLimJoinReq->bssDescription), + &session->limCurrentBssQosCaps, + &session->limCurrentBssPropCap, + &session->gLimCurrentBssUapsd, + &local_power_constraint, session); + + tx_pwr_attr.reg_max = reg_max; + tx_pwr_attr.ap_tx_power = local_power_constraint; + tx_pwr_attr.ini_tx_power = + mac_ctx->roam.configParam.nTxPowerCap; + tx_pwr_attr.frequency = + wlan_reg_get_channel_freq(mac_ctx->pdev, + session->currentOperChannel); + + session->maxTxPower = lim_get_max_tx_power(mac_ctx, + &tx_pwr_attr); + session->def_max_tx_pwr = session->maxTxPower; + + pe_debug("Reg max %d local power con %d max tx pwr %d", + reg_max, local_power_constraint, session->maxTxPower); + + if (sme_join_req->powerCap.maxTxPower > session->maxTxPower) { + sme_join_req->powerCap.maxTxPower = session->maxTxPower; + pe_debug("Update MaxTxPower in join Req to %d", + sme_join_req->powerCap.maxTxPower); + } + + if (session->gLimCurrentBssUapsd) { + session->gUapsdPerAcBitmask = + session->pLimJoinReq->uapsdPerAcBitmask; + pe_debug("UAPSD flag for all AC - 0x%2x", + session->gUapsdPerAcBitmask); + + /* resetting the dynamic uapsd mask */ + session->gUapsdPerAcDeliveryEnableMask = 0; + session->gUapsdPerAcTriggerEnableMask = 0; + } + + session->limRFBand = + lim_get_rf_band(session->currentOperChannel); + + /* Initialize 11h Enable Flag */ + if (BAND_5G == session->limRFBand) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, + &val) != QDF_STATUS_SUCCESS) { + pe_err("Fail to get WNI_CFG_11H_ENABLED"); + session->lim11hEnable = + WNI_CFG_11H_ENABLED_STADEF; + } else { + session->lim11hEnable = val; + } + } else { + session->lim11hEnable = 0; + } + + /* + * To care of the scenario when STA transitions from + * IBSS to Infrastructure mode. + */ + mac_ctx->lim.gLimIbssCoalescingHappened = false; + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_JOIN_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + /* Indicate whether spectrum management is enabled */ + session->spectrumMgtEnabled = + sme_join_req->spectrumMgtIndicator; + + /* Enable the spectrum management if this is a DFS channel */ + if (session->country_info_present && + lim_isconnected_on_dfs_channel(mac_ctx, + session->currentOperChannel)) + session->spectrumMgtEnabled = true; + + session->isOSENConnection = sme_join_req->isOSENConnection; + + /* Issue LIM_MLM_JOIN_REQ to MLM */ + lim_post_mlm_message(mac_ctx, LIM_MLM_JOIN_REQ, + (uint32_t *) mlm_join_req); + return; + + } else { + /* Received eWNI_SME_JOIN_REQ un expected state */ + pe_err("received unexpected SME_JOIN_REQ in state %X", + mac_ctx->lim.gLimSmeState); + lim_print_sme_state(mac_ctx, LOGE, mac_ctx->lim.gLimSmeState); + ret_code = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + session = NULL; + goto end; + } + +end: + lim_get_session_info(mac_ctx, (uint8_t *) msg_buf, + &sme_session_id, &sme_transaction_id); + + if (sme_join_req) { + qdf_mem_free(sme_join_req); + sme_join_req = NULL; + if (NULL != session) + session->pLimJoinReq = NULL; + } + if (ret_code != eSIR_SME_SUCCESS) { + if (NULL != session) { + pe_delete_session(mac_ctx, session); + session = NULL; + } + } + pe_debug("Send failure status on sessionid: %d with ret_code: %d", + sme_session_id, ret_code); + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_JOIN_RSP, ret_code, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session, sme_session_id, + sme_transaction_id); +} + +uint8_t lim_get_max_tx_power(tpAniSirGlobal mac, + struct lim_max_tx_pwr_attr *attr) +{ + uint8_t max_tx_power = 0; + uint8_t tx_power; + + if (!attr) + return 0; + + if (wlan_reg_get_fcc_constraint(mac->pdev, attr->frequency)) + return attr->reg_max; + + tx_power = QDF_MIN(attr->reg_max, attr->ap_tx_power); + tx_power = QDF_MIN(tx_power, attr->ini_tx_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; +} + +/** + * __lim_process_sme_reassoc_req() - process reassoc req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_REASSOC_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_reassoc_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + uint16_t caps; + uint32_t val; + tpSirSmeJoinReq reassoc_req = NULL; + tLimMlmReassocReq *mlm_reassoc_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + tpPESession session_entry = NULL; + uint8_t session_id; + uint8_t sme_session_id; + uint16_t transaction_id; + int8_t local_pwr_constraint = 0, reg_max = 0; + uint32_t tele_bcn_en = 0; + uint16_t size; + + size = __lim_get_sme_join_req_size_for_alloc((uint8_t *)msg_buf); + reassoc_req = qdf_mem_malloc(size); + if (NULL == reassoc_req) { + pe_err("call to AllocateMemory failed for reassoc_req"); + + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + (void)qdf_mem_copy((void *)reassoc_req, (void *)msg_buf, size); + + if (!lim_is_sme_join_req_valid(mac_ctx, + (tpSirSmeJoinReq)reassoc_req)) { + /* + * Received invalid eWNI_SME_REASSOC_REQ + */ + pe_warn("received SME_REASSOC_REQ with invalid data"); + + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + reassoc_req->bssDescription.bssId, + &session_id); + if (session_entry == NULL) { + pe_err("Session does not exist for given bssId"); + lim_print_mac_addr(mac_ctx, reassoc_req->bssDescription.bssId, + LOGE); + ret_code = eSIR_SME_INVALID_PARAMETERS; + lim_get_session_info(mac_ctx, (uint8_t *)msg_buf, + &sme_session_id, &transaction_id); + session_entry = + pe_find_session_by_sme_session_id(mac_ctx, + sme_session_id); + if (session_entry != NULL) + lim_handle_sme_join_result(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry); + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_REQ_EVENT, + session_entry, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + /* mac_ctx->lim.gpLimReassocReq = reassoc_req;//TO SUPPORT BT-AMP */ + + /* Store the reassoc handle in the session Table */ + session_entry->pLimReAssocReq = reassoc_req; + + session_entry->dot11mode = reassoc_req->dot11mode; + session_entry->vhtCapability = + IS_DOT11_MODE_VHT(reassoc_req->dot11mode); + + if (session_entry->vhtCapability) { + if (session_entry->pePersona == QDF_STA_MODE) { + session_entry->vht_config.su_beam_formee = + reassoc_req->vht_config.su_beam_formee; + } else { + reassoc_req->vht_config.su_beam_formee = 0; + } + session_entry->enableVhtpAid = + reassoc_req->enableVhtpAid; + session_entry->enableVhtGid = + reassoc_req->enableVhtGid; + pe_debug("vht su bformer [%d]", session_entry->vht_config.su_beam_former); + } + + session_entry->supported_nss_1x1 = reassoc_req->supported_nss_1x1; + session_entry->vdev_nss = reassoc_req->vdev_nss; + session_entry->nss = reassoc_req->nss; + session_entry->nss_forced_1x1 = reassoc_req->nss_forced_1x1; + + pe_debug("vhtCapability: %d su_beam_formee: %d su_tx_bformer %d", + session_entry->vhtCapability, + session_entry->vht_config.su_beam_formee, + session_entry->vht_config.su_beam_former); + + session_entry->enableHtSmps = reassoc_req->enableHtSmps; + session_entry->htSmpsvalue = reassoc_req->htSmps; + session_entry->send_smps_action = + reassoc_req->send_smps_action; + pe_debug("enableHtSmps: %d htSmps: %d send action: %d supported nss 1x1: %d", + session_entry->enableHtSmps, + session_entry->htSmpsvalue, + session_entry->send_smps_action, + session_entry->supported_nss_1x1); + /* + * 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(reassoc_req->bssDescription.bssId, + session_entry->limReAssocbssId, + 6)) { + lim_print_mac_addr(mac_ctx, + reassoc_req->bssDescription. + bssId, LOGE); + pe_err("Unknown bssId in reassoc state"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + lim_process_mlm_ft_reassoc_req(mac_ctx, msg_buf, + session_entry); + 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, + session_entry->pLimReAssocReq->bssDescription.bssId, + sizeof(tSirMacAddr)); + + session_entry->limReassocChannelId = + session_entry->pLimReAssocReq->bssDescription.channelId; + + session_entry->reAssocHtSupportedChannelWidthSet = + (session_entry->pLimReAssocReq->cbMode) ? 1 : 0; + session_entry->reAssocHtRecommendedTxWidthSet = + session_entry->reAssocHtSupportedChannelWidthSet; + session_entry->reAssocHtSecondaryChannelOffset = + session_entry->pLimReAssocReq->cbMode; + + session_entry->limReassocBssCaps = + session_entry->pLimReAssocReq->bssDescription.capabilityInfo; + reg_max = cfg_get_regulatory_max_transmit_power(mac_ctx, + session_entry->currentOperChannel); + local_pwr_constraint = reg_max; + + lim_extract_ap_capability(mac_ctx, + (uint8_t *)session_entry->pLimReAssocReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description( + &session_entry->pLimReAssocReq->bssDescription), + &session_entry->limReassocBssQosCaps, + &session_entry->limReassocBssPropCap, + &session_entry->gLimCurrentBssUapsd, + &local_pwr_constraint, session_entry); + session_entry->maxTxPower = QDF_MIN(reg_max, (local_pwr_constraint)); + pe_err("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 = reassoc_req->ssId.length; + qdf_mem_copy(session_entry->limReassocSSID.ssId, + reassoc_req->ssId.ssId, + session_entry->limReassocSSID.length); + if (session_entry->gLimCurrentBssUapsd) { + session_entry->gUapsdPerAcBitmask = + session_entry->pLimReAssocReq->uapsdPerAcBitmask; + pe_debug("UAPSD flag for all AC - 0x%2x", + session_entry->gUapsdPerAcBitmask); + } + + mlm_reassoc_req = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == mlm_reassoc_req) { + pe_err("call to AllocateMemory failed for mlmReassocReq"); + + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + qdf_mem_copy(mlm_reassoc_req->peerMacAddr, + session_entry->limReAssocbssId, sizeof(tSirMacAddr)); + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *)&mlm_reassoc_req->reassocFailureTimeout) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve ReassocFailureTimeout value"); + + if (cfg_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, + reassoc_req->bssDescription.capabilityInfo); + 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 + * WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_WAKEUP_EN, + &tele_bcn_en) != QDF_STATUS_SUCCESS) + pe_err("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN"); + + val = WNI_CFG_LISTEN_INTERVAL_STADEF; + + if (tele_bcn_en) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_MAX_LI, &val) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve ListenInterval"); + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, &val) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve ListenInterval"); + } + + mlm_reassoc_req->listenInterval = (uint16_t) val; + + /* Indicate whether spectrum management is enabled */ + session_entry->spectrumMgtEnabled = reassoc_req->spectrumMgtIndicator; + + /* Enable the spectrum management if this is a DFS channel */ + if (session_entry->country_info_present && + lim_isconnected_on_dfs_channel(mac_ctx, + session_entry->currentOperChannel)) + 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_post_mlm_message(mac_ctx, + LIM_MLM_REASSOC_REQ, (uint32_t *)mlm_reassoc_req); + return; +end: + if (reassoc_req) { + qdf_mem_free(reassoc_req); + if (session_entry) + session_entry->pLimReAssocReq = NULL; + } + + if (session_entry) { + /* + * error occurred after we determined the session so extract + * session and transaction info from there + */ + sme_session_id = session_entry->smeSessionId; + transaction_id = session_entry->transactionId; + } else { + /* + * error occurred before or during the time we determined + * the session so extract the session and transaction info + * from the message + */ + lim_get_session_info(mac_ctx, (uint8_t *) msg_buf, + &sme_session_id, &transaction_id); + } + /* + * 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, eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry, sme_session_id, + transaction_id); +} + +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 pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ + +static void __lim_process_sme_disassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint16_t disassocTrigger, reasonCode; + tLimMlmDisassocReq *pMlmDisassocReq; + tSirResultCodes retCode = eSIR_SME_SUCCESS; + tSirSmeDisassocReq smeDisassocReq; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + uint8_t smesessionId; + uint16_t smetransactionId; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + qdf_mem_copy(&smeDisassocReq, pMsgBuf, sizeof(tSirSmeDisassocReq)); + smesessionId = smeDisassocReq.sessionId; + smetransactionId = smeDisassocReq.transactionId; + if (!lim_is_sme_disassoc_req_valid(pMac, + &smeDisassocReq, + psessionEntry)) { + pe_err("received invalid SME_DISASSOC_REQ message"); + if (pMac->lim.gLimRspReqd) { + pMac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + psessionEntry = pe_find_session_by_bssid(pMac, + smeDisassocReq.bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given bssId " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(smeDisassocReq.bssid.bytes)); + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + pe_debug("received DISASSOC_REQ message on sessionid %d Systemrole %d Reason: %u SmeState: %d from: " + MAC_ADDRESS_STR, smesessionId, + GET_LIM_SYSTEM_ROLE(psessionEntry), smeDisassocReq.reasonCode, + pMac->lim.gLimSmeState, + MAC_ADDR_ARRAY(smeDisassocReq.peer_macaddr.bytes)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_REQ_EVENT, psessionEntry, + 0, smeDisassocReq.reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* Update SME session Id and SME transaction ID */ + + psessionEntry->smeSessionId = smesessionId; + psessionEntry->transactionId = smetransactionId; + pe_debug("ho_fail: %d ", smeDisassocReq.process_ho_fail); + psessionEntry->process_ho_fail = smeDisassocReq.process_ho_fail; + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + switch (psessionEntry->limSmeState) { + case eLIM_SME_ASSOCIATED_STATE: + case eLIM_SME_LINK_EST_STATE: + pe_debug("Rcvd SME_DISASSOC_REQ in limSmeState: %d ", + psessionEntry->limSmeState); + psessionEntry->limPrevSmeState = + psessionEntry->limSmeState; + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(pMac, psessionEntry); + MTRACE(mac_trace(pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->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. pMac->lim.gLimPrevSmeState shall remain the same as + * its been set when PE entered WT_DEAUTH_STATE. + */ + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + pe_debug("Rcvd SME_DISASSOC_REQ while in SME_WT_DEAUTH_STATE"); + 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. + */ + pe_debug("Rcvd SME_DISASSOC_REQ while in SME_WT_DISASSOC_STATE"); + break; + + case eLIM_SME_JOIN_FAILURE_STATE: { + /* Already in Disconnected State, return success */ + pe_debug("Rcvd SME_DISASSOC_REQ while in eLIM_SME_JOIN_FAILURE_STATE"); + if (pMac->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", + psessionEntry->limSmeState); + lim_print_sme_state(pMac, LOGE, + psessionEntry->limSmeState); + + if (pMac->lim.gLimRspReqd) { + if (psessionEntry->limSmeState != + eLIM_SME_WT_ASSOC_STATE) + pMac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + break; + + case eLIM_AP_ROLE: + /* Fall through */ + break; + + case eLIM_STA_IN_IBSS_ROLE: + default: + /* eLIM_UNKNOWN_ROLE */ + pe_err("received unexpected SME_DISASSOC_REQ for role %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } /* end switch (pMac->lim.gLimSystemRole) */ + + disassocTrigger = eLIM_HOST_DISASSOC; + reasonCode = smeDisassocReq.reasonCode; + + if (smeDisassocReq.doNotSendOverTheAir) { + pe_debug("do not send dissoc over the air"); + send_disassoc_frame = 0; + } + /* Trigger Disassociation frame to peer MAC entity */ + pe_debug("Sending Disasscoc with disassoc Trigger" + " : %d, reasonCode : %d", + disassocTrigger, reasonCode); + + pMlmDisassocReq = qdf_mem_malloc(sizeof(tLimMlmDisassocReq)); + if (NULL == pMlmDisassocReq) { + pe_err("call to AllocateMemory failed for mlmDisassocReq"); + 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(pMac, + LIM_MLM_DISASSOC_REQ, (uint32_t *) pMlmDisassocReq); + return; + +sendDisassoc: + if (psessionEntry) + lim_send_sme_disassoc_ntf(pMac, + smeDisassocReq.peer_macaddr.bytes, + retCode, + disassocTrigger, + 1, smesessionId, smetransactionId, + psessionEntry); + else + lim_send_sme_disassoc_ntf(pMac, + smeDisassocReq.peer_macaddr.bytes, + retCode, disassocTrigger, 1, + smesessionId, smetransactionId, 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 pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +static void __lim_process_sme_disassoc_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirSmeDisassocCnf smeDisassocCnf; + uint16_t aid; + tpDphHashNode pStaDs; + tpPESession psessionEntry; + uint8_t sessionId; + uint32_t *msg = NULL; + QDF_STATUS status; + + qdf_mem_copy(&smeDisassocCnf, pMsgBuf, + sizeof(struct sSirSmeDisassocCnf)); + + psessionEntry = pe_find_session_by_bssid(pMac, + smeDisassocCnf.bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given bssId"); + status = lim_prepare_disconnect_done_ind(pMac, &msg, + smeDisassocCnf.sme_session_id, + eSIR_SME_INVALID_SESSION, + NULL); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(pMac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + if (!lim_is_sme_disassoc_cnf_valid(pMac, &smeDisassocCnf, psessionEntry)) { + pe_err("received invalid SME_DISASSOC_CNF message"); + status = lim_prepare_disconnect_done_ind(pMac, &msg, + psessionEntry->smeSessionId, + eSIR_SME_INVALID_PARAMETERS, + &smeDisassocCnf.bssid.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(pMac, + 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(pMac, WLAN_PE_DIAG_DISASSOC_CNF_EVENT, + psessionEntry, + (uint16_t) smeDisassocCnf.statusCode, 0); + else if (smeDisassocCnf.messageType == eWNI_SME_DEAUTH_CNF) + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_CNF_EVENT, + psessionEntry, + (uint16_t) smeDisassocCnf.statusCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + if ((psessionEntry->limSmeState != eLIM_SME_IDLE_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && (psessionEntry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE)) { + pe_err("received unexp SME_DISASSOC_CNF in state %X", + psessionEntry->limSmeState); + lim_print_sme_state(pMac, LOGE, + psessionEntry->limSmeState); + status = lim_prepare_disconnect_done_ind(pMac, &msg, + psessionEntry->smeSessionId, + eSIR_SME_INVALID_STATE, + &smeDisassocCnf.bssid.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(pMac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + break; + + case eLIM_AP_ROLE: + /* Fall through */ + break; + + case eLIM_STA_IN_IBSS_ROLE: + default: /* eLIM_UNKNOWN_ROLE */ + pe_err("received unexpected SME_DISASSOC_CNF role %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + status = lim_prepare_disconnect_done_ind(pMac, &msg, + psessionEntry->smeSessionId, + eSIR_SME_INVALID_STATE, + &smeDisassocCnf.bssid.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(pMac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + if ((psessionEntry->limSmeState == eLIM_SME_WT_DISASSOC_STATE) || + (psessionEntry->limSmeState == eLIM_SME_WT_DEAUTH_STATE) || + LIM_IS_AP_ROLE(psessionEntry)) { + pStaDs = dph_lookup_hash_entry(pMac, + smeDisassocCnf.peer_macaddr.bytes, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + pe_err("DISASSOC_CNF for a STA with no context, addr= " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(smeDisassocCnf.peer_macaddr.bytes)); + status = lim_prepare_disconnect_done_ind(pMac, &msg, + psessionEntry->smeSessionId, + eSIR_SME_INVALID_PARAMETERS, + &smeDisassocCnf.bssid.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(pMac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + if ((pStaDs->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_BSS_RSP_STATE)) { + pe_err("No need of cleanup for addr:" MAC_ADDRESS_STR "as MLM state is %d", + MAC_ADDR_ARRAY(smeDisassocCnf.peer_macaddr.bytes), + pStaDs->mlmStaContext.mlmState); + status = lim_prepare_disconnect_done_ind(pMac, &msg, + psessionEntry->smeSessionId, + eSIR_SME_SUCCESS, + NULL); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(pMac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + /* Delete FT session if there exists one */ + lim_ft_cleanup_pre_auth_info(pMac, psessionEntry); + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + + lim_clean_up_disassoc_deauth_req(pMac, + (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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + uint16_t deauth_trigger, reason_code; + tLimMlmDeauthReq *mlm_deauth_req; + tSirSmeDeauthReq sme_deauth_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + tpPESession session_entry; + uint8_t session_id; /* PE sessionId */ + uint8_t sme_session_id; + uint16_t sme_transaction_id; + + qdf_mem_copy(&sme_deauth_req, msg_buf, sizeof(tSirSmeDeauthReq)); + sme_session_id = sme_deauth_req.sessionId; + sme_transaction_id = sme_deauth_req.transactionId; + + /* + * 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(mac_ctx, + sme_deauth_req.bssid.bytes, + &session_id); + if (session_entry == NULL) { + pe_err("session does not exist for given bssId"); + 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("received DEAUTH_REQ sessionid %d Systemrole %d reasoncode %u limSmestate %d from " + MAC_ADDRESS_STR, sme_session_id, + GET_LIM_SYSTEM_ROLE(session_entry), sme_deauth_req.reasonCode, + session_entry->limSmeState, + MAC_ADDR_ARRAY(sme_deauth_req.peer_macaddr.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 */ + + /* Update SME session ID and Transaction ID */ + session_entry->smeSessionId = sme_session_id; + session_entry->transactionId = sme_transaction_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; + pe_debug("Rcvd SME_DEAUTH_REQ while in 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_STA_IN_IBSS_ROLE: + pe_err("Deauth not allowed in IBSS"); + 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; + case eLIM_AP_ROLE: + 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) { + /* Deauthentication is triggered by Link Monitoring */ + pe_debug("** Lost link with AP **"); + deauth_trigger = eLIM_LINK_MONITORING_DEAUTH; + reason_code = eSIR_MAC_UNSPEC_FAILURE_REASON; + } 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 (NULL == mlm_deauth_req) { + pe_err("call to AllocateMemory failed for mlmDeauthReq"); + 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_post_mlm_message(mac_ctx, LIM_MLM_DEAUTH_REQ, + (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, + sme_session_id, sme_transaction_id); +} + +/** + * __lim_process_sme_set_context_req() + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_SETCONTEXT_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void +__lim_process_sme_set_context_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpSirSmeSetContextReq set_context_req; + tLimMlmSetKeysReq *mlm_set_key_req; + tpPESession session_entry; + uint8_t session_id; /* PE sessionID */ + uint8_t sme_session_id; + uint16_t sme_transaction_id; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + set_context_req = qdf_mem_malloc(sizeof(struct sSirSmeSetContextReq)); + if (NULL == set_context_req) { + pe_err("call to AllocateMemory failed for set_context_req"); + return; + } + qdf_mem_copy(set_context_req, msg_buf, + sizeof(struct sSirSmeSetContextReq)); + qdf_mem_zero(msg_buf, sizeof(struct sSirSmeSetContextReq)); + sme_session_id = set_context_req->sessionId; + sme_transaction_id = set_context_req->transactionId; + + if ((!lim_is_sme_set_context_req_valid(mac_ctx, set_context_req))) { + pe_warn("received invalid SME_SETCONTEXT_REQ message"); + goto end; + } + + if (set_context_req->keyMaterial.numKeys > + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + pe_err("numKeys:%d is more than SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS", + set_context_req->keyMaterial.numKeys); + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peer_macaddr, 1, + eSIR_SME_INVALID_PARAMETERS, NULL, + sme_session_id, sme_transaction_id); + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + set_context_req->bssid.bytes, &session_id); + if (session_entry == NULL) { + pe_err("Session does not exist for given BSSID"); + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peer_macaddr, 1, + eSIR_SME_INVALID_PARAMETERS, NULL, + sme_session_id, sme_transaction_id); + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_SETCONTEXT_REQ_EVENT, + session_entry, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if ((LIM_IS_STA_ROLE(session_entry) && + (session_entry->limSmeState == eLIM_SME_LINK_EST_STATE)) || + ((LIM_IS_IBSS_ROLE(session_entry) || + LIM_IS_AP_ROLE(session_entry)) && + (session_entry->limSmeState == eLIM_SME_NORMAL_STATE))) { + /* Trigger MLM_SETKEYS_REQ */ + mlm_set_key_req = qdf_mem_malloc(sizeof(tLimMlmSetKeysReq)); + if (NULL == mlm_set_key_req) { + pe_err("mem alloc failed for mlmSetKeysReq"); + goto end; + } + mlm_set_key_req->edType = set_context_req->keyMaterial.edType; + mlm_set_key_req->numKeys = + set_context_req->keyMaterial.numKeys; + if (mlm_set_key_req->numKeys > + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + pe_err("no.of keys exceeded max num of default keys limit"); + qdf_mem_free(mlm_set_key_req); + goto end; + } + qdf_copy_macaddr(&mlm_set_key_req->peer_macaddr, + &set_context_req->peer_macaddr); + + qdf_mem_copy((uint8_t *) &mlm_set_key_req->key, + (uint8_t *) &set_context_req->keyMaterial.key, + sizeof(tSirKeys) * + (mlm_set_key_req->numKeys ? mlm_set_key_req-> + numKeys : 1)); + + mlm_set_key_req->sessionId = session_id; + mlm_set_key_req->smesessionId = sme_session_id; + pe_debug("received SETCONTEXT_REQ message sessionId=%d", + mlm_set_key_req->sessionId); + + if (((set_context_req->keyMaterial.edType == eSIR_ED_WEP40) || + (set_context_req->keyMaterial.edType == eSIR_ED_WEP104)) && + LIM_IS_AP_ROLE(session_entry)) { + if (set_context_req->keyMaterial.key[0].keyLength) { + uint8_t key_id; + + key_id = + set_context_req->keyMaterial.key[0].keyId; + qdf_mem_copy((uint8_t *) + &session_entry->WEPKeyMaterial[key_id], + (uint8_t *) &set_context_req->keyMaterial, + sizeof(tSirKeyMaterial)); + } else { + uint32_t i; + + for (i = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + i++) { + qdf_mem_copy((uint8_t *) + &mlm_set_key_req->key[i], + (uint8_t *)session_entry->WEPKeyMaterial[i].key, + sizeof(tSirKeys)); + } + } + } + lim_post_mlm_message(mac_ctx, LIM_MLM_SETKEYS_REQ, + (uint32_t *) mlm_set_key_req); + } else { + pe_err("rcvd unexpected SME_SETCONTEXT_REQ for role %d, state=%X", + GET_LIM_SYSTEM_ROLE(session_entry), + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, session_entry->limSmeState); + + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peer_macaddr, 1, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, + session_entry, sme_session_id, + sme_transaction_id); + } +end: + qdf_mem_zero(set_context_req, sizeof(struct sSirSmeSetContextReq)); + qdf_mem_free(set_context_req); + return; +} + +/** + * lim_process_sme_get_assoc_sta_info() - process sme assoc sta req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_GET_ASSOC_STAS_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void lim_process_sme_get_assoc_sta_info(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tSirSmeGetAssocSTAsReq get_assoc_stas_req; + tpDphHashNode sta_ds = NULL; + tpPESession session_entry = NULL; + tSap_Event sap_event; + tpWLAN_SAPEventCB sap_event_cb = NULL; + tpSap_AssocMacAddr assoc_sta_tmp = NULL; + uint8_t session_id = CSR_SESSION_ID_INVALID; + uint8_t assoc_id = 0; + uint8_t sta_cnt = 0; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + qdf_mem_copy(&get_assoc_stas_req, msg_buf, + sizeof(struct sSirSmeGetAssocSTAsReq)); + /* + * Get Associated stations from PE. + * Find PE session Entry + */ + session_entry = pe_find_session_by_bssid(mac_ctx, + get_assoc_stas_req.bssid.bytes, + &session_id); + if (session_entry == NULL) { + pe_err("session does not exist for given bssId"); + goto lim_assoc_sta_end; + } + + if (!LIM_IS_AP_ROLE(session_entry)) { + pe_err("Received unexpected message in state %X, in role %X", + session_entry->limSmeState, + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_assoc_sta_end; + } + /* Retrieve values obtained in the request message */ + sap_event_cb = (tpWLAN_SAPEventCB)get_assoc_stas_req.pSapEventCallback; + assoc_sta_tmp = (tpSap_AssocMacAddr)get_assoc_stas_req.pAssocStasArray; + + if (NULL == assoc_sta_tmp) + goto lim_assoc_sta_end; + for (assoc_id = 0; assoc_id < session_entry->dph.dphHashTable.size; + assoc_id++) { + sta_ds = dph_get_hash_entry(mac_ctx, assoc_id, + &session_entry->dph.dphHashTable); + if (NULL == sta_ds) + continue; + if (sta_ds->valid) { + qdf_mem_copy((uint8_t *) &assoc_sta_tmp->staMac, + (uint8_t *) &sta_ds->staAddr, + QDF_MAC_ADDR_SIZE); + assoc_sta_tmp->assocId = (uint8_t) sta_ds->assocId; + assoc_sta_tmp->staId = (uint8_t) sta_ds->staIndex; + + qdf_mem_copy((uint8_t *)&assoc_sta_tmp->supportedRates, + (uint8_t *)&sta_ds->supportedRates, + sizeof(tSirSupportedRates)); + assoc_sta_tmp->ShortGI40Mhz = sta_ds->htShortGI40Mhz; + assoc_sta_tmp->ShortGI20Mhz = sta_ds->htShortGI20Mhz; + assoc_sta_tmp->Support40Mhz = + sta_ds->htDsssCckRate40MHzSupport; + + pe_debug("dph Station Number = %d", + sta_cnt + 1); + pe_debug("MAC = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(sta_ds->staAddr)); + pe_debug("Association Id: %d Station Index: %d", + sta_ds->assocId, sta_ds->staIndex); + assoc_sta_tmp++; + sta_cnt++; + } + } +lim_assoc_sta_end: + /* + * Call hdd callback with sap event to send the list of + * associated stations from PE + */ + if (sap_event_cb != NULL) { + sap_event.sapHddEventCode = eSAP_ASSOC_STA_CALLBACK_EVENT; + sap_event.sapevt.sapAssocStaListEvent.module = + QDF_MODULE_ID_PE; + sap_event.sapevt.sapAssocStaListEvent.noOfAssocSta = sta_cnt; + sap_event.sapevt.sapAssocStaListEvent.pAssocStas = + (tpSap_AssocMacAddr)get_assoc_stas_req.pAssocStasArray; + sap_event_cb(&sap_event, get_assoc_stas_req.pUsrContext); + } +} + +/** + * __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 pMac Pointer to Global MAC structure + * @return None + */ + +static void __lim_counter_measures(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMacAddr mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_send_disassoc_mgmt_frame(pMac, eSIR_MAC_MIC_FAILURE_REASON, + mac, psessionEntry, false); +}; + +static void +__lim_handle_sme_stop_bss_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirSmeStopBssReq stopBssReq; + QDF_STATUS status; + tLimSmeStates prevState; + tpPESession psessionEntry; + uint8_t smesessionId; + uint8_t sessionId; + uint16_t smetransactionId; + uint8_t i = 0; + tpDphHashNode pStaDs = NULL; + + qdf_mem_copy(&stopBssReq, pMsgBuf, sizeof(tSirSmeStopBssReq)); + smesessionId = stopBssReq.sessionId; + smetransactionId = stopBssReq.transactionId; + + if (!lim_is_sme_stop_bss_req_valid(pMsgBuf)) { + pe_warn("received invalid SME_STOP_BSS_REQ message"); + /* Send Stop BSS response to host */ + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_INVALID_PARAMETERS, smesessionId, + smetransactionId); + return; + } + + psessionEntry = pe_find_session_by_bssid(pMac, + stopBssReq.bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given BSSID"); + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_INVALID_PARAMETERS, smesessionId, + smetransactionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_STOP_BSS_REQ_EVENT, psessionEntry, + 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE || /* Added For BT -AMP Support */ + LIM_IS_STA_ROLE(psessionEntry)) { + /** + * 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", + psessionEntry->limSmeState, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + lim_print_sme_state(pMac, LOGE, psessionEntry->limSmeState); + /* / Send Stop BSS response to host */ + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, smesessionId, + smetransactionId); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_wpspbc_close(pMac, psessionEntry); + + pe_debug("RECEIVED STOP_BSS_REQ with reason code=%d", + stopBssReq.reasonCode); + + prevState = psessionEntry->limSmeState; + + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + /* Update SME session Id and Transaction Id */ + psessionEntry->smeSessionId = smesessionId; + psessionEntry->transactionId = smetransactionId; + + /* STA_IN_IBSS and NDI should NOT send Disassoc frame */ + if (!LIM_IS_IBSS_ROLE(psessionEntry) && + !LIM_IS_NDI_ROLE(psessionEntry)) { + tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + if (stopBssReq.reasonCode == eSIR_SME_MIC_COUNTER_MEASURES) + /* Send disassoc all stations associated thru TKIP */ + __lim_counter_measures(pMac, psessionEntry); + else + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + bcAddr, psessionEntry, false); + } + + if (!LIM_IS_NDI_ROLE(psessionEntry)) { + /* Free the buffer allocated in START_BSS_REQ */ + qdf_mem_free(psessionEntry->addIeParams.probeRespData_buff); + psessionEntry->addIeParams.probeRespDataLen = 0; + psessionEntry->addIeParams.probeRespData_buff = NULL; + + qdf_mem_free(psessionEntry->addIeParams.assocRespData_buff); + psessionEntry->addIeParams.assocRespDataLen = 0; + psessionEntry->addIeParams.assocRespData_buff = NULL; + + qdf_mem_free(psessionEntry->addIeParams.probeRespBCNData_buff); + psessionEntry->addIeParams.probeRespBCNDataLen = 0; + psessionEntry->addIeParams.probeRespBCNData_buff = NULL; + + /* + * lim_del_bss is also called as part of coalescing, + * when we send DEL BSS followed by Add Bss msg. + */ + pMac->lim.gLimIbssCoalescingHappened = false; + } + for (i = 1; i < psessionEntry->dph.dphHashTable.size; i++) { + pStaDs = + dph_get_hash_entry(pMac, i, &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) + continue; + status = lim_del_sta(pMac, pStaDs, false, psessionEntry); + if (QDF_STATUS_SUCCESS == status) { + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); + } else { + pe_err("lim_del_sta failed with Status: %d", status); + QDF_ASSERT(0); + } + } + /* send a delBss to HAL and wait for a response */ + status = lim_del_bss(pMac, NULL, psessionEntry->bssIdx, psessionEntry); + + if (status != QDF_STATUS_SUCCESS) { + pe_err("delBss failed for bss %d", psessionEntry->bssIdx); + psessionEntry->limSmeState = prevState; + + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_STOP_BSS_FAILURE, smesessionId, + smetransactionId); + } +} + +/** + * __lim_process_sme_stop_bss_req() - Process STOP_BSS from SME + * @pMac: Global MAC context + * @pMsg: Message from SME + * + * Wrapper for the function __lim_handle_sme_stop_bss_request + * This message will be defered 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 defered the message. + */ + +static bool __lim_process_sme_stop_bss_req(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + if (__lim_is_defered_msg_for_learn(pMac, pMsg)) { + /** + * If message defered, buffer is not consumed yet. + * So return false + */ + return false; + } + __lim_handle_sme_stop_bss_request(pMac, (uint32_t *) pMsg->bodyptr); + return true; +} /*** end __lim_process_sme_stop_bss_req() ***/ + +void lim_process_sme_del_bss_rsp(tpAniSirGlobal pMac, + uint32_t body, tpPESession psessionEntry) +{ + + (void)body; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_ibss_delete(pMac, psessionEntry); + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, eSIR_SME_SUCCESS, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + 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(tpAniSirGlobal mac_ctx, uint32_t msg_type, + uint32_t *msg_buf) +{ + tSirSmeAssocCnf assoc_cnf; + tpDphHashNode sta_ds = NULL; + tpPESession session_entry = NULL; + uint8_t session_id; + tpSirAssocReq assoc_req; + + if (msg_buf == NULL) { + pe_err("msg_buf is NULL"); + goto end; + } + + qdf_mem_copy(&assoc_cnf, msg_buf, sizeof(struct sSirSmeAssocCnf)); + 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 == NULL) { + 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) && + (session_entry->limSmeState != + eLIM_SME_NORMAL_CHANNEL_SCAN_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 == NULL) { + pe_err("Rcvd invalid msg %X due to no STA ctx, aid %d, peer", + msg_type, assoc_cnf.aid); + lim_print_mac_addr(mac_ctx, assoc_cnf.peer_macaddr.bytes, LOGE); + + /* + * 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, + eSIR_SME_STA_NOT_ASSOCIATED, + eLIM_PEER_ENTITY_DISASSOC, assoc_cnf.aid, + session_entry->smeSessionId, + session_entry->transactionId, + 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 ", + assoc_cnf.aid); + lim_print_mac_addr(mac_ctx, assoc_cnf.peer_macaddr.bytes, LOGD); + 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("not in MLM_WT_ASSOC_CNF_STATE, for aid %d, peer" + "StaD mlmState: %d", + assoc_cnf.aid, sta_ds->mlmStaContext.mlmState); + lim_print_mac_addr(mac_ctx, assoc_cnf.peer_macaddr.bytes, LOGD); + goto end; + } + /* + * Deactivate/delet 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.statusCode == 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; + pe_debug("sending Assoc Rsp frame to STA (assoc id=%d)", + sta_ds->assocId); + 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); + goto end; + } else { + /* + * 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 + */ + if (!sta_ds->mlmStaContext.updateContext) + sta_ds->mlmStaContext.updateContext = 1; + pe_debug("Recv Assoc Cnf, status Code : %d(assoc id=%d)", + assoc_cnf.statusCode, sta_ds->assocId); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, + true, sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry); + } +end: + if (((session_entry != NULL) && (sta_ds != NULL)) && + (session_entry->parsedAssocReq[sta_ds->assocId] != NULL)) { + assoc_req = (tpSirAssocReq) + session_entry->parsedAssocReq[sta_ds->assocId]; + if (assoc_req->assocReqFrame) { + qdf_mem_free(assoc_req->assocReqFrame); + assoc_req->assocReqFrame = NULL; + } + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +static void __lim_process_sme_addts_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpDphHashNode pStaDs; + tSirMacAddr peerMac; + tpSirAddtsReq pSirAddts; + uint32_t timeout; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionId */ + uint8_t smesessionId; + uint16_t smetransactionId; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smesessionId, + &smetransactionId); + + pSirAddts = (tpSirAddtsReq) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, pSirAddts->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given bssId"); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, QDF_STATUS_E_FAILURE, + NULL, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ADDTS_REQ_EVENT, psessionEntry, 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(psessionEntry)) { + pe_err("AddTs received on AP - ignoring"); + goto send_failure_addts_rsp; + } + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + pe_err("Cannot find AP context for addts req"); + goto send_failure_addts_rsp; + } + + if ((!pStaDs->valid) || (pStaDs->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 ((pStaDs->wsmEnabled) && + (pSirAddts->req.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA)) + pSirAddts->req.wsmTspecPresent = 1; + else if (pStaDs->wmeEnabled) + pSirAddts->req.wmeTspecPresent = 1; + else if (pStaDs->lleEnabled) + pSirAddts->req.lleTspecPresent = 1; + else { + pe_warn("ADDTS_REQ ignore - qos is disabled"); + goto send_failure_addts_rsp; + } + + if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + pe_err("AddTs received in invalid LIMsme state (%d)", + psessionEntry->limSmeState); + goto send_failure_addts_rsp; + } + + if (pMac->lim.gLimAddtsSent) { + pe_err("Addts (token %d, tsid %d, up %d) is still pending", + pMac->lim.gLimAddtsReq.req.dialogToken, + pMac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic.tsid, + pMac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic. + userPrio); + goto send_failure_addts_rsp; + } + + sir_copy_mac_addr(peerMac, psessionEntry->bssId); + + /* save the addts request */ + pMac->lim.gLimAddtsSent = true; + qdf_mem_copy((uint8_t *) &pMac->lim.gLimAddtsReq, + (uint8_t *) pSirAddts, sizeof(tSirAddtsReq)); + + /* ship out the message now */ + lim_send_addts_req_action_frame(pMac, peerMac, &pSirAddts->req, + psessionEntry); + pe_err("Sent ADDTS request"); + /* start a timer to wait for the response */ + if (pSirAddts->timeout) + timeout = pSirAddts->timeout; + else if (wlan_cfg_get_int(pMac, WNI_CFG_ADDTS_RSP_TIMEOUT, &timeout) != + QDF_STATUS_SUCCESS) { + pe_debug("Unable to get Cfg param %d (Addts Rsp Timeout)", + WNI_CFG_ADDTS_RSP_TIMEOUT); + goto send_failure_addts_rsp; + } + + timeout = SYS_MS_TO_TICKS(timeout); + if (tx_timer_change(&pMac->lim.limTimers.gLimAddtsRspTimer, timeout, 0) + != TX_SUCCESS) { + pe_err("AddtsRsp timer change failed!"); + goto send_failure_addts_rsp; + } + pMac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_change_context(&pMac->lim.limTimers.gLimAddtsRspTimer, + pMac->lim.gLimAddtsRspTimerCount) != + TX_SUCCESS) { + pe_err("AddtsRsp timer change failed!"); + goto send_failure_addts_rsp; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_ADDTS_RSP_TIMER)); + + /* add the sessionId to the timer object */ + pMac->lim.limTimers.gLimAddtsRspTimer.sessionId = sessionId; + if (tx_timer_activate(&pMac->lim.limTimers.gLimAddtsRspTimer) != + TX_SUCCESS) { + pe_err("AddtsRsp timer activation failed!"); + goto send_failure_addts_rsp; + } + return; + +send_failure_addts_rsp: + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, QDF_STATUS_E_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); +} + +static void __lim_process_sme_delts_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMacAddr peerMacAddr; + uint8_t ac; + tSirMacTSInfo *pTsinfo; + tpSirDeltsReq pDeltsReq = (tpSirDeltsReq) pMsgBuf; + tpDphHashNode pStaDs = NULL; + tpPESession psessionEntry; + uint8_t sessionId; + uint32_t status = QDF_STATUS_SUCCESS; + uint8_t smesessionId; + uint16_t smetransactionId; + + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smesessionId, + &smetransactionId); + + psessionEntry = pe_find_session_by_bssid(pMac, + pDeltsReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + 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(pMac, WLAN_PE_DIAG_DELTS_REQ_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (QDF_STATUS_SUCCESS != + lim_validate_delts_req(pMac, pDeltsReq, peerMacAddr, psessionEntry)) { + pe_err("lim_validate_delts_req failed"); + status = QDF_STATUS_E_FAILURE; + lim_send_sme_delts_rsp(pMac, pDeltsReq, QDF_STATUS_E_FAILURE, psessionEntry, + smesessionId, smetransactionId); + return; + } + + pe_debug("Sent DELTS request to station with assocId = %d MacAddr = " + MAC_ADDRESS_STR, + pDeltsReq->aid, MAC_ADDR_ARRAY(peerMacAddr)); + + lim_send_delts_req_action_frame(pMac, peerMacAddr, + pDeltsReq->req.wmeTspecPresent, + &pDeltsReq->req.tsinfo, + &pDeltsReq->req.tspec, psessionEntry); + + 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(pMac, psessionEntry, + 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) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } + + lim_set_active_edca_params(pMac, psessionEntry->gLimEdcaParams, + psessionEntry); + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + lim_send_edca_params(pMac, psessionEntry->gLimEdcaParamsActive, + pStaDs->bssId, 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(pMac, psessionEntry, 0, 0, 0); +#endif + + /* send an sme response back */ +end: + lim_send_sme_delts_rsp(pMac, pDeltsReq, QDF_STATUS_SUCCESS, psessionEntry, + smesessionId, smetransactionId); +} + +void lim_process_sme_addts_rsp_timeout(tpAniSirGlobal pMac, uint32_t param) +{ + /* fetch the sessionEntry based on the sessionId */ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimAddtsRspTimer. + sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_warn("AddtsRspTimeout in non-Sta role (%d)", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + pMac->lim.gLimAddtsSent = false; + return; + } + + if (!pMac->lim.gLimAddtsSent) { + pe_warn("AddtsRspTimeout but no AddtsSent"); + return; + } + + if (param != pMac->lim.gLimAddtsRspTimerCount) { + pe_err("Invalid AddtsRsp Timer count %d (exp %d)", param, + pMac->lim.gLimAddtsRspTimerCount); + return; + } + /* this a real response timeout */ + pMac->lim.gLimAddtsSent = false; + pMac->lim.gLimAddtsRspTimerCount++; + + lim_send_sme_addts_rsp(pMac, true, eSIR_SME_ADDTS_RSP_TIMEOUT, + psessionEntry, pMac->lim.gLimAddtsReq.req.tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * __lim_process_sme_get_statistics_request() + * + ***FUNCTION: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ +static void +__lim_process_sme_get_statistics_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpAniGetPEStatsReq pPEStatsReq; + struct scheduler_msg msgQ = {0}; + + pPEStatsReq = (tpAniGetPEStatsReq) pMsgBuf; + + msgQ.type = WMA_GET_STATISTICS_REQ; + + msgQ.reserved = 0; + msgQ.bodyptr = pMsgBuf; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + if (QDF_STATUS_SUCCESS != (wma_post_ctrl_msg(pMac, &msgQ))) { + qdf_mem_free(pMsgBuf); + pMsgBuf = NULL; + pe_err("Unable to forward request"); + return; + } + + return; +} +#else +static void __lim_process_sme_get_statistics_request( + struct sAniSirGlobal *mac_ctx, uint32_t *pMsgBuf) {} +#endif + +#ifdef FEATURE_WLAN_ESE +/** + * __lim_process_sme_get_tsm_stats_request() - get tsm stats request + * + * @pMac: Pointer to Global MAC structure + * @pMsgBuf: A pointer to the SME message buffer + * + * Return: None + */ +static void +__lim_process_sme_get_tsm_stats_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + struct scheduler_msg msgQ = {0}; + + msgQ.type = WMA_TSM_STATS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pMsgBuf; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + if (QDF_STATUS_SUCCESS != (wma_post_ctrl_msg(pMac, &msgQ))) { + qdf_mem_free(pMsgBuf); + pMsgBuf = NULL; + pe_err("Unable to forward request"); + return; + } +} +#endif /* FEATURE_WLAN_ESE */ + +static void lim_process_sme_set_addba_accept(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + uint32_t sme_session_id) +{ + tpPESession pe_session; + tpDphHashNode sta_ds_ptr; + + pe_session = pe_find_session_by_sme_session_id(mac_ctx, sme_session_id); + if (!pe_session) { + pe_err("Session does not exist: sme_id %d", sme_session_id); + return; + } + pe_session->gLimEdcaParamsActive[EDCA_AC_BE].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_AC_BE]; + pe_session->gLimEdcaParamsActive[EDCA_AC_BK].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_AC_BK]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VI].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_AC_VI]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VO].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_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, + sta_ds_ptr->bssId, false); + else + pe_err("Self entry missing in Hash Table"); +} + +static void lim_process_sme_update_config(tpAniSirGlobal mac_ctx, + struct update_config *msg) +{ + tpPESession pe_session; + + pe_debug("received eWNI_SME_UPDATE_HT_CONFIG message"); + if (msg == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pe_session = pe_find_session_by_sme_session_id(mac_ctx, + msg->sme_session_id); + if (pe_session == NULL) { + pe_warn("Session does not exist for given BSSID"); + return; + } + + switch (msg->capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + pe_session->htConfig.ht_rx_ldpc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + pe_session->htConfig.ht_tx_stbc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + pe_session->htConfig.ht_rx_stbc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + pe_session->htConfig.ht_sgi20 = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + pe_session->htConfig.ht_sgi40 = 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(tpAniSirGlobal pMac, + tpPESession psessionEntry, uint8_t sessionId) +{ + tpHalHiddenSsidVdevRestart pHalHiddenSsidVdevRestart = NULL; + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + if (psessionEntry == NULL) { + pe_err("Invalid parameters"); + return; + } + + pHalHiddenSsidVdevRestart = + qdf_mem_malloc(sizeof(tHalHiddenSsidVdevRestart)); + if (NULL == pHalHiddenSsidVdevRestart) { + pe_err("Unable to allocate memory"); + return; + } + + pHalHiddenSsidVdevRestart->ssidHidden = psessionEntry->ssidHidden; + pHalHiddenSsidVdevRestart->sessionId = sessionId; + pHalHiddenSsidVdevRestart->pe_session_id = psessionEntry->peSessionId; + + msgQ.type = WMA_HIDDEN_SSID_VDEV_RESTART; + msgQ.bodyptr = pHalHiddenSsidVdevRestart; + msgQ.bodyval = 0; + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("wma_post_ctrl_msg() failed"); + qdf_mem_free(pHalHiddenSsidVdevRestart); + } +} + +/** + * __lim_process_roam_scan_offload_req() - Process Roam scan offload from csr + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to SME message buffer + * + * Return: None + */ +static void __lim_process_roam_scan_offload_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpPESession pe_session; + struct scheduler_msg wma_msg = {0}; + QDF_STATUS status; + tSirRoamOffloadScanReq *req_buffer; + uint16_t local_ie_len; + uint8_t *local_ie_buf; + + req_buffer = (tSirRoamOffloadScanReq *)msg_buf; + pe_session = pe_find_session_by_sme_session_id(mac_ctx, + req_buffer->sessionId); + + local_ie_buf = qdf_mem_malloc(MAX_DEFAULT_SCAN_IE_LEN); + if (!local_ie_buf) { + pe_err("Mem Alloc failed for local_ie_buf"); + qdf_mem_zero(req_buffer, sizeof(*req_buffer)); + qdf_mem_free(req_buffer); + return; + } + + local_ie_len = req_buffer->assoc_ie.length; + /* Update ext cap IE if present */ + if (local_ie_len && + !lim_update_ext_cap_ie(mac_ctx, req_buffer->assoc_ie.addIEdata, + local_ie_buf, &local_ie_len)) { + if (local_ie_len < + QDF_ARRAY_SIZE(req_buffer->assoc_ie.addIEdata)) { + req_buffer->assoc_ie.length = local_ie_len; + qdf_mem_copy(req_buffer->assoc_ie.addIEdata, + local_ie_buf, local_ie_len); + } + } + qdf_mem_free(local_ie_buf); + + if (pe_session) + lim_update_fils_rik(pe_session, req_buffer); + + wma_msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ; + wma_msg.bodyptr = req_buffer; + + status = wma_post_ctrl_msg(mac_ctx, &wma_msg); + if (QDF_STATUS_SUCCESS != status) { + pe_err("Posting WMA_ROAM_SCAN_OFFLOAD_REQ failed"); + qdf_mem_zero(req_buffer, sizeof(*req_buffer)); + qdf_mem_free(req_buffer); + } +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * lim_process_roam_invoke() - process the Roam Invoke req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to the SME message buffer + * + * This function is called by limProcessMessageQueue(). This function sends the + * ROAM_INVOKE command to WMA. + * + * Return: None + */ +static void lim_process_roam_invoke(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + msg.type = SIR_HAL_ROAM_INVOKE; + msg.bodyptr = msg_buf; + msg.reserved = 0; + + status = wma_post_ctrl_msg(mac_ctx, &msg); + if (QDF_STATUS_SUCCESS != status) + pe_err("Not able to post SIR_HAL_ROAM_INVOKE to WMA"); +} +#else +static void lim_process_roam_invoke(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + qdf_mem_free(msg_buf); +} +#endif + +/* + * lim_handle_update_ssid_hidden() - Processes SSID hidden update + * @mac_ctx: Pointer to global mac context + * @session: Pointer to PE session + * @ssid_hidden: SSID hidden value to set; 0 - Broadcast SSID, + * 1 - Disable broadcast SSID + * + * Return: None + */ +static void lim_handle_update_ssid_hidden(tpAniSirGlobal mac_ctx, + tpPESession 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; + } + + /* Send vdev restart */ + lim_send_vdev_restart(mac_ctx, session, session->smeSessionId); + + return; +} + +/** + * __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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_update_session_param *msg; + tpPESession 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_sme_session_id(mac_ctx, msg->session_id); + if (!session) { + pe_warn("Session does not exist for given sessionId %d", + msg->session_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; + case SIR_PARAM_IGNORE_ASSOC_DISALLOWED: + session->ignore_assoc_disallowed = 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(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirChangeBIParams pChangeBIParams; + tpPESession psessionEntry; + uint8_t sessionId = 0; + tUpdateBeaconParams beaconParams; + + pe_debug("received Update Beacon Interval message"); + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + pChangeBIParams = (tpSirChangeBIParams) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, + pChangeBIParams->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("Session does not exist for given BSSID"); + return; + } + + /*Update sessionEntry Beacon Interval */ + if (psessionEntry->beaconParams.beaconInterval != + pChangeBIParams->beaconInterval) { + psessionEntry->beaconParams.beaconInterval = + pChangeBIParams->beaconInterval; + } + + /*Update sch beaconInterval */ + if (pMac->sch.schObject.gSchBeaconInterval != + pChangeBIParams->beaconInterval) { + pMac->sch.schObject.gSchBeaconInterval = + pChangeBIParams->beaconInterval; + + pe_debug("LIM send update BeaconInterval Indication: %d", + pChangeBIParams->beaconInterval); + + if (false == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + /* Update beacon */ + sch_set_fixed_beacon_fields(pMac, psessionEntry); + + beaconParams.bssIdx = psessionEntry->bssIdx; + /* Set change in beacon Interval */ + beaconParams.beaconInterval = + pChangeBIParams->beaconInterval; + beaconParams.paramChangeBitmap = + PARAM_BCN_INTERVAL_CHANGED; + lim_send_beacon_params(pMac, &beaconParams, psessionEntry); + } + } + + return; +} /*** end __lim_process_sme_change_bi(tpAniSirGlobal pMac, uint32_t *pMsgBuf) ***/ + +#ifdef QCA_HT_2040_COEX +static void __lim_process_sme_set_ht2040_mode(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + tpSirSetHT2040Mode pSetHT2040Mode; + tpPESession psessionEntry; + uint8_t sessionId = 0; + struct scheduler_msg msg = {0}; + tUpdateVHTOpMode *pHtOpMode = NULL; + uint16_t staId = 0; + tpDphHashNode pStaDs = NULL; + + pe_debug("received Set HT 20/40 mode message"); + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pSetHT2040Mode = (tpSirSetHT2040Mode) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, + pSetHT2040Mode->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_debug("Session does not exist for given BSSID"); + lim_print_mac_addr(pMac, pSetHT2040Mode->bssid.bytes, LOGD); + return; + } + + pe_debug("Update session entry for cbMod=%d", + pSetHT2040Mode->cbMode); + /*Update sessionEntry HT related fields */ + switch (pSetHT2040Mode->cbMode) { + case PHY_SINGLE_CHANNEL_CENTERED: + psessionEntry->htSecondaryChannelOffset = + PHY_SINGLE_CHANNEL_CENTERED; + psessionEntry->htRecommendedTxWidthSet = 0; + if (pSetHT2040Mode->obssEnabled) + psessionEntry->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_40MHZ; + else + psessionEntry->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_20MHZ; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + psessionEntry->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + psessionEntry->htRecommendedTxWidthSet = 1; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + psessionEntry->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + psessionEntry->htRecommendedTxWidthSet = 1; + break; + default: + pe_err("Invalid cbMode"); + return; + } + + /* Update beacon */ + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry, REASON_SET_HT2040); + + /* update OP Mode for each associated peer */ + for (staId = 0; staId < psessionEntry->dph.dphHashTable.size; staId++) { + pStaDs = dph_get_hash_entry(pMac, staId, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) + continue; + + if (pStaDs->valid && pStaDs->htSupportedChannelWidthSet) { + pHtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pHtOpMode) { + pe_err("Not able to allocate memory for setting OP mode"); + return; + } + pHtOpMode->opMode = + (psessionEntry->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) ? + eHT_CHANNEL_WIDTH_20MHZ : eHT_CHANNEL_WIDTH_40MHZ; + pHtOpMode->staId = staId; + qdf_mem_copy(pHtOpMode->peer_mac, &pStaDs->staAddr, + sizeof(tSirMacAddr)); + pHtOpMode->smesessionId = sessionId; + + 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 for staId=%d", + pHtOpMode->opMode, staId); + + } else + pe_debug("station %d does not support HT40", staId); + } + + 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(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + switch (pMsg->type) { + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + rrm_process_neighbor_report_req(pMac, pMsg->bodyptr); + break; + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + rrm_process_beacon_report_xmit(pMac, 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 pSessionEntry session entry. + * @return None + */ +QDF_STATUS +lim_send_set_max_tx_power_req(tpAniSirGlobal pMac, int8_t txPower, + tpPESession pSessionEntry) +{ + tpMaxTxPowerParams pMaxTxParams = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + if (pSessionEntry == NULL) { + pe_err("Invalid parameters"); + return QDF_STATUS_E_FAILURE; + } + + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + pe_err("Unable to allocate memory for pMaxTxParams"); + return QDF_STATUS_E_NOMEM; + + } + pMaxTxParams->power = txPower; + qdf_mem_copy(pMaxTxParams->bssId.bytes, pSessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pMaxTxParams->selfStaMacAddr.bytes, + pSessionEntry->selfMacAddr, + 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(pMac, pSessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + QDF_STATUS qdf_status; + tpSirRegisterMgmtFrame sme_req = (tpSirRegisterMgmtFrame)msg_buf; + struct mgmt_frm_reg_info *lim_mgmt_regn = NULL; + struct mgmt_frm_reg_info *next = NULL; + bool match = false; + + pe_debug("registerFrame %d, frameType %d, matchLen %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 != NULL) { + 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 != NULL) { + 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; +} + +static void +__lim_process_sme_reset_ap_caps_change(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirResetAPCapsChange pResetCapsChange; + tpPESession psessionEntry; + uint8_t sessionId = 0; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pResetCapsChange = (tpSirResetAPCapsChange) pMsgBuf; + psessionEntry = + pe_find_session_by_bssid(pMac, pResetCapsChange->bssId.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("Session does not exist for given BSSID"); + return; + } + + psessionEntry->limSentCapsChangeNtf = false; + 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(tpAniSirGlobal 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 (NULL == 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: function processes disassoc frame + * @mac_ctx: pointer to mac context + * @msg_buf: message buffer + * + * function processes disassoc request received from SME + * + * return: none + */ +static void __lim_process_send_disassoc_frame(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sme_send_disassoc_frm_req sme_send_disassoc_frame_req; + QDF_STATUS status; + tpPESession session_entry = NULL; + uint8_t sme_session_id; + uint16_t sme_trans_id; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + lim_get_session_info(mac_ctx, (uint8_t *)msg_buf, &sme_session_id, + &sme_trans_id); + + status = lim_send_disassoc_frm_req_ser_des(mac_ctx, + &sme_send_disassoc_frame_req, + (uint8_t *)msg_buf); + + if ((QDF_STATUS_E_FAILURE == status) || + (lim_is_group_addr(sme_send_disassoc_frame_req.peer_mac) && + !lim_is_addr_bc(sme_send_disassoc_frame_req.peer_mac))) { + pe_err("received invalid SME_DISASSOC_REQ message"); + return; + } + + session_entry = pe_find_session_by_sme_session_id( + mac_ctx, sme_session_id); + if (session_entry == NULL) { + pe_err("session does not exist for given bssId "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(sme_send_disassoc_frame_req.peer_mac)); + return; + } + + pe_debug("msg_type->%d len->%d sess_id->%d trans_id->%d mac->"MAC_ADDRESS_STR" reason->%d wait_for_ack->%d", + sme_send_disassoc_frame_req.msg_type, + sme_send_disassoc_frame_req.length, + sme_send_disassoc_frame_req.session_id, + sme_send_disassoc_frame_req.trans_id, + MAC_ADDR_ARRAY(sme_send_disassoc_frame_req.peer_mac), + sme_send_disassoc_frame_req.reason, + sme_send_disassoc_frame_req.wait_for_ack); + + lim_send_disassoc_mgmt_frame(mac_ctx, + sme_send_disassoc_frame_req.reason, + sme_send_disassoc_frame_req.peer_mac, + session_entry, sme_send_disassoc_frame_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(tpAniSirGlobal 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 (NULL == ie_params) { + pe_err("mem alloc failed"); + 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 (NULL == ie_params->ie_ptr) { + qdf_mem_free(ie_params); + pe_err("mem alloc failed"); + return; + } + *ie_params->ie_ptr = SIR_MAC_HT_CAPABILITIES_EID; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_ht_caps(mac_ctx, NULL, 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 (NULL == 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(tpAniSirGlobal 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 (NULL == ie_params) { + pe_err("mem alloc failed"); + 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 (NULL == ie_params->ie_ptr) { + qdf_mem_free(ie_params); + pe_err("mem alloc failed"); + return; + } + *ie_params->ie_ptr = SIR_MAC_VHT_CAPABILITIES_EID; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_vht_caps(mac_ctx, NULL, 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 (NULL == 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(tpAniSirGlobal 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 (NULL == p_msg) { + pe_err("NULL p_msg"); + return; + } + + pe_debug("rcvd set vdev ie per band req vdev_id = %d", + p_msg->vdev_id); + /* intentionally using NULL here so that self capabilty are sent */ + if (lim_send_ies_per_band(mac_ctx, NULL, p_msg->vdev_id) != + 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(tpAniSirGlobal 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 (NULL == 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( + tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + struct sme_update_access_policy_vendor_ie *update_vendor_ie; + struct sPESession *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_sme_session_id(mac_ctx, + update_vendor_ie->sme_session_id); + + if (!pe_session_entry) { + pe_err("Session does not exist for given sme session id(%hu)", + update_vendor_ie->sme_session_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) { + pe_err("Failed to allocate memory for 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; +} + +/** + * 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 pMac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *pMsgBuf A pointer to the SME message buffer + * @return Boolean - true - if pMsgBuf is consumed and can be freed. + * false - if pMsgBuf is not to be freed. + */ + +bool lim_process_sme_req_messages(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + bool bufConsumed = true; /* Set this flag to false within case block of any following message, that doesn't want pMsgBuf to be freed. */ + uint32_t *pMsgBuf = pMsg->bodyptr; + + pe_debug("LIM Received SME Message %s(%d) Global LimSmeState:%s(%d) Global LimMlmState: %s(%d)", + lim_msg_str(pMsg->type), pMsg->type, + lim_sme_state_str(pMac->lim.gLimSmeState), pMac->lim.gLimSmeState, + lim_mlm_state_str(pMac->lim.gLimMlmState), pMac->lim.gLimMlmState); + + /* 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(pMac, pMsgBuf); + break; + + case eWNI_SME_START_BSS_REQ: + bufConsumed = __lim_process_sme_start_bss_req(pMac, pMsg); + break; + + case eWNI_SME_JOIN_REQ: + __lim_process_sme_join_req(pMac, pMsgBuf); + break; + + case eWNI_SME_REASSOC_REQ: + __lim_process_sme_reassoc_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DISASSOC_REQ: + __lim_process_sme_disassoc_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + __lim_process_sme_disassoc_cnf(pMac, pMsgBuf); + break; + + case eWNI_SME_DEAUTH_REQ: + __lim_process_sme_deauth_req(pMac, pMsgBuf); + break; + + case eWNI_SME_SEND_DISASSOC_FRAME: + __lim_process_send_disassoc_frame(pMac, pMsgBuf); + break; + + case eWNI_SME_SETCONTEXT_REQ: + __lim_process_sme_set_context_req(pMac, pMsgBuf); + break; + + case eWNI_SME_STOP_BSS_REQ: + bufConsumed = __lim_process_sme_stop_bss_req(pMac, pMsg); + break; + + case eWNI_SME_ASSOC_CNF: +#ifdef WLAN_DEBUG + if (pMsg->type == eWNI_SME_ASSOC_CNF) + pe_debug("Received ASSOC_CNF message"); +#endif + __lim_process_sme_assoc_cnf_new(pMac, pMsg->type, + pMsgBuf); + break; + + case eWNI_SME_ADDTS_REQ: + pe_debug("Received ADDTS_REQ message"); + __lim_process_sme_addts_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DELTS_REQ: + pe_debug("Received DELTS_REQ message"); + __lim_process_sme_delts_req(pMac, pMsgBuf); + break; + + case SIR_LIM_ADDTS_RSP_TIMEOUT: + pe_debug("Received SIR_LIM_ADDTS_RSP_TIMEOUT message"); + lim_process_sme_addts_rsp_timeout(pMac, pMsg->bodyval); + break; + + case eWNI_SME_GET_STATISTICS_REQ: + __lim_process_sme_get_statistics_request(pMac, pMsgBuf); + /* HAL consumes pMsgBuf. It will be freed there. Set bufConsumed to false. */ + bufConsumed = false; + break; +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_REQ: + __lim_process_sme_get_tsm_stats_request(pMac, pMsgBuf); + bufConsumed = false; + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_GET_ASSOC_STAS_REQ: + lim_process_sme_get_assoc_sta_info(pMac, pMsgBuf); + break; + case eWNI_SME_SESSION_UPDATE_PARAM: + __lim_process_sme_session_update(pMac, pMsgBuf); + break; + case eWNI_SME_ROAM_SCAN_OFFLOAD_REQ: + __lim_process_roam_scan_offload_req(pMac, pMsgBuf); + bufConsumed = false; + break; + case eWNI_SME_ROAM_INVOKE: + lim_process_roam_invoke(pMac, pMsgBuf); + bufConsumed = false; + break; + case eWNI_SME_CHNG_MCC_BEACON_INTERVAL: + /* Update the beaconInterval */ + __lim_process_sme_change_bi(pMac, pMsgBuf); + break; + +#ifdef QCA_HT_2040_COEX + case eWNI_SME_SET_HT_2040_MODE: + __lim_process_sme_set_ht2040_mode(pMac, pMsgBuf); + break; +#endif + + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + __lim_process_report_message(pMac, pMsg); + break; + + case eWNI_SME_FT_PRE_AUTH_REQ: + bufConsumed = (bool) lim_process_ft_pre_auth_req(pMac, pMsg); + break; + case eWNI_SME_FT_UPDATE_KEY: + lim_process_ft_update_key(pMac, pMsgBuf); + break; + + case eWNI_SME_FT_AGGR_QOS_REQ: + lim_process_ft_aggr_qos_req(pMac, pMsgBuf); + break; + + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: + __lim_process_sme_register_mgmt_frame_req(pMac, pMsgBuf); + break; +#ifdef FEATURE_WLAN_TDLS + case eWNI_SME_TDLS_SEND_MGMT_REQ: + lim_process_sme_tdls_mgmt_send_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_ADD_STA_REQ: + lim_process_sme_tdls_add_sta_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_DEL_STA_REQ: + lim_process_sme_tdls_del_sta_req(pMac, pMsgBuf); + break; +#endif + case eWNI_SME_RESET_AP_CAPS_CHANGED: + __lim_process_sme_reset_ap_caps_change(pMac, pMsgBuf); + break; + + case eWNI_SME_CHANNEL_CHANGE_REQ: + lim_process_sme_channel_change_request(pMac, pMsgBuf); + break; + + case eWNI_SME_START_BEACON_REQ: + lim_process_sme_start_beacon_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ: + lim_process_sme_dfs_csa_ie_request(pMac, pMsgBuf); + break; + + case eWNI_SME_UPDATE_ADDITIONAL_IES: + lim_process_update_add_ies(pMac, pMsgBuf); + break; + + case eWNI_SME_MODIFY_ADDITIONAL_IES: + lim_process_modify_add_ies(pMac, pMsgBuf); + break; + case eWNI_SME_SET_HW_MODE_REQ: + lim_process_set_hw_mode(pMac, pMsgBuf); + break; + case eWNI_SME_NSS_UPDATE_REQ: + lim_process_nss_update_request(pMac, pMsgBuf); + break; + case eWNI_SME_SET_DUAL_MAC_CFG_REQ: + lim_process_set_dual_mac_cfg_req(pMac, pMsgBuf); + break; + case eWNI_SME_SET_IE_REQ: + lim_process_set_ie_req(pMac, pMsgBuf); + break; + case eWNI_SME_REGISTER_MGMT_FRAME_CB: + lim_register_mgmt_frame_ind_cb(pMac, pMsgBuf); + break; + case eWNI_SME_EXT_CHANGE_CHANNEL: + lim_process_ext_change_channel(pMac, pMsgBuf); + break; + case eWNI_SME_SET_ANTENNA_MODE_REQ: + lim_process_set_antenna_mode_req(pMac, pMsgBuf); + break; + case eWNI_SME_PDEV_SET_HT_VHT_IE: + lim_process_set_pdev_IEs(pMac, pMsgBuf); + break; + case eWNI_SME_SET_VDEV_IES_PER_BAND: + lim_process_set_vdev_ies_per_band(pMac, pMsgBuf); + break; + case eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE: + lim_process_sme_update_access_policy_vendor_ie(pMac, pMsgBuf); + break; + case eWNI_SME_UPDATE_CONFIG: + lim_process_sme_update_config(pMac, + (struct update_config *)pMsgBuf); + break; + case eWNI_SME_SET_ADDBA_ACCEPT: + lim_process_sme_set_addba_accept(pMac, + (struct sme_addba_accept *)pMsgBuf); + break; + case eWNI_SME_UPDATE_EDCA_PROFILE: + lim_process_sme_update_edca_params(pMac, pMsg->bodyval); + 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 pMac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *pMsgBuf A pointer to the SME message buffer + * @return Boolean - true - if pMsgBuf is consumed and can be freed. + * false - if pMsgBuf is not to be freed. + */ +static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg) +{ + tpSirStartBeaconIndication pBeaconStartInd; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionID */ + + if (pMsg == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pBeaconStartInd = (tpSirStartBeaconIndication) pMsg; + psessionEntry = pe_find_session_by_bssid(pMac, + pBeaconStartInd->bssid, + &sessionId); + if (psessionEntry == NULL) { + lim_print_mac_addr(pMac, pBeaconStartInd->bssid, LOGE); + pe_err("Session does not exist for given 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(pMac, psessionEntry); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("Start Beacon with ssid %s Ch %d"), + psessionEntry->ssId.ssId, + psessionEntry->currentOperChannel); + lim_send_beacon_ind(pMac, psessionEntry, REASON_DEFAULT); + lim_enable_obss_detection_config(pMac, psessionEntry); + lim_send_obss_color_collision_cfg(pMac, psessionEntry, + OBSS_COLOR_COLLISION_DETECTION); + } else { + pe_err("Invalid Beacon Start Indication"); + return; + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirChanChangeRequest ch_change_req; + tpPESession session_entry; + uint8_t session_id; /* PE session_id */ + int8_t max_tx_pwr; + uint32_t val = 0; + + if (msg_buf == NULL) { + pe_err("msg_buf is NULL"); + return; + } + ch_change_req = (tpSirChanChangeRequest)msg_buf; + + max_tx_pwr = cfg_get_regulatory_max_transmit_power(mac_ctx, + ch_change_req->targetChannel); + + if ((ch_change_req->messageType != eWNI_SME_CHANNEL_CHANGE_REQ) || + (max_tx_pwr == WMA_MAX_TXPOWER_INVALID)) { + pe_err("Invalid Request/max_tx_pwr"); + return; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + ch_change_req->bssid, &session_id); + if (session_entry == NULL) { + lim_print_mac_addr(mac_ctx, ch_change_req->bssid, LOGE); + pe_err("Session does not exist for given bssId"); + return; + } + + if ((session_entry->currentOperChannel == + ch_change_req->targetChannel) && + (session_entry->ch_width == ch_change_req->ch_width)) { + pe_err("Target channel and mode is same as current channel and mode channel %d and mode %d", + session_entry->currentOperChannel, 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_OPERATION; + + pe_debug("switch old chnl %d to new chnl %d, ch_bw %d, nw_type %d, dot11mode %d", + session_entry->currentOperChannel, + ch_change_req->targetChannel, + ch_change_req->ch_width, + ch_change_req->nw_type, + ch_change_req->dot11mode); + + /* 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_seg_0; + session_entry->ch_center_freq_seg1 = + ch_change_req->center_freq_seg_1; + 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->currentOperChannel = + ch_change_req->targetChannel; + session_entry->limRFBand = + lim_get_rf_band(session_entry->currentOperChannel); + + /* Update the global beacon filter */ + lim_update_bcn_probe_filter(mac_ctx, session_entry); + + /* Initialize 11h Enable Flag */ + if (CHAN_HOP_ALL_BANDS_ENABLE || + BAND_5G == session_entry->limRFBand) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &val) != + QDF_STATUS_SUCCESS) + pe_err("Fail to get WNI_CFG_11H_ENABLED"); + } + + session_entry->lim11hEnable = val; + session_entry->dot11mode = ch_change_req->dot11mode; + session_entry->nwType = ch_change_req->nw_type; + qdf_mem_copy(&session_entry->rateSet, + &ch_change_req->operational_rateset, + sizeof(session_entry->rateSet)); + qdf_mem_copy(&session_entry->extRateSet, + &ch_change_req->extended_rateset, + sizeof(session_entry->extRateSet)); + lim_set_channel(mac_ctx, ch_change_req->targetChannel, + session_entry->ch_center_freq_seg0, + session_entry->ch_center_freq_seg1, + session_entry->ch_width, + max_tx_pwr, session_entry->peSessionId, + ch_change_req->cac_duration_ms, + ch_change_req->dfs_regdomain); +} + +/****************************************************************************** +* 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 pMac 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(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (srcDataLen > 0 && pSrcData_buff != NULL) { + *pDstDataLen = srcDataLen; + + *pDstData_buff = qdf_mem_malloc(*pDstDataLen); + + if (NULL == *pDstData_buff) { + pe_err("AllocateMemory failed for 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 pMac 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(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (NULL == 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 (NULL == *pDstData_buff) { + pe_err("Memory allocation failed"); + *pDstDataLen = 0; + return; + } + } + + /* copy the content of buffer into dst buffer + */ + *pDstDataLen = srcDataLen; + qdf_mem_copy(*pDstData_buff, pSrcData_buff, *pDstDataLen); + +} + +/** + * lim_update_ibss_prop_add_ies() - update IBSS prop IE + * @pMac : Pointer to Global MAC structure + * @pDstData_buff : A pointer to pointer of dst buffer + * @pDstDataLen : A pointer to pointer of dst buffer length + * @pModifyIE : A pointer to tSirModifyIE + * + * This function replaces previous ibss prop_ie with new ibss prop_ie. + * + * Return: + * True or false depending upon whether IE is updated or not + */ +static bool +lim_update_ibss_prop_add_ies(tpAniSirGlobal pMac, uint8_t **pDstData_buff, + uint16_t *pDstDataLen, tSirModifyIE *pModifyIE) +{ + int32_t oui_length; + uint8_t *ibss_ie = NULL; + uint8_t *vendor_ie; +#define MAC_VENDOR_OUI "\x00\x16\x32" +#define MAC_VENDOR_SIZE 3 + + ibss_ie = pModifyIE->pIEBuffer; + oui_length = pModifyIE->oui_length; + + if ((0 == oui_length) || (NULL == ibss_ie)) { + pe_err("Invalid set IBSS vendor IE command length %d", + oui_length); + return false; + } + + /* + * Why replace only beacon OUI data here: + * 1. other ie (such as wpa) shall not be overwritten here. + * 2. per spec, beacon oui ie might be set twice and original one + * shall be updated. + */ + vendor_ie = (uint8_t *)wlan_get_vendor_ie_ptr_from_oui(MAC_VENDOR_OUI, + MAC_VENDOR_SIZE, *pDstData_buff, *pDstDataLen); + if (vendor_ie) { + QDF_ASSERT((vendor_ie[1] + 2) == pModifyIE->ieBufferlength); + qdf_mem_copy(vendor_ie, pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + } else { + uint16_t new_length; + uint8_t *new_ptr; + + /* + * check for uint16 overflow before using sum of two numbers as + * length of size to malloc + */ + if (USHRT_MAX - pModifyIE->ieBufferlength < *pDstDataLen) { + pe_err("U16 overflow due to %d + %d", + pModifyIE->ieBufferlength, *pDstDataLen); + return false; + } + + new_length = pModifyIE->ieBufferlength + *pDstDataLen; + new_ptr = qdf_mem_malloc(new_length); + if (NULL == new_ptr) { + pe_err("Memory allocation failed"); + return false; + } + qdf_mem_copy(new_ptr, *pDstData_buff, *pDstDataLen); + qdf_mem_copy(&new_ptr[*pDstDataLen], pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + qdf_mem_free(*pDstData_buff); + *pDstDataLen = new_length; + *pDstData_buff = new_ptr; + } + return true; +} + +/* +* 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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirModifyIEsInd modify_add_ies; + tpPESession session_entry; + uint8_t session_id; + bool ret = false; + tSirAddIeParams *add_ie_params; + + if (msg_buf == NULL) { + 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 (NULL == session_entry) { + pe_err("Session not found for given bssid" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(modify_add_ies->modifyIE.bssid.bytes)); + goto end; + } + if ((0 == modify_add_ies->modifyIE.ieBufferlength) || + (0 == modify_add_ies->modifyIE.ieIDLen) || + (NULL == 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->addIeParams; + switch (modify_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + /* Probe resp */ + if (LIM_IS_IBSS_ROLE(session_entry)) { + lim_update_ibss_prop_add_ies(mac_ctx, + &add_ie_params->probeRespData_buff, + &add_ie_params->probeRespDataLen, + &modify_add_ies->modifyIE); + } + break; + case eUPDATE_IE_ASSOC_RESP: + /* assoc resp IE */ + if (add_ie_params->assocRespDataLen == 0) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_ERROR, FL( + "assoc resp add ie not present %d"), + add_ie_params->assocRespDataLen); + } + /* search through the buffer and modify the IE */ + break; + case eUPDATE_IE_PROBE_BCN: + /*probe beacon IE */ + if (LIM_IS_IBSS_ROLE(session_entry)) { + ret = lim_update_ibss_prop_add_ies(mac_ctx, + &add_ie_params->probeRespBCNData_buff, + &add_ie_params->probeRespBCNDataLen, + &modify_add_ies->modifyIE); + } + 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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirUpdateIEsInd update_add_ies = (tpSirUpdateIEsInd)msg_buf; + uint8_t session_id; + tpPESession session_entry; + tSirAddIeParams *addn_ie; + uint16_t new_length = 0; + uint8_t *new_ptr = NULL; + tSirUpdateIE *update_ie; + + if (msg_buf == NULL) { + 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 (NULL == session_entry) { + pe_debug("Session not found for given bssid" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(update_ie->bssid.bytes)); + goto end; + } + addn_ie = &session_entry->addIeParams; + /* 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 (NULL == new_ptr) { + pe_err("Memory allocation failed"); + 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 refernece 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; +} + +/** + * 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: new channel to switch to. + * @ch_bandwidth: BW of channel to calculate op_class + * @session_entry: pe session + * + * This function is called to send ECSA frame for STA/CLI and SAP/GO. + * + * Return: void + */ + +static void send_extended_chan_switch_action_frame(tpAniSirGlobal mac_ctx, + uint16_t new_channel, uint8_t ch_bandwidth, + tpPESession session_entry) +{ + uint16_t op_class; + uint8_t switch_mode = 0, i; + tpDphHashNode psta; + uint8_t switch_count; + + op_class = wlan_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + new_channel, + ch_bandwidth); + + if (LIM_IS_AP_ROLE(session_entry) && + (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false)) + 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.maxStation; i++) { + psta = + session_entry->dph.dphHashTable.pDphNodeArray + i; + if (psta && psta->added) + lim_send_extended_chan_switch_action_frame( + mac_ctx, + psta->staAddr, + switch_mode, op_class, 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); + } + +} + +void lim_send_chan_switch_action_frame(tpAniSirGlobal mac_ctx, + uint16_t new_channel, + uint8_t ch_bandwidth, + tpPESession session_entry) +{ + uint16_t op_class; + 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 = wlan_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + new_channel, ch_bandwidth); + + 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.maxStation; 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); + } +} + +#define MAX_WAKELOCK_FOR_CSA 5000 + +/** + * 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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirDfsCsaIeRequest dfs_csa_ie_req; + tpPESession session_entry = NULL; + uint8_t session_id; + tLimWiderBWChannelSwitchInfo *wider_bw_ch_switch; + enum offset_t ch_offset; + + if (msg_buf == NULL) { + 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 == NULL) { + pe_err("Session not found for given BSSID" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 = + dfs_csa_ie_req->targetChannel; + + /* Channel switch announcement needs to be included in beacon */ + session_entry->dfsIncludeChanSwIe = true; + session_entry->gLimChannelSwitch.switchCount = + dfs_csa_ie_req->ch_switch_beacon_cnt; + session_entry->gLimChannelSwitch.ch_width = + dfs_csa_ie_req->ch_params.ch_width; + session_entry->gLimChannelSwitch.sec_ch_offset = + dfs_csa_ie_req->ch_params.sec_ch_offset; + if (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false) + session_entry->gLimChannelSwitch.switchMode = + dfs_csa_ie_req->ch_switch_mode; + + /* + * Validate if SAP is operating HT or VHT mode and set the Channel + * Switch Wrapper element with the Wide Band Switch subelement. + */ + if (true != session_entry->vhtCapability) + goto skip_vht; + + /* Now encode the Wider Ch BW element depending on the ch width */ + wider_bw_ch_switch = &session_entry->gLimWiderBWChannelSwitch; + switch (dfs_csa_ie_req->ch_params.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: + 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); + /* Send CSA IE request from here */ + lim_send_dfs_chan_sw_ie_update(mac_ctx, session_entry); + + if (dfs_csa_ie_req->ch_params.ch_width == CH_WIDTH_80MHZ) + ch_offset = BW80; + else + ch_offset = dfs_csa_ie_req->ch_params.sec_ch_offset; + + pe_debug("IE count:%d chan:%d width:%d wrapper:%d ch_offset:%d", + session_entry->gLimChannelSwitch.switchCount, + session_entry->gLimChannelSwitch.primaryChannel, + session_entry->gLimChannelSwitch.ch_width, + session_entry->dfsIncludeChanWrapperIe, + ch_offset); + + /* Send ECSA/CSA Action frame after updating the beacon */ + if (CHAN_HOP_ALL_BANDS_ENABLE) + lim_send_chan_switch_action_frame(mac_ctx, + session_entry->gLimChannelSwitch.primaryChannel, + ch_offset, session_entry); + else + send_extended_chan_switch_action_frame(mac_ctx, + session_entry->gLimChannelSwitch.primaryChannel, + ch_offset, 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(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + struct sir_sme_ext_cng_chan_req *ext_chng_channel = + (struct sir_sme_ext_cng_chan_req *) msg; + tpPESession session_entry = NULL; + + if (NULL == msg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + session_entry = + pe_find_session_by_sme_session_id(mac_ctx, + ext_chng_channel->session_id); + if (NULL == session_entry) { + pe_err("Session not found for given session %d", + ext_chng_channel->session_id); + return; + } + if (LIM_IS_AP_ROLE(session_entry)) { + pe_err("not an STA/CLI session"); + return; + } + send_extended_chan_switch_action_frame(mac_ctx, + ext_chng_channel->new_channel, + 0, session_entry); +} + +/** + * lim_nss_update_rsp() - send NSS update response to SME + * @mac_ctx Pointer to Global MAC structure + * @vdev_id: vdev id + * @status: nss update status + * + * Return: None + */ +static void lim_nss_update_rsp(tpAniSirGlobal mac_ctx, + uint8_t vdev_id, QDF_STATUS status) +{ + struct scheduler_msg msg = {0}; + struct sir_bcn_update_rsp *nss_rsp; + QDF_STATUS qdf_status; + + nss_rsp = qdf_mem_malloc(sizeof(*nss_rsp)); + if (!nss_rsp) { + pe_err("AllocateMemory failed for nss_rsp"); + return; + } + + nss_rsp->vdev_id = vdev_id; + nss_rsp->status = status; + nss_rsp->reason = REASON_NSS_UPDATE; + + msg.type = eWNI_SME_NSS_UPDATE_RSP; + msg.bodyptr = nss_rsp; + msg.bodyval = 0; + qdf_status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to post eWNI_SME_NSS_UPDATE_RSP"); + qdf_mem_free(nss_rsp); + } +} + +void lim_send_bcn_rsp(tpAniSirGlobal mac_ctx, tpSendbeaconParams rsp) +{ + if (!rsp) { + pe_err("rsp is NULL"); + return; + } + + pe_debug("Send beacon resp status %d for reason %d", + rsp->status, rsp->reason); + + if (rsp->reason == REASON_NSS_UPDATE) + lim_nss_update_rsp(mac_ctx, rsp->vdev_id, rsp->status); +} + +/** + * 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(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_nss_update_request *nss_update_req_ptr; + tpPESession 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_sme_session_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; + + 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_update_rsp(mac_ctx, vdev_id, status); +} + +/** + * 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(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + struct send_extcap_ie *msg; + QDF_STATUS status; + + if (msg_buf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + msg = (struct send_extcap_ie *)msg_buf; + status = lim_send_ext_cap_ie(mac_ctx, msg->session_id, NULL, false); + if (QDF_STATUS_SUCCESS != status) + pe_err("Unable to send ExtCap to FW"); + +} + +#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 disbale bss color. + * + * Return: None + */ +static void obss_color_collision_process_color_disable(tpAniSirGlobal mac_ctx, + tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession 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.session_id = obss_color_info->vdev_id; + he_bss_color.bss_color = bss_color_index_array[i]; + 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(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + struct sir_set_he_bss_color *bss_color; + tpPESession 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_sme_session_id(mac_ctx, + bss_color->session_id); + if (!session_entry) { + pe_err("Session not found for given session_id %d", + bss_color->session_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 (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_send_obss_color_collision_cfg(tpAniSirGlobal mac_ctx, + tpPESession 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->lim.global_obss_color_collision_det_offload); + return; + } + + cfg_param = qdf_mem_malloc(sizeof(*cfg_param)); + if (!cfg_param) { + pe_err("Failed to allocate memory"); + 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; + 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))) { + pe_err("Failed to post WMA_OBSS_COLOR_COLLISION_REQ to WMA"); + qdf_mem_free(cfg_param); + } else { + session->obss_color_collision_dec_evt = event_type; + } +} + +void lim_process_obss_color_collision_info(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct wmi_obss_color_collision_info *obss_color_info; + tpPESession 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_sme_session_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->lim.global_obss_color_collision_det_offload); + + 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->lim.global_obss_color_collision_det_offload); + 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, skiping", + 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_remove_duplicate_bssid_node(struct sir_rssi_disallow_lst *entry, + qdf_list_t *list) +{ + qdf_list_node_t *cur_list = NULL; + qdf_list_node_t *next_list = NULL; + struct sir_rssi_disallow_lst *cur_entry; + QDF_STATUS status; + + qdf_list_peek_front(list, &cur_list); + while (cur_list) { + qdf_list_peek_next(list, cur_list, &next_list); + cur_entry = qdf_container_of(cur_list, + struct sir_rssi_disallow_lst, + node); + + /* + * Remove the node from blacklisting if the timeout is 0 and + * rssi is 0 dbm i.e btm blacklisted entry + */ + if ((lim_assoc_rej_get_remaining_delta(cur_entry) == 0) && + cur_entry->expected_rssi == LIM_MIN_RSSI) { + status = qdf_list_remove_node(list, cur_list); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(cur_entry); + } else if (qdf_is_macaddr_equal(&entry->bssid, + &cur_entry->bssid)) { + /* + * Remove the node if we try to add the same bssid again + * Copy the old rssi value alone + */ + entry->expected_rssi = cur_entry->expected_rssi; + status = qdf_list_remove_node(list, cur_list); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(cur_entry); + break; + } + } + cur_list = next_list; + next_list = NULL; + } +} + +void lim_add_roam_blacklist_ap(tpAniSirGlobal mac_ctx, + struct roam_blacklist_event *src_lst) +{ + uint32_t i; + struct sir_rssi_disallow_lst *entry; + struct roam_blacklist_timeout *blacklist; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + blacklist = &src_lst->roam_blacklist[0]; + for (i = 0; i < src_lst->num_entries; i++) { + entry = qdf_mem_malloc(sizeof(struct sir_rssi_disallow_lst)); + if (!entry) + return; + + qdf_copy_macaddr(&entry->bssid, &blacklist->bssid); + entry->retry_delay = blacklist->timeout; + entry->time_during_rejection = blacklist->received_time; + /* set 0dbm as expected rssi for btm blaclisted entries */ + entry->expected_rssi = LIM_MIN_RSSI; + + qdf_mutex_acquire(&mac_ctx->roam.rssi_disallow_bssid_lock); + lim_remove_duplicate_bssid_node( + entry, + &mac_ctx->roam.rssi_disallow_bssid); + + if (qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid) >= + MAX_RSSI_AVOID_BSSID_LIST) { + status = lim_rem_blacklist_entry_with_lowest_delta( + &mac_ctx->roam.rssi_disallow_bssid); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mutex_release(&mac_ctx->roam. + rssi_disallow_bssid_lock); + pe_err("Failed to remove entry with lowest delta"); + qdf_mem_free(entry); + return; + } + } + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = qdf_list_insert_back( + &mac_ctx->roam.rssi_disallow_bssid, + &entry->node); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mutex_release(&mac_ctx->roam. + rssi_disallow_bssid_lock); + pe_err("Failed to enqueue bssid: %pM", + entry->bssid.bytes); + qdf_mem_free(entry); + return; + } + pe_debug("Added BTM blacklisted bssid: %pM", + entry->bssid.bytes); + } + qdf_mutex_release(&mac_ctx->roam.rssi_disallow_bssid_lock); + blacklist++; + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c new file mode 100644 index 0000000000000000000000000000000000000000..d370cf15c78ee7b6c958c5b1cef16a77ef578d66 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c @@ -0,0 +1,3332 @@ +/* + * 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. + */ + +/*=========================================================================== + * 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 "cfg_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "dot11f.h" +#include "lim_sta_hash_api.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_reg_services_api.h" +#include "wlan_tdls_tgt_api.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 + +static QDF_STATUS lim_tdls_setup_add_sta(tpAniSirGlobal pMac, + tSirTdlsAddStaReq * pAddStaReq, tpPESession psessionEntry); + +/* + * 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, +}; + +/* + * type of links used in TDLS + */ +enum tdlsLinks { + TDLS_LINK_AP, + TDLS_LINK_DIRECT +} e_tdls_link; + +/* + * node status in node searching + */ +enum tdlsLinkNodeStatus { + TDLS_NODE_NOT_FOUND, + TDLS_NODE_FOUND +} e_tdls_link_node_status; + +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 +} e_tdls_peer_capability; + +/* some local defines */ +#define LINK_IDEN_ADDR_OFFSET(x) (&x.LinkIdentifier) +#define PTI_LINK_IDEN_OFFSET (5) +#define PTI_BUF_STATUS_OFFSET (25) + +/* 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); + +#ifdef FEATURE_WLAN_TDLS +#define WNI_CFG_TDLS_LINK_SETUP_RSP_TIMEOUT (800) +#define WNI_CFG_TDLS_LINK_SETUP_CNF_TIMEOUT (200) +#endif + +#define IS_QOS_ENABLED(psessionEntry) ((((psessionEntry)->limQosEnabled) && \ + SIR_MAC_GET_QOS((psessionEntry)->limCurrentBssCaps)) || \ + (((psessionEntry)->limWmeEnabled) && \ + LIM_BSS_CAPS_GET(WME, (psessionEntry)->limCurrentBssQosCaps))) + +#define TID_AC_VI 4 +#define TID_AC_BK 1 + +#ifdef WLAN_DEBUG +static const uint8_t *lim_trace_tdls_action_string(uint8_t tdlsActionCode) +{ + switch (tdlsActionCode) { + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_CNF); + CASE_RETURN_STRING(SIR_MAC_TDLS_TEARDOWN); + CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_IND); + CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_RSP); + } + return (const uint8_t *)"UNKNOWN"; +} +#endif + +/* + * initialize TDLS setup list and related data structures. + */ +void lim_init_tdls_data(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + lim_init_peer_idxpool(pMac, pSessionEntry); + + return; +} + +static void populate_dot11f_tdls_offchannel_params( + tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIESuppChannels *suppChannels, + tDot11fIESuppOperatingClasses *suppOperClasses) +{ + uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t i; + 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; + + if (wlan_cfg_get_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans) != QDF_STATUS_SUCCESS) { + /** + * Could not get Valid channel list from CFG. + * Log error. + */ + pe_err("could not retrieve Valid channel list"); + return; + } + + if (IS_5G_CH(psessionEntry->currentOperChannel)) + band = BAND_5G; + else + band = BAND_2G; + + nss_5g = QDF_MIN(pMac->vdev_type_nss_5g.tdls, + pMac->user_configured_nss); + nss_2g = QDF_MIN(pMac->vdev_type_nss_2g.tdls, + pMac->user_configured_nss); + + /* validating the channel list for DFS and 2G channels */ + for (i = 0U; i < numChans; i++) { + if ((band == BAND_5G) && + (NSS_2x2_MODE == nss_5g) && + (NSS_1x1_MODE == nss_2g) && + (wlan_reg_is_dfs_ch(pMac->pdev, validChan[i]))) { + pe_debug("skipping channel: %d, nss_5g: %d, nss_2g: %d", + validChan[i], nss_5g, nss_2g); + continue; + } else { + if (wlan_reg_is_dsrc_chan(pMac->pdev, validChan[i])) { + pe_debug("skipping channel: %d from the valid channel list", + validChan[i]); + 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 (psessionEntry->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( + pMac->scan.countryCodeCurrent, + psessionEntry->currentOperChannel, + chanOffset); + + pe_debug("countryCodeCurrent: %s, currentOperChannel: %d, htSecondaryChannelOffset: %d, chanOffset: %d op class: %d", + pMac->scan.countryCodeCurrent, + psessionEntry->currentOperChannel, + psessionEntry->htSecondaryChannelOffset, + chanOffset, op_class); + suppOperClasses->present = 1; + suppOperClasses->classes[0] = op_class; + + wlan_reg_dmn_get_curr_opclasses(&numClasses, &classes[0]); + + for (i = 0; i < numClasses; i++) + suppOperClasses->classes[i + 1] = classes[i]; + + /* add one for present operating class, added in the beginning */ + suppOperClasses->num_classes = numClasses + 1; + + return; +} + +/* + * FUNCTION: Populate Link Identifier element IE + * + */ + +static void populate_dot11f_link_iden(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIELinkIdentifier *linkIden, + struct qdf_mac_addr peer_mac, + uint8_t reqType) +{ + uint8_t *initStaAddr = NULL; + uint8_t *respStaAddr = NULL; + + (reqType == TDLS_INITIATOR) ? ((initStaAddr = linkIden->InitStaAddr), + (respStaAddr = linkIden->RespStaAddr)) + : ((respStaAddr = linkIden->InitStaAddr), + (initStaAddr = linkIden->RespStaAddr)); + qdf_mem_copy((uint8_t *) linkIden->bssid, + (uint8_t *) psessionEntry->bssId, QDF_MAC_ADDR_SIZE); + + qdf_mem_copy((uint8_t *) initStaAddr, + psessionEntry->selfMacAddr, QDF_MAC_ADDR_SIZE); + + qdf_mem_copy((uint8_t *) respStaAddr, (uint8_t *) peer_mac.bytes, + QDF_MAC_ADDR_SIZE); + + linkIden->present = 1; + return; + +} + +static void populate_dot11f_tdls_ext_capability(tpAniSirGlobal pMac, + tpPESession psessionEntry, + 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 = pMac->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 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + 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; + + 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(tpAniSirGlobal pMac, uint8_t *pFrame, + tDot11fIELinkIdentifier *link_iden, + uint8_t tdlsLinkType, uint8_t reqType, + uint8_t tid, + tpPESession psessionEntry) +{ + 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 thorugh 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(pMac, peerMac, &aid, + &psessionEntry->dph.dphHashTable); + if (sta_ds) + qos_mode = sta_ds->qosMode; + + pMacHdr->fc.subType = + ((IS_QOS_ENABLED(psessionEntry) && + (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 = (psessionEntry->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:" + MAC_ADDRESS_STR", A2:"MAC_ADDRESS_STR", A3:" + MAC_ADDRESS_STR, + (tdlsLinkType == TDLS_LINK_AP) ? "AP" : "DIRECT", + MAC_ADDR_ARRAY(pMacHdr->addr1), + MAC_ADDR_ARRAY(pMacHdr->addr2), + MAC_ADDR_ARRAY(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) +{ + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)context; + + pe_debug("tdls_frm_session_id: %x tx_complete: %x", + mac_ctx->lim.tdls_frm_session_id, tx_complete); + + if (NO_SESSION != mac_ctx->lim.tdls_frm_session_id) { + 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; + } + + if (buf) + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; +} + +/* + * This function can be used for bacst or unicast discovery request + * We are not differentiating it here, it will all depnds on peer MAC address, + */ +static QDF_STATUS lim_send_tdls_dis_req_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSDisReq tdlsDisReq; + 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; + QDF_STATUS qdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + pe_err("psessionEntry is NULL"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + /* + * 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: + */ + qdf_mem_zero((uint8_t *) &tdlsDisReq, sizeof(tDot11fTDLSDisReq)); + + /* + * setup Fixed fields, + */ + tdlsDisReq.Category.category = SIR_MAC_ACTION_TDLS; + tdlsDisReq.Action.action = SIR_MAC_TDLS_DIS_REQ; + tdlsDisReq.DialogToken.token = dialog; + + size = sizeof(tSirMacAddr); + + populate_dot11f_link_iden(pMac, psessionEntry, &tdlsDisReq.LinkIdentifier, + peer_mac, TDLS_INITIATOR); + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_req_size(pMac, &tdlsDisReq, &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(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE; + +#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); + 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(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsDisReq), TDLS_LINK_AP, + TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + status = dot11f_pack_tdls_dis_req(pMac, &tdlsDisReq, 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); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Discovery Request (0x%08x)", + status); + } + +#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="MAC_ADDRESS_STR, + SIR_MAC_TDLS_DIS_REQ, + lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_REQ), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + lim_diag_mgmt_tx_event_report(pMac, (tpSirMacMgmtHdr) pFrame, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + qdf_status = wma_tx_frameWithTxComplete(pMac, 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, + smeSessionId, false, 0, RATEID_DEFAULT); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->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(tpAniSirGlobal pMac, + uint32_t selfDot11Mode, + tDot11fIEHTCaps *htCap, + tDot11fIEVHTCaps *vhtCap, + tpPESession psessionEntry) +{ + uint8_t nss; + uint32_t val; + + if (IS_5G_CH(psessionEntry->currentOperChannel)) + nss = pMac->vdev_type_nss_5g.tdls; + else + nss = pMac->vdev_type_nss_2g.tdls; + + nss = QDF_MIN(nss, pMac->user_configured_nss); + if (IS_DOT11_MODE_HT(selfDot11Mode)) { + /* Include HT Capability IE */ + populate_dot11f_ht_caps(pMac, psessionEntry, htCap); + val = SIZE_OF_SUPPORTED_MCS_SET; + wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + &htCap->supportedMCSSet[0], &val); + 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 (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && + pMac->roam.configParam.enableVhtFor24GHz) || + (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* Include VHT Capability IE */ + populate_dot11f_vht_caps(pMac, psessionEntry, vhtCap); + + /* + * Set to 0 if the TDLS STA does not support either 160 + * or 80+80 MHz. + * Set to 1 if the TDLS STA supports 160 MHz. + * Set to 2 if the TDLS STA supports 160 MHz and + * 80+80 MHz. + * The value 3 is reserved + */ + vhtCap->supportedChannelWidthSet = 0; + + vhtCap->suBeamformeeCap = 0; + vhtCap->suBeamFormerCap = 0; + vhtCap->muBeamformeeCap = 0; + vhtCap->muBeamformerCap = 0; + + wlan_cfg_get_int(pMac, WNI_CFG_VHT_RX_MCS_MAP, &val); + vhtCap->rxMCSMap = val; + wlan_cfg_get_int(pMac, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + &val); + vhtCap->rxHighSupDataRate = val; + wlan_cfg_get_int(pMac, WNI_CFG_VHT_TX_MCS_MAP, &val); + vhtCap->txMCSMap = val; + wlan_cfg_get_int(pMac, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + &val); + vhtCap->txSupDataRate = val; + 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: %hu", + vhtCap->present, vhtCap->supportedChannelWidthSet); +} + +/* + * Send TDLS discovery response frame on direct link. + */ + +static QDF_STATUS lim_send_tdls_dis_rsp_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + uint8_t *addIe, + uint16_t addIeLen) +{ + tDot11fTDLSDisRsp tdlsDisRsp; + 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; +/* 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; + + if (NULL == psessionEntry) { + pe_err("psessionEntry is NULL"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + /* + * 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: + */ + qdf_mem_zero((uint8_t *) &tdlsDisRsp, sizeof(tDot11fTDLSDisRsp)); + + /* + * setup Fixed fields, + */ + tdlsDisRsp.Category.category = SIR_MAC_ACTION_PUBLIC_USAGE; + tdlsDisRsp.Action.action = SIR_MAC_TDLS_DIS_RSP; + tdlsDisRsp.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsDisRsp.LinkIdentifier, + peer_mac, TDLS_RESPONDER); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) + != 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 *) &tdlsDisRsp.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (QDF_STATUS_E_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsDisRsp.SuppRates, + &tdlsDisRsp.ExtSuppRates, + psessionEntry->currentOperChannel)) + pe_err("could not populate supported data rates"); + + /* populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsDisRsp.ExtCap); + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsDisRsp.HTCaps, + &tdlsDisRsp.VHTCaps, psessionEntry); + + /* 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 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsDisRsp.SuppChannels, + &tdlsDisRsp. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != BAND_2G) { + tdlsDisRsp.ht2040_bss_coexistence.present = 1; + tdlsDisRsp.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", + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_rsp_size(pMac, &tdlsDisRsp, &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; + + /* 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); + 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_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac.bytes, + psessionEntry->selfMacAddr); + + { + tpSirMacMgmtHdr pMacHdr; + + pMacHdr = (tpSirMacMgmtHdr) pFrame; + pMacHdr->fc.toDS = ANI_TXDIR_IBSS; + pMacHdr->fc.powerMgmt = 0; + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + } + + status = dot11f_pack_tdls_dis_rsp(pMac, &tdlsDisRsp, 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); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Discovery Response (0x%08x)", + status); + } + + 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="MAC_ADDRESS_STR, + SIR_MAC_TDLS_DIS_RSP, + lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_RSP), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + lim_diag_mgmt_tx_event_report(pMac, (tpSirMacMgmtHdr) pFrame, + psessionEntry, 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 + */ + qdf_status = wma_tx_frameWithTxComplete(pMac, 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); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->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(tpAniSirGlobal pMac, uint32_t selfDot11Mode, + struct qdf_mac_addr peerMac, + tDot11fIEAID *Aid, + tpPESession psessionEntry) +{ + if (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && + pMac->roam.configParam.enableVhtFor24GHz) || + (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + + uint16_t aid; + tpDphHashNode pStaDs; + + pStaDs = + dph_lookup_hash_entry(pMac, peerMac.bytes, &aid, + &psessionEntry->dph. + dphHashTable); + if (NULL != pStaDs) { + Aid->present = 1; + Aid->assocId = aid | LIM_AID_MASK; /* set bit 14 and 15 1's */ + } else { + Aid->present = 0; + pe_err("pStaDs is NULL for " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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 + * @pMac: 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(tpAniSirGlobal pMac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(pMac, 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); +} +#else + +static inline QDF_STATUS +wma_tx_frame_with_tx_complete_send(tpAniSirGlobal pMac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(pMac, 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); +} +#endif + +void lim_set_tdls_flags(roam_offload_synch_ind *roam_sync_ind_ptr, + tpPESession ft_session_ptr) +{ + roam_sync_ind_ptr->join_rsp->tdls_prohibited = + ft_session_ptr->tdls_prohibited; + roam_sync_ind_ptr->join_rsp->tdls_chan_swit_prohibited = + ft_session_ptr->tdls_chan_swit_prohibited; +} + +/* + * TDLS setup Request frame on AP link + */ +static +QDF_STATUS lim_send_tdls_link_setup_req_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + uint8_t *addIe, + uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSSetupReq tdlsSetupReq; + uint16_t caps = 0; + 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; + uint32_t selfDot11Mode; + uint8_t smeSessionId = 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; */ + + /* + * 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 = psessionEntry->smeSessionId; + + qdf_mem_zero((uint8_t *) &tdlsSetupReq, sizeof(tDot11fTDLSSetupReq)); + tdlsSetupReq.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupReq.Action.action = SIR_MAC_TDLS_SETUP_REQ; + tdlsSetupReq.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupReq.LinkIdentifier, peer_mac, + TDLS_INITIATOR); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != 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 *) &tdlsSetupReq.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (QDF_STATUS_E_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsSetupReq.SuppRates, + &tdlsSetupReq.ExtSuppRates, + psessionEntry->currentOperChannel)) + pe_err("could not populate supported data rates"); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsSetupReq.ExtCap); + + if (1 == pMac->lim.gLimTDLSWmmMode) { + uint32_t val = 0; + + pe_debug("populate WMM IE in Setup Request Frame"); + /* include WMM IE */ + tdlsSetupReq.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + tdlsSetupReq.WMMInfoStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + tdlsSetupReq.WMMInfoStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupReq.WMMInfoStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupReq.WMMInfoStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + QDF_STATUS_SUCCESS) + pe_warn("could not retrieve Max SP Length"); + + tdlsSetupReq.WMMInfoStation.max_sp_length = (uint8_t) val; + tdlsSetupReq.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"); + tdlsSetupReq.QOSCapsStation.present = 1; + tdlsSetupReq.QOSCapsStation.max_sp_length = 0; + tdlsSetupReq.QOSCapsStation.qack = 0; + tdlsSetupReq.QOSCapsStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdlsSetupReq.QOSCapsStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupReq.QOSCapsStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupReq.QOSCapsStation.acvo_uapsd = + (pMac->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 + */ + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupReq.HTCaps, + &tdlsSetupReq.VHTCaps, psessionEntry); + + /* Populate AID */ + populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peer_mac, + &tdlsSetupReq.AID, psessionEntry); + + /* 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 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsSetupReq.SuppChannels, + &tdlsSetupReq. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != BAND_2G) { + tdlsSetupReq.ht2040_bss_coexistence.present = 1; + tdlsSetupReq.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", + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_req_size(pMac, &tdlsSetupReq, + &nPayload); + 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: */ + nPayload = 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 = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + + /* 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 Request", + nBytes); + 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(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsSetupReq), + TDLS_LINK_AP, TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + pe_debug("SupportedChnlWidth: %x rxMCSMap: %x rxMCSMap: %x txSupDataRate: %x", + tdlsSetupReq.VHTCaps.supportedChannelWidthSet, + tdlsSetupReq.VHTCaps.rxMCSMap, + tdlsSetupReq.VHTCaps.txMCSMap, + tdlsSetupReq.VHTCaps.txSupDataRate); + + status = dot11f_pack_tdls_setup_req(pMac, &tdlsSetupReq, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS Setup request (0x%08x)", + status); + cds_packet_free((void *)pPacket); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Setup Request (0x%08x)", + status); + } + + /* 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(pFrame + header_offset + nPayload, addIe, + addIeLen); + } + + pe_debug("[TDLS] action: %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR, + SIR_MAC_TDLS_SETUP_REQ, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_REQ), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + lim_diag_mgmt_tx_event_report(pMac, (tpSirMacMgmtHdr) pFrame, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->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(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint16_t reason, + uint8_t responder, + tpPESession psessionEntry, + uint8_t *addIe, uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSTeardown teardown; + 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; +#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 (NULL == psessionEntry) { + pe_err("psessionEntry is NULL"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + /* + * 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: + */ + qdf_mem_zero((uint8_t *) &teardown, sizeof(tDot11fTDLSTeardown)); + teardown.Category.category = SIR_MAC_ACTION_TDLS; + teardown.Action.action = SIR_MAC_TDLS_TEARDOWN; + teardown.Reason.code = reason; + + populate_dot11f_link_iden(pMac, psessionEntry, &teardown.LinkIdentifier, + 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(pMac, &teardown, &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(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(pMac, psessionEntry->bssId, &aid, + &psessionEntry->dph.dphHashTable); + if (sta_ds) + qos_mode = sta_ds->qosMode; + tdls_link_type = (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) + ? TDLS_LINK_AP : TDLS_LINK_DIRECT; + nBytes = nPayload + (((IS_QOS_ENABLED(psessionEntry) && + (tdls_link_type == TDLS_LINK_AP)) || + ((tdls_link_type == TDLS_LINK_DIRECT) && qos_mode)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + +#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 Teardown Frame.", + nBytes); + 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 */ + pe_debug("Reason of TDLS Teardown: %d", reason); + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(teardown), + (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) ? + TDLS_LINK_AP : TDLS_LINK_DIRECT, + (responder == true) ? TDLS_RESPONDER : TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + status = dot11f_pack_tdls_teardown(pMac, &teardown, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS Teardown frame (0x%08x)", + status); + cds_packet_free((void *)pPacket); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Teardown frame (0x%08x)", + status); + } + + if (addIeLen != 0) { + pe_debug("Copy Additional Ie Len = %d", addIeLen); + qdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } +#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) -%s-> OTA peer="MAC_ADDRESS_STR, + SIR_MAC_TDLS_TEARDOWN, + lim_trace_tdls_action_string(SIR_MAC_TDLS_TEARDOWN), + ((reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) ? "AP" : + "DIRECT"), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + lim_diag_mgmt_tx_event_report(pMac, (tpSirMacMgmtHdr) pFrame, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, + (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) + ? true : false); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->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(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + etdlsLinkSetupStatus setupStatus, + uint8_t *addIe, + uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSSetupRsp tdlsSetupRsp; + 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; +/* 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; + + if (NULL == psessionEntry) { + pe_err("psessionEntry is NULL"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + /* + * 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: + */ + qdf_mem_zero((uint8_t *) &tdlsSetupRsp, sizeof(tDot11fTDLSSetupRsp)); + + /* + * setup Fixed fields, + */ + tdlsSetupRsp.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupRsp.Action.action = SIR_MAC_TDLS_SETUP_RSP; + tdlsSetupRsp.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupRsp.LinkIdentifier, peer_mac, + TDLS_RESPONDER); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != 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 *) &tdlsSetupRsp.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (QDF_STATUS_E_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsSetupRsp.SuppRates, + &tdlsSetupRsp.ExtSuppRates, + psessionEntry->currentOperChannel)) + pe_err("could not populate supported data rates"); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsSetupRsp.ExtCap); + + if (1 == pMac->lim.gLimTDLSWmmMode) { + uint32_t val = 0; + + pe_debug("populate WMM IE in Setup Response frame"); + /* include WMM IE */ + tdlsSetupRsp.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + tdlsSetupRsp.WMMInfoStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + tdlsSetupRsp.WMMInfoStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupRsp.WMMInfoStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupRsp.WMMInfoStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); +#ifdef WLAN_DEBUG + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + QDF_STATUS_SUCCESS) + pe_warn("could not retrieve Max SP Length"); +#endif + tdlsSetupRsp.WMMInfoStation.max_sp_length = (uint8_t) val; + tdlsSetupRsp.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"); + tdlsSetupRsp.QOSCapsStation.present = 1; + tdlsSetupRsp.QOSCapsStation.max_sp_length = 0; + tdlsSetupRsp.QOSCapsStation.qack = 0; + tdlsSetupRsp.QOSCapsStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdlsSetupRsp.QOSCapsStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupRsp.QOSCapsStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupRsp.QOSCapsStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + } + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupRsp.HTCaps, + &tdlsSetupRsp.VHTCaps, psessionEntry); + + /* Populate AID */ + populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peer_mac, + &tdlsSetupRsp.AID, psessionEntry); + + /* 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 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsSetupRsp.SuppChannels, + &tdlsSetupRsp. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != BAND_2G) { + tdlsSetupRsp.ht2040_bss_coexistence.present = 1; + tdlsSetupRsp.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", + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + tdlsSetupRsp.Status.status = setupStatus; + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_rsp_size(pMac, &tdlsSetupRsp, + &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(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + + /* 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); + 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(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsSetupRsp), TDLS_LINK_AP, + TDLS_RESPONDER, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + pe_debug("SupportedChnlWidth: %x rxMCSMap: %x rxMCSMap: %x txSupDataRate: %x", + tdlsSetupRsp.VHTCaps.supportedChannelWidthSet, + tdlsSetupRsp.VHTCaps.rxMCSMap, + tdlsSetupRsp.VHTCaps.txMCSMap, + tdlsSetupRsp.VHTCaps.txSupDataRate); + status = dot11f_pack_tdls_setup_rsp(pMac, &tdlsSetupRsp, + 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); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Setup Response (0x%08x)", + status); + } + + /* 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); + } + + pe_debug("[TDLS] action: %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR, + SIR_MAC_TDLS_SETUP_RSP, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_RSP), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + lim_diag_mgmt_tx_event_report(pMac, (tpSirMacMgmtHdr) pFrame, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->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(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + uint32_t peerCapability, + tpPESession psessionEntry, + uint8_t *addIe, + uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSSetupCnf tdlsSetupCnf; + 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; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + + /* + * 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 = psessionEntry->smeSessionId; + + qdf_mem_zero((uint8_t *) &tdlsSetupCnf, sizeof(tDot11fTDLSSetupCnf)); + + /* + * setup Fixed fields, + */ + tdlsSetupCnf.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupCnf.Action.action = SIR_MAC_TDLS_SETUP_CNF; + tdlsSetupCnf.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupCnf.LinkIdentifier, 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 == pMac->lim.gLimTDLSWmmMode) && + (CHECK_BIT(peerCapability, TDLS_PEER_WMM_CAP))) { + pe_debug("populate WMM praram in Setup Confirm"); + populate_dot11f_wmm_params(pMac, &tdlsSetupCnf.WMMParams, + psessionEntry); + } + + /* Check peer is VHT capable */ + if (CHECK_BIT(peerCapability, TDLS_PEER_VHT_CAP)) { + populate_dot11f_vht_operation(pMac, + psessionEntry, + &tdlsSetupCnf.VHTOperation); + populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); + } else if (CHECK_BIT(peerCapability, TDLS_PEER_HT_CAP)) { /* Check peer is HT capable */ + populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); + } + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_cnf_size(pMac, &tdlsSetupCnf, + &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(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + +#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); + 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(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsSetupCnf), + TDLS_LINK_AP, + TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + status = dot11f_pack_tdls_setup_cnf(pMac, &tdlsSetupCnf, 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); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Discovery Request (0x%08x)", + status); + } + + /* 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); + } +#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="MAC_ADDRESS_STR, + SIR_MAC_TDLS_SETUP_CNF, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_CNF), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + lim_diag_mgmt_tx_event_report(pMac, (tpSirMacMgmtHdr) pFrame, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->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(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirTdlsAddStaReq * + pTdlsAddStaReq, + tDot11fIEHTCaps *pDot11f) +{ + uint32_t nCfgValue; + uint8_t nCfgValue8; + tSirMacHTParametersInfo *pHTParametersInfo; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + + nCfgValue = pTdlsAddStaReq->htCap.hc_cap; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->advCodingCap = uHTCapabilityInfo.htCapInfo.advCodingCap; + pDot11f->mimoPowerSave = uHTCapabilityInfo.htCapInfo.mimoPowerSave; + pDot11f->greenField = uHTCapabilityInfo.htCapInfo.greenField; + pDot11f->shortGI20MHz = uHTCapabilityInfo.htCapInfo.shortGI20MHz; + pDot11f->shortGI40MHz = uHTCapabilityInfo.htCapInfo.shortGI40MHz; + pDot11f->txSTBC = uHTCapabilityInfo.htCapInfo.txSTBC; + pDot11f->rxSTBC = uHTCapabilityInfo.htCapInfo.rxSTBC; + pDot11f->delayedBA = uHTCapabilityInfo.htCapInfo.delayedBA; + pDot11f->maximalAMSDUsize = + uHTCapabilityInfo.htCapInfo.maximalAMSDUsize; + pDot11f->dsssCckMode40MHz = + uHTCapabilityInfo.htCapInfo.dsssCckMode40MHz; + pDot11f->psmp = uHTCapabilityInfo.htCapInfo.psmp; + pDot11f->stbcControlFrame = + uHTCapabilityInfo.htCapInfo.stbcControlFrame; + pDot11f->lsigTXOPProtection = + uHTCapabilityInfo.htCapInfo.lsigTXOPProtection; + + /* + * All sessionized entries will need the check below + * Only in case of NO session + */ + if (psessionEntry == NULL) { + pDot11f->supportedChannelWidthSet = + uHTCapabilityInfo.htCapInfo.supportedChannelWidthSet; + } else { + pDot11f->supportedChannelWidthSet = + psessionEntry->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 = pTdlsAddStaReq->htCap.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, pTdlsAddStaReq->htCap.mcsset, + SIZE_OF_SUPPORTED_MCS_SET); + + nCfgValue = pTdlsAddStaReq->htCap.extcap; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; + pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; + pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; + + nCfgValue = pTdlsAddStaReq->htCap.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 = pTdlsAddStaReq->htCap.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 = pTdlsAddStaReq->htcap_present; + + return QDF_STATUS_SUCCESS; + +} + +static QDF_STATUS +lim_tdls_populate_dot11f_vht_caps(tpAniSirGlobal pMac, + tSirTdlsAddStaReq *pTdlsAddStaReq, + tDot11fIEVHTCaps *pDot11f) +{ + uint32_t nCfgValue = 0; + union { + uint32_t nCfgValue32; + tSirMacVHTCapabilityInfo vhtCapInfo; + } uVHTCapabilityInfo; + union { + uint16_t nCfgValue16; + tSirMacVHTTxSupDataRateInfo vhtTxSupDataRateInfo; + tSirMacVHTRxSupDataRateInfo vhtRxsupDataRateInfo; + } uVHTSupDataRateInfo; + + pDot11f->present = pTdlsAddStaReq->vhtcap_present; + + nCfgValue = pTdlsAddStaReq->vhtCap.vhtCapInfo; + 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->reserved1 = uVHTCapabilityInfo.vhtCapInfo.reserved1; + + pDot11f->rxMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.rxMcsMap; + + nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.rxHighest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->rxHighSupDataRate = + uVHTSupDataRateInfo.vhtRxsupDataRateInfo.rxSupDataRate; + + pDot11f->txMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.txMcsMap; + + nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.txHighest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->txSupDataRate = + uVHTSupDataRateInfo.vhtTxSupDataRateInfo.txSupDataRate; + + pDot11f->reserved3 = uVHTSupDataRateInfo.vhtTxSupDataRateInfo.reserved; + + lim_log_vht_cap(pMac, pDot11f); + + return QDF_STATUS_SUCCESS; + +} + +/** + * 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(tpAniSirGlobal mac_ctx, tpDphHashNode stads, + uint8_t *supp_rate_set, + uint8_t supp_rates_len, + uint8_t *supp_mcs_set, + tpPESession session_entry, + tDot11fIEVHTCaps *vht_caps) +{ + tSirMacRateSet temp_rate_set; + uint32_t i, j, val, min, is_a_rate; + tSirMacRateSet temp_rate_set2; + uint32_t phymode; + uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; + tpSirSupportedRates rates; + uint8_t a_rateindex = 0; + uint8_t b_rateindex = 0; + uint8_t nss; + + is_a_rate = 0; + temp_rate_set2.numRates = 0; + + lim_get_phy_mode(mac_ctx, &phymode, NULL); + + /* get own rate set */ + val = WNI_CFG_OPERATIONAL_RATE_SET_LEN; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_OPERATIONAL_RATE_SET, + (uint8_t *) &temp_rate_set.rate, + &val) != QDF_STATUS_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + pe_err("could not retrieve rateset"); + val = 0; + } + temp_rate_set.numRates = val; + + if (phymode == WNI_CFG_PHY_MODE_11G) { + /* get own extended rate set */ + val = WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN; + if (wlan_cfg_get_str(mac_ctx, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + (uint8_t *) &temp_rate_set2.rate, + &val) != QDF_STATUS_SUCCESS) + temp_rate_set2.numRates = val; + } + + if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { + 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 . + */ + if (supp_rates_len > SIR_MAC_RATESET_EID_MAX) { + pe_warn("Supported rates length: %d more than the Max limit, reset to Max", + supp_rates_len); + supp_rates_len = SIR_MAC_RATESET_EID_MAX; + } + + 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((uint8_t *) rates, sizeof(tSirSupportedRates)); + + for (i = 0; i < temp_rate_set2.numRates; i++) { + for (j = 0; j < temp_rate_set.numRates; j++) { + if ((temp_rate_set2.rate[i] & 0x7F) != + (temp_rate_set.rate[j] & 0x7F)) + continue; + + 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_set2.rate[i] & 0x7f)) { + is_a_rate = 1; + if (a_rateindex < SIR_NUM_11A_RATES) + rates->llaRates[a_rateindex++] = temp_rate_set2.rate[i]; + } else { + if (b_rateindex < SIR_NUM_11B_RATES) + rates->llbRates[b_rateindex++] = temp_rate_set2.rate[i]; + } + break; + } + } + + if (IS_5G_CH(session_entry->currentOperChannel)) + 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 = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + mcsSet, &val) != 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; 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); + /** + * 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; +} + +/* + * update HASH node entry info + */ +static void lim_tdls_update_hash_node_info(tpAniSirGlobal pMac, + tDphHashNode *pStaDs, + tSirTdlsAddStaReq *pTdlsAddStaReq, + tpPESession psessionEntry) +{ + tDot11fIEHTCaps htCap = {0,}; + tDot11fIEHTCaps *htCaps; + tDot11fIEVHTCaps *pVhtCaps = NULL; + tDot11fIEVHTCaps *pVhtCaps_txbf = NULL; + tDot11fIEVHTCaps vhtCap; + uint8_t cbMode; + + if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_ADD) { + populate_dot11f_ht_caps(pMac, psessionEntry, &htCap); + } else if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE) { + lim_tdls_populate_dot11f_ht_caps(pMac, NULL, pTdlsAddStaReq, &htCap); + } + htCaps = &htCap; + if (htCaps->present) { + pStaDs->mlmStaContext.htCapability = 1; + pStaDs->htGreenfield = htCaps->greenField; + /* + * pStaDs->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 + * psessionEntry. + */ + pe_debug("supportedChannelWidthSet: 0x%x htSupportedChannelWidthSet: 0x%x", + htCaps->supportedChannelWidthSet, + psessionEntry->htSupportedChannelWidthSet); + pStaDs->htSupportedChannelWidthSet = + (htCaps->supportedChannelWidthSet < + psessionEntry->htSupportedChannelWidthSet) ? + htCaps->supportedChannelWidthSet : + psessionEntry->htSupportedChannelWidthSet; + pe_debug("pStaDs->htSupportedChannelWidthSet: 0x%x", + pStaDs->htSupportedChannelWidthSet); + + pStaDs->htMIMOPSState = htCaps->mimoPowerSave; + pStaDs->htMaxAmsduLength = htCaps->maximalAMSDUsize; + pStaDs->htAMpduDensity = htCaps->mpduDensity; + pStaDs->htDsssCckRate40MHzSupport = htCaps->dsssCckMode40MHz; + pStaDs->htShortGI20Mhz = htCaps->shortGI20MHz; + pStaDs->htShortGI40Mhz = htCaps->shortGI40MHz; + pStaDs->htMaxRxAMpduFactor = htCaps->maxRxAMPDUFactor; + lim_fill_rx_highest_supported_rate(pMac, + &pStaDs->supportedRates. + rxHighestDataRate, + htCaps->supportedMCSSet); + pStaDs->baPolicyFlag = 0xFF; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_N; + pStaDs->ht_caps = pTdlsAddStaReq->htCap.hc_cap; + } else { + pStaDs->mlmStaContext.htCapability = 0; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_BG; + } + lim_tdls_populate_dot11f_vht_caps(pMac, pTdlsAddStaReq, &vhtCap); + pVhtCaps = &vhtCap; + if (pVhtCaps->present) { + pStaDs->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 (psessionEntry->ch_width) + pStaDs->vhtSupportedChannelWidthSet = + psessionEntry->ch_width - 1; + else + pStaDs->vhtSupportedChannelWidthSet = + psessionEntry->ch_width; + + pe_debug("vhtSupportedChannelWidthSet: %hu htSupportedChannelWidthSet: %hu", + pStaDs->vhtSupportedChannelWidthSet, + pStaDs->htSupportedChannelWidthSet); + + pStaDs->vhtLdpcCapable = pVhtCaps->ldpcCodingCap; + pStaDs->vhtBeamFormerCapable = 0; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_AC; + pVhtCaps_txbf = (tDot11fIEVHTCaps *) (&pTdlsAddStaReq->vhtCap); + pVhtCaps_txbf->suBeamformeeCap = 0; + pVhtCaps_txbf->suBeamFormerCap = 0; + pVhtCaps_txbf->muBeamformerCap = 0; + pVhtCaps_txbf->muBeamformeeCap = 0; + pStaDs->vht_caps = pTdlsAddStaReq->vhtCap.vhtCapInfo; + } else { + pStaDs->mlmStaContext.vhtCapability = 0; + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } + + /* + * Calculate the Secondary Coannel Offset if our + * own channel bonding state is enabled + */ + if (psessionEntry->htSupportedChannelWidthSet) { + cbMode = lim_select_cb_mode(pStaDs, psessionEntry, + psessionEntry->currentOperChannel, + pStaDs->vhtSupportedChannelWidthSet); + + if (pStaDs->mlmStaContext.vhtCapability) + pStaDs->htSecondaryChannelOffset = + lim_get_htcb_state(cbMode); + else + pStaDs->htSecondaryChannelOffset = cbMode; + } + /* Lets enable QOS parameter */ + pStaDs->qosMode = (pTdlsAddStaReq->capability & CAPABILITIES_QOS_OFFSET) + || pTdlsAddStaReq->htcap_present; + pStaDs->wmeEnabled = 1; + pStaDs->lleEnabled = 0; + /* TDLS Dummy AddSTA does not have qosInfo , is it OK ?? + */ + pStaDs->qos.capability.qosInfo = + (*(tSirMacQosInfoStation *) &pTdlsAddStaReq->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(pMac, pStaDs, + pTdlsAddStaReq->supported_rates, + pTdlsAddStaReq-> + supported_rates_length, + (uint8_t *)pTdlsAddStaReq-> + htCap.mcsset, + psessionEntry, pVhtCaps); + + /* TDLS Dummy AddSTA does not have right capability , is it OK ?? + */ + pStaDs->mlmStaContext.capabilityInfo = + (*(tSirMacCapabilityInfo *) &pTdlsAddStaReq->capability); + + return; +} + +/* + * Add STA for TDLS setup procedure + */ +static QDF_STATUS lim_tdls_setup_add_sta(tpAniSirGlobal pMac, + tSirTdlsAddStaReq *pAddStaReq, + tpPESession psessionEntry) +{ + tpDphHashNode pStaDs = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t aid = 0; + + pStaDs = dph_lookup_hash_entry(pMac, pAddStaReq->peermac.bytes, &aid, + &psessionEntry->dph.dphHashTable); + + if (pStaDs && pAddStaReq->tdlsAddOper == TDLS_OPER_ADD) { + pe_err("TDLS entry for peer: "MAC_ADDRESS_STR " already exist, cannot add new entry", + MAC_ADDR_ARRAY(pAddStaReq->peermac.bytes)); + } + if (!pStaDs && pAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE) { + pe_err("TDLS update peer is given without peer creation"); + return QDF_STATUS_E_FAILURE; + } + + if (pStaDs && pStaDs->staType != STA_ENTRY_TDLS_PEER) { + pe_err("Non TDLS entry for peer: "MAC_ADDRESS_STR " already exist", + MAC_ADDR_ARRAY(pAddStaReq->peermac.bytes)); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == pStaDs) { + aid = lim_assign_peer_idx(pMac, psessionEntry); + + if (!aid) { + pe_err("No more free AID for peer: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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(psessionEntry->peerAIDBitmap, aid); + + pe_debug("Aid: %d, for peer: " MAC_ADDRESS_STR, + aid, MAC_ADDR_ARRAY(pAddStaReq->peermac.bytes)); + pStaDs = + dph_get_hash_entry(pMac, aid, + &psessionEntry->dph.dphHashTable); + + if (pStaDs) { + (void)lim_del_sta(pMac, pStaDs, false /*asynchronous */, + psessionEntry); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, aid, + psessionEntry); + } + + pStaDs = dph_add_hash_entry(pMac, pAddStaReq->peermac.bytes, + aid, &psessionEntry->dph.dphHashTable); + + if (NULL == pStaDs) { + pe_err("add hash entry failed"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + } + + lim_tdls_update_hash_node_info(pMac, pStaDs, pAddStaReq, psessionEntry); + + pStaDs->staType = STA_ENTRY_TDLS_PEER; + + status = + lim_add_sta(pMac, pStaDs, + (pAddStaReq->tdlsAddOper == + TDLS_OPER_UPDATE) ? true : false, psessionEntry); + + if (QDF_STATUS_SUCCESS != status) { + /* should not fail */ + 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(tpAniSirGlobal pMac, + struct qdf_mac_addr peerMac, + tpPESession psessionEntry, + bool resp_reqd) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t peerIdx = 0; + tpDphHashNode pStaDs; + + pStaDs = dph_lookup_hash_entry(pMac, peerMac.bytes, &peerIdx, + &psessionEntry->dph.dphHashTable); + + if (pStaDs && pStaDs->staType == STA_ENTRY_TDLS_PEER) { + pe_debug("DEL STA peer MAC: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pStaDs->staAddr)); + + pe_debug("STA type: %x, sta idx: %x resp_reqd: %d", + pStaDs->staType, + pStaDs->staIndex, + resp_reqd); + + status = lim_del_sta(pMac, pStaDs, resp_reqd, psessionEntry); + } else { + pe_debug("TDLS peer "MAC_ADDRESS_STR" not found", + MAC_ADDR_ARRAY(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(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirMacAddr peerMac, + uint8_t updateSta, + tDphHashNode *pStaDs, uint8_t status) +{ + struct scheduler_msg mmhMsg = { 0 }; + tSirTdlsAddStaRsp *addStaRsp = NULL; + + mmhMsg.type = eWNI_SME_TDLS_ADD_STA_RSP; + + addStaRsp = qdf_mem_malloc(sizeof(tSirTdlsAddStaRsp)); + if (NULL == addStaRsp) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + addStaRsp->sessionId = sessionId; + addStaRsp->statusCode = status; + if (pStaDs) { + addStaRsp->staId = pStaDs->staIndex; + } + if (peerMac) { + qdf_mem_copy(addStaRsp->peermac.bytes, + (uint8_t *) peerMac, QDF_MAC_ADDR_SIZE); + } + if (updateSta) + addStaRsp->tdlsAddOper = TDLS_OPER_UPDATE; + else + addStaRsp->tdlsAddOper = TDLS_OPER_ADD; + + addStaRsp->length = sizeof(tSirTdlsAddStaRsp); + addStaRsp->messageType = eWNI_SME_TDLS_ADD_STA_RSP; + addStaRsp->psoc = pMac->psoc; + mmhMsg.bodyptr = addStaRsp; + mmhMsg.callback = tgt_tdls_add_peer_rsp; + + return scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &mmhMsg); +} + +/* + * STA RSP received from HAL + */ +QDF_STATUS lim_process_tdls_add_sta_rsp(tpAniSirGlobal pMac, void *msg, + tpPESession psessionEntry) +{ + tAddStaParams *pAddStaParams = (tAddStaParams *) msg; + uint8_t status = QDF_STATUS_SUCCESS; + tDphHashNode *pStaDs = NULL; + uint16_t aid = 0; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pe_debug("staIdx: %d, staMac: "MAC_ADDRESS_STR, + pAddStaParams->staIdx, + MAC_ADDR_ARRAY(pAddStaParams->staMac)); + + if (pAddStaParams->status != QDF_STATUS_SUCCESS) { + QDF_ASSERT(0); + pe_err("Add sta failed "); + status = QDF_STATUS_E_FAILURE; + goto add_sta_error; + } + + pStaDs = dph_lookup_hash_entry(pMac, pAddStaParams->staMac, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + pe_err("pStaDs is NULL "); + status = QDF_STATUS_E_FAILURE; + goto add_sta_error; + } + + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + pStaDs->valid = 1; +add_sta_error: + status = lim_send_sme_tdls_add_sta_rsp(pMac, psessionEntry->smeSessionId, + pAddStaParams->staMac, + pAddStaParams->updateSta, pStaDs, + 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 + * + * 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(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint16_t sme_transaction_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 (NULL == sme_rsp) { + /* Buffer not available. Log error */ + QDF_TRACE(QDF_MODULE_ID_PE, LOGP, + FL("call to AllocateMemory failed for eWNI_SME_*_RSP")); + return; + } + + sme_rsp->messageType = msg_type; + sme_rsp->length = sizeof(tSirSmeRsp); + sme_rsp->statusCode = result_code; + + sme_rsp->sessionId = sme_session_id; + sme_rsp->transactionId = sme_transaction_id; + + msg.type = msg_type; + sme_rsp->psoc = mac_ctx->psoc; + msg.bodyptr = sme_rsp; + msg.callback = tgt_tdls_send_mgmt_rsp; + scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + +} + +/** + * 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(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + /* get all discovery request parameters */ + tSirTdlsSendMgmtReq *send_req = (tSirTdlsSendMgmtReq *) msg; + tpPESession session_entry; + uint8_t session_id; + 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 (NULL == session_entry) { + pe_err("PE Session does not exist for given sme session_id %d", + send_req->sessionId); + 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(session_entry)) { + pe_err("roaming in progress, reject mgmt! for session %d", + send_req->sessionId); + 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(SIR_MAC_ACTION_TDLS, + SIR_MAC_ACTION_TX, SIR_MAC_MGMT_ACTION, + send_req->reqType, send_req->peer_mac.bytes); + + switch (send_req->reqType) { + case SIR_MAC_TDLS_DIS_REQ: + 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 SIR_MAC_TDLS_DIS_RSP: + 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->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq))); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_REQ: + 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->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_RSP: + 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->statusCode, &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_CNF: + pe_debug("Transmit Setup Confirm Frame"); + lim_send_tdls_link_setup_cnf_frame(mac_ctx, + send_req->peer_mac, send_req->dialog, + send_req->peerCapability, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_TEARDOWN: + pe_debug("Transmit Teardown Frame"); + lim_send_tdls_teardown_frame(mac_ctx, + send_req->peer_mac, send_req->statusCode, + send_req->responder, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_PEER_TRAFFIC_IND: + break; + case SIR_MAC_TDLS_CH_SWITCH_REQ: + break; + case SIR_MAC_TDLS_CH_SWITCH_RSP: + break; + case SIR_MAC_TDLS_PEER_TRAFFIC_RSP: + 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->sessionId, + send_req->transactionId); + + return QDF_STATUS_SUCCESS; +} + +/* + * Once link is teardown, send Del Peer Ind to SME + */ +static QDF_STATUS lim_send_sme_tdls_del_sta_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + struct qdf_mac_addr peerMac, + tDphHashNode *pStaDs, uint8_t status) +{ + struct scheduler_msg mmhMsg = { 0 }; + tSirTdlsDelStaRsp *pDelSta = NULL; + + mmhMsg.type = eWNI_SME_TDLS_DEL_STA_RSP; + + pDelSta = qdf_mem_malloc(sizeof(tSirTdlsDelStaRsp)); + if (NULL == pDelSta) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + pDelSta->sessionId = sessionId; + pDelSta->statusCode = status; + if (pStaDs) { + pDelSta->staId = pStaDs->staIndex; + } else + pDelSta->staId = STA_INVALID_IDX; + + qdf_copy_macaddr(&pDelSta->peermac, &peerMac); + + pDelSta->length = sizeof(tSirTdlsDelStaRsp); + pDelSta->messageType = eWNI_SME_TDLS_DEL_STA_RSP; + pDelSta->psoc = pMac->psoc; + mmhMsg.bodyptr = pDelSta; + mmhMsg.callback = tgt_tdls_del_peer_rsp; + return scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &mmhMsg); +} + +/* + * Process Send Mgmt Request from SME and transmit to AP. + */ +QDF_STATUS lim_process_sme_tdls_add_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + /* get all discovery request parameters */ + tSirTdlsAddStaReq *pAddStaReq = (tSirTdlsAddStaReq *) pMsgBuf; + tpPESession psessionEntry; + uint8_t sessionId; + + pe_debug("TDLS Add STA Request Received"); + psessionEntry = + pe_find_session_by_bssid(pMac, pAddStaReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("PE Session does not exist for given sme sessionId: %d", + pAddStaReq->sessionId); + goto lim_tdls_add_sta_error; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_err("send mgmt received in wrong system Role: %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + goto lim_tdls_add_sta_error; + } + + if (lim_is_roam_synch_in_progress(psessionEntry)) { + pe_err("roaming in progress, reject add sta! for session %d", + pAddStaReq->sessionId); + 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 ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + pe_err("send mgmt received in invalid LIMsme state: %d", + psessionEntry->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(pMac, pAddStaReq, psessionEntry)) { + 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(pMac, + pAddStaReq->sessionId, + pAddStaReq->peermac.bytes, + (pAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE), + NULL, QDF_STATUS_E_FAILURE); + + return QDF_STATUS_SUCCESS; +} + +/* + * Process Del Sta Request from SME . + */ +QDF_STATUS lim_process_sme_tdls_del_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + /* get all discovery request parameters */ + tSirTdlsDelStaReq *pDelStaReq = (tSirTdlsDelStaReq *) pMsgBuf; + tpPESession psessionEntry; + uint8_t sessionId; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + pe_debug("TDLS Delete STA Request Received"); + psessionEntry = + pe_find_session_by_bssid(pMac, pDelStaReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + pe_err("PE Session does not exist for given sme sessionId: %d", + pDelStaReq->sessionId); + lim_send_sme_tdls_del_sta_rsp(pMac, pDelStaReq->sessionId, + pDelStaReq->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(psessionEntry)) { + pe_err("Del sta received in wrong system Role %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + goto lim_tdls_del_sta_error; + } + + if (lim_is_roam_synch_in_progress(psessionEntry)) { + pe_err("roaming in progress, reject del sta! for session %d", + pDelStaReq->sessionId); + lim_send_sme_tdls_del_sta_rsp(pMac, pDelStaReq->sessionId, + pDelStaReq->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 ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + + pe_err("Del Sta received in invalid LIMsme state: (%d", + psessionEntry->limSmeState); + goto lim_tdls_del_sta_error; + } + + status = lim_tdls_del_sta(pMac, pDelStaReq->peermac, + psessionEntry, true); + if (status == QDF_STATUS_SUCCESS) + return status; + +lim_tdls_del_sta_error: + lim_send_sme_tdls_del_sta_rsp(pMac, psessionEntry->smeSessionId, + pDelStaReq->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(tpAniSirGlobal p_mac, + tpPESession 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 + */ + pe_debug("Delete all the TDLS peer connected"); + 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 (NULL == stads) + goto skip; + + pe_debug("Deleting "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(stads->staAddr)); + + if (!lim_is_roam_synch_in_progress(session_entry)) { + lim_send_deauth_mgmt_frame(p_mac, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + 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); + if (status != QDF_STATUS_SUCCESS) + pe_debug("peer " QDF_MAC_ADDR_STR " not found", + QDF_MAC_ADDR_ARRAY(stads->staAddr)); + + 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(tpPESession session_entry, bool value) +{ + session_entry->tdls_send_set_state_disable = value; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + pe_debug("Enter"); + + if (NULL == 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->smeSessionId); + + if (lim_is_roam_synch_in_progress(session_entry)) + 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; + pe_debug("Exit"); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_sme_del_all_tdls_peers(): process delete tdls peers + * @p_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(tpAniSirGlobal p_mac, + uint32_t *msg_buf) +{ + struct sir_del_all_tdls_peers *msg; + tpPESession session_entry; + uint8_t session_id; + + msg = (struct sir_del_all_tdls_peers *)msg_buf; + if (msg == NULL) { + pe_err("NULL msg"); + return QDF_STATUS_E_FAILURE; + } + + session_entry = pe_find_session_by_bssid(p_mac, + msg->bssid.bytes, &session_id); + if (NULL == session_entry) { + pe_err("NULL psessionEntry"); + 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg, + tpPESession 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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..ddd801fa08fac5d59077344e48d0a760b53ae2c8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c @@ -0,0 +1,468 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_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" + +#define LIM_GET_NOISE_MAX_TRY 5 + +#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, + tpPESession 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 + * @beacon_struct: beacon structure + * @session: A pointer to session entry. + * + * Return: None + */ +static void get_ese_version_ie_probe_response(tpAniSirGlobal mac_ctx, + tpSirProbeRespBeacon beacon_struct, + tpPESession session) +{ + if (mac_ctx->roam.configParam.isEseIniFeatureEnabled) + 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, + tpPESession session) +{ + +} + +static inline void get_ese_version_ie_probe_response(tpAniSirGlobal mac_ctx, + tpSirProbeRespBeacon beacon_struct, + tpPESession session) +{ +} +#endif + +#ifdef WLAN_FEATURE_11AX +static void lim_extract_he_op(tpPESession session, + tSirProbeRespBeacon *beacon_struct) +{ + if (session->he_capable && beacon_struct->he_op.present) { + qdf_mem_copy(&session->he_op, &beacon_struct->he_op, + sizeof(session->he_op)); + pe_debug("he_op.bss_color %d", session->he_op.bss_color); + pe_debug("he_op.default_pe %d", session->he_op.default_pe); + } +} + +static bool lim_check_he_80_mcs11_supp(tpPESession session, + tSirProbeRespBeacon *beacon_struct) { + uint8_t rx_mcs_map; + uint8_t tx_mcs_map; + rx_mcs_map = beacon_struct->he_cap.rx_he_mcs_map_lt_80; + tx_mcs_map = beacon_struct->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; +} + +static void lim_check_he_ldpc_cap(tpPESession session, + tSirProbeRespBeacon *beacon_struct) +{ + if (session->he_capable && beacon_struct->he_cap.present) { + if (beacon_struct->he_cap.ldpc_coding) + return; + else if ((session->ch_width == CH_WIDTH_20MHZ) && + !lim_check_he_80_mcs11_supp(session, + beacon_struct)) + return; + session->he_capable = false; + pe_err("LDPC check failed for HE operation"); + if (session->vhtCapability) { + session->dot11mode = WNI_CFG_DOT11_MODE_11AC; + pe_debug("Update dot11mode to 11ac"); + } else { + session->dot11mode = WNI_CFG_DOT11_MODE_11N; + pe_debug("Update dot11mode to 11N"); + } + } +} +#else +static inline void lim_extract_he_op(tpPESession session, + tSirProbeRespBeacon *beacon_struct) +{} +static void lim_check_he_ldpc_cap(tpPESession session, + tSirProbeRespBeacon *beacon_struct) +{} +#endif + +static 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); +} +/** + * 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 + * @prop_cap: Pointer to prop info IE. + * @uapsd: pointer to uapsd + * @local_constraint: Pointer to local power constraint. + * @session: A pointer to session entry. + * + * 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(tpAniSirGlobal mac_ctx, uint8_t *p_ie, + uint16_t ie_len, uint8_t *qos_cap, uint16_t *prop_cap, uint8_t *uapsd, + int8_t *local_constraint, tpPESession session) +{ + tSirProbeRespBeacon *beacon_struct; + uint32_t enable_txbf_20mhz; + QDF_STATUS cfg_get_status = QDF_STATUS_E_FAILURE; + 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; + + beacon_struct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == beacon_struct) { + pe_err("Unable to allocate memory"); + return; + } + + *qos_cap = 0; + *prop_cap = 0; + *uapsd = 0; + pe_debug("In lim_extract_ap_capability: The IE's being received:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + p_ie, ie_len); + if (sir_parse_beacon_ie(mac_ctx, beacon_struct, p_ie, + (uint32_t) ie_len) != QDF_STATUS_SUCCESS) { + pe_err("sir_parse_beacon_ie failed to parse beacon"); + qdf_mem_free(beacon_struct); + return; + } + + 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->propIEinfo.capabilityPresent) + *prop_cap = beacon_struct->propIEinfo.capability; + if (beacon_struct->HTCaps.present) + mac_ctx->lim.htCapabilityPresentInBeacon = 1; + else + mac_ctx->lim.htCapabilityPresentInBeacon = 0; + + pe_debug("Bcon: VHTCap.present: %d SU Beamformer: %d BSS_VHT_CAPABLE: %d", + beacon_struct->VHTCaps.present, + beacon_struct->VHTCaps.suBeamFormerCap, + IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps)); + + vht_op = &beacon_struct->VHTOperation; + 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) { + cfg_get_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + &enable_txbf_20mhz); + if ((QDF_IS_STATUS_SUCCESS(cfg_get_status)) && + (false == enable_txbf_20mhz)) + session->vht_config.su_beam_formee = 0; + } 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 ((ap_bcon_ch_width == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && + vht_op->chanCenterFreqSeg2) { + new_ch_width_dfn = true; + if (vht_op->chanCenterFreqSeg2 > + vht_op->chanCenterFreqSeg1) + center_freq_diff = vht_op->chanCenterFreqSeg2 - + vht_op->chanCenterFreqSeg1; + else + center_freq_diff = vht_op->chanCenterFreqSeg1 - + vht_op->chanCenterFreqSeg2; + 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; + } + + fw_vht_ch_wd = wma_get_vht_ch_width(); + vht_ch_wd = QDF_MIN(fw_vht_ch_wd, ap_bcon_ch_width); + /* + * 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) && + mac_ctx->sta_prefer_80MHz_over_160MHz) { + if (!(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->chanCenterFreqSeg1: center freq of 80MHz/160MHz/ + * primary 80 in 80+80MHz. + * + * vht_op->chanCenterFreqSeg2: center freq of secondary 80 + * in 80+80MHz. + * + * VHT OP IE NEW definition: + * vht_op->chanCenterFreqSeg1: 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->chanCenterFreqSeg2: center freq of secondary 80 + * in 80+80MHz/center freq of 160MHz. + */ + session->ch_center_freq_seg0 = vht_op->chanCenterFreqSeg1; + session->ch_center_freq_seg1 = vht_op->chanCenterFreqSeg2; + 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->chanCenterFreqSeg1; + session->ch_center_freq_seg0 = + lim_get_80Mhz_center_channel( + beacon_struct->channelNumber); + } + } 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; + } + } else if (vht_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + /* DUT or AP supports only 80MHz */ + if (ap_bcon_ch_width == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ && + !new_ch_width_dfn) + /* AP is in 160MHz mode */ + session->ch_center_freq_seg0 = + lim_get_80Mhz_center_channel( + beacon_struct->channelNumber); + else + session->ch_center_freq_seg1 = 0; + } + session->ch_width = vht_ch_wd + 1; + pe_debug("cntr_freq0: %d cntr_freq1: %d width: %d", + session->ch_center_freq_seg0, + session->ch_center_freq_seg1, + session->ch_width); + if (CH_WIDTH_80MHZ < session->ch_width) { + session->vht_config.su_beam_former = 0; + session->nss = 1; + } + } + + 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) { + if (CH_WIDTH_160MHZ > session->ch_width) + session->gLimOperatingMode.chanWidth = + session->ch_width; + else + session->gLimOperatingMode.chanWidth = + CH_WIDTH_160MHZ; + } else { + pe_err("AP does not support op_mode rx"); + } + } + lim_check_he_ldpc_cap(session, beacon_struct); + lim_extract_he_op(session, beacon_struct); + /* Extract the UAPSD flag from WMM Parameter element */ + if (beacon_struct->wmeEdcaPresent) + *uapsd = beacon_struct->edcaParams.qosInfo.uapsd; + + if (mac_ctx->roam.configParam.allow_tpc_from_ap) { + if (beacon_struct->powerConstraintPresent) { + *local_constraint -= + beacon_struct->localPowerConstraint. + localPowerConstraints; + } else { + get_local_power_constraint_probe_response( + beacon_struct, local_constraint, session); + } + } + + 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); + 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 pMac - 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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..69026abda0dcce16e3b7c3de735019b70956f66c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +/* + * + * 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 + +/* Function templates */ +void limQuietBss(tpAniSirGlobal, uint32_t); +void lim_cleanupMeasData(tpAniSirGlobal); +void limDeleteMeasTimers(tpAniSirGlobal); +void limStopMeasTimers(tpAniSirGlobal pMac); +void lim_cleanupMeasResources(tpAniSirGlobal); +void limRestorePreLearnState(tpAniSirGlobal); +void limCollectMeasurementData(tpAniSirGlobal, uint32_t *, tpSchBeaconStruct); +void limCollectRSSI(tpAniSirGlobal); +void limDeleteCurrentBssWdsNode(tpAniSirGlobal); +uint32_t limComputeAvg(tpAniSirGlobal, uint32_t, uint32_t); + +/* / Function to extract AP's HCF capability from IE fields */ +void lim_extract_ap_capability(tpAniSirGlobal, uint8_t *, uint16_t, uint8_t *, + uint16_t *, uint8_t *, int8_t *, tpPESession); + +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode); + +#endif /* __LIM_PROP_EXTS_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..236b9642279c68f5b6cecda8589f0635d5ca75ca --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c @@ -0,0 +1,505 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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 "cfg_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_sta_hash_api.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#include "qdf_types.h" +#include "wma_types.h" +#include "lim_types.h" + +/** + * lim_update_re_assoc_globals() - Update reassoc global data + * @pMac: Global MAC context + * @pAssocRsp: Reassociation response data + * @psessionEntry: PE Session + * + * This function is called to Update the Globals (LIM) during ReAssoc. + * + * Return: None + */ + +void lim_update_re_assoc_globals(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry) +{ + /* Update the current Bss Information */ + qdf_mem_copy(psessionEntry->bssId, + psessionEntry->limReAssocbssId, sizeof(tSirMacAddr)); + psessionEntry->currentOperChannel = psessionEntry->limReassocChannelId; + psessionEntry->htSecondaryChannelOffset = + psessionEntry->reAssocHtSupportedChannelWidthSet; + psessionEntry->htRecommendedTxWidthSet = + psessionEntry->reAssocHtRecommendedTxWidthSet; + psessionEntry->htSecondaryChannelOffset = + psessionEntry->reAssocHtSecondaryChannelOffset; + psessionEntry->limCurrentBssCaps = psessionEntry->limReassocBssCaps; + psessionEntry->limCurrentBssQosCaps = + psessionEntry->limReassocBssQosCaps; + psessionEntry->limCurrentBssPropCap = + psessionEntry->limReassocBssPropCap; + + qdf_mem_copy((uint8_t *) &psessionEntry->ssId, + (uint8_t *) &psessionEntry->limReassocSSID, + psessionEntry->limReassocSSID.length + 1); + + /* Store assigned AID for TIM processing */ + psessionEntry->limAID = pAssocRsp->aid & 0x3FFF; + /** Set the State Back to ReAssoc Rsp*/ + psessionEntry->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + +} + +/** + * @lim_handle_del_bss_in_re_assoc_context() - DEL BSS during reassociation + * @pMac: Global MAC Context + * @pStaDs: Station Hash entry + * @psessionEntry: 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(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + tpSirBssDescription bss_desc; + /* + * Skipped the DeleteDPH Hash Entry as we need it for the new BSS + * Set the MlmState to IDLE + */ + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + /* Update PE session Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + switch (psessionEntry->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: + { + tpSirAssocRsp assocRsp; + tpDphHashNode pStaDs; + QDF_STATUS retStatus = QDF_STATUS_SUCCESS; + tpSchBeaconStruct beacon_struct; + + beacon_struct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == beacon_struct) { + pe_err("beaconStruct alloc failed"); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_delete_dph_hash_entry(pMac, psessionEntry->bssId, + DPH_STA_HASH_INDEX_PEER, psessionEntry); + goto error; + } + /* Delete the older STA Table entry */ + lim_delete_dph_hash_entry(pMac, psessionEntry->bssId, + DPH_STA_HASH_INDEX_PEER, psessionEntry); + /* + * Add an entry for AP to hash table + * maintained by DPH module + */ + pStaDs = dph_add_hash_entry(pMac, + psessionEntry->limReAssocbssId, + DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + pe_err("could not add hash entry at DPH for"); + lim_print_mac_addr(pMac, + psessionEntry->limReAssocbssId, LOGE); + 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) psessionEntry->limAssocResponseData; + lim_update_assoc_sta_datas(pMac, pStaDs, assocRsp, + psessionEntry); + lim_update_re_assoc_globals(pMac, assocRsp, psessionEntry); + bss_desc = &psessionEntry->pLimReAssocReq->bssDescription; + lim_extract_ap_capabilities(pMac, + (uint8_t *) bss_desc->ieFields, + lim_get_ielen_from_bss_description(bss_desc), + beacon_struct); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, + beacon_struct, + psessionEntry); + if (beacon_struct->erpPresent) { + if (beacon_struct->erpIEInfo.barkerPreambleMode) + psessionEntry->beaconParams.fShortPreamble = 0; + else + psessionEntry->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(pMac, assocRsp, beacon_struct, + bss_desc, + false, psessionEntry)) { + 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 = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + qdf_mem_free(assocRsp); + pMac->lim.gLimAssocResponseData = NULL; + qdf_mem_free(beacon_struct); + goto error; + } + qdf_mem_free(assocRsp); + qdf_mem_free(beacon_struct); + psessionEntry->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(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * @lim_handle_add_bss_in_re_assoc_context() - ADD BSS during reassociation + * @pMac: Global MAC Context + * @pStaDs: Station Hash entry + * @psessionEntry: 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(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + /** Skipped the DeleteDPH Hash Entry as we need it for the new BSS*/ + /** Set the MlmState to IDLE*/ + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + switch (psessionEntry->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: { + tpSirAssocRsp assocRsp; + tpDphHashNode pStaDs; + QDF_STATUS retStatus = QDF_STATUS_SUCCESS; + tSchBeaconStruct *pBeaconStruct; + + pBeaconStruct = + qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + pe_err("Unable to allocate memory"); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + goto Error; + } + /* Get the AP entry from DPH hash table */ + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + 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) psessionEntry->limAssocResponseData; + lim_update_assoc_sta_datas(pMac, pStaDs, assocRsp, + psessionEntry); + lim_update_re_assoc_globals(pMac, assocRsp, psessionEntry); + lim_extract_ap_capabilities(pMac, + (uint8_t *) psessionEntry-> + pLimReAssocReq->bssDescription. + ieFields, + lim_get_ielen_from_bss_description + (&psessionEntry-> + pLimReAssocReq-> + bssDescription), + pBeaconStruct); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, + pBeaconStruct, + psessionEntry); + + if (pBeaconStruct->erpPresent) { + if (pBeaconStruct->erpIEInfo.barkerPreambleMode) + psessionEntry->beaconParams. + fShortPreamble = 0; + else + psessionEntry->beaconParams. + fShortPreamble = 1; + } + + psessionEntry->isNonRoamReassoc = 1; + if (QDF_STATUS_SUCCESS != + lim_sta_send_add_bss(pMac, assocRsp, pBeaconStruct, + &psessionEntry->pLimReAssocReq-> + bssDescription, true, + psessionEntry)) { + 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 = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + qdf_mem_free(assocRsp); + pMac->lim.gLimAssocResponseData = NULL; + qdf_mem_free(pBeaconStruct); + goto Error; + } + qdf_mem_free(assocRsp); + psessionEntry->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(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_is_reassoc_in_progress() - Check if reassoiciation is in progress + * @pMac: Global MAC Context + * @psessionEntry: PE Session + * + * Return: true When STA is waiting for Reassoc response from AP + * else false + */ +bool lim_is_reassoc_in_progress(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (psessionEntry == NULL) + return false; + + if (LIM_IS_STA_ROLE(psessionEntry) && + (psessionEntry->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(tpAniSirGlobal mac_ctx, uint16_t assoc_id, + tpPESession session_entry) +{ + tpAddStaParams add_sta_params = NULL; + QDF_STATUS ret_code = QDF_STATUS_SUCCESS; + struct scheduler_msg msg_q = {0}; + + add_sta_params = session_entry->ftPEContext.pAddStaReq; + add_sta_params->assocId = assoc_id; + add_sta_params->smesessionId = session_entry->smeSessionId; + + msg_q.type = WMA_ADD_STA_REQ; + msg_q.reserved = 0; + msg_q.bodyptr = add_sta_params; + msg_q.bodyval = 0; + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_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 + * @pMac: Global MAC Context + * @resultCode: Assoc response result + * @protStatusCode: Internal protocol status code + * @psessionEntry: 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(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint16_t protStatusCode, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + + pe_debug("sessionid: %d protStatusCode: %d resultCode: %d", + psessionEntry->smeSessionId, protStatusCode, resultCode); + + psessionEntry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, eLIM_REASSOC_FAIL_TIMER); + + lim_set_channel(pMac, psessionEntry->currentOperChannel, + psessionEntry->ch_center_freq_seg0, + psessionEntry->ch_center_freq_seg1, + psessionEntry->ch_width, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, + 0, 0); + + /* @ToDo:Need to Integrate the STOP the Dataxfer to AP from 11H code */ + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_post_reassoc_failure() - Post failure message to SME + * @pMac: Global MAC Context + * @resultCode: Result Code + * @protStatusCode: Protocol Status Code + * @psessionEntry: PE Session + * + * Return: None + */ +void lim_post_reassoc_failure(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint16_t protStatusCode, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + + psessionEntry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + lim_deactivate_and_change_timer(pMac, eLIM_REASSOC_FAIL_TIMER); + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..a3b1395f8028d278048e51537dc919feed609fcd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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(tpAniSirGlobal mac_ctx) +{ + uint32_t cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + &cfg_value) != QDF_STATUS_SUCCESS) + pe_warn("could not retrieve ReassocFailureTimeout value"); + + cfg_value = SYS_MS_TO_TICKS(cfg_value); + /* Create Association failure timer and activate it later */ + if (tx_timer_create(mac_ctx, + &mac_ctx->lim.limTimers.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.limTimers.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.limTimers.gLimReassocFailureTimer); + return TX_TIMER_ERROR; +} + +void lim_delete_timers_host_roam(tpAniSirGlobal mac_ctx) +{ + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + + /* 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(tpAniSirGlobal mac_ctx) +{ + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + + /* 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(tpAniSirGlobal 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.limTimers.gLimReassocFailureTimer) != + TX_SUCCESS) + pe_warn("unable to deactivate Reassoc fail timer"); + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + &val) != QDF_STATUS_SUCCESS) + pe_warn("could not get ReassocFailureTimeout val"); + + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&mac_ctx->lim.limTimers.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.limTimers.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.limTimers.gLimFTPreAuthRspTimer, + val, 0) != TX_SUCCESS) { + pe_err("Unable to change Join Failure timer"); + return; + } + break; + } +} + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..f2cc1a1d9b1a1c2fa058e0b0c265e949f00c4052 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c @@ -0,0 +1,200 @@ +/* + * 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. + */ + +/* + * 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 pMac - 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(tpAniSirGlobal pMac, + tSirBssDescription *pBssDescr, + tpSirProbeRespBeacon pBPR, + uint8_t *pRxPacketInfo, uint8_t fScanning) +{ + uint8_t *pBody; + uint32_t ieLen = 0; + tpSirMacMgmtHdr pHdr; + uint8_t channelNum; + uint8_t rxChannel; + 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; + rxChannel = WMA_GET_RX_CH(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + rfBand = WMA_GET_RX_RFBAND(pRxPacketInfo); + + /** + * Length of BSS desription is without length of + * length itself and length of pointer that holds ieFields. + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + pBssDescr->length = (uint16_t)(offsetof(tSirBssDescription, ieFields[0]) + - sizeof(pBssDescr->length) + ieLen); + + /* Copy BSS Id */ + qdf_mem_copy((uint8_t *) &pBssDescr->bssId, + (uint8_t *) pHdr->bssId, sizeof(tSirMacAddr)); + + /* Copy Timestamp, Beacon Interval and Capability Info */ + pBssDescr->scansystimensec = qdf_get_bootbased_boottime_ns(); + + 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 " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(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. + */ + pBssDescr->channelId = lim_get_channel_from_beacon(pMac, pBPR); + + pBssDescr->channelIdSelf = pBssDescr->channelId; + pBssDescr->rx_channel = rxChannel; + + /* set the network type in bss description */ + channelNum = pBssDescr->channelId; + pBssDescr->nwType = + lim_get_nw_type(pMac, channelNum, 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); + + /* SINR no longer reported by HW */ + pBssDescr->sinr = 0; + pe_debug(MAC_ADDRESS_STR " rssi: normalized: %d, absolute: %d", + MAC_ADDR_ARRAY(pHdr->bssId), pBssDescr->rssi, + pBssDescr->rssi_raw); + + pBssDescr->received_time = (uint64_t)qdf_mc_timer_get_system_time(); + pBssDescr->tsf_delta = WMA_GET_RX_TSF_DELTA(pRxPacketInfo); + pBssDescr->seq_ctrl = pHdr->seqControl; + + pe_debug("Received %s from BSSID: %pM tsf_delta = %u Seq Num: %x ssid:%.*s, rssi: %d", + pBssDescr->fProbeRsp ? "Probe Rsp" : "Beacon", pHdr->bssId, + pBssDescr->tsf_delta, ((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | pHdr->seqControl.seqNumLo), + pBPR->ssId.length, pBPR->ssId.ssId, pBssDescr->rssi_raw); + + if (fScanning) { + rrm_get_start_tsf(pMac, 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]; + } + +#ifdef FEATURE_WLAN_ESE + pBssDescr->QBSSLoad_present = false; + pBssDescr->QBSSLoad_avail = 0; + if (pBPR->QBSSLoad.present) { + pBssDescr->QBSSLoad_present = true; + pBssDescr->QBSSLoad_avail = pBPR->QBSSLoad.avail; + } +#endif + /* 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->channelNumber = pBssDescr->channelId; + pMac->lim.beacon_probe_rsp_cnt_per_scan++; + + return; +} /*** end lim_collect_bss_description() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..cdaad9dabcfc24ec4ebc4e4dd4b958c0c57e0d38 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + +/* + * 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 */ +uint8_t lim_scan_hash_function(tSirMacAddr); +void lim_restore_pre_scan_state(tpAniSirGlobal); +void lim_copy_scan_result(tpAniSirGlobal, uint8_t *); +void lim_collect_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pBssDescr, + tpSirProbeRespBeacon pBPR, + uint8_t *pRxPacketInfo, uint8_t fScanning); +#endif /* __LIM_SCAN_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..5328fb7028e5f06b00df2273a78642bf373ca3c4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c @@ -0,0 +1,1038 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_api.h" + +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#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(tpAniSirGlobal pMac, tAniAuthType authType, + tpPESession psessionEntry) +{ + uint32_t algoEnable, privacyOptImp; + + if (authType == eSIR_OPEN_SYSTEM) { + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((psessionEntry->authType == eSIR_OPEN_SYSTEM) + || (psessionEntry->authType == eSIR_AUTO_SWITCH)) + return true; + else + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + &algoEnable) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve AuthAlgo1 Enable value"); + + return false; + } else + return algoEnable > 0 ? true : false; + } else { + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((psessionEntry->authType == eSIR_SHARED_KEY) + || (psessionEntry->authType == eSIR_AUTO_SWITCH)) + algoEnable = true; + else + algoEnable = false; + + } else + + if (wlan_cfg_get_int + (pMac, WNI_CFG_SHARED_KEY_AUTH_ENABLE, + &algoEnable) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve AuthAlgo2 Enable value"); + + return false; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + privacyOptImp = psessionEntry->privacy; + } else + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, + &privacyOptImp) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve PrivacyOptImplemented value"); + + return false; + } + 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 pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_init_pre_auth_list(tpAniSirGlobal pMac) +{ + pMac->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 pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_delete_pre_auth_list(tpAniSirGlobal pMac) +{ + struct tLimPreAuthNode *pCurrNode, *pTempNode; + + pCurrNode = pTempNode = pMac->lim.pLimPreAuthList; + while (pCurrNode != NULL) { + pTempNode = pCurrNode->next; + lim_release_pre_auth_node(pMac, pCurrNode); + + pCurrNode = pTempNode; + } + pMac->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(tpAniSirGlobal pMac, + tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pTempNode = pMac->lim.pLimPreAuthList; + + while (pTempNode != NULL) { + 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() ***/ + +/** + * 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(tpAniSirGlobal 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 == NULL) + return auth_node_freed; + + while (temp_node != NULL) { + 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 pMac - 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(tpAniSirGlobal pMac, struct tLimPreAuthNode *pAuthNode) +{ + pMac->lim.gLimNumPreAuthContexts++; + + pAuthNode->next = pMac->lim.pLimPreAuthList; + + pMac->lim.pLimPreAuthList = pAuthNode; +} /*** end lim_add_pre_auth_node() ***/ + +/** + * lim_release_pre_auth_node + * + ***FUNCTION: + * This function is called to realease the acquired + * pre auth node from list. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pAuthNode - Pointer to Pre Auth node to be released + * @return None + */ + +void lim_release_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthNode pAuthNode) +{ + pAuthNode->fFree = 1; + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, + eLIM_PRE_AUTH_CLEANUP_TIMER)); + tx_timer_deactivate(&pAuthNode->timer); + pMac->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 pMac - 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(tpAniSirGlobal pMac, tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pPrevNode, *pTempNode; + + pTempNode = pPrevNode = pMac->lim.pLimPreAuthList; + + if (pTempNode == NULL) + return; + + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + /* First node to be deleted */ + + pMac->lim.pLimPreAuthList = pTempNode->next; + + pe_debug("first node to delete, Release data entry: %pK id %d peer", + pTempNode, pTempNode->authNodeIdx); + lim_print_mac_addr(pMac, macAddr, LOGD); + lim_release_pre_auth_node(pMac, pTempNode); + + return; + } + + pTempNode = pTempNode->next; + + while (pTempNode != NULL) { + 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", + pTempNode, pTempNode->authNodeIdx); + lim_print_mac_addr(pMac, macAddr, LOG1); + lim_release_pre_auth_node(pMac, pTempNode); + + return; + } + + pPrevNode = pTempNode; + pTempNode = pTempNode->next; + } + + pe_err("peer not found in pre-auth list, addr= "); + lim_print_mac_addr(pMac, macAddr, LOGE); + +} /*** 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 pMac - Pointer to Global MAC structure + * @param resultCode - result of authentication attempt + * @return None + */ + +void +lim_restore_from_auth_state(tpAniSirGlobal pMac, tSirResultCodes resultCode, + uint16_t protStatusCode, tpPESession sessionEntry) +{ + tSirMacAddr currentBssId; + tLimMlmAuthCnf mlmAuthCnf; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_AUTH_COMP_EVENT, sessionEntry, + resultCode, protStatusCode); +#endif + + qdf_mem_copy((uint8_t *) &mlmAuthCnf.peerMacAddr, + (uint8_t *) &pMac->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + mlmAuthCnf.authType = pMac->lim.gpLimMlmAuthReq->authType; + mlmAuthCnf.resultCode = resultCode; + mlmAuthCnf.protStatusCode = protStatusCode; + + /* Update PE session ID */ + mlmAuthCnf.sessionId = sessionEntry->peSessionId; + + /* / Free up buffer allocated */ + /* / for pMac->lim.gLimMlmAuthReq */ + qdf_mem_free(pMac->lim.gpLimMlmAuthReq); + pMac->lim.gpLimMlmAuthReq = NULL; + + sessionEntry->limMlmState = sessionEntry->limPrevMlmState; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, + sessionEntry->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 + */ + pMac->auth_ack_status = LIM_AUTH_ACK_RCD_SUCCESS; + + /* Auth retry and AUth failure timers are not started for SAE */ + /* 'Change' timer for future activations */ + if (tx_timer_running(&pMac->lim.limTimers. + g_lim_periodic_auth_retry_timer)) + lim_deactivate_and_change_timer(pMac, + eLIM_AUTH_RETRY_TIMER); + /* 'Change' timer for future activations */ + if (tx_timer_running(&pMac->lim.limTimers.gLimAuthFailureTimer)) + lim_deactivate_and_change_timer(pMac, + eLIM_AUTH_FAIL_TIMER); + + sir_copy_mac_addr(currentBssId, sessionEntry->bssId); + + if (sessionEntry->limSmeState == eLIM_SME_WT_PRE_AUTH_STATE) { + pMac->lim.gLimPreAuthChannelNumber = 0; + } + + lim_post_sme_message(pMac, 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 pMac 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(tpAniSirGlobal pMac, 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; + + /* 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 pMac 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(tpAniSirGlobal pMac, 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() ******/ + +/** + * lim_post_sme_set_keys_cnf + * + * A utility API to send MLM_SETKEYS_CNF to SME + */ +void lim_post_sme_set_keys_cnf(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + tLimMlmSetKeysCnf *mlmSetKeysCnf) +{ + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + qdf_copy_macaddr(&mlmSetKeysCnf->peer_macaddr, + &pMlmSetKeysReq->peer_macaddr); + + /* Free up buffer allocated for mlmSetKeysReq */ + qdf_mem_zero(pMlmSetKeysReq, sizeof(tLimMlmSetKeysReq)); + qdf_mem_free(pMlmSetKeysReq); + pMac->lim.gpLimMlmSetKeysReq = NULL; + + lim_post_sme_message(pMac, + LIM_MLM_SETKEYS_CNF, (uint32_t *) mlmSetKeysCnf); +} + +/** + * lim_send_set_bss_key_req() + * + ***FUNCTION: + * This function is called from lim_process_mlm_set_keys_req(), + * when PE is trying to setup the Group Keys related + * to a specified encryption type + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer + * @return none + */ +void lim_send_set_bss_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + tpPESession psessionEntry) +{ + struct scheduler_msg msgQ = {0}; + tpSetBssKeyParams pSetBssKeyParams = NULL; + tLimMlmSetKeysCnf mlmSetKeysCnf; + QDF_STATUS retCode; + uint32_t val = 0; + + if (pMlmSetKeysReq->numKeys > SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + pe_debug("numKeys = %d is more than SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS", + pMlmSetKeysReq->numKeys); + + /* Respond to SME with error code */ + mlmSetKeysCnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* Package WMA_SET_BSSKEY_REQ message parameters */ + + pSetBssKeyParams = qdf_mem_malloc(sizeof(tSetBssKeyParams)); + if (NULL == pSetBssKeyParams) { + pe_err("Unable to allocate memory during SET_BSSKEY"); + + /* Respond to SME with error code */ + mlmSetKeysCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + /* Update the WMA_SET_BSSKEY_REQ parameters */ + pSetBssKeyParams->bssIdx = psessionEntry->bssIdx; + pSetBssKeyParams->encType = pMlmSetKeysReq->edType; + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) + pe_warn("Unable to read WNI_CFG_SINGLE_TID_RC"); + + pSetBssKeyParams->singleTidRc = (uint8_t) val; + + /* Update PE session Id */ + pSetBssKeyParams->sessionId = psessionEntry->peSessionId; + + pSetBssKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; + + if (pMlmSetKeysReq->key[0].keyId && + ((pMlmSetKeysReq->edType == eSIR_ED_WEP40) || + (pMlmSetKeysReq->edType == eSIR_ED_WEP104)) + ) { + /* IF the key id is non-zero and encryption type is WEP, Send all the 4 + * keys to HAL with filling the key at right index in pSetBssKeyParams->key. */ + pSetBssKeyParams->numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + qdf_mem_copy((uint8_t *) &pSetBssKeyParams-> + key[pMlmSetKeysReq->key[0].keyId], + (uint8_t *) &pMlmSetKeysReq->key[0], + sizeof(pMlmSetKeysReq->key[0])); + + } else { + pSetBssKeyParams->numKeys = pMlmSetKeysReq->numKeys; + qdf_mem_copy((uint8_t *) &pSetBssKeyParams->key, + (uint8_t *) &pMlmSetKeysReq->key, + sizeof(tSirKeys) * pMlmSetKeysReq->numKeys); + } + + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + msgQ.type = WMA_SET_BSSKEY_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pSetBssKeyParams; + msgQ.bodyval = 0; + + pe_debug("Sending WMA_SET_BSSKEY_REQ..."); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("Posting SET_BSSKEY to HAL failed, reason=%X", + retCode); + + /* Respond to SME with LIM_MLM_SETKEYS_CNF */ + mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + qdf_mem_zero(pSetBssKeyParams, sizeof(tSetBssKeyParams)); + qdf_mem_free(pSetBssKeyParams); + } else + return; /* Continue after WMA_SET_BSSKEY_RSP... */ + +end: + lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); + +} + +/** + * @function : lim_send_set_sta_key_req() + * + * @brief : This function is called from lim_process_mlm_set_keys_req(), + * when PE is trying to setup the Unicast Keys related + * to a specified STA with specified encryption type + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer + * @param staIdx STA index for which the keys are being set + * @param defWEPIdx The default WEP key index [0..3] + * @return none + */ +void lim_send_set_sta_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + uint16_t staIdx, + uint8_t defWEPIdx, + tpPESession sessionEntry, bool sendRsp) +{ + struct scheduler_msg msgQ = {0}; + tpSetStaKeyParams pSetStaKeyParams = NULL; + tLimMlmSetKeysCnf mlmSetKeysCnf; + QDF_STATUS retCode; + uint32_t val = 0; + + /* Package WMA_SET_STAKEY_REQ message parameters */ + pSetStaKeyParams = qdf_mem_malloc(sizeof(tSetStaKeyParams)); + if (NULL == pSetStaKeyParams) { + pe_err("Unable to allocate memory during SET_BSSKEY"); + goto fail; + } + + /* Update the WMA_SET_STAKEY_REQ parameters */ + pSetStaKeyParams->staIdx = staIdx; + pSetStaKeyParams->encType = pMlmSetKeysReq->edType; + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) + pe_warn("Unable to read WNI_CFG_SINGLE_TID_RC"); + + pSetStaKeyParams->singleTidRc = (uint8_t) val; + + /* Update PE session ID */ + pSetStaKeyParams->sessionId = sessionEntry->peSessionId; + + /** + * For WEP - defWEPIdx indicates the default WEP + * Key to be used for TX + * For all others, there's just one key that can + * be used and hence it is assumed that + * defWEPIdx = 0 (from the caller) + */ + + pSetStaKeyParams->defWEPIdx = defWEPIdx; + + pSetStaKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; + qdf_copy_macaddr(&pSetStaKeyParams->peer_macaddr, + &pMlmSetKeysReq->peer_macaddr); + + if (sendRsp == true) { + /** Store the Previous MlmState*/ + sessionEntry->limPrevMlmState = sessionEntry->limMlmState; + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + } + + if (LIM_IS_IBSS_ROLE(sessionEntry) + && !pMlmSetKeysReq->key[0].unicast) { + if (sendRsp == true) + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE; + msgQ.type = WMA_SET_STA_BCASTKEY_REQ; + } else { + if (sendRsp == true) + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_KEY_STATE; + msgQ.type = WMA_SET_STAKEY_REQ; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, + sessionEntry->limMlmState)); + + /** + * In the Case of WEP_DYNAMIC, ED_TKIP and ED_CCMP + * the Key[0] contains the KEY, so just copy that alone, + * for the case of WEP_STATIC the hal gets the key from cfg + */ + switch (pMlmSetKeysReq->edType) { + case eSIR_ED_WEP40: + case eSIR_ED_WEP104: + /* FIXME! Is this OK? */ + if (0 == pMlmSetKeysReq->numKeys) { + uint32_t i; + + for (i = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) { + qdf_mem_copy((uint8_t *) &pSetStaKeyParams-> + key[i], + (uint8_t *) &pMlmSetKeysReq-> + key[i], sizeof(tSirKeys)); + } + pSetStaKeyParams->wepType = eSIR_WEP_STATIC; + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_KEY_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + sessionEntry->peSessionId, + sessionEntry->limMlmState)); + } else { + /*This case the keys are coming from upper layer so need to fill the + * key at the default wep key index and send to the HAL */ + if (defWEPIdx < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + qdf_mem_copy((uint8_t *) &pSetStaKeyParams-> + key[defWEPIdx], + (uint8_t *) &pMlmSetKeysReq-> + key[0], + sizeof(pMlmSetKeysReq->key[0])); + pMlmSetKeysReq->numKeys = + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + } else { + pe_err("Wrong Key Index %d", defWEPIdx); + goto free_sta_key; + } + } + break; + case eSIR_ED_TKIP: + case eSIR_ED_CCMP: + case eSIR_ED_GCMP: + case eSIR_ED_GCMP_256: +#ifdef FEATURE_WLAN_WAPI + case eSIR_ED_WPI: +#endif + { + qdf_mem_copy((uint8_t *) &pSetStaKeyParams->key, + (uint8_t *) &pMlmSetKeysReq->key[0], + sizeof(tSirKeys)); + } + break; + default: + break; + } + + pSetStaKeyParams->sendRsp = sendRsp; + + msgQ.reserved = 0; + msgQ.bodyptr = pSetStaKeyParams; + msgQ.bodyval = 0; + + pe_debug("Sending WMA_SET_STAKEY_REQ..."); + MTRACE(mac_trace_msg_tx(pMac, sessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("Posting SET_STAKEY to HAL failed, reason=%X", + retCode); + goto free_sta_key; + } else + return; /* Continue after WMA_SET_STAKEY_RSP... */ + +free_sta_key: + qdf_mem_zero(pSetStaKeyParams, sizeof(tSetStaKeyParams)); + qdf_mem_free(pSetStaKeyParams); +fail: + /* Respond to SME with LIM_MLM_SETKEYS_CNF */ + mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + if (sendRsp == true) + lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..4974e7808df6db42734dc7cf11670a3a8d20811d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * + * 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(tpAniSirGlobal, tAniAuthType, tpPESession); + +/* MAC based authentication related functions */ +void lim_init_pre_auth_list(tpAniSirGlobal); +void lim_delete_pre_auth_list(tpAniSirGlobal); +struct tLimPreAuthNode *lim_search_pre_auth_list(tpAniSirGlobal, tSirMacAddr); +void lim_add_pre_auth_node(tpAniSirGlobal, struct tLimPreAuthNode *); +void lim_delete_pre_auth_node(tpAniSirGlobal, tSirMacAddr); +void lim_release_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthNode pAuthNode); +void lim_restore_from_auth_state(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +uint8_t lim_delete_open_auth_pre_auth_node(tpAniSirGlobal 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(tpAniSirGlobal, uint8_t, uint8_t *, uint8_t *, + uint8_t *, uint32_t); +uint8_t lim_decrypt_auth_frame(tpAniSirGlobal, uint8_t *, uint8_t *, uint8_t *, + uint32_t, uint16_t); + +void lim_send_set_bss_key_req(tpAniSirGlobal, tLimMlmSetKeysReq *, tpPESession); +void lim_send_set_sta_key_req(tpAniSirGlobal, tLimMlmSetKeysReq *, uint16_t, uint8_t, + tpPESession, bool sendRsp); +void lim_post_sme_set_keys_cnf(tpAniSirGlobal, tLimMlmSetKeysReq *, + tLimMlmSetKeysCnf *); + +#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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..628748d8dabd2ad0808c3b624595f85b041a1f70 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c @@ -0,0 +1,843 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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 "cfg_api.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 "lim_sta_hash_api.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "lim_assoc_utils.h" +#include "lim_ft.h" +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif + +#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(tpAniSirGlobal mac_ctx, + tLimMlmReassocReq *mlm_reassoc_req, + tpPESession pe_session) +{ + static 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 sme_sessionid = 0; + bool vht_enabled = false; + tpSirMacMgmtHdr mac_hdr; + tftSMEContext *ft_sme_context; + + if (NULL == pe_session) + return; + + sme_sessionid = pe_session->smeSessionId; + + /* check this early to avoid unncessary operation */ + if (NULL == pe_session->pLimReAssocReq) + return; + + 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)); + + 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(mac_ctx, &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->pLimReAssocReq->spectrumMgtIndicator == true) { + 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 + * 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': + * + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+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 (NULL == 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 (pe_session->pLimReAssocReq->cckmIE.length) { + populate_dot11f_ese_cckm_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->cckmIE), + &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->roam.configParam.isEseIniFeatureEnabled) + populate_dot11f_ese_version(&frm.ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (pe_session->isESEconnection && + pe_session->pLimReAssocReq->isESEFeatureIniEnabled) { +#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 (pe_session->isESEconnection) { + 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 (pe_session->pLimReAssocReq->eseTspecInfo. + numTspecs) { + tSirMacESETSRSIE tsrs_ie; + + tsrs_ie.tsid = 0; + tsrs_ie.rates[0] = rate; + populate_dot11_tsrsie(mac_ctx, &tsrs_ie, + &frm.ESETrafStrmRateSet, + sizeof(uint8_t)); + } + } +#endif + } + + ft_sme_context = &mac_ctx->roam.roamSession[sme_sessionid].ftSmeContext; + if (pe_session->htCapability && + mac_ctx->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm.HTCaps); + } + if (pe_session->pLimReAssocReq->bssDescription.mdiePresent && + (ft_sme_context->addMDIE == true) +#if defined FEATURE_WLAN_ESE + && !pe_session->isESEconnection +#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); + } + + 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) + add_ie_len; + + pe_debug("FT IE Reassoc Req %d", + ft_sme_context->reassoc_ft_ies_length); + + if (pe_session->is11Rconnection) + ft_ies_length = ft_sme_context->reassoc_ft_ies_length; + + 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); + + lim_print_mac_addr(mac_ctx, pe_session->limReAssocbssId, LOGD); + /* 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->selfMacAddr); + 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->assocReq != NULL) { + qdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + pe_session->assocReqLen = 0; + } + + if (add_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + add_ie, add_ie_len); + payload += add_ie_len; + } + + pe_session->assocReq = qdf_mem_malloc(payload); + if (NULL == pe_session->assocReq) { + pe_err("Failed to alloc memory"); + } else { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assocReq, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + if (pe_session->is11Rconnection && ft_sme_context->reassoc_ft_ies) { + int i = 0; + + body = frame + bytes; + for (i = 0; i < ft_ies_length; i++) { + *body = ft_sme_context->reassoc_ft_ies[i]; + body++; + } + } + 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 ((NULL != pe_session->ftPEContext.pFTPreAuthReq) && + (BAND_5G == lim_get_rf_band( + pe_session->ftPEContext.pFTPreAuthReq->preAuthchannelNum))) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + else if ((BAND_5G == + lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == QDF_P2P_CLIENT_MODE) + || (pe_session->pePersona == QDF_P2P_GO_MODE)) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (NULL != pe_session->assocReq) { + qdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + pe_session->assocReqLen = 0; + } + if (ft_ies_length) { + pe_session->assocReq = qdf_mem_malloc(ft_ies_length); + if (NULL == pe_session->assocReq) { + pe_err("Failed to alloc memory for FT IEs"); + pe_session->assocReqLen = 0; + } else { + /* + * Store the FT IEs. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assocReq, + ft_sme_context->reassoc_ft_ies, ft_ies_length); + pe_session->assocReqLen = ft_ies_length; + } + } else { + pe_debug("FT IEs not present"); + pe_session->assocReqLen = 0; + } + + 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, sme_sessionid, + 0, RATEID_DEFAULT); + 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: + /* 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 + * @pMac: Global MAC Context + * @pMlmReassocReq: Request buffer to be sent + * @psessionEntry: PE Session + * + * Return: None + */ +void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tLimMlmReassocReq *pTmpMlmReassocReq = NULL; + + if (NULL == pTmpMlmReassocReq) { + pTmpMlmReassocReq = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == pTmpMlmReassocReq) + goto end; + qdf_mem_copy(pTmpMlmReassocReq, pMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ + pMac->lim.limTimers.gLimReassocFailureTimer.sessionId = + psessionEntry->peSessionId; + /* Start reassociation failure timer */ + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&pMac->lim.limTimers.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 = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + lim_send_reassoc_req_with_ft_ies_mgmt_frame(pMac, pTmpMlmReassocReq, + psessionEntry); + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq != NULL) { + qdf_mem_free(pMlmReassocReq); + pMlmReassocReq = NULL; + } + if (pTmpMlmReassocReq != NULL) { + qdf_mem_free(pTmpMlmReassocReq); + pTmpMlmReassocReq = NULL; + } + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_send_reassoc_req_mgmt_frame() - Send the reassociation frame + * @pMac: Global MAC Context + * @pMlmReassocReq: Reassociation request buffer to be sent + * @psessionEntry: PE Session + * + * Return: None + */ +void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{ + static 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; + + if (NULL == psessionEntry) + return; + + smeSessionId = psessionEntry->smeSessionId; + if (NULL == psessionEntry->pLimReAssocReq) + return; + nAddIELen = psessionEntry->pLimReAssocReq->addIEAssoc.length; + pAddIE = psessionEntry->pLimReAssocReq->addIEAssoc.addIEdata; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + 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 (psessionEntry->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 *) psessionEntry->bssId, 6); + + populate_dot11f_ssid2(pMac, &frm.SSID); + populate_dot11f_supp_rates(pMac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, psessionEntry); + + fQosEnabled = (psessionEntry->limQosEnabled) && + SIR_MAC_GET_QOS(psessionEntry->limReassocBssCaps); + + fWmeEnabled = (psessionEntry->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, psessionEntry->limReassocBssQosCaps); + + fWsmEnabled = (psessionEntry->limWsmEnabled) && fWmeEnabled && + LIM_BSS_CAPS_GET(WSM, psessionEntry->limReassocBssQosCaps); + + if (psessionEntry->lim11hEnable && + psessionEntry->pLimReAssocReq->spectrumMgtIndicator == true) { + PowerCapsPopulated = true; + populate_dot11f_power_caps(pMac, &frm.PowerCaps, LIM_REASSOC, + psessionEntry); + populate_dot11f_supp_channels(pMac, &frm.SuppChannels, + LIM_REASSOC, psessionEntry); + } + if (pMac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(psessionEntry->limCurrentBssCaps)) { + if (PowerCapsPopulated == false) { + PowerCapsPopulated = true; + populate_dot11f_power_caps(pMac, &frm.PowerCaps, + LIM_REASSOC, psessionEntry); + } + } + + if (fQosEnabled) + populate_dot11f_qos_caps_station(pMac, psessionEntry, + &frm.QOSCapsStation); + + populate_dot11f_ext_supp_rates(pMac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.ExtSuppRates, psessionEntry); + + if (pMac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(psessionEntry->limCurrentBssCaps)) + populate_dot11f_rrm_ie(pMac, &frm.RRMEnabledCap, psessionEntry); + /* The join request *should* contain zero or one of the WPA and RSN */ + /* IEs. The payload send along with the request is a */ + /* 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': */ + + /* typedef struct sSirRSNie */ + /* { */ + /* uint16_t length; */ + /* uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+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(pMac, pAddIE, nAddIELen); + if (NULL == wpsIe) { + populate_dot11f_rsn_opaque(pMac, + &(psessionEntry->pLimReAssocReq->rsnIE), + &frm.RSNOpaque); + populate_dot11f_wpa_opaque(pMac, + &(psessionEntry->pLimReAssocReq->rsnIE), + &frm.WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(pMac, + &(psessionEntry->pLimReAssocReq-> + rsnIE), &frm.WAPIOpaque); +#endif /* defined(FEATURE_WLAN_WAPI) */ + } + /* include WME EDCA IE as well */ + if (fWmeEnabled) { + populate_dot11f_wmm_info_station_per_session(pMac, + psessionEntry, &frm.WMMInfoStation); + + if (fWsmEnabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); + } + + if (psessionEntry->htCapability && + pMac->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(pMac, psessionEntry, &frm.HTCaps); + } + if (psessionEntry->vhtCapability && + psessionEntry->vhtCapabilityPresentInBeacon) { + pe_warn("Populate VHT IEs in Re-Assoc Request"); + populate_dot11f_vht_caps(pMac, psessionEntry, &frm.VHTCaps); + isVHTEnabled = true; + } + populate_dot11f_ext_cap(pMac, isVHTEnabled, &frm.ExtCap, psessionEntry); + + if (lim_is_session_he_capable(psessionEntry)) { + pe_debug("Populate HE IEs"); + populate_dot11f_he_caps(pMac, psessionEntry, + &frm.he_cap); + } + + nStatus = + dot11f_get_packed_re_assoc_request_size(pMac, &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) + nAddIELen; + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + psessionEntry->limMlmState = psessionEntry->limPrevMlmState; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_REASSOC_REQ, psessionEntry->limReAssocbssId, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* That done, pack the Probe Request: */ + nStatus = dot11f_pack_re_assoc_request(pMac, &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); + } + + pe_debug("*** Sending Re-Association Request length: %d" "to", nBytes); + + if (psessionEntry->assocReq != NULL) { + qdf_mem_free(psessionEntry->assocReq); + psessionEntry->assocReq = NULL; + psessionEntry->assocReqLen = 0; + } + + if (nAddIELen) { + qdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, + pAddIE, nAddIELen); + nPayload += nAddIELen; + } + + psessionEntry->assocReq = qdf_mem_malloc(nPayload); + if (NULL == psessionEntry->assocReq) { + pe_err("Unable to allocate mem for assoc req"); + } else { + /* Store the Assocrequest. It is sent to csr in joincnfrsp */ + qdf_mem_copy(psessionEntry->assocReq, + pFrame + sizeof(tSirMacMgmtHdr), nPayload); + psessionEntry->assocReqLen = nPayload; + } + + if ((BAND_5G == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE || + psessionEntry->pePersona == QDF_STA_MODE) + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + lim_diag_event_report(pMac, WLAN_PE_DIAG_REASSOC_START_EVENT, + psessionEntry, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + qdf_status = + wma_tx_frame(pMac, pPacket, + (uint16_t) (sizeof(tSirMacMgmtHdr) + nPayload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, txFlag, smeSessionId, 0, + RATEID_DEFAULT); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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: + /* Free up buffer allocated for mlmAssocReq */ + qdf_mem_free(pMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + +} + +void lim_process_rx_scan_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + tpAniSirGlobal mac_ctx; + enum sir_scan_event_type event_type; + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_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 = (tpAniSirGlobal)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: + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "No.of beacons and probe response received per scan %d", + mac_ctx->lim.beacon_probe_rsp_cnt_per_scan); + /* Fall through */ + 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: + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "Received unhandled scan event %u", + event_type); + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c new file mode 100644 index 0000000000000000000000000000000000000000..32f8d08908be40b5bdb1d5de25f49f733489591b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c @@ -0,0 +1,5018 @@ +/* + * 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. + */ + +/** + * \file lim_send_management_frames.c + * + * \brief Code for preparing and sending 802.11 Management frames + * + * + */ + +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.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 "lim_sta_hash_api.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "lim_assoc_utils.h" +#include "lim_ft.h" +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif + +#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 "wma_types.h" +#include +#include +#include "lim_process_fils.h" +#include "wlan_utility.h" + +/** + * + * \brief This function is called to add the sequence number to the + * management frames + * + * \param pMac 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 pMac 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(tpAniSirGlobal pMac, tpSirMacMgmtHdr pMacHdr) +{ + if (pMac->mgmtSeqNum >= WLAN_HOST_SEQ_NUM_MAX) { + pMac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + } + + pMac->mgmtSeqNum++; + + pMacHdr->seqControl.seqNumLo = (pMac->mgmtSeqNum & LOW_SEQ_NUM_MASK); + pMacHdr->seqControl.seqNumHi = + ((pMac->mgmtSeqNum & HIGH_SEQ_NUM_MASK) >> HIGH_SEQ_NUM_OFFSET); +} + +/** + * + * \brief This function is called before sending a p2p action frame + * inorder to add sequence numbers to action packets + * + * \param pMac Pointer to Global MAC structure + * + * \param pBD Pointer to the frame buffer that needs to be populate + * + * The pMacHdr argument points to the MAC management header. The + * sequence number stored in the pMac 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. + * + */ +void lim_populate_p2p_mac_header(tpAniSirGlobal pMac, uint8_t *pBD) +{ + tpSirMacMgmtHdr pMacHdr; + + /* / Prepare MAC management header */ + pMacHdr = (tpSirMacMgmtHdr) (pBD); + + /* Prepare sequence number */ + lim_add_mgmt_seq_num(pMac, pMacHdr); + pe_debug("seqNumLo=%d, seqNumHi=%d, mgmtSeqNum=%d", + pMacHdr->seqControl.seqNumLo, + pMacHdr->seqControl.seqNumHi, pMac->mgmtSeqNum); +} + +/** + * 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(tpAniSirGlobal 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", + mac_hdr->seqControl.seqNumLo, + mac_hdr->seqControl.seqNumHi, mac_ctx->mgmtSeqNum); +} + +/** + * 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 + * @channel: Channel # 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(tpAniSirGlobal mac_ctx, + tSirMacSSid *ssid, + tSirMacAddr bssid, + uint8_t channel, + 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; + tpPESession pesession; + uint8_t sessionid; + const uint8_t *p2pie = NULL; + uint8_t txflag = 0; + uint8_t sme_sessionid = 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; + + if (additional_ielen) + addn_ielen = *additional_ielen; + + /* The probe req should not send 11ac capabilieties if band is 2.4GHz, + * unless enableVhtFor24GHz is enabled in INI. So if enableVhtFor24GHz + * is false and dot11mode is 11ac set it to 11n. + */ + if (channel <= SIR_11B_CHANNEL_END && + (false == mac_ctx->roam.configParam.enableVhtFor24GHz) && + (WNI_CFG_DOT11_MODE_11AC == dot11mode || + WNI_CFG_DOT11_MODE_11AC_ONLY == dot11mode)) + dot11mode = WNI_CFG_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 != NULL) + sme_sessionid = pesession->smeSessionId; + + /* 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: */ + qdf_mem_zero((uint8_t *) &pr, sizeof(pr)); + + /* & 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 serach or probe request is + * sent by P2P Client + */ + if ((WNI_CFG_DOT11_MODE_11B != dot11mode) && (p2pie != NULL) && + ((pesession != NULL) && + (QDF_P2P_CLIENT_MODE == pesession->pePersona))) { + /* + * 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 (WNI_CFG_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, channel); + /* 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 != NULL) { + pesession->htCapability = IS_DOT11_MODE_HT(dot11mode); + /* Include HT Capability IE */ + if (pesession->htCapability) + populate_dot11f_ht_caps(mac_ctx, pesession, &pr.HTCaps); + } else { /* pesession == NULL */ + if (IS_DOT11_MODE_HT(dot11mode)) + populate_dot11f_ht_caps(mac_ctx, NULL, &pr.HTCaps); + } + + /* + * Set channelbonding information as "disabled" when tunned to a + * 2.4 GHz channel + */ + if (channel <= SIR_11B_CHANNEL_END) { + 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 != NULL) { + pesession->vhtCapability = IS_DOT11_MODE_VHT(dot11mode); + /* Include VHT Capability IE */ + if (pesession->vhtCapability) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr.VHTCaps); + is_vht_enabled = true; + } + } else { + if (IS_DOT11_MODE_VHT(dot11mode)) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr.VHTCaps); + is_vht_enabled = true; + } + } + if (pesession != NULL) + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &pr.ExtCap, + pesession); + + if (IS_DOT11_MODE_HE(dot11mode) && NULL != pesession) + lim_update_session_he_capable(mac_ctx, pesession); + + pe_debug("Populate HE IEs"); + populate_dot11f_he_caps(mac_ctx, pesession, &pr.he_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 (mac_ctx->roam.configParam.qcn_ie_support && !qcn_ie) + populate_dot11f_qcn_ie(&pr.QCN_IE); + + /* + * 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); + + /* 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; + + /* 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); + return QDF_STATUS_E_NOMEM; + } + /* 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); + return QDF_STATUS_E_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing a Probe Request (0x%08x)", status); + } + /* Append any AddIE if present. */ + if (addn_ielen) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + additional_ie, addn_ielen); + payload += addn_ielen; + } + + /* If this probe request is sent during P2P Search State, then we need + * to send it at OFDM rate. + */ + if ((BAND_5G == lim_get_rf_band(channel)) || + /* + * 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 pePersona is P2P_CLIENT or not + */ + ((pesession != NULL) && + (QDF_P2P_CLIENT_MODE == pesession->pePersona))) { + 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, sme_sessionid, + 0, RATEID_DEFAULT); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("could not send Probe Request frame!"); + /* Pkt will be freed up by the callback */ + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} /* End lim_send_probe_req_mgmt_frame. */ + +static QDF_STATUS lim_get_addn_ie_for_probe_resp(tpAniSirGlobal pMac, + 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 (NULL == addIE) { + pe_err("NULL addIE pointer"); + return QDF_STATUS_E_FAILURE; + } + + tempbuf = qdf_mem_malloc(left); + if (NULL == tempbuf) { + pe_err("Unable to allocate memory to store addn IE"); + 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 (!((SIR_MAC_EID_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_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 + * @n_staid: Station ID, currently unused. + * @pe_session: PE session id + * @keepalive: Keep alive flag. Currently unused. + * @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(tpAniSirGlobal mac_ctx, + tSirMacAddr peer_macaddr, + tpAniSSID ssid, + short n_staid, + uint8_t keepalive, + tpPESession 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; + uint32_t wps_ap = 0, tmp; + uint8_t tx_flag = 0; + uint8_t *add_ie = NULL; + const 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 sme_sessionid = 0; + bool is_vht_enabled = false; + tDot11fIEExtCap extracted_ext_cap = {0}; + bool extracted_ext_cap_flag = false; + + /* We don't answer requests in this case*/ + if (ANI_DRIVER_TYPE(mac_ctx) == QDF_DRIVER_TYPE_MFG) + return; + + if (NULL == 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->pePersona == QDF_SAP_MODE) || + (pe_session->pePersona == QDF_P2P_GO_MODE)) && + (true == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("CAC timer is running, probe response dropped")); + return; + } + sme_sessionid = pe_session->smeSessionId; + frm = qdf_mem_malloc(sizeof(tDot11fProbeResponse)); + if (NULL == frm) { + pe_err("Unable to allocate memory"); + 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.schObject.gSchBeaconInterval; + } else { + sir_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_BEACON_INTERVAL, &cfg); + if (QDF_STATUS_SUCCESS != sir_status) { + pe_err("Failed to get WNI_CFG_BEACON_INTERVAL (%d)", + sir_status); + goto err_ret; + } + 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_ds_params(mac_ctx, &frm->DSParams, + pe_session->currentOperChannel); + populate_dot11f_ibss_params(mac_ctx, &frm->IBSSParams, pe_session); + + 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 { + if (wlan_cfg_get_int(mac_ctx, (uint16_t) WNI_CFG_WPS_ENABLE, + &tmp) != QDF_STATUS_SUCCESS) + pe_err("Failed to cfg get id %d", WNI_CFG_WPS_ENABLE); + + wps_ap = tmp & 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 != WNI_CFG_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 (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_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) */ + + if (mac_ctx->lim.gpLimRemainOnChanReq) + bytes += (mac_ctx->lim.gpLimRemainOnChanReq->length - + sizeof(tSirRemainOnChnReq)); + else + /* + * 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->addIeParams.probeRespDataLen != 0); + + if (addn_ie_present) { + + add_ie = qdf_mem_malloc( + pe_session->addIeParams.probeRespDataLen); + if (NULL == add_ie) { + pe_err("add_ie allocation failed"); + goto err_ret; + } + + qdf_mem_copy(add_ie, + pe_session->addIeParams.probeRespData_buff, + pe_session->addIeParams.probeRespDataLen); + addn_ie_len = pe_session->addIeParams.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 = limGetP2pIEPtr(mac_ctx, &add_ie[0], + addn_ie_len); + + if (p2p_ie != NULL) { + /* get NoA attribute stream P2P IE */ + noalen = lim_get_noa_attr_stream(mac_ctx, + noa_stream, pe_session); + if (noalen != 0) { + total_noalen = + lim_build_p2p_ie(mac_ctx, &noa_ie[0], + &noa_stream[0], noalen); + bytes = bytes + total_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); + + 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); + + 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->selfMacAddr); + + 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); + } + + pe_debug("Sending Probe Response frame to"); + lim_print_mac_addr(mac_ctx, peer_macaddr, LOGD); + + if (mac_ctx->lim.gpLimRemainOnChanReq) + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + mac_ctx->lim.gpLimRemainOnChanReq->probeRspIe, + (mac_ctx->lim.gpLimRemainOnChanReq->length - + sizeof(tSirRemainOnChnReq))); + + if (addn_ie_present) + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + &add_ie[0], addn_ie_len); + + if (noalen != 0) { + if (total_noalen > + (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)) { + pe_err("Not able to insert NoA, total len=%d", + total_noalen); + goto err_ret; + } else { + qdf_mem_copy(&frame[bytes - (total_noalen)], + &noa_ie[0], total_noalen); + } + } + + if ((BAND_5G == lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == QDF_P2P_CLIENT_MODE) || + (pe_session->pePersona == 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((tHalHandle) mac_ctx, packet, + (uint16_t) bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, tx_flag, + sme_sessionid, 0, RATEID_DEFAULT); + + /* 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 != NULL) + qdf_mem_free(add_ie); + + qdf_mem_free(frm); + return; + +err_ret: + if (add_ie != NULL) + qdf_mem_free(add_ie); + if (frm != NULL) + qdf_mem_free(frm); + if (packet != NULL) + cds_packet_free((void *)packet); + return; + +} /* End lim_send_probe_rsp_mgmt_frame. */ + +void +lim_send_addts_req_action_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *pAddTS, tpPESession psessionEntry) +{ + 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 (NULL == psessionEntry) { + return; + } + + smeSessionId = psessionEntry->smeSessionId; + + if (!pAddTS->wmeTspecPresent) { + qdf_mem_zero((uint8_t *) &AddTSReq, sizeof(AddTSReq)); + + AddTSReq.Action.action = SIR_MAC_QOS_ADD_TS_REQ; + AddTSReq.DialogToken.token = pAddTS->dialogToken; + AddTSReq.Category.category = SIR_MAC_ACTION_QOS_MGMT; + 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(pMac, &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(pMac, + &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(pMac, &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 = SIR_MAC_QOS_ADD_TS_REQ; + WMMAddTSReq.DialogToken.token = pAddTS->dialogToken; + WMMAddTSReq.Category.category = SIR_MAC_ACTION_WME; + + /* 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(pMac, &phyMode, psessionEntry); + + 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(pMac, &pAddTS->tsrsIE, + &WMMAddTSReq.ESETrafStrmRateSet, + sizeof(uint8_t)); +#endif + /* fillWmeTspecIE */ + + nStatus = + dot11f_get_packed_wmm_add_ts_request_size(pMac, &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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peerMacAddr, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peerMacAddr, pMacHdr); +#endif + + /* That done, pack the struct: */ + if (!pAddTS->wmeTspecPresent) { + nStatus = dot11f_pack_add_ts_request(pMac, &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(pMac, &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"); + lim_print_mac_addr(pMac, peerMacAddr, LOGD); + + if ((BAND_5G == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) + || (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + /* Queue Addts Response frame in high priority WQ */ + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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. */ + +/** + * 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. + * + * Builds and sends association response frame to the requesting peer. + * + * Return: void + */ + +void +lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal mac_ctx, + uint16_t status_code, uint16_t aid, tSirMacAddr peer_addr, + uint8_t subtype, tpDphHashNode sta, tpPESession pe_session) +{ + 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[WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN]; + 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; +#ifdef WLAN_FEATURE_11W + uint32_t retry_int; + uint32_t max_retries; +#endif + + if (NULL == pe_session) { + pe_err("pe_session is NULL"); + 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 (NULL == 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 != NULL && + QDF_STATUS_SUCCESS == status_code) { + assoc_req = (tpSirAssocReq) + pe_session->parsedAssocReq[sta->assocId]; + /* + * populate P2P IE in AssocRsp when assocReq from the peer + * includes P2P IE + */ + if (assoc_req != NULL && assoc_req->addIEPresent) + populate_dot11_assoc_res_p2p_ie(mac_ctx, + &frm.P2PAssocRes, + assoc_req); + } + + if (NULL != 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) { + pe_debug("Populate HT IEs in Assoc Response"); + 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); + } + pe_debug("SupportedChnlWidth: %d, mimoPS: %d, GF: %d, short GI20:%d, shortGI40: %d, dsssCck: %d, AMPDU Param: %x", + frm.HTCaps.supportedChannelWidthSet, + frm.HTCaps.mimoPowerSave, + frm.HTCaps.greenField, frm.HTCaps.shortGI20MHz, + frm.HTCaps.shortGI40MHz, + frm.HTCaps.dsssCckMode40MHz, + frm.HTCaps.maxRxAMPDUFactor); + + if (sta->mlmStaContext.vhtCapability && + pe_session->vhtCapability) { + pe_debug("Populate VHT IEs in Assoc Response"); + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm.VHTOperation); + is_vht = true; + } + + if (pe_session->vhtCapability && + pe_session->vendor_vht_sap && + (assoc_req != NULL) && + assoc_req->vendor_vht_ie.VHTCaps.present) { + pe_debug("Populate Vendor VHT IEs in Assoc Rsponse"); + 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); + + if (lim_is_sta_he_capable(sta) && + 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); + } +#ifdef WLAN_FEATURE_11W + if (eSIR_MAC_TRY_AGAIN_LATER == status_code) { + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &max_retries) != QDF_STATUS_SUCCESS) + pe_err("get WNI_CFG_PMF_SA_QUERY_MAX_RETRIES failure"); + else if (wlan_cfg_get_int + (mac_ctx, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retry_int) != QDF_STATUS_SUCCESS) + pe_err("get WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL failure"); + else + populate_dot11f_timeout_interval(mac_ctx, + &frm.TimeoutInterval, + SIR_MAC_TI_TYPE_ASSOC_COMEBACK, + (max_retries - + sta->pmfSaQueryRetryCount) + * retry_int); + } +#endif + + 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 != + WNI_CFG_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.bssIdx = pe_session->bssIdx; + + /* 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); + + if (assoc_req != NULL) { + addn_ie_len = pe_session->addIeParams.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->addIeParams.assocRespData_buff, + pe_session->addIeParams.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; + } + pe_debug("addn_ie_len: %d for Assoc Resp: %d", + addn_ie_len, assoc_req->addIEPresent); + } + + /* + * 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); + + /* 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); + return; + } else if (DOT11F_WARNED(status)) { + pe_warn("get Association Response size warning (0x%08x)", + status); + } + + bytes += sizeof(tSirMacMgmtHdr) + payload; + + 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"); + return; + } + /* 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->selfMacAddr); + 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); + return; + } else if (DOT11F_WARNED(status)) { + pe_warn("Association Response pack warning (0x%08x)", + status); + } + + if (subtype == LIM_ASSOC) + pe_debug("*** Sending Assoc Resp status %d aid %d to", + status_code, aid); + else + pe_debug("*** Sending ReAssoc Resp status %d aid %d to", + status_code, aid); + + lim_print_mac_addr(mac_ctx, mac_hdr->da, LOGD); + + 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); + + if ((BAND_5G == + lim_get_rf_band(pe_session->currentOperChannel)) || + (pe_session->pePersona == QDF_P2P_CLIENT_MODE) || + (pe_session->pePersona == QDF_P2P_GO_MODE)) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + 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 */ + 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); + 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); + +} + +void +lim_send_delts_req_action_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t wmmTspecPresent, + tSirMacTSInfo *pTsinfo, + tSirMacTspecIE *pTspecIe, tpPESession psessionEntry) +{ + 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 (NULL == psessionEntry) { + return; + } + + smeSessionId = psessionEntry->smeSessionId; + + if (!wmmTspecPresent) { + qdf_mem_zero((uint8_t *) &DelTS, sizeof(DelTS)); + + DelTS.Category.category = SIR_MAC_ACTION_QOS_MGMT; + DelTS.Action.action = SIR_MAC_QOS_DEL_TS_REQ; + populate_dot11f_ts_info(pTsinfo, &DelTS.TSInfo); + + nStatus = dot11f_get_packed_del_ts_size(pMac, &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 = SIR_MAC_ACTION_WME; + WMMDelTS.Action.action = SIR_MAC_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(pMac, &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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* That done, pack the struct: */ + if (!wmmTspecPresent) { + nStatus = dot11f_pack_del_ts(pMac, &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(pMac, &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 ", nBytes); + lim_print_mac_addr(pMac, pMacHdr->da, LOGD); + + if ((BAND_5G == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) + || (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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. */ + +/** + * 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; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)context; + + pe_debug("tx_complete= %d", tx_complete); + if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) { + assoc_ack_status = ACKED; + reason_code = QDF_STATUS_SUCCESS; + } else { + assoc_ack_status = NOT_ACKED; + reason_code = QDF_STATUS_E_FAILURE; + } + 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; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tLimMlmAssocReq *mlm_assoc_req, + tpPESession pe_session) +{ + int ret; + tDot11fAssocRequest *frm; + uint16_t caps; + uint8_t *frame; + 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; + uint8_t *add_ie; + const uint8_t *wps_ie = NULL; + uint8_t power_caps = false; + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + bool vht_enabled = false; + tDot11fIEExtCap extr_ext_cap; + bool extr_ext_flag = true; + 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; + uint8_t mbo_ie_len = 0; + + if (NULL == pe_session) { + pe_err("pe_session is NULL"); + qdf_mem_free(mlm_assoc_req); + return; + } + + sme_sessionid = pe_session->smeSessionId; + + /* check this early to avoid unncessary operation */ + if (NULL == pe_session->pLimJoinReq) { + pe_err("pe_session->pLimJoinReq is NULL"); + qdf_mem_free(mlm_assoc_req); + return; + } + add_ie_len = pe_session->pLimJoinReq->addIEAssoc.length; + add_ie = pe_session->pLimJoinReq->addIEAssoc.addIEdata; + + frm = qdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (NULL == frm) { + pe_err("Unable to allocate memory"); + qdf_mem_free(mlm_assoc_req); + 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 { + pe_debug("No addn IE or peer doesn't support addnIE for Assoc Req"); + 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(mac_ctx, &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->pLimJoinReq->spectrumMgtIndicator == 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 + * 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+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 (NULL == wps_ie) { + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->RSNOpaque); + populate_dot11f_wpa_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(mac_ctx, + &(pe_session->pLimJoinReq->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) { + pe_debug("Populate HT Caps in Assoc Request"); + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &frm->HTCaps, sizeof(frm->HTCaps)); + } else if (pe_session->he_with_wep_tkip) { + pe_debug("Populate HT Caps in Assoc Request with WEP/TKIP"); + populate_dot11f_ht_caps(mac_ctx, NULL, &frm->HTCaps); + } + pe_debug("SupportedChnlWidth: %d, mimoPS: %d, GF: %d, short GI20:%d, shortGI40: %d, dsssCck: %d, AMPDU Param: %x", + frm->HTCaps.supportedChannelWidthSet, + frm->HTCaps.mimoPowerSave, + frm->HTCaps.greenField, frm->HTCaps.shortGI20MHz, + frm->HTCaps.shortGI40MHz, + frm->HTCaps.dsssCckMode40MHz, + frm->HTCaps.maxRxAMPDUFactor); + + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + pe_debug("Populate VHT IEs in Assoc Request"); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &frm->VHTCaps, sizeof(frm->VHTCaps)); + vht_enabled = true; + if (pe_session->enableHtSmps && + !pe_session->supported_nss_1x1) { + pe_err("VHT OP mode IE in Assoc Req"); + populate_dot11f_operating_mode(mac_ctx, + &frm->OperatingMode, pe_session); + } + } else if (pe_session->he_with_wep_tkip) { + pe_debug("Populate VHT IEs in Assoc Request with WEP/TKIP"); + populate_dot11f_vht_caps(mac_ctx, NULL, &frm->VHTCaps); + } + + if (!vht_enabled && + pe_session->is_vendor_specific_vhtcaps) { + pe_debug("Populate Vendor VHT IEs in 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; + if (!mac_ctx->roam.configParam.enable_subfee_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); + + if (mac_ctx->roam.configParam.qcn_ie_support) + populate_dot11f_qcn_ie(&frm->QCN_IE); + + if (lim_is_session_he_capable(pe_session)) { + pe_debug("Populate HE IEs"); + populate_dot11f_he_caps(mac_ctx, pe_session, + &frm->he_cap); + } else if (pe_session->he_with_wep_tkip) { + pe_debug("Populate HE IEs in Assoc Request with WEP/TKIP"); + populate_dot11f_he_caps(mac_ctx, NULL, &frm->he_cap); + } + + if (pe_session->pLimJoinReq->is11Rconnection) { + tSirBssDescription *bssdescr; + + bssdescr = &pe_session->pLimJoinReq->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->pLimJoinReq->bssDescription.mdie); + } else { + /* No 11r IEs dont send any MDIE */ + pe_debug("MDIE not present"); + } + +#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->roam.configParam.isEseIniFeatureEnabled) + populate_dot11f_ese_version(&frm->ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (pe_session->isESEconnection && + pe_session->pLimJoinReq->isESEFeatureIniEnabled) { +#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) { + bcn_ie = pe_session->beacon + ie_offset; + bcn_ie_len = pe_session->bcnLen - ie_offset; + 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); + } + + 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; + } + + /* + * 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 (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) { + pe_err("Failed to allocate mbo_ie"); + goto end; + } + + qdf_status = lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + SIR_MAC_EID_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 free_mbo_ie; + } + + /* Include the EID and length fields */ + mbo_ie_len = mbo_ie[1] + 2; + pe_debug("Stripped MBO IE of length %d", mbo_ie_len); + } + + /* + * 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; + } + } + + 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 + mbo_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->selfMacAddr); + /* 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); + } + + /* 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; + + if (pe_session->assocReq != NULL) { + qdf_mem_free(pe_session->assocReq); + pe_session->assocReq = 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); + qdf_mem_free(frm); + return; + } + } + + pe_session->assocReq = qdf_mem_malloc(payload); + if (NULL == pe_session->assocReq) { + pe_err("Unable to allocate memory"); + } else { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assocReq, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + if ((BAND_5G == lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == QDF_P2P_CLIENT_MODE) + || (pe_session->pePersona == QDF_P2P_GO_MODE) + ) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (pe_session->pePersona == QDF_P2P_CLIENT_MODE || + pe_session->pePersona == 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("Sending Association Request length %d to ", bytes); + min_rid = lim_get_min_session_txrate(pe_session); + 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); + 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, sme_sessionid, false, 0, min_rid); + 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); + 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 */ + } +free_mbo_ie: + if (mbo_ie) + qdf_mem_free(mbo_ie); + +end: + /* Free up buffer allocated for mlm_assoc_req */ + qdf_mem_free(mlm_assoc_req); + mlm_assoc_req = NULL; + qdf_mem_free(frm); + return; +} + +/** + * 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) +{ + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)context; + uint16_t auth_ack_status; + uint16_t reason_code; + + pe_debug("tx_complete = %d %s", tx_complete, + (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) ? + "success" : "fail"); + if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) { + mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_SUCCESS; + auth_ack_status = ACKED; + reason_code = QDF_STATUS_SUCCESS; + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + } else { + mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_FAILURE; + auth_ack_status = NOT_ACKED; + 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; +} + +/** + * 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_bit: wep bit in frame control for Authentication frame3 + * @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(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, + tSirMacAddr peer_addr, + uint8_t wep_challenge_len, + tpPESession session) +{ + uint8_t *frame, *body; + uint32_t frame_len = 0, body_len = 0; + tpSirMacMgmtHdr mac_hdr; + void *packet; + QDF_STATUS qdf_status; + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + uint16_t ft_ies_length = 0; + bool challenge_req = false; + enum rateid min_rid = RATEID_DEFAULT; + + if (NULL == session) { + pe_err("Error: psession Entry is NULL"); + return; + } + + sme_sessionid = session->smeSessionId; + + 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. + */ + pe_debug("Sending encrypted auth frame to " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_addr)); + + body_len = wep_challenge_len + LIM_ENCR_AUTH_INFO_LEN; + frame_len = sizeof(tSirMacMgmtHdr) + body_len; + + goto alloc_packet; + } + + pe_debug("Sending Auth seq# %d status %d (%d) to " + MAC_ADDRESS_STR, + auth_frame->authTransactionSeqNumber, + auth_frame->authStatusCode, + (auth_frame->authStatusCode == eSIR_MAC_SUCCESS_STATUS), + MAC_ADDR_ARRAY(peer_addr)); + + 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; + + frame_len += lim_create_fils_auth_data(mac_ctx, + auth_frame, session); + if (auth_frame->authAlgoNumber == eSIR_FT_AUTH) { + if (NULL != 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); + } + } + break; + + case SIR_MAC_AUTH_FRAME_2: + if ((auth_frame->authAlgoNumber == eSIR_OPEN_SYSTEM) || + ((auth_frame->authAlgoNumber == eSIR_SHARED_KEY) && + (auth_frame->authStatusCode != + eSIR_MAC_SUCCESS_STATUS))) { + /* + * 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) */ + +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->selfMacAddr); + 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); + + pe_debug("Sending Auth seq# 3 to " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac_hdr->da)); + + } 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 != NULL)) { + + 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 (NULL != session->ftPEContext. + pFTPreAuthReq->pbssDescription) { + /* MDID attr is 54 */ + *body = SIR_MDIE_ELEMENT_ID; + 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) { + /* TODO MDIE */ + pe_debug("appending fils Auth data"); + lim_add_fils_data_to_auth_frame(session, body); + } + + pe_debug("*** Sending Auth seq# %d status %d (%d) to " + MAC_ADDRESS_STR, + auth_frame->authTransactionSeqNumber, + auth_frame->authStatusCode, + (auth_frame->authStatusCode == + eSIR_MAC_SUCCESS_STATUS), + MAC_ADDR_ARRAY(mac_hdr->da)); + } + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + frame, frame_len); + + if ((NULL != session->ftPEContext.pFTPreAuthReq) && + (BAND_5G == lim_get_rf_band( + session->ftPEContext.pFTPreAuthReq->preAuthchannelNum))) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + else if ((BAND_5G == + lim_get_rf_band(session->currentOperChannel)) + || (session->pePersona == QDF_P2P_CLIENT_MODE) + || (session->pePersona == QDF_P2P_GO_MODE)) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (session->pePersona == QDF_P2P_CLIENT_MODE || + session->pePersona == 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)); + + mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD; + min_rid = lim_get_min_session_txrate(session); + lim_diag_mgmt_tx_event_report(mac_ctx, mac_hdr, + session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + 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, sme_sessionid, false, 0, min_rid); + 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_AUTH_ACK_RCD_FAILURE; + 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; +} + +QDF_STATUS lim_send_deauth_cnf(tpAniSirGlobal mac_ctx) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tLimMlmDeauthReq *deauth_req; + tLimMlmDeauthCnf deauth_cnf; + tpPESession session_entry; + + deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (deauth_req) { + if (tx_timer_running( + &mac_ctx->lim.limTimers.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 == NULL) { + pe_err("session does not exist for given sessionId"); + deauth_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + sta_ds = + dph_lookup_hash_entry(mac_ctx, + deauth_req->peer_macaddr.bytes, + &aid, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* / 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); + if ((session_entry->limSystemRole == eLIM_STA_ROLE) && + ( +#ifdef FEATURE_WLAN_ESE + (session_entry->isESEconnection) || +#endif + (session_entry->isFastRoamIniFeatureEnabled) || + (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 { + pe_debug("No FT Preauth Session Cleanup in role %d" +#ifdef FEATURE_WLAN_ESE + " isESE %d" +#endif + " isLFR %d" + " is11r %d, Deauth reason %d Trigger = %d", + session_entry->limSystemRole, +#ifdef FEATURE_WLAN_ESE + session_entry->isESEconnection, +#endif + session_entry->isFastRoamIniFeatureEnabled, + session_entry->is11Rconnection, + deauth_req->reasonCode, + deauth_req->deauthTrigger); + } + /* Free up buffer allocated for mlmDeauthReq */ + qdf_mem_free(deauth_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } + 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(tpAniSirGlobal mac_ctx) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tLimMlmDisassocCnf disassoc_cnf; + tpPESession pe_session; + tLimMlmDisassocReq *disassoc_req; + + disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (disassoc_req) { + if (tx_timer_running( + &mac_ctx->lim.limTimers.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 == NULL) { + 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 == NULL) { + pe_err("StaDs Null"); + disassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* Receive path cleanup with dummy packet */ + if (QDF_STATUS_SUCCESS != + lim_cleanup_rx_path(mac_ctx, sta_ds, pe_session)) { + 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 != + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON)) { + 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 != NULL) { + /* / 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) +{ + tpAniSirGlobal max_ctx = (tpAniSirGlobal)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) +{ + tpAniSirGlobal max_ctx = (tpAniSirGlobal)context; + QDF_STATUS status_code; + struct scheduler_msg msg = {0}; + + 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) +{ + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)context; + + pe_debug("tx_success: %d", tx_success); + + return lim_send_deauth_cnf(mac_ctx); +} + +static QDF_STATUS lim_deauth_tx_complete_cnf_handler(void *context, + qdf_nbuf_t buf, + uint32_t tx_success, + void *params) +{ + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)context; + QDF_STATUS status_code; + struct scheduler_msg msg = {0}; + + pe_debug("tx_success: %d", tx_success); + + if (buf) + qdf_nbuf_free(buf); + msg.type = (uint16_t) WMA_DEAUTH_TX_COMP; + msg.bodyptr = params; + msg.bodyval = tx_success; + + status_code = lim_post_msg_high_priority(mac_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; +} + +/** + * \brief This function is called to send Disassociate frame. + * + * + * \param pMac 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(tpAniSirGlobal pMac, + uint16_t nReason, + tSirMacAddr peer, + tpPESession psessionEntry, 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; + + if (NULL == psessionEntry) { + return; + } + + /* + * In case when cac timer is running for this SAP session then + * avoid sending disassoc out. It is violation of dfs specification. + */ + if (((psessionEntry->pePersona == QDF_SAP_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) && + (true == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL + ("CAC timer is running, drop disassoc from going out")); + return; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_disassociation_size(pMac, &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); + + 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); + return; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DISASSOC, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_disassociation(pMac, &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); + return; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a Disassociation (0x%08x)", + nStatus); + } + + pe_debug("***Sessionid %d Sending Disassociation frame with " + "reason %u and waitForAck %d to " MAC_ADDRESS_STR " ,From " + MAC_ADDRESS_STR, psessionEntry->peSessionId, nReason, + waitForAck, MAC_ADDR_ARRAY(pMacHdr->da), + MAC_ADDR_ARRAY(psessionEntry->selfMacAddr)); + + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + if (waitForAck) { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + /* Queue Disassociation frame in high priority WQ */ + /* get the duration from the request */ + qdf_status = + wma_tx_frameWithTxComplete(pMac, 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); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + + if (tx_timer_change + (&pMac->lim.limTimers.gLimDisassocAckTimer, val, 0) + != TX_SUCCESS) { + pe_err("Unable to change Disassoc ack Timer val"); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers. + gLimDisassocAckTimer)) { + pe_err("Unable to activate Disassoc ack Timer"); + lim_deactivate_and_change_timer(pMac, + eLIM_DISASSOC_ACK_TIMER); + return; + } + } else { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + /* Queue Disassociation frame in high priority WQ */ + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, + lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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 pMac Pointer to global MAC structure + * + * \param nReason Indicates the reason that need to be sent in the + * Deauthenticate frame + * + * \param peeer address of the STA to which the frame is to be sent + * + * + */ + +void +lim_send_deauth_mgmt_frame(tpAniSirGlobal pMac, + uint16_t nReason, + tSirMacAddr peer, + tpPESession psessionEntry, 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 pStaDs; +#endif + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + return; + } + + /* + * In case when cac timer is running for this SAP session then + * avoid deauth frame out. It is violation of dfs specification. + */ + if (((psessionEntry->pePersona == QDF_SAP_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) && + (true == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL + ("CAC timer is running, drop the deauth from going out")); + return; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_de_auth_size(pMac, &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); + + 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); + return; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DEAUTH, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_de_auth(pMac, &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); + return; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a De-Authentication (0x%08x)", + nStatus); + } + pe_debug("***Sessionid %d Sending Deauth frame with " + "reason %u and waitForAck %d to " MAC_ADDRESS_STR + " ,From " MAC_ADDRESS_STR, + psessionEntry->peSessionId, nReason, waitForAck, + MAC_ADDR_ARRAY(pMacHdr->da), + MAC_ADDR_ARRAY(psessionEntry->selfMacAddr)); + + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; +#ifdef FEATURE_WLAN_TDLS + pStaDs = + dph_lookup_hash_entry(pMac, peer, &aid, + &psessionEntry->dph.dphHashTable); +#endif + + if (waitForAck) { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + /* Queue Disassociation frame in high priority WQ */ + qdf_status = + wma_tx_frameWithTxComplete(pMac, 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); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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(pMac); + return; + } + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + + if (tx_timer_change + (&pMac->lim.limTimers.gLimDeauthAckTimer, val, 0) + != TX_SUCCESS) { + pe_err("Unable to change Deauth ack Timer val"); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers. + gLimDeauthAckTimer)) { + pe_err("Unable to activate Deauth ack Timer"); + lim_deactivate_and_change_timer(pMac, + eLIM_DEAUTH_ACK_TIMER); + return; + } + } else { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); +#ifdef FEATURE_WLAN_TDLS + if ((NULL != pStaDs) + && (STA_ENTRY_TDLS_PEER == pStaDs->staType)) { + /* Queue Disassociation frame in high priority WQ */ + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, + QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_IBSS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + } else { +#endif + lim_diag_mgmt_tx_event_report(pMac, pMacHdr, + psessionEntry, + QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + /* Queue Disassociation frame in high priority WQ */ + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); +#ifdef FEATURE_WLAN_TDLS + } +#endif + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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 pMac 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(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peer, tpPESession psessionEntry) +{ + 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 = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_MEASURE_REPORT_ID; + frm.DialogToken.token = pMeasReqFrame->actionHeader.dialogToken; + + switch (pMeasReqFrame->measReqIE.measType) { + case SIR_MAC_BASIC_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report0(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report1(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report2(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + default: + pe_err("Unknown measurement type %d in limSen" + "dMeasReportFrame", + 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(pMac, &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(pMac->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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_measurement_report(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a Measurement Report (0x%08x)", + nStatus); + cds_packet_free(pMac->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, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0, RATEID_DEFAULT); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->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 Request Action frame + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param peer MAC address to which the frame should be sent + * + * + */ + +void +lim_send_tpc_request_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fTPCRequest frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_TPC_REQUEST_ID; + frm.DialogToken.token = 1; + frm.TPCRequest.present = 1; + + nStatus = dot11f_get_packed_tpc_request_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a TPC Request (0x%08x)", nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTPCRequest); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a TPC Request (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc(pMac->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" + " Request", nBytes); + return; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_tpc_request(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a TPC Request (0x%08x)", + nStatus); + cds_packet_free(pMac->hdd_handle, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a TPC Request (0x%08x)", + nStatus); + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0, RATEID_DEFAULT); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->peSessionId : NO_SESSION), + qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send a TPC Request (%X)!", + qdf_status); + /* Pkt will be freed up by the callback */ + } + +} /* End lim_send_tpc_request_frame. */ + +/** + * \brief Send a TPC Report Action frame + * + * + * \param pMac 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(tpAniSirGlobal pMac, + tpSirMacTpcReqActionFrame pTpcReqFrame, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fTPCReport frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_TPC_REPORT_ID; + frm.DialogToken.token = pTpcReqFrame->actionHeader.dialogToken; + + frm.TPCReport.tx_power = 0; + frm.TPCReport.link_margin = 0; + frm.TPCReport.present = 1; + + nStatus = dot11f_get_packed_tpc_report_size(pMac, &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(pMac->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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_tpc_report(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a TPC Report (0x%08x)", + nStatus); + cds_packet_free(pMac->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, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0, RATEID_DEFAULT); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->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 pMac 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(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nMode, + uint8_t nNewChannel, + uint8_t nCount, tpPESession psessionEntry) +{ + 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 (psessionEntry == NULL) { + pe_err("Session entry is NULL!!!"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_CHANNEL_SWITCH_ID; + frm.ChanSwitchAnn.switchMode = nMode; + frm.ChanSwitchAnn.newChannel = nNewChannel; + frm.ChanSwitchAnn.switchCount = nCount; + frm.ChanSwitchAnn.present = 1; + + nStatus = dot11f_get_packed_channel_switch_size(pMac, &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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + qdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_channel_switch(pMac, &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 ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, uint8_t mode, uint8_t new_op_class, + uint8_t new_channel, uint8_t count, tpPESession 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 sme_session_id = 0; + uint8_t ch_spacing; + tLimWiderBWChannelSwitchInfo *wide_bw_ie; + + if (session_entry == NULL) { + pe_err("Session entry is NULL!!!"); + return QDF_STATUS_E_FAILURE; + } + + sme_session_id = session_entry->smeSessionId; + + qdf_mem_zero(&frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_PUBLIC_USAGE; + frm.Action.action = SIR_MAC_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; + + ch_spacing = wlan_reg_dmn_get_chanwidth_from_opclass( + mac_ctx->scan.countryCodeCurrent, new_channel, + new_op_class); + pe_debug("wrapper: ch_spacing %hu", ch_spacing); + + 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); + } + + 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->selfMacAddr); + 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 ((BAND_5G == + lim_get_rf_band(session_entry->currentOperChannel)) || + (session_entry->pePersona == QDF_P2P_CLIENT_MODE) || + (session_entry->pePersona == QDF_P2P_GO_MODE)) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + pe_debug("Send Ext channel Switch to :"MAC_ADDRESS_STR" with swcount %d, swmode %d , newchannel %d newops %d", + MAC_ADDR_ARRAY(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, sme_session_id, 0, + RATEID_DEFAULT); + 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(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, tpPESession 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 sme_session_id = 0; + + if (session_entry == NULL) { + pe_err("Session entry is NULL!!!"); + return QDF_STATUS_E_FAILURE; + } + + sme_session_id = session_entry->smeSessionId; + + qdf_mem_zero(&frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY; + + 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->selfMacAddr); + 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 ((BAND_5G == + lim_get_rf_band(session_entry->currentOperChannel)) || + (session_entry->pePersona == QDF_P2P_CLIENT_MODE) || + (session_entry->pePersona == QDF_P2P_GO_MODE)) { + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + pe_debug("Send frame on channel %d to mac " + MAC_ADDRESS_STR, session_entry->currentOperChannel, + MAC_ADDR_ARRAY(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, sme_session_id, false, 0, RATEID_DEFAULT); + + 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; +} + + +QDF_STATUS +lim_send_vht_opmode_notification_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nMode, tpPESession psessionEntry) +{ + tDot11fOperatingMode frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload = 0, nStatus; /* , nCfg; */ + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + pe_err("Session entry is NULL!!!"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_VHT; + frm.Action.action = SIR_MAC_VHT_OPMODE_NOTIFICATION; + frm.OperatingMode.chanWidth = nMode; + frm.OperatingMode.rxNSS = 0; + frm.OperatingMode.rxNSSType = 0; + + nStatus = dot11f_get_packed_operating_mode_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Operating Mode (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fOperatingMode); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a Operating Mode (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 Operating Mode Report", + nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + if (psessionEntry->pePersona == QDF_SAP_MODE) + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, + psessionEntry->selfMacAddr); + else + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, psessionEntry->bssId, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + qdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + nStatus = dot11f_pack_operating_mode(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a Operating Mode (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 Operating Mode (0x%08x)", + nStatus); + } + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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; +} + +/** + * \brief Send a Neighbor Report Request Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pNeighborReq Address of a tSirMacNeighborReportReq + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE else + * + * + */ + +QDF_STATUS +lim_send_neighbor_report_request_frame(tpAniSirGlobal pMac, + tpSirMacNeighborReportReq pNeighborReq, + tSirMacAddr peer, tpPESession psessionEntry) +{ + QDF_STATUS statusCode = 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 (psessionEntry == NULL) { + pe_err("(psession == NULL) in Request to send Neighbor Report request action frame"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_RRM; + frm.Action.action = SIR_MAC_RRM_NEIGHBOR_REQ; + frm.DialogToken.token = pNeighborReq->dialogToken; + + if (pNeighborReq->ssid_present) { + populate_dot11f_ssid(pMac, &pNeighborReq->ssid, &frm.SSID); + } + + nStatus = + dot11f_get_packed_neighbor_report_request_size(pMac, &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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_neighbor_report_request(pMac, + &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 */ + statusCode = 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"); + lim_print_mac_addr(pMac, peer, LOGD); + + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + statusCode = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + return statusCode; + } else + return QDF_STATUS_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return statusCode; +} /* End lim_send_neighbor_report_request_frame. */ + +/** + * \brief Send a Link Report Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pLinkReport Address of a tSirMacLinkReport + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE else + * + * + */ + +QDF_STATUS +lim_send_link_report_action_frame(tpAniSirGlobal pMac, + tpSirMacLinkReport pLinkReport, + tSirMacAddr peer, tpPESession psessionEntry) +{ + QDF_STATUS statusCode = 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 smeSessionId = 0; + + if (psessionEntry == NULL) { + pe_err("(psession == NULL) in Request to send Link Report action frame"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = SIR_MAC_ACTION_RRM; + frm.Action.action = SIR_MAC_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 = SIR_MAC_TPC_RPT_EID; + 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(pMac, &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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_link_measurement_report(pMac, + &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 */ + statusCode = 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("Sending a Link Report to"); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + statusCode = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + return statusCode; + } else + return QDF_STATUS_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return statusCode; +} /* End lim_send_link_report_action_frame. */ + +QDF_STATUS +lim_send_radio_measure_report_action_frame(tpAniSirGlobal pMac, + uint8_t dialog_token, + uint8_t num_report, + struct rrm_beacon_report_last_beacon_params + *last_beacon_report_params, + tpSirMacRadioMeasureReport pRRMReport, + tSirMacAddr peer, + tpPESession psessionEntry) +{ + QDF_STATUS statusCode = 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; + + tDot11fRadioMeasurementReport *frm = + qdf_mem_malloc(sizeof(tDot11fRadioMeasurementReport)); + if (!frm) { + pe_err("Not enough memory to allocate tDot11fRadioMeasurementReport"); + return QDF_STATUS_E_NOMEM; + } + + if (psessionEntry == NULL) { + pe_err("(psession == NULL) in Request to send Beacon Report action frame"); + qdf_mem_free(frm); + return QDF_STATUS_E_FAILURE; + } + + smeSessionId = psessionEntry->smeSessionId; + + pe_debug("dialog_token %d num_report %d", + dialog_token, num_report); + + frm->Category.category = SIR_MAC_ACTION_RRM; + frm->Action.action = SIR_MAC_RRM_RADIO_MEASURE_RPT; + frm->DialogToken.token = dialog_token; + + frm->num_MeasurementReport = + (num_report > + RADIO_REPORTS_MAX_IN_A_FRAME) ? RADIO_REPORTS_MAX_IN_A_FRAME : + 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: + populate_dot11f_beacon_report(pMac, + &frm->MeasurementReport[i], + &pRRMReport[i].report. + beaconReport, + last_beacon_report_params); + 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(pMac, frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Radio Measure 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("There were warnings while calculating the packed size for a 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_err("Failed to allocate %d bytes for a Radio Measure " + "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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_radio_measurement_report(pMac, + frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack an Radio Measure Report (0x%08x)", + nStatus); + + /* FIXME - Need to convert to QDF_STATUS */ + statusCode = QDF_STATUS_E_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing Radio Measure Report (0x%08x)", + nStatus); + } + + pe_warn("Sending a Radio Measure Report to"); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + statusCode = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + qdf_mem_free(frm); + return statusCode; + } else { + qdf_mem_free(frm); + return QDF_STATUS_SUCCESS; + } + +returnAfterError: + qdf_mem_free(frm); + cds_packet_free((void *)pPacket); + return statusCode; +} + +#ifdef WLAN_FEATURE_11W +/** + * \brief Send SA query request action frame to peer + * + * \sa lim_send_sa_query_request_frame + * + * + * \param pMac The global tpAniSirGlobal object + * + * \param transId Transaction identifier + * + * \param peer The Mac address of the station to which this action frame is addressed + * + * \param psessionEntry 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(tpAniSirGlobal pMac, uint8_t *transId, + tSirMacAddr peer, + tpPESession psessionEntry) +{ + + 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 = SIR_MAC_ACTION_SA_QUERY; + /* 11w action field is : + action: 0 --> SA Query Request action frame + action: 1 --> SA Query Response action frame */ + frm.Action.action = SIR_MAC_SA_QUERY_REQ; + /* 11w SA Query Request transId */ + qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + + nStatus = dot11f_get_packed_sa_query_req_size(pMac, &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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* Since this is a SA Query Request, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); + + /* Pack 11w SA Query Request frame */ + nStatus = dot11f_pack_sa_query_req(pMac, + &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 to"); + lim_print_mac_addr(pMac, peer, LOGD); + pe_debug("Sending an SA Query Request from "); + lim_print_mac_addr(pMac, psessionEntry->selfMacAddr, LOGD); + + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) +#ifdef WLAN_FEATURE_P2P + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) +#endif + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + 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 */ + +/** + * \brief Send SA query response action frame to peer + * + * \sa lim_send_sa_query_response_frame + * + * + * \param pMac The global tpAniSirGlobal object + * + * \param transId Transaction identifier received in SA query request action frame + * + * \param peer The Mac address of the AP to which this action frame is addressed + * + * \param psessionEntry 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(tpAniSirGlobal pMac, + uint8_t *transId, tSirMacAddr peer, + tpPESession psessionEntry) +{ + + 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 = psessionEntry->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + frm.Category.category = SIR_MAC_ACTION_SA_QUERY; + /*11w action field is : + action: 0 --> SA query request action frame + action: 1 --> SA query response action frame */ + frm.Action.action = SIR_MAC_SA_QUERY_RSP; + /*11w SA query response transId is same as + SA query request transId */ + qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + + nStatus = dot11f_get_packed_sa_query_rsp_size(pMac, &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(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* Since this is a SA Query Response, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); + + /* Pack 11w SA query response frame */ + nStatus = dot11f_pack_sa_query_rsp(pMac, + &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 a SA Query Response to"); + lim_print_mac_addr(pMac, peer, LOGD); + + if ((BAND_5G == lim_get_rf_band(psessionEntry->currentOperChannel)) +#ifdef WLAN_FEATURE_P2P + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) +#endif + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->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 */ +#endif + +/** + * 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 + * + * 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(tpAniSirGlobal mac_ctx, + tSirMacAddr peer_mac, uint16_t tid, + tpPESession session, uint8_t addba_extn_present, + uint8_t amsdu_support) +{ + + 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 sme_sessionid = 0; + uint16_t buff_size, status_code, batimeout; + uint8_t peer_id, dialog_token; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *peer, *pdev; + uint8_t he_frag = 0; + + sme_sessionid = session->smeSessionId; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + pe_err("pdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer = cdp_peer_get_ref_by_addr(soc, pdev, peer_mac, &peer_id, + PEER_DEBUG_ID_LIM_SEND_ADDBA_RESP); + if (!peer) { + pe_err("PEER [%pM] not found", peer_mac); + return QDF_STATUS_E_FAILURE; + } + + cdp_addba_responsesetup(soc, peer, tid, &dialog_token, + &status_code, &buff_size, &batimeout); + + cdp_peer_release_ref(soc, peer, PEER_DEBUG_ID_LIM_SEND_ADDBA_RESP); + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + frm.Category.category = SIR_MAC_ACTION_BLKACK; + frm.Action.action = SIR_MAC_ADDBA_RSP; + + frm.DialogToken.token = dialog_token; + frm.Status.status = status_code; + if (mac_ctx->reject_addba_req) { + frm.Status.status = eSIR_MAC_REQ_DECLINED_STATUS; + pe_err("refused addba req"); + } + frm.addba_param_set.tid = tid; + frm.addba_param_set.buff_size = SIR_MAC_BA_DEFAULT_BUFF_SIZE; + if (mac_ctx->usr_cfg_ba_buff_size) + frm.addba_param_set.buff_size = mac_ctx->usr_cfg_ba_buff_size; + if (mac_ctx->is_usr_cfg_amsdu_enabled) + 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; + 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; + } + } + } + + pe_debug("Sending a ADDBA Response from %pM to %pM", + session->selfMacAddr, peer_mac); + pe_debug("tid: %d, dialog_token: %d, status: %d, buff_size: %d", + tid, frm.DialogToken.token, frm.Status.status, + frm.addba_param_set.buff_size); + pe_debug("addba_extn %d he_capable %d no_frag %d he_frag %d", + addba_extn_present, + lim_is_session_he_capable(session), + frm.addba_extn_element.no_fragmentation, + frm.addba_extn_element.he_frag_operation); + + 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, session->selfMacAddr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr) frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->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); + + 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 ((BAND_5G == lim_get_rf_band(session->currentOperChannel)) +#ifdef WLAN_FEATURE_P2P + || (session->pePersona == QDF_P2P_CLIENT_MODE) || + (session->pePersona == QDF_P2P_GO_MODE) +#endif + ) { + 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, sme_sessionid, 0, + RATEID_DEFAULT); + 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); + qdf_status = QDF_STATUS_E_FAILURE; + /* + * wma_tx_frame free memory in certain cases, free pkt_ptr + * only if not freed already. + */ + if (pkt_ptr) + cds_packet_free((void *)pkt_ptr); + return qdf_status; + } else { + return QDF_STATUS_SUCCESS; + } + +error_addba_rsp: + cds_packet_free((void *)pkt_ptr); + return qdf_status; +} + +/** + * lim_tx_mgmt_frame() - Transmits Auth mgmt frame + * @mac_ctx Pointer to Global MAC structure + * @mb_msg: Received message info + * @msg_len: Received message length + * @packet: Packet to be transmitted + * @frame: Received frame + * + * Return: None + */ +static void lim_tx_mgmt_frame(tpAniSirGlobal mac_ctx, + struct sir_mgmt_msg *mb_msg, uint32_t msg_len, + void *packet, uint8_t *frame) +{ +#ifdef WLAN_DEBUG + tpSirMacFrameCtl fc = (tpSirMacFrameCtl) mb_msg->data; +#endif + QDF_STATUS qdf_status; + uint8_t sme_session_id = 0; + tpPESession session; + uint16_t auth_ack_status; + enum rateid min_rid = RATEID_DEFAULT; + + sme_session_id = mb_msg->session_id; + session = pe_find_session_by_sme_session_id(mac_ctx, sme_session_id); + if (session == NULL) { + pe_err("session not found for given sme session"); + return; + } + +#ifdef WLAN_DEBUG + qdf_mtrace(QDF_MODULE_ID_PE, QDF_MODULE_ID_WMA, TRACE_CODE_TX_MGMT, + session->peSessionId, 0); +#endif + + mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD; + min_rid = lim_get_min_session_txrate(session); + + 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, sme_session_id, false, 0, min_rid); + 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 (subType: %d), retCode=%X ***", + fc->subType, qdf_status); + mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_FAILURE; + 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 */ + } +} + +void lim_send_mgmt_frame_tx(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + struct sir_mgmt_msg *mb_msg = (struct sir_mgmt_msg *)msg->bodyptr; + uint32_t msg_len; +#ifdef WLAN_DEBUG + tpSirMacFrameCtl fc = (tpSirMacFrameCtl) mb_msg->data; +#endif + uint8_t sme_session_id; + QDF_STATUS qdf_status; + uint8_t *frame; + void *packet; + + msg_len = mb_msg->msg_len - sizeof(*mb_msg); + pe_debug("sending fc->type: %d fc->subType: %d", + fc->type, fc->subType); + + sme_session_id = mb_msg->session_id; + + qdf_status = cds_packet_alloc((uint16_t) msg_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, mb_msg->data, msg_len); + + lim_tx_mgmt_frame(mac_ctx, mb_msg, msg_len, packet, frame); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..903f22c576b3f8be064a3c4daebe88a861395c6d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c @@ -0,0 +1,809 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_api.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" + +/** + * lim_send_cf_params() + * + ***FUNCTION: + * This function is called to send CFP Parameters to WMA, when they are changed. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param bssIdx Bss Index of the BSS to which STA is associated. + * @param cfpCount CFP Count, if that is changed. + * @param cfpPeriod CFP Period if that is changed. + * + * @return success if message send is ok, else false. + */ +QDF_STATUS lim_send_cf_params(tpAniSirGlobal pMac, uint8_t bssIdx, + uint8_t cfpCount, uint8_t cfpPeriod) +{ + tpUpdateCFParams pCFParams = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pCFParams = qdf_mem_malloc(sizeof(tUpdateCFParams)); + if (NULL == pCFParams) { + pe_err("Unable to allocate memory during Update CF Params"); + retCode = QDF_STATUS_E_NOMEM; + goto returnFailure; + } + pCFParams->cfpCount = cfpCount; + pCFParams->cfpPeriod = cfpPeriod; + pCFParams->bssIdx = bssIdx; + + msgQ.type = WMA_UPDATE_CF_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pCFParams; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_CF_IND"); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pCFParams); + pe_err("Posting WMA_UPDATE_CF_IND failed, reason=%X", + retCode); + } +returnFailure: + return retCode; +} + +/** + * lim_send_beacon_params() - updates bcn params to WMA + * + * @pMac : 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(tpAniSirGlobal pMac, + tpUpdateBeaconParams pUpdatedBcnParams, + tpPESession psessionEntry) +{ + tpUpdateBeaconParams pBcnParams = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pBcnParams = qdf_mem_malloc(sizeof(*pBcnParams)); + if (NULL == pBcnParams) { + pe_err("Unable to allocate memory during Update Beacon Params"); + 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 (NULL == psessionEntry) { + qdf_mem_free(pBcnParams); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + return QDF_STATUS_E_FAILURE; + } else { + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + } + pBcnParams->smeSessionId = psessionEntry->smeSessionId; + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pBcnParams); + pe_err("Posting WMA_UPDATE_BEACON_IND, reason=%X", + retCode); + } + lim_send_beacon_ind(pMac, psessionEntry, REASON_DEFAULT); + return retCode; +} + +/** + * lim_send_switch_chnl_params() + * + ***FUNCTION: + * This function is called to send Channel Switch Indication to WMA + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param chnlNumber New Channel Number to be switched to. + * @param ch_width an enum for channel width. + * @param localPowerConstraint 11h local power constraint value + * + * @return success if message send is ok, else false. + */ +QDF_STATUS lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, + int8_t maxTxPower, + uint8_t peSessionId, + uint8_t is_restart, + uint32_t cac_duration_ms, + uint32_t dfs_regdomain) +{ + tpSwitchChannelParams pChnlParams = NULL; + struct scheduler_msg msgQ = {0}; + tpPESession pSessionEntry; + + pSessionEntry = pe_find_session_by_session_id(pMac, peSessionId); + if (pSessionEntry == NULL) { + pe_err("Unable to get Session for session Id %d", + peSessionId); + return QDF_STATUS_E_FAILURE; + } + pChnlParams = qdf_mem_malloc(sizeof(tSwitchChannelParams)); + if (NULL == pChnlParams) { + pe_err("Unable to allocate memory for Switch Ch Params"); + return QDF_STATUS_E_NOMEM; + } + pChnlParams->channelNumber = chnlNumber; + pChnlParams->ch_center_freq_seg0 = ch_center_freq_seg0; + pChnlParams->ch_center_freq_seg1 = ch_center_freq_seg1; + pChnlParams->ch_width = ch_width; + qdf_mem_copy(pChnlParams->selfStaMacAddr, pSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + pChnlParams->maxTxPower = maxTxPower; + qdf_mem_copy(pChnlParams->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + pChnlParams->peSessionId = peSessionId; + pChnlParams->vhtCapable = pSessionEntry->vhtCapability; + if (lim_is_session_he_capable(pSessionEntry)) + lim_update_chan_he_capable(pMac, pChnlParams); + pChnlParams->dot11_mode = pSessionEntry->dot11mode; + pChnlParams->nss = pSessionEntry->nss; + pe_debug("dot11mode: %d, vht_capable: %d nss value: %d", + pChnlParams->dot11_mode, pChnlParams->vhtCapable, + pChnlParams->nss); + + /*Set DFS flag for DFS channel */ + if (ch_width == CH_WIDTH_160MHZ) { + pChnlParams->isDfsChannel = true; + } else if (ch_width == CH_WIDTH_80P80MHZ) { + pChnlParams->isDfsChannel = false; + if (wlan_reg_get_channel_state(pMac->pdev, chnlNumber) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state(pMac->pdev, + pChnlParams->ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + pChnlParams->isDfsChannel = true; + } else { + if (wlan_reg_get_channel_state(pMac->pdev, chnlNumber) == + CHANNEL_STATE_DFS) + pChnlParams->isDfsChannel = true; + else + pChnlParams->isDfsChannel = false; + } + + pChnlParams->restart_on_chan_switch = is_restart; + pChnlParams->cac_duration_ms = cac_duration_ms; + pChnlParams->dfs_regdomain = dfs_regdomain; + pChnlParams->reduced_beacon_interval = + pMac->sap.SapDfsInfo.reduced_beacon_interval; + + pChnlParams->ssid_hidden = pSessionEntry->ssidHidden; + pChnlParams->ssid = pSessionEntry->ssId; + + if (cds_is_5_mhz_enabled()) + pChnlParams->ch_width = CH_WIDTH_5MHZ; + else if (cds_is_10_mhz_enabled()) + pChnlParams->ch_width = CH_WIDTH_10MHZ; + + /* we need to defer the message until we + * get the response back from WMA + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + msgQ.type = WMA_CHNL_SWITCH_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pChnlParams; + msgQ.bodyval = 0; + pe_debug("Sending CH_SWITCH_REQ, ch_width %d, ch_num %d, maxTxPower %d", + pChnlParams->ch_width, + pChnlParams->channelNumber, pChnlParams->maxTxPower); + MTRACE(mac_trace_msg_tx(pMac, peSessionId, msgQ.type)); + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(pMac, &msgQ)) { + qdf_mem_free(pChnlParams); + pe_err("Posting CH_SWITCH_REQ to WMA failed"); + return QDF_STATUS_E_FAILURE; + } + pSessionEntry->ch_switch_in_progress = true; + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_edca_params() + * + ***FUNCTION: + * This function is called to send dynamically changing EDCA Parameters to WMA. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param tpUpdatedEdcaParams pointer to the structure which contains + * dynamically changing EDCA parameters. + * @param highPerformance If the peer is Airgo (taurus) then switch to highPerformance is true. + * + * @return success if message send is ok, else false. + */ +QDF_STATUS lim_send_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t bssIdx, bool mu_edca) +{ + tEdcaParams *pEdcaParams = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pEdcaParams = qdf_mem_malloc(sizeof(tEdcaParams)); + if (NULL == pEdcaParams) { + pe_err("Unable to allocate memory during Update EDCA Params"); + retCode = QDF_STATUS_E_NOMEM; + return retCode; + } + pEdcaParams->bssIdx = bssIdx; + pEdcaParams->acbe = pUpdatedEdcaParams[EDCA_AC_BE]; + pEdcaParams->acbk = pUpdatedEdcaParams[EDCA_AC_BK]; + pEdcaParams->acvi = pUpdatedEdcaParams[EDCA_AC_VI]; + pEdcaParams->acvo = pUpdatedEdcaParams[EDCA_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(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pEdcaParams); + pe_err("Posting WMA_UPDATE_EDCA_PROFILE_IND failed, reason=%X", + retCode); + } + return retCode; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tSirMacEdcaParamRecord *edca_params, + tpPESession 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 */ + /* Initialize gLimEdcaParamsActive[] to be same as localEdcaParams */ + pe_session->gLimEdcaParamsActive[EDCA_AC_BE] = edca_params[EDCA_AC_BE]; + pe_session->gLimEdcaParamsActive[EDCA_AC_BK] = edca_params[EDCA_AC_BK]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VI] = edca_params[EDCA_AC_VI]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VO] = edca_params[EDCA_AC_VO]; + + pe_session->gLimEdcaParamsActive[EDCA_AC_BE].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_AC_BE]; + pe_session->gLimEdcaParamsActive[EDCA_AC_BK].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_AC_BK]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VI].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_AC_VI]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VO].no_ack = + mac_ctx->no_ack_policy_cfg[EDCA_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. + */ + pe_debug("adAdmitMask[UPLINK] = 0x%x ", + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK]); + pe_debug("adAdmitMask[DOWNLINK] = 0x%x ", + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK]); + for (ac = EDCA_AC_BK; ac <= EDCA_AC_VO; ac++) { + ac_admitted = + ((pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] & + (1 << ac)) >> ac); + + pe_debug("For 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)) { + pe_debug("We need to downgrade AC %d!!", ac); + /* Loop backwards through AC values until it finds + * acm == 0 or reaches EDCA_AC_BE. + * Note that for block has no executable statements. + */ + for (i = ac - 1; + (i > EDCA_AC_BE && + (edca_params[i].aci.acm != 0)); + i--) + ; + new_ac = i; + pe_debug("Downgrading AC %d ---> AC %d ", ac, new_ac); + pe_session->gLimEdcaParamsActive[ac] = + edca_params[new_ac]; + } + } +/* 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[EDCA_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[EDCA_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[EDCA_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[EDCA_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; +} + +/** --------------------------------------------------------- + \fn lim_set_link_state + \brief LIM sends a message to WMA to set the link state + \param tpAniSirGlobal pMac + \param tSirLinkState state + \return None + -----------------------------------------------------------*/ +QDF_STATUS lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMacAddr, + tpSetLinkStateCallback callback, + void *callbackArg) +{ + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode; + tpLinkStateParams pLinkStateParams = NULL; + /* Allocate memory. */ + pLinkStateParams = qdf_mem_malloc(sizeof(tLinkStateParams)); + if (NULL == pLinkStateParams) { + pe_err("Unable to allocate memory while sending Set Link State"); + retCode = QDF_STATUS_E_NOMEM; + return retCode; + } + pLinkStateParams->state = state; + pLinkStateParams->callback = callback; + pLinkStateParams->callbackArg = callbackArg; + + /* Copy Mac address */ + sir_copy_mac_addr(pLinkStateParams->bssid, bssId); + sir_copy_mac_addr(pLinkStateParams->selfMacAddr, selfMacAddr); + + msgQ.type = WMA_SET_LINK_STATE; + msgQ.reserved = 0; + msgQ.bodyptr = pLinkStateParams; + msgQ.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + retCode = (uint32_t) wma_post_ctrl_msg(pMac, &msgQ); + if (retCode != QDF_STATUS_SUCCESS) { + qdf_mem_free(pLinkStateParams); + pe_err("Posting link state %d failed, reason = %x", state, + retCode); + } + return retCode; +} + +extern QDF_STATUS lim_set_link_state_ft(tpAniSirGlobal pMac, tSirLinkState + state, tSirMacAddr bssId, + tSirMacAddr selfMacAddr, int ft, + tpPESession psessionEntry) +{ + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode; + tpLinkStateParams pLinkStateParams = NULL; + /* Allocate memory. */ + pLinkStateParams = qdf_mem_malloc(sizeof(tLinkStateParams)); + if (NULL == pLinkStateParams) { + pe_err("Unable to allocate memory while sending Set Link State"); + retCode = QDF_STATUS_E_NOMEM; + return retCode; + } + pLinkStateParams->state = state; + /* Copy Mac address */ + sir_copy_mac_addr(pLinkStateParams->bssid, bssId); + sir_copy_mac_addr(pLinkStateParams->selfMacAddr, selfMacAddr); + pLinkStateParams->ft = 1; + pLinkStateParams->session = psessionEntry; + + msgQ.type = WMA_SET_LINK_STATE; + msgQ.reserved = 0; + msgQ.bodyptr = pLinkStateParams; + msgQ.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + } else { + MTRACE(mac_trace_msg_tx + (pMac, psessionEntry->peSessionId, msgQ.type)); + } + + retCode = (uint32_t) wma_post_ctrl_msg(pMac, &msgQ); + if (retCode != QDF_STATUS_SUCCESS) { + qdf_mem_free(pLinkStateParams); + pe_err("Posting link state %d failed, reason = %x", state, + retCode); + } + return retCode; +} + +QDF_STATUS lim_send_mode_update(tpAniSirGlobal pMac, + tUpdateVHTOpMode *pTempParam, + tpPESession psessionEntry) +{ + tUpdateVHTOpMode *pVhtOpMode = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pVhtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pVhtOpMode) { + pe_err("Unable to allocate memory during Update Op Mode"); + 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, sta_id %d", + pVhtOpMode->opMode, pVhtOpMode->staId); + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &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(tpAniSirGlobal pMac, + tUpdateRxNss *pTempParam, + tpPESession psessionEntry) +{ + tUpdateRxNss *pRxNss = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pRxNss = qdf_mem_malloc(sizeof(tUpdateRxNss)); + if (NULL == pRxNss) { + pe_err("Unable to allocate memory during Update Rx Nss"); + 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 (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &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(tpAniSirGlobal pMac, + tUpdateMembership *pTempParam, + tpPESession psessionEntry) +{ + tUpdateMembership *pMembership = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pMembership = qdf_mem_malloc(sizeof(tUpdateMembership)); + if (NULL == pMembership) { + pe_err("Unable to allocate memory during Update Membership Mode"); + 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 (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &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(tpAniSirGlobal pMac, + tUpdateUserPos *pTempParam, + tpPESession psessionEntry) +{ + tUpdateUserPos *pUserPos = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pUserPos = qdf_mem_malloc(sizeof(tUpdateUserPos)); + if (NULL == pUserPos) { + pe_err("Unable to allocate memory during Update User Position"); + 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 (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pUserPos); + pe_err("Posting WMA_UPDATE_USERPOS failed, reason=%X", + retCode); + } + + return retCode; +} + +#ifdef WLAN_FEATURE_11W +/** + * lim_send_exclude_unencrypt_ind() - sends WMA_EXCLUDE_UNENCRYPTED_IND to HAL + * @pMac: mac global context + * @excludeUnenc: true: ignore, false: indicate + * @psessionEntry: 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(tpAniSirGlobal pMac, + bool excludeUnenc, + tpPESession psessionEntry) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + tSirWlanExcludeUnencryptParam *pExcludeUnencryptParam; + + pExcludeUnencryptParam = + qdf_mem_malloc(sizeof(tSirWlanExcludeUnencryptParam)); + if (NULL == pExcludeUnencryptParam) { + pe_err("Unable to allocate memory during lim_send_exclude_unencrypt_ind"); + return QDF_STATUS_E_NOMEM; + } + + pExcludeUnencryptParam->excludeUnencrypt = excludeUnenc; + qdf_mem_copy(pExcludeUnencryptParam->bssid.bytes, psessionEntry->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(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pExcludeUnencryptParam); + pe_err("Posting WMA_EXCLUDE_UNENCRYPTED_IND failed, reason=%X", + retCode); + } + + return retCode; +} +#endif + +/** + * 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(tpAniSirGlobal mac_ctx, + struct sPESession *session) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct obss_ht40_scanind *ht40_obss_scanind; + uint32_t channelnum; + struct scheduler_msg msg = {0}; + uint8_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t channel24gnum, count; + + ht40_obss_scanind = qdf_mem_malloc(sizeof(struct obss_ht40_scanind)); + if (NULL == ht40_obss_scanind) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "Memory allocation failed"); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "OBSS Scan Indication bssIdx- %d staId %d", + session->bssIdx, session->staId); + + 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( + mac_ctx->scan.countryCodeCurrent, + session->currentOperChannel, + session->ch_width); + channelnum = WNI_CFG_VALID_CHANNEL_LIST_LEN; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_VALID_CHANNEL_LIST, + chan_list, &channelnum) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve Valid channel list"); + qdf_mem_free(ht40_obss_scanind); + return QDF_STATUS_E_FAILURE; + } + /* Extract 24G channel list */ + channel24gnum = 0; + for (count = 0; count < channelnum && + (channel24gnum < SIR_ROAM_MAX_CHANNELS); count++) { + if ((chan_list[count] > CHAN_ENUM_1) && + (chan_list[count] < CHAN_ENUM_14)) { + ht40_obss_scanind->channels[channel24gnum] = + chan_list[count]; + channel24gnum++; + } + } + ht40_obss_scanind->channel_count = channel24gnum; + /* FW API requests BSS IDX */ + ht40_obss_scanind->self_sta_idx = session->staId; + ht40_obss_scanind->bss_id = session->bssIdx; + 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("Sending WDA_HT40_OBSS_SCAN_IND to WDA" + "Obss Scan trigger width: %d, delay factor: %d", + ht40_obss_scanind->obss_width_trigger_interval, + ht40_obss_scanind->bsswidth_ch_trans_delay); + 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; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h new file mode 100644 index 0000000000000000000000000000000000000000..6d3d405be94c8e97a0a1fb2d8d433358ec824b62 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h @@ -0,0 +1,101 @@ +/* + * 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. + */ + +/* + * + * 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_cf_params(tpAniSirGlobal pMac, uint8_t bssIdx, + uint8_t cfpCount, uint8_t cfpPeriod); +QDF_STATUS lim_send_beacon_params(tpAniSirGlobal pMac, + tpUpdateBeaconParams pUpdatedBcnParams, + tpPESession psessionEntry); +/* QDF_STATUS lim_send_beacon_params(tpAniSirGlobal pMac, tpUpdateBeaconParams pUpdatedBcnParams); */ +QDF_STATUS lim_send_mode_update(tpAniSirGlobal pMac, + tUpdateVHTOpMode *tempParam, + tpPESession psessionEntry); +QDF_STATUS lim_send_rx_nss_update(tpAniSirGlobal pMac, + tUpdateRxNss *tempParam, + tpPESession psessionEntry); + +QDF_STATUS lim_set_membership(tpAniSirGlobal pMac, + tUpdateMembership *pTempParam, + tpPESession psessionEntry); + +QDF_STATUS lim_set_user_pos(tpAniSirGlobal pMac, + tUpdateUserPos *pTempParam, + tpPESession psessionEntry); +QDF_STATUS lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, + int8_t maxTxPower, + uint8_t peSessionId, + uint8_t is_restart, + uint32_t cac_duration_ms, + uint32_t dfs_regdomain); + +QDF_STATUS lim_send_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t bssIdx, bool mu_edca); +QDF_STATUS lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMac, + tpSetLinkStateCallback callback, + void *callbackArg); +extern QDF_STATUS lim_set_link_state_ft(tpAniSirGlobal pMac, tSirLinkState + state, tSirMacAddr bssId, + tSirMacAddr selfMacAddr, int ft, + tpPESession psessionEntry); +void lim_set_active_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *plocalEdcaParams, + tpPESession psessionEntry); +#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 + +#ifdef WLAN_FEATURE_11W +QDF_STATUS lim_send_exclude_unencrypt_ind(tpAniSirGlobal pMac, + bool excludeUnenc, + tpPESession psessionEntry); +#endif +QDF_STATUS lim_send_ht40_obss_scanind(tpAniSirGlobal mac_ctx, + tpPESession session); +void lim_handle_sme_join_result(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..3564fe6d662e7992f2dd981d1e4580167e7bfcb2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -0,0 +1,2499 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.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_ibss_peer_mgmt.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" + +static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirResultCodes result_code, + tpSirSmeJoinRsp sme_join_rsp); + +/** + * lim_send_sme_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 + * + * 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(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint16_t sme_transaction_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 (NULL == sme_rsp) { + /* Buffer not available. Log error */ + pe_err("call to AllocateMemory failed for eWNI_SME_*_RSP"); + return; + } + + sme_rsp->messageType = msg_type; + sme_rsp->length = sizeof(tSirSmeRsp); + sme_rsp->statusCode = result_code; + + sme_rsp->sessionId = sme_session_id; + sme_rsp->transactionId = sme_transaction_id; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.bodyval = 0; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TX_SME_MSG, + sme_session_id, msg.type)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + switch (msg_type) { + case eWNI_SME_STOP_BSS_RSP: + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, + NULL, (uint16_t) result_code, 0); + break; + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + + + +/** + * lim_send_sme_roc_rsp() - Send Response to SME + * @mac_ctx: Pointer to Global MAC structure + * @status: Resume link status + * @result_code: Result of the ROC request + * @sme_session_id: SME sesson Id + * @scan_id: Scan Identifier + * + * This function is called to send ROC rsp + * message to SME. + * + * Return: None + */ +void +lim_send_sme_roc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint32_t scan_id) +{ + struct scheduler_msg msg = {0}; + struct sir_roc_rsp *sme_rsp; + + pe_debug("Sending message: %s with reasonCode: %s scanId: %d", + lim_msg_str(msg_type), lim_result_code_str(result_code), + scan_id); + + sme_rsp = qdf_mem_malloc(sizeof(struct sir_roc_rsp)); + if (NULL == sme_rsp) { + pe_err("call to AllocateMemory failed for eWNI_SME_*_RSP"); + return; + } + + sme_rsp->message_type = msg_type; + sme_rsp->length = sizeof(struct sir_roc_rsp); + sme_rsp->status = result_code; + + sme_rsp->session_id = sme_session_id; + sme_rsp->scan_id = scan_id; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, sme_session_id, msg.type)); + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + + +/** + * 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(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds) +{ + uint32_t rate_flags = 0; + + if (sta_ds == NULL) { + pe_err("sta_ds is NULL"); + return rate_flags; + } + + if (!sta_ds->mlmStaContext.htCapability && + !sta_ds->mlmStaContext.vhtCapability) { + rate_flags |= TX_RATE_LEGACY; + } else { + if (sta_ds->mlmStaContext.vhtCapability) { + 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; +} + +/** + * lim_send_sme_join_reassoc_rsp_after_resume() - Send Response to SME + * @mac_ctx Pointer to Global MAC structure + * @status Resume link status + * @ctx context passed while calling resmune link. + * (join response to be sent) + * + * This function is called to send Join/Reassoc rsp + * message to SME after the resume link. + * + * Return: None + */ +static void lim_send_sme_join_reassoc_rsp_after_resume(tpAniSirGlobal mac_ctx, + QDF_STATUS status, uint32_t *ctx) +{ + struct scheduler_msg msg = {0}; + tpSirSmeJoinRsp sme_join_rsp = (tpSirSmeJoinRsp) ctx; + + msg.type = sme_join_rsp->messageType; + msg.bodyptr = sme_join_rsp; + msg.bodyval = 0; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TX_SME_MSG, NO_SESSION, msg.type)); + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + +/** + * lim_handle_join_rsp_status() - Handle the response. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE Session Info + * @result_code: Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * @sme_join_rsp The received response. + * + * This function will handle both the success and failure status + * of the received response. + * + * Return: None + */ +static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirResultCodes result_code, + tpSirSmeJoinRsp sme_join_rsp) +{ + uint16_t bss_ie_len; + void *bss_ies; + bool is_vendor_ap_1_present; + tpSirSmeJoinReq join_reassoc_req = NULL; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *ht_profile; +#endif + if (result_code == eSIR_SME_SUCCESS) { + if (session_entry->beacon != NULL) { + sme_join_rsp->beaconLength = session_entry->bcnLen; + qdf_mem_copy(sme_join_rsp->frames, + session_entry->beacon, + sme_join_rsp->beaconLength); + qdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + session_entry->bcnLen = 0; + pe_debug("Beacon: %d", + sme_join_rsp->beaconLength); + } + if (session_entry->assocReq != NULL) { + sme_join_rsp->assocReqLength = + session_entry->assocReqLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength, + session_entry->assocReq, + sme_join_rsp->assocReqLength); + qdf_mem_free(session_entry->assocReq); + session_entry->assocReq = NULL; + session_entry->assocReqLen = 0; + pe_debug("AssocReq: %d", + sme_join_rsp->assocReqLength); + } + if (session_entry->assocRsp != NULL) { + sme_join_rsp->assocRspLength = + session_entry->assocRspLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength + + sme_join_rsp->assocReqLength, + session_entry->assocRsp, + sme_join_rsp->assocRspLength); + qdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + session_entry->assocRspLen = 0; + } + if (session_entry->ricData != NULL) { + sme_join_rsp->parsedRicRspLen = + session_entry->RICDataLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength + + sme_join_rsp->assocReqLength + + sme_join_rsp->assocRspLength, + session_entry->ricData, + sme_join_rsp->parsedRicRspLen); + qdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + session_entry->RICDataLen = 0; + pe_debug("RicLength: %d", + sme_join_rsp->parsedRicRspLen); + } +#ifdef FEATURE_WLAN_ESE + if (session_entry->tspecIes != NULL) { + sme_join_rsp->tspecIeLen = + session_entry->tspecLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength + + sme_join_rsp->assocReqLength + + sme_join_rsp->assocRspLength + + sme_join_rsp->parsedRicRspLen, + session_entry->tspecIes, + sme_join_rsp->tspecIeLen); + qdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + session_entry->tspecLen = 0; + pe_debug("ESE-TspecLen: %d", + sme_join_rsp->tspecIeLen); + } +#endif + sme_join_rsp->aid = session_entry->limAID; + pe_debug("AssocRsp: %d", + sme_join_rsp->assocRspLength); + sme_join_rsp->vht_channel_width = + session_entry->ch_width; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (session_entry->cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_DISABLE) { + ht_profile = &sme_join_rsp->HTProfile; + ht_profile->htSupportedChannelWidthSet = + session_entry->htSupportedChannelWidthSet; + ht_profile->htRecommendedTxWidthSet = + session_entry->htRecommendedTxWidthSet; + ht_profile->htSecondaryChannelOffset = + session_entry->htSecondaryChannelOffset; + ht_profile->dot11mode = session_entry->dot11mode; + ht_profile->htCapability = session_entry->htCapability; + ht_profile->vhtCapability = + session_entry->vhtCapability; + ht_profile->apCenterChan = session_entry->ch_center_freq_seg0; + ht_profile->apChanWidth = session_entry->ch_width; + } +#endif + pe_debug("pLimJoinReq:%pK, pLimReAssocReq:%pK", + session_entry->pLimJoinReq, + session_entry->pLimReAssocReq); + + if (session_entry->pLimJoinReq) + join_reassoc_req = session_entry->pLimJoinReq; + + if (session_entry->pLimReAssocReq) + join_reassoc_req = session_entry->pLimReAssocReq; + + if (!join_reassoc_req) { + pe_err("both pLimJoinReq and pLimReAssocReq NULL"); + return; + } + + bss_ie_len = lim_get_ielen_from_bss_description( + &join_reassoc_req->bssDescription); + bss_ies = &join_reassoc_req->bssDescription.ieFields; + is_vendor_ap_1_present = (wlan_get_vendor_ie_ptr_from_oui( + SIR_MAC_VENDOR_AP_1_OUI, SIR_MAC_VENDOR_AP_1_OUI_LEN, + bss_ies, bss_ie_len) != NULL); + + if (mac_ctx->roam.configParam.is_force_1x1_enable && + is_vendor_ap_1_present && (session_entry->nss == 2) && + (mac_ctx->lteCoexAntShare == 0 || + IS_5G_CH(session_entry->currentOperChannel))) { + /* SET vdev param */ + pe_debug("sending SMPS intolrent vdev_param"); + wma_cli_set_command(session_entry->smeSessionId, + (int)WMI_VDEV_PARAM_SMPS_INTOLERANT, + 1, VDEV_CMD); + + } + } else { + if (session_entry->beacon != NULL) { + qdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + session_entry->bcnLen = 0; + } + if (session_entry->assocReq != NULL) { + qdf_mem_free(session_entry->assocReq); + session_entry->assocReq = NULL; + session_entry->assocReqLen = 0; + } + if (session_entry->assocRsp != NULL) { + qdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + session_entry->assocRspLen = 0; + } + if (session_entry->ricData != NULL) { + qdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + session_entry->RICDataLen = 0; + } +#ifdef FEATURE_WLAN_ESE + if (session_entry->tspecIes != NULL) { + qdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + session_entry->tspecLen = 0; + } +#endif + } +} + +/** + * lim_add_bss_info() - copy data from session entry to join rsp + * @sta_ds: Station dph entry + * @sme_join_rsp: Join response buffer to be filled up + * + * Return: None + */ +static void lim_add_bss_info(tpDphHashNode sta_ds, tpSirSmeJoinRsp sme_join_rsp) +{ + struct parsed_ies *parsed_ies = &sta_ds->parsed_ies; + + if (parsed_ies->hs20vendor_ie.present) + sme_join_rsp->hs20vendor_ie = parsed_ies->hs20vendor_ie; + if (parsed_ies->vht_caps.present) + sme_join_rsp->vht_caps = parsed_ies->vht_caps; + if (parsed_ies->ht_caps.present) + sme_join_rsp->ht_caps = parsed_ies->ht_caps; + if (parsed_ies->ht_operation.present) + sme_join_rsp->ht_operation = parsed_ies->ht_operation; + if (parsed_ies->vht_operation.present) + sme_join_rsp->vht_operation = parsed_ies->vht_operation; +} + +#ifdef WLAN_FEATURE_FILS_SK +static void lim_update_fils_seq_num(tpSirSmeJoinRsp sme_join_rsp, + tpPESession session_entry) +{ + sme_join_rsp->fils_seq_num = + session_entry->fils_info->sequence_number; +} +#else +static inline void lim_update_fils_seq_num(tpSirSmeJoinRsp sme_join_rsp, + tpPESession session_entry) +{} +#endif +/** + * 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 + * eWNI_SME_msgType_REQ message + * @prot_status_code: Protocol Status Code + * @session_entry: PE Session Info + * @sme_session_id: SME Session ID + * @sme_transaction_id: SME Transaction 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(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint16_t prot_status_code, + tpPESession session_entry, uint8_t sme_session_id, + uint16_t sme_transaction_id) +{ + tpSirSmeJoinRsp sme_join_rsp; + uint32_t rsp_len; + tpDphHashNode sta_ds = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (msg_type == eWNI_SME_REASSOC_RSP) + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_RSP_EVENT, + session_entry, (uint16_t) result_code, 0); + else + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_RSP_EVENT, + session_entry, (uint16_t) result_code, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + pe_debug("Sending message: %s with reasonCode: %s", + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + if (session_entry == NULL) { + rsp_len = sizeof(tSirSmeJoinRsp); + sme_join_rsp = qdf_mem_malloc(rsp_len); + if (NULL == sme_join_rsp) { + pe_err("Mem Alloc fail - JOIN/REASSOC_RSP"); + return; + } + + sme_join_rsp->beaconLength = 0; + sme_join_rsp->assocReqLength = 0; + sme_join_rsp->assocRspLength = 0; + } else { + rsp_len = session_entry->assocReqLen + + session_entry->assocRspLen + session_entry->bcnLen + + session_entry->RICDataLen + +#ifdef FEATURE_WLAN_ESE + session_entry->tspecLen + +#endif + sizeof(tSirSmeJoinRsp) - sizeof(uint8_t); + sme_join_rsp = qdf_mem_malloc(rsp_len); + if (NULL == sme_join_rsp) { + pe_err("MemAlloc fail - JOIN/REASSOC_RSP"); + return; + } + + if (lim_is_fils_connection(session_entry)) { + sme_join_rsp->is_fils_connection = true; + lim_update_fils_seq_num(sme_join_rsp, + session_entry); + } + + if (result_code == eSIR_SME_SUCCESS) { + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + pe_err("Get Self Sta Entry fail"); + } else { + /* Pass the peer's staId */ + sme_join_rsp->staId = sta_ds->staIndex; + sme_join_rsp->timingMeasCap = + sta_ds->timingMeasCap; +#ifdef FEATURE_WLAN_TDLS + sme_join_rsp->tdls_prohibited = + session_entry->tdls_prohibited; + sme_join_rsp->tdls_chan_swit_prohibited = + session_entry->tdls_chan_swit_prohibited; +#endif + sme_join_rsp->nss = sta_ds->nss; + sme_join_rsp->max_rate_flags = + lim_get_max_rate_flags(mac_ctx, sta_ds); + lim_add_bss_info(sta_ds, sme_join_rsp); + + /* Copy FILS params only for Successful join */ + populate_fils_connect_params(mac_ctx, + session_entry, sme_join_rsp); + } + } + + sme_join_rsp->beaconLength = 0; + sme_join_rsp->assocReqLength = 0; + sme_join_rsp->assocRspLength = 0; + sme_join_rsp->parsedRicRspLen = 0; +#ifdef FEATURE_WLAN_ESE + sme_join_rsp->tspecIeLen = 0; +#endif + lim_handle_join_rsp_status(mac_ctx, session_entry, result_code, + sme_join_rsp); + sme_join_rsp->uapsd_mask = session_entry->gUapsdPerAcBitmask; + /* Send supported NSS 1x1 to SME */ + sme_join_rsp->supported_nss_1x1 = + session_entry->supported_nss_1x1; + pe_debug("SME Join Rsp is supported NSS 1X1: %d", + sme_join_rsp->supported_nss_1x1); + } + + sme_join_rsp->messageType = msg_type; + sme_join_rsp->length = (uint16_t) rsp_len; + sme_join_rsp->statusCode = result_code; + sme_join_rsp->protStatusCode = prot_status_code; + + sme_join_rsp->sessionId = sme_session_id; + sme_join_rsp->transactionId = sme_transaction_id; + + lim_send_sme_join_reassoc_rsp_after_resume(mac_ctx, QDF_STATUS_SUCCESS, + (uint32_t *)sme_join_rsp); +} + +/** + * lim_send_sme_start_bss_rsp() + * + ***FUNCTION: + * This function is called to send eWNI_SME_START_BSS_RSP + * message to applications above MAC Software. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates message type + * @param resultCode Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * + * @return None + */ + +void +lim_send_sme_start_bss_rsp(tpAniSirGlobal pMac, + uint16_t msgType, tSirResultCodes resultCode, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + + uint16_t size = 0; + struct scheduler_msg mmhMsg = {0}; + tSirSmeStartBssRsp *pSirSmeRsp; + uint16_t ieLen; + uint16_t ieOffset, curLen; + + pe_debug("Sending message: %s with reasonCode: %s", + lim_msg_str(msgType), lim_result_code_str(resultCode)); + + size = sizeof(tSirSmeStartBssRsp); + + if (psessionEntry == NULL) { + pSirSmeRsp = qdf_mem_malloc(size); + if (NULL == pSirSmeRsp) { + /* / Buffer not available. Log error */ + pe_err("call to AllocateMemory failed for eWNI_SME_START_BSS_RSP"); + return; + } + } else { + /* subtract size of beaconLength + Mac Hdr + Fixed Fields before SSID */ + ieOffset = sizeof(tAniBeaconStruct) + SIR_MAC_B_PR_SSID_OFFSET; + ieLen = psessionEntry->schBeaconOffsetBegin + + psessionEntry->schBeaconOffsetEnd - ieOffset; + /* calculate the memory size to allocate */ + size += ieLen; + + pSirSmeRsp = qdf_mem_malloc(size); + if (NULL == pSirSmeRsp) { + /* / Buffer not available. Log error */ + pe_err("call to AllocateMemory failed for eWNI_SME_START_BSS_RSP"); + return; + } + size = sizeof(tSirSmeStartBssRsp); + if (resultCode == eSIR_SME_SUCCESS) { + + sir_copy_mac_addr(pSirSmeRsp->bssDescription.bssId, + psessionEntry->bssId); + + /* Read beacon interval from session */ + pSirSmeRsp->bssDescription.beaconInterval = + (uint16_t) psessionEntry->beaconParams. + beaconInterval; + pSirSmeRsp->bssType = psessionEntry->bssType; + + if (cfg_get_capability_info + (pMac, &pSirSmeRsp->bssDescription.capabilityInfo, + psessionEntry) + != QDF_STATUS_SUCCESS) + pe_err("could not retrieve Capabilities value"); + + lim_get_phy_mode(pMac, + (uint32_t *) &pSirSmeRsp->bssDescription. + nwType, psessionEntry); + + pSirSmeRsp->bssDescription.channelId = + psessionEntry->currentOperChannel; + + if (!LIM_IS_NDI_ROLE(psessionEntry)) { + curLen = psessionEntry->schBeaconOffsetBegin - ieOffset; + qdf_mem_copy((uint8_t *) &pSirSmeRsp->bssDescription. + ieFields, + psessionEntry->pSchBeaconFrameBegin + + ieOffset, (uint32_t) curLen); + + qdf_mem_copy(((uint8_t *) &pSirSmeRsp->bssDescription. + ieFields) + curLen, + psessionEntry->pSchBeaconFrameEnd, + (uint32_t) psessionEntry-> + schBeaconOffsetEnd); + + pSirSmeRsp->bssDescription.length = (uint16_t) + (offsetof(tSirBssDescription, ieFields[0]) + - sizeof(pSirSmeRsp->bssDescription.length) + + ieLen); + /* This is the size of the message, subtracting the size of the pointer to ieFields */ + size += ieLen - sizeof(uint32_t); + } +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (psessionEntry->cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) { + pSirSmeRsp->HTProfile. + htSupportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + pSirSmeRsp->HTProfile.htRecommendedTxWidthSet = + psessionEntry->htRecommendedTxWidthSet; + pSirSmeRsp->HTProfile.htSecondaryChannelOffset = + psessionEntry->htSecondaryChannelOffset; + pSirSmeRsp->HTProfile.dot11mode = + psessionEntry->dot11mode; + pSirSmeRsp->HTProfile.htCapability = + psessionEntry->htCapability; + pSirSmeRsp->HTProfile.vhtCapability = + psessionEntry->vhtCapability; + pSirSmeRsp->HTProfile.apCenterChan = + psessionEntry->ch_center_freq_seg0; + pSirSmeRsp->HTProfile.apChanWidth = + psessionEntry->ch_width; + } +#endif + } + } + pSirSmeRsp->messageType = msgType; + pSirSmeRsp->length = size; + + /* Update SME session Id and transaction Id */ + pSirSmeRsp->sessionId = smesessionId; + pSirSmeRsp->transactionId = smetransactionId; + pSirSmeRsp->statusCode = resultCode; + if (psessionEntry != NULL) + pSirSmeRsp->staId = psessionEntry->staId; /* else it will be always zero smeRsp StaID = 0 */ + + mmhMsg.type = msgType; + mmhMsg.bodyptr = pSirSmeRsp; + mmhMsg.bodyval = 0; + if (psessionEntry == NULL) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_START_BSS_RSP_EVENT, + psessionEntry, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} /*** end lim_send_sme_start_bss_rsp() ***/ + +void lim_send_sme_disassoc_deauth_ntf(tpAniSirGlobal pMac, + 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(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, mmhMsg.type)); + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +/** + * lim_send_sme_disassoc_ntf() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_DISASSOC_RSP/IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_DISASSOC_CNF, + * or eWNI_SME_DISASSOC_IND to host depending on + * disassociation trigger. + * + * @param peerMacAddr Indicates the peer MAC addr to which + * disassociate was initiated + * @param reasonCode Indicates the reason for Disassociation + * @param disassocTrigger Indicates the trigger for Disassociation + * @param aid Indicates the STAID. This parameter is + * present only on AP. + * + * @return None + */ +void +lim_send_sme_disassoc_ntf(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, + uint16_t disassocTrigger, + uint16_t aid, + uint8_t smesessionId, + uint16_t smetransactionId, tpPESession psessionEntry) +{ + + uint8_t *pBuf; + tSirSmeDisassocRsp *pSirSmeDisassocRsp; + tSirSmeDisassocInd *pSirSmeDisassocInd; + uint32_t *pMsg = NULL; + bool failure = false; + tpPESession session = NULL; + uint16_t i, assoc_id; + tpDphHashNode sta_ds = NULL; + QDF_STATUS status; + + 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 " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peerMacAddr)); + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((&pMac->lim.gpSession[i] != NULL) && + (pMac->lim.gpSession[i].valid) && + (pMac->lim.gpSession[i].pePersona == + QDF_SAP_MODE)) { + /* Find the sta ds entry in another session */ + session = &pMac->lim.gpSession[i]; + sta_ds = dph_lookup_hash_entry(pMac, + peerMacAddr, &assoc_id, + &session->dph.dphHashTable); + if (sta_ds) + break; + } + } + if (sta_ds +#ifdef WLAN_FEATURE_11W + && (!sta_ds->rmfEnabled) +#endif + ) { + if (lim_add_sta(pMac, 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(pMac, &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(tSirSmeDisassocRsp)); + if (NULL == pSirSmeDisassocRsp) { + /* Log error */ + pe_err("Memory allocation failed"); + failure = true; + goto error; + } + pe_debug("send eWNI_SME_DISASSOC_RSP with retCode: %d for " MAC_ADDRESS_STR, + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDisassocRsp->messageType = eWNI_SME_DISASSOC_RSP; + pSirSmeDisassocRsp->length = sizeof(tSirSmeDisassocRsp); + /* sessionId */ + pBuf = (uint8_t *) &pSirSmeDisassocRsp->sessionId; + *pBuf = smesessionId; + pBuf++; + + /* transactionId */ + lim_copy_u16(pBuf, smetransactionId); + pBuf += sizeof(uint16_t); + + /* statusCode */ + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + /* peerMacAddr */ + qdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + /* Clear Station Stats */ + /* for sta, it is always 1, IBSS is handled at halInitSta */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_RSP_EVENT, + psessionEntry, (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(pMac, &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(tSirSmeDisassocInd)); + if (NULL == pSirSmeDisassocInd) { + /* Log error */ + pe_err("Memory allocation failed"); + failure = true; + goto error; + } + pe_debug("send eWNI_SME_DISASSOC_IND with retCode: %d for " MAC_ADDRESS_STR, + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(tSirSmeDisassocInd); + + /* Update SME session Id and Transaction Id */ + pSirSmeDisassocInd->sessionId = smesessionId; + pSirSmeDisassocInd->transactionId = smetransactionId; + pSirSmeDisassocInd->reasonCode = reasonCode; + pBuf = (uint8_t *) &pSirSmeDisassocInd->statusCode; + + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + qdf_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + qdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, + psessionEntry, (uint16_t) reasonCode, 0); +#endif + pMsg = (uint32_t *) pSirSmeDisassocInd; + + break; + } + +error: + /* Delete the PE session Created */ + if ((psessionEntry != NULL) && LIM_IS_STA_ROLE(psessionEntry)) + pe_delete_session(pMac, psessionEntry); + + if (false == failure) + lim_send_sme_disassoc_deauth_ntf(pMac, QDF_STATUS_SUCCESS, + (uint32_t *) pMsg); +} /*** end lim_send_sme_disassoc_ntf() ***/ + +/** ----------------------------------------------------------------- + \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 pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_disassoc_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + struct scheduler_msg mmhMsg = {0}; + tSirSmeDisassocInd *pSirSmeDisassocInd; + + pSirSmeDisassocInd = qdf_mem_malloc(sizeof(tSirSmeDisassocInd)); + if (NULL == pSirSmeDisassocInd) { + pe_err("AllocateMemory failed for eWNI_SME_DISASSOC_IND"); + return; + } + + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(tSirSmeDisassocInd); + + pSirSmeDisassocInd->sessionId = psessionEntry->smeSessionId; + pSirSmeDisassocInd->transactionId = psessionEntry->transactionId; + pSirSmeDisassocInd->statusCode = eSIR_SME_DEAUTH_STATUS; + pSirSmeDisassocInd->reasonCode = pStaDs->mlmStaContext.disassocReason; + + qdf_mem_copy(pSirSmeDisassocInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + + qdf_mem_copy(pSirSmeDisassocInd->peer_macaddr.bytes, pStaDs->staAddr, + QDF_MAC_ADDR_SIZE); + + pSirSmeDisassocInd->staId = pStaDs->staIndex; + + mmhMsg.type = eWNI_SME_DISASSOC_IND; + mmhMsg.bodyptr = pSirSmeDisassocInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, psessionEntry, + 0, (uint16_t) pStaDs->mlmStaContext.disassocReason); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + +} /*** 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 pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_deauth_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + struct scheduler_msg mmhMsg = {0}; + tSirSmeDeauthInd *pSirSmeDeauthInd; + + pSirSmeDeauthInd = qdf_mem_malloc(sizeof(tSirSmeDeauthInd)); + if (NULL == pSirSmeDeauthInd) { + pe_err("AllocateMemory failed for eWNI_SME_DEAUTH_IND"); + return; + } + + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(tSirSmeDeauthInd); + + pSirSmeDeauthInd->sessionId = psessionEntry->smeSessionId; + pSirSmeDeauthInd->transactionId = psessionEntry->transactionId; + if (eSIR_INFRA_AP_MODE == psessionEntry->bssType) { + pSirSmeDeauthInd->statusCode = + (tSirResultCodes) pStaDs->mlmStaContext.cleanupTrigger; + } else { + /* Need to indicatet he reascon code over the air */ + pSirSmeDeauthInd->statusCode = + (tSirResultCodes) pStaDs->mlmStaContext.disassocReason; + } + /* BSSID */ + qdf_mem_copy(pSirSmeDeauthInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + /* peerMacAddr */ + qdf_mem_copy(pSirSmeDeauthInd->peer_macaddr.bytes, pStaDs->staAddr, + QDF_MAC_ADDR_SIZE); + pSirSmeDeauthInd->reasonCode = pStaDs->mlmStaContext.disassocReason; + + pSirSmeDeauthInd->staId = pStaDs->staIndex; + if (eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON == + pStaDs->mlmStaContext.disassocReason) + pSirSmeDeauthInd->rssi = pStaDs->del_sta_ctx_rssi; + + mmhMsg.type = eWNI_SME_DEAUTH_IND; + mmhMsg.bodyptr = pSirSmeDeauthInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, psessionEntry, + 0, pStaDs->mlmStaContext.cleanupTrigger); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + 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 pMac - Pointer to global MAC structure + * @param pStaDs - Pointer to internal STA Datastructure + * @param psessionEntry - Pointer to the session entry + * @param reasonCode - Reason for TDLS sta deletion + * @return None + */ +void +lim_send_sme_tdls_del_sta_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry, uint16_t reasonCode) +{ + struct tdls_event_info info; + + pe_debug("Delete TDLS Peer "MAC_ADDRESS_STR "with reason code: %d", + MAC_ADDR_ARRAY(pStaDs->staAddr), reasonCode); + info.vdev_id = psessionEntry->smeSessionId; + qdf_mem_copy(info.peermac.bytes, pStaDs->staAddr, QDF_MAC_ADDR_SIZE); + info.message_type = TDLS_PEER_DISCONNECTED; + info.peer_reason = TDLS_DISCONNECTED_PEER_DELETE; + + tgt_tdls_event_handler(pMac->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 pMac - Pointer to global MAC structure + * @param psessionEntry - Pointer to the session entry + * @param txCompleteStatus - TX Complete Status of Mgmt Frames + * @return None + */ +void +lim_send_sme_mgmt_tx_completion(tpAniSirGlobal pMac, + uint32_t sme_session_id, + uint32_t txCompleteStatus) +{ + struct scheduler_msg mmhMsg = {0}; + tSirMgmtTxCompletionInd *pSirMgmtTxCompletionInd; + + pSirMgmtTxCompletionInd = + qdf_mem_malloc(sizeof(tSirMgmtTxCompletionInd)); + if (NULL == pSirMgmtTxCompletionInd) { + pe_err("AllocateMemory failed for eWNI_SME_MGMT_FRM_TX_COMPLETION_IND"); + return; + } + /* messageType */ + pSirMgmtTxCompletionInd->messageType = + eWNI_SME_MGMT_FRM_TX_COMPLETION_IND; + pSirMgmtTxCompletionInd->length = sizeof(tSirMgmtTxCompletionInd); + + /* sessionId */ + pSirMgmtTxCompletionInd->sessionId = sme_session_id; + + pSirMgmtTxCompletionInd->txCompleteStatus = txCompleteStatus; + + mmhMsg.type = eWNI_SME_MGMT_FRM_TX_COMPLETION_IND; + mmhMsg.bodyptr = pSirMgmtTxCompletionInd; + mmhMsg.bodyval = 0; + + pSirMgmtTxCompletionInd->psoc = pMac->psoc; + mmhMsg.callback = tgt_tdls_send_mgmt_tx_completion; + scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &mmhMsg); + return; +} /*** end lim_send_sme_tdls_delete_all_peer_ind() ***/ + +#endif /* FEATURE_WLAN_TDLS */ + +QDF_STATUS lim_prepare_disconnect_done_ind(tpAniSirGlobal 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) { + pe_err("Failed to allocate memory"); + 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; +} + +/** + * lim_send_sme_deauth_ntf() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_DISASSOC_RSP/IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_DEAUTH_CNF or + * eWNI_SME_DEAUTH_IND to host depending on deauthentication trigger. + * + * @param peerMacAddr Indicates the peer MAC addr to which + * deauthentication was initiated + * @param reasonCode Indicates the reason for Deauthetication + * @param deauthTrigger Indicates the trigger for Deauthetication + * @param aid Indicates the STAID. This parameter is present + * only on AP. + * + * @return None + */ +void +lim_send_sme_deauth_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, uint16_t deauthTrigger, + uint16_t aid, uint8_t smesessionId, + uint16_t smetransactionId) +{ + uint8_t *pBuf; + tSirSmeDeauthRsp *pSirSmeDeauthRsp; + tSirSmeDeauthInd *pSirSmeDeauthInd; + tpPESession psessionEntry; + uint8_t sessionId; + uint32_t *pMsg = NULL; + QDF_STATUS status; + + psessionEntry = pe_find_session_by_bssid(pMac, peerMacAddr, &sessionId); + switch (deauthTrigger) { + case eLIM_HOST_DEAUTH: + /** + * Deauthentication response to host triggered + * deauthentication. + */ + pSirSmeDeauthRsp = qdf_mem_malloc(sizeof(tSirSmeDeauthRsp)); + if (NULL == pSirSmeDeauthRsp) { + /* Log error */ + pe_err("call to AllocateMemory failed for eWNI_SME_DEAUTH_RSP"); + return; + } + pe_debug("send eWNI_SME_DEAUTH_RSP with retCode: %d for" MAC_ADDRESS_STR, + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDeauthRsp->messageType = eWNI_SME_DEAUTH_RSP; + pSirSmeDeauthRsp->length = sizeof(tSirSmeDeauthRsp); + pSirSmeDeauthRsp->statusCode = reasonCode; + pSirSmeDeauthRsp->sessionId = smesessionId; + pSirSmeDeauthRsp->transactionId = smetransactionId; + + 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(pMac, WLAN_PE_DIAG_DEAUTH_RSP_EVENT, + psessionEntry, 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(pMac, &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(tSirSmeDeauthInd)); + if (NULL == pSirSmeDeauthInd) { + /* Log error */ + pe_err("call to AllocateMemory failed for eWNI_SME_DEAUTH_Ind"); + return; + } + pe_debug("send eWNI_SME_DEAUTH_IND with retCode: %d for " MAC_ADDRESS_STR, + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(tSirSmeDeauthInd); + pSirSmeDeauthInd->reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON; + + /* sessionId */ + pBuf = (uint8_t *) &pSirSmeDeauthInd->sessionId; + *pBuf++ = smesessionId; + + /* transaction ID */ + lim_copy_u16(pBuf, smetransactionId); + pBuf += sizeof(uint16_t); + + /* status code */ + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + /* bssId */ + qdf_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + /* peerMacAddr */ + 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(pMac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, + psessionEntry, 0, (uint16_t) reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pMsg = (uint32_t *) pSirSmeDeauthInd; + + break; + } + + /*Delete the PE session created */ + if (psessionEntry && LIM_IS_STA_ROLE(psessionEntry)) + pe_delete_session(pMac, psessionEntry); + + lim_send_sme_disassoc_deauth_ntf(pMac, QDF_STATUS_SUCCESS, + (uint32_t *) pMsg); + +} /*** end lim_send_sme_deauth_ntf() ***/ + +/** + * lim_send_sme_wm_status_change_ntf() - Send Notification + * @mac_ctx: Global MAC Context + * @status_change_code: Indicates the change in the wireless medium. + * @status_change_info: Indicates the information associated with + * change in the wireless medium. + * @info_len: Indicates the length of status change information + * being sent. + * @session_id SessionID + * + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_WM_STATUS_CHANGE_NTF message to host. + * + * Return: None + */ +void +lim_send_sme_wm_status_change_ntf(tpAniSirGlobal mac_ctx, + tSirSmeStatusChangeCode status_change_code, + uint32_t *status_change_info, uint16_t info_len, uint8_t session_id) +{ + struct scheduler_msg msg = {0}; + tSirSmeWmStatusChangeNtf *wm_status_change_ntf; + uint32_t max_info_len; + + wm_status_change_ntf = qdf_mem_malloc(sizeof(tSirSmeWmStatusChangeNtf)); + if (NULL == wm_status_change_ntf) { + pe_err("Mem Alloc failed - eWNI_SME_WM_STATUS_CHANGE_NTF"); + return; + } + + msg.type = eWNI_SME_WM_STATUS_CHANGE_NTF; + msg.bodyval = 0; + msg.bodyptr = wm_status_change_ntf; + + switch (status_change_code) { + case eSIR_SME_AP_CAPS_CHANGED: + max_info_len = sizeof(tSirSmeApNewCaps); + break; + case eSIR_SME_JOINED_NEW_BSS: + max_info_len = sizeof(tSirSmeNewBssInfo); + break; + default: + max_info_len = sizeof(wm_status_change_ntf->statusChangeInfo); + break; + } + + switch (status_change_code) { + case eSIR_SME_RADAR_DETECTED: + break; + default: + wm_status_change_ntf->messageType = + eWNI_SME_WM_STATUS_CHANGE_NTF; + wm_status_change_ntf->statusChangeCode = status_change_code; + wm_status_change_ntf->length = sizeof(tSirSmeWmStatusChangeNtf); + wm_status_change_ntf->sessionId = session_id; + if (info_len <= max_info_len && status_change_info) { + qdf_mem_copy( + (uint8_t *) &wm_status_change_ntf->statusChangeInfo, + (uint8_t *) status_change_info, info_len); + } + pe_debug("StatusChg code: 0x%x length: %d", + status_change_code, info_len); + break; + } + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TX_SME_MSG, session_id, msg.type)); + if (QDF_STATUS_SUCCESS != lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT)) { + qdf_mem_free(wm_status_change_ntf); + pe_err("lim_sys_process_mmh_msg_api failed"); + } + +} /*** end lim_send_sme_wm_status_change_ntf() ***/ + +/** + * lim_send_sme_set_context_rsp() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_SETCONTEXT_RSP message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param peerMacAddr Indicates the peer MAC addr to which + * setContext was performed + * @param aid Indicates the aid corresponding to the peer MAC + * address + * @param resultCode Indicates the result of previously issued + * eWNI_SME_SETCONTEXT_RSP message + * + * @return None + */ +void +lim_send_sme_set_context_rsp(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_macaddr, uint16_t aid, + tSirResultCodes resultCode, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + struct scheduler_msg mmhMsg = {0}; + tSirSmeSetContextRsp *pSirSmeSetContextRsp; + + pSirSmeSetContextRsp = qdf_mem_malloc(sizeof(tSirSmeSetContextRsp)); + if (NULL == pSirSmeSetContextRsp) { + /* Log error */ + pe_err("call to AllocateMemory failed for SmeSetContextRsp"); + return; + } + + pSirSmeSetContextRsp->messageType = eWNI_SME_SETCONTEXT_RSP; + pSirSmeSetContextRsp->length = sizeof(tSirSmeSetContextRsp); + pSirSmeSetContextRsp->statusCode = resultCode; + + qdf_copy_macaddr(&pSirSmeSetContextRsp->peer_macaddr, &peer_macaddr); + + /* Update SME session and transaction Id */ + pSirSmeSetContextRsp->sessionId = smesessionId; + pSirSmeSetContextRsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_SETCONTEXT_RSP; + mmhMsg.bodyptr = pSirSmeSetContextRsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_SETCONTEXT_RSP_EVENT, + psessionEntry, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + pMac->lim.sme_msg_callback(pMac, &mmhMsg); +} /*** end lim_send_sme_set_context_rsp() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_addts_rsp() - sends SME ADDTS RSP + \ This function sends a eWNI_SME_ADDTS_RSP to SME. + \ SME only looks at rc and tspec field. + \param pMac - global mac structure + \param rspReqd - is SmeAddTsRsp required + \param status - status code of SME_ADD_TS_RSP + \return tspec + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_addts_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, uint32_t status, + tpPESession psessionEntry, tSirMacTspecIE tspec, + uint8_t smesessionId, uint16_t smetransactionId) +{ + tpSirAddtsRsp rsp; + struct scheduler_msg mmhMsg = {0}; + + if (!rspReqd) + return; + + rsp = qdf_mem_malloc(sizeof(tSirAddtsRsp)); + if (NULL == rsp) { + pe_err("AllocateMemory failed for ADDTS_RSP"); + return; + } + + rsp->messageType = eWNI_SME_ADDTS_RSP; + rsp->rc = status; + rsp->rsp.status = (enum eSirMacStatusCodes)status; + rsp->rsp.tspec = tspec; + /* Update SME session Id and transcation Id */ + rsp->sessionId = smesessionId; + rsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_ADDTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ADDTS_RSP_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} + +void +lim_send_sme_delts_rsp(tpAniSirGlobal pMac, tpSirDeltsReq delts, uint32_t status, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + 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 (NULL == rsp) { + /* Log error */ + pe_err("AllocateMemory failed for DELTS_RSP"); + return; + } + + if (psessionEntry != NULL) { + + rsp->aid = delts->aid; + qdf_copy_macaddr(&rsp->macaddr, &delts->macaddr); + qdf_mem_copy((uint8_t *) &rsp->rsp, (uint8_t *) &delts->req, + sizeof(tSirDeltsReqInfo)); + } + + rsp->messageType = eWNI_SME_DELTS_RSP; + rsp->rc = status; + + /* Update SME session Id and transcation Id */ + rsp->sessionId = smesessionId; + rsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_DELTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_RSP_EVENT, psessionEntry, + (uint16_t) status, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +void +lim_send_sme_delts_ind(tpAniSirGlobal pMac, tpSirDeltsReqInfo delts, uint16_t aid, + tpPESession psessionEntry) +{ + 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 (NULL == rsp) { + /* Log error */ + pe_err("AllocateMemory failed for DELTS_IND"); + 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)); + + /* Update SME session Id and SME transaction Id */ + + rsp->sessionId = psessionEntry->smeSessionId; + rsp->transactionId = psessionEntry->transactionId; + + mmhMsg.type = eWNI_SME_DELTS_IND; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_IND_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * lim_send_sme_pe_statistics_rsp() + * + ***FUNCTION: + * This function is called to send 802.11 statistics response to HDD. + * This function posts the result back to HDD. This is a response to + * HDD's request for statistics. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param p80211Stats Statistics sent in response + * @param resultCode TODO: + * + * + * @return none + */ + +void +lim_send_sme_pe_statistics_rsp(tpAniSirGlobal pMac, uint16_t msgType, void *stats) +{ + struct scheduler_msg mmhMsg = {0}; + uint8_t sessionId; + tAniGetPEStatsRsp *pPeStats = (tAniGetPEStatsRsp *) stats; + tpPESession pPeSessionEntry; + + /* Get the Session Id based on Sta Id */ + pPeSessionEntry = + pe_find_session_by_sta_id(pMac, pPeStats->staId, &sessionId); + + /* Fill the Session Id */ + if (NULL != pPeSessionEntry) { + /* Fill the Session Id */ + pPeStats->sessionId = pPeSessionEntry->smeSessionId; + } + + pPeStats->msgType = eWNI_SME_GET_STATISTICS_RSP; + + /* msgType should be WMA_GET_STATISTICS_RSP */ + mmhMsg.type = eWNI_SME_GET_STATISTICS_RSP; + + mmhMsg.bodyptr = stats; + mmhMsg.bodyval = 0; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; + +} /*** end lim_send_sme_pe_statistics_rsp() ***/ +#endif + +#ifdef FEATURE_WLAN_ESE +/** + * lim_send_sme_pe_ese_tsm_rsp() - send tsm response + * @pMac: Pointer to global pMac 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(tpAniSirGlobal pMac, + tAniGetTsmStatsRsp *pStats) +{ + struct scheduler_msg mmhMsg = {0}; + uint8_t sessionId; + tAniGetTsmStatsRsp *pPeStats = (tAniGetTsmStatsRsp *) pStats; + tpPESession pPeSessionEntry = NULL; + + /* Get the Session Id based on Sta Id */ + pPeSessionEntry = + pe_find_session_by_sta_id(pMac, pPeStats->staId, &sessionId); + + /* Fill the Session Id */ + if (NULL != pPeSessionEntry) { + /* Fill the Session Id */ + pPeStats->sessionId = pPeSessionEntry->smeSessionId; + } else { + pe_err("Session not found for the Sta id: %d", + pPeStats->staId); + 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(pMac, TRACE_CODE_TX_SME_MSG, sessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} /*** end lim_send_sme_pe_ese_tsm_rsp() ***/ + +#endif /* FEATURE_WLAN_ESE */ + +void +lim_send_sme_ibss_peer_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint16_t staIndex, + uint8_t *beacon, + uint16_t beaconLen, uint16_t msgType, uint8_t sessionId) +{ + struct scheduler_msg mmhMsg = {0}; + tSmeIbssPeerInd *pNewPeerInd; + + pNewPeerInd = qdf_mem_malloc(sizeof(tSmeIbssPeerInd) + beaconLen); + if (NULL == pNewPeerInd) { + pe_err("Failed to allocate memory"); + return; + } + + qdf_mem_copy((uint8_t *) pNewPeerInd->peer_addr.bytes, + peerMacAddr, QDF_MAC_ADDR_SIZE); + pNewPeerInd->staId = staIndex; + pNewPeerInd->mesgLen = sizeof(tSmeIbssPeerInd) + beaconLen; + pNewPeerInd->mesgType = msgType; + pNewPeerInd->sessionId = sessionId; + + if (beacon != NULL) { + qdf_mem_copy((void *)((uint8_t *) pNewPeerInd + + sizeof(tSmeIbssPeerInd)), (void *)beacon, + beaconLen); + } + + mmhMsg.type = msgType; + mmhMsg.bodyptr = pNewPeerInd; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, sessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + +} + +/** + * 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(tpAniSirGlobal mac_ctx, + struct csa_offload_params *csa_params, + tLimWiderBWChannelSwitchInfo *chnl_switch_info, + tpPESession session_entry) +{ + struct ch_params ch_params = {0}; + uint8_t ap_new_ch_width; + bool new_ch_width_dfn = false; + uint8_t center_freq_diff; + uint32_t fw_vht_ch_wd = wma_get_vht_ch_width() + 1; + + ap_new_ch_width = csa_params->new_ch_width + 1; + + pe_debug("new channel: %d new_ch_width: %d seg0: %d seg1: %d", + csa_params->channel, ap_new_ch_width, + csa_params->new_ch_freq_seg1, + csa_params->new_ch_freq_seg2); + + if ((ap_new_ch_width != CH_WIDTH_80MHZ) && + (ap_new_ch_width != CH_WIDTH_160MHZ) && + (ap_new_ch_width != CH_WIDTH_80P80MHZ)) { + pe_err("CSA wide BW IE has wrong ch_width %d", + csa_params->new_ch_width); + return QDF_STATUS_E_INVAL; + } + + if (!csa_params->new_ch_freq_seg1 && !csa_params->new_ch_freq_seg2) { + pe_err("CSA wide BW IE has invalid center freq"); + return QDF_STATUS_E_INVAL; + } + if ((ap_new_ch_width == CH_WIDTH_80MHZ) && + csa_params->new_ch_freq_seg2) { + new_ch_width_dfn = true; + if (csa_params->new_ch_freq_seg2 > + csa_params->new_ch_freq_seg1) + center_freq_diff = csa_params->new_ch_freq_seg2 - + csa_params->new_ch_freq_seg1; + else + center_freq_diff = csa_params->new_ch_freq_seg1 - + csa_params->new_ch_freq_seg2; + if (center_freq_diff == CENTER_FREQ_DIFF_160MHz) + ap_new_ch_width = CH_WIDTH_160MHZ; + else if (center_freq_diff > CENTER_FREQ_DIFF_80P80MHz) + ap_new_ch_width = CH_WIDTH_80P80MHZ; + else + ap_new_ch_width = CH_WIDTH_80MHZ; + } + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + if ((ap_new_ch_width == CH_WIDTH_160MHZ) && + !new_ch_width_dfn) { + if (csa_params->new_ch_freq_seg1 != csa_params->channel + + CH_TO_CNTR_FREQ_DIFF_160MHz) { + pe_err("CSA wide BW IE has invalid center freq"); + return QDF_STATUS_E_INVAL; + } + + if (ap_new_ch_width > fw_vht_ch_wd) { + pe_debug("New BW is not supported, setting 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(mac_ctx->pdev, + csa_params->channel, 0, &ch_params); + 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; + } else if (!new_ch_width_dfn) { + if (ap_new_ch_width > fw_vht_ch_wd) { + pe_debug("New BW is not supported, setting BW to %d", + fw_vht_ch_wd); + ap_new_ch_width = fw_vht_ch_wd; + } + if (csa_params->new_ch_freq_seg1 != csa_params->channel + + CH_TO_CNTR_FREQ_DIFF_80MHz) { + pe_err("CSA wide BW IE has invalid center freq"); + return QDF_STATUS_E_INVAL; + } + csa_params->new_ch_freq_seg2 = 0; + } + if (new_ch_width_dfn) { + if (csa_params->new_ch_freq_seg1 != csa_params->channel + + CH_TO_CNTR_FREQ_DIFF_80MHz) { + pe_err("CSA wide BW IE has invalid center freq"); + return QDF_STATUS_E_INVAL; + } + if (ap_new_ch_width > fw_vht_ch_wd) { + pe_debug("New width is not supported, setting BW to %d", + fw_vht_ch_wd); + ap_new_ch_width = fw_vht_ch_wd; + } + if ((ap_new_ch_width == CH_WIDTH_160MHZ) && + (csa_params->new_ch_freq_seg1 != + csa_params->channel + + CH_TO_CNTR_FREQ_DIFF_160MHz)) { + pe_err("wide BW IE has invalid 160M center freq"); + csa_params->new_ch_freq_seg2 = 0; + ap_new_ch_width = CH_WIDTH_80MHZ; + } + } + 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; + + if (session_entry->ch_width == ap_new_ch_width) + goto prnt_log; + + if (session_entry->ch_width == CH_WIDTH_80MHZ) { + chnl_switch_info->newChanWidth = CH_WIDTH_80MHZ; + chnl_switch_info->newCenterChanFreq1 = 0; + } else { + session_entry->ch_width = ap_new_ch_width; + chnl_switch_info->newChanWidth = ap_new_ch_width; + } +prnt_log: + pe_debug("new channel: %d new_ch_width: %d seg0: %d seg1: %d", + csa_params->channel, + chnl_switch_info->newChanWidth, + chnl_switch_info->newCenterChanFreq0, + chnl_switch_info->newCenterChanFreq1); + + return QDF_STATUS_SUCCESS; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + tpPESession session_entry; + struct scheduler_msg mmh_msg = {0}; + struct csa_offload_params *csa_params = + (struct csa_offload_params *) (msg->bodyptr); + tpSmeCsaOffloadInd csa_offload_ind; + tpDphHashNode sta_ds = NULL; + uint8_t session_id; + uint16_t aid = 0; + uint16_t chan_space = 0; + struct ch_params ch_params = {0}; + + tLimWiderBWChannelSwitchInfo *chnl_switch_info = NULL; + tLimChannelSwitchInfo *lim_ch_switch = NULL; + + pe_debug("handle csa offload msg"); + + if (!csa_params) { + pe_err("limMsgQ body ptr is NULL"); + return; + } + + csa_offload_ind = qdf_mem_malloc(sizeof(tSmeCsaOffloadInd)); + if (NULL == csa_offload_ind) { + pe_err("memalloc fail eWNI_SME_CSA_OFFLOAD_EVENT"); + goto err; + } + + session_entry = + pe_find_session_by_bssid(mac_ctx, + csa_params->bssId, &session_id); + if (!session_entry) { + pe_err("Session does not exists for %pM", + csa_params->bssId); + qdf_mem_free(csa_offload_ind); + goto err; + } + + 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"); + qdf_mem_free(csa_offload_ind); + goto err; + } + + if (!LIM_IS_STA_ROLE(session_entry)) { + pe_debug("Invalid role to handle CSA"); + qdf_mem_free(csa_offload_ind); + goto err; + } + /* + * 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 = &session_entry->gLimChannelSwitch; + session_entry->gLimChannelSwitch.switchMode = + csa_params->switch_mode; + /* timer already started by firmware, switch immediately */ + session_entry->gLimChannelSwitch.switchCount = 0; + session_entry->gLimChannelSwitch.primaryChannel = + csa_params->channel; + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + session_entry->gLimChannelSwitch.ch_width = CH_WIDTH_20MHZ; + lim_ch_switch->sec_ch_offset = + session_entry->htSecondaryChannelOffset; + session_entry->gLimChannelSwitch.ch_center_freq_seg0 = 0; + session_entry->gLimChannelSwitch.ch_center_freq_seg1 = 0; + chnl_switch_info = + &session_entry->gLimWiderBWChannelSwitch; + + pe_debug("vht: %d ht: %d flag: %x chan: %d, sec_ch_offset %d", + session_entry->vhtCapability, + session_entry->htSupportedChannelWidthSet, + csa_params->ies_present_flag, + csa_params->channel, + csa_params->sec_chan_offset); + pe_debug("seg1: %d seg2: %d width: %d country: %s class: %d", + csa_params->new_ch_freq_seg1, + csa_params->new_ch_freq_seg2, + csa_params->new_ch_width, + mac_ctx->scan.countryCodeCurrent, + csa_params->new_op_class); + + if (session_entry->vhtCapability && + session_entry->htSupportedChannelWidthSet) { + if ((csa_params->ies_present_flag & lim_wbw_ie_present) && + (QDF_STATUS_SUCCESS == lim_process_csa_wbw_ie(mac_ctx, + csa_params, chnl_switch_info, + session_entry))) { + pe_debug("CSA wide BW IE process successful"); + lim_ch_switch->sec_ch_offset = + PHY_SINGLE_CHANNEL_CENTERED; + if (chnl_switch_info->newChanWidth) { + if (csa_params->channel < + csa_params->new_ch_freq_seg1) + lim_ch_switch->sec_ch_offset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + else + lim_ch_switch->sec_ch_offset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + } + } else if (csa_params->ies_present_flag + & lim_xcsa_ie_present) { + chan_space = + wlan_reg_dmn_get_chanwidth_from_opclass( + mac_ctx->scan.countryCodeCurrent, + csa_params->channel, + csa_params->new_op_class); + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + + if (chan_space == 80) { + chnl_switch_info->newChanWidth = + CH_WIDTH_80MHZ; + } else if (chan_space == 40) { + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + } 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(mac_ctx->pdev, + csa_params->channel, 0, &ch_params); + 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(mac_ctx->pdev, + csa_params->channel, 0, &ch_params); + 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->gLimChannelSwitch.ch_center_freq_seg0 = + chnl_switch_info->newCenterChanFreq0; + session_entry->gLimChannelSwitch.ch_center_freq_seg1 = + chnl_switch_info->newCenterChanFreq1; + session_entry->gLimChannelSwitch.ch_width = + chnl_switch_info->newChanWidth; + + } else if (session_entry->htSupportedChannelWidthSet) { + if (csa_params->ies_present_flag + & lim_xcsa_ie_present) { + chan_space = + wlan_reg_dmn_get_chanwidth_from_opclass( + mac_ctx->scan.countryCodeCurrent, + 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(mac_ctx->pdev, + csa_params->channel, + 0, &ch_params); + lim_ch_switch->ch_center_freq_seg0 = + ch_params.center_freq_seg0; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + } else { + lim_ch_switch->ch_width = + CH_WIDTH_20MHZ; + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + 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(mac_ctx->pdev, + csa_params->channel, 0, &ch_params); + lim_ch_switch->ch_center_freq_seg0 = + ch_params.center_freq_seg0; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + } + + } + pe_debug("new ch width: %d space: %d", + session_entry->gLimChannelSwitch.ch_width, chan_space); + if ((session_entry->currentOperChannel == csa_params->channel) && + (session_entry->ch_width == + session_entry->gLimChannelSwitch.ch_width)) { + pe_debug("Ignore CSA, no change in ch and bw"); + qdf_mem_free(csa_offload_ind); + goto err; + } + + if (WLAN_REG_IS_24GHZ_CH(csa_params->channel) && + (session_entry->dot11mode == WNI_CFG_DOT11_MODE_11A)) + session_entry->dot11mode = WNI_CFG_DOT11_MODE_11G; + else if (WLAN_REG_IS_5GHZ_CH(csa_params->channel) && + ((session_entry->dot11mode == WNI_CFG_DOT11_MODE_11G) || + (session_entry->dot11mode == WNI_CFG_DOT11_MODE_11G_ONLY))) + session_entry->dot11mode = WNI_CFG_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_ctx, + session_entry->smeSessionId, + ecsr_driver_disabled); + + lim_prepare_for11h_channel_switch(mac_ctx, session_entry); + + csa_offload_ind->mesgType = eWNI_SME_CSA_OFFLOAD_EVENT; + csa_offload_ind->mesgLen = sizeof(tSmeCsaOffloadInd); + qdf_mem_copy(csa_offload_ind->bssid.bytes, session_entry->bssId, + QDF_MAC_ADDR_SIZE); + mmh_msg.type = eWNI_SME_CSA_OFFLOAD_EVENT; + mmh_msg.bodyptr = csa_offload_ind; + mmh_msg.bodyval = 0; + pe_debug("Sending eWNI_SME_CSA_OFFLOAD_EVENT to SME"); + MTRACE(mac_trace_msg_tx + (mac_ctx, session_entry->peSessionId, mmh_msg.type)); +#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 + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); + +err: + qdf_mem_free(csa_params); +} + +/*-------------------------------------------------------------------------- + \brief pe_delete_session() - Handle the Delete BSS Response from HAL. + + \param pMac - pointer to global adapter context + \param sessionId - Message pointer. + + \sa + --------------------------------------------------------------------------*/ + +void lim_handle_delete_bss_rsp(tpAniSirGlobal pMac, struct scheduler_msg *MsgQ) +{ + tpPESession psessionEntry; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) (MsgQ->bodyptr); + + psessionEntry = + pe_find_session_by_session_id(pMac, pDelBss->sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID: %d", + pDelBss->sessionId); + qdf_mem_free(MsgQ->bodyptr); + MsgQ->bodyptr = NULL; + 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 + */ + psessionEntry->process_ho_fail = false; + if (LIM_IS_IBSS_ROLE(psessionEntry)) + lim_ibss_del_bss_rsp(pMac, MsgQ->bodyptr, psessionEntry); + else if (LIM_IS_UNKNOWN_ROLE(psessionEntry)) + lim_process_sme_del_bss_rsp(pMac, MsgQ->bodyval, psessionEntry); + else if (LIM_IS_NDI_ROLE(psessionEntry)) + lim_ndi_del_bss_rsp(pMac, MsgQ->bodyptr, psessionEntry); + else + lim_process_mlm_del_bss_rsp(pMac, MsgQ, psessionEntry); + +} + +/** ----------------------------------------------------------------- + \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 pMac - 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(tpAniSirGlobal pMac, 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(pMac, TRACE_CODE_TX_SME_MSG, + smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} + +void lim_send_sme_max_assoc_exceeded_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint8_t smesessionId) +{ + struct scheduler_msg mmhMsg = {0}; + tSmeMaxAssocInd *pSmeMaxAssocInd; + + pSmeMaxAssocInd = qdf_mem_malloc(sizeof(tSmeMaxAssocInd)); + if (NULL == pSmeMaxAssocInd) { + pe_err("Failed to allocate memory"); + 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 "MAC_ADDRESS_STR "sme session id %d", + "eWNI_SME_MAX_ASSOC_EXCEEDED", MAC_ADDR_ARRAY(peerMacAddr), + pSmeMaxAssocInd->sessionId); + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + 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 pMac - global mac structure + \param psessionEntry - session info + \param pChnlParams - Channel switch params + --------------------------------------------------------------------*/ +void +lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSwitchChannelParams pChnlParams) +{ + struct scheduler_msg mmhMsg = {0}; + tpSwitchChannelParams pSmeSwithChnlParams; + uint8_t channelId; + bool is_ch_dfs = false; + enum phy_ch_width ch_width; + uint8_t ch_center_freq_seg1; + + qdf_runtime_pm_allow_suspend(&psessionEntry->ap_ecsa_runtime_lock); + qdf_wake_lock_release(&psessionEntry->ap_ecsa_wakelock, 0); + + pSmeSwithChnlParams = (tSwitchChannelParams *) + qdf_mem_malloc(sizeof(tSwitchChannelParams)); + if (NULL == pSmeSwithChnlParams) { + pe_err("AllocateMemory failed for pSmeSwithChnlParams"); + return; + } + + qdf_mem_copy(pSmeSwithChnlParams, pChnlParams, + sizeof(tSwitchChannelParams)); + + channelId = pSmeSwithChnlParams->channelNumber; + ch_width = pSmeSwithChnlParams->ch_width; + ch_center_freq_seg1 = pSmeSwithChnlParams->ch_center_freq_seg1; + + /* + * Pass the sme sessionID to SME instead + * PE session ID. + */ + pSmeSwithChnlParams->peSessionId = psessionEntry->smeSessionId; + + mmhMsg.type = eWNI_SME_CHANNEL_CHANGE_RSP; + mmhMsg.bodyptr = (void *)pSmeSwithChnlParams; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + /* + * 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 . + */ + + if (ch_width == CH_WIDTH_160MHZ) { + is_ch_dfs = true; + } else if (ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state(pMac->pdev, channelId) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state(pMac->pdev, + ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + if (wlan_reg_get_channel_state(pMac->pdev, channelId) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } + + if (!is_ch_dfs) { + if (channelId == psessionEntry->currentOperChannel) { + lim_apply_configuration(pMac, psessionEntry); + lim_send_beacon_ind(pMac, + psessionEntry, REASON_DEFAULT); + } else { + pe_debug("Failed to Transmit Beacons on channel: %d after AP channel change response", + psessionEntry->bcnLen); + } + + lim_obss_send_detection_cfg(pMac, psessionEntry, 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(tpAniSirGlobal mac_ctx, + tpPESession 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); +} + +static void +lim_handle_bss_color_change_ie(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + tUpdateBeaconParams beacon_params; + + /* handle bss color change IE */ + if (LIM_IS_AP_ROLE(session) && + session->he_op.bss_col_disabled) { + if (session->he_bss_color_change.countdown > 0) { + session->he_bss_color_change.countdown--; + } else { + session->bss_color_changing = 0; + qdf_mem_zero(&beacon_params, sizeof(beacon_params)); + if (session->he_bss_color_change.new_color != 0) { + session->he_op.bss_col_disabled = 0; + session->he_op.bss_color = + session->he_bss_color_change.new_color; + 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); + } + } + + lim_send_bss_color_change_ie_update(mac_ctx, session); + } +} + +#else +static void +lim_handle_bss_color_change_ie(tpAniSirGlobal mac_ctx, + tpPESession session) +{ +} +#endif + +void +lim_process_beacon_tx_success_ind(tpAniSirGlobal mac_ctx, uint16_t msgType, + void *event) +{ + tpPESession session; + tpSirFirstBeaconTxCompleteInd bcn_ind = + (tSirFirstBeaconTxCompleteInd *) event; + + session = pe_find_session_by_bss_idx(mac_ctx, bcn_ind->bssIdx); + if (!session) { + pe_err("Session Does not exist for given session id"); + return; + } + + pe_debug("role: %d swIe: %d opIe: %d switch cnt:%d", + GET_LIM_SYSTEM_ROLE(session), + session->dfsIncludeChanSwIe, + session->gLimOperatingMode.present, + session->gLimChannelSwitch.switchCount); + + if (!LIM_IS_AP_ROLE(session)) + return; + + if (session->dfsIncludeChanSwIe && + (session->gLimChannelSwitch.switchCount == + mac_ctx->sap.SapDfsInfo.sap_ch_switch_beacon_cnt)) + 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; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h new file mode 100644 index 0000000000000000000000000000000000000000..6ff6e2e35ab2b063b289f33ab76d69d1b2b3c42d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h @@ -0,0 +1,134 @@ +/* + * 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. + */ + +/* + * 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" + +/* Functions for sending responses to Host */ +void lim_send_sme_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, uint8_t, + uint16_t); +void lim_send_sme_roc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint32_t scan_id); +void lim_send_sme_start_bss_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, + tpPESession, uint8_t, uint16_t); +void lim_send_sme_join_reassoc_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, + uint16_t, tpPESession, uint8_t, uint16_t); + +/* + * 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(tpAniSirGlobal mac_ctx, + uint32_t **msg, + uint8_t session_id, + tSirResultCodes reason_code, + uint8_t *peer_mac_addr); +void lim_send_sme_disassoc_ntf(tpAniSirGlobal, tSirMacAddr, tSirResultCodes, + uint16_t, uint16_t, uint8_t, uint16_t, tpPESession); +void lim_send_sme_deauth_ntf(tpAniSirGlobal, tSirMacAddr, tSirResultCodes, uint16_t, + uint16_t, uint8_t, uint16_t); +void lim_send_sme_disassoc_ind(tpAniSirGlobal, tpDphHashNode, tpPESession); +void lim_send_sme_deauth_ind(tpAniSirGlobal, tpDphHashNode, + tpPESession psessionEntry); +void lim_send_sme_wm_status_change_ntf(tpAniSirGlobal, tSirSmeStatusChangeCode, + uint32_t *, uint16_t, uint8_t); +void lim_send_sme_set_context_rsp(tpAniSirGlobal, struct qdf_mac_addr, uint16_t, + tSirResultCodes, tpPESession, uint8_t, uint16_t); +void lim_handle_delete_bss_rsp(tpAniSirGlobal pMac, struct scheduler_msg *MsgQ); +void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg); + +void +lim_send_sme_aggr_qos_rsp(tpAniSirGlobal pMac, tpSirAggrQosRsp aggrQosRsp, + uint8_t smesessionId); + +void lim_send_sme_addts_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, uint32_t status, + tpPESession psessionEntry, tSirMacTspecIE tspec, + uint8_t smesessionId, uint16_t smetransactionId); +void lim_send_sme_delts_rsp(tpAniSirGlobal pMac, tpSirDeltsReq delts, + uint32_t status, tpPESession psessionEntry, + uint8_t smessionId, uint16_t smetransactionId); +void lim_send_sme_delts_ind(tpAniSirGlobal pMac, tpSirDeltsReqInfo delts, + uint16_t aid, tpPESession); +void lim_send_sme_stats_rsp(tpAniSirGlobal pMac, uint16_t msgtype, void *stats); + +#ifdef QCA_SUPPORT_CP_STATS +static inline void lim_send_sme_pe_statistics_rsp(tpAniSirGlobal pMac, + uint16_t msgtype, void *stats) {} +#else +void lim_send_sme_pe_statistics_rsp(tpAniSirGlobal pMac, uint16_t msgtype, + void *stats); +#endif /* QCA_SUPPORT_CP_STATS */ + +#ifdef FEATURE_WLAN_ESE +void lim_send_sme_pe_ese_tsm_rsp(tpAniSirGlobal pMac, tAniGetTsmStatsRsp *pStats); +#endif + +void lim_send_sme_ibss_peer_ind(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint16_t staIndex, uint8_t *beacon, + uint16_t beaconLen, uint16_t msgType, + uint8_t sessionId); +void lim_send_sme_max_assoc_exceeded_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint8_t smesessionId); + +void lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSwitchChannelParams pChnlParams); +/* + * lim_process_beacon_tx_success_ind() - handle successful beacon transmission + * indication from the FW This is a generic event generated by the FW afer 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(tpAniSirGlobal pMac, uint16_t msgType, + void *event); + +typedef enum { + lim_csa_ie_present = 0x00000001, + lim_xcsa_ie_present = 0x00000002, + lim_wbw_ie_present = 0x00000004, + lim_cswarp_ie_present = 0x00000008, +} lim_csa_event_ies_present_flag; + +#endif /* __LIM_SEND_SME_RSP_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..a76d386ee408d1f7360911919c0285ffa484750a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.c @@ -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. + */ + +/* + * + * This file lim_ser_des_utils.cc contains the serializer/deserializer + * utility functions LIM uses while communicating with upper layer + * software entities + * Author: Chandra Modumudi + * Date: 10/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_system_defs.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_ser_des_utils.h" + + +/**--------------------------------------------------------------- + \fn lim_get_session_info + \brief This function returns the sessionId and transactionId + \ of a message. This assumes that the message structure + \ is of format: + \ uint16_t messageType + \ uint16_t messageLength + \ uint8_t sessionId + \ uint16_t transactionId + \param pMac - pMac global structure + \param *pBuf - pointer to the message buffer + \param sessionId - returned session id value + \param transactionId - returned transaction ID value + \return None + ------------------------------------------------------------------*/ +void +lim_get_session_info(tpAniSirGlobal pMac, uint8_t *pBuf, uint8_t *sessionId, + uint16_t *transactionId) +{ + if (!pBuf) { + pe_err("NULL ptr received"); + return; + } + + pBuf += sizeof(uint16_t); /* skip message type */ + pBuf += sizeof(uint16_t); /* skip message length */ + + *sessionId = *pBuf; /* get sessionId */ + pBuf++; + *transactionId = lim_get_u16(pBuf); /* get transactionId */ + + return; +} + +/** + * lim_send_disassoc_frm_req_ser_des - called on receiving SME_DISASSOC_REQ + * @mac_ctx: pointer to mac context + * @disassoc_frm_req: pointer to structure sme_send_disassoc_frm_req + * + * function send's disassoc frame request on receiving SME_DISASSOC_REQ + * + * return: QDF_STATUS_SUCCESS:Success Error value: Failure + */ +QDF_STATUS lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx, + struct sme_send_disassoc_frm_req *disassoc_frm_req, + uint8_t *buf) +{ + A_INT16 len = 0; + + if (!disassoc_frm_req || !buf) + return QDF_STATUS_E_FAILURE; + + disassoc_frm_req->msg_type = lim_get_u16(buf); + buf += sizeof(A_UINT16); + + len = disassoc_frm_req->length = lim_get_u16(buf); + buf += sizeof(A_UINT16); + + if (len < (A_INT16) sizeof(A_UINT32)) + return QDF_STATUS_E_FAILURE; + + /* skip message header */ + len -= sizeof(A_UINT32); + if (len < 0) + return QDF_STATUS_E_FAILURE; + + /* Extract sessionID */ + disassoc_frm_req->session_id = *buf; + buf += sizeof(A_UINT8); + len -= sizeof(A_UINT8); + if (len < 0) + return QDF_STATUS_E_FAILURE; + + /* Extract transactionid */ + disassoc_frm_req->trans_id = lim_get_u16(buf); + buf += sizeof(A_UINT16); + len -= sizeof(A_UINT16); + + if (len < 0) + return QDF_STATUS_E_FAILURE; + + /* Extract peerMacAddr */ + qdf_mem_copy(disassoc_frm_req->peer_mac, buf, sizeof(tSirMacAddr)); + buf += sizeof(tSirMacAddr); + len -= sizeof(tSirMacAddr); + + if (len < 0) + return QDF_STATUS_E_FAILURE; + + /* Extract reasonCode */ + disassoc_frm_req->reason = lim_get_u16(buf); + buf += sizeof(A_UINT16); + len -= sizeof(A_UINT16); + + if (len < 0) + return QDF_STATUS_E_FAILURE; + + disassoc_frm_req->wait_for_ack = *buf; + buf += sizeof(A_UINT8); + len -= sizeof(A_UINT8); + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..eb5c036a15ff36f0da4ed7ff46c3557acb1c78fb --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * + * 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" + +void lim_get_session_info(tpAniSirGlobal pMac, uint8_t *, + uint8_t *, uint16_t *); + +/* 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]; +} + +QDF_STATUS lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx, + struct sme_send_disassoc_frm_req *disassoc_frm_req, + uint8_t *buf); + +#endif /* __LIM_SERDES_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session.c new file mode 100644 index 0000000000000000000000000000000000000000..8127a20783c7be0fa5ef8fd7d4be1455aec23638 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session.c @@ -0,0 +1,1069 @@ +/* + * 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. + */ + +/**========================================================================= + + \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" + + +static struct sDphHashNode + g_dph_node_array[SIR_MAX_SUPPORTED_BSS][SIR_SAP_MAX_NUM_PEERS + 1]; + +/*-------------------------------------------------------------------------- + + \brief pe_init_beacon_params() - Initialize the beaconParams structure + + \param tpPESession - pointer to the session context or NULL if session can not be created. + \return void + \sa + + --------------------------------------------------------------------------*/ + +static void pe_init_beacon_params(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + psessionEntry->beaconParams.beaconInterval = 0; + psessionEntry->beaconParams.fShortPreamble = 0; + psessionEntry->beaconParams.llaCoexist = 0; + psessionEntry->beaconParams.llbCoexist = 0; + psessionEntry->beaconParams.llgCoexist = 0; + psessionEntry->beaconParams.ht20Coexist = 0; + psessionEntry->beaconParams.llnNonGFCoexist = 0; + psessionEntry->beaconParams.fRIFSMode = 0; + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = 0; + psessionEntry->beaconParams.gHTObssMode = 0; + + /* Number of legacy STAs associated */ + qdf_mem_zero((void *)&psessionEntry->gLim11bParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&psessionEntry->gLim11aParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&psessionEntry->gLim11gParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&psessionEntry->gLimNonGfParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&psessionEntry->gLimHt20Params, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&psessionEntry->gLimLsigTxopParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&psessionEntry->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 pSessionEntry + * + * 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) +{ + tpPESession pe_session_entry = (tpPESession)ptr; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)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.gLimAssocStaLimit ; i++) { + station_hash_node = dph_get_hash_entry(mac_ctx, i, + &pe_session_entry->dph.dphHashTable); + if (NULL == 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.bssIdx = pe_session_entry->bssIdx; + 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.smeSessionId = + pe_session_entry->smeSessionId; + 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"); + } +} + +#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(tpPESession session) +{ + struct pe_fils_session *fils_info; + + if (!session || (session && !session->valid)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("session is not valid")); + return; + } + fils_info = session->fils_info; + if (!fils_info) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("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(tpPESession session) +{ + struct pe_fils_session *fils_info; + + if (!session || (session && !session->valid)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("session is not valid")); + return; + } + session->fils_info = qdf_mem_malloc(sizeof(struct pe_fils_session)); + fils_info = session->fils_info; + if (!fils_info) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("fils info not found")); + 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(tpPESession session) { } +static void pe_init_fils_info(tpPESession 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, tSirBssType 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, tSirBssType bss_type) +{ + return num_sta + 1; +} +#endif + +void lim_set_bcn_probe_filter(tpAniSirGlobal mac_ctx, + tpPESession session, + tSirMacSSid *ibss_ssid, + uint8_t sap_channel) +{ + struct mgmt_beacon_probe_filter *filter; + tSirBssType 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 >= SIR_MAX_SUPPORTED_BSS) { + 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) { + filter->num_sta_sessions++; + sir_copy_mac_addr(filter->sta_bssid[session_id], *bssid); + pe_debug("Set filter for STA Session %d bssid "MAC_ADDRESS_STR, + session_id, MAC_ADDR_ARRAY(*bssid)); + } else if (eSIR_IBSS_MODE == bss_type) { + if (!ibss_ssid) { + pe_err("IBSS Type with NULL SSID"); + goto done; + } + filter->num_ibss_sessions++; + filter->ibss_ssid[session_id].length = ibss_ssid->length; + qdf_mem_copy(&filter->ibss_ssid[session_id].length, + ibss_ssid->ssId, + ibss_ssid->length); + pe_debug("Set filter for IBSS session %d ssid %s", + session_id, ibss_ssid->ssId); + } else if (eSIR_INFRA_AP_MODE == bss_type) { + if (!sap_channel) { + pe_err("SAP Type with invalid channel"); + goto done; + } + filter->num_sap_sessions++; + filter->sap_channel[session_id] = sap_channel; + pe_debug("Set filter for SAP session %d channel %d", + session_id, sap_channel); + } + +done: + pe_debug("sta %d ibss %d sap %d", + filter->num_sta_sessions, filter->num_ibss_sessions, + filter->num_sap_sessions); +} + +void lim_reset_bcn_probe_filter(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + struct mgmt_beacon_probe_filter *filter; + tSirBssType 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 >= SIR_MAX_SUPPORTED_BSS) { + 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_IBSS_MODE == bss_type) { + if (filter->num_ibss_sessions) + filter->num_ibss_sessions--; + filter->ibss_ssid[session_id].length = 0; + qdf_mem_zero(&filter->ibss_ssid[session_id].ssId, + SIR_MAC_MAX_SSID_LENGTH); + pe_debug("Cleared IBSS 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 ibss %d sap %d", + filter->num_sta_sessions, filter->num_ibss_sessions, + filter->num_sap_sessions); +} + +void lim_update_bcn_probe_filter(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + struct mgmt_beacon_probe_filter *filter; + tSirBssType 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 >= SIR_MAX_SUPPORTED_BSS) { + 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] = session->currentOperChannel; + 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 ibss %d sap %d", + filter->num_sta_sessions, filter->num_ibss_sessions, + filter->num_sap_sessions); +} + +/** + * pe_create_session() creates a new PE session given the BSSID + * @param pMac: pointer to global adapter context + * @param bssid: BSSID of the new session + * @param sessionId: session ID is returned here, if session is created. + * @param bssType: station or a + * + * 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: tpPESession: pointer to the session context or NULL if session + * can not be created. + */ + +tpPESession +pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId, + uint16_t numSta, tSirBssType bssType) +{ + QDF_STATUS status; + uint8_t i; + tpPESession session_ptr; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (pMac->lim.gpSession[i].valid == true) + continue; + break; + } + + if (i == pMac->lim.maxBssId) { + pe_err("Session can't be created. Reached max sessions"); + return NULL; + } + + session_ptr = &pMac->lim.gpSession[i]; + qdf_mem_zero((void *)session_ptr, sizeof(tPESession)); + /* Allocate space for Station Table for this session. */ + session_ptr->dph.dphHashTable.pHashTable = + qdf_mem_malloc(sizeof(tpDphHashNode) * (numSta + 1)); + if (NULL == session_ptr->dph.dphHashTable.pHashTable) { + pe_err("memory allocate failed!"); + return NULL; + } + + session_ptr->dph.dphHashTable.pDphNodeArray = g_dph_node_array[i]; + session_ptr->dph.dphHashTable.size = numSta + 1; + dph_hash_table_class_init(pMac, &session_ptr->dph.dphHashTable); + session_ptr->gpLimPeerIdxpool = qdf_mem_malloc( + sizeof(*(session_ptr->gpLimPeerIdxpool)) * + lim_get_peer_idxpool_size(numSta, bssType)); + if (NULL == session_ptr->gpLimPeerIdxpool) { + pe_err("memory allocate failed!"); + 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; + return NULL; + } + session_ptr->freePeerIdxHead = 0; + session_ptr->freePeerIdxTail = 0; + session_ptr->gLimNumOfCurrentSTAs = 0; + /* Copy the BSSID to the session table */ + sir_copy_mac_addr(session_ptr->bssId, bssid); + if (bssType == eSIR_MONITOR_MODE) + sir_copy_mac_addr(pMac->lim.gpSession[i].selfMacAddr, 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(pMac, &pMac->lim.gpSession[i]); + session_ptr->is11Rconnection = false; +#ifdef FEATURE_WLAN_ESE + session_ptr->isESEconnection = false; +#endif + session_ptr->isFastTransitionEnabled = false; + session_ptr->isFastRoamIniFeatureEnabled = 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)); + session_ptr->tdls_prohibited = false; + session_ptr->tdls_chan_swit_prohibited = false; +#endif + lim_update_tdls_set_state_for_fw(session_ptr, true); + session_ptr->fWaitForProbeRsp = 0; + session_ptr->fIgnoreCapsChange = 0; + session_ptr->ignore_assoc_disallowed = pMac->ignore_assoc_disallowed; + session_ptr->is_session_obss_color_collision_det_enabled = + pMac->lim.global_obss_color_collision_det_offload; + + pe_debug("Create a new PE session: %d BSSID: "MAC_ADDRESS_STR" Max No of STA: %d", + *sessionId, MAC_ADDR_ARRAY(bssid), numSta); + + if (eSIR_INFRA_AP_MODE == bssType || eSIR_IBSS_MODE == bssType) { + 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 ((NULL == session_ptr->pSchProbeRspTemplate) + || (NULL == session_ptr->pSchBeaconFrameBegin) + || (NULL == session_ptr->pSchBeaconFrameEnd)) { + pe_err("memory allocate failed!"); + 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)); + qdf_mem_free(session_ptr->gpLimPeerIdxpool); + qdf_mem_free(session_ptr->pSchProbeRspTemplate); + qdf_mem_free(session_ptr->pSchBeaconFrameBegin); + qdf_mem_free(session_ptr->pSchBeaconFrameEnd); + + session_ptr->dph.dphHashTable.pHashTable = NULL; + session_ptr->dph.dphHashTable.pDphNodeArray = NULL; + session_ptr->gpLimPeerIdxpool = NULL; + session_ptr->pSchProbeRspTemplate = NULL; + session_ptr->pSchBeaconFrameBegin = NULL; + session_ptr->pSchBeaconFrameEnd = NULL; + return NULL; + } + } + if (eSIR_INFRASTRUCTURE_MODE == bssType) + lim_ft_open(pMac, &pMac->lim.gpSession[i]); + + if (eSIR_MONITOR_MODE == bssType) + lim_ft_open(pMac, &pMac->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; + session_ptr->mac_ctx = (void *)pMac; + + status = qdf_mc_timer_init(&session_ptr-> + protection_fields_reset_timer, + QDF_TIMER_TYPE_SW, + pe_reset_protection_callback, + (void *)&pMac->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; + + status = qdf_mc_timer_init(&session_ptr->ap_ecsa_timer, + QDF_TIMER_TYPE_WAKE_APPS, + lim_process_ap_ecsa_timeout, + (void *)&pMac->lim.gpSession[i]); + if (status != QDF_STATUS_SUCCESS) + pe_err("cannot create ap_ecsa_timer"); + qdf_wake_lock_create(&session_ptr->ap_ecsa_wakelock, + "ap_ecsa_wakelock"); + qdf_runtime_lock_init(&session_ptr->ap_ecsa_runtime_lock); + } + pe_init_fils_info(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; + + return &pMac->lim.gpSession[i]; +} + +/*-------------------------------------------------------------------------- + \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 pMac - pointer to global adapter context + \param bssid - BSSID of the session + \param sessionId -session ID is returned here, if session is found. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_bssid(tpAniSirGlobal pMac, uint8_t *bssid, + uint8_t *sessionId) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((pMac->lim.gpSession[i].valid) + && (sir_compare_mac_addr(pMac->lim.gpSession[i].bssId, + bssid))) { + *sessionId = i; + return &pMac->lim.gpSession[i]; + } + } + + return NULL; + +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_bss_idx() - looks up the PE session given the bssIdx. + + This function returns the session context if the session + corresponding to the given bssIdx is found in the PE session table. + \param pMac - pointer to global adapter context + \param bssIdx - bss index of the session + \return tpPESession - pointer to the session context or NULL if session is not found. + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_bss_idx(tpAniSirGlobal pMac, uint8_t bssIdx) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((pMac->lim.gpSession[i].valid) + && (pMac->lim.gpSession[i].bssIdx == bssIdx)) { + return &pMac->lim.gpSession[i]; + } + } + pe_debug("Session lookup fails for bssIdx: %d", bssIdx); + 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 pMac - pointer to global adapter context + \param sessionId -session ID for which session context needs to be looked up. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_session_id(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + if (sessionId >= pMac->lim.maxBssId) { + pe_err("Invalid sessionId: %d", sessionId); + return NULL; + } + + if (pMac->lim.gpSession[sessionId].valid) + return &pMac->lim.gpSession[sessionId]; + + return NULL; +} + +/** + * pe_find_session_by_sta_id() - looks up the PE session given staid. + * @mac_ctx: pointer to global adapter context + * @staid: StaId of the session + * @session_id: 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 StaId is found in the PE session table. + * + * Return: session pointer + */ +tpPESession +pe_find_session_by_sta_id(tpAniSirGlobal mac_ctx, + uint8_t staid, + uint8_t *session_id) +{ + uint8_t i, j; + tpPESession session_ptr; + dphHashTableClass *dph_ptr; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (!mac_ctx->lim.gpSession[i].valid) + continue; + session_ptr = &mac_ctx->lim.gpSession[i]; + dph_ptr = &session_ptr->dph.dphHashTable; + for (j = 0; j < dph_ptr->size; j++) { + if (dph_ptr->pDphNodeArray[j].valid + && dph_ptr->pDphNodeArray[j].added + && staid == dph_ptr->pDphNodeArray[j].staIndex) { + *session_id = i; + return session_ptr; + } + } + } + + pe_debug("Session lookup fails for StaId: %d", staid); + return NULL; +} + +/** + * 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(tpAniSirGlobal mac_ctx, tpPESession session) +{ + uint16_t i = 0; + uint16_t n; + TX_TIMER *timer_ptr; + + if (!session || (session && !session->valid)) { + pe_err("session is not valid"); + return; + } + + pe_debug("Trying to delete PE session: %d Opmode: %d BssIdx: %d BSSID: "MAC_ADDRESS_STR, + session->peSessionId, session->operMode, + session->bssIdx, + MAC_ADDR_ARRAY(session->bssId)); + + lim_reset_bcn_probe_filter(mac_ctx, session); + + /* Restore default failure timeout */ + if (session->defaultAuthFailureTimeout) { + pe_debug("Restore default failure timeout"); + cfg_set_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + session->defaultAuthFailureTimeout); + } + + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + timer_ptr = &mac_ctx->lim.limTimers.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 != NULL) { + qdf_mem_free(session->pLimStartBssReq); + session->pLimStartBssReq = NULL; + } + + if (session->pLimJoinReq != NULL) { + qdf_mem_free(session->pLimJoinReq); + session->pLimJoinReq = NULL; + } + + if (session->pLimReAssocReq != NULL) { + qdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } + + if (session->pLimMlmJoinReq != NULL) { + qdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + + if (session->dph.dphHashTable.pHashTable != NULL) { + qdf_mem_free(session->dph.dphHashTable.pHashTable); + session->dph.dphHashTable.pHashTable = NULL; + } + + if (session->dph.dphHashTable.pDphNodeArray != NULL) { + qdf_mem_zero(session->dph.dphHashTable.pDphNodeArray, + sizeof(struct sDphHashNode) * + (SIR_SAP_MAX_NUM_PEERS + 1)); + session->dph.dphHashTable.pDphNodeArray = NULL; + } + + if (session->gpLimPeerIdxpool != NULL) { + qdf_mem_free(session->gpLimPeerIdxpool); + session->gpLimPeerIdxpool = NULL; + } + + if (session->beacon != NULL) { + qdf_mem_free(session->beacon); + session->beacon = NULL; + session->bcnLen = 0; + } + + if (session->assocReq != NULL) { + qdf_mem_free(session->assocReq); + session->assocReq = NULL; + session->assocReqLen = 0; + } + + if (session->assocRsp != NULL) { + qdf_mem_free(session->assocRsp); + session->assocRsp = NULL; + session->assocRspLen = 0; + } + + if (session->parsedAssocReq != NULL) { + tpSirAssocReq tmp_ptr = NULL; + /* Cleanup the individual allocation first */ + for (i = 0; i < session->dph.dphHashTable.size; i++) { + if (session->parsedAssocReq[i] == NULL) + continue; + tmp_ptr = ((tpSirAssocReq) + (session->parsedAssocReq[i])); + if (tmp_ptr->assocReqFrame) { + qdf_mem_free(tmp_ptr->assocReqFrame); + tmp_ptr->assocReqFrame = NULL; + tmp_ptr->assocReqFrameLength = 0; + } + qdf_mem_free(session->parsedAssocReq[i]); + session->parsedAssocReq[i] = NULL; + } + /* Cleanup the whole block */ + qdf_mem_free(session->parsedAssocReq); + session->parsedAssocReq = NULL; + } + if (NULL != session->limAssocResponseData) { + qdf_mem_free(session->limAssocResponseData); + session->limAssocResponseData = NULL; + } + if (NULL != session->pLimMlmReassocRetryReq) { + qdf_mem_free(session->pLimMlmReassocRetryReq); + session->pLimMlmReassocRetryReq = NULL; + } + if (NULL != session->pLimMlmReassocReq) { + qdf_mem_free(session->pLimMlmReassocReq); + session->pLimMlmReassocReq = NULL; + } + + if (NULL != session->pSchProbeRspTemplate) { + qdf_mem_free(session->pSchProbeRspTemplate); + session->pSchProbeRspTemplate = NULL; + } + + if (NULL != session->pSchBeaconFrameBegin) { + qdf_mem_free(session->pSchBeaconFrameBegin); + session->pSchBeaconFrameBegin = NULL; + } + + if (NULL != session->pSchBeaconFrameEnd) { + qdf_mem_free(session->pSchBeaconFrameEnd); + session->pSchBeaconFrameEnd = NULL; + } + + /* Must free the buffer before peSession invalid */ + if (NULL != session->addIeParams.probeRespData_buff) { + qdf_mem_free(session->addIeParams.probeRespData_buff); + session->addIeParams.probeRespData_buff = NULL; + session->addIeParams.probeRespDataLen = 0; + } + if (NULL != session->addIeParams.assocRespData_buff) { + qdf_mem_free(session->addIeParams.assocRespData_buff); + session->addIeParams.assocRespData_buff = NULL; + session->addIeParams.assocRespDataLen = 0; + } + if (NULL != session->addIeParams.probeRespBCNData_buff) { + qdf_mem_free(session->addIeParams.probeRespBCNData_buff); + session->addIeParams.probeRespBCNData_buff = NULL; + session->addIeParams.probeRespBCNDataLen = 0; + } + pe_delete_fils_info(session); + session->valid = false; + + qdf_mem_zero(session->WEPKeyMaterial, + sizeof(session->WEPKeyMaterial)); + 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); + + return; +} + +/*-------------------------------------------------------------------------- + \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 pMac - 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 tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ + +tpPESession pe_find_session_by_peer_sta(tpAniSirGlobal pMac, uint8_t *sa, + uint8_t *sessionId) +{ + uint8_t i; + tpDphHashNode pSta; + uint16_t aid; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid)) { + pSta = + dph_lookup_hash_entry(pMac, sa, &aid, + &pMac->lim.gpSession[i].dph. + dphHashTable); + if (pSta != NULL) { + *sessionId = i; + return &pMac->lim.gpSession[i]; + } + } + } + + pe_debug("Session lookup fails for Peer StaId:"); + lim_print_mac_addr(pMac, sa, LOGD); + return NULL; +} + +/** + * pe_find_session_by_sme_session_id() - looks up the PE session for given sme + * session id + * @mac_ctx: pointer to global adapter context + * @sme_session_id: sme session id + * + * looks up the PE session for given sme session id + * + * Return: pe session entry for given sme session if found else NULL + */ +tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx, + uint8_t sme_session_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].smeSessionId == + sme_session_id)) { + return &mac_ctx->lim.gpSession[i]; + } + } + return NULL; +} + +/** + * 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(tpAniSirGlobal 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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..ab6b5396d104b42fe67acc966a474f0d09b68a01 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/**========================================================================= + + \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" + +/** + * is_lim_session_off_channel() - checks if any other off channel session exists + * @mac_ctx: Global MAC context. + * @sessionId: PE session ID. + * + * Return: This function returns true if the session Id passed needs to be on + * a different channel than atleast one session already active. + **/ +uint8_t is_lim_session_off_channel(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + uint8_t i; + + if (session_id >= mac_ctx->lim.maxBssId) { + pe_warn("Invalid session_id: %d", session_id); + return false; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* Skip the session_id that is to be joined. */ + if (i == session_id) + continue; + /* + * if another session is valid and it is on different channel + * then it is an off channel operation. + */ + if ((mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].currentOperChannel != + mac_ctx->lim.gpSession[session_id].currentOperChannel)) + return true; + } + return false; + +} + +/** + * lim_is_chan_switch_running() - check if channel switch is happening + * @mac_ctx: Global MAC context. + * + * Return: 1 - if channel switch is happening on any session. + * 0 - if channel switch is not happening. + **/ +uint8_t lim_is_chan_switch_running(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid && + mac_ctx->lim.gpSession[i].gLimSpecMgmt.dot11hChanSwState + == eLIM_11H_CHANSW_RUNNING) + return 1; + return 0; +} + +/** + * 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(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + uint8_t chan = 0; + uint8_t curr_oper_channel = 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_channel = + mac_ctx->lim.gpSession[i].currentOperChannel; + if (curr_oper_channel == 0) + continue; + if (chan == 0) + chan = curr_oper_channel; + else if (chan != curr_oper_channel) + 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(tpAniSirGlobal 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/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..9639d270a025740b6b295f8477d861e0314a576a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012-2015 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 is_lim_session_off_channel(tpAniSirGlobal pMac, uint8_t sessionId); +uint8_t lim_is_chan_switch_running(tpAniSirGlobal pMac); +uint8_t lim_is_in_mcc(tpAniSirGlobal pMac); +uint8_t pe_get_current_stas_count(tpAniSirGlobal pMac); + +#endif /* #if !defined( __LIM_SESSION_UTILS_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..1d1f3e2fd022b05fa9f67d7a1924bc93e707e99e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c @@ -0,0 +1,834 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_api.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_rs_nie_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(tpAniSirGlobal mac_ctx, tpSirRSNie rsn_ie) +{ + uint8_t start = 0; + uint32_t privacy, val; + int len; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &privacy) != QDF_STATUS_SUCCESS) + pe_warn("Unable to retrieve POI from CFG"); + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_RSN_ENABLED, &val) + != QDF_STATUS_SUCCESS) + pe_warn("Unable to retrieve RSN_ENABLED from CFG"); + + 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 PRIVACY: %d RSN: %d", + rsn_ie->length, privacy, val); + } + + if (!rsn_ie->length) + 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 (SIR_MAC_MAX_IE_LENGTH <= start) + break; + + if (start <= (SIR_MAC_MAX_IE_LENGTH - 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_is_addie_valid_in_sme_req_message() + * + ***FUNCTION: + * This function is called to verify if the Add IE + * received in various SME_REQ messages is valid or not + * + ***LOGIC: + * Add IE validity checks are performed on only length + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pWSCie Pointer to received WSC IE + * @return true when WSC IE is valid, false otherwise + */ + +static uint8_t +lim_is_addie_valid_in_sme_req_message(tpAniSirGlobal pMac, tpSirAddie pAddie) +{ + int left = pAddie->length; + uint8_t *ptr = pAddie->addIEdata; + uint8_t elem_id, elem_len; + + if (left == 0) + return true; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + pe_err("Invalid Add IEs eid: %d elem_len: %d left: %d", + elem_id, elem_len, left); + return false; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + /* there shouldn't be any left byte */ + + return true; +} /*** end lim_is_addie_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(tpAniSirGlobal mac_ctx, + tpSirRSNie rsn_ie, + tpPESession session) +{ + uint32_t ret; + uint8_t wpa_idx = 0; + uint32_t privacy, val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &privacy) != QDF_STATUS_SUCCESS) + pe_warn("Unable to retrieve POI from CFG"); + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_RSN_ENABLED, + &val) != QDF_STATUS_SUCCESS) + pe_warn("Unable to retrieve RSN_ENABLED from CFG"); + + 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] != SIR_MAC_RSN_EID) && + (rsn_ie->rsnIEdata[0] != SIR_MAC_WPA_EID)) { + pe_err("RSN/WPA EID: %d not [%d || %d]", + rsn_ie->rsnIEdata[0], SIR_MAC_RSN_EID, + SIR_MAC_WPA_EID); + return false; + } + /* Check validity of RSN IE */ + if ((rsn_ie->rsnIEdata[0] == SIR_MAC_RSN_EID) && + (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, + SIR_MAC_RSN_IE_MAX_LENGTH); + return false; + } + + if (rsn_ie->length > rsn_ie->rsnIEdata[1] + 2) { + if (rsn_ie->rsnIEdata[0] != SIR_MAC_RSN_EID) { + 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] == SIR_MAC_RSN_EID)) { + 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 >= SIR_MAC_MAX_IE_LENGTH) + 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, + SIR_MAC_RSN_IE_MAX_LENGTH, 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; +} + +/** + * lim_is_bss_descr_valid_in_sme_req_message() + * + ***FUNCTION: + * This function is called to verify if the BSS Descr + * received in various SME_REQ messages is valid or not + * + ***LOGIC: + * BSS Descritipion validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pBssDescr Pointer to received Bss Descritipion + * @return true when BSS description is valid, false otherwise + */ + +static uint8_t +lim_is_bss_descr_valid_in_sme_req_message(tpAniSirGlobal pMac, + tpSirBssDescription pBssDescr) +{ + uint8_t valid = true; + + if (lim_is_addr_bc(pBssDescr->bssId) || !pBssDescr->channelId) { + valid = false; + goto end; + } + +end: + return valid; +} /*** end lim_is_bss_descr_valid_in_sme_req_message() ***/ + +/** + * 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 + * + * 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 + */ + +uint8_t +lim_is_sme_start_bss_req_valid(tpAniSirGlobal mac_ctx, + tpSirSmeStartBssReq start_bss_req) +{ + uint8_t i = 0; + tSirMacRateSet *opr_rates = &start_bss_req->operationalRateSet; + + pe_debug("Parsed START_BSS_REQ fields are bssType: %s (%d) channelId: %d SSID len: %d rsnIE len: %d nwType: %d rateset len: %d", + lim_bss_type_to_string(start_bss_req->bssType), + start_bss_req->bssType, start_bss_req->channelId, + start_bss_req->ssId.length, start_bss_req->rsnIE.length, + start_bss_req->nwType, opr_rates->numRates); + + switch (start_bss_req->bssType) { + case eSIR_INFRASTRUCTURE_MODE: + /** + * Should not have received start BSS req with bssType + * Infrastructure on STA. + */ + pe_warn("Invalid bssType: %d in eWNI_SME_START_BSS_REQ", + start_bss_req->bssType); + return false; + break; + case eSIR_IBSS_MODE: + 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 bssType: %d in eWNI_SME_START_BSS_REQ", + start_bss_req->bssType); + return false; + } + + if (start_bss_req->bssType == eSIR_IBSS_MODE + && (!start_bss_req->ssId.length + || start_bss_req->ssId.length > SIR_MAC_MAX_SSID_LENGTH)) { + pe_warn("Invalid SSID length in eWNI_SME_START_BSS_REQ"); + 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; +} + +/** + * lim_is_sme_join_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_JOIN_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pJoinReq Pointer to received SME_JOIN_REQ message + * @return true when received SME_JOIN_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_join_req_valid(tpAniSirGlobal pMac, tpSirSmeJoinReq pJoinReq) +{ + uint8_t valid = true; + + /* + * If force_rsne_override is enabled that mean User has provided the + * test RSNIE which need to be send as it is in assoc req and thus RSNIE + * validity is not required. + */ + if (!pJoinReq->force_rsne_override && + !lim_is_rsn_ie_valid_in_sme_req_message(pMac, &pJoinReq->rsnIE)) { + pe_err("received SME_JOIN_REQ with invalid RSNIE"); + valid = false; + goto end; + } + + if (!lim_is_addie_valid_in_sme_req_message(pMac, &pJoinReq->addIEScan)) { + pe_err("received SME_JOIN_REQ with invalid additional IE for scan"); + valid = false; + goto end; + } + + if (!lim_is_addie_valid_in_sme_req_message(pMac, &pJoinReq->addIEAssoc)) { + pe_err("received SME_JOIN_REQ with invalid additional IE for assoc"); + valid = false; + goto end; + } + + if (!lim_is_bss_descr_valid_in_sme_req_message(pMac, &pJoinReq->bssDescription)) { + /* / Received eWNI_SME_JOIN_REQ with invalid BSS Info */ + /* Log the event */ + pe_err("received SME_JOIN_REQ with invalid bssInfo"); + + valid = false; + goto end; + } + + /* + Reject Join Req if the Self Mac Address and + the Ap's Mac Address is same + */ + if (!qdf_mem_cmp((uint8_t *) pJoinReq->selfMacAddr, + (uint8_t *) pJoinReq->bssDescription.bssId, + (uint8_t) (sizeof(tSirMacAddr)))) { + /* Log the event */ + pe_err("received SME_JOIN_REQ with Self Mac and BSSID Same"); + + valid = false; + goto end; + } + +end: + return valid; +} /*** end lim_is_sme_join_req_valid() ***/ + +/** + * lim_is_sme_disassoc_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDisassocReq Pointer to received SME_DISASSOC_REQ message + * @return true When received SME_DISASSOC_REQ is formatted + * correctly + * false otherwise + */ + +uint8_t +lim_is_sme_disassoc_req_valid(tpAniSirGlobal pMac, + tpSirSmeDisassocReq pDisassocReq, + tpPESession psessionEntry) +{ + if (qdf_is_macaddr_group(&pDisassocReq->peer_macaddr) && + !qdf_is_macaddr_broadcast(&pDisassocReq->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_req_valid() ***/ + +/** + * lim_is_sme_disassoc_cnf_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_CNF message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDisassocCnf Pointer to received SME_DISASSOC_REQ message + * @return true When received SME_DISASSOC_CNF is formatted + * correctly + * false otherwise + */ + +uint8_t +lim_is_sme_disassoc_cnf_valid(tpAniSirGlobal pMac, + tpSirSmeDisassocCnf pDisassocCnf, + tpPESession psessionEntry) +{ + if (qdf_is_macaddr_group(&pDisassocCnf->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_cnf_valid() ***/ + +/** + * lim_is_sme_deauth_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DEAUTH_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDeauthReq Pointer to received SME_DEAUTH_REQ message + * @return true When received SME_DEAUTH_REQ is formatted correctly + * false otherwise + */ + +uint8_t +lim_is_sme_deauth_req_valid(tpAniSirGlobal pMac, tpSirSmeDeauthReq pDeauthReq, + tpPESession psessionEntry) +{ + if (qdf_is_macaddr_group(&pDeauthReq->peer_macaddr) && + !qdf_is_macaddr_broadcast(&pDeauthReq->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_deauth_req_valid() ***/ + +/** + * lim_is_sme_set_context_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_SET_CONTEXT_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMsg - Pointer to received SME_SET_CONTEXT_REQ message + * @return true when received SME_SET_CONTEXT_REQ is formatted correctly + * false otherwise + */ + +uint8_t +lim_is_sme_set_context_req_valid(tpAniSirGlobal pMac, + tpSirSmeSetContextReq pSetContextReq) +{ + uint8_t i = 0; + uint8_t valid = true; + tpSirKeys pKey = pSetContextReq->keyMaterial.key; + + if ((pSetContextReq->keyMaterial.edType != eSIR_ED_WEP40) && + (pSetContextReq->keyMaterial.edType != eSIR_ED_WEP104) && + (pSetContextReq->keyMaterial.edType != eSIR_ED_NONE) && +#ifdef FEATURE_WLAN_WAPI + (pSetContextReq->keyMaterial.edType != eSIR_ED_WPI) && +#endif + !pSetContextReq->keyMaterial.numKeys) { + /** + * No keys present in case of TKIP or CCMP + * Log error. + */ + pe_warn("No keys present in SME_SETCONTEXT_REQ for edType: %d", + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + + if (pSetContextReq->keyMaterial.numKeys && + (pSetContextReq->keyMaterial.edType == eSIR_ED_NONE)) { + /** + * Keys present in case of no ED policy + * Log error. + */ + pe_warn("Keys present in SME_SETCONTEXT_REQ for edType: %d", + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + + if (pSetContextReq->keyMaterial.edType >= eSIR_ED_NOT_IMPLEMENTED) { + /** + * Invalid edType in the message + * Log error. + */ + pe_warn("Invalid edType: %d in SME_SETCONTEXT_REQ", + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } else if (pSetContextReq->keyMaterial.edType > eSIR_ED_NONE) { + uint32_t poi; + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, + &poi) != QDF_STATUS_SUCCESS) + pe_warn("Unable to retrieve POI from CFG"); + + if (!poi) { + /** + * Privacy is not enabled + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + pe_debug("Privacy is not enabled, yet non-None EDtype: %d in SME_SETCONTEXT_REQ", + pSetContextReq->keyMaterial.edType); + } + } + + for (i = 0; i < pSetContextReq->keyMaterial.numKeys; i++) { + if (((pSetContextReq->keyMaterial.edType == eSIR_ED_WEP40) && + (pKey->keyLength != 5)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_WEP104) && + (pKey->keyLength != 13)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_TKIP) && + (pKey->keyLength != 32)) || +#ifdef FEATURE_WLAN_WAPI + ((pSetContextReq->keyMaterial.edType == eSIR_ED_WPI) && + (pKey->keyLength != 32)) || +#endif + ((pSetContextReq->keyMaterial.edType == eSIR_ED_GCMP) && + (pKey->keyLength != 16)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_GCMP_256) && + (pKey->keyLength != 32)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_CCMP) && + (pKey->keyLength != 16))) { + /** + * Invalid key length for a given ED type + * Log error. + */ + pe_warn("Invalid keyLength: %d for edType: %d in SME_SETCONTEXT_REQ", + pKey->keyLength, + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + pKey++; + } + +end: + return valid; +} /*** end lim_is_sme_set_context_req_valid() ***/ + +/** + * lim_is_sme_stop_bss_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_STOP_BSS_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMsg - Pointer to received SME_STOP_BSS_REQ message + * @return true when received SME_STOP_BSS_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_stop_bss_req_valid(uint32_t *pMsg) +{ + uint8_t valid = true; + + return valid; +} /*** end lim_is_sme_stop_bss_req_valid() ***/ + +/** + * lim_get_bss_id_from_sme_join_req_msg() + * + ***FUNCTION: + * This function is called in various places to get BSSID + * from BSS description/Neighbor BSS Info in the SME_JOIN_REQ/ + * SME_REASSOC_REQ message. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBuf - Pointer to received SME_JOIN/SME_REASSOC_REQ + * message + * @return pBssId - Pointer to BSSID + */ + +uint8_t *lim_get_bss_id_from_sme_join_req_msg(uint8_t *pBuf) +{ + if (!pBuf) + return NULL; + + pBuf += sizeof(uint32_t); /* skip message header */ + + pBuf += lim_get_u16(pBuf) + sizeof(uint16_t); /* skip RSN IE */ + + pBuf += sizeof(uint16_t); /* skip length of BSS description */ + + return pBuf; +} /*** end lim_get_bss_id_from_sme_join_req_msg() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..7bcf5b8214632de45ee56f8d170b29c345c098e6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011-2012,2014-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. + */ + +/* + * + * 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 */ +uint8_t lim_is_sme_start_bss_req_valid(tpAniSirGlobal, tpSirSmeStartBssReq); +uint8_t lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(tpAniSirGlobal, + tpSirRSNie, tpPESession); +uint8_t lim_is_sme_join_req_valid(tpAniSirGlobal, tpSirSmeJoinReq); +uint8_t lim_is_sme_disassoc_req_valid(tpAniSirGlobal, tpSirSmeDisassocReq, + tpPESession); +uint8_t lim_is_sme_deauth_req_valid(tpAniSirGlobal, tpSirSmeDeauthReq, tpPESession); +uint8_t lim_is_sme_set_context_req_valid(tpAniSirGlobal, tpSirSmeSetContextReq); +uint8_t lim_is_sme_stop_bss_req_valid(uint32_t *); +uint8_t *lim_get_bss_id_from_sme_join_req_msg(uint8_t *); +uint8_t lim_is_sme_disassoc_cnf_valid(tpAniSirGlobal, tpSirSmeDisassocCnf, + tpPESession); + +#endif /* __LIM_SME_REQ_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.c new file mode 100644 index 0000000000000000000000000000000000000000..3fa1df7e31c48758196f9483786a89c3fb30f82b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +/* + * + * lim_sta_hash_api.c: Provides access functions to get/set values of station hash entry fields. + * Author: Sunit Bhatia + * Date: 09/19/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ + +#include "lim_sta_hash_api.h" + +/** + * lim_get_sta_hash_bssidx() + * + ***FUNCTION: + * This function is called to Get the Bss Index of the currently associated Station. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param assocId AssocID of the Station. + * @param bssidx pointer to the bss index, which will be returned by the function. + * + * @return success if GET operation is ok, else Failure. + */ + +QDF_STATUS lim_get_sta_hash_bssidx(tpAniSirGlobal pMac, uint16_t assocId, + uint8_t *bssidx, tpPESession psessionEntry) +{ + tpDphHashNode pSta = + dph_get_hash_entry(pMac, assocId, &psessionEntry->dph.dphHashTable); + + if (pSta == NULL) { + pe_err("invalid STA: %d", assocId); + return QDF_STATUS_E_NOENT; + } + + *bssidx = (uint8_t) pSta->bssId; + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.h new file mode 100644 index 0000000000000000000000000000000000000000..ad02da7a7d2a50dd52ee1c90f84aadc1e7d85284 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011-2012, 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 lim_sta_hash_api.h contains the + * function prototypes for accessing station hash entry fields. + * + * Author: Sunit Bhatia + * Date: 09/19/2006 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_STA_HASH_API_H__ +#define __LIM_STA_HASH_API_H__ + +#include "ani_global.h" +#include "lim_types.h" + +QDF_STATUS lim_get_sta_hash_bssidx(tpAniSirGlobal pMac, uint16_t assocId, + uint8_t *bssidx, tpPESession psessionEntry); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..d784baf8eaadfdd39607ecafd09633b11ea49584 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c @@ -0,0 +1,1059 @@ +/* + * 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_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 + +/* channel Switch Timer in ticks */ +#define LIM_CHANNEL_SWITCH_TIMER_TICKS 1 +/* 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 JoinProbeRequest Retry timer default (200)ms */ +#define LIM_JOIN_PROBE_REQ_TIMER_MS 200 +/* 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 + +static bool lim_create_non_ap_timers(tpAniSirGlobal pMac) +{ + uint32_t cfgValue; + /* Create Channel Switch Timer */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimChannelSwitchTimer, + "CHANNEL SWITCH TIMER", + lim_channel_switch_timer_handler, 0, + LIM_CHANNEL_SWITCH_TIMER_TICKS, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("failed to create Ch Switch timer"); + return false; + } + /* Create Quiet Timer + * This is used on the STA to go and shut-off Tx/Rx "after" the + * specified quiteInterval + */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimQuietTimer, + "QUIET TIMER", lim_quiet_timer_handler, + SIR_LIM_QUIET_TIMEOUT, LIM_QUIET_TIMER_TICKS, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("failed to create Quiet Begin Timer"); + return false; + } + /* Create Quiet BSS Timer + * After the specified quiteInterval, determined by gLimQuietTimer, this + * timer, gLimQuietBssTimer, trigger and put the STA to sleep for the + * specified gLimQuietDuration + */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimQuietBssTimer, + "QUIET BSS TIMER", lim_quiet_bss_timer_handler, + SIR_LIM_QUIET_BSS_TIMEOUT, LIM_QUIET_BSS_TIMER_TICK, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("failed to create Quiet Bss Timer"); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + &cfgValue) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve JoinFailureTimeout value"); + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Join failure timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.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; + } + /* Send unicast probe req frame every 200 ms */ + if (tx_timer_create(pMac, + &pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer, + "Periodic Join Probe Request Timer", + lim_timer_handler, + SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT, + SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS), 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(pMac, + &pMac->lim.limTimers.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; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + &cfgValue) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve AssocFailureTimeout value"); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Association failure timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.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; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ADDTS_RSP_TIMEOUT, &cfgValue) + != QDF_STATUS_SUCCESS) + pe_err("Fail to get WNI_CFG_ADDTS_RSP_TIMEOUT"); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + + /* Create Addts response timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.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; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + &cfgValue) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve AuthFailureTimeout value"); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Auth failure timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.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; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + &cfgValue) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value"); + + /* Change timer to reactivate it in future */ + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimProbeAfterHBTimer, + "Probe after Heartbeat TIMEOUT", + lim_timer_handler, + SIR_LIM_PROBE_HB_FAILURE_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("unable to create ProbeAfterHBTimer"); + return false; + } + + /* + * SAE auth timer of 5secs. This is required for duration of entire SAE + * authentication. + */ + if ((tx_timer_create(pMac, + &pMac->lim.limTimers.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() + * + * @pMac : 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(tpAniSirGlobal pMac) +{ + uint32_t cfgValue, i = 0; + + pe_debug("Creating Timers used by LIM module in Role: %d", + pMac->lim.gLimSystemRole); + /* Create timers required for host roaming feature */ + if (TX_SUCCESS != lim_create_timers_host_roam(pMac)) + return TX_TIMER_ERROR; + + if (pMac->lim.gLimSystemRole != eLIM_AP_ROLE) + if (false == lim_create_non_ap_timers(pMac)) + goto err_timer; + + /* Create all CNF_WAIT Timers upfront */ + if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT, &cfgValue) + != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve CNF timeout value"); + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + for (i = 0; i < (pMac->lim.maxStation + 1); i++) { + if (tx_timer_create(pMac, + &pMac->lim.limTimers.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 */ + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_NUM_PRE_AUTH, + &cfgValue) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve mac preauth value"); + pMac->lim.gLimPreAuthTimerTable.numEntry = cfgValue; + pMac->lim.gLimPreAuthTimerTable.pTable = + qdf_mem_malloc(cfgValue * sizeof(tLimPreAuthNode *)); + + if (pMac->lim.gLimPreAuthTimerTable.pTable == NULL) { + pe_err("AllocateMemory failed!"); + goto err_timer; + } + + for (i = 0; i < cfgValue; i++) { + pMac->lim.gLimPreAuthTimerTable.pTable[i] = + qdf_mem_malloc(sizeof(tLimPreAuthNode)); + if (pMac->lim.gLimPreAuthTimerTable.pTable[i] == NULL) { + pMac->lim.gLimPreAuthTimerTable.numEntry = 0; + pe_err("AllocateMemory failed!"); + goto err_timer; + } + } + + lim_init_pre_auth_timer_table(pMac, &pMac->lim.gLimPreAuthTimerTable); + pe_debug("alloc and init table for preAuth timers"); + + if (wlan_cfg_get_int(pMac, WNI_CFG_OLBC_DETECT_TIMEOUT, + &cfgValue) != QDF_STATUS_SUCCESS) + pe_err("could not retrieve OLBD detect timeout value"); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, &pMac->lim.limTimers.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(pMac, &pMac->lim.limTimers.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(pMac, &pMac->lim.limTimers.gLimDeauthAckTimer, + "DISASSOC ACK TIMEOUT", + lim_timer_handler, SIR_LIM_DEAUTH_ACK_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not create DEAUTH ACK TIMEOUT timer"); + goto err_timer; + } + + return TX_SUCCESS; + +err_timer: + lim_delete_timers_host_roam(pMac); + tx_timer_delete(&pMac->lim.limTimers.gLimDeauthAckTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimDisassocAckTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer); + while (((int32_t)-- i) >= 0) { + tx_timer_delete(&pMac->lim.limTimers.gpLimCnfWaitTimer[i]); + } + tx_timer_delete(&pMac->lim.limTimers.gLimProbeAfterHBTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAuthFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAddtsRspTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAssocFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimJoinFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer); + tx_timer_delete(&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer); + tx_timer_delete(&pMac->lim.limTimers.gLimQuietBssTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimQuietTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimChannelSwitchTimer); + tx_timer_delete(&pMac->lim.limTimers.sae_auth_timer); + + if (NULL != pMac->lim.gLimPreAuthTimerTable.pTable) { + for (i = 0; i < pMac->lim.gLimPreAuthTimerTable.numEntry; i++) + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable[i]); + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable); + pMac->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}; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = (uint16_t) param; + msg.bodyptr = NULL; + msg.bodyval = 0; + + status = lim_post_msg_high_priority(pMac, &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}; + tpAniSirGlobal pMac = (tpAniSirGlobal) 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(pMac, &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}; + tpAniSirGlobal pMac = (tpAniSirGlobal) 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(pMac, &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}; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal) mac_global; + tpPESession session = NULL; + + session = mac_ctx->lim.pSessionEntry; + if (LIM_REASSOC == param && NULL != 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 (NULL != 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}; + tpAniSirGlobal pMac = (tpAniSirGlobal) 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(pMac, &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 pMac - 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(tpAniSirGlobal pMac, uint32_t timerId) +{ + uint32_t val = 0; + tpPESession session_entry; + + switch (timerId) { + case eLIM_REASSOC_FAIL_TIMER: + case eLIM_FT_PREAUTH_RSP_TIMER: + lim_deactivate_and_change_timer_host_roam(pMac, timerId); + break; + + case eLIM_ADDTS_RSP_TIMER: + pMac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_deactivate(&pMac->lim.limTimers.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 + (&pMac->lim.limTimers.gLimJoinFailureTimer) + != TX_SUCCESS) { + /** + * Could not deactivate Join Failure + * timer. Log error. + */ + pe_err("Unable to deactivate Join Failure timer"); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + &val) != QDF_STATUS_SUCCESS) { + /** + * Could not get JoinFailureTimeout value + * from CFG. Log error. + */ + pe_err("could not retrieve JoinFailureTimeout value"); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.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 + (&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + /* Could not deactivate periodic join req Times. */ + pe_err("Unable to deactivate periodic join request timer"); + } + + val = SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS); + if (tx_timer_change + (&pMac->lim.limTimers.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 + (&pMac->lim.limTimers.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 */ + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + &val) != QDF_STATUS_SUCCESS) { + /** + * Could not get AuthFailureTimeout value + * from CFG. Log error. + */ + pe_err("could not retrieve AuthFailureTimeout value"); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.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 + (&pMac->lim.limTimers.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(pMac, + pMac->lim.limTimers. + g_lim_periodic_auth_retry_timer.sessionId); + if (NULL == session_entry) { + pe_err("session does not exist for given SessionId : %d", + pMac->lim.limTimers. + 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 + (&pMac->lim.limTimers.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 + (&pMac->lim.limTimers.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 */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + &val) != QDF_STATUS_SUCCESS) { + /** + * Could not get AssocFailureTimeout value + * from CFG. Log error. + */ + pe_err("could not retrieve AssocFailureTimeout value"); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimAssocFailureTimer, + val, 0) != TX_SUCCESS) { + /* Could not change Association failure timer. */ + /* Log error */ + pe_err("unable to change Assoc failure timer"); + } + + break; + + case eLIM_PROBE_AFTER_HB_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimProbeAfterHBTimer) != + TX_SUCCESS) { + /* Could not deactivate Heartbeat timer. */ + /* Log error */ + pe_err("unable to deactivate probeAfterHBTimer"); + } else { + pe_debug("Deactivated probe after hb timer"); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + &val) != QDF_STATUS_SUCCESS) { + /** + * Could not get PROBE_AFTER_HB_FAILURE + * value from CFG. Log error. + */ + pe_err("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value"); + } + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimProbeAfterHBTimer, + val, 0) != TX_SUCCESS) { + /* Could not change HeartBeat timer. */ + /* Log error */ + pe_err("unable to change ProbeAfterHBTimer"); + } else { + pe_debug("Probe after HB timer value is changed: %u", + val); + } + + break; + + case eLIM_LEARN_DURATION_TIMER: + break; + + case eLIM_DISASSOC_ACK_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.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(&pMac->lim.limTimers.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(&pMac->lim.limTimers.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(&pMac->lim.limTimers.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 + (&pMac->lim.limTimers.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(&pMac->lim.limTimers.sae_auth_timer, + val, 0) != TX_SUCCESS) + pe_err("unable to change SAE auth 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 pMac - 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(tpAniSirGlobal pMac, uint32_t timerId, + uint16_t staId) +{ + uint32_t val; + + switch (timerId) { + case eLIM_CNF_WAIT_TIMER: + + if (tx_timer_deactivate + (&pMac->lim.limTimers.gpLimCnfWaitTimer[staId]) + != TX_SUCCESS) { + pe_err("unable to deactivate CNF wait timer"); + } + /* Change timer to reactivate it in future */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT, + &val) != QDF_STATUS_SUCCESS) { + /** + * Could not get cnf timeout value + * from CFG. Log error. + */ + pe_err("could not retrieve cnf timeout value"); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change + (&pMac->lim.limTimers.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(pMac, + &pMac->lim. + gLimPreAuthTimerTable, + staId); + + if (pAuthNode == NULL) { + 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 */ + + if (wlan_cfg_get_int + (pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + &val) != QDF_STATUS_SUCCESS) { + /** + * Could not get auth rsp timeout value + * from CFG. Log error. + */ + pe_err("could not retrieve auth response timeout value"); + } + + val = SYS_MS_TO_TICKS(val); + + 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 pMac - Pointer to Global MAC structure + * @param StaId - staId + * + * @return None + */ + +void lim_activate_cnf_timer(tpAniSirGlobal pMac, uint16_t staId, + tpPESession psessionEntry) +{ + pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId = + psessionEntry->peSessionId; + if (tx_timer_activate(&pMac->lim.limTimers.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 pMac - Pointer to Global MAC structure + * @param id - id + * + * @return None + */ + +void lim_activate_auth_rsp_timer(tpAniSirGlobal pMac, 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 statusCode; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_CNF_WAIT_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + statusCode = lim_post_msg_api(pMac, &msg); + if (statusCode != QDF_STATUS_SUCCESS) + pe_err("posting to LIM failed, reason: %d", statusCode); + +} + +void lim_channel_switch_timer_handler(void *pMacGlobal, uint32_t param) +{ + struct scheduler_msg msg = {0}; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + pe_debug("ChannelSwitch Timer expired. Posting msg to LIM"); + + msg.type = SIR_LIM_CHANNEL_SWITCH_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + lim_post_msg_api(pMac, &msg); +} + +void lim_quiet_timer_handler(void *pMacGlobal, uint32_t param) +{ + struct scheduler_msg msg = {0}; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_QUIET_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + pe_debug("Post SIR_LIM_QUIET_TIMEOUT msg"); + lim_post_msg_api(pMac, &msg); +} + +void lim_quiet_bss_timer_handler(void *pMacGlobal, uint32_t param) +{ + struct scheduler_msg msg = {0}; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_QUIET_BSS_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + pe_debug("Post SIR_LIM_QUIET_BSS_TIMEOUT msg"); + lim_post_msg_api(pMac, &msg); +} + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..a4ef5f30fd1adb0cb4e6f823a31d87b1e6283d2c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011-2014, 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. + */ + +/* + * + * 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 { + 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_PROBE_AFTER_HB_TIMER, + eLIM_ADDTS_RSP_TIMER, + eLIM_CHANNEL_SWITCH_TIMER, + eLIM_LEARN_DURATION_TIMER, + eLIM_QUIET_TIMER, + eLIM_QUIET_BSS_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 +}; + +#define LIM_DISASSOC_DEAUTH_ACK_TIMEOUT 500 + +/* Timer Handler functions */ +uint32_t lim_create_timers(tpAniSirGlobal); +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 limReassocFailureTimerHandler(void *, uint32_t); + +void lim_deactivate_and_change_timer(tpAniSirGlobal, uint32_t); +void limDummyPktExpTimerHandler(void *, uint32_t); +void lim_cnf_wait_tmer_handler(void *, uint32_t); +void lim_deactivate_and_change_per_sta_id_timer(tpAniSirGlobal, uint32_t, uint16_t); +void lim_activate_cnf_timer(tpAniSirGlobal, uint16_t, tpPESession); +void lim_activate_auth_rsp_timer(tpAniSirGlobal, tLimPreAuthNode *); +void lim_update_olbc_cache_timer_handler(void *, uint32_t); +void lim_addts_response_timer_handler(void *, uint32_t); +void lim_channel_switch_timer_handler(void *, uint32_t); +void lim_quiet_timer_handler(void *, uint32_t); +void lim_quiet_bss_timer_handler(void *, uint32_t); +void limCBScanIntervalTimerHandler(void *, uint32_t); +void limCBScanDurationTimerHandler(void *, uint32_t); +#endif /* __LIM_TIMER_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..847dd2e8b24d5b12f7fdf5828f85a131444a7a7a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c @@ -0,0 +1,461 @@ +/* + * 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. + */ + +/**========================================================================= + + \file lim_trace.c + + \brief implementation for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "ani_global.h" /* for tpAniSirGlobal */ + +#include "lim_trace.h" +#include "lim_timer_utils.h" +#include "qdf_trace.h" + +#ifdef LIM_TRACE_RECORD +uint32_t g_mgmt_frame_stats[14]; + +#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_PROBE_AFTER_HB_TIMER); + CASE_RETURN_STRING(eLIM_ADDTS_RSP_TIMER); + CASE_RETURN_STRING(eLIM_CHANNEL_SWITCH_TIMER); + CASE_RETURN_STRING(eLIM_LEARN_DURATION_TIMER); + CASE_RETURN_STRING(eLIM_QUIET_TIMER); + CASE_RETURN_STRING(eLIM_QUIET_BSS_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); + 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(tpAniSirGlobal pMac) +{ + qdf_trace_register(QDF_MODULE_ID_PE, &lim_trace_dump); +} + +void lim_trace_dump(void *pMac, 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_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_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_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_debug("Wrong Subtype - %d", + LIM_TRACE_GET_SUBTYPE(pRecord->data)); + else + pe_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_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_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_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_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_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_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_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_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_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_TX_CFG_MSG: + pe_debug("%04d %012llu %s S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX CFG Msg:", + mac_trace_get_cfg_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_CFG_MSG: + pe_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 CFG Msg:", + mac_trace_get_cfg_msg_string( + (uint16_t)MAC_TRACE_GET_MSG_ID(pRecord->data)), + pRecord->data); + break; + + case TRACE_CODE_TIMER_ACTIVATE: + pe_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_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_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_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(tpAniSirGlobal pMac, 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(pMac, TRACE_CODE_TX_LIM_MSG, session, data); + else + mac_trace(pMac, TRACE_CODE_TX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(pMac, TRACE_CODE_TX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace(pMac, TRACE_CODE_TX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, module_id, session, data); + break; + } +} + +void mac_trace_msg_tx_new(tpAniSirGlobal pMac, uint8_t module, 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_new(pMac, module, TRACE_CODE_TX_LIM_MSG, + session, data); + else + mac_trace_new(pMac, module, TRACE_CODE_TX_SME_MSG, + session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_TX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_TX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, module_id, session, data); + break; + } +} + +/* + * bit31: Rx message deferred or not + * bit 0-15: message ID: + */ +void mac_trace_msg_rx(tpAniSirGlobal pMac, 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(pMac, TRACE_CODE_RX_LIM_MSG, session, data); + else + mac_trace(pMac, TRACE_CODE_RX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(pMac, TRACE_CODE_RX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace(pMac, TRACE_CODE_RX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, module_id, session, data); + break; + } +} + +/* + * bit31: Rx message deferred or not + * bit 0-15: message ID: + */ +void mac_trace_msg_rx_new(tpAniSirGlobal pMac, uint8_t module, 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_new(pMac, module, TRACE_CODE_RX_LIM_MSG, + session, data); + else + mac_trace_new(pMac, module, TRACE_CODE_RX_SME_MSG, + session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_RX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_RX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, module_id, 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_PROBE_RESP_STATE); + CASE_RETURN_STRING(eLIM_MLM_PASSIVE_SCAN_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_LEARN_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_SET_MIMOPS_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_FT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_P2P_LISTEN_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_SCAN_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_LINK_EST_WT_SCAN_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); + CASE_RETURN_STRING(eLIM_SME_CHANNEL_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_CHANNEL_SCAN_STATE); + default: + return "UNKNOWN"; + break; + } +} + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_types.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_types.h new file mode 100644 index 0000000000000000000000000000000000000000..df90080b8ebde36c3de683def87d08f34f9f9bf1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_types.h @@ -0,0 +1,1119 @@ +/* + * 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. + */ + +/* + * 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 + +/* MLM message types */ +#define LIM_MLM_MSG_START 1000 +#define LIM_MLM_SCAN_REQ LIM_MLM_MSG_START +#define LIM_MLM_SCAN_CNF (LIM_MLM_MSG_START + 1) +#define LIM_MLM_START_REQ (LIM_MLM_MSG_START + 2) +#define LIM_MLM_START_CNF (LIM_MLM_MSG_START + 3) +#define LIM_MLM_JOIN_REQ (LIM_MLM_MSG_START + 4) +#define LIM_MLM_JOIN_CNF (LIM_MLM_MSG_START + 5) +#define LIM_MLM_AUTH_REQ (LIM_MLM_MSG_START + 6) +#define LIM_MLM_AUTH_CNF (LIM_MLM_MSG_START + 7) +#define LIM_MLM_AUTH_IND (LIM_MLM_MSG_START + 8) +#define LIM_MLM_ASSOC_REQ (LIM_MLM_MSG_START + 9) +#define LIM_MLM_ASSOC_CNF (LIM_MLM_MSG_START + 10) +#define LIM_MLM_ASSOC_IND (LIM_MLM_MSG_START + 11) +#define LIM_MLM_DISASSOC_REQ (LIM_MLM_MSG_START + 12) +#define LIM_MLM_DISASSOC_CNF (LIM_MLM_MSG_START + 13) +#define LIM_MLM_DISASSOC_IND (LIM_MLM_MSG_START + 14) +#define LIM_MLM_REASSOC_REQ (LIM_MLM_MSG_START + 15) +#define LIM_MLM_REASSOC_CNF (LIM_MLM_MSG_START + 16) +#define LIM_MLM_REASSOC_IND (LIM_MLM_MSG_START + 17) +#define LIM_MLM_DEAUTH_REQ (LIM_MLM_MSG_START + 18) +#define LIM_MLM_DEAUTH_CNF (LIM_MLM_MSG_START + 19) +#define LIM_MLM_DEAUTH_IND (LIM_MLM_MSG_START + 20) +#define LIM_MLM_TSPEC_REQ (LIM_MLM_MSG_START + 21) +#define LIM_MLM_TSPEC_CNF (LIM_MLM_MSG_START + 22) +#define LIM_MLM_TSPEC_IND (LIM_MLM_MSG_START + 23) +#define LIM_MLM_SETKEYS_REQ (LIM_MLM_MSG_START + 24) +#define LIM_MLM_SETKEYS_CNF (LIM_MLM_MSG_START + 25) +#define LIM_MLM_LINK_TEST_STOP_REQ (LIM_MLM_MSG_START + 30) +#define 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_HASH_ADD 0 +#define LIM_HASH_UPDATE 1 + +#define LIM_WEP_IN_FC 1 +#define LIM_NO_WEP_IN_FC 0 + +#define LIM_DECRYPT_ICV_FAIL 1 + +/* / Definitions to distinquish between Association/Reassociaton */ +#define LIM_ASSOC 0 +#define LIM_REASSOC 1 + +/* / Minimum Memory blocks require for different scenario */ +#define LIM_MIN_MEM_ASSOC 4 + +/* / Verifies whether given mac addr matches the CURRENT Bssid */ +#define IS_CURRENT_BSSID(pMac, addr, psessionEntry) (!qdf_mem_cmp(addr, \ + psessionEntry->bssId, \ + sizeof(psessionEntry->bssId))) +/* / Verifies whether given addr matches the REASSOC Bssid */ +#define IS_REASSOC_BSSID(pMac, addr, psessionEntry) (!qdf_mem_cmp(addr, \ + psessionEntry->limReAssocbssId, \ + sizeof(psessionEntry->limReAssocbssId))) + +#define REQ_TYPE_REGISTRAR (0x2) +#define REQ_TYPE_WLAN_MANAGER_REGISTRAR (0x3) + +#define RESP_TYPE_REGISTRAR (0x2) +#define RESP_TYPE_ENROLLEE_INFO_ONLY (0x0) +#define RESP_TYPE_ENROLLEE_OPEN_8021X (0x1) +#define RESP_TYPE_AP (0x3) +#define LIM_TX_FRAMES_THRESHOLD_ON_CHIP 300 + + +#define HAL_TXCOMP_REQUESTED_MASK 0x1 /* bit 0 for TxComp intr requested. */ +#define HAL_USE_SELF_STA_REQUESTED_MASK 0x2 /* bit 1 for STA overwrite with selfSta Requested. */ +#define HAL_TX_NO_ENCRYPTION_MASK 0x4 /* bit 2. If set, the frame is not to be encrypted */ +#if defined(LIBRA_WAPI_SUPPORT) +#define HAL_WAPI_STA_MASK 0x8 /* bit 3. If set, this frame is for WAPI station */ +#endif + +#define HAL_TRIGGER_ENABLED_AC_MASK 0x10 /* bit 4 for data frames belonging to trigger enabled AC */ +#define HAL_USE_NO_ACK_REQUESTED_MASK 0x20 + +#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 */ + +#ifdef FEATURE_WLAN_TDLS +#define HAL_TDLS_PEER_STA_MASK 0x80 /* bit 7 set for TDLS peer station */ +#endif + +#define LIM_DOS_PROTECTION_TIME 1000 //1000ms +#define LIM_MIN_RSSI 0 /* 0dbm */ +/* 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 +}; + +/* Reason code to determine the channel change context while sending + * WMA_CHNL_SWITCH_REQ message to HAL + */ +enum eChannelChangeReasonCodes { + LIM_SWITCH_CHANNEL_REASSOC, + LIM_SWITCH_CHANNEL_JOIN, + LIM_SWITCH_CHANNEL_OPERATION, /* Generic change channel */ + LIM_SWITCH_CHANNEL_SAP_DFS, /* DFS channel change */ +}; + +typedef struct sLimAuthRspTimeout { + tSirMacAddr peerMacAddr; +} tLimAuthRspTimeout; + +typedef struct sLimMlmStartReq { + tSirMacSSid ssId; + tSirBssType bssType; + tSirMacAddr bssId; + tSirMacBeaconInterval beaconPeriod; + uint8_t dtimPeriod; + tSirMacCfParamSet cfParamSet; + tSirMacChanNum channelNumber; + ePhyChanBondState cbMode; + uint16_t atimWindow; + 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 sLimMlmScanCnf { + tSirResultCodes resultCode; + uint16_t scanResultLength; + uint8_t sessionId; + tSirBssDescription bssDescription[1]; + /* + * WARNING: Pls make bssDescription as last variable in struct + * tLimMlmScanCnf as it has ieFields followed after this bss + * description. Adding a variable after this corrupts the ieFields + */ +} tLimMlmScanCnf, *tpLimMlmScanCnf; + +typedef struct sLimScanResult { + uint16_t numBssDescriptions; + tSirBssDescription bssDescription[1]; +} tLimScanResult; + +typedef struct sLimMlmJoinCnf { + tSirResultCodes resultCode; + uint16_t protStatusCode; + uint8_t sessionId; +} tLimMlmJoinCnf, *tpLimMlmJoinCnf; + +typedef struct sLimMlmAssocReq { + tSirMacAddr peerMacAddr; + uint32_t assocFailureTimeout; + 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; + 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; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + uint8_t sessionId; + + bool WmmStaInfoPresent; + + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + tSirSmeChanInfo 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 rx_mcs_map; + uint8_t tx_mcs_map; + uint8_t ecsa_capable; + + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + bool he_caps_present; +} tLimMlmAssocInd, *tpLimMlmAssocInd; + +typedef struct sLimMlmReassocReq { + tSirMacAddr peerMacAddr; + uint32_t reassocFailureTimeout; + 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 sLimMlmReassocInd { + tSirMacAddr peerMacAddr; + tSirMacAddr currentApAddr; + uint16_t aid; + tAniAuthType authType; + tAniSSID ssId; + tSirRSNie rsnIE; + tSirWAPIie wapiIE; + tSirAddie addIE; /* additional IE received from the peer, which can be WSC IE and/or P2P IE. */ + tSirMacCapabilityInfo capabilityInfo; + bool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + + bool WmmStaInfoPresent; + + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + uint8_t ecsa_capable; +} tLimMlmReassocInd, *tpLimMlmReassocInd; + +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; + 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 sLimMlmPurgeStaReq { + tSirMacAddr peerMacAddr; + uint16_t aid; + uint8_t sessionId; /* Added For BT-AMP Support */ +} tLimMlmPurgeStaReq, *tpLimMlmPurgeStaReq; + +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; + +typedef struct sLimMlmResetReq { + tSirMacAddr macAddr; + uint8_t performCleanup; + uint8_t sessionId; +} tLimMlmResetReq, *tpLimMlmResetReq; + +typedef struct sLimMlmResetCnf { + tSirMacAddr macAddr; + tSirResultCodes resultCode; + uint8_t sessionId; +} tLimMlmResetCnf, *tpLimMlmResetCnf; + +typedef struct sLimMlmLinkTestStopReq { + tSirMacAddr peerMacAddr; + uint8_t sessionId; +} tLimMlmLinkTestStopReq, *tpLimMlmLinkTestStopReq; + +/* Function templates */ + +bool lim_process_sme_req_messages(tpAniSirGlobal, struct scheduler_msg *); +void lim_process_mlm_req_messages(tpAniSirGlobal, struct scheduler_msg *); +void lim_process_mlm_rsp_messages(tpAniSirGlobal, uint32_t, uint32_t *); +void lim_process_sme_del_bss_rsp(tpAniSirGlobal, uint32_t, tpPESession); + +void lim_get_random_bssid(tpAniSirGlobal pMac, uint8_t *data); + +/* Function to handle HT and HT IE CFG parameter intializations */ +void handle_ht_capabilityand_ht_info(struct sAniSirGlobal *pMac, + tpPESession psessionEntry); + +/* Function to handle CFG parameter updates */ +void lim_handle_cf_gparam_update(tpAniSirGlobal, uint32_t); + +void lim_handle_param_update(tpAniSirGlobal pMac, eUpdateIEsType cfgId); + +/* Function to apply CFG parameters before join/reassoc/start BSS */ +void lim_apply_configuration(tpAniSirGlobal, tpPESession); + +void lim_set_cfg_protection(tpAniSirGlobal pMac, tpPESession pesessionEntry); + +/* Function to Initialize MLM state machine on STA */ +QDF_STATUS lim_init_mlm(tpAniSirGlobal); + +/* Function to cleanup MLM state machine */ +void lim_cleanup_mlm(tpAniSirGlobal); + +/* Management frame handling functions */ +void lim_process_beacon_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_probe_req_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_probe_rsp_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_probe_req_frame_multiple_bss(tpAniSirGlobal, uint8_t *, + tpPESession); + +/* Process Auth frame when we have a session in progress. */ +void lim_process_auth_frame(tpAniSirGlobal, uint8_t *, tpPESession); +QDF_STATUS lim_process_auth_frame_no_session(tpAniSirGlobal pMac, uint8_t *, + void *body); + +void lim_process_assoc_req_frame(tpAniSirGlobal, uint8_t *, uint8_t, tpPESession); +void lim_send_mlm_assoc_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry); + +void lim_process_assoc_rsp_frame(tpAniSirGlobal, uint8_t *, uint8_t, tpPESession); +void lim_process_disassoc_frame(tpAniSirGlobal, uint8_t *, tpPESession); +/* + * 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(tpAniSirGlobal mac_ctx, int32_t frame_rssi, + uint16_t rc, tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession pe_session, tSirMacAddr addr); +#else +static inline void lim_disassoc_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession pe_session, tSirMacAddr addr) +{ +} +#endif +void lim_process_deauth_frame(tpAniSirGlobal, uint8_t *, tpPESession); +/* + * 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(tpAniSirGlobal mac_ctx, tpPESession pe_session, + uint16_t rc, tSirMacAddr addr, int32_t frame_rssi); +void lim_process_action_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_action_frame_no_session(tpAniSirGlobal pMac, uint8_t *pRxMetaInfo); + +void lim_populate_p2p_mac_header(tpAniSirGlobal, uint8_t *); +void lim_populate_mac_header(tpAniSirGlobal, uint8_t *, uint8_t, uint8_t, + tSirMacAddr, tSirMacAddr); +QDF_STATUS lim_send_probe_req_mgmt_frame(tpAniSirGlobal, tSirMacSSid *, + tSirMacAddr, uint8_t, tSirMacAddr, + uint32_t, uint16_t *, uint8_t *); +void lim_send_probe_rsp_mgmt_frame(tpAniSirGlobal, tSirMacAddr, tpAniSSID, short, + uint8_t, tpPESession, uint8_t); +void lim_send_auth_mgmt_frame(tpAniSirGlobal, tSirMacAuthFrameBody *, tSirMacAddr, + uint8_t, tpPESession); +void lim_send_assoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmAssocReq *, tpPESession); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_send_reassoc_req_with_ft_ies_mgmt_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, tpPESession psessionEntry); +void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmReassocReq *, + tpPESession); +/** + * 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( + tpAniSirGlobal pMac, tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{} +static inline void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal mac_ctx, + tLimMlmReassocReq *reassoc_req, tpPESession 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(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + tpPESession session, + enum wmi_obss_color_collision_evt_type + event_type); +#else +static inline void lim_process_set_he_bss_color(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{} +static inline void lim_process_obss_color_collision_info(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{} +static inline void lim_send_obss_color_collision_cfg(tpAniSirGlobal mac_ctx, + tpPESession session, + enum wmi_obss_color_collision_evt_type event_type) +{} +#endif +void lim_send_delts_req_action_frame(tpAniSirGlobal pMac, tSirMacAddr peer, + uint8_t wmmTspecPresent, + tSirMacTSInfo * pTsinfo, + tSirMacTspecIE * pTspecIe, + tpPESession psessionEntry); +void lim_send_addts_req_action_frame(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *addts, tpPESession); +void lim_send_addts_rsp_action_frame(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint16_t statusCode, tSirAddtsReqInfo *addts, + tSirMacScheduleIE *pSchedule, tpPESession); + +void lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal, uint16_t, uint16_t, tSirMacAddr, + uint8_t, tpDphHashNode pSta, tpPESession); + +void lim_send_disassoc_mgmt_frame(tpAniSirGlobal, uint16_t, tSirMacAddr, + tpPESession, bool waitForAck); +void lim_send_deauth_mgmt_frame(tpAniSirGlobal, uint16_t, tSirMacAddr, tpPESession, + bool waitForAck); + +void lim_process_mlm_update_hidden_ssid_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg); + +tSirResultCodes lim_mlm_add_bss(tpAniSirGlobal, tLimMlmStartReq *, + tpPESession psessionEntry); + +QDF_STATUS lim_send_channel_switch_mgmt_frame(tpAniSirGlobal, tSirMacAddr, + uint8_t, uint8_t, uint8_t, + tpPESession); + +QDF_STATUS lim_send_extended_chan_switch_action_frame(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, uint8_t mode, uint8_t new_op_class, + uint8_t new_channel, uint8_t count, tpPESession session_entry); +QDF_STATUS lim_p2p_oper_chan_change_confirm_action_frame( + tpAniSirGlobal mac_ctx, tSirMacAddr peer, + tpPESession session_entry); + +QDF_STATUS lim_send_vht_opmode_notification_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, uint8_t nMode, + tpPESession psessionEntry); + +QDF_STATUS lim_send_neighbor_report_request_frame(tpAniSirGlobal, + tpSirMacNeighborReportReq, + tSirMacAddr, tpPESession); +QDF_STATUS lim_send_link_report_action_frame(tpAniSirGlobal, tpSirMacLinkReport, + tSirMacAddr, tpPESession); + +/** + * lim_send_radio_measure_report_action_frame - Send RRM report action frame + * @pMac: pointer to global MAC context + * @dialog_token: Dialog token to be used in the action frame + * @num_report: number of reports in pRRMReport + * @last_beacon_report_params: Last Beacon Report indication params + * @pRRMReport: Pointer to the RRM report structure + * @peer: MAC address of the peer + * @psessionEntry: Pointer to the PE session entry + * + * Return: Ret Status + */ +QDF_STATUS +lim_send_radio_measure_report_action_frame(tpAniSirGlobal pMac, + uint8_t dialog_token, + uint8_t num_report, + struct rrm_beacon_report_last_beacon_params + *last_beacon_report_params, + tpSirMacRadioMeasureReport pRRMReport, + tSirMacAddr peer, + tpPESession psessionEntry); + +#ifdef FEATURE_WLAN_TDLS +void lim_init_tdls_data(tpAniSirGlobal, tpPESession); +QDF_STATUS lim_process_sme_tdls_mgmt_send_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +QDF_STATUS lim_process_sme_tdls_add_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +QDF_STATUS lim_process_sme_tdls_del_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +void lim_send_sme_mgmt_tx_completion( + tpAniSirGlobal pMac, + uint32_t sme_session_id, + uint32_t txCompleteStatus); +QDF_STATUS lim_delete_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession session_entry); +QDF_STATUS lim_process_tdls_add_sta_rsp(tpAniSirGlobal pMac, void *msg, tpPESession); +void lim_process_tdls_del_sta_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg, + tpPESession 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(tpPESession session_entry, bool value); +#else +static inline QDF_STATUS lim_delete_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + return QDF_STATUS_SUCCESS; +} +static inline void lim_init_tdls_data(tpAniSirGlobal pMac, + tpPESession pSessionEntry) +{ + +} + +static inline void lim_update_tdls_set_state_for_fw(tpPESession session_entry, + bool value) +{ +} +#endif + +/* Algorithms & Link Monitoring related functions */ +/* / Function that handles heartbeat failure */ +void lim_handle_heart_beat_failure(tpAniSirGlobal, tpPESession); + +/* / Function that triggers link tear down with AP upon HB failure */ +void lim_tear_down_link_with_ap(tpAniSirGlobal, uint8_t, tSirMacReasonCodes); + +/* / Function that processes Max retries interrupt from TFP */ +void limHandleMaxRetriesInterrupt(uint32_t); + +/* / Function that defers the messages received */ +uint32_t lim_defer_msg(tpAniSirGlobal, struct scheduler_msg *); + +/* / Function that Switches the Channel and sets the CB Mode */ +void lim_set_channel(tpAniSirGlobal pMac, uint8_t channel, + uint8_t ch_center_freq_seg0, uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, int8_t maxTxPower, + uint8_t peSessionId, uint32_t cac_duration_ms, + uint32_t dfs_regdomain); + + +#ifdef ANI_SUPPORT_11H +/* / Function that sends Measurement Report action frame */ +QDF_STATUS lim_send_meas_report_frame(tpAniSirGlobal, tpSirMacMeasReqActionFrame, + tSirMacAddr, tpPESession psessionEntry); + +/* / Function that sends TPC Report action frame */ +QDF_STATUS lim_send_tpc_report_frame(tpAniSirGlobal, tpSirMacTpcReqActionFrame, + tSirMacAddr, tpPESession psessionEntry); +#endif + +/* / Function that sends TPC Request action frame */ +void lim_send_tpc_request_frame(tpAniSirGlobal, tSirMacAddr, + tpPESession psessionEntry); + +/* Function(s) to handle responses received from HAL */ +void lim_process_mlm_add_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ); +void lim_process_mlm_add_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQt, + tpPESession psessionEntry); +void lim_process_mlm_del_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ); +void lim_process_mlm_del_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession); +void lim_process_sta_mlm_add_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry); +void lim_process_sta_mlm_del_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry); +void lim_process_sta_mlm_del_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry); +void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ); +void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ); + +/* Function to process WMA_SWITCH_CHANNEL_RSP message */ +void lim_process_switch_channel_rsp(tpAniSirGlobal pMac, void *); + +void limContinueChannelLearn(tpAniSirGlobal); + +#ifdef WLAN_FEATURE_11W +/* 11w send SA query request action frame */ +QDF_STATUS lim_send_sa_query_request_frame(tpAniSirGlobal pMac, uint8_t *transId, + tSirMacAddr peer, + tpPESession psessionEntry); +/* 11w SA query request action frame handler */ +QDF_STATUS lim_send_sa_query_response_frame(tpAniSirGlobal pMac, + uint8_t *transId, tSirMacAddr peer, + tpPESession psessionEntry); +#endif + +/* 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 pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_sme_message(tpAniSirGlobal pMac, uint32_t msgType, uint32_t *pMsgBuf) +{ + struct scheduler_msg msg = {0}; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + msg.type = (uint16_t) msgType; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + if (msgType > eWNI_SME_MSG_TYPES_BEGIN) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, + msg.type)); + lim_process_sme_req_messages(pMac, &msg); + } else { + lim_process_mlm_rsp_messages(pMac, msgType, pMsgBuf); + } +} /*** 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 pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_mlm_message(tpAniSirGlobal pMac, uint32_t msgType, uint32_t *pMsgBuf) +{ + struct scheduler_msg msg = {0}; + + if (pMsgBuf == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + msg.type = (uint16_t) msgType; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + MTRACE(mac_trace_msg_rx(pMac, NO_SESSION, msg.type)); + lim_process_mlm_req_messages(pMac, &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 tSirBssDescription 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(tpSirBssDescription pBssDescr) +{ + uint16_t ielen; + + if (!pBssDescr) + return 0; + + /* + * Length of BSS desription is without length of + * length itself and length of pointer + * that holds ieFields + * + * <------------sizeof(tSirBssDescription)--------------------> + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + + ielen = (uint16_t)(pBssDescr->length + sizeof(pBssDescr->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + return ielen; +} /*** 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(tpAniSirGlobal mac_ctx, tpPESession session, + enum sir_bcn_update_reason reason); + +void +lim_send_vdev_restart(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t sessionId); + +void lim_get_wpspbc_sessions(tpAniSirGlobal pMac, struct qdf_mac_addr addr, + uint8_t *uuid_e, eWPSPBCOverlap *overlap, + tpPESession psessionEntry); +void limWPSPBCTimeout(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_wpspbc_close(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_remove_pbc_sessions(tpAniSirGlobal pMac, + struct qdf_mac_addr pRemoveMac, + tpPESession psessionEntry); + +#define LIM_WPS_OVERLAP_TIMER_MS 10000 +void +lim_change_channel_with_callback(tpAniSirGlobal pMac, uint8_t newChannel, + CHANGE_CHANNEL_CALLBACK callback, + uint32_t *cbdata, tpPESession psessionEntry); + +void lim_process_remain_on_chn_timeout(tpAniSirGlobal pMac); +void lim_send_p2p_action_frame(tpAniSirGlobal pMac, struct scheduler_msg *pMsg); + +void lim_process_disassoc_ack_timeout(tpAniSirGlobal pMac); +void lim_process_deauth_ack_timeout(tpAniSirGlobal pMac); +QDF_STATUS lim_send_disassoc_cnf(tpAniSirGlobal pMac); +QDF_STATUS lim_send_deauth_cnf(tpAniSirGlobal pMac); + +/** + * 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); + +typedef struct sSetLinkCbackParams { + void *cbackDataPtr; +} tSetLinkCbackParams; + +int lim_process_remain_on_chnl_req(tpAniSirGlobal pMac, uint32_t *pMsg); +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, QDF_STATUS status, uint32_t *data); +void lim_send_sme_disassoc_deauth_ntf(tpAniSirGlobal mac_ctx, + QDF_STATUS status, uint32_t *ctx); + +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS lim_process_sme_del_all_tdls_peers(tpAniSirGlobal p_mac, + uint32_t *msg_buf); +#else +static inline +QDF_STATUS lim_process_sme_del_all_tdls_peers(tpAniSirGlobal p_mac, + uint32_t *msg_buf) +{ + 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(tpAniSirGlobal mac_ctx, tpSendbeaconParams rsp); + +/** + * lim_remove_duplicate_bssid_node() - remove duplicate bssid from the + * @entry: entry to check for which the duplicate entry is present + * @list: mac_ctx->roam.rssi_disallow_bssid list + * + * Return: None + */ +void lim_remove_duplicate_bssid_node(struct sir_rssi_disallow_lst *entry, + qdf_list_t *list); + +/** + * lim_add_roam_blacklist_ap() - handle the blacklist bssid list received from + * firmware + * @mac_ctx: Pointer to Global MAC structure + * @list: roam blacklist ap list + * + * Return: None + */ +void lim_add_roam_blacklist_ap(tpAniSirGlobal mac_ctx, + struct roam_blacklist_event *src_lst); + +/** + * lim_process_rx_channel_status_event() - processes + * event WDA_RX_CHN_STATUS_EVENT + * @mac_ctx Pointer to Global MAC structure + * @buf: Received message info + * + * Return: None + */ +void lim_process_rx_channel_status_event(tpAniSirGlobal mac_ctx, void *buf); + +/* / Bit value data structure */ +typedef enum sHalBitVal /* For Bit operations */ +{ + eHAL_CLEAR, + eHAL_SET +} tHalBitVal; + +enum { + eHI_PRI, + ePROT, + eDBG +}; + +QDF_STATUS lim_send_addba_response_frame(tpAniSirGlobal mac_ctx, + tSirMacAddr peer_mac, uint16_t tid, + tpPESession session, + uint8_t addba_extn_present, + uint8_t amsdu_support); +/** + * 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(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + uint32_t msg_type); + +/** + * 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg); + +#endif /* __LIM_TYPES_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..e39c9a0215d658c7e07d0b4539fb0ec81ecbaf9e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c @@ -0,0 +1,8489 @@ +/* + * 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_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 "lim_sta_hash_api.h" +#include "dot11f.h" +#include "dot11fdefs.h" +#include "wmm_apsd.h" +#include "lim_trace.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "lim_ibss_peer_mgmt.h" +#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" +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +#include "wma_he.h" +#endif +#include "wlan_utility.h" +#include "wlan_mlme_main.h" + +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif +#define ASCII_SPACE_CHARACTER 0x20 + +/** ------------------------------------------------------------- + \fn lim_delete_dialogue_token_list + \brief deletes the complete lim dialogue token linked list. + \param tpAniSirGlobal pMac + \return None + -------------------------------------------------------------*/ +void lim_delete_dialogue_token_list(tpAniSirGlobal pMac) +{ + tpDialogueToken pCurrNode = pMac->lim.pDialogueTokenHead; + + while (NULL != pMac->lim.pDialogueTokenHead) { + pCurrNode = pMac->lim.pDialogueTokenHead; + pMac->lim.pDialogueTokenHead = + pMac->lim.pDialogueTokenHead->next; + qdf_mem_free(pCurrNode); + pCurrNode = NULL; + } + pMac->lim.pDialogueTokenTail = NULL; +} + +char *lim_dot11_reason_str(uint16_t reasonCode) +{ + switch (reasonCode) { + case 0: + return " "; + CASE_RETURN_STRING(eSIR_MAC_UNSPEC_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_PREV_AUTH_NOT_VALID_REASON); + CASE_RETURN_STRING(eSIR_MAC_DEAUTH_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON); + CASE_RETURN_STRING + (eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON); + CASE_RETURN_STRING + (eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON); + CASE_RETURN_STRING(eSIR_MAC_PWR_CAPABILITY_BAD_REASON); + CASE_RETURN_STRING(eSIR_MAC_SPRTD_CHANNELS_BAD_REASON); + + CASE_RETURN_STRING(eSIR_MAC_INVALID_IE_REASON); + CASE_RETURN_STRING(eSIR_MAC_MIC_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_RSN_IE_MISMATCH_REASON); + + CASE_RETURN_STRING(eSIR_MAC_INVALID_MC_CIPHER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_UC_CIPHER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_AKMP_REASON); + CASE_RETURN_STRING(eSIR_MAC_UNSUPPORTED_RSN_IE_VER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_RSN_CAPABILITIES_REASON); + CASE_RETURN_STRING(eSIR_MAC_1X_AUTH_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_CIPHER_SUITE_REJECTED_REASON); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE); + CASE_RETURN_STRING(eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); +#endif + /* Reserved 27 - 30 */ +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING + (eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION); +#endif + CASE_RETURN_STRING(eSIR_MAC_QOS_UNSPECIFIED_REASON); + CASE_RETURN_STRING(eSIR_MAC_QAP_NO_BANDWIDTH_REASON); + CASE_RETURN_STRING(eSIR_MAC_XS_UNACKED_FRAMES_REASON); + CASE_RETURN_STRING(eSIR_MAC_BAD_TXOP_USE_REASON); + CASE_RETURN_STRING(eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_PEER_REJECT_MECHANISIM_REASON); + CASE_RETURN_STRING(eSIR_MAC_MECHANISM_NOT_SETUP_REASON); + + CASE_RETURN_STRING(eSIR_MAC_PEER_TIMEDOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_CIPHER_NOT_SUPPORTED_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON); + /* Reserved 47 - 65535 */ + default: + return "Unknown"; + } +} + +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_PROBE_RESP_STATE: + return "eLIM_MLM_WT_PROBE_RESP_STATE"; + case eLIM_MLM_PASSIVE_SCAN_STATE: + return "eLIM_MLM_PASSIVE_SCAN_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(tpAniSirGlobal pMac, 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_SCAN_STATE: + return "eLIM_SME_WT_SCAN_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_LINK_EST_WT_SCAN_STATE: + return "eLIM_SME_LINK_EST_WT_SCAN_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"; + case eLIM_SME_CHANNEL_SCAN_STATE: + return "eLIM_SME_CHANNEL_SCAN_STATE"; + case eLIM_SME_NORMAL_CHANNEL_SCAN_STATE: + return "eLIM_SME_NORMAL_CHANNEL_SCAN_STATE"; + default: + return "INVALID SME STATE"; + } +} + +void +lim_print_sme_state(tpAniSirGlobal pMac, uint16_t logLevel, tLimSmeStates state) +{ + pe_debug("SME state: %s", lim_sme_state_str(state)); +} + +char *lim_msg_str(uint32_t msgType) +{ +#ifdef FIXME_GEN6 + 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_REQ: + return "eWNI_SME_SETCONTEXT_REQ"; + 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_WM_STATUS_CHANGE_NTF: + return "eWNI_SME_WM_STATUS_CHANGE_NTF"; + 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_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_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 WMA_SUSPEND_ACTIVITY_RSP: + return "WMA_SUSPEND_ACTIVITY_RSP"; + case SIR_LIM_RETRY_INTERRUPT_MSG: + return "SIR_LIM_RETRY_INTERRUPT_MSG"; + case SIR_BB_XPORT_MGMT_MSG: + return "SIR_BB_XPORT_MGMT_MSG"; + case SIR_LIM_INV_KEY_INTERRUPT_MSG: + return "SIR_LIM_INV_KEY_INTERRUPT_MSG"; + case SIR_LIM_KEY_ID_INTERRUPT_MSG: + return "SIR_LIM_KEY_ID_INTERRUPT_MSG"; + case SIR_LIM_REPLAY_THRES_INTERRUPT_MSG: + return "SIR_LIM_REPLAY_THRES_INTERRUPT_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_HASH_MISS_THRES_TIMEOUT: + return "SIR_LIM_HASH_MISS_THRES_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_RADAR_DETECT_IND: + return "SIR_LIM_RADAR_DETECT_IND"; + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + return "SIR_LIM_FT_PREAUTH_RSP_TIMEOUT"; + case WNI_CFG_PARAM_UPDATE_IND: + return "WNI_CFG_PARAM_UPDATE_IND"; + case WNI_CFG_DNLD_REQ: + return "WNI_CFG_DNLD_REQ"; + case WNI_CFG_DNLD_CNF: + return "WNI_CFG_DNLD_CNF"; + case WNI_CFG_GET_RSP: + return "WNI_CFG_GET_RSP"; + case WNI_CFG_SET_CNF: + return "WNI_CFG_SET_CNF"; + case WNI_CFG_GET_ATTRIB_RSP: + return "WNI_CFG_GET_ATTRIB_RSP"; + case WNI_CFG_ADD_GRP_ADDR_CNF: + return "WNI_CFG_ADD_GRP_ADDR_CNF"; + case WNI_CFG_DEL_GRP_ADDR_CNF: + return "WNI_CFG_DEL_GRP_ADDR_CNF"; + case ANI_CFG_GET_RADIO_STAT_RSP: + return "ANI_CFG_GET_RADIO_STAT_RSP"; + case ANI_CFG_GET_PER_STA_STAT_RSP: + return "ANI_CFG_GET_PER_STA_STAT_RSP"; + case ANI_CFG_GET_AGG_STA_STAT_RSP: + return "ANI_CFG_GET_AGG_STA_STAT_RSP"; + case ANI_CFG_CLEAR_STAT_RSP: + return "ANI_CFG_CLEAR_STAT_RSP"; + case WNI_CFG_DNLD_RSP: + return "WNI_CFG_DNLD_RSP"; + case WNI_CFG_GET_REQ: + return "WNI_CFG_GET_REQ"; + case eWNI_PMC_ENTER_IMPS_RSP: + return "eWNI_PMC_ENTER_IMPS_RSP"; + case eWNI_PMC_EXIT_IMPS_RSP: + return "eWNI_PMC_EXIT_IMPS_RSP"; + case eWNI_PMC_ENTER_BMPS_RSP: + return "eWNI_PMC_ENTER_BMPS_RSP"; + case eWNI_PMC_EXIT_BMPS_RSP: + return "eWNI_PMC_EXIT_BMPS_RSP"; + case eWNI_PMC_EXIT_BMPS_IND: + return "eWNI_PMC_EXIT_BMPS_IND"; +#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_CSA_OFFLOAD_EVENT: + return "eWNI_SME_CSA_OFFLOAD_EVENT"; + 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"; + default: + return "INVALID SME message"; + } +#endif + return ""; +} + +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 "INVALID resultCode"; + } +} + +void lim_print_msg_name(tpAniSirGlobal pMac, 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 + * @pMac: Pointer to Global MAC structure + * + * @Return: Status of operation + */ +QDF_STATUS lim_init_mlm(tpAniSirGlobal pMac) +{ + uint32_t retVal; + + pMac->lim.gLimTimersCreated = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_MLM_STATE, NO_SESSION, + pMac->lim.gLimMlmState)); + + /* Initialize number of pre-auth contexts */ + pMac->lim.gLimNumPreAuthContexts = 0; + + /* Initialize MAC based Authentication STA list */ + lim_init_pre_auth_list(pMac); + + /* Create timers used by LIM */ + retVal = lim_create_timers(pMac); + if (retVal != TX_SUCCESS) { + pe_err("lim_create_timers Failed"); + return QDF_STATUS_SUCCESS; + } + + pMac->lim.gLimTimersCreated = 1; + return QDF_STATUS_SUCCESS; +} /*** end lim_init_mlm() ***/ + +void lim_deactivate_timers(tpAniSirGlobal mac_ctx) +{ + uint32_t n; + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + + lim_deactivate_timers_host_roam(mac_ctx); + + /* Deactivate channel switch timer. */ + tx_timer_deactivate(&lim_timer->gLimChannelSwitchTimer); + + /* 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.limTimers.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 wait-for-probe-after-Heartbeat timer. */ + tx_timer_deactivate(&lim_timer->gLimProbeAfterHBTimer); + + /* Deactivate and delete Quiet timer. */ + tx_timer_deactivate(&lim_timer->gLimQuietTimer); + + /* Deactivate Quiet BSS timer. */ + tx_timer_deactivate(&lim_timer->gLimQuietBssTimer); + + /* 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_timer_handler(mac_ctx, SIR_LIM_DEAUTH_ACK_TIMEOUT); + } + tx_timer_deactivate(&lim_timer->gLimDeauthAckTimer); + + tx_timer_deactivate(&lim_timer->sae_auth_timer); +} + + +/** + * 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(tpAniSirGlobal mac_ctx) +{ + uint32_t n; + + tLimPreAuthNode **pAuthNode; + tLimTimers *lim_timer = NULL; + + if (mac_ctx->lim.gLimTimersCreated == 1) { + lim_timer = &mac_ctx->lim.limTimers; + + lim_deactivate_timers(mac_ctx); + + lim_delete_timers_host_roam(mac_ctx); + /* Delete channel switch timer. */ + tx_timer_delete(&lim_timer->gLimChannelSwitchTimer); + + /* 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 wait-for-probe-after-Heartbeat timer. */ + tx_timer_delete(&lim_timer->gLimProbeAfterHBTimer); + + /* Delete Quiet timer. */ + tx_timer_delete(&lim_timer->gLimQuietTimer); + + /* Delete Quiet BSS timer. */ + tx_timer_delete(&lim_timer->gLimQuietBssTimer); + + /* 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); + + mac_ctx->lim.gLimTimersCreated = 0; + } +} /*** end lim_cleanup_mlm() ***/ + +/** + * lim_is_addr_bc() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed MAC address is a broadcast or not + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param macAddr Indicates MAC address that need to be determined + * whether it is Broadcast address or not + * + * @return true if passed address is Broadcast address else false + */ + +uint8_t lim_is_addr_bc(tSirMacAddr macAddr) +{ + int i; + + for (i = 0; i < 6; i++) { + if ((macAddr[i] & 0xFF) != 0xFF) + return false; + } + + return true; +} /****** end lim_is_addr_bc() ******/ + +/** + * lim_is_group_addr() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed MAC address is a group address or not + * + ***LOGIC: + * If least significant bit of first octet of the MAC address is + * set to 1, it is a Group address. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param macAddr Indicates MAC address that need to be determined + * whether it is Group address or not + * + * @return true if passed address is Group address else false + */ + +uint8_t lim_is_group_addr(tSirMacAddr macAddr) +{ + if ((macAddr[0] & 0x01) == 0x01) + return true; + else + return false; +} /****** end lim_is_group_addr() ******/ + +/** + * lim_print_mac_addr() + * + ***FUNCTION: + * This function is called to print passed MAC address + * in : format. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * @param macAddr - MacAddr to be printed + * @param logLevel - Loglevel to be used + * + * @return None. + */ + +void lim_print_mac_addr(tpAniSirGlobal pMac, tSirMacAddr macAddr, uint8_t logLevel) +{ + pe_debug(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(macAddr)); +} /****** end lim_print_mac_addr() ******/ + +/* + * lim_reset_deferred_msg_q() + * + ***FUNCTION: + * This function resets the deferred message queue parameters. + * + ***PARAMS: + * @param pMac - Pointer to Global MAC structure + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + ***RETURNS: + * None + */ + +void lim_reset_deferred_msg_q(tpAniSirGlobal pMac) +{ + struct scheduler_msg *read_msg = {0}; + + if (pMac->lim.gLimDeferredMsgQ.size > 0) { + while ((read_msg = lim_read_deferred_msg_q(pMac)) != NULL) { + pe_free_msg(pMac, read_msg); + } + } + + pMac->lim.gLimDeferredMsgQ.size = + pMac->lim.gLimDeferredMsgQ.write = + pMac->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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg) +{ + uint8_t type, subtype; + + 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, + true, 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 scan: %d global sme: %d global mlme: %d addts: %d", + mac_ctx->lim.gLimDeferredMsgQ.size, + lim_msg->type, + lim_is_system_in_scan_state(mac_ctx), + 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("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 pMac - 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(tpAniSirGlobal pMac) +{ + struct scheduler_msg *msg = {0}; + + /* + ** check any messages left. If no, return + **/ + if (pMac->lim.gLimDeferredMsgQ.size <= 0) + return NULL; + + /* + ** decrement the queue size + **/ + pMac->lim.gLimDeferredMsgQ.size--; + + /* + ** retrieve the message from the head of the queue + **/ + msg = + &pMac->lim.gLimDeferredMsgQ.deferredQueue[pMac->lim. + gLimDeferredMsgQ.read]; + + /* + ** advance the read pointer + **/ + pMac->lim.gLimDeferredMsgQ.read++; + + /* + ** if the read pointer hits the end of the queue, rewind it + **/ + if (pMac->lim.gLimDeferredMsgQ.read >= MAX_DEFERRED_QUEUE_LEN) + pMac->lim.gLimDeferredMsgQ.read = 0; + + pe_debug("DeQueue a deferred message size: %d read: %d - type: 0x%x", + pMac->lim.gLimDeferredMsgQ.size, + pMac->lim.gLimDeferredMsgQ.read, msg->type); + + pe_debug("DQ msg -- scan: %d global sme: %d global mlme: %d addts: %d", + lim_is_system_in_scan_state(pMac), pMac->lim.gLimSmeState, + pMac->lim.gLimMlmState, pMac->lim.gLimAddtsSent); + + return msg; +} + +QDF_STATUS +lim_sys_process_mmh_msg_api(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg, uint8_t qType) +{ + /* FIXME */ + sys_process_mmh_msg(pMac, pMsg); + return QDF_STATUS_SUCCESS; +} + +/* + * 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(tpAniSirGlobal mac_ctx) +{ + int i; + static int enable; + tUpdateBeaconParams beaconParams; + + tpPESession psessionEntry = lim_is_ap_session_active(mac_ctx); + + if (psessionEntry == NULL) { + pe_err(" Session not found"); + return; + } + + if (psessionEntry->is_session_obss_offload_enabled) { + pe_debug("protection offloaded"); + return; + } + qdf_mem_zero((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams)); + beaconParams.bssIdx = psessionEntry->bssIdx; + + 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"); + psessionEntry->gLimOlbcParams.numSta = 0; + psessionEntry->gLimOverlap11gParams.numSta = 0; + psessionEntry->gLimOverlapHt20Params.numSta = 0; + psessionEntry->gLimNonGfParams.numSta = 0; + psessionEntry->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 ((!psessionEntry->gLimOlbcParams.numSta) && + (psessionEntry->gLimOlbcParams.protectionEnabled) && + (!psessionEntry->gLim11bParams.protectionEnabled)) { + pe_debug("Overlap cache clear and no 11B STA set"); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + if ((!psessionEntry->gLimOverlap11gParams.numSta) && + (psessionEntry->gLimOverlap11gParams.protectionEnabled) + && (!psessionEntry->gLim11gParams.protectionEnabled)) { + pe_debug("Overlap cache clear and no 11G STA set"); + lim_enable_ht_protection_from11g(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + if ((!psessionEntry->gLimOverlapHt20Params.numSta) && + (psessionEntry->gLimOverlapHt20Params.protectionEnabled) + && (!psessionEntry->gLimHt20Params.protectionEnabled)) { + pe_debug("Overlap cache clear and no HT20 STA set"); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + enable = 0; + } + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beaconParams.paramChangeBitmap) { + sch_set_fixed_beacon_fields(mac_ctx, psessionEntry); + lim_send_beacon_params(mac_ctx, &beaconParams, psessionEntry); + } + /* Start OLBC timer */ + if (tx_timer_activate(&mac_ctx->lim.limTimers.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 charactes 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 charactes 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 tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tLimProtStaCacheType protStaCacheType + \param tHalBitVal gfSupported + \param tHalBitVal lsigTxopSupported + \return None + -------------------------------------------------------------*/ +static void +lim_update_prot_sta_params(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tLimProtStaCacheType protStaCacheType, + tHalBitVal gfSupported, tHalBitVal lsigTxopSupported, + tpPESession psessionEntry) +{ + uint32_t i; + + pe_debug("Associated STA addr is:"); + lim_print_mac_addr(pMac, peerMacAddr, LOGD); + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (psessionEntry->protStaCache[i].active) { + pe_debug("Addr:"); + lim_print_mac_addr + (pMac, psessionEntry->protStaCache[i].addr, + LOGD); + + if (!qdf_mem_cmp + (psessionEntry->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 (!psessionEntry->protStaCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + pe_err("No space in ProtStaCache"); + return; + } + + qdf_mem_copy(psessionEntry->protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr)); + + psessionEntry->protStaCache[i].protStaCacheType = protStaCacheType; + psessionEntry->protStaCache[i].active = true; + if (eLIM_PROT_STA_CACHE_TYPE_llB == protStaCacheType) { + psessionEntry->gLim11bParams.numSta++; + pe_debug("11B,"); + } else if (eLIM_PROT_STA_CACHE_TYPE_llG == protStaCacheType) { + psessionEntry->gLim11gParams.numSta++; + pe_debug("11G,"); + } else if (eLIM_PROT_STA_CACHE_TYPE_HT20 == protStaCacheType) { + psessionEntry->gLimHt20Params.numSta++; + pe_debug("HT20,"); + } + + if (!gfSupported) { + psessionEntry->gLimNonGfParams.numSta++; + pe_debug("NonGf,"); + } + if (!lsigTxopSupported) { + psessionEntry->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 tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \return None + -------------------------------------------------------------*/ +void +lim_decide_ap_protection(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + uint16_t tmpAid; + tpDphHashNode pStaDs; + enum band_info rfBand = 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 */ + pStaDs = + dph_lookup_hash_entry(pMac, peerMacAddr, &tmpAid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + pe_err("pStaDs is NULL"); + return; + } + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + /* if we are in 5 GHZ band */ + if (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 == psessionEntry->htCapability) { + /* we are 11N and 11A station is joining. */ + /* protection from 11A required. */ + if (false == pStaDs->mlmStaContext.htCapability) { + lim_update_11a_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + return; + } + } + } else if (BAND_2G == rfBand) { + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* We are 11G. Check if we need protection from 11b Stations. */ + if ((phyMode == WNI_CFG_PHY_MODE_11G) && + (false == psessionEntry->htCapability)) { + + if (pStaDs->erpEnabled == eHAL_CLEAR) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + pe_debug("Enabling protection from 11B"); + lim_enable11g_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + } + } + /* HT station. */ + if (true == psessionEntry->htCapability) { + /* check if we need protection from 11b station */ + if ((pStaDs->erpEnabled == eHAL_CLEAR) && + (!pStaDs->mlmStaContext.htCapability)) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + pe_debug("Enabling protection from 11B"); + lim_enable11g_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + } + /* station being joined is non-11b and non-ht ==> 11g device */ + else if (!pStaDs->mlmStaContext.htCapability) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llG; + /* enable protection */ + lim_enable_ht_protection_from11g(pMac, true, false, + pBeaconParams, + psessionEntry); + } + /* 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 == psessionEntry->htCapability) && + (true == pStaDs->mlmStaContext.htCapability)) { + if (!pStaDs->htGreenfield) { + lim_enable_ht_non_gf_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + gfSupported = eHAL_CLEAR; + } + /* Station joining is HT 20Mhz */ + if ((eHT_CHANNEL_WIDTH_20MHZ == + pStaDs->htSupportedChannelWidthSet) && + (eHT_CHANNEL_WIDTH_20MHZ != + psessionEntry->htSupportedChannelWidthSet)){ + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_HT20; + lim_enable_ht20_protection(pMac, true, false, + pBeaconParams, psessionEntry); + } + /* Station joining does not support LSIG TXOP Protection */ + if (!pStaDs->htLsigTXOPProtection) { + lim_enable_ht_lsig_txop_protection(pMac, false, false, + pBeaconParams, + psessionEntry); + lsigTxopSupported = eHAL_CLEAR; + } + } + + lim_update_prot_sta_params(pMac, peerMacAddr, protStaCacheType, + gfSupported, lsigTxopSupported, psessionEntry); + + return; +} + +/** ------------------------------------------------------------- + \fn lim_enable_overlap11g_protection + \brief wrapper function for setting overlap 11g protection. + \param tpAniSirGlobal pMac + \param tpUpdateBeaconParams pBeaconParams + \param tpSirMacMgmtHdr pMh + \return None + -------------------------------------------------------------*/ +void +lim_enable_overlap11g_protection(tpAniSirGlobal pMac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, tpPESession psessionEntry) +{ + lim_update_overlap_sta_param(pMac, pMh->bssId, + &(psessionEntry->gLimOlbcParams)); + + if (psessionEntry->gLimOlbcParams.numSta && + !psessionEntry->gLimOlbcParams.protectionEnabled) { + /* enable protection */ + pe_debug("OLBC happens!!!"); + lim_enable11g_protection(pMac, true, true, pBeaconParams, + psessionEntry); + } +} + +/** + * 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 tpPESession + * + * Function Updates short preamble if needed when a new station joins + * + * Return: none + */ +void +lim_update_short_preamble(tpAniSirGlobal mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beaconparams, + tpPESession 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 == NULL || 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"); + + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGD); + + 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) { +#ifdef WLAN_DEBUG + tLimNoShortParams *lim_params = + &psession_entry->gLimNoShortParams; +#endif + if (LIM_IS_AP_ROLE(psession_entry)) { + pe_err("No space in Short cache active: %d sta: %d for sta", + i, lim_params->numNonShortPreambleSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } else { + pe_err("No space in Short cache active: %d sta: %d for sta", + i, lim_params->numNonShortPreambleSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + 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 tpPESession + * + * Function Updates short slot time if needed when a new station joins + * + * Return: None + */ +void +lim_update_short_slot_time(tpAniSirGlobal mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beacon_params, + tpPESession 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 == NULL || 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"); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGD); + 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", + i, session_entry->gLimNoShortSlotParams. + numNonShortSlotSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } else { + pe_err("No space in ShortSlot cache active: %d sta: %d for sta", + i, mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + 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++; + } + wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val); + /* + * 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 tpAniSirGlobal pMac + \param tpSchBeaconStruct pBeaconStruct + \return None + -------------------------------------------------------------*/ +void +lim_decide_sta_protection_on_assoc(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpPESession psessionEntry) +{ + enum band_info rfBand = BAND_UNKNOWN; + uint32_t phyMode = WNI_CFG_PHY_MODE_NONE; + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + if (BAND_5G == rfBand) { + if ((eSIR_HT_OP_MODE_MIXED == pBeaconStruct->HTInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + pBeaconStruct->HTInfo.opMode)) { + if (pMac->lim.cfgProtection.fromlla) + psessionEntry->beaconParams.llaCoexist = true; + } else if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + pBeaconStruct->HTInfo.opMode) { + if (pMac->lim.cfgProtection.ht20) + psessionEntry->beaconParams.ht20Coexist = true; + } + + } else if (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 (pMac->lim.cfgProtection.fromllb && + pBeaconStruct->erpPresent && + (pBeaconStruct->erpIEInfo.useProtection || + pBeaconStruct->erpIEInfo.nonErpPresent)) { + psessionEntry->beaconParams.llbCoexist = true; + } + /* AP has no 11b station associated. */ + else { + psessionEntry->beaconParams.llbCoexist = false; + } + } + /* following code block is only for HT station. */ + if ((psessionEntry->htCapability) && + (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + + /* Obss Non HT STA present mode */ + psessionEntry->beaconParams.gHTObssMode = + (uint8_t) htInfo.obssNonHTStaPresent; + + /* CFG protection from 11G is enabled and */ + /* our AP has at least one 11G station associated. */ + if (pMac->lim.cfgProtection.fromllg && + ((eSIR_HT_OP_MODE_MIXED == htInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == htInfo.opMode)) + && (!psessionEntry->beaconParams.llbCoexist)) { + if (pMac->lim.cfgProtection.fromllg) + psessionEntry->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. */ + psessionEntry->beaconParams.llgCoexist = false; + /* CFG protection from HT 20 is enabled. */ + if (pMac->lim.cfgProtection.ht20) + psessionEntry->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) { + psessionEntry->beaconParams.llgCoexist = false; + psessionEntry->beaconParams.ht20Coexist = false; + } + + } + } + /* protection related factors other than HT operating mode. Applies to 2.4 GHZ as well as 5 GHZ. */ + if ((psessionEntry->htCapability) && (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + + psessionEntry->beaconParams.fRIFSMode = + (uint8_t) htInfo.rifsMode; + psessionEntry->beaconParams.llnNonGFCoexist = + (uint8_t) htInfo.nonGFDevicesPresent; + psessionEntry->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(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + tpPESession 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(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + tpPESession psession_entry) +{ + + enum band_info rfband = 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 ((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 (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 pMac - Pointer to Global MAC structure + * @return None + */ +void lim_process_channel_switch_timeout(tpAniSirGlobal pMac) +{ + tpPESession psessionEntry = NULL; + uint8_t channel; /* This is received and stored from channelSwitch Action frame */ + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) { + pe_warn("Channel switch can be done only in STA role, Current Role: %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + return; + } + + if (psessionEntry->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) { + pe_warn("Channel switch timer should not have been running in state: %d", + psessionEntry->gLimSpecMgmt.dot11hChanSwState); + return; + } + + channel = psessionEntry->gLimChannelSwitch.primaryChannel; + /* Restore Channel Switch parameters to default */ + psessionEntry->gLimChannelSwitch.switchTimeoutValue = 0; + + /* Channel-switch timeout has occurred. reset the state */ + psessionEntry->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(pMac, channel)) { + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + QDF_STATUS_SUCCESS) { + pe_err("Could not restore pre-channelSwitch (11h) state, resetting the system"); + return; + } + + /* + * If the channel-list that AP is asking us to switch is invalid + * then we cannot switch the channel. Just disassociate from AP. + * We will find a better AP !!! + */ + if ((psessionEntry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + pe_err("Invalid channel! Disconnect"); + lim_tear_down_link_with_ap(pMac, + pMac->lim.limTimers. + gLimChannelSwitchTimer.sessionId, + eSIR_MAC_UNSPEC_FAILURE_REASON); + return; + } + } + switch (psessionEntry->gLimChannelSwitch.state) { + case eLIM_CHANNEL_SWITCH_PRIMARY_ONLY: + pe_warn("CHANNEL_SWITCH_PRIMARY_ONLY"); + lim_switch_primary_channel(pMac, + psessionEntry->gLimChannelSwitch. + primaryChannel, psessionEntry); + psessionEntry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_IDLE; + break; + case eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY: + pe_warn("CHANNEL_SWITCH_PRIMARY_AND_SECONDARY"); + lim_switch_primary_secondary_channel(pMac, psessionEntry, + psessionEntry->gLimChannelSwitch.primaryChannel, + psessionEntry->gLimChannelSwitch.ch_center_freq_seg0, + psessionEntry->gLimChannelSwitch.ch_center_freq_seg1, + psessionEntry->gLimChannelSwitch.ch_width); + psessionEntry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_IDLE; + break; + + case eLIM_CHANNEL_SWITCH_IDLE: + default: + pe_err("incorrect state"); + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + QDF_STATUS_SUCCESS) { + pe_err("Could not restore pre-channelSwitch (11h) state, resetting the system"); + } + return; /* Please note, this is 'return' and not 'break' */ + } +} + +/** + * lim_update_channel_switch() - This Function updates channel switch + * @mac_ctx: pointer to Global MAC structure + * @beacon: pointer to tpSirProbeRespBeacon + * @psessionentry: pointer to tpPESession + * + * This function is invoked whenever Station receives + * either 802.11h channel switch IE or airgo proprietary + * channel switch IE. + * + * Return: none + */ +void +lim_update_channel_switch(struct sAniSirGlobal *mac_ctx, + tpSirProbeRespBeacon beacon, + tpPESession psession_entry) +{ + uint16_t beacon_period; + tDot11fIEChanSwitchAnn *chnl_switch; + tLimChannelSwitchInfo *ch_switch_params; + tDot11fIEWiderBWChanSwitchAnn *widerchnl_switch; + + beacon_period = psession_entry->beaconParams.beaconInterval; + + /* 802.11h standard channel switch IE */ + chnl_switch = &(beacon->channelSwitchIE); + ch_switch_params = &psession_entry->gLimChannelSwitch; + ch_switch_params->primaryChannel = + chnl_switch->newChannel; + ch_switch_params->switchCount = chnl_switch->switchCount; + ch_switch_params->switchTimeoutValue = + SYS_MS_TO_TICKS(beacon_period) * (chnl_switch->switchCount); + ch_switch_params->switchMode = chnl_switch->switchMode; + widerchnl_switch = &(beacon->WiderBWChanSwitchAnn); + if (beacon->WiderBWChanSwitchAnnPresent) { + psession_entry->gLimWiderBWChannelSwitch.newChanWidth = + widerchnl_switch->newChanWidth; + psession_entry->gLimWiderBWChannelSwitch.newCenterChanFreq0 = + widerchnl_switch->newCenterChanFreq0; + psession_entry->gLimWiderBWChannelSwitch.newCenterChanFreq1 = + widerchnl_switch->newCenterChanFreq1; + } + /* Only primary channel switch element is present */ + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + ch_switch_params->ch_width = CH_WIDTH_20MHZ; + + /* + * Do not bother to look and operate on extended channel switch element + * if our own channel-bonding state is not enabled + */ + if (psession_entry->htSupportedChannelWidthSet && + beacon->sec_chan_offset_present) { + if (beacon->sec_chan_offset.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel + 2; + } else if (beacon->sec_chan_offset.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel - 2; + } + if (psession_entry->vhtCapability && + beacon->WiderBWChanSwitchAnnPresent) { + ch_switch_params->ch_width = + widerchnl_switch->newChanWidth + 1; + ch_switch_params->ch_center_freq_seg0 = + psession_entry->gLimWiderBWChannelSwitch. + newCenterChanFreq0; + ch_switch_params->ch_center_freq_seg1 = + psession_entry->gLimWiderBWChannelSwitch. + newCenterChanFreq1; + } + } + if (QDF_STATUS_SUCCESS != lim_start_channel_switch(mac_ctx, psession_entry)) + pe_warn("Could not start Channel Switch"); + + pe_debug("session: %d primary chl: %d ch_width: %d count: %d (%d ticks)", + psession_entry->peSessionId, + psession_entry->gLimChannelSwitch.primaryChannel, + psession_entry->gLimChannelSwitch.ch_width, + psession_entry->gLimChannelSwitch.switchCount, + psession_entry->gLimChannelSwitch.switchTimeoutValue); + return; +} + +/** + * lim_cancel_dot11h_channel_switch + * + ***FUNCTION: + * This function is called when STA does not send updated channel-swith IE + * after indicating channel-switch start. This will cancel the channel-swith + * timer which is already running. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * + * @return None + */ +void lim_cancel_dot11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + pe_debug("Received a beacon without channel switch IE"); + + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_CHANNEL_SWITCH_TIMER)); + + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + QDF_STATUS_SUCCESS) { + pe_err("tx_timer_deactivate failed!"); + } + + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + QDF_STATUS_SUCCESS) { + pe_err("LIM: Could not restore pre-channelSwitch (11h) state, resetting the system"); + } +} + +/** + * lim_cancel_dot11h_quiet() + * + * @mac_ctx: pointer to global mac structure + * @psession_entry: pointer to tppesession + * + * Cancel the quieting on Station if latest beacon + * doesn't contain quiet IE in it. + * + * Return: none + */ +void lim_cancel_dot11h_quiet(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_BEGIN) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer) != + TX_SUCCESS) { + pe_err("tx_timer_deactivate failed"); + } + } else if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_BSS_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietBssTimer) + != TX_SUCCESS) { + pe_err("tx_timer_deactivate failed"); + } + /** + * If the channel switch is already running in silent mode, dont resume the + * transmission. Channel switch timer when timeout, transmission will be resumed. + */ + if (! + ((psessionEntry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) + && (psessionEntry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT))) { + lim_frame_transmission_control(pMac, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(pMac, psessionEntry); + } + } + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; +} + +/** + * lim_process_quiet_timeout + * + * FUNCTION: + * This function is active only on the STA. + * Handles SIR_LIM_QUIET_TIMEOUT + * + * LOGIC: + * This timeout can occur under only one circumstance: + * + * 1) When gLimQuietState = eLIM_QUIET_BEGIN + * This indicates that the timeout "interval" has + * expired. This is a trigger for the STA to now + * shut-off Tx/Rx for the specified gLimQuietDuration + * -> The TIMER object gLimQuietBssTimer is + * activated + * -> With timeout = gLimQuietDuration + * -> gLimQuietState is set to eLIM_QUIET_RUNNING + * + * ASSUMPTIONS: + * Using two TIMER objects - + * gLimQuietTimer & gLimQuietBssTimer + * + * NOTE: + * + * @param pMac - Pointer to Global MAC structure + * + * @return None + */ +void lim_process_quiet_timeout(tpAniSirGlobal pMac) +{ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimQuietTimer.sessionId); + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + pe_debug("quietState: %d", psessionEntry->gLimSpecMgmt.quietState); + switch (psessionEntry->gLimSpecMgmt.quietState) { + case eLIM_QUIET_BEGIN: + /* Time to Stop data traffic for quietDuration */ + /* lim_deactivate_and_change_timer(pMac, eLIM_QUIET_BSS_TIMER); */ + if (TX_SUCCESS != tx_timer_deactivate( + &pMac->lim.limTimers.gLimQuietBssTimer)) { + pe_err("Unable to de-activate gLimQuietBssTimer! Will attempt to activate anyway"); + } + /* gLimQuietDuration appears to be in units of ticks */ + /* Use it as is */ + if (TX_SUCCESS != + tx_timer_change(&pMac->lim.limTimers.gLimQuietBssTimer, + psessionEntry->gLimSpecMgmt.quietDuration, + 0)) { + pe_err("Unable to change gLimQuietBssTimer! Will still attempt to activate anyway"); + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, + pMac->lim.limTimers.gLimQuietTimer.sessionId, + eLIM_QUIET_BSS_TIMER)); + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimQuietBssTimer)) { + pe_warn("Unable to activate gLimQuietBssTimer! The STA will be unable to honor Quiet BSS"); + } else { + /* Transition to eLIM_QUIET_RUNNING */ + psessionEntry->gLimSpecMgmt.quietState = + eLIM_QUIET_RUNNING; + /* Shut-off Tx/Rx for gLimSpecMgmt.quietDuration */ + /* freeze the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, + eLIM_STOP_TX); + + pe_debug("Quiet BSS: STA shutting down for %d ticks", + psessionEntry->gLimSpecMgmt.quietDuration); + } + break; + + case eLIM_QUIET_RUNNING: + case eLIM_QUIET_INIT: + case eLIM_QUIET_END: + default: + /* */ + /* As of now, nothing to be done */ + /* */ + break; + } +} + +/** + * lim_process_quiet_bss_timeout() - Handles SIR_LIM_QUIET_BSS_TIMEOUT + * @mac_ctx: pointer to Globale Mac Structure + * + * This function is active on the AP and STA. + * Handles SIR_LIM_QUIET_BSS_TIMEOUT + * + * On the AP - + * When the SIR_LIM_QUIET_BSS_TIMEOUT is triggered, it is + * an indication for the AP to START sending out the + * Quiet BSS IE. + * If 802.11H is enabled, the Quiet BSS IE is sent as per + * the 11H spec + * If 802.11H is not enabled, the Quiet BSS IE is sent as + * a Proprietary IE. This will be understood by all the + * TITAN STA's + * Transitioning gLimQuietState to eLIM_QUIET_BEGIN will + * initiate the SCH to include the Quiet BSS IE in all + * its subsequent Beacons/PR's. + * The Quiet BSS IE will be included in all the Beacons + * & PR's until the next DTIM period + * + * On the STA - + * When gLimQuietState = eLIM_QUIET_RUNNING + * This indicates that the STA was successfully shut-off + * for the specified gLimQuietDuration. This is a trigger + * for the STA to now resume data traffic. + * -> gLimQuietState is set to eLIM_QUIET_INIT + * + * + * Return: none + */ +void lim_process_quiet_bss_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession psession_entry = NULL; + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + + psession_entry = pe_find_session_by_session_id(mac_ctx, + lim_timer->gLimQuietBssTimer.sessionId); + + if (psession_entry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + pe_debug("quietState: %d", + psession_entry->gLimSpecMgmt.quietState); + + if (LIM_IS_AP_ROLE(psession_entry)) + return; + + /* eLIM_STA_ROLE */ + switch (psession_entry->gLimSpecMgmt.quietState) { + case eLIM_QUIET_RUNNING: + /* Transition to eLIM_QUIET_INIT */ + psession_entry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* + * Resume data traffic only if channel switch is + * not running in silent mode. + */ + if (!((psession_entry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) && + (psession_entry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT))) { + lim_frame_transmission_control(mac_ctx, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(mac_ctx, psession_entry); + } + pe_debug("Quiet BSS: Resuming traffic"); + break; + + case eLIM_QUIET_INIT: + case eLIM_QUIET_BEGIN: + case eLIM_QUIET_END: + pe_debug("Quiet state not in RUNNING"); + /* + * If the quiet period has ended, then resume the + * frame transmission + */ + lim_frame_transmission_control(mac_ctx, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(mac_ctx, psession_entry); + psession_entry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + break; + + default: + /* As of now, nothing to be done */ + break; + } +} + +/**---------------------------------------------- + \fn lim_start_quiet_timer + \brief Starts the quiet timer. + + \param pMac + \return NONE + -----------------------------------------------*/ +void lim_start_quiet_timer(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + + if (psessionEntry == NULL) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + /* First, de-activate Timer, if its already active */ + lim_cancel_dot11h_quiet(pMac, psessionEntry); + + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, sessionId, eLIM_QUIET_TIMER)); + if (TX_SUCCESS != + tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer)) { + pe_err("Unable to deactivate gLimQuietTimer! Will still attempt to re-activate anyway"); + } + /* Set the NEW timeout value, in ticks */ + if (TX_SUCCESS != tx_timer_change(&pMac->lim.limTimers.gLimQuietTimer, + SYS_MS_TO_TICKS(psessionEntry-> + gLimSpecMgmt. + quietTimeoutValue), + 0)) { + pe_err("Unable to change gLimQuietTimer! Will still attempt to re-activate anyway"); + } + + pMac->lim.limTimers.gLimQuietTimer.sessionId = sessionId; + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimQuietTimer)) { + pe_err("Unable to activate gLimQuietTimer! STA cannot honor Quiet BSS!"); + lim_restore_pre_quiet_state(pMac, psessionEntry); + + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + return; + } +} + +/** ------------------------------------------------------------------------ **/ +/** + * 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(tpAniSirGlobal pMac, + tpDphHashNode pSta, tpPESession psessionEntry) +{ + + if ((!pSta) || (!pSta->valid) || (pSta->fAniCount)) + return; + + pSta->fAniCount = 1; + + if (pMac->lim.gLimNumOfAniSTAs++ != 0) + return; + + /* get here only if this is the first ANI peer in the BSS */ + sch_edca_profile_update(pMac, psessionEntry); +} + +void +lim_util_count_sta_del(tpAniSirGlobal pMac, + tpDphHashNode pSta, tpPESession psessionEntry) +{ + + if ((pSta == NULL) || (!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 (pMac->lim.gLimNumOfAniSTAs <= 0) { + pe_err("CountStaDel: ignoring Delete Req when AniPeer count: %d", + pMac->lim.gLimNumOfAniSTAs); + return; + } + + pMac->lim.gLimNumOfAniSTAs--; + + if (pMac->lim.gLimNumOfAniSTAs != 0) + return; + + /* get here only if this is the last ANI peer in the BSS */ + sch_edca_profile_update(pMac, psessionEntry); +} + +/** + * 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 pMac Pointer to Global MAC structure + * @param status Status of channel switch request + * @param data User data + * @param psessionEntry Session information + * @return NONE + */ +void lim_switch_channel_cback(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + struct scheduler_msg mmhMsg = { 0 }; + tSirSmeSwitchChannelInd *pSirSmeSwitchChInd; + + psessionEntry->currentOperChannel = psessionEntry->currentReqChannel; + + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + 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(tSirSmeSwitchChannelInd)); + if (NULL == pSirSmeSwitchChInd) { + pe_err("Failed to allocate buffer for buffer descriptor"); + return; + } + + pSirSmeSwitchChInd->messageType = eWNI_SME_SWITCH_CHL_IND; + pSirSmeSwitchChInd->length = sizeof(tSirSmeSwitchChannelInd); + pSirSmeSwitchChInd->newChannelId = + psessionEntry->gLimChannelSwitch.primaryChannel; + pSirSmeSwitchChInd->sessionId = psessionEntry->smeSessionId; + pSirSmeSwitchChInd->chan_params.ch_width = + psessionEntry->gLimChannelSwitch.ch_width; + pSirSmeSwitchChInd->chan_params.sec_ch_offset = + psessionEntry->gLimChannelSwitch.sec_ch_offset; + pSirSmeSwitchChInd->chan_params.center_freq_seg0 = + psessionEntry->gLimChannelSwitch.ch_center_freq_seg0; + pSirSmeSwitchChInd->chan_params.center_freq_seg1 = + psessionEntry->gLimChannelSwitch.ch_center_freq_seg1; + + pe_debug("session: %d chan: %d width: %d sec offset: %d seg0: %d seg1: %d", + pSirSmeSwitchChInd->sessionId, + pSirSmeSwitchChInd->newChannelId, + pSirSmeSwitchChInd->chan_params.ch_width, + pSirSmeSwitchChInd->chan_params.sec_ch_offset, + pSirSmeSwitchChInd->chan_params.center_freq_seg0, + pSirSmeSwitchChInd->chan_params.center_freq_seg1); + + qdf_mem_copy(pSirSmeSwitchChInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + mmhMsg.bodyptr = pSirSmeSwitchChInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + + sys_process_mmh_msg(pMac, &mmhMsg); +} + +/** + * lim_switch_primary_channel() + * + ***FUNCTION: + * This function changes the current operating channel + * and sets the new new channel ID in WNI_CFG_CURRENT_CHANNEL. + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param newChannel new chnannel ID + * @return NONE + */ +void lim_switch_primary_channel(tpAniSirGlobal pMac, uint8_t newChannel, + tpPESession psessionEntry) +{ + pe_debug("old chnl: %d --> new chnl: %d", + psessionEntry->currentOperChannel, newChannel); + + psessionEntry->currentReqChannel = newChannel; + psessionEntry->limRFBand = lim_get_rf_band(newChannel); + + psessionEntry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + + pMac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + pMac->lim.gpchangeChannelData = NULL; + + lim_send_switch_chnl_params(pMac, newChannel, 0, 0, CH_WIDTH_20MHZ, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, false, 0, 0); + return; +} + +/** + * lim_switch_primary_secondary_channel() + * + ***FUNCTION: + * This function changes the primary and secondary channel. + * If 11h is enabled and user provides a "new channel ID" + * that is different from the current operating channel, + * then we must set this new channel in WNI_CFG_CURRENT_CHANNEL, + * assign notify LIM of such change. + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param newChannel New chnannel ID (or current channel ID) + * @param subband CB secondary info: + * - eANI_CB_SECONDARY_NONE + * - eANI_CB_SECONDARY_UP + * - eANI_CB_SECONDARY_DOWN + * @return NONE + */ +void lim_switch_primary_secondary_channel(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t newChannel, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width) +{ + + /* Assign the callback to resume TX once channel is changed. */ + psessionEntry->currentReqChannel = newChannel; + psessionEntry->limRFBand = lim_get_rf_band(newChannel); + psessionEntry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + pMac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + pMac->lim.gpchangeChannelData = NULL; + + lim_send_switch_chnl_params(pMac, newChannel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, + false, 0, 0); + + /* Store the new primary and secondary channel in session entries if different */ + if (psessionEntry->currentOperChannel != newChannel) { + pe_warn("switch old chnl: %d --> new chnl: %d", + psessionEntry->currentOperChannel, newChannel); + psessionEntry->currentOperChannel = newChannel; + } + if (psessionEntry->htSecondaryChannelOffset != + psessionEntry->gLimChannelSwitch.sec_ch_offset) { + pe_warn("switch old sec chnl: %d --> new sec chnl: %d", + psessionEntry->htSecondaryChannelOffset, + psessionEntry->gLimChannelSwitch.sec_ch_offset); + psessionEntry->htSecondaryChannelOffset = + psessionEntry->gLimChannelSwitch.sec_ch_offset; + if (psessionEntry->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) { + psessionEntry->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + } else { + psessionEntry->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + } + psessionEntry->htRecommendedTxWidthSet = + psessionEntry->htSupportedChannelWidthSet; + } + + return; +} + +/** + * 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 pMac 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(tpAniSirGlobal pMac, + uint32_t htCap, tpPESession psessionEntry) +{ + uint8_t retVal = 0; + uint8_t *ptr; + uint32_t cfgValue; + tSirMacHTCapabilityInfo macHTCapabilityInfo = { 0 }; + tSirMacExtendedHTCapabilityInfo macExtHTCapabilityInfo = { 0 }; + tSirMacTxBFCapabilityInfo macTxBFCapabilityInfo = { 0 }; + tSirMacASCapabilityInfo macASCapabilityInfo = { 0 }; + + /* */ + /* 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 Seletion HT Capabilities */ + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_AS_CAP, &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macASCapabilityInfo; + *((uint8_t *) ptr) = (uint8_t) (cfgValue & 0xff); + } else { + if (htCap >= eHT_TX_BEAMFORMING && + htCap < eHT_ANTENNA_SELECTION) { + /* Get Transmit Beam Forming HT Capabilities */ + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TX_BF_CAP, &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macTxBFCapabilityInfo; + *((uint32_t *) ptr) = (uint32_t) (cfgValue); + } else { + if (htCap >= eHT_PCO && htCap < eHT_TX_BEAMFORMING) { + /* Get Extended HT Capabilities */ + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, + WNI_CFG_EXT_HT_CAP_INFO, + &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macExtHTCapabilityInfo; + *((uint16_t *) ptr) = + (uint16_t) (cfgValue & 0xffff); + } else { + if (htCap < eHT_MAX_RX_AMPDU_FACTOR) { + /* Get HT Capabilities */ + if (QDF_STATUS_SUCCESS != + wlan_cfg_get_int(pMac, + WNI_CFG_HT_CAP_INFO, + &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macHTCapabilityInfo; + /* CR 265282 MDM SoftAP 2.4PL: SoftAP boot up crash in 2.4 PL builds while same WLAN SU is working on 2.1 PL */ + *ptr++ = cfgValue & 0xff; + *ptr = (cfgValue >> 8) & 0xff; + } + } + } + } + + switch (htCap) { + case eHT_LSIG_TXOP_PROTECTION: + retVal = pMac->lim.gHTLsigTXOPProtection; + break; + + case eHT_STBC_CONTROL_FRAME: + retVal = (uint8_t) macHTCapabilityInfo.stbcControlFrame; + break; + + case eHT_PSMP: + retVal = pMac->lim.gHTPSMPSupport; + break; + + case eHT_DSSS_CCK_MODE_40MHZ: + retVal = pMac->lim.gHTDsssCckRate40MHzSupport; + break; + + case eHT_MAX_AMSDU_LENGTH: + retVal = (uint8_t) macHTCapabilityInfo.maximalAMSDUsize; + break; + + case eHT_MAX_AMSDU_NUM: + retVal = (uint8_t) psessionEntry->max_amsdu_num; + break; + + case eHT_RX_STBC: + retVal = (uint8_t) psessionEntry->htConfig.ht_rx_stbc; + break; + + case eHT_TX_STBC: + retVal = (uint8_t) psessionEntry->htConfig.ht_tx_stbc; + break; + + case eHT_SHORT_GI_40MHZ: + retVal = (uint8_t) (psessionEntry->htConfig.ht_sgi40) ? + macHTCapabilityInfo.shortGI40MHz : 0; + break; + + case eHT_SHORT_GI_20MHZ: + retVal = (uint8_t) (psessionEntry->htConfig.ht_sgi20) ? + macHTCapabilityInfo.shortGI20MHz : 0; + break; + + case eHT_GREENFIELD: + retVal = (uint8_t) macHTCapabilityInfo.greenField; + break; + + case eHT_MIMO_POWER_SAVE: + retVal = (uint8_t) pMac->lim.gHTMIMOPSState; + break; + + case eHT_SUPPORTED_CHANNEL_WIDTH_SET: + retVal = (uint8_t) psessionEntry->htSupportedChannelWidthSet; + break; + + case eHT_ADVANCED_CODING: + retVal = (uint8_t) psessionEntry->htConfig.ht_rx_ldpc; + break; + + case eHT_MAX_RX_AMPDU_FACTOR: + retVal = pMac->lim.gHTMaxRxAMpduFactor; + break; + + case eHT_MPDU_DENSITY: + retVal = pMac->lim.gHTAMpduDensity; + break; + + case eHT_PCO: + retVal = (uint8_t) macExtHTCapabilityInfo.pco; + break; + + case eHT_TRANSITION_TIME: + retVal = (uint8_t) macExtHTCapabilityInfo.transitionTime; + break; + + case eHT_MCS_FEEDBACK: + retVal = (uint8_t) macExtHTCapabilityInfo.mcsFeedback; + 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 = pMac->lim.gHTServiceIntervalGranularity; + break; + + case eHT_CONTROLLED_ACCESS: + retVal = pMac->lim.gHTControlledAccessOnly; + break; + + case eHT_RIFS_MODE: + retVal = psessionEntry->beaconParams.fRIFSMode; + break; + + case eHT_RECOMMENDED_TX_WIDTH_SET: + retVal = psessionEntry->htRecommendedTxWidthSet; + break; + + case eHT_EXTENSION_CHANNEL_OFFSET: + retVal = psessionEntry->htSecondaryChannelOffset; + break; + + case eHT_OP_MODE: + if (LIM_IS_AP_ROLE(psessionEntry)) + retVal = psessionEntry->htOperMode; + else + retVal = pMac->lim.gHTOperMode; + break; + + case eHT_BASIC_STBC_MCS: + retVal = pMac->lim.gHTSTBCBasicMCS; + break; + + case eHT_DUAL_CTS_PROTECTION: + retVal = pMac->lim.gHTDualCTSProtection; + break; + + case eHT_LSIG_TXOP_PROTECTION_FULL_SUPPORT: + retVal = + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport; + break; + + case eHT_PCO_ACTIVE: + retVal = pMac->lim.gHTPCOActive; + break; + + case eHT_PCO_PHASE: + retVal = pMac->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(tpAniSirGlobal mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + tpPESession 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(tpAniSirGlobal mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + tpPESession 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(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams bcn_prms, + tpPESession session) +{ + if (NULL == 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 tpPESession + * + * Function handles 11g protection enaled case + * + * Return: none + */ +static void +lim_handle_enable11g_protection_enabled(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, tpPESession 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 tpPESession + * + * Function handles 11g protection for 11b co-exist + * + * Return: none + */ +static void +lim_handle_11g_protection_for_11bcoexist(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, tpPESession 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 tpPESession + * + * based on config setting enables\disables 11g protection. + * + * Return: Success - QDF_STATUS_SUCCESS - Success, Error number - Failure + */ +QDF_STATUS +lim_enable11g_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession 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(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return QDF_STATUS_SUCCESS; /* protection from 11g is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + if ((LIM_IS_AP_ROLE(psessionEntry)) + && (!psessionEntry->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(psessionEntry) && + !psessionEntry->cfgProtection.fromllg) { + /* protection disabled. */ + pe_debug("protection from 11g is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + if (!pMac->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(psessionEntry)) { + if (overlap) { + psessionEntry->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 != + psessionEntry->htOperMode) + && (eSIR_HT_OP_MODE_MIXED != + psessionEntry->htOperMode)) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + lim_enable_ht_rifs_protection(pMac, true, overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, true, overlap, + pBeaconParams, + psessionEntry); + } else { + /* 11g is associated to an AP operating in 11n mode. */ + /* Change the HT operating mode to 'mixed mode'. */ + psessionEntry->gLim11gParams.protectionEnabled = + true; + if (eSIR_HT_OP_MODE_MIXED != + psessionEntry->htOperMode) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + } + } + } + /* This part is common for staiton as well. */ + if (false == psessionEntry->beaconParams.llgCoexist) { + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } else if (true == + psessionEntry->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 */ + /* pMac->sch.schObject.fBeaconChanged = 1; */ + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } else if (true == psessionEntry->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(psessionEntry)) { + if (overlap) { + /* Overlap Legacy protection disabled. */ + if (psessionEntry->gLim11gParams.numSta == 0) + psessionEntry->gLimOverlap11gParams. + protectionEnabled = false; + + /* no HT op mode change if any of the overlap protection enabled. */ + if (! + (psessionEntry->gLimOlbcParams. + protectionEnabled + || psessionEntry->gLimOverlapHt20Params. + protectionEnabled + || psessionEntry->gLimOverlapNonGfParams. + protectionEnabled)) { + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + psessionEntry->htOperMode) { + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + + if (psessionEntry->gLimHt20Params.protectionEnabled) { + if (eHT_CHANNEL_WIDTH_20MHZ == + psessionEntry->htSupportedChannelWidthSet) + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + } else + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else { + /* Disable protection from 11G stations. */ + psessionEntry->gLim11gParams.protectionEnabled = + false; + /* Check if any other non-HT protection enabled. */ + if (!psessionEntry->gLim11bParams. + protectionEnabled) { + + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(pMac, false, + overlap, + pBeaconParams, + psessionEntry); + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (psessionEntry->gLimOlbcParams. + protectionEnabled + || psessionEntry-> + gLimOverlap11gParams. + protectionEnabled + || psessionEntry-> + gLimOverlapHt20Params. + protectionEnabled + || psessionEntry-> + gLimOverlapNonGfParams. + protectionEnabled) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(pMac, + true, + overlap, + pBeaconParams, + psessionEntry); + } else if (psessionEntry-> + gLimHt20Params. + protectionEnabled) { + /* Commenting because of CR 258588 WFA cert */ + /* psessionEntry->htOperMode = eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; */ + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } else { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } + } + } + if (!psessionEntry->gLimOverlap11gParams. + protectionEnabled + && !psessionEntry->gLim11gParams. + protectionEnabled) { + pe_debug("===> Protection from 11G Disabled"); + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = + false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } + /* for station role */ + else { + pe_debug("===> Protection from 11G Disabled"); + pBeaconParams->llgCoexist = + psessionEntry->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(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + if (!psessionEntry->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(psessionEntry)) && + !psessionEntry->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(psessionEntry)) { + if (!pMac->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(psessionEntry)) { + if ((enable) + && (false == psessionEntry->beaconParams.gHTObssMode)) { + pe_debug("=>obss protection enabled"); + psessionEntry->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + psessionEntry->beaconParams.gHTObssMode)) { + pe_debug("===> obss Protection disabled"); + psessionEntry->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) { + psessionEntry->gLimOverlap11gParams.protectionEnabled = + false; + } + } else { + if ((enable) + && (false == psessionEntry->beaconParams.gHTObssMode)) { + pe_debug("=>obss protection enabled"); + psessionEntry->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + psessionEntry->beaconParams.gHTObssMode)) { + pe_debug("===> obss Protection disabled"); + psessionEntry->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 tpPESession + * + * Function handles ht20 protection enabled + * + * Return: none + */ +static void lim_handle_ht20protection_enabled(tpAniSirGlobal mac_ctx, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession 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 tpPESession + * @overlap: variable for overlap detection + * + * Function handles ht20 protection for ht20 coexist + * + * Return: none + */ +static void lim_handle_ht20coexist_ht20protection(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + tpPESession 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 tpPESession + * + * based on cofig enables\disables protection from Ht20 + * + * Return: 0 - success + */ +QDF_STATUS lim_enable_ht20_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession 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(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->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(psessionEntry) && + !psessionEntry->cfgProtection.nonGf) { + /* protection disabled. */ + pe_debug("protection from NonGf is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.nonGf) { + /* protection disabled. */ + pe_debug("protection from NonGf is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == psessionEntry->beaconParams.llnNonGFCoexist)) { + pe_debug(" => Protection from non GF Enabled"); + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams.llnNonGFCoexist)) { + pe_debug("===> Protection from Non GF Disabled"); + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + } else { + if ((enable) + && (false == psessionEntry->beaconParams.llnNonGFCoexist)) { + pe_debug(" => Protection from non GF Enabled"); + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams.llnNonGFCoexist)) { + pe_debug("===> Protection from Non GF Disabled"); + pBeaconParams->llnNonGFCoexist = + psessionEntry->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(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->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(psessionEntry) && + !psessionEntry->cfgProtection.lsigTxop) { + /* protection disabled. */ + pe_debug("protection from LsigTxop not supported is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.lsigTxop) { + /* protection disabled. */ + pe_debug("protection from LsigTxop not supported is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug(" => Protection from LsigTxop Enabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug("===> Protection from LsigTxop Disabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = false; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + } else { + if ((enable) + && (false == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug(" => Protection from LsigTxop Enabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug("===> Protection from LsigTxop Disabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->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(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->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(psessionEntry) && + !psessionEntry->cfgProtection.rifs) { + /* protection disabled. */ + pe_debug("protection from Rifs is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.rifs) { + /* protection disabled. */ + pe_debug("protection from Rifs is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + /* Disabling the RIFS Protection means Enable the RIFS mode of operation in the BSS */ + if ((!enable) + && (false == psessionEntry->beaconParams.fRIFSMode)) { + pe_debug(" => Rifs protection Disabled"); + pBeaconParams->fRIFSMode = + psessionEntry->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 == psessionEntry->beaconParams.fRIFSMode)) { + pe_debug("===> Rifs Protection Enabled"); + pBeaconParams->fRIFSMode = + psessionEntry->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 == psessionEntry->beaconParams.fRIFSMode)) { + pe_debug(" => Rifs protection Disabled"); + pBeaconParams->fRIFSMode = + psessionEntry->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 == psessionEntry->beaconParams.fRIFSMode)) { + pe_debug("===> Rifs Protection Enabled"); + pBeaconParams->fRIFSMode = + psessionEntry->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(tpAniSirGlobal pMac, uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + uint32_t val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != QDF_STATUS_SUCCESS) { + /* Could not get short preamble enabled flag from CFG. Log error. */ + pe_err("could not retrieve short preamble flag"); + return QDF_STATUS_E_FAILURE; + } + + if (!val) + return QDF_STATUS_SUCCESS; + + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve 11G short preamble switching enabled flag"); + return QDF_STATUS_E_FAILURE; + } + + if (!val) /* 11G short preamble switching is disabled. */ + return QDF_STATUS_SUCCESS; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if (enable && (psessionEntry->beaconParams.fShortPreamble == 0)) { + pe_debug("===> Short Preamble Enabled"); + psessionEntry->beaconParams.fShortPreamble = true; + pBeaconParams->fShortPreamble = + (uint8_t) psessionEntry->beaconParams. + fShortPreamble; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_PREAMBLE_CHANGED; + } else if (!enable + && (psessionEntry->beaconParams.fShortPreamble == + 1)) { + pe_debug("===> Short Preamble Disabled"); + psessionEntry->beaconParams.fShortPreamble = false; + pBeaconParams->fShortPreamble = + (uint8_t) psessionEntry->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; +} + +/** + * \brief This function updates lim global structure, if CB parameters in the BSS + * have changed, and sends an indication to HAL also with the + * updated HT Parameters. + * This function does not detect the change in the primary channel, that is done as part + * of channel Swtich IE processing. + * If STA is configured with '20Mhz only' mode, then this function does not do anything + * This function changes the CB mode, only if the self capability is set to '20 as well as 40Mhz' + * + * + * \param pMac Pointer to global MAC structure + * + * \param pRcvdHTInfo Pointer to HT Info IE obtained from a Beacon or + * Probe Response + * + * \param bssIdx BSS Index of the Bss to which Station is associated. + * + * + */ + +void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + uint8_t bssIdx, + tpPESession psessionEntry) +{ + uint8_t center_freq = 0; + enum phy_ch_width ch_width = CH_WIDTH_20MHZ; + + /* If self capability is set to '20Mhz only', then do not change the CB mode. */ + if (!lim_get_ht_capability + (pMac, eHT_SUPPORTED_CHANNEL_WIDTH_SET, psessionEntry)) + return; + + if (WLAN_REG_IS_24GHZ_CH(psessionEntry->currentOperChannel) && + psessionEntry->force_24ghz_in_ht20) { + pe_debug("force_24ghz_in_ht20 is set and channel is 2.4 Ghz"); + return; + } + + if (psessionEntry->ftPEContext.ftPreAuthSession) { + pe_err("FT PREAUTH channel change is in progress"); + return; + } + + /* + * Do not try to switch channel if RoC is in progress. RoC code path + * uses pMac->lim.gpLimRemainOnChanReq to notify the upper layers that + * the device has started listening on the channel requested as part of + * RoC, if we set pMac->lim.gpLimRemainOnChanReq to NULL as we do below + * then the upper layers will think that the channel change is not + * successful and the RoC from the upper layer perspective will never + * end... + */ + if (pMac->lim.gpLimRemainOnChanReq) { + pe_debug("RoC is in progress"); + return; + } + + if (psessionEntry->ch_switch_in_progress == true) { + pe_debug("ch switch is in progress, ignore HT IE BW update"); + return; + } + + if (reg_get_chan_enum(pHTInfo->primaryChannel) == INVALID_CHANNEL) { + pe_debug("Ignore Invalid channel in HT info"); + return; + } + + /* If channel mismatch the CSA will take care of this change */ + if (pHTInfo->primaryChannel != psessionEntry->currentOperChannel) { + pe_debug("Current channel doesnt match HT info ignore"); + return; + } + + if (psessionEntry->htSecondaryChannelOffset != + (uint8_t) pHTInfo->secondaryChannelOffset + || psessionEntry->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + psessionEntry->htSecondaryChannelOffset = + (ePhyChanBondState) pHTInfo->secondaryChannelOffset; + psessionEntry->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + if (eHT_CHANNEL_WIDTH_40MHZ == + psessionEntry->htRecommendedTxWidthSet) { + ch_width = CH_WIDTH_40MHZ; + if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY == + pHTInfo->secondaryChannelOffset) + center_freq = pHTInfo->primaryChannel + 2; + else if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY == + pHTInfo->secondaryChannelOffset) + center_freq = pHTInfo->primaryChannel - 2; + else + ch_width = CH_WIDTH_20MHZ; + } + + /* notify HAL */ + pe_debug("Channel Information in HT IE change" + "d; sending notification to HAL."); + pe_debug("Primary Channel: %d Secondary Chan" + "nel Offset: %d Channel Width: %d", + pHTInfo->primaryChannel, center_freq, + psessionEntry->htRecommendedTxWidthSet); + psessionEntry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + pMac->lim.gpchangeChannelCallback = NULL; + pMac->lim.gpchangeChannelData = NULL; + + /* Before restarting vdev, delete the tdls peers */ + lim_update_tdls_set_state_for_fw(psessionEntry, false); + lim_delete_tdls_peers(pMac, psessionEntry); + lim_send_switch_chnl_params(pMac, (uint8_t) pHTInfo->primaryChannel, + center_freq, 0, ch_width, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, + true, 0, 0); + + + + /* In case of IBSS, if STA should update HT Info IE in its beacons. */ + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + sch_set_fixed_beacon_fields(pMac, psessionEntry); + } + + } +} /* End limUpdateStaRunTimeHTParams. */ + +/** + * \brief This function updates the lim global structure, if any of the + * HT Capabilities have changed. + * + * + * \param pMac 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(tpAniSirGlobal pMac, + tDot11fIEHTCaps *pHTCaps) +{ + + if (pMac->lim.gHTLsigTXOPProtection != + (uint8_t) pHTCaps->lsigTXOPProtection) { + pMac->lim.gHTLsigTXOPProtection = + (uint8_t) pHTCaps->lsigTXOPProtection; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTAMpduDensity != (uint8_t) pHTCaps->mpduDensity) { + pMac->lim.gHTAMpduDensity = (uint8_t) pHTCaps->mpduDensity; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTMaxRxAMpduFactor != + (uint8_t) pHTCaps->maxRxAMPDUFactor) { + pMac->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 pMac 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(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + tpPESession psessionEntry) +{ + if (psessionEntry->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + psessionEntry->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.fRIFSMode != + (uint8_t) pHTInfo->rifsMode) { + psessionEntry->beaconParams.fRIFSMode = + (uint8_t) pHTInfo->rifsMode; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTServiceIntervalGranularity != + (uint8_t) pHTInfo->serviceIntervalGranularity) { + pMac->lim.gHTServiceIntervalGranularity = + (uint8_t) pHTInfo->serviceIntervalGranularity; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTOperMode != (tSirMacHTOperatingMode) pHTInfo->opMode) { + pMac->lim.gHTOperMode = + (tSirMacHTOperatingMode) pHTInfo->opMode; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.llnNonGFCoexist != + pHTInfo->nonGFDevicesPresent) { + psessionEntry->beaconParams.llnNonGFCoexist = + (uint8_t) pHTInfo->nonGFDevicesPresent; + } + + if (pMac->lim.gHTSTBCBasicMCS != (uint8_t) pHTInfo->basicSTBCMCS) { + pMac->lim.gHTSTBCBasicMCS = (uint8_t) pHTInfo->basicSTBCMCS; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTDualCTSProtection != + (uint8_t) pHTInfo->dualCTSProtection) { + pMac->lim.gHTDualCTSProtection = + (uint8_t) pHTInfo->dualCTSProtection; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTSecondaryBeacon != (uint8_t) pHTInfo->secondaryBeacon) { + pMac->lim.gHTSecondaryBeacon = + (uint8_t) pHTInfo->secondaryBeacon; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport != + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport) { + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTPCOActive != (uint8_t) pHTInfo->pcoActive) { + pMac->lim.gHTPCOActive = (uint8_t) pHTInfo->pcoActive; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTPCOPhase != (uint8_t) pHTInfo->pcoPhase) { + pMac->lim.gHTPCOPhase = (uint8_t) pHTInfo->pcoPhase; + /* Send change notification to HAL */ + } + +} /* End lim_update_sta_run_time_ht_info. */ + +/** ------------------------------------------------------------- + \fn lim_process_hal_ind_messages + \brief callback function for HAL indication + \param tpAniSirGlobal pMac + \param uint32_t mesgId + \param void *mesgParam + \return tSirRetStatu - status + -------------------------------------------------------------*/ + +QDF_STATUS lim_process_hal_ind_messages(tpAniSirGlobal pMac, uint32_t msgId, + void *msgParam) +{ + /* its PE's responsibility to free msgparam when its done extracting the message parameters. */ + struct scheduler_msg msg = {0}; + + switch (msgId) { + case SIR_LIM_DEL_TS_IND: + case SIR_LIM_DELETE_STA_CONTEXT_IND: + case SIR_LIM_BEACON_GEN_IND: + msg.type = (uint16_t) msgId; + msg.bodyptr = msgParam; + msg.bodyval = 0; + break; + + default: + qdf_mem_free(msgParam); + pe_err("invalid message id: %d received", msgId); + return QDF_STATUS_E_FAILURE; + } + + if (lim_post_msg_api(pMac, &msg) != QDF_STATUS_SUCCESS) { + qdf_mem_free(msgParam); + pe_err("lim_post_msg_api failed for msgid: %d", msg.type); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * 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 + * + * 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(tpAniSirGlobal mac_ctx, tpSirDeltsReq delts_req, + tSirMacAddr peer_mac_addr, tpPESession psession_entry) +{ + tpDphHashNode sta; + uint8_t ts_status; + tSirMacTSInfo *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 == NULL) { + pe_err("Delete TS request pointer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (LIM_IS_STA_ROLE(psession_entry)) { + uint32_t val; + + /* station always talks to the AP */ + sta = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &psession_entry->dph.dphHashTable); + + val = sizeof(tSirMacAddr); + sir_copy_mac_addr(peer_mac_addr, psession_entry->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, + &psession_entry->dph.dphHashTable); + else + sta = dph_lookup_hash_entry(mac_ctx, + delts_req->macaddr.bytes, + &associd, + &psession_entry->dph. + dphHashTable); + + if (sta != NULL) + /* TBD: check sta assoc state as well */ + for (i = 0; i < sizeof(tSirMacAddr); i++) + macaddr[i] = sta->staAddr[i]; + } + + if (sta == NULL) { + 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, sta->staIndex, + tspec_idx, delts_req->req, + psession_entry->peSessionId, + psession_entry->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; +} + +/** ------------------------------------------------------------- + \fn lim_register_hal_ind_call_back + \brief registers callback function to HAL for any indication. + \param tpAniSirGlobal pMac + \return none. + -------------------------------------------------------------*/ +void lim_register_hal_ind_call_back(tpAniSirGlobal pMac) +{ + struct scheduler_msg msg = {0}; + tpHalIndCB pHalCB; + + pHalCB = qdf_mem_malloc(sizeof(tHalIndCB)); + if (NULL == pHalCB) { + pe_err("AllocateMemory() failed"); + return; + } + + pHalCB->pHalIndCB = lim_process_hal_ind_messages; + + msg.type = WMA_REGISTER_PE_CALLBACK; + msg.bodyptr = pHalCB; + msg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + qdf_mem_free(pHalCB); + pe_err("wma_post_ctrl_msg() failed"); + } + + return; +} + +/** + * lim_process_del_ts_ind() - handle del_ts_ind from HAL + * + * @mac_ctx: pointer to Global Mac Structure + * @lim_msg: pointer to msg buff + * + * handles the DeleteTS indication coming from HAL or generated by PE itself + * in some error cases. Validates the request, sends the DelTs action frame + * to the Peer and sends DelTs indicatoin to HDD. + * + * Return: none + */ +void lim_process_del_ts_ind(tpAniSirGlobal pMac, struct scheduler_msg *limMsg) +{ + tpDphHashNode pSta; + tpDelTsParams pDelTsParam = (tpDelTsParams) (limMsg->bodyptr); + tpSirDeltsReq pDelTsReq = NULL; + tSirMacAddr peerMacAddr; + tpSirDeltsReqInfo pDelTsReqInfo; + tpLimTspecInfo pTspecInfo; + tpPESession psessionEntry; + uint8_t sessionId; + + psessionEntry = pe_find_session_by_bssid(pMac, pDelTsParam->bssId, + &sessionId); + if (psessionEntry == NULL) { + pe_err("session does not exist for given BssId"); + qdf_mem_free(limMsg->bodyptr); + limMsg->bodyptr = NULL; + return; + } + + pTspecInfo = &(pMac->lim.tspecInfo[pDelTsParam->tspecIdx]); + if (pTspecInfo->inuse == false) { + pe_err("tspec entry with index: %d is not in use", + pDelTsParam->tspecIdx); + goto error1; + } + + pSta = + dph_get_hash_entry(pMac, pTspecInfo->assocId, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + pe_err("Could not find entry in DPH table for assocId: %d", + pTspecInfo->assocId); + goto error1; + } + + pDelTsReq = qdf_mem_malloc(sizeof(tSirDeltsReq)); + if (NULL == pDelTsReq) { + pe_err("AllocateMemory() failed"); + goto error1; + } + + if (pSta->wmeEnabled) + qdf_mem_copy(&(pDelTsReq->req.tspec), &(pTspecInfo->tspec), + sizeof(tSirMacTspecIE)); + else + qdf_mem_copy(&(pDelTsReq->req.tsinfo), + &(pTspecInfo->tspec.tsinfo), + sizeof(tSirMacTSInfo)); + + /* validate the req */ + if (QDF_STATUS_SUCCESS != + lim_validate_delts_req(pMac, pDelTsReq, peerMacAddr, psessionEntry)) { + pe_err("lim_validate_delts_req failed"); + goto error2; + } + pe_debug("Sent DELTS request to station with " + "assocId = %d MacAddr = " MAC_ADDRESS_STR, + pDelTsReq->aid, MAC_ADDR_ARRAY(peerMacAddr)); + + lim_send_delts_req_action_frame(pMac, peerMacAddr, + pDelTsReq->req.wmeTspecPresent, + &pDelTsReq->req.tsinfo, + &pDelTsReq->req.tspec, psessionEntry); + + /* prepare and send an sme indication to HDD */ + pDelTsReqInfo = qdf_mem_malloc(sizeof(tSirDeltsReqInfo)); + if (NULL == pDelTsReqInfo) { + pe_err("AllocateMemory() failed"); + goto error3; + } + + if (pSta->wmeEnabled) + qdf_mem_copy(&(pDelTsReqInfo->tspec), &(pTspecInfo->tspec), + sizeof(tSirMacTspecIE)); + else + qdf_mem_copy(&(pDelTsReqInfo->tsinfo), + &(pTspecInfo->tspec.tsinfo), + sizeof(tSirMacTSInfo)); + + lim_send_sme_delts_ind(pMac, pDelTsReqInfo, pDelTsReq->aid, psessionEntry); + +error3: + qdf_mem_free(pDelTsReqInfo); +error2: + qdf_mem_free(pDelTsReq); +error1: + qdf_mem_free(limMsg->bodyptr); + limMsg->bodyptr = NULL; + return; +} + +/** + * @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 pMac - 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(tpAniSirGlobal pMac, + uint16_t staIdx, 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 (NULL == pMIMO_PSParams) { + pe_err(" AllocateMemory failed"); + return QDF_STATUS_E_NOMEM; + } + + pMIMO_PSParams->htMIMOPSState = state; + pMIMO_PSParams->staIdx = staIdx; + 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(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &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(tpAniSirGlobal pMac, + eFrameType frmType, uint8_t *pRxPacketInfo, void *pBody) +{ + (void)pMac; + (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(tpAniSirGlobal pMac, void *body, uint32_t **pRxPacketInfo) +{ + *pRxPacketInfo = (uint32_t *) body; +} /*** end lim_get_b_dfrom_rx_packet() ***/ + +void lim_add_channel_status_info(tpAniSirGlobal p_mac, + struct lim_channel_status *channel_stat, + uint8_t channel_id) +{ + uint8_t i; + bool found = false; + struct lim_scan_channel_status *channel_info = + &p_mac->lim.scan_channel_status; + struct lim_channel_status *channel_status_list = + channel_info->channel_status_list; + uint8_t total_channel = channel_info->total_channel; + + if (!p_mac->sap.acs_with_more_param) + return; + + for (i = 0; i < total_channel; i++) { + if (channel_status_list[i].channel_id == channel_id) { + if (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 */ + channel_stat->rx_clear_count -= + channel_status_list[i].rx_clear_count; + channel_stat->cycle_count -= + channel_status_list[i].cycle_count; + channel_stat->rx_frame_count -= + channel_status_list[i].rx_frame_count; + channel_stat->tx_frame_count -= + channel_status_list[i].tx_frame_count; + channel_stat->bss_rx_cycle_count -= + channel_status_list[i].bss_rx_cycle_count; + } + qdf_mem_copy(&channel_status_list[i], channel_stat, + sizeof(*channel_status_list)); + found = true; + break; + } + } + + if (!found) { + if (total_channel < SIR_MAX_SUPPORTED_CHANNEL_LIST) { + qdf_mem_copy(&channel_status_list[total_channel++], + channel_stat, + sizeof(*channel_status_list)); + channel_info->total_channel = total_channel; + } else { + pe_warn("Chan cnt exceed, channel_id=%d", channel_id); + } + } + + return; +} + +/** + * @function : lim_is_channel_valid_for_channel_switch() + * + * @brief : This function checks if the channel to which AP + * is expecting us to switch, is a valid channel for us. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param channel - New channel to which we are expected to move + * @return None + */ +bool lim_is_channel_valid_for_channel_switch(tpAniSirGlobal pMac, uint8_t channel) +{ + uint8_t index; + uint32_t validChannelListLen = WNI_CFG_VALID_CHANNEL_LIST_LEN; + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + bool ok = false; + + if (policy_mgr_is_chan_ok_for_dnbs(pMac->psoc, channel, &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_cfg_get_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, + (uint8_t *) validChannelList, + (uint32_t *) &validChannelListLen) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve valid channel list"); + return false; + } + + for (index = 0; index < validChannelListLen; index++) { + if (validChannelList[index] != channel) + continue; + + ok = policy_mgr_is_valid_for_channel_switch(pMac->psoc, + channel); + return ok; + } + + /* channel does not belong to list of valid channels */ + return false; +} + +/**------------------------------------------------------ + \fn __lim_fill_tx_control_params + \brief Fill the message for stopping/resuming tx. + + \param pMac + \param pTxCtrlMsg - Pointer to tx control message. + \param type - Which way we want to stop/ resume tx. + \param mode - To stop/resume. + -------------------------------------------------------*/ +static QDF_STATUS +__lim_fill_tx_control_params(tpAniSirGlobal pMac, tpTxControlParams pTxCtrlMsg, + tLimQuietTxMode type, tLimControlTx mode) +{ + + tpPESession psessionEntry = &pMac->lim.gpSession[0]; + + if (mode == eLIM_STOP_TX) + pTxCtrlMsg->stopTx = true; + else + pTxCtrlMsg->stopTx = false; + + switch (type) { + case eLIM_TX_ALL: + /** Stops/resumes transmission completely */ + pTxCtrlMsg->fCtrlGlobal = 1; + break; + + case eLIM_TX_BSS_BUT_BEACON: + /** Stops/resumes transmission on a particular BSS. Stopping BSS, doesn't + * stop beacon transmission. + */ + pTxCtrlMsg->ctrlBss = 1; + pTxCtrlMsg->bssBitmap |= (1 << psessionEntry->bssIdx); + break; + + case eLIM_TX_STA: + /** Memory for station bitmap is allocated dynamically in caller of this + * so decode properly here and fill the bitmap. Now not implemented, + * fall through. + */ + case eLIM_TX_BSS: + /* Fall thru... */ + default: + pe_warn("Invalid case: Not Handled"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * @function : lim_frame_transmission_control() + * + * @brief : This API is called by the user to halt/resume any frame + * transmission from the device. If stopped, all frames will be + * queued starting from hardware. Then back-pressure + * is built till the driver. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ +void lim_frame_transmission_control(tpAniSirGlobal pMac, tLimQuietTxMode type, + tLimControlTx mode) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpTxControlParams pTxCtrlMsg; + struct scheduler_msg msgQ = {0}; + uint8_t nBytes = 0; /* No of bytes required for station bitmap. */ + + /** Allocate only required number of bytes for station bitmap + * Make it to align to 4 byte boundary */ + nBytes = (uint8_t) HALMSG_NUMBYTES_STATION_BITMAP(pMac->lim.maxStation); + + pTxCtrlMsg = qdf_mem_malloc(sizeof(*pTxCtrlMsg) + nBytes); + if (NULL == pTxCtrlMsg) { + pe_err("AllocateMemory() failed"); + return; + } + + status = __lim_fill_tx_control_params(pMac, pTxCtrlMsg, type, mode); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(pTxCtrlMsg); + pe_err("__lim_fill_tx_control_params failed, status: %d", + status); + return; + } + + msgQ.bodyptr = (void *)pTxCtrlMsg; + msgQ.bodyval = 0; + msgQ.reserved = 0; + msgQ.type = WMA_TRANSMISSION_CONTROL_IND; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + if (wma_post_ctrl_msg(pMac, &msgQ) != QDF_STATUS_SUCCESS) { + qdf_mem_free(pTxCtrlMsg); + pe_err("Posting Message to HAL failed"); + return; + } + + pe_debug("Stopping the transmission of all packets, indicated softmac tx_control: %d", + mode); + + return; +} + +/** + * @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 pMac - Pointer to Global MAC structure + * @return None + */ + +QDF_STATUS +lim_restore_pre_channel_switch_state(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + if (!LIM_IS_STA_ROLE(psessionEntry)) + return retCode; + + /* Channel switch should be ready for the next time */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_INIT; + + /* Restore the frame transmission, all the time. */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + + return retCode; +} + +/**-------------------------------------------- + \fn lim_restore_pre_quiet_state + \brief Restore the pre quiet state + + \param pMac + \return NONE + ---------------------------------------------*/ +QDF_STATUS lim_restore_pre_quiet_state(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + if (pMac->lim.gLimSystemRole != eLIM_STA_ROLE) + return retCode; + + /* Quiet should be ready for the next time */ + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* Restore the frame transmission, all the time. */ + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + + 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 pMac - Pointer to Global MAC structure + * @param psessionEntry + * @return None + */ +void +lim_prepare_for11h_channel_switch(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + /* Flag to indicate 11h channel switch in progress */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_RUNNING; + + if (pMac->lim.gLimSmeState == eLIM_SME_LINK_EST_WT_SCAN_STATE || + pMac->lim.gLimSmeState == eLIM_SME_CHANNEL_SCAN_STATE) { + pe_debug("Posting finish scan as we are in scan state"); + /* Stop ongoing scanning if any */ + if (GET_LIM_PROCESS_DEFD_MESGS(pMac)) { + /* Set the resume channel to Any valid channel (invalid). */ + /* This will instruct HAL to set it to any previous valid channel. */ + pe_set_resume_channel(pMac, 0, 0); + } else { + lim_restore_pre_channel_switch_state(pMac, psessionEntry); + } + return; + } else { + pe_debug("Not in scan state, start channel switch timer"); + /** We are safe to switch channel at this point */ + lim_stop_tx_and_switch_channel(pMac, psessionEntry->peSessionId); + } +} + +/**---------------------------------------------------- + \fn lim_get_nw_type + + \brief Get type of the network from data packet or beacon + \param pMac + \param channelNum - Channel number + \param type - Type of packet. + \param pBeacon - Pointer to beacon or probe response + + \return Network type a/b/g. + -----------------------------------------------------*/ +tSirNwType lim_get_nw_type(tpAniSirGlobal pMac, uint8_t channelNum, uint32_t type, + tpSchBeaconStruct pBeacon) +{ + tSirNwType nwType = eSIR_11B_NW_TYPE; + + if (type == SIR_MAC_DATA_FRAME) { + if ((channelNum > 0) && (channelNum < 15)) { + nwType = eSIR_11G_NW_TYPE; + } else { + nwType = eSIR_11A_NW_TYPE; + } + } else { + if ((channelNum > 0) && (channelNum < 15)) { + 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; +} + +/**--------------------------------------------------------- + \fn lim_get_channel_from_beacon + \brief To extract channel number from beacon + + \param pMac + \param pBeacon - Pointer to beacon or probe rsp + \return channel number + -----------------------------------------------------------*/ +uint8_t lim_get_channel_from_beacon(tpAniSirGlobal pMac, tpSchBeaconStruct pBeacon) +{ + uint8_t channelNum = 0; + + if (pBeacon->dsParamsPresent) + channelNum = pBeacon->channelNumber; + else if (pBeacon->HTInfo.present) + channelNum = pBeacon->HTInfo.primaryChannel; + else + channelNum = pBeacon->channelNumber; + + return channelNum; +} + +void lim_set_tspec_uapsd_mask_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacTSInfo *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) + psessionEntry->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + psessionEntry->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + psessionEntry->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + } + } else if (action == SET_UAPSD_MASK) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + psessionEntry->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + psessionEntry->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + psessionEntry->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + } + } + + pe_debug("New psessionEntry->gUapsdPerAcTriggerEnableMask 0x%x psessionEntry->gUapsdPerAcDeliveryEnableMask 0x%x", + psessionEntry->gUapsdPerAcTriggerEnableMask, + psessionEntry->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 tpPESession + * + * Function handles heart beat time out for session + * + * Return: none + */ +void lim_handle_heart_beat_timeout_for_session(tpAniSirGlobal mac_ctx, + tpPESession psession_entry) +{ + if (psession_entry->valid == true) { + if (psession_entry->bssType == eSIR_IBSS_MODE) + lim_ibss_heart_beat_handle(mac_ctx, psession_entry); + + if ((psession_entry->bssType == eSIR_INFRASTRUCTURE_MODE) && + (LIM_IS_STA_ROLE(psession_entry))) + lim_handle_heart_beat_failure(mac_ctx, psession_entry); + } + /* + * In the function lim_handle_heart_beat_failure things can change + * so check for the session entry valid and the other things + * again + */ + if ((psession_entry->valid == true) && + (psession_entry->bssType == eSIR_INFRASTRUCTURE_MODE) && + (LIM_IS_STA_ROLE(psession_entry)) && + (psession_entry->LimHBFailureStatus == true)) { + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + /* + * Activate Probe After HeartBeat Timer incase HB + * Failure detected + */ + pe_debug("Sending Probe for Session: %d", + psession_entry->bssIdx); + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PROBE_AFTER_HB_TIMER); + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, 0, + eLIM_PROBE_AFTER_HB_TIMER)); + if (tx_timer_activate(&lim_timer->gLimProbeAfterHBTimer) + != TX_SUCCESS) + pe_err("Fail to re-activate Probe-after-hb timer"); + } +} + +uint8_t lim_get_current_operating_channel(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + if ((pMac->lim.gpSession[i].bssType == + eSIR_INFRASTRUCTURE_MODE) + && (pMac->lim.gpSession[i].limSystemRole == + eLIM_STA_ROLE)) { + return pMac->lim.gpSession[i]. + currentOperChannel; + } + } + } + return 0; +} + +/** + * 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(tpAniSirGlobal mac_ctx, struct scheduler_msg *msg) +{ + tpPESession 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 == NULL) { + 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_IBSS_ROLE(session)) + (void)lim_ibss_add_sta_rsp(mac_ctx, msg->bodyptr, session); + else 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(tpAniSirGlobal 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) + || (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_STA_IN_IBSS_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); + } + } +} + +/** + * lim_handle_heart_beat_failure_timeout - handle heart beat failure + * @mac_ctx: pointer to Global Mac Structure + * + * Function handle heart beat failure timeout + * + * Return: none + */ +void lim_handle_heart_beat_failure_timeout(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + tpPESession psession_entry; + /* + * Probe response is not received after HB failure. + * This is handled by LMM sub module. + */ + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid != true) + continue; + psession_entry = &mac_ctx->lim.gpSession[i]; + if (psession_entry->LimHBFailureStatus != true) + continue; + pe_debug("SME: %d MLME: %d HB-Count: %d", + psession_entry->limSmeState, + psession_entry->limMlmState, + psession_entry->LimRxedBeaconCntDuringHB); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_HB_FAILURE_TIMEOUT, + psession_entry, 0, 0); +#endif + if ((psession_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (psession_entry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (psession_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) && + ((!LIM_IS_CONNECTION_ACTIVE(psession_entry)) || + /* + * Disconnect even if we have not received a single + * beacon after connection. + */ + (psession_entry->currentBssBeaconCnt == 0))) { + pe_debug("for session: %d", + psession_entry->peSessionId); + + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + psession_entry->bssId, psession_entry, false); + + /* + * AP did not respond to Probe Request. + * Tear down link with it. + */ + lim_tear_down_link_with_ap(mac_ctx, + psession_entry->peSessionId, + eSIR_BEACON_MISSED); + mac_ctx->lim.gLimProbeFailureAfterHBfailedCnt++; + } else { + pe_err("Unexpected wt-probe-timeout in state"); + lim_print_mlm_state(mac_ctx, LOGE, + psession_entry->limMlmState); + if (mac_ctx->sme.tx_queue_cb) + mac_ctx->sme.tx_queue_cb(mac_ctx->hdd_handle, + psession_entry->smeSessionId, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + } + /* + * Deactivate Timer ProbeAfterHB Timer -> As its a oneshot timer, + * need not deactivate the timer + * tx_timer_deactivate(&pMac->lim.limTimers.gLimProbeAfterHBTimer); + */ +} + +/* + * This function assumes there will not be more than one IBSS session active at any time. + */ +tpPESession lim_is_ibss_session_active(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid) && + (pMac->lim.gpSession[i].limSystemRole == + eLIM_STA_IN_IBSS_ROLE)) + return &pMac->lim.gpSession[i]; + } + + return NULL; +} + +tpPESession lim_is_ap_session_active(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid && + (pMac->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE)) + return &pMac->lim.gpSession[i]; + } + + return NULL; +} + +/**--------------------------------------------------------- + \fn lim_handle_defer_msg_error + \brief handles error scenario, when the msg can not be deferred. + \param pMac + \param pLimMsg LIM msg, which could not be deferred. + \return void + -----------------------------------------------------------*/ + +void lim_handle_defer_msg_error(tpAniSirGlobal pMac, + struct scheduler_msg *pLimMsg) +{ + if (SIR_BB_XPORT_MGMT_MSG == pLimMsg->type) { + lim_decrement_pending_mgmt_count(pMac); + cds_pkt_return_packet((cds_pkt_t *) pLimMsg->bodyptr); + pLimMsg->bodyptr = NULL; + } else if (pLimMsg->bodyptr != NULL) { + 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 pMac + \param eventType + \param bssid + \param status + \param reasonCode + \return void + -----------------------------------------------------------*/ +void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t eventType, + tpPESession pSessionEntry, 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 (NULL == pSessionEntry) { + qdf_mem_copy(peEvent.bssid, nullBssid, sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) pMac->lim.gLimSmeState; + peEvent.mlm_state = (uint16_t) pMac->lim.gLimMlmState; + + } else { + qdf_mem_copy(peEvent.bssid, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) pSessionEntry->limSmeState; + peEvent.mlm_state = (uint16_t) pSessionEntry->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(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tpPESession 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->selfMacAddr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(mgmt_event->bssid, session->bssId, + QDF_MAC_ADDR_SIZE); + length = session->ssId.length; + if (length > SIR_MAC_MAX_SSID_LENGTH) + length = SIR_MAC_MAX_SSID_LENGTH; + qdf_mem_copy(mgmt_event->ssid, session->ssId.ssId, length); + mgmt_event->ssid_len = length; + mgmt_event->operating_channel = session->currentOperChannel; + mgmt_event->result_code = result_code; + mgmt_event->reason_code = reason_code; +} + +void lim_diag_mgmt_tx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, + tpPESession 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:%.*s selfmacaddr:%pM bssid:%pM channel:%d", + mgmt_event.mgmt_type, mgmt_event.mgmt_subtype, + ((mac_hdr->seqControl.seqNumHi << 4) | + mac_hdr->seqControl.seqNumLo), + mgmt_event.ssid_len, mgmt_event.ssid, + mgmt_event.self_mac_addr, 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(tpAniSirGlobal mac_ctx, void *mgmt_hdr, + tpPESession 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:%.*s selfmacaddr:%pM bssid:%pM channel:%d", + mgmt_event.mgmt_type, mgmt_event.mgmt_subtype, + ((mac_hdr->seqControl.seqNumHi << 4) | + mac_hdr->seqControl.seqNumLo), + mgmt_event.ssid_len, mgmt_event.ssid, + mgmt_event.self_mac_addr, 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(tpAniSirGlobal pMac, uint8_t *ie, uint8_t *data, + uint8_t ie_len) +{ + int length = 0; + uint8_t *ptr = ie; + + ptr[length++] = SIR_MAC_EID_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_in_mult_p2p_ies(tpAniSirGlobal pMac, + uint8_t *noaStream, uint8_t noaLen, + uint8_t overFlowLen) +{ + uint8_t overFlowP2pStream[SIR_MAX_NOA_ATTR_LEN]; + + if ((noaLen <= (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)) && + (noaLen >= overFlowLen) && (overFlowLen <= SIR_MAX_NOA_ATTR_LEN)) { + qdf_mem_copy(overFlowP2pStream, + noaStream + noaLen - overFlowLen, overFlowLen); + noaStream[noaLen - overFlowLen] = SIR_MAC_EID_VENDOR; + noaStream[noaLen - overFlowLen + 1] = + overFlowLen + SIR_MAC_P2P_OUI_SIZE; + qdf_mem_copy(noaStream + noaLen - overFlowLen + 2, + SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + qdf_mem_copy(noaStream + noaLen + 2 + SIR_MAC_P2P_OUI_SIZE - + overFlowLen, overFlowP2pStream, overFlowLen); + } + + return noaLen + 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(tpAniSirGlobal pMac, uint8_t *pNoaStream, + tpPESession psessionEntry) +{ + uint8_t len = 0; + + uint8_t *pBody = pNoaStream; + + if ((psessionEntry != NULL) && (psessionEntry->valid) && + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) { + if ((!(psessionEntry->p2pGoPsUpdate.uNoa1Duration)) + && (!(psessionEntry->p2pGoPsUpdate.uNoa2Duration)) + && (!psessionEntry->p2pGoPsUpdate.oppPsFlag) + ) + return 0; /* No NoA Descriptor then return 0 */ + + pBody[0] = SIR_P2P_NOA_ATTR; + + pBody[3] = psessionEntry->p2pGoPsUpdate.index; + pBody[4] = + psessionEntry->p2pGoPsUpdate.ctWin | (psessionEntry-> + p2pGoPsUpdate. + oppPsFlag << 7); + len = 5; + pBody += len; + + if (psessionEntry->p2pGoPsUpdate.uNoa1Duration) { + *pBody = psessionEntry->p2pGoPsUpdate.uNoa1IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1StartTime); + pBody += sizeof(uint32_t); + len += 4; + + } + + if (psessionEntry->p2pGoPsUpdate.uNoa2Duration) { + *pBody = psessionEntry->p2pGoPsUpdate.uNoa2IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->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(tpAniSirGlobal pMac, uint16_t channel, + ePhyChanBondState phyCbState) +{ + + pMac->lim.gResumeChannel = channel; + pMac->lim.gResumePhyCbState = phyCbState; +} + +bool lim_is_noa_insert_reqd(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + if ((eLIM_AP_ROLE == + pMac->lim.gpSession[i].limSystemRole) + && (QDF_P2P_GO_MODE == + pMac->lim.gpSession[i].pePersona) + ) { + return true; + } + } + } + return false; +} + +bool lim_isconnected_on_dfs_channel(tpAniSirGlobal mac_ctx, + uint8_t currentChannel) +{ + if (CHANNEL_STATE_DFS == + wlan_reg_get_channel_state(mac_ctx->pdev, currentChannel)) { + return true; + } else { + return false; + } +} + +#ifdef WLAN_FEATURE_11W +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + tPmfSaQueryTimerId timerId; + tpPESession psessionEntry; + tpDphHashNode pSta; + uint32_t maxRetries; + + pe_debug("SA Query timer fires"); + timerId.value = param; + + /* Check that SA Query is in progress */ + psessionEntry = pe_find_session_by_session_id(pMac, + timerId.fields.sessionId); + if (psessionEntry == NULL) { + pe_err("Session does not exist for given session ID: %d", + timerId.fields.sessionId); + return; + } + pSta = dph_get_hash_entry(pMac, timerId.fields.peerIdx, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + 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 */ + if (wlan_cfg_get_int(pMac, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &maxRetries) != QDF_STATUS_SUCCESS) { + pe_err("Could not retrieve PMF SA Query maximum retries value"); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + return; + } + pSta->pmfSaQueryRetryCount++; + if (pSta->pmfSaQueryRetryCount >= maxRetries) { + pe_err("SA Query timed out,Deleting STA"); + lim_print_mac_addr(pMac, pSta->staAddr, LOGE); + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + pSta->staAddr, psessionEntry, false); + lim_trigger_sta_deletion(pMac, pSta, psessionEntry); + pSta->pmfSaQueryState = DPH_SA_QUERY_TIMED_OUT; + return; + } + /* Retry SA Query */ + lim_send_sa_query_request_frame(pMac, + (uint8_t *) &(pSta-> + pmfSaQueryCurrentTransId), + pSta->staAddr, psessionEntry); + 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; + } +} +#endif + +bool lim_check_vht_op_mode_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t chanWidth, uint8_t staId, + uint8_t *peerMac) +{ + tUpdateVHTOpMode tempParam; + + tempParam.opMode = chanWidth; + tempParam.staId = staId; + tempParam.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_mode_update(pMac, &tempParam, psessionEntry); + + return true; +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +bool lim_send_he_ie_update(tpAniSirGlobal mac_ctx, tpPESession 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(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t rxNss, uint8_t staId, uint8_t *peerMac) +{ + tUpdateRxNss tempParam; + + if (!rxNss) { + pe_err("Invalid rxNss value: %u", rxNss); + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); + } + + tempParam.rxNss = rxNss; + tempParam.staId = staId; + tempParam.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_rx_nss_update(pMac, &tempParam, psessionEntry); + + return true; +} + +bool lim_check_membership_user_position(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t membership, uint32_t userPosition, + uint8_t staId) +{ + tUpdateMembership tempParamMembership; + tUpdateUserPos tempParamUserPosition; + + tempParamMembership.membership = membership; + tempParamMembership.staId = staId; + tempParamMembership.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParamMembership.peer_mac, psessionEntry->bssId, + sizeof(tSirMacAddr)); + + lim_set_membership(pMac, &tempParamMembership, psessionEntry); + + tempParamUserPosition.userPos = userPosition; + tempParamUserPosition.staId = staId; + tempParamUserPosition.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParamUserPosition.peer_mac, psessionEntry->bssId, + sizeof(tSirMacAddr)); + + lim_set_user_pos(pMac, &tempParamUserPosition, psessionEntry); + + return true; +} + +void lim_get_short_slot_from_phy_mode(tpAniSirGlobal pMac, tpPESession psessionEntry, + 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 ((psessionEntry->pePersona == QDF_SAP_MODE) || + (psessionEntry->pePersona == QDF_IBSS_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) { + val = true; + } + /* Program Polaris based on AP capability */ + if (psessionEntry->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE) { + /* Joining BSS. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(psessionEntry-> + limCurrentBssCaps); + } else if (psessionEntry->limMlmState == + eLIM_MLM_WT_REASSOC_RSP_STATE) { + /* Reassociating with AP. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(psessionEntry-> + 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; +} + +#ifdef WLAN_FEATURE_11W +/** + * + * \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 pMac Pointer to Global MAC structure + * + * \param psessionEntry 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(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr) +{ + uint16_t aid; + tpDphHashNode pStaDs; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + + pStaDs = dph_lookup_hash_entry(pMac, peer, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* 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 (pStaDs->rmfEnabled && pStaDs->is_key_installed) + pMacHdr->fc.wep = 1; + } + } else if (psessionEntry->limRmfEnabled && + psessionEntry->is_key_installed) { + pMacHdr->fc.wep = 1; + } +} /*** end lim_set_protected_bit() ***/ +#endif + +void lim_set_ht_caps(tpAniSirGlobal p_mac, tpPESession p_session_entry, + 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, p_session_entry, &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(tpAniSirGlobal p_mac, tpPESession p_session_entry, + 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, p_session_entry, &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->reserved1 = dot11_vht_cap.reserved1; + + /* 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.reserved = + dot11_vht_cap.reserved2; + 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.reserved = + dot11_vht_cap.reserved3; + vht_mcs->txHighest = u_vht_data_rate_info.u_value; + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tSirMacAddr a1, tpPESession session) +{ + if (mac_ctx == NULL || session == NULL) { + pe_err("mac or session context is null"); + /* let main routine handle it */ + return true; + } + if (lim_is_group_addr(a1) || lim_is_addr_bc(a1)) { + /* just for fail safe, don't handle MC/BC a1 in this routine */ + return true; + } + if (qdf_mem_cmp(a1, session->selfMacAddr, 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(tpAniSirGlobal 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 funciton 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, + tpAniSirGlobal 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(tpPESession 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 + * @sme_session_id: sme session id + * @eid: IE id + * @band: band for which IE is intended + * @buf: buffer containing IE + * @len: length of buffer + * + * This funciton sends the IE data to WMA. + * + * Return: status of operation + */ +static QDF_STATUS lim_send_ie(tpAniSirGlobal mac_ctx, uint32_t sme_session_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) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + ie_msg->vdev_id = sme_session_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(tpAniSirGlobal mac_ctx, enum channel_enum ch) +{ + if (mac_ctx->roam.configParam.rx_ldpc_enable && + wma_is_rx_ldpc_supported_for_channel(WLAN_REG_CH_NUM(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(tpAniSirGlobal mac_ctx, + struct sHtCaps *ht_cap, + uint8_t vdev_id, + uint8_t band) +{ + struct 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(tpAniSirGlobal mac_ctx, + uint8_t *vht_caps, + uint8_t vdev_id, + uint8_t band) +{ + struct 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); +} + +/** + * lim_send_ies_per_band() - gets ht and vht capability and send to firmware via + * wma + * @mac_ctx: global mac context + * @session: pe session. This can be NULL. In that case self cap will be sent + * @vdev_id: vdev for which IE is targeted + * + * This funciton gets ht and vht capability and send to firmware via wma + * + * Return: status of operation + */ +QDF_STATUS lim_send_ies_per_band(tpAniSirGlobal mac_ctx, + tpPESession session, + uint8_t vdev_id) +{ + uint8_t ht_caps[DOT11F_IE_HTCAPS_MIN_LEN + 2] = {0}; + uint8_t vht_caps[DOT11F_IE_VHTCAPS_MAX_LEN + 2] = {0}; + tHtCaps *p_ht_cap = (tHtCaps *)(&ht_caps[2]); + tSirMacVHTCapabilityInfo *p_vht_cap = + (tSirMacVHTCapabilityInfo *)(&vht_caps[2]); + QDF_STATUS status; + + /* + * 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. + */ + ht_caps[0] = DOT11F_EID_HTCAPS; + ht_caps[1] = DOT11F_IE_HTCAPS_MIN_LEN; + lim_set_ht_caps(mac_ctx, session, 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_6); + /* Get self cap for HT40 support in 2G */ + if (mac_ctx->roam.configParam.channelBondingMode24GHz) { + 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); + + 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_64); + /* 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); + + lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HTCAPS, + CDS_BAND_5GHZ, &ht_caps[2], DOT11F_IE_HTCAPS_MIN_LEN); + + vht_caps[0] = DOT11F_EID_VHTCAPS; + vht_caps[1] = DOT11F_IE_VHTCAPS_MAX_LEN; + lim_set_vht_caps(mac_ctx, session, 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_64); + /* Self VHT channel width for 5G is already negotiated with FW */ + lim_populate_mcs_set_vht_per_vdev(mac_ctx, vht_caps, + vdev_id, NSS_CHAINS_BAND_5GHZ); + + lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_VHTCAPS, + CDS_BAND_5GHZ, &vht_caps[2], DOT11F_IE_VHTCAPS_MIN_LEN); + + /* Get LDPC and over write for 2G */ + p_vht_cap->ldpcCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_6); + /* 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); + + lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_VHTCAPS, + CDS_BAND_2GHZ, &vht_caps[2], DOT11F_IE_VHTCAPS_MIN_LEN); + + status = lim_send_he_caps_ie(mac_ctx, session, vdev_id); + + return status; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + uint32_t session_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; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &dot11mode); + 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; + } + + num_bytes = ext_cap_data.num_bytes; + + if (merge && NULL != 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); + } + + /* Allocate memory for the WMI request, and copy the parameter */ + vdev_ie = qdf_mem_malloc(sizeof(*vdev_ie) + num_bytes); + if (!vdev_ie) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + vdev_ie->vdev_id = session_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; +} + +/** + * lim_strip_ie() - strip requested IE from IE buffer + * @mac_ctx: global MAC context + * @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 + * + * This utility function is used to strip of the requested IE if present + * in IE buffer. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_strip_ie(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, eSizeOfLenField size_of_len_field, + uint8_t *oui, uint8_t oui_length, uint8_t *extracted_ie, + uint32_t eid_max_len) +{ + uint8_t *tempbuf = NULL; + uint16_t templen = 0; + int left = *addn_ielen; + uint8_t *ptr = addn_ie; + uint8_t elem_id; + uint16_t elem_len; + + if (NULL == addn_ie) { + pe_debug("NULL addn_ie pointer"); + return QDF_STATUS_E_INVAL; + } + + tempbuf = qdf_mem_malloc(left); + if (NULL == tempbuf) { + pe_err("Unable to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + 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) { + 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 (eid != elem_id || + (oui && qdf_mem_cmp(oui, + &ptr[size_of_len_field + 1], + oui_length))) { + qdf_mem_copy(tempbuf + templen, &ptr[0], + elem_len + size_of_len_field + 1); + templen += (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 (NULL != extracted_ie) { + qdf_mem_zero(extracted_ie, + eid_max_len + size_of_len_field + 1); + if (elem_len <= eid_max_len) + qdf_mem_copy(extracted_ie, &ptr[0], + elem_len + size_of_len_field + 1); + } + } + left -= elem_len; + ptr += (elem_len + size_of_len_field + 1); + } + qdf_mem_copy(addn_ie, tempbuf, templen); + + *addn_ielen = templen; + qdf_mem_free(tempbuf); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11W +void lim_del_pmf_sa_query_timer(tpAniSirGlobal mac_ctx, tpPESession pe_session) +{ + uint32_t associated_sta; + tpDphHashNode sta_ds = NULL; + + for (associated_sta = 1; + associated_sta < mac_ctx->lim.gLimAssocStaLimit; + associated_sta++) { + sta_ds = dph_get_hash_entry(mac_ctx, associated_sta, + &pe_session->dph.dphHashTable); + if (NULL == sta_ds) + continue; + if (!sta_ds->rmfEnabled) { + pe_debug("no PMF timer for sta-idx:%d assoc-id:%d", + sta_ds->staIndex, sta_ds->assocId); + continue; + } + + pe_debug("Deleting pmfSaQueryTimer for sta-idx:%d assoc-id:%d", + sta_ds->staIndex, sta_ds->assocId); + tx_timer_deactivate(&sta_ds->pmfSaQueryTimer); + tx_timer_delete(&sta_ds->pmfSaQueryTimer); + } +} +#endif + +QDF_STATUS lim_strip_supp_op_class_update_struct(tpAniSirGlobal 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; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + uint8_t *buf, tDot11fIEExtCap *dst) +{ + uint8_t out[DOT11F_IE_EXTCAP_MAX_LEN]; + uint32_t status; + + if (NULL == buf) { + pe_err("Invalid Buffer Address"); + return; + } + + if (NULL == 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(tpAniSirGlobal 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; + + /* 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; +} + +/** + * 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_IBSS_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 + * @sesssion: LIM session + * @mac_ctx: Mac context + * + * Return: None + */ +void lim_init_obss_params(tpAniSirGlobal mac_ctx, tpPESession session) +{ + uint32_t cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + &cfg_value) != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve: %x value", + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME); + return; + } + session->obss_ht40_scanparam.obss_active_dwelltime = cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + &cfg_value) != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve: %x value", + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME); + return; + } + session->obss_ht40_scanparam.obss_passive_dwelltime = cfg_value; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + &cfg_value) != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve: %x value", + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL); + return; + } + session->obss_ht40_scanparam.obss_width_trigger_interval = cfg_value; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL, + &cfg_value) != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve: %x value", + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL); + return; + } + session->obss_ht40_scanparam.obss_active_total_per_channel = cfg_value; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL, &cfg_value) + != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve: %x value", + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL); + return; + } + session->obss_ht40_scanparam.obss_passive_total_per_channel = cfg_value; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY, &cfg_value) + != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve: %x value", + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY); + return; + } + session->obss_ht40_scanparam.bsswidth_ch_trans_delay = + cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD, + &cfg_value) != QDF_STATUS_SUCCESS) { + pe_err("Fail to retrieve: %x value", + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD); + return; + } + session->obss_ht40_scanparam.obss_activity_threshold = cfg_value; +} + +/** + * lim_update_obss_scanparams(): Updates OBSS SCAN IE parameters to session + * @sesssion: LIM session + * @scan_params: Scan parameters + * + * Return: None + */ +void lim_update_obss_scanparams(tpPESession 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 > + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMIN) && + (scan_params->obssScanActiveDwell < + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMAX)) + session->obss_ht40_scanparam.obss_active_dwelltime = + scan_params->obssScanActiveDwell; + + if ((scan_params->obssScanPassiveDwell > + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMIN) && + (scan_params->obssScanPassiveDwell < + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMAX)) + session->obss_ht40_scanparam.obss_passive_dwelltime = + scan_params->obssScanPassiveDwell; + + if ((scan_params->bssWidthChannelTransitionDelayFactor > + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMIN) && + (scan_params->bssWidthChannelTransitionDelayFactor < + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMAX)) + session->obss_ht40_scanparam.bsswidth_ch_trans_delay = + scan_params->bssWidthChannelTransitionDelayFactor; + + if ((scan_params->obssScanActiveTotalPerChannel > + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMIN) && + (scan_params->obssScanActiveTotalPerChannel < + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMAX)) + session->obss_ht40_scanparam.obss_active_total_per_channel = + scan_params->obssScanActiveTotalPerChannel; + + if ((scan_params->obssScanPassiveTotalPerChannel > + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMIN) && + (scan_params->obssScanPassiveTotalPerChannel < + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMAX)) + session->obss_ht40_scanparam.obss_passive_total_per_channel = + scan_params->obssScanPassiveTotalPerChannel; + + if ((scan_params->bssChannelWidthTriggerScanInterval > + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMIN) && + (scan_params->bssChannelWidthTriggerScanInterval < + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMAX)) + session->obss_ht40_scanparam.obss_width_trigger_interval = + scan_params->bssChannelWidthTriggerScanInterval; + + if ((scan_params->obssScanActivityThreshold > + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMIN) && + (scan_params->obssScanActivityThreshold < + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMAX)) + session->obss_ht40_scanparam.obss_activity_threshold = + scan_params->obssScanActivityThreshold; + return; +} + +/** + * lim_is_robust_mgmt_action_frame() - Check if action category is + * robust action frame + * @action_category: Action frame category. + * + * This function is used to check if given action category is robust + * action frame. + * + * Return: bool + */ +bool lim_is_robust_mgmt_action_frame(uint8_t action_category) +{ + switch (action_category) { + /* + * NOTE: This function doesn't take care of the DMG + * (Directional Multi-Gigatbit) BSS case as 8011ad + * support is not yet added. In future, if the support + * is required then this function need few more arguments + * and little change in logic. + */ + case SIR_MAC_ACTION_SPECTRUM_MGMT: + case SIR_MAC_ACTION_QOS_MGMT: + case SIR_MAC_ACTION_DLP: + case SIR_MAC_ACTION_BLKACK: + case SIR_MAC_ACTION_RRM: + case SIR_MAC_ACTION_FAST_BSS_TRNST: + case SIR_MAC_ACTION_SA_QUERY: + case SIR_MAC_ACTION_PROT_DUAL_PUB: + case SIR_MAC_ACTION_WNM: + case SIR_MAC_ACITON_MESH: + case SIR_MAC_ACTION_MHF: + case SIR_MAC_ACTION_FST: + return true; + default: + pe_debug("non-PMF action category: %d", action_category); + break; + } + return false; +} + +/** + * 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 doesnot support it + * + * Return: None + */ +void lim_update_caps_info_for_bss(tpAniSirGlobal 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. + * + * @sesssion: LIM session + * @dtim_period: dtim value + * @mac_ctx: Mac context + * @return None + */ +void lim_send_set_dtim_period(tpAniSirGlobal mac_ctx, uint8_t dtim_period, + tpPESession 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) { + pe_err("Unable to allocate memory"); + 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 "MAC_ADDRESS_STR " Seq Number %d", + MAC_ADDR_ARRAY(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; +} + +#ifdef WLAN_FEATURE_11AX +void lim_add_he_cap(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)); +} + +void lim_add_self_he_cap(tpAddStaParams add_sta_params, tpPESession 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)); +} + +/** + * lim_intersect_he_caps() - Intersect peer capability and self capability + * @rcvd_he: pointer to received peer capability + * @session_he: pointer to self capability + * @peer_he: pointer to Intersected capability + * + * Return: None + */ +static void lim_intersect_he_caps(tDot11fIEhe_cap *rcvd_he, + tDot11fIEhe_cap *session_he, + tDot11fIEhe_cap *peer_he) +{ + uint8_t val; + + qdf_mem_copy(peer_he, rcvd_he, sizeof(*peer_he)); + + peer_he->fragmentation &= session_he->fragmentation; + + if (session_he->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->tx_stbc_lt_80mhz) + peer_he->tx_stbc_lt_80mhz = 1; + else + peer_he->tx_stbc_lt_80mhz = 0; + + if (session_he->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->tx_stbc_gt_80mhz) + peer_he->tx_stbc_gt_80mhz = 1; + else + peer_he->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(tpSirAssocReq assoc_req, tpPESession session, + tpDphHashNode sta_ds) +{ + tDot11fIEhe_cap *rcvd_he = &assoc_req->he_cap; + tDot11fIEhe_cap *session_he = &session->he_config; + tDot11fIEhe_cap *peer_he = &sta_ds->he_config; + + if (sta_ds->mlmStaContext.he_capable) + lim_intersect_he_caps(rcvd_he, session_he, peer_he); +} + +void lim_intersect_ap_he_caps(tpPESession session, tpAddBssParams add_bss, + tSchBeaconStruct *beacon, tpSirAssocRsp assoc_rsp) +{ + tDot11fIEhe_cap *rcvd_he; + tDot11fIEhe_cap *session_he = &session->he_config; + tDot11fIEhe_cap *peer_he = &add_bss->staContext.he_config; + + if (beacon) + rcvd_he = &beacon->he_cap; + else + rcvd_he = &assoc_rsp->he_cap; + + lim_intersect_he_caps(rcvd_he, session_he, peer_he); + add_bss->staContext.he_capable = true; +} + +void lim_add_bss_he_cap(tpAddBssParams 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(tpAddBssParams add_bss, tpPESession session) +{ + add_bss->he_sta_obsspd = session->he_sta_obsspd; +} + +void lim_update_stads_he_caps(tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession session_entry) +{ + tDot11fIEhe_cap *he_cap; + + he_cap = &assoc_rsp->he_cap; + sta_ds->mlmStaContext.he_capable = he_cap->present; + + if (!he_cap->present) + return; + + qdf_mem_copy(&sta_ds->he_config, he_cap, sizeof(*he_cap)); + +} + +void lim_update_usr_he_cap(tpAniSirGlobal mac_ctx, tpPESession session) +{ + tSirAddIeParams *add_ie = &session->addIeParams; + 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; + 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); +} + +void lim_decide_he_op(tpAniSirGlobal mac_ctx, tpAddBssParams add_bss, + tpPESession session) +{ + uint32_t val; + uint8_t color; + struct he_ops_network_endian *he_ops_from_ie; + tDot11fIEhe_op *he_ops = &add_bss->he_op; + tSirAddIeParams *add_ie = &session->addIeParams; + 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 { + cds_rand_get_bytes(0, &color, 1); + /* 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->rts_threshold = he_ops_from_ie->rts_threshold; + he_ops->partial_bss_col = he_ops_from_ie->partial_bss_col; + he_ops->tx_bssid_ind = he_ops_from_ie->tx_bssid_ind; + he_ops->bss_col_disabled = he_ops_from_ie->bss_col_disabled; + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(mac_ctx, + WNI_CFG_HE_OPS_BASIC_MCS_NSS, &val)) + val = WNI_CFG_HE_OPS_BASIC_MCS_NSS_DEF; + *((uint16_t *)he_ops->basic_mcs_nss) = (uint16_t)val; + + qdf_mem_copy(&session->he_op, he_ops, sizeof(*he_ops)); + + 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, rts_threshold: 0x%0x", + he_ops->twt_required, he_ops->rts_threshold); + pe_debug("HE Op: partial_bss_color: 0x%0x, Tx BSSID Indicator: 0x%0x", + he_ops->partial_bss_col, he_ops->tx_bssid_ind); + 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)); +} + +void lim_copy_bss_he_cap(tpPESession session, + tpSirSmeStartBssReq sme_start_bss_req) +{ + qdf_mem_copy(&(session->he_config), &(sme_start_bss_req->he_config), + sizeof(session->he_config)); +} + +void lim_copy_join_req_he_cap(tpPESession session, + tpSirSmeJoinReq sme_join_req) +{ + qdf_mem_copy(&(session->he_config), &(sme_join_req->he_config), + sizeof(session->he_config)); + + if (session->ch_width <= CH_WIDTH_80MHZ) { + *(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; + *(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_log_he_cap(tpAniSirGlobal mac, tDot11fIEhe_cap *he_cap) +{ + uint8_t chan_width; + struct ppet_hdr *hdr; + + if (!he_cap->present) + return; + + pe_debug("HE Capabilities:"); + + /* HE MAC capabilities */ + pe_debug("\tHTC-HE conrol: 0x%01x", he_cap->htc_he); + pe_debug("\tTWT Requestor support: 0x%01x", + he_cap->twt_request); + pe_debug("\tTWT Responder support: 0x%01x", + he_cap->twt_responder); + pe_debug("\tFragmentation support: 0x%02x", + he_cap->fragmentation); + pe_debug("\tMax no.of frag MSDUs: 0x%03x", + he_cap->max_num_frag_msdu); + pe_debug("\tMin. frag size: 0x%02x", he_cap->min_frag_size); + pe_debug("\tTrigger MAC pad duration: 0x%02x", + he_cap->trigger_frm_mac_pad); + pe_debug("\tMulti-TID aggr support: 0x%03x", + he_cap->multi_tid_aggr); + pe_debug("\tLink adaptation: 0x%02x", + he_cap->he_link_adaptation); + pe_debug("\tAll ACK support: 0x%01x", he_cap->all_ack); + pe_debug("\tUL MU resp. scheduling: 0x%01x", + he_cap->ul_mu_rsp_sched); + pe_debug("\tA-Buff status report: 0x%01x", he_cap->a_bsr); + pe_debug("\tBroadcast TWT support: 0x%01x", + he_cap->broadcast_twt); + pe_debug("\t32bit BA bitmap support: 0x%01x", + he_cap->ba_32bit_bitmap); + pe_debug("\tMU Cascading support: 0x%01x", + he_cap->mu_cascade); + pe_debug("\tACK enabled Multi-TID: 0x%01x", + he_cap->ack_enabled_multitid); + pe_debug("\tMulti-STA BA in DL MU: 0x%01x", he_cap->dl_mu_ba); + pe_debug("\tOMI A-Control support: 0x%01x", + he_cap->omi_a_ctrl); + pe_debug("\tOFDMA RA support: 0x%01x", he_cap->ofdma_ra); + pe_debug("\tMax A-MPDU Length: 0x%02x", + he_cap->max_ampdu_len); + pe_debug("\tA-MSDU Fragmentation: 0x%01x", + he_cap->amsdu_frag); + pe_debug("\tFlex. TWT sched support: 0x%01x", + he_cap->flex_twt_sched); + pe_debug("\tRx Ctrl frame to MBSS: 0x%01x", + he_cap->rx_ctrl_frame); + pe_debug("\tBSRP A-MPDU Aggregation: 0x%01x", + he_cap->bsrp_ampdu_aggr); + pe_debug("\tQuite Time Period support: 0x%01x", he_cap->qtp); + pe_debug("\tA-BQR support: 0x%01x", he_cap->a_bqr); + pe_debug("\tSR Reponder support: 0x%01x", he_cap->sr_responder); + pe_debug("\tNDP Feedback support: 0x%01x", he_cap->ndp_feedback_supp); + pe_debug("\tOPS support: 0x%01x", he_cap->ops_supp); + pe_debug("\tOPS support: 0x%01x", he_cap->amsdu_in_ampdu); + + /* HE PHY capabilities */ + pe_debug("\tDual band support: 0x%01x", he_cap->dual_band); + 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_debug("\tChannel width support: 0x%07x", chan_width); + pe_debug("\tPreamble puncturing Rx: 0x%04x", + he_cap->rx_pream_puncturing); + pe_debug("\tClass of device: 0x%01x", he_cap->device_class); + pe_debug("\tLDPC coding support: 0x%01x", + he_cap->ldpc_coding); + pe_debug("\tLTF and GI for HE PPDUs: 0x%02x", + he_cap->he_1x_ltf_800_gi_ppdu); + pe_debug("\tMidamble Rx MAX NSTS: 0x%02x", + he_cap->midamble_rx_max_nsts); + pe_debug("\tLTF and GI for NDP: 0x%02x", + he_cap->he_4x_ltf_3200_gi_ndp); + pe_debug("\tSTBC Tx support (<= 80MHz): 0x%01x", + he_cap->tx_stbc_lt_80mhz); + pe_debug("\tSTBC Rx support (<= 80MHz): 0x%01x", + he_cap->rx_stbc_lt_80mhz); + pe_debug("\tDoppler support: 0x%02x", he_cap->doppler); + pe_debug("\tUL MU: 0x%02x", he_cap->ul_mu); + pe_debug("\tDCM encoding Tx: 0x%03x", he_cap->dcm_enc_tx); + pe_debug("\tDCM encoding Tx: 0x%03x", he_cap->dcm_enc_rx); + pe_debug("\tHE MU PPDU payload support: 0x%01x", + he_cap->ul_he_mu); + pe_debug("\tSU Beamformer: 0x%01x", he_cap->su_beamformer); + pe_debug("\tSU Beamformee: 0x%01x", he_cap->su_beamformee); + pe_debug("\tMU Beamformer: 0x%01x", he_cap->mu_beamformer); + pe_debug("\tBeamformee STS for <= 80Mhz: 0x%03x", + he_cap->bfee_sts_lt_80); + pe_debug("\tBeamformee STS for > 80Mhz: 0x%03x", + he_cap->bfee_sts_gt_80); + pe_debug("\tNo. of sounding dim <= 80Mhz: 0x%03x", + he_cap->num_sounding_lt_80); + pe_debug("\tNo. of sounding dim > 80Mhz: 0x%03x", + he_cap->num_sounding_gt_80); + pe_debug("\tNg=16 for SU feedback support: 0x%01x", + he_cap->su_feedback_tone16); + pe_debug("\tNg=16 for MU feedback support: 0x%01x", + he_cap->mu_feedback_tone16); + pe_debug("\tCodebook size for SU: 0x%01x", + he_cap->codebook_su); + pe_debug("\tCodebook size for MU: 0x%01x ", + he_cap->codebook_mu); + pe_debug("\tBeamforming trigger w/ Trigger: 0x%01x", + he_cap->beamforming_feedback); + pe_debug("\tHE ER SU PPDU payload: 0x%01x", + he_cap->he_er_su_ppdu); + pe_debug("\tDL MUMIMO on partial BW: 0x%01x", + he_cap->dl_mu_mimo_part_bw); + pe_debug("\tPPET present: 0x%01x", he_cap->ppet_present); + pe_debug("\tSRP based SR-support: 0x%01x", he_cap->srp); + pe_debug("\tPower boost factor: 0x%01x", he_cap->power_boost); + pe_debug("\t4x HE LTF support: 0x%01x", he_cap->he_ltf_800_gi_4x); + pe_debug("\tSTBC Tx support (> 80MHz): 0x%01x", + he_cap->tx_stbc_gt_80mhz); + pe_debug("\tSTBC Rx support (> 80MHz): 0x%01x", + he_cap->rx_stbc_gt_80mhz); + pe_debug("\tMax Nc: 0x%03x", he_cap->max_nc); + pe_debug("\tER 4x HE LTF support: 0x%01x", he_cap->er_he_ltf_800_gi_4x); + pe_debug("\tER 4x HE LTF support: 0x%01x", + he_cap->he_ppdu_20_in_40Mhz_2G); + pe_debug("\tER 4x HE LTF support: 0x%01x", + he_cap->he_ppdu_20_in_160_80p80Mhz); + pe_debug("\tER 4x HE LTF support: 0x%01x", + he_cap->he_ppdu_80_in_160_80p80Mhz); + pe_debug("\tER 4x HE LTF support: 0x%01x", + he_cap->er_1x_he_ltf_gi); + pe_debug("\tER 4x HE LTF support: 0x%01x", + he_cap->midamble_rx_1x_he_ltf); + pe_debug("\tRx MCS map for <= 80 Mhz: 0x%04x", + he_cap->rx_he_mcs_map_lt_80); + pe_debug("\tTx MCS map for <= 80 Mhz: 0x%04x", + he_cap->tx_he_mcs_map_lt_80); + pe_debug("\tRx MCS map for <= 160 Mhz: 0x%04x", + *((uint16_t *)he_cap->rx_he_mcs_map_160)); + pe_debug("\tTx MCS map for <= 160 Mhz: 0x%04x", + *((uint16_t *)he_cap->tx_he_mcs_map_160)); + pe_debug("\tRx MCS map for <= 80+80 Mhz: 0x%04x", + *((uint16_t *)he_cap->rx_he_mcs_map_80_80)); + pe_debug("\tTx MCS map for <= 80+80 Mhz: 0x%04x", + *((uint16_t *)he_cap->tx_he_mcs_map_80_80)); + + hdr = (struct ppet_hdr *)&he_cap->ppet; + pe_debug("\t ppe_th:: nss_count: %d, ru_idx_msk: %d", + 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(tpAniSirGlobal mac, tDot11fIEhe_op *he_ops) +{ + pe_debug("bss_color: %0x, default_pe_duration: %0x, twt_required: %0x, rts_threshold: %0x, vht_oper_present: %0x", + he_ops->bss_color, he_ops->default_pe, + he_ops->twt_required, he_ops->rts_threshold, + he_ops->vht_oper_present); + pe_debug("\tpartial_bss_color: %0x, MBSSID AP: %0x, Tx BSSID Indicator: %0x, BSS color disabled: %0x", + he_ops->partial_bss_col, he_ops->mbssid_ap, + he_ops->tx_bssid_ind, he_ops->bss_col_disabled); + + pe_debug("he basic mcs nss: 0x%04x", + *((uint16_t *)he_ops->basic_mcs_nss)); + + if (he_ops->vht_oper_present) + pe_debug("VHT Info not present in HE Operation"); + else + pe_debug("VHT Info: chan_width: %d, center_freq0: %d, center_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); +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +void lim_log_he_bss_color(tpAniSirGlobal 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(tpAniSirGlobal mac, + tpAddStaParams add_sta_params, tpDphHashNode sta_ds, + tpPESession session_entry) +{ + if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry)) + add_sta_params->he_capable = sta_ds->mlmStaContext.he_capable; + else + add_sta_params->he_capable = session_entry->he_capable; + + pe_debug("he_capable: %d", add_sta_params->he_capable); +} + +void lim_update_bss_he_capable(tpAniSirGlobal mac, tpAddBssParams 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(tpAniSirGlobal mac, tpPESession session) +{ + session->he_capable = true; + pe_debug("he_capable: %d", session->he_capable); +} + +void lim_update_chan_he_capable(tpAniSirGlobal mac, tpSwitchChannelParams chan) +{ + chan->he_capable = true; + pe_debug("he_capable: %d", chan->he_capable); +} + +void lim_set_he_caps(tpAniSirGlobal mac, tpPESession session, uint8_t *ie_start, + uint32_t num_bytes) +{ + const uint8_t *ie = NULL; + tDot11fIEhe_cap dot11_cap; + struct he_capability_info *he_cap; + + populate_dot11f_he_caps(mac, session, &dot11_cap); + 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 = dot11_cap.max_num_frag_msdu; + 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 = dot11_cap.multi_tid_aggr; + he_cap->he_link_adaptation = dot11_cap.he_link_adaptation; + he_cap->all_ack = dot11_cap.all_ack; + he_cap->ul_mu_rsp_sched = dot11_cap.ul_mu_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->dl_mu_ba = dot11_cap.dl_mu_ba; + he_cap->omi_a_ctrl = dot11_cap.omi_a_ctrl; + he_cap->ofdma_ra = dot11_cap.ofdma_ra; + he_cap->max_ampdu_len = dot11_cap.max_ampdu_len; + 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->sr_responder = dot11_cap.sr_responder; + 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; + he_cap->reserved1 = dot11_cap.reserved1; + + he_cap->dual_band = dot11_cap.dual_band; + + 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_rx_max_nsts = dot11_cap.midamble_rx_max_nsts; + he_cap->he_4x_ltf_3200_gi_ndp = dot11_cap.he_4x_ltf_3200_gi_ndp; + he_cap->tx_stbc_lt_80mhz = dot11_cap.tx_stbc_lt_80mhz; + he_cap->rx_stbc_lt_80mhz = dot11_cap.rx_stbc_lt_80mhz; + he_cap->tx_stbc_gt_80mhz = dot11_cap.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->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_rx_1x_he_ltf = + dot11_cap.midamble_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; + 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); + 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); + } +} + +QDF_STATUS lim_send_he_caps_ie(tpAniSirGlobal mac_ctx, tpPESession session, + uint8_t vdev_id) +{ + uint8_t he_caps[SIR_MAC_HE_CAP_MIN_LEN + 3]; + struct he_capability_info *he_cap; + QDF_STATUS status_5g, status_2g; + + /* Sending only minimal info(no PPET) to FW now, update if required */ + qdf_mem_zero(he_caps, SIR_MAC_HE_CAP_MIN_LEN + 3); + 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, session, he_caps, + SIR_MAC_HE_CAP_MIN_LEN + 3); + he_cap = (struct he_capability_info *) (&he_caps[2 + HE_CAP_OUI_SIZE]); + he_cap->ppet_present = 0; + + status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_CAP, + CDS_BAND_5GHZ, &he_caps[2], + SIR_MAC_HE_CAP_MIN_LEN + 1); + if (QDF_IS_STATUS_ERROR(status_5g)) + pe_err("Unable send HE Cap IE for 5GHZ band, status: %d", + status_5g); + + status_2g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_CAP, + CDS_BAND_2GHZ, &he_caps[2], + SIR_MAC_HE_CAP_MIN_LEN + 1); + 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 + */ +static QDF_STATUS lim_populate_he_mcs_per_bw(tpAniSirGlobal mac_ctx, + uint16_t *self_rx, uint16_t *self_tx, + uint16_t peer_rx, uint16_t peer_tx, uint8_t nss, + uint32_t cfg_rx_param, uint32_t cfg_tx_param) +{ + uint32_t val; + + pe_debug("peer rates: rx_mcs - 0x%04x tx_mcs - 0x%04x", + peer_rx, peer_tx); + if (wlan_cfg_get_int(mac_ctx, cfg_rx_param, &val) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve HE_MCS"); + return QDF_STATUS_E_FAILURE; + } + *self_rx = (uint16_t) val; + if (wlan_cfg_get_int(mac_ctx, cfg_tx_param, &val) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve HE_MCS"); + return QDF_STATUS_E_FAILURE; + } + *self_tx = (uint16_t) val; + + *self_rx = HE_INTERSECT_MCS(*self_rx, peer_tx); + *self_tx = HE_INTERSECT_MCS(*self_tx, peer_rx); + + if (nss == NSS_1x1_MODE) { + *self_rx |= HE_MCS_INV_MSK_4_NSS(1); + *self_tx |= HE_MCS_INV_MSK_4_NSS(1); + } + /* if nss is 2, disable higher NSS */ + if (nss == NSS_2x2_MODE) { + *self_rx |= (HE_MCS_INV_MSK_4_NSS(1) & HE_MCS_INV_MSK_4_NSS(2)); + *self_tx |= (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(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, + tDot11fIEhe_cap *peer_he_caps, + tpPESession session_entry, uint8_t nss) +{ + bool support_2x2 = false; + uint32_t self_sta_dot11mode = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); + + if (!IS_DOT11_MODE_HE(self_sta_dot11mode)) + return QDF_STATUS_SUCCESS; + + if ((peer_he_caps == NULL) || (!peer_he_caps->present)) { + pe_debug("peer not he capable or he_caps NULL"); + return QDF_STATUS_SUCCESS; + } + + pe_debug("peer rates lt 80: rx_mcs - 0x%04x tx_mcs - 0x%04x", + peer_he_caps->rx_he_mcs_map_lt_80, + peer_he_caps->tx_he_mcs_map_lt_80); + pe_debug("peer rates 160: rx_mcs - 0x%04x tx_mcs - 0x%04x", + (*(uint16_t *)peer_he_caps->rx_he_mcs_map_160), + (*(uint16_t *)peer_he_caps->tx_he_mcs_map_160)); + pe_debug("peer rates 80+80: rx_mcs - 0x%04x tx_mcs - 0x%04x", + (*(uint16_t *)peer_he_caps->rx_he_mcs_map_80_80), + (*(uint16_t *)peer_he_caps->tx_he_mcs_map_80_80)); + + if (session_entry && session_entry->nss == NSS_2x2_MODE) { + if (mac_ctx->lteCoexAntShare && + IS_24G_CH(session_entry->currentOperChannel)) { + if (IS_2X2_CHAIN(session_entry->chainMask)) + support_2x2 = true; + else + pe_err("2x2 not enabled %d", + session_entry->chainMask); + } else { + support_2x2 = true; + } + } + + 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, + WNI_CFG_HE_RX_MCS_MAP_LT_80, WNI_CFG_HE_TX_MCS_MAP_LT_80); + 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, + WNI_CFG_HE_RX_MCS_MAP_160, WNI_CFG_HE_TX_MCS_MAP_160); + 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, + WNI_CFG_HE_RX_MCS_MAP_80_80, WNI_CFG_HE_TX_MCS_MAP_80_80); + 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("enable2x2 - %d nss %d", + mac_ctx->roam.configParam.enable2x2, nss); + pe_debug("he_rx_lt_80 - 0x%x he_tx_lt_80 0x%x", + rates->rx_he_mcs_map_lt_80, rates->tx_he_mcs_map_lt_80); + pe_debug("he_rx_160 - 0x%x he_tx_160 0x%x", + rates->rx_he_mcs_map_160, rates->tx_he_mcs_map_160); + pe_debug("he_rx_80_80 - 0x%x he_tx_80_80 0x%x", + rates->rx_he_mcs_map_80_80, rates->tx_he_mcs_map_80_80); + return QDF_STATUS_SUCCESS; +} +#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_blacklist_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 %pM with lowest delta %d", + 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_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx, + struct sir_rssi_disallow_lst *ap_info) +{ + struct sir_rssi_disallow_lst *entry; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + entry = qdf_mem_malloc(sizeof(*entry)); + if (!entry) { + pe_err("malloc failed for bssid entry"); + return; + } + + pe_debug("%pM: assoc resp, expected rssi %d retry delay %d sec and list size %d", + ap_info->bssid.bytes, ap_info->expected_rssi, + ap_info->retry_delay, + qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid)); + + *entry = *ap_info; + entry->time_during_rejection = + qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + + qdf_mutex_acquire(&mac_ctx->roam.rssi_disallow_bssid_lock); + if (qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid) >= + MAX_RSSI_AVOID_BSSID_LIST) { + status = lim_rem_blacklist_entry_with_lowest_delta( + &mac_ctx->roam.rssi_disallow_bssid); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Failed to remove entry with lowest delta"); + } + + if (QDF_IS_STATUS_SUCCESS(status)) + status = qdf_list_insert_back( + &mac_ctx->roam.rssi_disallow_bssid, + &entry->node); + qdf_mutex_release(&mac_ctx->roam.rssi_disallow_bssid_lock); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to enqueue bssid entry"); + qdf_mem_free(entry); + } +} + +void lim_decrement_pending_mgmt_count(tpAniSirGlobal 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); +} + +struct csr_roam_session *lim_get_session_by_macaddr(tpAniSirGlobal mac_ctx, + tSirMacAddr self_mac) +{ + int i = 0; + struct csr_roam_session *session; + + if (!mac_ctx || !self_mac) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Invalid arguments")); + return NULL; + } + + for (i = 0; i < mac_ctx->sme.max_intf_count; i++) { + session = CSR_GET_SESSION(mac_ctx, i); + if (!session) + continue; + else if (!qdf_mem_cmp(&session->selfMacAddr, + self_mac, sizeof(tSirMacAddr))) { + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("session %d exists with mac address " + MAC_ADDRESS_STR), session->sessionId, + MAC_ADDR_ARRAY(self_mac)); + + return session; + } + } + + return NULL; +} + +bool lim_check_if_vendor_oui_match(tpAniSirGlobal 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 (NULL == ie || 0 == ie_len) { + pe_err("IE Null or ie len zero %d", ie_len); + return false; + } + + elem_id = *ie; + + if (elem_id == IE_EID_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, false); + 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; +} + +enum rateid lim_get_min_session_txrate(tpPESession session) +{ + enum rateid rid = RATEID_DEFAULT; + uint8_t min_rate = SIR_MAC_RATE_54, curr_rate, i; + tSirMacRateSet *rateset = &session->rateSet; + + if (!session) + return rid; + + 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); + + 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(tpAniSirGlobal mac_ctx, uint8_t frame_type, + uint8_t *frame, uint32_t frame_len, + uint16_t session_id, uint32_t rx_channel, + tpPESession psession_entry, int8_t rx_rssi) +{ + tpSirSmeMgmtFrameInd sme_mgmt_frame = NULL; + uint16_t length; + + length = sizeof(tSirSmeMgmtFrameInd) + frame_len; + + sme_mgmt_frame = qdf_mem_malloc(length); + if (!sme_mgmt_frame) { + pe_err("AllocateMemory failed for eWNI_SME_LISTEN_RSP"); + return; + } + + if (qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *)(frame + 4)) && + !session_id) { + pe_debug("Broadcast action frame"); + session_id = SME_SESSION_ID_BROADCAST; + } + + sme_mgmt_frame->frame_len = frame_len; + sme_mgmt_frame->sessionId = session_id; + sme_mgmt_frame->frameType = frame_type; + sme_mgmt_frame->rxRssi = rx_rssi; + sme_mgmt_frame->rxChan = rx_channel; + + qdf_mem_zero(sme_mgmt_frame->frameBuf, frame_len); + qdf_mem_copy(sme_mgmt_frame->frameBuf, frame, frame_len); + + 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(tpAniSirGlobal mac_ctx, tpPESession 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); +} + +void lim_process_ap_ecsa_timeout(void *data) +{ + tpPESession session = (tpPESession)data; + tpAniSirGlobal mac_ctx; + uint8_t bcn_int, ch, ch_width; + QDF_STATUS status; + + if (!session || !session->valid) { + pe_err("Session is not valid"); + return; + } + + mac_ctx = (tpAniSirGlobal)session->mac_ctx; + + if (!session->dfsIncludeChanSwIe) { + pe_debug("session->dfsIncludeChanSwIe not set"); + return; + } + + if (session->gLimChannelSwitch.switchCount) { + /* Decrement the beacon switch count */ + session->gLimChannelSwitch.switchCount--; + pe_debug("current beacon count %d", + 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 = session->gLimChannelSwitch.primaryChannel; + ch_width = session->gLimChannelSwitch.ch_width; + if (mac_ctx->sap.SapDfsInfo.dfs_beacon_tx_enhanced) + /* Send Action frame after updating beacon */ + lim_send_chan_switch_action_frame(mac_ctx, ch, ch_width, + session); + + /* Restart the timer */ + if (session->beaconParams.beaconInterval) + bcn_int = session->beaconParams.beaconInterval; + else + bcn_int = WNI_CFG_BEACON_INTERVAL_STADEF; + + 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 { + tSirSmeCSAIeTxCompleteRsp *chan_switch_tx_rsp; + struct scheduler_msg msg = {0}; + uint8_t length = sizeof(*chan_switch_tx_rsp); + + /* 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) { + pe_err("AllocateMemory failed for tSirSmeCSAIeTxCompleteRsp"); + 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)) { + sme_err("Failed to post eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND"); + qdf_mem_free(chan_switch_tx_rsp); + } + } +} + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..393fcc2dd237dc40fde700847fe94ac9022e8e15 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h @@ -0,0 +1,1475 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.h" + +#include "lim_types.h" +#include "lim_scan_result_utils.h" +#include "lim_timer_utils.h" +#include "lim_trace.h" +typedef enum { + ONE_BYTE = 1, + TWO_BYTE = 2 +} eSizeOfLenField; + +#define LIM_STA_ID_MASK 0x00FF +#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 + +/* classifier ID is coded as 0-3: tsid, 4-5:direction */ +#define LIM_MAKE_CLSID(tsid, dir) (((tsid) & 0x0F) | (((dir) & 0x03) << 4)) + +#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) + +#ifdef WLAN_FEATURE_11W +typedef union uPmfSaQueryTimerId { + struct { + uint8_t sessionId; + uint16_t peerIdx; + } fields; + uint32_t value; +} tPmfSaQueryTimerId, *tpPmfSaQueryTimerId; +#endif + +typedef struct last_processed_frame { + tSirMacAddr sa; + uint16_t seq_num; +} last_processed_msg; + +/** + * struct lim_max_tx_pwr_attr - List of tx powers from various sources + * @reg_max: power from regulatory database + * @ap_tx_power: local power constraint adjusted value + * @ini_tx_power: Max tx power from ini config + * @frequency: current operating frequency for which above powers are defined + */ +struct lim_max_tx_pwr_attr { + int8_t reg_max; + int8_t ap_tx_power; + uint8_t ini_tx_power; + uint32_t frequency; +}; + +/* 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); +void limGetBssidFromPkt(tpAniSirGlobal, uint8_t *, uint8_t *, uint32_t *); +char *lim_dot11_reason_str(uint16_t reasonCode); +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(tpAniSirGlobal pMac, uint8_t dot11Mode); +void lim_print_mlm_state(tpAniSirGlobal pMac, uint16_t logLevel, + tLimMlmStates state); +void lim_print_sme_state(tpAniSirGlobal pMac, uint16_t logLevel, + tLimSmeStates state); +void lim_print_msg_name(tpAniSirGlobal pMac, uint16_t logLevel, uint32_t msgType); + +extern QDF_STATUS lim_send_set_max_tx_power_req(tpAniSirGlobal pMac, + int8_t txPower, + tpPESession pSessionEntry); +uint8_t lim_is_addr_bc(tSirMacAddr); +uint8_t lim_is_group_addr(tSirMacAddr); + +/** + * lim_get_max_tx_power() - Utility to get maximum tx power + * @mac: mac handle + * @attr: pointer to buffer 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(tpAniSirGlobal mac, + struct lim_max_tx_pwr_attr *attr); + +/* AID pool management functions */ +void lim_init_peer_idxpool(tpAniSirGlobal, tpPESession); +uint16_t lim_assign_peer_idx(tpAniSirGlobal, tpPESession); + +void lim_enable_overlap11g_protection(tpAniSirGlobal pMac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, + tpPESession psessionEntry); +void lim_update_overlap_sta_param(tpAniSirGlobal pMac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams); +void lim_update_short_preamble(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +void lim_update_short_slot_time(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); + +/* + * 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 + * @session_id : session id + * @psession_entry : PE Session Entry + * @rx_channel : Channel of where packet is received + * @rx_rssi : rssi value + * + * 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(tpAniSirGlobal mac_ctx, uint8_t frame_type, + uint8_t *frame, uint32_t frame_len, + uint16_t session_id, uint32_t rx_channel, + tpPESession psession_entry, int8_t rx_rssi); + +/* + * 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(tpAniSirGlobal mac_ctx); + +/* + * The below 'product' check tobe removed if 'Association' is + * allowed in IBSS. + */ +void lim_release_peer_idx(tpAniSirGlobal, uint16_t, tpPESession); + +void lim_decide_ap_protection(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, tpPESession); +void lim_decide_ap_protection_on_delete(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); + +extern QDF_STATUS lim_update_11a_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession); +extern QDF_STATUS lim_enable11g_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +extern QDF_STATUS lim_enable_ht_protection_from11g(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + tpPESession psessionEntry); +extern QDF_STATUS lim_enable_ht20_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession sessionEntry); +extern QDF_STATUS lim_enable_ht_non_gf_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +extern QDF_STATUS lim_enable_ht_rifs_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + tpPESession psessionEntry); +extern QDF_STATUS lim_enable_ht_lsig_txop_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +extern QDF_STATUS lim_enable_short_preamble(tpAniSirGlobal pMac, + uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +extern QDF_STATUS lim_enable_ht_obss_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +void lim_decide_sta_protection(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +void lim_decide_sta_protection_on_assoc(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpPESession psessionEntry); +void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + uint8_t bssIdx, + tpPESession psessionEntry); +/* Print MAC address utility function */ +void lim_print_mac_addr(tpAniSirGlobal, tSirMacAddr, uint8_t); + +/* Deferred Message Queue read/write */ +uint8_t lim_write_deferred_msg_q(tpAniSirGlobal pMac, + struct scheduler_msg *limMsg); +struct scheduler_msg *lim_read_deferred_msg_q(tpAniSirGlobal pMac); +void lim_handle_defer_msg_error(tpAniSirGlobal pMac, + struct scheduler_msg *pLimMsg); + +/* Deferred Message Queue Reset */ +void lim_reset_deferred_msg_q(tpAniSirGlobal pMac); + +QDF_STATUS lim_sys_process_mmh_msg_api(tpAniSirGlobal, + struct scheduler_msg *, uint8_t); + +void lim_handle_update_olbc_cache(tpAniSirGlobal pMac); + +uint8_t lim_is_null_ssid(tSirMacSSid *pSsid); + +/* 11h Support */ +void lim_stop_tx_and_switch_channel(tpAniSirGlobal pMac, uint8_t sessionId); +void lim_process_channel_switch_timeout(tpAniSirGlobal); +QDF_STATUS lim_start_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_update_channel_switch(tpAniSirGlobal, tpSirProbeRespBeacon, + tpPESession psessionEntry); +void lim_process_quiet_timeout(tpAniSirGlobal); +void lim_process_quiet_bss_timeout(tpAniSirGlobal); + +void lim_start_quiet_timer(tpAniSirGlobal pMac, uint8_t sessionId); +void lim_switch_primary_channel(tpAniSirGlobal, uint8_t, tpPESession); +void lim_switch_primary_secondary_channel(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t newChannel, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width); +void limUpdateStaRunTimeHTSwtichChnlParams(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pRcvdHTInfo, + uint8_t bssIdx); +void lim_update_sta_run_time_ht_capability(tpAniSirGlobal pMac, + tDot11fIEHTCaps *pHTCaps); +void lim_update_sta_run_time_ht_info(struct sAniSirGlobal *pMac, + tDot11fIEHTInfo *pRcvdHTInfo, + tpPESession psessionEntry); +void lim_cancel_dot11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_cancel_dot11h_quiet(tpAniSirGlobal pMac, tpPESession psessionEntry); +bool lim_is_channel_valid_for_channel_switch(tpAniSirGlobal pMac, + uint8_t channel); +void lim_frame_transmission_control(tpAniSirGlobal pMac, tLimQuietTxMode type, + tLimControlTx mode); +QDF_STATUS lim_restore_pre_channel_switch_state(tpAniSirGlobal pMac, + tpPESession psessionEntry); +QDF_STATUS lim_restore_pre_quiet_state(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +void lim_prepare_for11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_switch_channel_cback(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); + +/** + * 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_blacklist_entry_with_lowest_delta() - Remove the entry with lowest + * time delta + * @list: rssi based rejected BSSID list + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_rem_blacklist_entry_with_lowest_delta(qdf_list_t *list); + +/** + * lim_get_session_by_macaddr() - api to find session based on MAC + * @mac_ctx: Pointer to global mac structure. + * @self_mac: MAC address. + * + * This function is used to get session for given MAC address. + * + * Return: session pointer if exists, NULL otherwise. + */ +struct csr_roam_session *lim_get_session_by_macaddr(tpAniSirGlobal mac_ctx, + tSirMacAddr self_mac); + +static inline enum band_info lim_get_rf_band(uint8_t channel) +{ + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + return BAND_5G; + + if ((channel >= SIR_11B_CHANNEL_BEGIN) && + (channel <= SIR_11B_CHANNEL_END)) + return BAND_2G; + + return BAND_UNKNOWN; +} + +static inline QDF_STATUS +lim_get_mgmt_staid(tpAniSirGlobal pMac, uint16_t *staid, + tpPESession psessionEntry) +{ + if (LIM_IS_AP_ROLE(psessionEntry)) + *staid = 1; + else if (LIM_IS_STA_ROLE(psessionEntry)) + *staid = 0; + else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +static inline uint8_t lim_is_system_in_set_mimops_state(tpAniSirGlobal pMac) +{ + if (pMac->lim.gLimMlmState == eLIM_MLM_WT_SET_MIMOPS_STATE) + return true; + return false; +} + +static inline uint8_t +is_entering_mimo_ps(tSirMacHTMIMOPowerSaveState curState, + tSirMacHTMIMOPowerSaveState newState) +{ + if (curState == eSIR_HT_MIMO_PS_NO_LIMIT && + (newState == eSIR_HT_MIMO_PS_DYNAMIC + || newState == eSIR_HT_MIMO_PS_STATIC)) + return true; + return false; +} + +static inline int lim_select_cb_mode(tDphHashNode *pStaDs, + tpPESession psessionEntry, uint8_t channel, + uint8_t chan_bw) +{ + if (pStaDs->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 (pStaDs->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(tpAniSirGlobal pMac, tpDphHashNode pSta, + tpPESession psessionEntry); +void lim_util_count_sta_del(tpAniSirGlobal pMac, tpDphHashNode pSta, + tpPESession psessionEntry); + +uint8_t lim_get_ht_capability(tpAniSirGlobal, uint32_t, tpPESession); +QDF_STATUS lim_tx_complete(void *context, qdf_nbuf_t buf, bool free); + +/** + * This function will be registered with HAL for callback when TSPEC inactivity + * timer fires. + */ + +void lim_process_del_ts_ind(tpAniSirGlobal pMac, struct scheduler_msg *limMsg); +QDF_STATUS lim_process_hal_ind_messages(tpAniSirGlobal pMac, uint32_t mesgId, + void *mesgParam); +QDF_STATUS lim_validate_delts_req(tpAniSirGlobal pMac, + tpSirDeltsReq pDeltsReq, + tSirMacAddr peerMacAddr, + tpPESession psessionEntry); + +/* callback function registration to HAL for any indication. */ +void lim_register_hal_ind_call_back(tpAniSirGlobal pMac); +void lim_pkt_free(tpAniSirGlobal pMac, + eFrameType frmType, uint8_t *pBD, void *body); + +void lim_get_b_dfrom_rx_packet(tpAniSirGlobal pMac, 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(tpAniSirGlobal pMac, + uint16_t StaIdx, + tSirMacHTMIMOPowerSaveState MIMOPSState, + uint8_t *pPeerStaMac, uint8_t sessionId); + +void lim_delete_sta_context(tpAniSirGlobal pMac, struct scheduler_msg *limMsg); +void lim_delete_dialogue_token_list(tpAniSirGlobal pMac); + +/** + * lim_add_channel_status_info() - store + * chan status info into Global MAC structure + * @p_mac: Pointer to Global MAC structure + * @channel_stat: Pointer to chan status info reported by firmware + * @channel_id: current channel id + * + * Return: None + */ +void lim_add_channel_status_info(tpAniSirGlobal p_mac, + struct lim_channel_status *channel_stat, + uint8_t channel_id); +uint8_t lim_get_channel_from_beacon(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon); +tSirNwType lim_get_nw_type(tpAniSirGlobal pMac, uint8_t channelNum, + uint32_t type, tpSchBeaconStruct pBeacon); + +void lim_set_tspec_uapsd_mask_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacTSInfo *pTsInfo, uint32_t action); + +void lim_handle_heart_beat_timeout_for_session(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +void lim_process_add_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *pMsgQ); + +void lim_update_beacon(tpAniSirGlobal pMac); + +void lim_process_ap_mlm_add_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry); +void lim_process_ap_mlm_del_bss_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry); + +void lim_process_ap_mlm_del_sta_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ, + tpPESession psessionEntry); + +tpPESession lim_is_ibss_session_active(tpAniSirGlobal pMac); +tpPESession lim_is_ap_session_active(tpAniSirGlobal pMac); +void lim_handle_heart_beat_failure_timeout(tpAniSirGlobal pMac); + +#define limGetWscIEPtr(pMac, ie, ie_len) \ + wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_WSC_OUI, \ + SIR_MAC_WSC_OUI_SIZE, ie, ie_len) + +#define limGetP2pIEPtr(pMac, 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_in_mult_p2p_ies(tpAniSirGlobal pMac, + uint8_t *noaStream, uint8_t noaLen, + uint8_t overFlowLen); +uint8_t lim_get_noa_attr_stream(tpAniSirGlobal pMac, uint8_t *pNoaStream, + tpPESession psessionEntry); + +uint8_t lim_build_p2p_ie(tpAniSirGlobal pMac, uint8_t *ie, uint8_t *data, + uint8_t ie_len); +bool lim_is_noa_insert_reqd(tpAniSirGlobal pMac); +bool lim_isconnected_on_dfs_channel(tpAniSirGlobal mac_ctx, + uint8_t currentChannel); +uint8_t lim_get_current_operating_channel(tpAniSirGlobal pMac); +uint32_t lim_get_max_rate_flags(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds); + +bool lim_check_vht_op_mode_change(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t chanWidth, uint8_t staId, + uint8_t *peerMac); +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +bool lim_send_he_ie_update(tpAniSirGlobal mac_ctx, tpPESession pe_session); +#endif +bool lim_set_nss_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t rxNss, uint8_t staId, uint8_t *peerMac); +bool lim_check_membership_user_position(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t membership, uint32_t userPosition, + uint8_t staId); + +/** + * 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(tpAniSirGlobal pMac, uint16_t eventType, + tpPESession pSessionEntry, 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(tpAniSirGlobal mac_ctx, void *mgmt_hdr, + tpPESession 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(tpAniSirGlobal mac_ctx, void *mgmt_hdr, + tpPESession session, uint16_t result_code, + uint16_t reason_code); +#else +static inline void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t + eventType, tpPESession pSessionEntry, uint16_t status, + uint16_t reasonCode) {} +void lim_diag_mgmt_tx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, + tpPESession session, uint16_t result_code, + uint16_t reason_code) {} +void lim_diag_mgmt_rx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, + tpPESession session, uint16_t result_code, + uint16_t reason_code) {} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +void pe_set_resume_channel(tpAniSirGlobal pMac, uint16_t channel, + ePhyChanBondState cbState); + +void lim_get_short_slot_from_phy_mode(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t phyMode, uint8_t *pShortSlotEnable); + +void lim_clean_up_disassoc_deauth_req(tpAniSirGlobal pMac, uint8_t *staMac, + bool cleanRxPath); + +bool lim_check_disassoc_deauth_ack_pending(tpAniSirGlobal pMac, + uint8_t *staMac); + +#ifdef WLAN_FEATURE_11W +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param); +void lim_set_protected_bit(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr); +#else +static inline void lim_set_protected_bit(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr) {} +#endif /* WLAN_FEATURE_11W */ + +void lim_set_ht_caps(tpAniSirGlobal p_mac, + tpPESession p_session_ntry, + uint8_t *p_ie_start, + uint32_t num_bytes); + +void lim_set_vht_caps(tpAniSirGlobal p_mac, + tpPESession p_session_entry, + uint8_t *p_ie_start, + uint32_t num_bytes); +bool lim_validate_received_frame_a1_addr(tpAniSirGlobal mac_ctx, + tSirMacAddr a1, tpPESession session); +void lim_set_stads_rtt_cap(tpDphHashNode sta_ds, struct s_ext_cap *ext_cap, + tpAniSirGlobal mac_ctx); + +void lim_check_and_reset_protection_params(tpAniSirGlobal mac_ctx); + +QDF_STATUS lim_send_ext_cap_ie(tpAniSirGlobal mac_ctx, uint32_t session_id, + tDot11fIEExtCap *extracted_extcap, bool merge); + +QDF_STATUS lim_send_ies_per_band(tpAniSirGlobal mac_ctx, + tpPESession session, uint8_t vdev_id); + +QDF_STATUS lim_strip_extcap_ie(tpAniSirGlobal mac_ctx, uint8_t *addn_ie, + uint16_t *addn_ielen, uint8_t *extracted_extcap); +void lim_update_extcap_struct(tpAniSirGlobal mac_ctx, uint8_t *buf, + tDot11fIEExtCap *ext_cap); +QDF_STATUS lim_strip_extcap_update_struct(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, tDot11fIEExtCap *dst); +void lim_merge_extcap_struct(tDot11fIEExtCap *dst, tDot11fIEExtCap *src, + bool add); + +#ifdef WLAN_FEATURE_11W +/** + * 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(tpAniSirGlobal mac_ctx, tpPESession pe_session); +#else +/** + * 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 + */ +static inline void +lim_del_pmf_sa_query_timer(tpAniSirGlobal mac_ctx, tpPESession pe_session) +{ +} +#endif + +/** + * 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(tpAniSirGlobal 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(tpPESession session, + tDot11fIEOBSSScanParameters *scan_params); +void lim_init_obss_params(tpAniSirGlobal mac_ctx, tpPESession session); +#ifdef WLAN_FEATURE_HOST_ROAM +uint32_t lim_create_timers_host_roam(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx); +void lim_deactivate_and_change_timer_host_roam(tpAniSirGlobal mac_ctx, + uint32_t timer_id); +#else +static inline uint32_t lim_create_timers_host_roam(tpAniSirGlobal mac_ctx) +{ + return 0; +} +static inline void lim_delete_timers_host_roam(tpAniSirGlobal mac_ctx) +{} +static inline void lim_deactivate_timers_host_roam(tpAniSirGlobal mac_ctx) {} +static inline void lim_deactivate_and_change_timer_host_roam( + tpAniSirGlobal mac_ctx, uint32_t timer_id) +{} +#endif + +bool lim_is_robust_mgmt_action_frame(uint8_t action_category); +uint8_t lim_compute_ext_cap_ie_length(tDot11fIEExtCap *ext_cap); + +/** + * lim_p2p_action_cnf() - callback to indicate Tx completion + * @mac_ctx: pointer to mac structure + * @buf: buffer + * @tx_complete_success: 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 + */ +QDF_STATUS lim_p2p_action_cnf(void *mac_ctx, qdf_nbuf_t buf, + uint32_t tx_complete_success, void *params); +void lim_update_caps_info_for_bss(tpAniSirGlobal mac_ctx, + uint16_t *caps, uint16_t bss_caps); +void lim_send_set_dtim_period(tpAniSirGlobal mac_ctx, uint8_t dtim_period, + tpPESession session); + +QDF_STATUS lim_strip_ie(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, eSizeOfLenField 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 + * + * Return: None + */ +void lim_intersect_ap_he_caps(tpPESession session, tpAddBssParams add_bss, + tSchBeaconStruct *pBeaconStruct, tpSirAssocRsp assoc_rsp); + +/** + * lim_intersect_sta_he_caps() - Intersect STA capability with SAP capability + * @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(tpSirAssocReq assoc_req, tpPESession session, + tpDphHashNode sta_ds); + +/** + * lim_add_he_cap() - Copy HE capability into Add sta params + * @add_sta_params: pointer to add sta params + * @assoc_req: pointer to Assoc request + * + * Return: None + */ +void lim_add_he_cap(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, tpPESession 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(tpAddBssParams 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(tpAddBssParams add_bss, tpPESession session); + +/** + * lim_copy_bss_he_cap() - Copy HE capability into PE session from start bss + * @session: pointer to PE session + * @sme_start_bss_req: pointer to start BSS request + * + * Return: None + */ +void lim_copy_bss_he_cap(tpPESession session, + tpSirSmeStartBssReq sme_start_bss_req); + +/** + * 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 + * @sme_join_req: pointer to SME join request + * + * Return: None + */ +void lim_copy_join_req_he_cap(tpPESession session, + tpSirSmeJoinReq sme_join_req); + +/** + * lim_log_he_op() - Print HE Operation + * @mac: pointer to MAC context + * @he_op: pointer to HE Operation + * + * Print HE operation stored as dot11f structure + * + * Return: None + */ +void lim_log_he_op(tpAniSirGlobal mac, tDot11fIEhe_op *he_ops); + +#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(tpAniSirGlobal 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(tpAniSirGlobal mac, tDot11fIEhe_cap *he_cap); + +/** + * lim_update_stads_he_caps() - Copy HE capability into STA DPH hash table entry + * @sta_ds: pointer to sta dph hash table entry + * @assoc_rsp: pointer to assoc response + * @session_entry: pointer to PE session + * + * Return: None + */ +void lim_update_stads_he_caps(tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession session_entry); + +/** + * 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(tpAniSirGlobal mac_ctx, tpPESession session); + +/** + * lim_decide_he_op() - Determine HE operation elements + * @mac_ctx: global mac context + * @he_ops: pointer to HE operation IE + * @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(tpAniSirGlobal mac_ctx, tpAddBssParams add_bss, + tpPESession 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(tpAniSirGlobal mac, + tpAddStaParams add_sta_params, tpDphHashNode sta_ds, + tpPESession session_entry); + +static inline bool lim_is_session_he_capable(tpPESession session) +{ + return session->he_capable; +} + +/** + * 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(tpPESession 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(tpAniSirGlobal mac, tpAddBssParams 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(tpAniSirGlobal mac, tpPESession session); + +/** + * lim_update_chan_he_capable(): Update he_capable in chan switch params + * @mac: pointer to MAC context + * @chan: pointer to channel switch params + * + * Return: None + */ +void lim_update_chan_he_capable(tpAniSirGlobal mac, tpSwitchChannelParams chan); + +/** + * lim_set_he_caps() - update HE caps to be sent to FW as part of scan IE + * @mac: pointer to MAC + * @session: pointer to PE session + * @ie_start: pointer to start of IE buffer + * @num_bytes: length of IE buffer + * + * Return: None + */ +void lim_set_he_caps(tpAniSirGlobal mac, tpPESession session, + uint8_t *ie_start, uint32_t num_bytes); + +/** + * lim_send_he_caps_ie() - gets HE capability and send to firmware via wma + * @mac_ctx: global mac context + * @session: pe session. This can be NULL. In that case self cap will be sent + * @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(tpAniSirGlobal mac_ctx, tpPESession session, + uint8_t vdev_id); + +/** + * 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 + * + * Populates HE mcs rate set based on peer and self capabilities + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_populate_he_mcs_set(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, tDot11fIEhe_cap *peer_he_caps, + tpPESession session_entry, uint8_t nss); + +#else +static inline void lim_add_he_cap(tpAddStaParams add_sta_params, + tpSirAssocReq assoc_req) +{ +} + +static inline void lim_add_self_he_cap(tpAddStaParams add_sta_params, + tpPESession session) +{ +} + +static inline void lim_add_bss_he_cap(tpAddBssParams add_bss, + tpSirAssocRsp assoc_rsp) +{ + return; +} + +static inline void lim_add_bss_he_cfg(tpAddBssParams add_bss, + tpPESession session) +{ +} + +static inline void lim_intersect_ap_he_caps(tpPESession session, + tpAddBssParams add_bss, tSchBeaconStruct *pBeaconStruct, + tpSirAssocRsp assoc_rsp) +{ + return; +} + +static inline void lim_intersect_sta_he_caps(tpSirAssocReq assoc_req, + tpPESession session, tpDphHashNode sta_ds) +{ +} + +static inline void lim_update_stads_he_caps(tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession session_entry) +{ + return; +} + +static inline void lim_update_usr_he_cap(tpAniSirGlobal mac_ctx, + tpPESession session) +{ +} + +static inline void lim_decide_he_op(tpAniSirGlobal mac_ctx, + tpAddBssParams add_bss, tpPESession session) +{ +} + +static inline void lim_copy_bss_he_cap(tpPESession session, + tpSirSmeStartBssReq sme_start_bss_req) +{ +} + +static inline void lim_copy_join_req_he_cap(tpPESession session, + tpSirSmeJoinReq sme_join_req) +{ +} + +static inline void lim_log_he_op(tpAniSirGlobal mac, + tDot11fIEhe_op *he_ops) +{ +} + +static inline void lim_log_he_cap(tpAniSirGlobal mac, + tDot11fIEhe_cap *he_cap) +{ +} + +static inline void lim_update_sta_he_capable(tpAniSirGlobal mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, tpPESession session_entry) +{ +} + +static inline bool lim_is_session_he_capable(tpPESession session) +{ + return false; +} + +static inline uint8_t lim_get_session_he_frag_cap(tpPESession session) +{ + return 0; +} + +static inline bool lim_is_sta_he_capable(tpDphHashNode sta_ds) +{ + return false; +} + +static inline void lim_update_bss_he_capable(tpAniSirGlobal mac, + tpAddBssParams add_bss) +{ +} + +static inline void lim_update_stads_he_capable(tpDphHashNode sta_ds, + tpSirAssocReq assoc_req) +{ +} + +static inline void lim_update_session_he_capable(tpAniSirGlobal mac, + tpPESession session) +{ +} + +static inline void lim_update_chan_he_capable(tpAniSirGlobal mac, + tpSwitchChannelParams chan) +{ +} + +static inline void lim_set_he_caps(tpAniSirGlobal mac, tpPESession session, + uint8_t *ie_start, uint32_t num_bytes) +{ +} + +static inline QDF_STATUS lim_send_he_caps_ie(tpAniSirGlobal mac_ctx, + tpPESession session, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS lim_populate_he_mcs_set(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, + tDot11fIEhe_cap *peer_he_caps, + tpPESession session_entry, uint8_t nss) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + +/** + * lim_assoc_rej_add_to_rssi_based_reject_list() - Add BSSID to the rssi based + * rejection list + * @mac_ctx: mac ctx + * @ap_info: ap's info which is to be rejected. + * + * Add BSSID to the rssi based rejection list. Also if number + * of entries is greater than MAX_RSSI_AVOID_BSSID_LIST + * remove the entry with lowest time delta + * + * Return: void + */ +void lim_assoc_rej_add_to_rssi_based_reject_list(tpAniSirGlobal mac_ctx, + struct sir_rssi_disallow_lst *ap_info); + +/** + * 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(tpAniSirGlobal 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(tpAniSirGlobal 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 + * + * 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(tpPESession session); + +/** + * 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(tpAniSirGlobal mac_ctx, + tpPESession 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_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: new channel to switch to. + * @ch_bandwidth: BW of channel to calculate op_class + * @session_entry: pe session + * + * Return: void + */ +void lim_send_chan_switch_action_frame(tpAniSirGlobal mac_ctx, + uint16_t new_channel, + uint8_t ch_bandwidth, + tpPESession 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession session); + +#ifdef WLAN_SUPPORT_TWT +void lim_set_peer_twt_cap(tpPESession session, struct s_ext_cap *ext_cap); +#else +static inline void lim_set_peer_twt_cap(tpPESession session, + struct s_ext_cap *ext_cap) +{ +} +#endif + +#endif /* __LIM_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c new file mode 100644 index 0000000000000000000000000000000000000000..02437d2dca6ebe49022c48f74897fa0dda5f080b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c @@ -0,0 +1,536 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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(tpAniSirGlobal mac_ctx, + uint32_t vdev_id, struct qdf_mac_addr peer_mac_addr) +{ + tpPESession 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 (!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_sme_session_id(mac_ctx, + vdev_id); + if (session == NULL) { + /* 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 != NULL) { + pe_err("NDI Peer already exists!!"); + return QDF_STATUS_SUCCESS; + } + pe_info("Need to create NDI Peer :" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_mac_addr.bytes)); + + 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 == NULL) { + pe_err("Couldn't add dph entry"); + /* couldn't add dph entry */ + return QDF_STATUS_E_FAILURE; + } + + /* wma decides NDI mode from wma->inferface 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) +{ + tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, uint8_t vdev_id, + struct qdf_mac_addr peer_ndi_mac_addr) +{ + tpPESession 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: "MAC_ADDRESS_STR" confirm rejected", + MAC_ADDR_ARRAY(peer_ndi_mac_addr.bytes)); + + session = pe_find_session_by_sme_session_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) +{ + tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + struct peer_ndp_map *ndp_map, uint8_t num_peers) +{ + tpDphHashNode sta_ds = NULL; + uint16_t deleted_num = 0; + int i, j; + tpPESession 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) { + pe_err("Memory allocation failed"); + return; + } + + for (i = 0; i < num_peers; i++) { + pe_info("ndp_map[%d]: MAC: " MAC_ADDRESS_STR " num_active %d", + i, + MAC_ADDR_ARRAY(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_sme_session_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) +{ + tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg, + tpPESession 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 staId %d MAC " MAC_ADDRESS_STR, + sta_ds->assocId, sta_ds->staIndex, + MAC_ADDR_ARRAY(sta_ds->staAddr)); + + /* + * Copy peer info in del peer indication before + * lim_delete_dph_hash_entry is called as this will be lost. + */ + peer_ind.sta_id = sta_ds->staIndex; + 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_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; +} + +/** + * lim_process_ndi_mlm_add_bss_rsp() - Process ADD_BSS response for NDI + * @mac_ctx: Pointer to Global MAC structure + * @lim_msgq: The MsgQ header, which contains the response buffer + * @session_entry: PE session + * + * Return: None + */ +void lim_process_ndi_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msgq, + tpPESession session_entry) +{ + tLimMlmStartCnf mlm_start_cnf; + tpAddBssParams add_bss_params = (tpAddBssParams) lim_msgq->bodyptr; + + if (NULL == add_bss_params) { + pe_err("Invalid body pointer in message"); + goto end; + } + pe_debug("Status %d", add_bss_params->status); + if (QDF_STATUS_SUCCESS == add_bss_params->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->bssIdx = (uint8_t) add_bss_params->bssIdx; + session_entry->limSystemRole = eLIM_NDI_ROLE; + session_entry->statypeForBss = STA_ENTRY_SELF; + session_entry->staId = add_bss_params->staContext.staIdx; + /* 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_params->status); + mlm_start_cnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + mlm_start_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); +end: + qdf_mem_free(lim_msgq->bodyptr); + lim_msgq->bodyptr = NULL; +} + +/** + * lim_ndi_del_bss_rsp() - Handler for DEL BSS resp for NDI interface + * @mac_ctx: handle to mac structure + * @msg: pointer to message + * @session_entry: session entry + * + * Return: None + */ +void lim_ndi_del_bss_rsp(tpAniSirGlobal mac_ctx, + void *msg, tpPESession session_entry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + tpDeleteBssParams del_bss = (tpDeleteBssParams) msg; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + if (del_bss == NULL) { + pe_err("NDI: DEL_BSS_RSP with no body!"); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + session_entry = + pe_find_session_by_session_id(mac_ctx, del_bss->sessionId); + 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) Bss %d", + del_bss->status, del_bss->bssIdx); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, + session_entry->selfMacAddr, + session_entry->selfMacAddr, NULL, NULL) + != QDF_STATUS_SUCCESS) { + pe_err("NDI: DEL_BSS_RSP setLinkState failed"); + goto end; + } + + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + +end: + if (del_bss) + qdf_mem_free(del_bss); + /* Delete PE session once BSS is deleted */ + if (NULL != session_entry) { + lim_send_sme_rsp(mac_ctx, eWNI_SME_STOP_BSS_RSP, + rc, session_entry->smeSessionId, + session_entry->transactionId); + pe_delete_session(mac_ctx, session_entry); + session_entry = NULL; + } +} + +static QDF_STATUS lim_send_sme_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, + tpPESession 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) { + pe_err("Failed to allocate memory"); + 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)); + new_peer_ind->sta_id = add_sta_rsp->staIdx; + + ucfg_nan_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(tpAniSirGlobal mac_ctx, tpPESession session, + tAddStaParams *add_sta_rsp) +{ + tpDphHashNode sta_ds; + uint16_t peer_idx; + + if (NULL == 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 == NULL) { + pe_err("NAN: ADD_STA_RSP for unknown MAC addr " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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: %pM", + add_sta_rsp->status, 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->bssId = add_sta_rsp->bssIdx; + sta_ds->staIndex = add_sta_rsp->staIdx; + 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/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..b13a4fd84bb3ab6aee3fa0a26344e79880f447d4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 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. + */ + +/** + * DOC: nan_datapath.h + * + * MAC NAN Data path API specification + */ + +#ifndef __MAC_NAN_DATAPATH_H +#define __MAC_NAN_DATAPATH_H + +#if defined(WLAN_FEATURE_NAN_DATAPATH) || defined(WLAN_FEATURE_NAN_CONVERGENCE) + +#include "sir_common.h" +#include "ani_global.h" +#include "sir_params.h" + +struct peer_nan_datapath_map; + +/** + * struct ndp_peer_node - structure for holding per-peer context + * @next: pointer to the next peer + * @peer_mac_addr: peer mac address + * @ext_rates_present: extended rates supported + * @edca_present: edca supported + * @wme_edca_present: WME EDCA supported + * @wme_info_present: WME info supported + * @ht_capable: HT capable + * @vht_capable: VHT capabale + * @ht_sec_chan_offset: HT secondary channel offset + * @capability_info: Generic capability info + * @supported_rates: Supported rates + * @extended_rates: Supported extended rates + * @supported_mcs_rate: Supported MCS rates + * @edca_params: EDCA parameters + * @erp_ie_present: ERP IE supported + * @ht_green_field: HT green field supported + * @ht_shortGI_40Mhz; 40 MHZ short GI support + * @ht_shortGI_20Mhz; 20 MHZ short GI support + * @ht_mimo_ps_state: MIMO power state + * @ht_ampdu_density: AMPDU density + * @ht_max_rxampdu_factor: receieve AMPDU factor + * @ht_max_amsdu_len: Max AMSDU length supported + * @ht_supp_chan_widthset: Supported channel widthset + * @ht_ldpc_capable: LDPC capable + * @heartbeat_failure: heart beat failure indication flag + * @vht_caps: VHT capability + * @vht_supp_chanwidth_set: VHT supported channel width + * @vht_beamformer_capable: Beam former capable + */ +struct ndp_peer_node { + struct ndp_peer_node *next; + struct qdf_mac_addr peer_mac_addr; + uint8_t ext_rates_present; + uint8_t edca_present; + uint8_t wme_edca_present; + uint8_t wme_info_present; + uint8_t ht_capable; + uint8_t vht_capable; + uint8_t ht_sec_chan_offset; + tSirMacCapabilityInfo capability_info; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + uint8_t supported_mcs_rate[SIZE_OF_SUPPORTED_MCS_SET]; + tSirMacEdcaParamSetIE edca_params; + uint8_t erp_ie_present; + uint8_t ht_green_field; + uint8_t ht_shortGI_40Mhz; + uint8_t ht_shortGI_20Mhz; + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState ht_mimo_ps_state; + uint8_t ht_ampdu_density; + /* Maximum Rx A-MPDU factor */ + uint8_t ht_max_rxampdu_factor; + uint8_t ht_max_amsdu_len; + uint8_t ht_supp_chan_widthset; + uint8_t ht_ldpc_capable; + uint8_t heartbeat_failure; + +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps vht_caps; + uint8_t vht_supp_chanwidth_set; + uint8_t vht_beamformer_capable; +#endif +}; + +void lim_process_ndi_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg_q, + tpPESession session_entry); +/* Handler for DEL BSS resp for NDI interface */ +void lim_ndi_del_bss_rsp(tpAniSirGlobal mac_ctx, + void *msg, tpPESession session_entry); + +void lim_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, tpPESession session_entry, + tAddStaParams *add_sta_rsp); + +void lim_process_ndi_del_sta_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg, + tpPESession 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(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg_q, + tpPESession session_entry) +{ +} +static inline void lim_ndi_del_bss_rsp(tpAniSirGlobal mac_ctx, + void *msg, tpPESession session_entry) +{ +} +static inline void lim_process_ndi_del_sta_rsp(tpAniSirGlobal mac_ctx, + struct scheduler_msg *lim_msg, + tpPESession pe_session) +{ +} + +static inline void lim_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tAddStaParams *add_sta_rsp) +{ +} + +#endif /* WLAN_FEATURE_NAN_DATAPATH || WLAN_FEATURE_NAN_CONVERGENCE */ + +static inline QDF_STATUS lim_handle_ndp_event_message(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg) +{ + return QDF_STATUS_SUCCESS; +} + +#endif /* __MAC_NAN_DATAPATH_H */ + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c new file mode 100644 index 0000000000000000000000000000000000000000..f976c2b56b0139eeb8ac80ca71bc827fc495bf12 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c @@ -0,0 +1,1357 @@ +/* + * 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. + */ + +/**========================================================================= + + \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" + +uint8_t +rrm_get_min_of_max_tx_power(tpAniSirGlobal pMac, + int8_t regMax, int8_t apTxPower) +{ + uint8_t maxTxPower = 0; + uint8_t txPower = QDF_MIN(regMax, (apTxPower)); + + if ((txPower >= RRM_MIN_TX_PWR_CAP) && (txPower <= RRM_MAX_TX_PWR_CAP)) + maxTxPower = txPower; + else if (txPower < RRM_MIN_TX_PWR_CAP) + maxTxPower = RRM_MIN_TX_PWR_CAP; + else + maxTxPower = RRM_MAX_TX_PWR_CAP; + + pe_debug("regulatoryMax: %d, apTxPwr: %d, maxTxpwr: %d", + regMax, apTxPower, maxTxPower); + return maxTxPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_cache_mgmt_tx_power + ** + * FUNCTION: Store Tx power for management frames. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry session entry. + * @return None + */ +void +rrm_cache_mgmt_tx_power(tpAniSirGlobal pMac, int8_t txPower, + tpPESession pSessionEntry) +{ + pe_debug("Cache Mgmt Tx Power: %d", txPower); + + if (pSessionEntry == NULL) + pMac->rrm.rrmPEContext.txMgmtPower = txPower; + else + pSessionEntry->txMgmtPower = txPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_mgmt_tx_power + * + * FUNCTION: Get the Tx power for management frames. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry session entry. + * @return txPower + */ +int8_t rrm_get_mgmt_tx_power(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + if (pSessionEntry == NULL) + return pMac->rrm.rrmPEContext.txMgmtPower; + + pe_debug("tx mgmt pwr %d", pSessionEntry->txMgmtPower); + + return pSessionEntry->txMgmtPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_send_set_max_tx_power_req + * + * FUNCTION: Send WMA_SET_MAX_TX_POWER_REQ message to change the max tx power. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +QDF_STATUS +rrm_send_set_max_tx_power_req(tpAniSirGlobal pMac, int8_t txPower, + tpPESession pSessionEntry) +{ + tpMaxTxPowerParams pMaxTxParams; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + if (pSessionEntry == NULL) { + pe_err("Invalid parameters"); + return QDF_STATUS_E_FAILURE; + } + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + pe_err("Unable to allocate memory for 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, pSessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pMaxTxParams->selfStaMacAddr.bytes, + pSessionEntry->selfMacAddr, + 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(pMac, pSessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &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 + * + * FUNCTION: Process WMA_SET_MAX_TX_POWER_RSP message. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +QDF_STATUS rrm_set_max_tx_power_rsp(tpAniSirGlobal pMac, + struct scheduler_msg *limMsgQ) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + tpMaxTxPowerParams pMaxTxParams = (tpMaxTxPowerParams) limMsgQ->bodyptr; + tpPESession pSessionEntry; + uint8_t sessionId, i; + + if (qdf_is_macaddr_broadcast(&pMaxTxParams->bssId)) { + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + pSessionEntry = &pMac->lim.gpSession[i]; + rrm_cache_mgmt_tx_power(pMac, pMaxTxParams->power, + pSessionEntry); + } + } + } else { + pSessionEntry = pe_find_session_by_bssid(pMac, + pMaxTxParams->bssId.bytes, + &sessionId); + if (pSessionEntry == NULL) { + retCode = QDF_STATUS_E_FAILURE; + } else { + rrm_cache_mgmt_tx_power(pMac, pMaxTxParams->power, + pSessionEntry); + } + } + + qdf_mem_free(limMsgQ->bodyptr); + limMsgQ->bodyptr = NULL; + return retCode; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_link_measurement_request + * + * FUNCTION: Processes the Link measurement request and send the report. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pBd pointer to BD to extract RSSI and SNR + * @param pLinkReq pointer to the Link request frame structure. + * @param pSessionEntry session entry. + * @return None + */ +QDF_STATUS +rrm_process_link_measurement_request(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest *pLinkReq, + tpPESession pSessionEntry) +{ + tSirMacLinkReport LinkReport; + tpSirMacMgmtHdr pHdr; + int8_t currentRSSI = 0; + struct lim_max_tx_pwr_attr tx_pwr_attr = {0}; + + pe_debug("Received Link measurement request"); + + if (pRxPacketInfo == NULL || pLinkReq == NULL || pSessionEntry == NULL) { + pe_err("Invalid parameters - Ignoring the request"); + return QDF_STATUS_E_FAILURE; + } + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + tx_pwr_attr.reg_max = pSessionEntry->def_max_tx_pwr; + tx_pwr_attr.ap_tx_power = pLinkReq->MaxTxPower.maxTxPower; + tx_pwr_attr.ini_tx_power = pMac->roam.configParam.nTxPowerCap; + + LinkReport.txPower = lim_get_max_tx_power(pMac, &tx_pwr_attr); + + if ((LinkReport.txPower != (uint8_t) (pSessionEntry->maxTxPower)) && + (QDF_STATUS_SUCCESS == rrm_send_set_max_tx_power_req(pMac, + LinkReport.txPower, + pSessionEntry))) { + pe_warn("maxTx power in link report is not same as local..." + " Local: %d Link Request TxPower: %d" + " Link Report TxPower: %d", + pSessionEntry->maxTxPower, LinkReport.txPower, + pLinkReq->MaxTxPower.maxTxPower); + pSessionEntry->maxTxPower = + LinkReport.txPower; + } + + LinkReport.dialogToken = pLinkReq->DialogToken.token; + LinkReport.rxAntenna = 0; + LinkReport.txAntenna = 0; + currentRSSI = WMA_GET_RX_RSSI_RAW(pRxPacketInfo); + + pe_info("Received Link report frame with %d", currentRSSI); + + /* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */ + if ((currentRSSI) <= RCPI_LOW_RSSI_VALUE) + LinkReport.rcpi = 0; + else if ((currentRSSI > RCPI_LOW_RSSI_VALUE) && (currentRSSI <= 0)) + LinkReport.rcpi = CALCULATE_RCPI(currentRSSI); + else + LinkReport.rcpi = RCPI_MAX_VALUE; + + LinkReport.rsni = WMA_GET_RX_SNR(pRxPacketInfo); + + pe_debug("Sending Link report frame"); + + return lim_send_link_report_action_frame(pMac, &LinkReport, pHdr->sa, + pSessionEntry); +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_neighbor_report_response + * + * FUNCTION: Processes the Neighbor Report response from the peer AP. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pNeighborRep pointer to the Neighbor report frame structure. + * @param pSessionEntry session entry. + * @return None + */ +QDF_STATUS +rrm_process_neighbor_report_response(tpAniSirGlobal pMac, + tDot11fNeighborReportResponse *pNeighborRep, + tpPESession pSessionEntry) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpSirNeighborReportInd pSmeNeighborRpt = NULL; + uint16_t length; + uint8_t i; + struct scheduler_msg mmhMsg = {0}; + + if (pNeighborRep == NULL || pSessionEntry == NULL) { + pe_err("Invalid parameters"); + return status; + } + + pe_debug("Neighbor report response received"); + + /* Dialog token */ + if (pMac->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 (NULL == pSmeNeighborRpt) { + pe_err("Unable to allocate memory"); + 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; + + 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->sessionId = pSessionEntry->smeSessionId; + pSmeNeighborRpt->numNeighborReports = pNeighborRep->num_NeighborReport; + qdf_mem_copy(pSmeNeighborRpt->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + + /* Send request to SME. */ + mmhMsg.type = pSmeNeighborRpt->messageType; + mmhMsg.bodyptr = pSmeNeighborRpt; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + pSessionEntry->peSessionId, mmhMsg.type)); + status = lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return status; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_neighbor_report_req + * + * FUNCTION: + * + * LOGIC: Create a Neighbor report request and send it to peer. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pNeighborReq Neighbor report request params . + * @return None + */ +QDF_STATUS +rrm_process_neighbor_report_req(tpAniSirGlobal pMac, + tpSirNeighborReportReqInd pNeighborReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirMacNeighborReportReq NeighborReportReq; + tpPESession pSessionEntry; + uint8_t sessionId; + + if (pNeighborReq == NULL) { + pe_err("NeighborReq is NULL"); + return QDF_STATUS_E_FAILURE; + } + pSessionEntry = pe_find_session_by_bssid(pMac, pNeighborReq->bssId, + &sessionId); + if (pSessionEntry == NULL) { + 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 = ++pMac->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(pMac, &NeighborReportReq, + pNeighborReq->bssId, + pSessionEntry); + + return status; +} + +#define ABS(x) ((x < 0) ? -x : x) +/* -------------------------------------------------------------------- */ +/** + * rrm_process_beacon_report_req + * + * FUNCTION: Processes the Beacon report request from the peer AP. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pCurrentReq pointer to the current Req comtext. + * @param pBeaconReq pointer to the beacon report request IE from the peer. + * @param pSessionEntry session entry. + * @return None + */ +static tRrmRetStatus +rrm_process_beacon_report_req(tpAniSirGlobal pMac, + tpRRMReq pCurrentReq, + tDot11fIEMeasurementRequest *pBeaconReq, + tpPESession pSessionEntry) +{ + struct scheduler_msg mmhMsg = {0}; + tpSirBeaconReportReqInd pSmeBcnReportReq; + uint8_t num_channels = 0, num_APChanReport; + uint16_t measDuration, maxMeasduration; + int8_t maxDuration; + uint8_t sign; + + if (pBeaconReq->measurement_request.Beacon.BeaconReporting.present && + (pBeaconReq->measurement_request.Beacon.BeaconReporting. + reportingCondition != 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_err("Dropping the request: Reporting condition included in beacon report request and it is not zero"); + return eRRM_INCAPABLE; + } + + /* 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 + */ + maxDuration = + pMac->rrm.rrmPEContext.rrmEnabledCaps.nonOperatingChanMax - 4; + sign = (maxDuration < 0) ? 1 : 0; + maxDuration = (1L << ABS(maxDuration)); + if (!sign) + maxMeasduration = + maxDuration * pSessionEntry->beaconParams.beaconInterval; + else + maxMeasduration = + pSessionEntry->beaconParams.beaconInterval / maxDuration; + + measDuration = pBeaconReq->measurement_request.Beacon.meas_duration; + + pe_info("maxDuration = %d sign = %d maxMeasduration = %d measDuration = %d", + maxDuration, sign, maxMeasduration, measDuration); + + if (maxMeasduration < measDuration) { + if (pBeaconReq->durationMandatory) { + pe_err("Dropping the request: duration mandatory and maxduration > measduration"); + return eRRM_REFUSED; + } else + measDuration = maxMeasduration; + } + /* 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("Last Beacon Report in request = %d", + pCurrentReq->request.Beacon. + last_beacon_report_indication); + } else { + pCurrentReq->request.Beacon.last_beacon_report_indication = 0; + pe_debug("Last Beacon report not present in request"); + } + + if (pBeaconReq->measurement_request.Beacon.RequestedInfo.present) { + pCurrentReq->request.Beacon.reqIes.pElementIds = + qdf_mem_malloc(sizeof(uint8_t) * + pBeaconReq->measurement_request.Beacon. + RequestedInfo.num_requested_eids); + if (NULL == pCurrentReq->request.Beacon.reqIes.pElementIds) { + pe_err("Unable to allocate memory for request IEs buffer"); + 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); + } + + if (pBeaconReq->measurement_request.Beacon.num_APChannelReport) { + for (num_APChanReport = 0; + num_APChanReport < + pBeaconReq->measurement_request.Beacon.num_APChannelReport; + num_APChanReport++) + num_channels += + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport].num_channelList; + } + /* Prepare the request to send to SME. */ + pSmeBcnReportReq = qdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (NULL == pSmeBcnReportReq) { + pe_err("Unable to allocate memory during Beacon Report Req Ind to SME"); + return eRRM_FAILURE; + + } + + /* Allocated memory for pSmeBcnReportReq....will be freed by other modulea */ + qdf_mem_copy(pSmeBcnReportReq->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + pSmeBcnReportReq->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + pSmeBcnReportReq->length = sizeof(tSirBeaconReportReqInd); + pSmeBcnReportReq->uDialogToken = pBeaconReq->measurement_token; + pSmeBcnReportReq->msgSource = eRRM_MSG_SOURCE_11K; + pSmeBcnReportReq->randomizationInterval = + SYS_TU_TO_MS(pBeaconReq->measurement_request.Beacon.randomization); + pSmeBcnReportReq->channelInfo.regulatoryClass = + pBeaconReq->measurement_request.Beacon.regClass; + pSmeBcnReportReq->channelInfo.channelNum = + pBeaconReq->measurement_request.Beacon.channel; + pSmeBcnReportReq->measurementDuration[0] = SYS_TU_TO_MS(measDuration); + pSmeBcnReportReq->fMeasurementtype[0] = + pBeaconReq->measurement_request.Beacon.meas_mode; + qdf_mem_copy(pSmeBcnReportReq->macaddrBssid, + pBeaconReq->measurement_request.Beacon.BSSID, + sizeof(tSirMacAddr)); + + if (pBeaconReq->measurement_request.Beacon.SSID.present) { + pSmeBcnReportReq->ssId.length = + pBeaconReq->measurement_request.Beacon.SSID.num_ssid; + qdf_mem_copy(pSmeBcnReportReq->ssId.ssId, + pBeaconReq->measurement_request.Beacon.SSID.ssid, + pSmeBcnReportReq->ssId.length); + } + + pCurrentReq->token = pBeaconReq->measurement_token; + + pSmeBcnReportReq->channelList.numChannels = num_channels; + if (pBeaconReq->measurement_request.Beacon.num_APChannelReport) { + uint8_t *ch_lst = pSmeBcnReportReq->channelList.channelNumber; + uint8_t len; + uint16_t ch_ctr = 0; + + for (num_APChanReport = 0; + num_APChanReport < + pBeaconReq->measurement_request.Beacon.num_APChannelReport; + num_APChanReport++) { + len = pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport].num_channelList; + if (ch_ctr + len > + sizeof(pSmeBcnReportReq->channelList.channelNumber)) + break; + + qdf_mem_copy(&ch_lst[ch_ctr], + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport]. + channelList, len); + + ch_ctr += len; + } + } + /* Send request to SME. */ + mmhMsg.type = eWNI_SME_BEACON_REPORT_REQ_IND; + mmhMsg.bodyptr = pSmeBcnReportReq; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + pSessionEntry->peSessionId, mmhMsg.type)); + if (QDF_STATUS_SUCCESS != + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT)) + return eRRM_FAILURE; + return eRRM_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_fill_beacon_ies + * + * FUNCTION: + * + * LOGIC: Fills Fixed fields and Ies in bss description to an array of uint8_t. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pIes - pointer to the buffer that should be populated with ies. + * @param pNumIes - returns the num of ies filled in this param. + * @param pIesMaxSize - Max size of the buffer pIes. + * @param eids - pointer to array of eids. If NULL, all ies will be populated. + * @param numEids - number of elements in array eids. + * @param pBssDesc - pointer to Bss Description. + * @return None + */ +static void +rrm_fill_beacon_ies(tpAniSirGlobal pMac, + uint8_t *pIes, uint8_t *pNumIes, uint8_t pIesMaxSize, + uint8_t *eids, uint8_t numEids, tpSirBssDescription pBssDesc) +{ + uint8_t len, *pBcnIes, count = 0, i; + uint16_t BcnNumIes; + + if ((pIes == NULL) || (pNumIes == NULL) || (pBssDesc == NULL)) { + pe_err("Invalid parameters"); + return; + } + /* Make sure that if eid is null, numEids is set to zero. */ + numEids = (eids == NULL) ? 0 : numEids; + + pBcnIes = (uint8_t *) &pBssDesc->ieFields[0]; + BcnNumIes = GET_IE_LEN_IN_BSS(pBssDesc->length); + + *pNumIes = 0; + + *((uint32_t *) pIes) = pBssDesc->timeStamp[0]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint32_t *) pIes) = pBssDesc->timeStamp[1]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint16_t *) pIes) = pBssDesc->beaconInterval; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + *((uint16_t *) pIes) = pBssDesc->capabilityInfo; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + + while (BcnNumIes > 0) { + len = *(pBcnIes + 1) + 2; /* element id + length. */ + pe_debug("EID = %d, len = %d total = %d", + *pBcnIes, *(pBcnIes + 1), len); + + i = 0; + do { + if (((eids == NULL) || (*pBcnIes == eids[i])) && + ((*pNumIes) + len) < pIesMaxSize) { + pe_debug("Adding Eid %d, len=%d", + *pBcnIes, len); + + qdf_mem_copy(pIes, pBcnIes, len); + pIes += len; + *pNumIes += len; + count++; + break; + } + i++; + } while (i < numEids); + + pBcnIes += len; + BcnNumIes -= len; + } + pe_debug("Total length of Ies added = %d", *pNumIes); +} + +/** + * 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(tpAniSirGlobal mac_ctx, + tpSirBeaconReportXmitInd beacon_xmit_ind) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirMacRadioMeasureReport *report = NULL; + tSirMacBeaconReport *beacon_report; + tpSirBssDescription bss_desc; + tpRRMReq curr_req = mac_ctx->rrm.rrmPEContext.pCurrentReq; + tpPESession session_entry; + struct rrm_beacon_report_last_beacon_params last_beacon_report_params; + uint8_t session_id, counter; + uint8_t bss_desc_count = 0; + uint8_t report_index = 0; + + pe_debug("Received beacon report xmit indication"); + + if (NULL == beacon_xmit_ind) { + pe_err("Received beacon_xmit_ind is NULL in PE"); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == curr_req) { + pe_err("Received report xmit while there is no request pending in PE"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + if ((beacon_xmit_ind->numBssDesc) || curr_req->sendEmptyBcnRpt) { + 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 (NULL == session_entry) { + pe_err("session does not exist for given bssId"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + report = qdf_mem_malloc(beacon_xmit_ind->numBssDesc * + sizeof(*report)); + + if (NULL == report) { + pe_err("RRM Report is NULL, allocation failed"); + status = QDF_STATUS_E_NOMEM; + goto end; + } + + for (bss_desc_count = 0; bss_desc_count < + beacon_xmit_ind->numBssDesc; bss_desc_count++) { + beacon_report = + &report[bss_desc_count].report.beaconReport; + /* + * If the scan result is NULL then send report request + * with option subelement as NULL. + */ + bss_desc = beacon_xmit_ind-> + pBssDescription[bss_desc_count]; + /* Prepare the beacon report and send it to the peer.*/ + report[bss_desc_count].token = + beacon_xmit_ind->uDialogToken; + report[bss_desc_count].refused = 0; + report[bss_desc_count].incapable = 0; + report[bss_desc_count].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 = bss_desc->channelId; + qdf_mem_copy(beacon_report->measStartTime, + bss_desc->startTSF, + sizeof(bss_desc->startTSF)); + beacon_report->measDuration = + SYS_MS_TO_TU(beacon_xmit_ind->duration); + beacon_report->phyType = bss_desc->nwType; + beacon_report->bcnProbeRsp = 1; + beacon_report->rsni = bss_desc->sinr; + 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)); + } + + switch (curr_req->request.Beacon.reportingDetail) { + case BEACON_REPORTING_DETAIL_NO_FF_IE: + /* 0: No need to include any elements. */ + pe_debug("No reporting detail requested"); + break; + case BEACON_REPORTING_DETAIL_ALL_FF_REQ_IE: + /* 1: Include all FFs and Requested Ies. */ + pe_debug("Only requested IEs in reporting detail requested"); + + if (bss_desc) { + 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, + bss_desc); + } + break; + case BEACON_REPORTING_DETAIL_ALL_FF_IE: + /* 2: default - Include all FFs and all Ies. */ + default: + pe_debug("Default all IEs and FFs"); + if (bss_desc) { + rrm_fill_beacon_ies(mac_ctx, + (uint8_t *) &beacon_report->Ies[0], + (uint8_t *) &beacon_report->numIes, + BEACON_REPORT_MAX_IES, + NULL, + 0, + bss_desc); + } + break; + } + } + + + qdf_mem_zero(&last_beacon_report_params, + sizeof(last_beacon_report_params)); + /* + * Each frame can hold RADIO_REPORTS_MAX_IN_A_FRAME reports. + * Multiple frames may be sent if bss_desc_count is larger. + * Count the total number of frames to be sent first + */ + + + last_beacon_report_params.last_beacon_ind = + curr_req->request.Beacon.last_beacon_report_indication; + last_beacon_report_params.num_frags = + (bss_desc_count / RADIO_REPORTS_MAX_IN_A_FRAME); + if (bss_desc_count % RADIO_REPORTS_MAX_IN_A_FRAME) + last_beacon_report_params.num_frags++; + + pe_debug("last_beacon_report_ind required %d num_frags %d bss_count %d", + last_beacon_report_params.last_beacon_ind, + last_beacon_report_params.num_frags, + bss_desc_count); + + while (report_index < bss_desc_count) { + int m_count; + + m_count = QDF_MIN((bss_desc_count - report_index), + RADIO_REPORTS_MAX_IN_A_FRAME); + pe_info("Sending Action frame with %d bss info frag_id %d", + m_count, last_beacon_report_params.frag_id); + lim_send_radio_measure_report_action_frame(mac_ctx, + curr_req->dialog_token, m_count, + &last_beacon_report_params, + &report[report_index], + beacon_xmit_ind->bssId, session_entry); + report_index += m_count; + last_beacon_report_params.frag_id++; + } + 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....cleanup the context"); + rrm_cleanup(mac_ctx); + } + + if (NULL != report) + qdf_mem_free(report); + + return status; +} + +static void rrm_process_beacon_request_failure(tpAniSirGlobal pMac, + tpPESession pSessionEntry, + tSirMacAddr peer, + tRrmRetStatus status) +{ + tpSirMacRadioMeasureReport pReport = NULL; + tpRRMReq pCurrentReq = pMac->rrm.rrmPEContext.pCurrentReq; + + pReport = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == pReport) { + pe_err("Unable to allocate memory during RRM Req processing"); + return; + } + pReport->token = pCurrentReq->token; + pReport->type = SIR_MAC_RRM_BEACON_TYPE; + + pe_debug("status %d token %d", status, pReport->token); + + switch (status) { + case eRRM_REFUSED: + pReport->refused = 1; + break; + case eRRM_INCAPABLE: + pReport->incapable = 1; + break; + default: + pe_err("Beacon request processing failed no report sent with status %d", + status); + qdf_mem_free(pReport); + return; + } + + lim_send_radio_measure_report_action_frame(pMac, + pCurrentReq->dialog_token, + 1, NULL, + pReport, peer, + pSessionEntry); + + 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 + * @curr_req: Pointer to RRM request + * @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(tpAniSirGlobal mac_ctx, tSirMacAddr peer, + tpPESession session_entry, tpRRMReq curr_req, + tpSirMacRadioMeasureReport *radiomes_report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, int index) +{ + tRrmRetStatus rrm_status = eRRM_SUCCESS; + tpSirMacRadioMeasureReport report; + + if (curr_req) { + if (*radiomes_report == NULL) { + /* + * Allocate memory to send reports for + * any subsequent requests. + */ + *radiomes_report = qdf_mem_malloc(sizeof(*report) * + (rrm_req->num_MeasurementRequest - index)); + if (NULL == *radiomes_report) { + pe_err("Unable to allocate memory during RRM Req processing"); + return QDF_STATUS_E_NOMEM; + } + pe_debug("rrm beacon type refused of %d report in beacon table", + *num_report); + } + report = *radiomes_report; + report[*num_report].refused = 1; + report[*num_report].type = SIR_MAC_RRM_BEACON_TYPE; + report[*num_report].token = + rrm_req->MeasurementRequest[index].measurement_token; + (*num_report)++; + return QDF_STATUS_SUCCESS; + } else { + curr_req = qdf_mem_malloc(sizeof(*curr_req)); + if (NULL == curr_req) { + pe_err("Unable to allocate memory during RRM Req processing"); + qdf_mem_free(*radiomes_report); + return QDF_STATUS_E_NOMEM; + } + pe_debug("Processing Beacon Report request"); + curr_req->dialog_token = rrm_req->DialogToken.token; + curr_req->token = rrm_req-> + MeasurementRequest[index].measurement_token; + curr_req->sendEmptyBcnRpt = true; + mac_ctx->rrm.rrmPEContext.pCurrentReq = curr_req; + 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); + rrm_cleanup(mac_ctx); + } + } + 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(tpAniSirGlobal mac_ctx, + tpSirMacRadioMeasureReport report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, int index) +{ + if (report == NULL) { + /* + * Allocate memory to send reports for + * any subsequent requests. + */ + report = qdf_mem_malloc(sizeof(*report) * + (rrm_req->num_MeasurementRequest - index)); + if (NULL == report) { + pe_err("Unable to allocate memory during RRM Req processing"); + return QDF_STATUS_E_NOMEM; + } + pe_debug("rrm beacon type incapable of %d report", + *num_report); + } + report[*num_report].incapable = 1; + report[*num_report].type = + rrm_req->MeasurementRequest[index].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(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest *rrm_req, + tpPESession session_entry) +{ + uint8_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirMacRadioMeasureReport report = NULL; + uint8_t num_report = 0; + tpRRMReq curr_req = mac_ctx->rrm.rrmPEContext.pCurrentReq; + + if (!rrm_req->num_MeasurementRequest) { + report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == report) { + pe_err("Unable to allocate memory during RRM Req processing"); + return QDF_STATUS_E_NOMEM; + } + pe_err("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, NULL, + report, peer, session_entry); + qdf_mem_free(report); + return QDF_STATUS_E_FAILURE; + } + /* PF Fix */ + if (rrm_req->NumOfRepetitions.repetitions > 0) { + pe_info("number of repetitions %d", + rrm_req->NumOfRepetitions.repetitions); + /* + * Send a report with incapable bit set. + * Not supporting repetitions. + */ + report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == report) { + pe_err("Unable to allocate memory during RRM Req processing"); + return QDF_STATUS_E_NOMEM; + } + report->incapable = 1; + report->type = rrm_req->MeasurementRequest[0].measurement_type; + num_report = 1; + goto end; + } + + for (i = 0; i < rrm_req->num_MeasurementRequest; i++) { + switch (rrm_req->MeasurementRequest[i].measurement_type) { + case SIR_MAC_RRM_BEACON_TYPE: + /* Process beacon request. */ + status = rrm_process_beacon_req(mac_ctx, peer, + session_entry, curr_req, &report, rrm_req, + &num_report, i); + if (QDF_STATUS_SUCCESS != status) + return status; + 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, NULL, + report, peer, session_entry); + qdf_mem_free(report); + } + return status; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_update_start_tsf + ** + * FUNCTION: Store start TSF of measurement. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param startTSF - TSF value at the start of measurement. + * @return None + */ +void rrm_update_start_tsf(tpAniSirGlobal pMac, uint32_t startTSF[2]) +{ + pMac->rrm.rrmPEContext.startTSF[0] = startTSF[0]; + pMac->rrm.rrmPEContext.startTSF[1] = startTSF[1]; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_start_tsf + * + * FUNCTION: Get the Start TSF. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param startTSF - store star TSF in this buffer. + * @return txPower + */ +void rrm_get_start_tsf(tpAniSirGlobal pMac, uint32_t *pStartTSF) +{ + pStartTSF[0] = pMac->rrm.rrmPEContext.startTSF[0]; + pStartTSF[1] = pMac->rrm.rrmPEContext.startTSF[1]; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_capabilities + * + * FUNCTION: + * Returns a pointer to tpRRMCaps with all the caps enabled in RRM + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry + * @return pointer to tRRMCaps + */ +tpRRMCaps rrm_get_capabilities(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + return &pMac->rrm.rrmPEContext.rrmEnabledCaps; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_initialize + * + * FUNCTION: + * Initialize RRM module + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @return None + */ + +QDF_STATUS rrm_initialize(tpAniSirGlobal pMac) +{ + tpRRMCaps pRRMCaps = &pMac->rrm.rrmPEContext.rrmEnabledCaps; + + pMac->rrm.rrmPEContext.pCurrentReq = NULL; + pMac->rrm.rrmPEContext.txMgmtPower = 0; + pMac->rrm.rrmPEContext.DialogToken = 0; + + pMac->rrm.rrmPEContext.rrmEnable = 0; + pMac->rrm.rrmPEContext.prev_rrm_report_seq_num = 0xFFFF; + + 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->operatingChanMax = 3; + pRRMCaps->nonOperatingChanMax = 3; + + return QDF_STATUS_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_cleanup + * + * FUNCTION: + * cleanup RRM module + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param mode + * @param rate + * @return None + */ + +QDF_STATUS rrm_cleanup(tpAniSirGlobal pMac) +{ + if (pMac->rrm.rrmPEContext.pCurrentReq) { + if (pMac->rrm.rrmPEContext.pCurrentReq->request.Beacon.reqIes. + pElementIds) { + qdf_mem_free(pMac->rrm.rrmPEContext.pCurrentReq-> + request.Beacon.reqIes.pElementIds); + } + + qdf_mem_free(pMac->rrm.rrmPEContext.pCurrentReq); + } + + pMac->rrm.rrmPEContext.pCurrentReq = NULL; + return QDF_STATUS_SUCCESS; +} + +/** + * lim_update_rrm_capability() - Update PE context's rrm capability + * @mac_ctx: Global pointer to MAC context + * @join_req: Pointer to SME join request. + * + * Update PE context's rrm capability based on SME join request. + * + * Return: None + */ +void lim_update_rrm_capability(tpAniSirGlobal mac_ctx, + tpSirSmeJoinReq join_req) +{ + mac_ctx->rrm.rrmPEContext.rrmEnable = join_req->rrm_config.rrm_enabled; + qdf_mem_copy(&mac_ctx->rrm.rrmPEContext.rrmEnabledCaps, + &join_req->rrm_config.rm_capability, + RMENABLEDCAP_MAX_LEN); + + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_api.c new file mode 100644 index 0000000000000000000000000000000000000000..79f877fd6f3a2563e9135b1eb4131129e9bfcd0b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_api.c @@ -0,0 +1,493 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_api.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" + +/* -------------------------------------------------------------------- */ +/* */ +/* Static Variables */ +/* */ +/* -------------------------------------------------------------------- */ +/** + * sch_post_message + * + * FUNCTION: + * Post the beacon message to the scheduler message queue + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMsg pointer to message + * @return None + */ + +QDF_STATUS sch_post_message(tpAniSirGlobal pMac, struct scheduler_msg *pMsg) +{ + sch_process_message(pMac, pMsg); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sch_send_beacon_req(tpAniSirGlobal pMac, uint8_t *beaconPayload, + uint16_t size, tpPESession psessionEntry, + enum sir_bcn_update_reason reason) +{ + struct scheduler_msg msgQ = {0}; + tpSendbeaconParams beaconParams = NULL; + QDF_STATUS retCode; + + pe_debug("Indicating HAL to copy the beacon template [%d bytes] to memory, reason %d", + size, reason); + + if (LIM_IS_AP_ROLE(psessionEntry) && + (pMac->sch.schObject.fBeaconChanged)) { + retCode = lim_send_probe_rsp_template_to_hal(pMac, + psessionEntry, + &psessionEntry->DefProbeRspIeBitmap[0]); + if (QDF_STATUS_SUCCESS != retCode) + pe_err("FAILED to send probe response template with retCode %d", + retCode); + } + + beaconParams = qdf_mem_malloc(sizeof(tSendbeaconParams)); + if (NULL == 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, psessionEntry->bssId, + sizeof(psessionEntry->bssId)); + + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + beaconParams->timIeOffset = 0; + } else { + beaconParams->timIeOffset = psessionEntry->schBeaconOffsetBegin; + if (psessionEntry->dfsIncludeChanSwIe) { + beaconParams->csa_count_offset = + pMac->sch.schObject.csa_count_offset; + beaconParams->ecsa_count_offset = + pMac->sch.schObject.ecsa_count_offset; + pe_debug("csa_count_offset %d ecsa_count_offset %d", + beaconParams->csa_count_offset, + beaconParams->ecsa_count_offset); + } + } + + beaconParams->vdev_id = psessionEntry->smeSessionId; + beaconParams->reason = reason; + + /* p2pIeOffset should be atleast greater than timIeOffset */ + if ((pMac->sch.schObject.p2pIeOffset != 0) && + (pMac->sch.schObject.p2pIeOffset < + psessionEntry->schBeaconOffsetBegin)) { + pe_err("Invalid p2pIeOffset:[%d]", + pMac->sch.schObject.p2pIeOffset); + QDF_ASSERT(0); + qdf_mem_free(beaconParams); + return QDF_STATUS_E_FAILURE; + } + beaconParams->p2pIeOffset = pMac->sch.schObject.p2pIeOffset; +#ifdef WLAN_SOFTAP_FW_BEACON_TX_PRNT_LOG + pe_err("TimIeOffset:[%d]", beaconParams->TimIeOffset); +#endif + + 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; + + /* Keep a copy of recent beacon frame sent */ + + /* free previous copy of the beacon */ + if (psessionEntry->beacon) { + qdf_mem_free(psessionEntry->beacon); + } + + psessionEntry->bcnLen = 0; + psessionEntry->beacon = NULL; + + psessionEntry->beacon = qdf_mem_malloc(size); + if (psessionEntry->beacon != NULL) { + qdf_mem_copy(psessionEntry->beacon, beaconPayload, size); + psessionEntry->bcnLen = size; + } + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) + pe_err("Posting SEND_BEACON_REQ to HAL failed, reason=%X", + retCode); + else + pe_debug("Successfully posted WMA_SEND_BEACON_REQ to HAL"); + + return retCode; +} + +static uint32_t lim_remove_p2p_ie_from_add_ie(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t *addIeWoP2pIe, + uint32_t *addnIELenWoP2pIe) +{ + uint32_t left = psessionEntry->addIeParams.probeRespDataLen; + uint8_t *ptr = psessionEntry->addIeParams.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 != NULL) { + 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(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t *IeBitmap) +{ + struct scheduler_msg msgQ = {0}; + uint8_t *pFrame2Hal = psessionEntry->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; + + /* Check if probe response IE is present or not */ + addnIEPresent = (psessionEntry->addIeParams.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(psessionEntry->addIeParams. + probeRespDataLen); + if (NULL == addIeWoP2pIe) { + pe_err("FAILED to alloc memory when removing P2P IE"); + return QDF_STATUS_E_NOMEM; + } + + retStatus = lim_remove_p2p_ie_from_add_ie(pMac, psessionEntry, + 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 (NULL == addIE) { + pe_err("Unable to get WNI_CFG_PROBE_RSP_ADDNIE_DATA1 length"); + 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(pMac, addIE, + &addn_ielen, &extracted_extcap); + if (QDF_STATUS_SUCCESS != status) { + pe_debug("extcap not extracted"); + } else { + extcap_present = true; + } + } + + if (addnIEPresent) { + if ((nBytes + addn_ielen) <= SIR_MAX_PACKET_SIZE) + nBytes += addn_ielen; + else + addnIEPresent = false; /* Dont include the IE. */ + } + + /* + * 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 = &psessionEntry->probeRespFrame; + if (extcap_present) + lim_merge_extcap_struct(&prb_rsp_frm->ExtCap, + &extracted_extcap, + true); + + nStatus = dot11f_get_packed_probe_response_size(pMac, + &psessionEntry->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); + } + + nBytes += nPayload + sizeof(tSirMacMgmtHdr); + + /* 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(pMac, pFrame2Hal, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_RSP, + psessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + + pMacHdr = (tpSirMacMgmtHdr) pFrame2Hal; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* That done, pack the Probe Response: */ + nStatus = + dot11f_pack_probe_response(pMac, &psessionEntry->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 (addnIEPresent) { + qdf_mem_copy(&pFrame2Hal[nBytes - addn_ielen], + &addIE[0], addn_ielen); + } + + qdf_mem_free(addIE); + + pprobeRespParams = qdf_mem_malloc(sizeof(tSendProbeRespParams)); + if (NULL == pprobeRespParams) { + pe_err("malloc failed for bytes %d", nBytes); + } else { + sir_copy_mac_addr(pprobeRespParams->bssId, psessionEntry->bssId); + qdf_mem_copy(pprobeRespParams->probeRespTemplate, + pFrame2Hal, nBytes); + pprobeRespParams->probeRespTemplateLen = nBytes; + qdf_mem_copy(pprobeRespParams->ucProxyProbeReqValidIEBmap, + IeBitmap, (sizeof(uint32_t) * 8)); + msgQ.type = WMA_SEND_PROBE_RSP_TMPL; + msgQ.reserved = 0; + msgQ.bodyptr = pprobeRespParams; + msgQ.bodyval = 0; + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("lim_send_probe_rsp_template_to_hal: FAIL bytes %d retcode[%X]", + nBytes, retCode); + qdf_mem_free(pprobeRespParams); + } else { + pe_debug( + FL + ("lim_send_probe_rsp_template_to_hal: Probe response template msg posted to HAL of bytes %d"), + nBytes); + } + } + + return retCode; +} + +/** + * sch_gen_timing_advert_frame() - Generate the TA frame and populate the buffer + * @pMac: 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. + */ +int sch_gen_timing_advert_frame(tpAniSirGlobal 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; + int status; + struct qdf_mac_addr wildcard_bssid = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + }; + + qdf_mem_zero((uint8_t *)&frame, sizeof(tDot11fTimingAdvertisementFrame)); + + /* Populate the TA fields */ + status = populate_dot11f_timing_advert_frame(mac_ctx, &frame); + if (status) { + pe_err("Error populating TA frame %x", status); + return status; + } + + status = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx, + &frame, &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Error getting packed frame size %x", status); + return status; + } else if (DOT11F_WARNED(status)) { + pe_warn("Warning getting packed frame size"); + } + + buf_size = sizeof(tSirMacMgmtHdr) + payload_size; + *buf = qdf_mem_malloc(buf_size); + if (*buf == NULL) { + pe_err("Cannot allocate memory"); + return QDF_STATUS_E_FAILURE; + } + + payload_size = 0; + status = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame, + *buf + sizeof(tSirMacMgmtHdr), buf_size - + sizeof(tSirMacMgmtHdr), &payload_size); + pe_err("TA payload size2 = %d", payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Error packing frame %x", status); + goto fail; + } else if (DOT11F_WARNED(status)) { + 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: + if (*buf) + qdf_mem_free(*buf); + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c new file mode 100644 index 0000000000000000000000000000000000000000..35006e2df4bcf69c080a56173700c4a611b6be07 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c @@ -0,0 +1,1077 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.h" +#include "sch_api.h" + +#include "parser_api.h" +#include "wlan_utility.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 }; + +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 + * @max_bcn_size: max beacon size + * @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(tpAniSirGlobal mac_ctx, tpPESession session, + uint8_t *frm, uint32_t max_bcn_size, 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 + *num_bytes) <= max_bcn_size)); + + if (!valid_ie) + 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, SIR_MAC_EID_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] == SIR_MAC_EID_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 != NULL) && !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; +} + +/** + * sch_get_csa_ecsa_count_offset() - get the offset of Switch count field + * @ie: pointer to the beggining 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(uint8_t *ie, uint32_t ie_len, + uint32_t *csa_count_offset, + uint32_t *ecsa_count_offset) +{ + 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; + + ie_len -= elem_len; + offset += elem_len; + ptr += (elem_len + 2); + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, tpPESession session) +{ + tpAniBeaconStruct bcn_struct = (tpAniBeaconStruct) + session->pSchBeaconFrameBegin; + tpSirMacMgmtHdr mac; + uint16_t offset; + uint8_t *ptr; + tDot11fBeacon1 *bcn_1; + tDot11fBeacon2 *bcn_2; + uint32_t i, n_status, n_bytes; + uint32_t wps_ap_enable = 0, tmp; + 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; + + bcn_1 = qdf_mem_malloc(sizeof(tDot11fBeacon1)); + if (NULL == bcn_1) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + bcn_2 = qdf_mem_malloc(sizeof(tDot11fBeacon2)); + if (NULL == bcn_2) { + pe_err("Failed to allocate memory"); + qdf_mem_free(bcn_1); + return QDF_STATUS_E_NOMEM; + } + + wsc_prb_res = qdf_mem_malloc(sizeof(tDot11fIEWscProbeRes)); + if (NULL == wsc_prb_res) { + pe_err("Failed to allocate memory"); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + return QDF_STATUS_E_NOMEM; + } + + pe_debug("Setting fixed beacon fields"); + + /* + * 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->selfMacAddr, + sizeof(session->selfMacAddr)); + 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 fileds 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->currentOperChannel); + populate_dot11f_ibss_params(mac_ctx, &bcn_1->IBSSParams, session); + + 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; + pe_debug("Initialized beacon begin, offset %d", offset); + + /* Initialize the 'new' fields at the end of the beacon */ + + if ((session->limSystemRole == eLIM_AP_ROLE) && + session->dfsIncludeChanSwIe == true) { + if (!CHAN_HOP_ALL_BANDS_ENABLE || + session->lim_non_ecsa_cap_num == 0) { + 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); + pe_debug("ecsa: mode:%d reg:%d chan:%d count:%d", + ext_csa->switch_mode, + ext_csa->new_reg_class, + ext_csa->new_channel, + ext_csa->switch_count); + } else { + populate_dot11f_chan_switch_ann(mac_ctx, + &bcn_2->ChanSwitchAnn, + session); + pe_debug("csa: mode:%d chan:%d count:%d", + bcn_2->ChanSwitchAnn.switchMode, + bcn_2->ChanSwitchAnn.newChannel, + bcn_2->ChanSwitchAnn.switchCount); + } + } + + 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 == true) { + /* + * Channel switch announcement only if radar is detected + * and SAP has instructed to announce channel switch IEs + * in beacon and probe responses + */ + populate_dot11f_chan_switch_ann(mac_ctx, + &bcn_2->ChanSwitchAnn, session); + pe_debug("csa: mode:%d chan:%d count:%d", + bcn_2->ChanSwitchAnn.switchMode, + bcn_2->ChanSwitchAnn.newChannel, + bcn_2->ChanSwitchAnn.switchCount); + /* + * TODO: depending the CB mode, extended channel switch + * announcement need to be called + */ + /* + populate_dot11f_ext_chan_switch_ann(mac_ctx, + &bcn_2->ExtChanSwitchAnn, session); + */ + /* + * TODO: If in 11AC mode, wider bw channel switch + * announcement needs to be called + */ + /* + populate_dot11f_wider_bw_chan_switch_ann(mac_ctx, + &bcn_2->WiderBWChanSwitchAnn, session); + */ + /* + * Populate the Channel Switch Wrapper Element if + * SAP operates in 40/80 Mhz Channel Width. + */ + if (true == session->dfsIncludeChanWrapperIe) { + populate_dot11f_chan_switch_wrapper(mac_ctx, + &bcn_2->ChannelSwitchWrapper, session); + pe_debug("wrapper: width:%d f0:%d f1:%d", + bcn_2->ChannelSwitchWrapper. + WiderBWChanSwitchAnn.newChanWidth, + bcn_2->ChannelSwitchWrapper. + WiderBWChanSwitchAnn.newCenterChanFreq0, + bcn_2->ChannelSwitchWrapper. + WiderBWChanSwitchAnn.newCenterChanFreq1 + ); + } + } + } + if (mac_ctx->rrm.rrmSmeContext.rrmConfig.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 != WNI_CFG_DOT11_MODE_11B) + populate_dot11f_erp_info(mac_ctx, &bcn_2->ERPInfo, session); + + 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) { + pe_debug("Populate VHT IEs in Beacon"); + 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 (lim_is_session_he_capable(session)) { + pe_warn("Populate HE IEs"); + populate_dot11f_he_caps(mac_ctx, session, + &bcn_2->he_cap); + populate_dot11f_he_operation(mac_ctx, session, + &bcn_2->he_op); + populate_dot11f_he_bss_color_change(mac_ctx, session, + &bcn_2->bss_color_change); + } + + if (session->limSystemRole != eLIM_STA_IN_IBSS_ROLE) + 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 != NULL) { + populate_dot11f_wpa(mac_ctx, &session->pLimStartBssReq->rsnIE, + &bcn_2->WPA); + populate_dot11f_rsn_opaque(mac_ctx, + &session->pLimStartBssReq->rsnIE, + &bcn_2->RSNOpaque); + } + + 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 { + status = wlan_cfg_get_int(mac_ctx, WNI_CFG_WPS_ENABLE, &tmp); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Failed to cfg get id %d", WNI_CFG_WPS_ENABLE); + + wps_ap_enable = tmp & 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)) { + /* + * 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->addIeParams.probeRespBCNDataLen != 0); + if (addnie_present) { + addn_ielen = session->addIeParams.probeRespBCNDataLen; + addn_ie = qdf_mem_malloc(addn_ielen); + if (!addn_ie) { + pe_err("addn_ie malloc failed"); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(addn_ie, + session->addIeParams.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 && + session->limSystemRole != eLIM_STA_IN_IBSS_ROLE) + lim_merge_extcap_struct(&bcn_2->ExtCap, + &extracted_extcap, + true); + + } + + 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, + SIR_MAC_VHT_OPMODE_EID, ONE_BYTE, NULL, 0, + NULL, SIR_MAC_VHT_OPMODE_SIZE - 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); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + qdf_mem_free(addn_ie); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(n_status)) { + pe_err("Warnings while packing a tDot11fBeacon2(0x%08x)", + n_status); + } + + /* Fill the CSA/ECSA count offsets if the IEs are present */ + 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.schObject.csa_count_offset = + session->schBeaconOffsetBegin + TIM_IE_SIZE + + csa_count_offset; + if (ecsa_count_offset) + mac_ctx->sch.schObject.ecsa_count_offset = + session->schBeaconOffsetBegin + TIM_IE_SIZE + + ecsa_count_offset; + + pe_debug("csa_count_offset %d ecsa_count_offset %d", + mac_ctx->sch.schObject.csa_count_offset, + mac_ctx->sch.schObject.ecsa_count_offset); + + extra_ie = session->pSchBeaconFrameEnd + n_bytes; + extra_ie_offset = n_bytes; + + /* TODO: Append additional IE here. */ + if (addn_ielen > 0) + sch_append_addn_ie(mac_ctx, session, + session->pSchBeaconFrameEnd + n_bytes, + SIR_MAX_BEACON_SIZE, &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.schObject.p2pIeOffset = + session->schBeaconOffsetBegin + TIM_IE_SIZE + + extra_ie_offset + p2p_ie_offset; + else + mac_ctx->sch.schObject.p2pIeOffset = 0; + + pe_debug("Initialized beacon end, offset %d", + session->schBeaconOffsetEnd); + mac_ctx->sch.schObject.fBeaconChanged = 1; + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + qdf_mem_free(addn_ie); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +lim_update_probe_rsp_template_ie_bitmap_beacon1(tpAniSirGlobal pMac, + tDot11fBeacon1 *beacon1, + tpPESession psessionEntry) +{ + uint32_t *DefProbeRspIeBitmap; + tDot11fProbeResponse *prb_rsp; + + if (!psessionEntry) { + pe_debug("PESession is null!"); + return QDF_STATUS_E_FAILURE; + } + DefProbeRspIeBitmap = &psessionEntry->DefProbeRspIeBitmap[0]; + prb_rsp = &psessionEntry->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, SIR_MAC_SSID_EID); + /* populating it, because probe response has to go with SSID even in hidden case */ + populate_dot11f_ssid(pMac, &psessionEntry->ssId, &prb_rsp->SSID); + } + /* supported rates */ + if (beacon1->SuppRates.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_RATESET_EID); + 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, + SIR_MAC_DS_PARAM_SET_EID); + qdf_mem_copy((void *)&prb_rsp->DSParams, + (void *)&beacon1->DSParams, + sizeof(beacon1->DSParams)); + + } + + /* IBSS params will not be present in the Beacons transmitted by AP */ + return QDF_STATUS_SUCCESS; +} + +void lim_update_probe_rsp_template_ie_bitmap_beacon2(tpAniSirGlobal pMac, + tDot11fBeacon2 *beacon2, + uint32_t *DefProbeRspIeBitmap, + tDot11fProbeResponse *prb_rsp) +{ + /* IBSS parameter set - will not be present in probe response tx by AP */ + /* country */ + if (beacon2->Country.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_COUNTRY_EID); + 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, + SIR_MAC_PWR_CONSTRAINT_EID); + qdf_mem_copy((void *)&prb_rsp->PowerConstraints, + (void *)&beacon2->PowerConstraints, + sizeof(beacon2->PowerConstraints)); + + } + /* Channel Switch Annoouncement SIR_MAC_CHNL_SWITCH_ANN_EID */ + if (beacon2->ChanSwitchAnn.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_CHNL_SWITCH_ANN_EID); + 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, + SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID); + 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, + SIR_MAC_OPERATING_CLASS_EID); + 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, SIR_MAC_ERP_INFO_EID); + 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, + SIR_MAC_EXTENDED_RATE_EID); + 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, SIR_MAC_RSN_EID); + qdf_mem_copy((void *)&prb_rsp->RSNOpaque, + (void *)&beacon2->RSNOpaque, + sizeof(beacon2->RSNOpaque)); + } + + /* EDCA Parameter set */ + if (beacon2->EDCAParamSet.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_EDCA_PARAM_SET_EID); + 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, + SIR_MAC_HT_CAPABILITIES_EID); + 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, SIR_MAC_HT_INFO_EID); + qdf_mem_copy((void *)&prb_rsp->HTInfo, (void *)&beacon2->HTInfo, + sizeof(beacon2->HTInfo)); + } + if (beacon2->VHTCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_CAPABILITIES_EID); + qdf_mem_copy((void *)&prb_rsp->VHTCaps, + (void *)&beacon2->VHTCaps, + sizeof(beacon2->VHTCaps)); + } + if (beacon2->VHTOperation.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_OPERATION_EID); + qdf_mem_copy((void *)&prb_rsp->VHTOperation, + (void *)&beacon2->VHTOperation, + sizeof(beacon2->VHTOperation)); + } + if (beacon2->VHTExtBssLoad.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_EXT_BSS_LOAD_EID); + 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)); + } + + /* 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)); + } + +} + +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 + * @pMac: pointer to mac structure + * @size: Size of the beacon to write to memory + * @length: Length field of the beacon to write to memory + * @psessionEntry: pe session + * @reason: beacon update reason + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +static QDF_STATUS write_beacon_to_memory(tpAniSirGlobal pMac, uint16_t size, + uint16_t length, + tpPESession psessionEntry, + 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) { + for (i = 0; i < psessionEntry->schBeaconOffsetEnd; i++) + psessionEntry->pSchBeaconFrameBegin[size++] = + psessionEntry->pSchBeaconFrameEnd[i]; + } + /* Update the beacon length */ + pBeacon = (tpAniBeaconStruct) psessionEntry->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 (!pMac->sch.schObject.fBeaconChanged) + return QDF_STATUS_E_FAILURE; + + /* + * Copy beacon data to SoftMAC shared memory... + * Do this by sending a message to HAL + */ + + size = (size + 3) & (~3); + status = sch_send_beacon_req(pMac, psessionEntry->pSchBeaconFrameBegin, + size, psessionEntry, reason); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("sch_send_beacon_req() returned an error %d, size %d", + status, size); + pMac->sch.schObject.fBeaconChanged = 0; + + return status; +} + +/** + * sch_generate_tim + * + * FUNCTION: + * Generate TIM + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac 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(tpAniSirGlobal pMac, 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++ = SIR_MAC_TIM_EID; + *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(tpAniSirGlobal pMac, + struct scheduler_msg *limMsg, + enum sir_bcn_update_reason reason) +{ + tpBeaconGenParams pMsg = (tpBeaconGenParams) limMsg->bodyptr; + uint32_t beaconSize; + tpPESession psessionEntry; + uint8_t sessionId; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + psessionEntry = pe_find_session_by_bssid(pMac, pMsg->bssId, &sessionId); + if (!psessionEntry) { + pe_err("session lookup fails"); + goto end; + } + + beaconSize = psessionEntry->schBeaconOffsetBegin; + + /* If SME is not in normal mode, no need to generate beacon */ + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE) { + pe_debug("PreBeaconInd received in invalid state: %d", + psessionEntry->limSmeState); + goto end; + } + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + + case eLIM_STA_IN_IBSS_ROLE: + /* generate IBSS parameter set */ + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) + status = + write_beacon_to_memory(pMac, (uint16_t) beaconSize, + (uint16_t) beaconSize, + psessionEntry, reason); + else + pe_err("can not send beacon for PEER session entry"); + break; + + case eLIM_AP_ROLE: { + uint8_t *ptr = + &psessionEntry->pSchBeaconFrameBegin[psessionEntry-> + schBeaconOffsetBegin]; + uint16_t timLength = 0; + + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) { + sch_generate_tim(pMac, &ptr, &timLength, + psessionEntry->dtimPeriod); + beaconSize += 2 + timLength; + status = + write_beacon_to_memory(pMac, (uint16_t) beaconSize, + (uint16_t) beaconSize, + psessionEntry, 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(psessionEntry)); + } + +end: + qdf_mem_free(pMsg); + + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c new file mode 100644 index 0000000000000000000000000000000000000000..32110239677b77258ce9a5506688d258817e0593 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c @@ -0,0 +1,1671 @@ +/* + * 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. + */ + +/* + * 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_api.h" +#include "lim_api.h" +#include "utils_api.h" +#include "sch_api.h" + +#include "lim_utils.h" +#include "lim_send_messages.h" +#include "lim_sta_hash_api.h" + +#include "rrm_api.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#include "wma.h" +/** + * Number of bytes of variation in beacon length from the last beacon + * to trigger reprogramming of rx delay register + */ +#define SCH_BEACON_LEN_DELTA 3 + +/* calculate 2^cw - 1 */ +#define CW_GET(cw) (((cw) == 0) ? 1 : ((1 << (cw)) - 1)) + +static void +ap_beacon_process_5_ghz(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session, + uint32_t phy_mode) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + + if (!session->htCapability) + return; + + if (bcn_struct->channelNumber != session->currentOperChannel) + 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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession 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->channelNumber != session->currentOperChannel) + return; + + tmp_exp = (!bcn_struct->erpPresent + && !bcn_struct->HTInfo.present) + /* if erp not present then 11B AP overlapping */ + || (!mac_ctx->roam.configParam.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent)); + if (!tmp_exp) + return; +#ifdef FEATURE_WLAN_ESE + if (session->isESEconnection) + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_INFO, + FL("[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->channelNumber != session->currentOperChannel) + return; + + tmp_exp = (!bcn_struct->erpPresent && !bcn_struct->HTInfo.present) + /* if erp not present then 11B AP overlapping */ + || (!mac_ctx->roam.configParam.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent)); + if (tmp_exp) { +#ifdef FEATURE_WLAN_ESE + if (session->isESEconnection) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("[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->roam.configParam.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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session) +{ + uint32_t phy_mode; + enum band_info rf_band = BAND_UNKNOWN; + /* Get RF band from session */ + rf_band = session->limRFBand; + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + + if (BAND_5G == rf_band) + ap_beacon_process_5_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); + else if (BAND_2G == rf_band) + ap_beacon_process_24_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); +} + +/* -------------------------------------------------------------------- */ + +/** + * __sch_beacon_process_no_session + * + * FUNCTION: + * Process the received beacon frame when + * -- Station is not scanning + * -- No corresponding session is found + * + * LOGIC: + * Following scenarios exist when Session Does not exist: + * * IBSS Beacons, when IBSS session already exists with same SSID, + * but from STA which has not yet joined and has a different BSSID. + * - invoke lim_handle_ibs_scoalescing with the session context of existing IBSS session. + * + * * IBSS Beacons when IBSS session does not exist, only Infra or BT-AMP session exists, + * then save the beacon in the scan results and throw it away. + * + * * Infra Beacons + * - beacons received when no session active + * should not come here, it should be handled as part of scanning, + * else they should not be getting received, should update scan results and drop it if that happens. + * - beacons received when IBSS session active: + * update scan results and drop it. + * - beacons received when Infra session(STA) is active: + * update scan results and drop it + * - beacons received when BT-STA session is active: + * update scan results and drop it. + * - beacons received when Infra/BT-STA or Infra/IBSS is active. + * update scan results and drop it. + * + + */ +static void __sch_beacon_process_no_session(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + uint8_t *pRxPacketInfo) +{ + tpPESession psessionEntry = NULL; + + psessionEntry = lim_is_ibss_session_active(pMac); + if (psessionEntry != NULL) { + lim_handle_ibss_coalescing(pMac, pBeacon, pRxPacketInfo, + psessionEntry); + } + return; +} + +/** + * get_operating_channel_width() - Get operating channel width + * @stads - station entry. + * + * This function returns the operating channel width based on + * the supported channel width entry. + * + * Return: tSirMacHTChannelWidth on success + */ +static tSirMacHTChannelWidth get_operating_channel_width(tpDphHashNode stads) +{ + tSirMacHTChannelWidth ch_width = eHT_CHANNEL_WIDTH_20MHZ; + + if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + else if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + else if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + ch_width = eHT_CHANNEL_WIDTH_80MHZ; + else if (stads->htSupportedChannelWidthSet) + ch_width = eHT_CHANNEL_WIDTH_40MHZ; + else + ch_width = eHT_CHANNEL_WIDTH_20MHZ; + + return ch_width; +} + +/* + * sch_bcn_process_sta() - Process the received beacon frame for sta, + * bt_amp_sta + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * @bssIdx: bss index + * @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(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session, uint8_t *bssIdx, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + uint32_t bi; + tpDphHashNode pStaDs = 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 ((uint8_t) bcn->channelNumber != session->currentOperChannel) { + pe_err("Channel Change from %d --> %d - Ignoring beacon!", + session->currentOperChannel, + bcn->channelNumber); + 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); + if (lim_get_sta_hash_bssidx(mac_ctx, DPH_STA_HASH_INDEX_PEER, bssIdx, + session) != QDF_STATUS_SUCCESS) + return false; + + beaconParams->bssIdx = *bssIdx; + 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) { + cfg_set_int(mac_ctx, WNI_CFG_CFP_PERIOD, + bcn->cfParamSet.cfpPeriod); + lim_send_cf_params(mac_ctx, *bssIdx, + bcn->cfParamSet.cfpCount, + bcn->cfParamSet.cfpPeriod); + } + + /* No need to send DTIM Period and Count to HAL/SMAC */ + /* SMAC already parses TIM bit. */ + if (bcn->timPresent) + cfg_set_int(mac_ctx, WNI_CFG_DTIM_PERIOD, bcn->tim.dtimPeriod); + + if (mac_ctx->lim.gLimProtectionControl != + WNI_CFG_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); + + pStaDs = 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) { + status = sch_beacon_edca_process(mac_ctx, + &bcn->edcaParams, + session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("EDCA parameter processing error"); + } else if (pStaDs != NULL) { + /* If needed, downgrade the EDCA parameters */ + lim_set_active_edca_params(mac_ctx, + session->gLimEdcaParams, session); + lim_send_edca_params(mac_ctx, + session->gLimEdcaParamsActive, + pStaDs->bssId, false); + } 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; +} + +/** + * update_nss() - Function to update NSS + * @mac_ctx: pointer to Global Mac structure + * @sta_ds: pointer to tpDphHashNode + * @beacon: pointer to tpSchBeaconStruct + * @session_entry: pointer to tpPESession + * @mgmt_hdr: pointer to tpSirMacMgmtHdr + * + * function to update NSS + * + * Return: none + */ +static void update_nss(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpSchBeaconStruct beacon, tpPESession session_entry, + tpSirMacMgmtHdr mgmt_hdr) +{ + if (sta_ds->vhtSupportedRxNss != (beacon->OperatingMode.rxNSS + 1)) { + if (session_entry->nss_forced_1x1) { + pe_debug("Not Updating NSS for special AP"); + return; + } + sta_ds->vhtSupportedRxNss = + beacon->OperatingMode.rxNSS + 1; + lim_set_nss_change(mac_ctx, session_entry, + sta_ds->vhtSupportedRxNss, sta_ds->staIndex, + mgmt_hdr->sa); + } +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +static void +sch_bcn_update_he_ies(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpPESession 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(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpPESession session, tpSchBeaconStruct bcn, + tpSirMacMgmtHdr mac_hdr) +{ + return; +} +#endif + +static void +sch_bcn_update_opmode_change(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpPESession session, tpSchBeaconStruct bcn, + tpSirMacMgmtHdr mac_hdr, uint8_t cb_mode) +{ + bool skip_opmode_update = false; + uint8_t oper_mode; + uint32_t fw_vht_ch_wd = wma_get_vht_ch_width(); + uint8_t ch_width = 0; + + /* + * 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 (session->vhtCapability && bcn->OperatingMode.present) { + update_nss(mac_ctx, sta_ds, bcn, session, mac_hdr); + oper_mode = get_operating_channel_width(sta_ds); + if ((oper_mode == eHT_CHANNEL_WIDTH_80MHZ) && + (bcn->OperatingMode.chanWidth > eHT_CHANNEL_WIDTH_80MHZ)) + skip_opmode_update = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode) { + /* + * if channel bonding is disabled from INI do not + * update the chan width + */ + pe_debug_rl("CB disabled skip bw update: old[%d] new[%d]", + oper_mode, + bcn->OperatingMode.chanWidth); + return; + } + + if (!skip_opmode_update && + ((oper_mode != bcn->OperatingMode.chanWidth) || + (sta_ds->vhtSupportedRxNss != + (bcn->OperatingMode.rxNSS + 1)))) { + pe_debug("received OpMode Chanwidth %d, staIdx = %d", + bcn->OperatingMode.chanWidth, sta_ds->staIndex); + 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]); + + if ((bcn->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_160MHZ) && + (fw_vht_ch_wd > eHT_CHANNEL_WIDTH_80MHZ)) { + pe_debug("Updating the CH Width to 160MHz"); + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + } else if (bcn->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_80MHZ) { + pe_debug("Updating the CH Width to 80MHz"); + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_width = eHT_CHANNEL_WIDTH_80MHZ; + } else if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_40MHZ) { + pe_debug("Updating the CH Width to 40MHz"); + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_width = eHT_CHANNEL_WIDTH_40MHZ; + } else if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_20MHZ) { + pe_debug("Updating the CH Width to 20MHz"); + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + ch_width = eHT_CHANNEL_WIDTH_20MHZ; + } + lim_check_vht_op_mode_change(mac_ctx, session, + ch_width, sta_ds->staIndex, mac_hdr->sa); + update_nss(mac_ctx, sta_ds, bcn, session, mac_hdr); + } + return; + } + + if (!(session->vhtCapability && bcn->VHTOperation.present)) + return; + + oper_mode = sta_ds->vhtSupportedChannelWidthSet; + if ((oper_mode == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && + (oper_mode < bcn->VHTOperation.chanWidth)) + skip_opmode_update = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode) { + /* + * if channel bonding is disabled from INI do not + * update the chan width + */ + pe_debug_rl("CB disabled skip bw update: old[%d] new[%d]", + oper_mode, bcn->OperatingMode.chanWidth); + + return; + } + + if (!skip_opmode_update && + (oper_mode != bcn->VHTOperation.chanWidth)) { + pe_debug("received VHTOP CHWidth %d staIdx = %d", + bcn->VHTOperation.chanWidth, sta_ds->staIndex); + 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]); + + if ((bcn->VHTOperation.chanWidth >= + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) && + (fw_vht_ch_wd > eHT_CHANNEL_WIDTH_80MHZ)) { + pe_debug("Updating the CH Width to 160MHz"); + sta_ds->vhtSupportedChannelWidthSet = + bcn->VHTOperation.chanWidth; + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + } else if (bcn->VHTOperation.chanWidth >= + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + pe_debug("Updating the CH Width to 80MHz"); + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_width = eHT_CHANNEL_WIDTH_80MHZ; + } else if (bcn->VHTOperation.chanWidth == + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ) { + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + if (bcn->HTCaps.supportedChannelWidthSet) { + pe_debug("Updating the CH Width to 40MHz"); + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_width = eHT_CHANNEL_WIDTH_40MHZ; + } else { + pe_debug("Updating the CH Width to 20MHz"); + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + ch_width = eHT_CHANNEL_WIDTH_20MHZ; + } + } + lim_check_vht_op_mode_change(mac_ctx, session, ch_width, + sta_ds->staIndex, mac_hdr->sa); + } +} + +/* + * sch_bcn_process_sta_ibss() - Process the received beacon frame + * for sta, bt_amp_sta and ibss + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * @bssIdx: bss index + * @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 and ibss + * + * Return: void + */ +static void +sch_bcn_process_sta_ibss(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session, uint8_t *bssIdx, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + tpDphHashNode pStaDs = NULL; + uint16_t aid; + uint8_t cb_mode; + + if (CHAN_ENUM_14 >= session->currentOperChannel) { + if (session->force_24ghz_in_ht20) + cb_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + else + cb_mode = + mac_ctx->roam.configParam.channelBondingMode24GHz; + } else + cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz; + /* check for VHT capability */ + pStaDs = dph_lookup_hash_entry(mac_ctx, pMh->sa, &aid, + &session->dph.dphHashTable); + if ((NULL == pStaDs) || ((NULL != pStaDs) && + (STA_INVALID_IDX == pStaDs->staIndex))) + return; + sch_bcn_update_opmode_change(mac_ctx, pStaDs, session, bcn, pMh, + cb_mode); + sch_bcn_update_he_ies(mac_ctx, pStaDs, session, bcn, pMh); + return; +} + +/** + * get_local_power_constraint_beacon() - extracts local constraint + * from beacon + * @bcn: beacon structure + * @local_constraint: local constraint pointer + * + * Return: None + */ +#ifdef FEATURE_WLAN_ESE +static void get_local_power_constraint_beacon( + tpSchBeaconStruct bcn, + int8_t *local_constraint) +{ + if (bcn->eseTxPwr.present) + *local_constraint = bcn->eseTxPwr.power_limit; +} +#else +static void get_local_power_constraint_beacon( + tpSchBeaconStruct bcn, + int8_t *local_constraint) +{ + +} +#endif + +/* + * __sch_beacon_process_for_session() - Process the received beacon frame when + * station is not scanning and corresponding session is found + * + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * + * Following scenarios exist when Session exists + * IBSS STA receiving beacons from IBSS Peers, who are part of IBSS. + * - call lim_handle_ibs_scoalescing with that session context. + * Infra STA receiving beacons from AP to which it is connected + * - call sch_beacon_processFromAP with that session's context. + * - call sch_beacon_processFromAP with that session's context. + * (here need to make sure BTAP creates session entry for BT STA) + * - just update the beacon count for heart beat purposes for now, + * for now, don't process the beacon. + * Infra/IBSS both active and receives IBSS beacon: + * - call lim_handle_ibs_scoalescing with that session context. + * Infra/IBSS both active and receives Infra beacon: + * - call sch_beacon_processFromAP with that session's context. + * any updates to EDCA parameters will be effective for IBSS as well, + * even though no WMM for IBSS ?? Need to figure out how to handle + * this scenario. + * Infra/BTSTA both active and receive Infra beacon. + * - change in EDCA parameters on Infra affect the BTSTA link. + * Update the same parameters on BT link + * Infra/BTSTA both active and receive BT-AP beacon. + * - update beacon cnt for heartbeat + * Infra/BTAP both active and receive Infra beacon. + * - BT-AP starts advertising BE parameters from Infra AP, if they get + * changed. + * Infra/BTAP both active and receive BTSTA beacon. + * - update beacon cnt for heartbeat + * + * Return: void + */ +static void __sch_beacon_process_for_session(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session) +{ + uint8_t bssIdx = 0; + tUpdateBeaconParams beaconParams; + uint8_t sendProbeReq = false; + tpSirMacMgmtHdr pMh = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + int8_t regMax = 0, maxTxPower = 0, local_constraint; + struct lim_max_tx_pwr_attr tx_pwr_attr = {0}; + + qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + beaconParams.paramChangeBitmap = 0; + + if (LIM_IS_IBSS_ROLE(session)) { + lim_handle_ibss_coalescing(mac_ctx, bcn, rx_pkt_info, session); + } else if (LIM_IS_STA_ROLE(session)) { + if (false == sch_bcn_process_sta(mac_ctx, bcn, + rx_pkt_info, session, &bssIdx, + &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_IS_IBSS_ROLE(session)) + lim_update_sta_run_time_ht_switch_chnl_params(mac_ctx, + &bcn->HTInfo, bssIdx, session); + + if ((LIM_IS_STA_ROLE(session) && !wma_is_csa_offload_enabled()) + || LIM_IS_IBSS_ROLE(session)) { + /* Channel Switch information element updated */ + if (bcn->channelSwitchPresent) { + /* + * on receiving channel switch announcement from AP, + * delete all TDLS peers before leaving BSS and proceed + * for channel switch + */ + if (LIM_IS_STA_ROLE(session)) { + lim_update_tdls_set_state_for_fw(session, + false); + lim_delete_tdls_peers(mac_ctx, session); + } + lim_update_channel_switch(mac_ctx, bcn, session); + } else if (session->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) { + lim_cancel_dot11h_channel_switch(mac_ctx, session); + } + } + if (LIM_IS_STA_ROLE(session) + || LIM_IS_IBSS_ROLE(session)) + sch_bcn_process_sta_ibss(mac_ctx, bcn, + rx_pkt_info, session, &bssIdx, + &beaconParams, &sendProbeReq, pMh); + /* Obtain the Max Tx power for the current regulatory */ + regMax = cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + + local_constraint = regMax; + + if (mac_ctx->roam.configParam.allow_tpc_from_ap) { + get_local_power_constraint_beacon(bcn, &local_constraint); + pe_debug("ESE localPowerConstraint = %d,", + local_constraint); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + bcn->powerConstraintPresent) { + local_constraint = regMax; + local_constraint -= + bcn->localPowerConstraint.localPowerConstraints; + pe_debug("localPowerConstraint = %d,", + local_constraint); + } + } + + tx_pwr_attr.reg_max = regMax; + tx_pwr_attr.ap_tx_power = local_constraint; + tx_pwr_attr.ini_tx_power = mac_ctx->roam.configParam.nTxPowerCap; + tx_pwr_attr.frequency = + wlan_reg_get_channel_freq(mac_ctx->pdev, + session->currentOperChannel); + + maxTxPower = lim_get_max_tx_power(mac_ctx, &tx_pwr_attr); + + pe_debug("RegMax = %d, MaxTx pwr = %d", + regMax, maxTxPower); + + /* If maxTxPower is increased or decreased */ + if (maxTxPower != session->maxTxPower) { + pe_debug( + FL("Local power constraint change, Updating new maxTx power %d from old pwr %d"), + maxTxPower, session->maxTxPower); + if (lim_send_set_max_tx_power_req(mac_ctx, maxTxPower, session) + == QDF_STATUS_SUCCESS) + session->maxTxPower = maxTxPower; + } + + /* Indicate to LIM that Beacon is received */ + if (bcn->HTInfo.present) + lim_received_hb_handler(mac_ctx, + (uint8_t) bcn->HTInfo.primaryChannel, session); + else + lim_received_hb_handler(mac_ctx, (uint8_t) bcn->channelNumber, + 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->currentOperChannel, + session->selfMacAddr, 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.", + session->peSessionId); + pe_debug("sending beacon param change bitmap: 0x%x", + beaconParams.paramChangeBitmap); + lim_send_beacon_params(mac_ctx, &beaconParams, session); + } + + if ((session->pePersona == 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; + } +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +static void ap_update_bss_color_info(tpAniSirGlobal mac_ctx, + tpPESession 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(tpAniSirGlobal mac_ctx, tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession 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(tpAniSirGlobal mac_ctx, + tpPESession ap_session, + tSchBeaconStruct *bcn, + tUpdateBeaconParams *bcn_prm) +{ +} +#endif + +void sch_beacon_process_for_ap(tpAniSirGlobal mac_ctx, + uint8_t session_id, + uint8_t *rx_pkt_info, + tSchBeaconStruct *bcn) +{ + tpPESession 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.bssIdx = ap_session->bssIdx; + + 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 != + WNI_CFG_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); + } +} + +/** + * 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(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + static tSchBeaconStruct bcn; + + /* 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; + } + + /* + * Now process the beacon in the context of the BSS which is + * transmitting the beacons, if one is found + */ + if (session == NULL) + __sch_beacon_process_no_session(mac_ctx, &bcn, rx_pkt_info); + else + __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(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *edca, + tpPESession session) +{ + uint8_t i; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + host_log_qos_edca_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + pe_debug("Updating parameter set count: Old %d ---> new %d", + session->gLimEdcaParamSetCount, edca->qosInfo.count); + + session->gLimEdcaParamSetCount = edca->qosInfo.count; + session->gLimEdcaParams[EDCA_AC_BE] = edca->acbe; + session->gLimEdcaParams[EDCA_AC_BK] = edca->acbk; + session->gLimEdcaParams[EDCA_AC_VI] = edca->acvi; + session->gLimEdcaParams[EDCA_AC_VO] = edca->acvo; + + if (pMac->roam.configParam.enable_edca_params) { + session->gLimEdcaParams[EDCA_AC_VO].aci.aifsn = + pMac->roam.configParam.edca_vo_aifs; + session->gLimEdcaParams[EDCA_AC_VI].aci.aifsn = + pMac->roam.configParam.edca_vi_aifs; + session->gLimEdcaParams[EDCA_AC_BK].aci.aifsn = + pMac->roam.configParam.edca_bk_aifs; + session->gLimEdcaParams[EDCA_AC_BE].aci.aifsn = + pMac->roam.configParam.edca_be_aifs; + + session->gLimEdcaParams[EDCA_AC_VO].cw.min = + pMac->roam.configParam.edca_vo_cwmin; + session->gLimEdcaParams[EDCA_AC_VI].cw.min = + pMac->roam.configParam.edca_vi_cwmin; + session->gLimEdcaParams[EDCA_AC_BK].cw.min = + pMac->roam.configParam.edca_bk_cwmin; + session->gLimEdcaParams[EDCA_AC_BE].cw.min = + pMac->roam.configParam.edca_be_cwmin; + + session->gLimEdcaParams[EDCA_AC_VO].cw.max = + pMac->roam.configParam.edca_vo_cwmax; + session->gLimEdcaParams[EDCA_AC_VI].cw.max = + pMac->roam.configParam.edca_vi_cwmax; + session->gLimEdcaParams[EDCA_AC_BK].cw.max = + pMac->roam.configParam.edca_bk_cwmax; + session->gLimEdcaParams[EDCA_AC_BE].cw.max = + pMac->roam.configParam.edca_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[EDCA_AC_BE].aci.aci; + log_ptr->cw_be = + session->gLimEdcaParams[EDCA_AC_BE].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_BE].cw.min; + log_ptr->txoplimit_be = + session->gLimEdcaParams[EDCA_AC_BE].txoplimit; + log_ptr->aci_bk = + session->gLimEdcaParams[EDCA_AC_BK].aci.aci; + log_ptr->cw_bk = + session->gLimEdcaParams[EDCA_AC_BK].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_BK].cw.min; + log_ptr->txoplimit_bk = + session->gLimEdcaParams[EDCA_AC_BK].txoplimit; + log_ptr->aci_vi = + session->gLimEdcaParams[EDCA_AC_VI].aci.aci; + log_ptr->cw_vi = + session->gLimEdcaParams[EDCA_AC_VI].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_VI].cw.min; + log_ptr->txoplimit_vi = + session->gLimEdcaParams[EDCA_AC_VI].txoplimit; + log_ptr->aci_vo = + session->gLimEdcaParams[EDCA_AC_VO].aci.aci; + log_ptr->cw_vo = + session->gLimEdcaParams[EDCA_AC_VO].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_VO].cw.min; + log_ptr->txoplimit_vo = + session->gLimEdcaParams[EDCA_AC_VO].txoplimit; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pe_debug("Edsa param enabled in ini %d. Updating Local EDCA Params(gLimEdcaParams) to: ", + pMac->roam.configParam.enable_edca_params); + for (i = 0; i < MAX_NUM_AC; i++) { + pe_debug("AC[%d]: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", + i, session->gLimEdcaParams[i].aci.aifsn, + session->gLimEdcaParams[i].aci.acm, + session->gLimEdcaParams[i].cw.min, + session->gLimEdcaParams[i].cw.max, + session->gLimEdcaParams[i].txoplimit); + } + return QDF_STATUS_SUCCESS; +} + +void lim_enable_obss_detection_config(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!session) { + pe_err("Invalid session, protection not enabled"); + return; + } + + if (session->gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) { + pe_err("protectiond disabled, force policy, session %d", + session->smeSessionId); + return; + } + + if (mac_ctx->lim.global_obss_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->lim.global_obss_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(tpAniSirGlobal mac_ctx, + tpPESession session, + struct obss_detection_cfg *cfg) +{ + uint32_t phy_mode; + enum band_info rf_band = 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 == 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->roam.configParam.ignore_peer_erp_info) + cfg->obss_11b_sta_detect_mode = + OBSS_OFFLOAD_DETECTION_DISABLED; + + if (mac_ctx->roam.configParam.ignore_peer_ht_opmode) + cfg->obss_ht_legacy_detect_mode = + OBSS_OFFLOAD_DETECTION_DISABLED; + } + + if ((rf_band == 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 == BAND_2G) || (rf_band == 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(tpAniSirGlobal mac_ctx, + tpPESession 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 == + WNI_CFG_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) { + pe_err("Failed to allocate memory"); + 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)) { + pe_err("Failed to post WMA_OBSS_DETECTION_REQ to WMA"); + qdf_mem_free(req_param); + return status; + } + } else { + pe_debug("Skiping WMA_OBSS_DETECTION_REQ, force = %d", force); + } + + return status; +} + +QDF_STATUS lim_process_obss_detection_ind(tpAniSirGlobal 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; + tpPESession session; + tUpdateBeaconParams bcn_prm; + enum band_info rf_band = BAND_UNKNOWN; + struct obss_detection_cfg *cur_detect; + + pe_debug("obss detect ind id %d, reason %d, msk 0x%x, " MAC_ADDRESS_STR, + obss_detection->vdev_id, obss_detection->reason, + obss_detection->matched_detection_masks, + MAC_ADDR_ARRAY(obss_detection->matched_bssid_addr)); + + session = pe_find_session_by_sme_session_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 != 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 != 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 != 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 != 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 != 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 != 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/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_message.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_message.c new file mode 100644 index 0000000000000000000000000000000000000000..181cbdec130b750e2a0ad8c26e47df3ce28cbb6b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_message.c @@ -0,0 +1,577 @@ +/* + * 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. + */ + +#include "cds_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "lim_api.h" +#include "lim_send_messages.h" + +#include "sch_api.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))) + +/* local functions */ +static QDF_STATUS +get_wmm_local_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]); +static void +set_sch_edca_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + tpPESession psessionEntry); + +/* -------------------------------------------------------------------- */ +/** + * sch_set_beacon_interval + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_set_beacon_interval(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t bi; + + bi = psessionEntry->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; + } + + pMac->sch.schObject.gSchBeaconInterval = (uint16_t) bi; +} + +static void sch_edca_profile_update_all(tpAniSirGlobal pmac) +{ + uint32_t i; + tpPESession 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_process_message + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_process_message(tpAniSirGlobal pMac, struct scheduler_msg *pSchMsg) +{ + tpPESession psessionEntry = &pMac->lim.gpSession[0]; + + switch (pSchMsg->type) { + case SIR_CFG_PARAM_UPDATE_IND: + switch (pSchMsg->bodyval) { + case WNI_CFG_BEACON_INTERVAL: + /* What to do for IBSS ?? - TBD */ + if (LIM_IS_AP_ROLE(psessionEntry)) + sch_set_beacon_interval(pMac, psessionEntry); + break; + + case WNI_CFG_COUNTRY_CODE: + pe_debug("sch: WNI_CFG_COUNTRY_CODE changed"); + sch_edca_profile_update_all(pMac); + break; + + case WNI_CFG_EDCA_PROFILE: + sch_edca_profile_update(pMac, psessionEntry); + break; + + case WNI_CFG_EDCA_ANI_ACBK_LOCAL: + case WNI_CFG_EDCA_ANI_ACBE_LOCAL: + case WNI_CFG_EDCA_ANI_ACVI_LOCAL: + case WNI_CFG_EDCA_ANI_ACVO_LOCAL: + case WNI_CFG_EDCA_WME_ACBK_LOCAL: + case WNI_CFG_EDCA_WME_ACBE_LOCAL: + case WNI_CFG_EDCA_WME_ACVI_LOCAL: + case WNI_CFG_EDCA_WME_ACVO_LOCAL: + if (LIM_IS_AP_ROLE(psessionEntry)) + sch_qos_update_local(pMac, psessionEntry); + break; + + case WNI_CFG_EDCA_ANI_ACBK: + case WNI_CFG_EDCA_ANI_ACBE: + case WNI_CFG_EDCA_ANI_ACVI: + case WNI_CFG_EDCA_ANI_ACVO: + case WNI_CFG_EDCA_WME_ACBK: + case WNI_CFG_EDCA_WME_ACBE: + case WNI_CFG_EDCA_WME_ACVI: + case WNI_CFG_EDCA_WME_ACVO: + if (LIM_IS_AP_ROLE(psessionEntry)) { + sch_qos_update_broadcast(pMac, psessionEntry); + } + break; + + default: + pe_err("Cfg param %d indication not handled", + pSchMsg->bodyval); + } + break; + + default: + pe_err("Unknown message in schMsgQ type %d", pSchMsg->type); + } + +} + +/* get the local or broadcast parameters based on the profile sepcified in the config */ +/* params are delivered in this order: BK, BE, VI, VO */ +static QDF_STATUS +sch_get_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + uint8_t local) +{ + uint32_t val; + uint32_t i, idx; + uint32_t *prf; + uint8_t country_code_str[WNI_CFG_COUNTRY_CODE_LEN]; + uint32_t country_code_len = WNI_CFG_COUNTRY_CODE_LEN; + uint32_t ani_l[] = { + WNI_CFG_EDCA_ANI_ACBE_LOCAL, WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL, WNI_CFG_EDCA_ANI_ACVO_LOCAL}; + uint32_t wme_l[] = { + WNI_CFG_EDCA_WME_ACBE_LOCAL, WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, WNI_CFG_EDCA_WME_ACVO_LOCAL}; + uint32_t etsi_l[] = {WNI_CFG_EDCA_ETSI_ACBE_LOCAL, + WNI_CFG_EDCA_ETSI_ACBK_LOCAL, + WNI_CFG_EDCA_ETSI_ACVI_LOCAL, + WNI_CFG_EDCA_ETSI_ACVO_LOCAL}; + uint32_t ani_b[] = { WNI_CFG_EDCA_ANI_ACBE, WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACVI, WNI_CFG_EDCA_ANI_ACVO}; + uint32_t wme_b[] = { WNI_CFG_EDCA_WME_ACBE, WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACVI, WNI_CFG_EDCA_WME_ACVO}; + uint32_t etsi_b[] = {WNI_CFG_EDCA_ETSI_ACBE, WNI_CFG_EDCA_ETSI_ACBK, + WNI_CFG_EDCA_ETSI_ACVI, WNI_CFG_EDCA_ETSI_ACVO}; + + if (wlan_cfg_get_str(pMac, WNI_CFG_COUNTRY_CODE, country_code_str, + &country_code_len) == QDF_STATUS_SUCCESS && + 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 if (wlan_cfg_get_int(pMac, WNI_CFG_EDCA_PROFILE, &val) != + QDF_STATUS_SUCCESS) { + pe_err("failed to cfg get EDCA_PROFILE id %d", + WNI_CFG_EDCA_PROFILE); + return QDF_STATUS_E_FAILURE; + } + + 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[WNI_CFG_EDCA_ANI_ACBK_LEN]; + uint32_t len = WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN; + + if (wlan_cfg_get_str + (pMac, (uint16_t) prf[i], (uint8_t *) &data[0], + &len) != QDF_STATUS_SUCCESS) { + pe_err("cfgGet failed for %d", prf[i]); + return QDF_STATUS_E_FAILURE; + } + if (len > WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN) { + pe_err("cfgGet for %d: length is %d instead of %d", + prf[i], len, WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN); + return QDF_STATUS_E_FAILURE; + } + for (idx = 0; idx < 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(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + uint8_t i, j; + tpPESession 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].currentOperChannel == + session->currentOperChannel) + && (mac_ctx->lim.gpSession[i].limSystemRole + == eLIM_STA_ROLE))) + continue; + + concurrent_session = &(mac_ctx->lim.gpSession[i]); + break; + } + + if (concurrent_session == NULL) + 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 < MAX_NUM_AC; 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(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + uint8_t i; + bool updated = false; + QDF_STATUS status; + + if (sch_get_params(pMac, params, false) != QDF_STATUS_SUCCESS) { + pe_debug("QosUpdateBroadcast: failed"); + return; + } + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + pe_debug("QosUpdBcast: mode %d", phyMode); + + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPG_IDX; + } else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPA_IDX; + } + + for (i = 0; i < MAX_NUM_AC; i++) { + if (psessionEntry->gLimEdcaParamsBC[i].aci.acm != + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]) { + psessionEntry->gLimEdcaParamsBC[i].aci.acm = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]; + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].aci.aifsn != + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]) { + psessionEntry->gLimEdcaParamsBC[i].aci.aifsn = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]; + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].cw.min != + convert_cw(GET_CW(¶ms[i][cwminidx]))) { + psessionEntry->gLimEdcaParamsBC[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].cw.max != + convert_cw(GET_CW(¶ms[i][cwmaxidx]))) { + psessionEntry->gLimEdcaParamsBC[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].txoplimit != + (uint16_t) params[i][txopidx]) { + psessionEntry->gLimEdcaParamsBC[i].txoplimit = + (uint16_t) params[i][txopidx]; + updated = true; + } + + pe_debug("QoSUpdateBCast: AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", + i, psessionEntry->gLimEdcaParamsBC[i].aci.aifsn, + psessionEntry->gLimEdcaParamsBC[i].aci.acm, + psessionEntry->gLimEdcaParamsBC[i].cw.min, + psessionEntry->gLimEdcaParamsBC[i].cw.max, + psessionEntry->gLimEdcaParamsBC[i].txoplimit); + + } + + /* + * 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(pMac, psessionEntry)) + updated = true; + if (updated) + psessionEntry->gLimEdcaParamSetCount++; + + status = sch_set_fixed_beacon_fields(pMac, psessionEntry); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Unable to set beacon fields!"); +} + +void sch_qos_update_local(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + QDF_STATUS status; + + status = sch_get_params(pMac, params, true /*local */); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("sch_get_params(local) failed"); + return; + } + + set_sch_edca_params(pMac, params, psessionEntry); + + /* For AP, the bssID is stored in LIM Global context. */ + lim_send_edca_params(pMac, psessionEntry->gLimEdcaParams, + psessionEntry->bssIdx, false); +} + +/** ---------------------------------------------------------- + \fn sch_set_default_edca_params + \brief This function sets the gLimEdcaParams to the default + \ local wmm profile. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +void sch_set_default_edca_params(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + + if (get_wmm_local_params(pMac, params) != QDF_STATUS_SUCCESS) { + pe_err("get_wmm_local_params() failed"); + return; + } + + set_sch_edca_params(pMac, params, psessionEntry); + return; +} + +/** ---------------------------------------------------------- + \fn set_sch_edca_params + \brief This function fills in the gLimEdcaParams structure + \ with the given edca params. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +static void +set_sch_edca_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + tpPESession psessionEntry) +{ + uint32_t i; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + pe_debug("lim_get_phy_mode() = %d", phyMode); + /* if (pMac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11G) */ + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPG_IDX; + } + /* else if (pMac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11B) */ + else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPA_IDX; + } + + for (i = 0; i < MAX_NUM_AC; i++) { + psessionEntry->gLimEdcaParams[i].aci.acm = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]; + psessionEntry->gLimEdcaParams[i].aci.aifsn = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]; + psessionEntry->gLimEdcaParams[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + psessionEntry->gLimEdcaParams[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + psessionEntry->gLimEdcaParams[i].txoplimit = + (uint16_t) params[i][txopidx]; + + pe_debug("AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", + i, psessionEntry->gLimEdcaParams[i].aci.aifsn, + psessionEntry->gLimEdcaParams[i].aci.acm, + psessionEntry->gLimEdcaParams[i].cw.min, + psessionEntry->gLimEdcaParams[i].cw.max, + psessionEntry->gLimEdcaParams[i].txoplimit); + + } + return; +} + +/** ---------------------------------------------------------- + \fn get_wmm_local_params + \brief This function gets the WMM local edca parameters. + \param tpAniSirGlobal pMac + \param uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN] + \return none + \ ------------------------------------------------------------ */ +static QDF_STATUS +get_wmm_local_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]) +{ + uint32_t i, idx; + uint32_t *prf; + uint32_t wme_l[] = { + WNI_CFG_EDCA_WME_ACBE_LOCAL, WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, WNI_CFG_EDCA_WME_ACVO_LOCAL}; + + prf = &wme_l[0]; + for (i = 0; i < 4; i++) { + uint8_t data[WNI_CFG_EDCA_ANI_ACBK_LEN]; + uint32_t len = WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN; + + if (wlan_cfg_get_str + (pMac, (uint16_t) prf[i], (uint8_t *) &data[0], + &len) != QDF_STATUS_SUCCESS) { + pe_err("cfgGet failed for %d", prf[i]); + return QDF_STATUS_E_FAILURE; + } + if (len > WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN) { + pe_err("cfgGet for %d: length is %d instead of %d", + prf[i], len, WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN); + return QDF_STATUS_E_FAILURE; + } + for (idx = 0; idx < len; idx++) + params[i][idx] = (uint32_t) data[idx]; + } + return QDF_STATUS_SUCCESS; +} + +/** ---------------------------------------------------------- + \fn sch_edca_profile_update + \brief This function updates the local and broadcast + \ EDCA params in the gLimEdcaParams structure. It also + \ updates the edcaParamSetCount. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +void sch_edca_profile_update(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + sch_qos_update_local(pMac, psessionEntry); + sch_qos_update_broadcast(pMac, psessionEntry); + } +} + +/* -------------------------------------------------------------------- */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h new file mode 100644 index 0000000000000000000000000000000000000000..e55fb03898b38c752f5529889418e61b67bfeea6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h @@ -0,0 +1,35 @@ +/* + * 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/drivers/staging/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h new file mode 100644 index 0000000000000000000000000000000000000000..ae6378edf443b8cac0050336e22862edbfbe1b30 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h @@ -0,0 +1,102 @@ +/* + * 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. + */ + +#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 + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Type declarations + -------------------------------------------------------------------------*/ + +/** + * sys_rsp_cb() - SYS async resonse 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); + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Function declarations and documenation + -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + + \brief sys_build_message_header() - Build / initialize a SYS message header + + 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. + + \param sysMsgId - a valid message ID for a SYS message. See the + SYS_MSG_ID enum for all the valid SYS message IDs. + + \param pMsg - pointer to the message structure to be setup. + + \return + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sys_build_message_header(SYS_MSG_ID sysMsgId, + struct scheduler_msg *pMsg); +/** + * umac_stop() - send schedule message to mc thread to stop umac (sme and mac) + * @p_cds_context: cds context + * + * Return: status of operation + */ +QDF_STATUS umac_stop(void); + +QDF_STATUS sys_mc_process_handler(struct scheduler_msg *msg); + +#endif /* WLAN_QCT_SYS_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c new file mode 100644 index 0000000000000000000000000000000000000000..d9a16e07c4d1f000433dcc2ae8d1ae24fcd6e7ae --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c @@ -0,0 +1,300 @@ +/* + * 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. + */ + +#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; + +/** + * sys_build_message_header() - to build the sys message header + * @umac_stop_msgId: message id + * @pMsg: pointer to message context + * + * This API is used to build the sys message header. + * + * Return: QDF_STATUS + */ +QDF_STATUS sys_build_message_header(SYS_MSG_ID umac_stop_msg_id, + struct scheduler_msg *msg) +{ + msg->type = umac_stop_msg_id; + msg->reserved = SYS_MSG_COOKIE; + + return QDF_STATUS_SUCCESS; +} + +/** + * umac_stop_complete_cb() - a callback when system stop completes + * @user_data: pointer to user provided data context + * + * this callback is used once system stop is completed. + * + * Return: none + */ +#ifdef QDF_ENABLE_TRACING +static void umac_stop_complete_cb(void *user_data) +{ + qdf_event_t *stop_evt = (qdf_event_t *) user_data; + QDF_STATUS qdf_status = qdf_event_set(stop_evt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + +} +#else +static void umac_stop_complete_cb(void *user_data) +{ + return; +} +#endif + +/** + * 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; + + /* 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 + * @p_cds_context: pointer to cds context + * @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; + data_stall_detect_cb data_stall_detect_callback; + void *hHal; + + if (NULL == 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"); + hHal = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal", __func__); + break; + } + qdf_status = sme_stop(hHal); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + qdf_status = mac_stop(hHal); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + ((sys_rsp_cb) pMsg->callback)(pMsg->bodyptr); + qdf_status = QDF_STATUS_SUCCESS; + break; + + case SYS_MSG_ID_DATA_STALL_MSG: + data_stall_detect_callback = pMsg->callback; + if (NULL != data_stall_detect_callback) + data_stall_detect_callback(pMsg->bodyptr); + 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); +} + +/** + * sys_process_mmh_msg() - this api to process mmh message + * @pMac: pointer to mac context + * @pMsg: pointer to message + * + * This API is used to process mmh message + * + * Return: none + */ +void sys_process_mmh_msg(tpAniSirGlobal pMac, struct scheduler_msg *pMsg) +{ + QDF_MODULE_ID targetMQ = QDF_MODULE_ID_SYS; + + /* + * The body of this pMsg is a tSirMbMsg + * Contrary to previous generation, we cannot free it here! + * It is up to the callee to free it + */ + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "NULL Message Pointer"); + QDF_ASSERT(0); + return; + } + + switch (pMsg->type) { + /* + * Following messages are routed to SYS + */ + case WNI_CFG_DNLD_REQ: + case WNI_CFG_DNLD_CNF: + /* Forward this message to the SYS module */ + targetMQ = QDF_MODULE_ID_SYS; + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Handling for the Message ID %d is removed in SYS", + pMsg->type); + QDF_ASSERT(0); + break; + + /* + * Following messages are routed to HAL + */ + case WNI_CFG_DNLD_RSP: + /* Forward this message to the HAL module */ + targetMQ = QDF_MODULE_ID_WMA; + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Handling for the Message ID %d is removed as no HAL", + pMsg->type); + + QDF_ASSERT(0); + break; + + case WNI_CFG_GET_REQ: + case eWNI_SME_SYS_READY_IND: + /* Forward this message to the PE module */ + targetMQ = QDF_MODULE_ID_PE; + break; + + case WNI_CFG_GET_RSP: + case WNI_CFG_SET_CNF: + /* Forward this message to the SME module */ + targetMQ = QDF_MODULE_ID_SME; + break; + + default: + if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) + && (pMsg->type <= eWNI_SME_MSG_TYPES_END)) { + targetMQ = 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", + pMsg->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, + targetMQ, + pMsg)) { + /* + * Caller doesn't allocate memory for the pMsg. + * It allocate memory for bodyptr free the mem and return + */ + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + } + +} + diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..34c444af8820e7677c0a9a9062efcc5b58a18be0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.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. + */ + +/* + * @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_NO_WAIT 0 +#define TX_WAIT_FOREVER 0xFFFFFFFFUL +#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 worng 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 *pMac; + +} TX_TIMER; + +#define TX_TIMER_VALID(timer) (timer.pMac != 0) + +extern uint64_t tx_time_get(void); +extern uint32_t tx_timer_activate(TX_TIMER *); +extern uint32_t tx_timer_change(TX_TIMER *, uint64_t, uint64_t); +extern uint32_t tx_timer_change_context(TX_TIMER *, uint32_t); +#ifdef TIMER_MANAGER +extern 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 +extern uint32_t tx_timer_create_intern(void *, TX_TIMER *, char *, + void (*)(void *, uint32_t), + uint32_t, uint64_t, uint64_t, + uint64_t); +#endif +extern uint32_t tx_timer_deactivate(TX_TIMER *); +extern uint32_t tx_timer_delete(TX_TIMER *); +extern bool tx_timer_running(TX_TIMER *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c new file mode 100644 index 0000000000000000000000000000000000000000..bbaf7258b41a7a04fad74d5e7e82a3cb606373e4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c @@ -0,0 +1,477 @@ +/* + * 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. + */ + +/*=========================================================================== + @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 dependecy 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_time_get() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return current system time in units of miliseconds + * + */ +uint64_t tx_time_get(void) +{ + return qdf_mc_timer_get_system_ticks(); + +} /* * tx_time_get() */ + +/**--------------------------------------------------------------------- + * 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(NULL != timer_ptr); */ + + /* If the NIC is halting just spoof a successful timer activation, so that all */ + /* the timers can be cleaned up. */ + + if (NULL == 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 (NULL == timer_ptr) { + QDF_ASSERT(0); + return; + } + + if (NULL == 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->pMac, 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 (NULL == expiration_function) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "NULL timer expiration"); + QDF_ASSERT(0); + return TX_TIMER_ERROR; + } + + if (NULL == 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->pMac = 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 ((NULL == name_ptr) || (NULL == 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->pMac = 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); + 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/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h new file mode 100644 index 0000000000000000000000000000000000000000..2de3ae86c97e372c9960003c21e94e194e2bc80f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h @@ -0,0 +1,159 @@ +/* + * 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 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) + +/* / Clocks in a millisecond */ +#define SYS_CLOCKS_PER_MS 120000 /* 120 MHz */ + +/* / System timer tick duration in clocks */ +#define SYS_TICK_DUR_CLK (SYS_TICK_DUR_MS * SYS_CLOCKS_PER_MS) + +/* / Number of timer ticks in a second */ +#define SYS_TICKS_PER_SECOND (1000/SYS_TICK_DUR_MS) + +/* / Macro to convert MS to Ticks */ +#define SYS_MS_TO_TICKS(x) ((x) / SYS_TICK_DUR_MS) + +/* / Macro to convert Seconds to Ticks */ +#define SYS_SEC_TO_TICKS(x) ((x) * SYS_TICKS_PER_SECOND) + +/* / Macro to convert Minutes to Ticks */ +#define SYS_MIN_TO_TICKS(x) (((x) * 60) * SYS_TICKS_PER_SECOND) + +/* / MNT task processing interval in seconds */ +#define SYS_MNT_INTERVAL 60 + +/* / 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) + +/* --------- End of Windows & RTAI ----------- */ + +/* / Message queue definitions */ + +/* / gHalMsgQ */ +#define SYS_HAL_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / gMMHhiPriorityMsgQ */ +#define SYS_MMH_HI_PRI_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / gMMHprotocolMsgQ */ +#define SYS_MMH_PROT_Q_SIZE 400 /* Holds up to 50 messages */ + +/* / gMMHdebugMsgQ */ +#define SYS_MMH_DEBUG_Q_SIZE 800 /* Holds up to 100 messages */ + +/* / gMAINTmsgQ */ +#define SYS_MNT_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / LIM Message Queue */ +#define SYS_LIM_Q_SIZE 400 /* Holds up to 50 messages */ + +/* / Scheduler Message Queue */ +#define SYS_SCH_Q_SIZE 800 /* Holds up to 25 messages */ + +/* / PMM Message Queue */ +#define SYS_PMM_Q_SIZE 800 /* Holds up to 100 messages */ + +/* / TX Message Queue */ +#define SYS_TX_Q_SIZE 2048 /* Holds up to 400 messages */ + +/* / RX Message Queue */ +#define SYS_RX_Q_SIZE 2048 /* Holds up to 400 messages */ + +/* / PTT Message Queue */ +#define SYS_NIM_PTT_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / Thread definitions */ +/* tHAL */ + +#define SYS_HAL_THREAD_ENTRY_FUNCTION halEntry +#define SYS_HAL_STACK_SIZE 8192 +#define SYS_HAL_THREAD_PRIORITY 2 + +/* tDPH */ + +#define SYS_DPH_THREAD_ENTRY_FUNCTION dphEntry +#define SYS_DPH_STACK_SIZE 8192 +#define SYS_DPH_THREAD_PRIORITY 15 + +/* tBBT */ + +#define SYS_BBT_THREAD_ENTRY_FUNCTION bbtEntry +#define SYS_BBT_STACK_SIZE 8192 +#define SYS_BBT_THREAD_PRIORITY 16 + +/* tSCH */ + +#define SYS_SCH_STACK_SIZE 8192 +#define SYS_SCH_THREAD_PRIORITY 17 + +/* tPMM */ + +#define SYS_PMM_STACK_SIZE 8192 +#define SYS_PMM_THREAD_PRIORITY 17 + +/* tLIM */ + +#define SYS_LIM_THREAD_ENTRY_FUNCTION limEntry +#define SYS_LIM_STACK_SIZE 8192 +#define SYS_LIM_THREAD_PRIORITY 18 + +/* tMAINT */ + +#define SYS_MNT_THREAD_ENTRY_FUNCTION mntEntry +#define SYS_MNT_STACK_SIZE 8192 +#define SYS_MNT_THREAD_PRIORITY 25 + +/* tMMH */ + +#define SYS_MMH_THREAD_ENTRY_FUNCTION mmhEntry +#define SYS_MMH_STACK_SIZE 8192 +#define SYS_MMH_THREAD_PRIORITY 10 + +/* tNIM_MNT_PKT_GEN */ + +#define SYS_NIM_PTT_THREAD_STACK_SIZE 8192 +#define SYS_NIM_PTT_THREAD_PRIORITY 28 + +#endif /* __SYSDEF_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h new file mode 100644 index 0000000000000000000000000000000000000000..36613b31776b08276290b36d521a6f1b409608a3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +/* + * + * 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" + +extern QDF_STATUS sys_init_globals(tpAniSirGlobal); +extern void sysBbtEntry(uint32_t dummy); +extern void sysSchEntry(uint32_t dummy); +extern void sysPmmEntry(uint32_t dummy); +extern void sysDphEntry(uint32_t dummy); +extern void sysLimEntry(uint32_t dummy); +extern void sysMmhEntry(uint32_t dummy); +extern void sysMntEntry(uint32_t dummy); +extern void sysHalEntry(uint32_t dummy); +extern void sysNimPttEntry(uint32_t dummy); + +#endif /* __SYS_ENTRY_FUNC_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h new file mode 100644 index 0000000000000000000000000000000000000000..9cfc50f34f1cf1ab4cbf248c945ee91f177624ef --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h @@ -0,0 +1,45 @@ +/* + * 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 */ + +void sysMACCleanup(void *); +QDF_STATUS sys_bbt_process_message_core(struct sAniSirGlobal *, + struct scheduler_msg *, + uint32_t, uint32_t); + +#endif /* __SYSSTARTUP_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c new file mode 100644 index 0000000000000000000000000000000000000000..21e992146ec2a14acefca8b6324f849024fe6bd9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c @@ -0,0 +1,174 @@ +/* + * 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. + */ + +/* + * + * 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 "cfg_api.h" /* cfg_cleanup */ +#include "lim_api.h" /* lim_cleanup */ +#include "sir_types.h" +#include "sys_entry_func.h" +#include "mac_init_api.h" + +#ifdef TRACE_RECORD +#include "mac_trace.h" +#endif + +static tAniSirGlobal global_mac_context; + +QDF_STATUS mac_start(mac_handle_t mac_handle, + struct mac_start_params *params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal 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) +{ + tpAniSirGlobal mac = MAC_CONTEXT(mac_handle); + + pe_stop(mac); + cfg_cleanup(mac); + + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn mac_open + \brief this function will be called during init. This function is suppose to allocate all the + \ memory with the global context will be allocated here. + \param tHalHandle pHalHandle + \param hdd_handle_t hdd_handle + \param tHalOpenParameters* pHalOpenParams + \return QDF_STATUS + -------------------------------------------------------------*/ + +QDF_STATUS mac_open(struct wlan_objmgr_psoc *psoc, tHalHandle *pHalHandle, + hdd_handle_t hdd_handle, struct cds_config_info *cds_cfg) +{ + tpAniSirGlobal p_mac = &global_mac_context; + QDF_STATUS status; + + QDF_BUG(pHalHandle); + if (!pHalHandle) + return QDF_STATUS_E_FAILURE; + + /* + * Set various global fields of p_mac here + * (Could be platform dependent as some variables in p_mac are platform + * dependent) + */ + p_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"); + return QDF_STATUS_E_FAILURE; + } + + p_mac->psoc = psoc; + *pHalHandle = (tHalHandle)p_mac; + + /* For Non-FTM cases this value will be reset during mac_start */ + if (cds_cfg->driver_type) + p_mac->gDriverType = QDF_DRIVER_TYPE_MFG; + + status = cfg_init(p_mac); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("failed to init legacy CFG; status:%u", status); + goto release_psoc_ref; + } + + sys_init_globals(p_mac); + + /* FW: 0 to 2047 and Host: 2048 to 4095 */ + p_mac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + p_mac->he_sgi_ltf_cfg_bit_mask = DEF_HE_AUTO_SGI_LTF; + p_mac->is_usr_cfg_amsdu_enabled = true; + + status = pe_open(p_mac, cds_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("failed to open PE; status:%u", status); + goto deinit_cfg; + } + + return QDF_STATUS_SUCCESS; + +deinit_cfg: + cfg_de_init(p_mac); + +release_psoc_ref: + wlan_objmgr_psoc_release_ref(psoc, WLAN_LEGACY_MAC_ID); + + return status; +} + +/** ------------------------------------------------------------- + \fn mac_close + \brief this function will be called in shutdown sequence from HDD. All the + \ allocated memory with global context will be freed here. + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +QDF_STATUS mac_close(tHalHandle hHal) +{ + + tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; + + if (!pMac) + return QDF_STATUS_E_FAILURE; + + pe_close(pMac); + + /* Call routine to free-up all CFG data structures */ + cfg_de_init(pMac); + + if (pMac->pdev) { + wlan_objmgr_pdev_release_ref(pMac->pdev, WLAN_LEGACY_MAC_ID); + pMac->pdev = NULL; + } + wlan_objmgr_psoc_release_ref(pMac->psoc, WLAN_LEGACY_MAC_ID); + pMac->psoc = NULL; + qdf_mem_zero(pMac, sizeof(*pMac)); + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c new file mode 100644 index 0000000000000000000000000000000000000000..dc8837a60ac60098e97e597f81102faf3635d2a1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c @@ -0,0 +1,183 @@ +/* + * 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. + */ + +/* + * 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" + +#define MAX_DEAUTH_ALLOWED 5 +/* --------------------------------------------------------------------------- */ +/** + * sys_init_globals + * + * FUNCTION: + * Initializes system level global parameters + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param tpAniSirGlobal Sirius software parameter struct pointer + * @return None + */ + +QDF_STATUS sys_init_globals(tpAniSirGlobal pMac) +{ + + qdf_mem_zero((uint8_t *) &pMac->sys, sizeof(pMac->sys)); + + pMac->sys.gSysEnableLinkMonitorMode = 0; + + return QDF_STATUS_SUCCESS; +} + +/** + * 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(tpAniSirGlobal 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, false); + + 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) && + (!lim_is_system_in_scan_state(mac_ctx)) && + (GET_LIM_PROCESS_DEFD_MESGS(mac_ctx) != true)) { + pe_debug("dropping received beacon in deffered 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: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", Assoc Req count so far: %d", + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + if (subtype == SIR_MAC_MGMT_DEAUTH) { + pe_debug("DEAUTH frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DEAUTH count so far: %d", + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + if (subtype == SIR_MAC_MGMT_DISASSOC) { + pe_debug("DISASSOC frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DISASSOC count so far: %d", + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(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/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h new file mode 100644 index 0000000000000000000000000000000000000000..2e38267cc3964ddda443931fb4b4ab3f12e5f057 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..b7f87fac048609a9a3ec9d0751ab890577d85916 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h @@ -0,0 +1,92 @@ +/* + * 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. + */ + +/* + * + * 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 +#include "sir_api.h" +#include "dot11f.h" +#include "utils_api.h" + +void convert_ssid(tpAniSirGlobal, tSirMacSSid *, tDot11fIESSID *); +void convert_supp_rates(tpAniSirGlobal, tSirMacRateSet *, tDot11fIESuppRates *); +void convert_fh_params(tpAniSirGlobal, tSirMacFHParamSet *, + tDot11fIEFHParamSet *); +void convert_ext_supp_rates(tpAniSirGlobal, tSirMacRateSet *, + tDot11fIEExtSuppRates *); +void convert_qos_caps(tpAniSirGlobal, tSirMacQosCapabilityIE *, + tDot11fIEQOSCapsAp *); +void convert_qos_caps_station(tpAniSirGlobal, tSirMacQosCapabilityStaIE *, + tDot11fIEQOSCapsStation *); +QDF_STATUS convert_wpa(tpAniSirGlobal, tSirMacWpaInfo *, tDot11fIEWPA *); +QDF_STATUS convert_wpa_opaque(tpAniSirGlobal, tSirMacWpaInfo *, + tDot11fIEWPAOpaque *); +QDF_STATUS convert_wapi_opaque(tpAniSirGlobal, tSirMacWapiInfo *, + tDot11fIEWAPIOpaque *); +QDF_STATUS convert_rsn(tpAniSirGlobal, tSirMacRsnInfo *, tDot11fIERSN *); +QDF_STATUS convert_rsn_opaque(tpAniSirGlobal, tSirMacRsnInfo *, + tDot11fIERSNOpaque *); +void convert_power_caps(tpAniSirGlobal, tSirMacPowerCapabilityIE *, + tDot11fIEPowerCaps *); +void convert_supp_channels(tpAniSirGlobal, tSirMacSupportedChannelIE *, + tDot11fIESuppChannels *); +void convert_cf_params(tpAniSirGlobal, tSirMacCfParamSet *, tDot11fIECFParams *); +void convert_tim(tpAniSirGlobal, tSirMacTim *, tDot11fIETIM *); +void convert_country(tpAniSirGlobal, tSirCountryInformation *, + tDot11fIECountry *); +void convert_wmm_params(tpAniSirGlobal, tSirMacEdcaParamSetIE *, + tDot11fIEWMMParams *); +void convert_erp_info(tpAniSirGlobal, tSirMacErpInfo *, tDot11fIEERPInfo *); +void convert_edca_param(tpAniSirGlobal, tSirMacEdcaParamSetIE *, + tDot11fIEEDCAParamSet *); +void convert_mu_edca_param(tpAniSirGlobal mac_ctx, + tSirMacEdcaParamSetIE *mu_edca, + tDot11fIEmu_edca_param_set *ie); +void convert_tspec(tpAniSirGlobal, tSirMacTspecIE *, tDot11fIETSPEC *); +QDF_STATUS convert_tclas(tpAniSirGlobal, tSirTclasInfo *, tDot11fIETCLAS *); +void convert_wmmtspec(tpAniSirGlobal, tSirMacTspecIE *, tDot11fIEWMMTSPEC *); +QDF_STATUS convert_wmmtclas(tpAniSirGlobal, tSirTclasInfo *, + tDot11fIEWMMTCLAS *); +void convert_ts_delay(tpAniSirGlobal, tSirMacTsDelayIE *, tDot11fIETSDelay *); +void convert_schedule(tpAniSirGlobal, tSirMacScheduleIE *, tDot11fIESchedule *); +void convert_wmm_schedule(tpAniSirGlobal, tSirMacScheduleIE *, + tDot11fIEWMMSchedule *); +QDF_STATUS convert_wsc_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEWscIEOpaque *); +QDF_STATUS convert_p2p_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEP2PIEOpaque *); +#ifdef WLAN_FEATURE_WFD +QDF_STATUS convert_wfd_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEWFDIEOpaque *); +#endif +void convert_qos_mapset_frame(tpAniSirGlobal, tSirQosMapSet *, + tDot11fIEQosMapSet *); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c new file mode 100644 index 0000000000000000000000000000000000000000..ea103d9e75ff692d8c86b27b36913cfdef0bcbb3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c @@ -0,0 +1,29370 @@ +/* + * 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. + */ + +/* + * \file dot11f.c + * + * \brief Structures, functions & definitions for + * working with 802.11 Frames + * + * + * This file was automatically generated by 'framesc' + * Mon Mar 25 14:48:07 2019 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))\ + eturn 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 < 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->pbcc = 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) + +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) + + +#define SigTlvmbo_ap_cap (0x0028) + + +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 (0x0029) + + +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 (0x002a) + + +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 (0x002b) + + +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 (0x002c) + + +#define SigTlvtransition_reason (0x002d) + + +#define SigTlvtransition_reject_reason (0x002e) + + +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 (0x002f) + + +#define SigTlvP2PManageability (0x0030) + + +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_beacon_reporting(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBeaconReporting *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->reportingCondition = *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_beacon_reporting. */ + +#define SigIeBeaconReporting (0x0008) + + +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 (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->reserved1 = 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->reserved2 = 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->reserved3 = tmp24__ >> 13 & 0x7; + (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->chanCenterFreqSeg1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->chanCenterFreqSeg2 = *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_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 (0x0021) + + +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 (0x0022) + + +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 tmp30__; + uint8_t tmp31__; + (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; + } + + tmp30__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APReachability = tmp30__ >> 0 & 0x3; + pDst->Security = tmp30__ >> 2 & 0x1; + pDst->KeyScope = tmp30__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp30__ >> 4 & 0x1; + pDst->QosCap = tmp30__ >> 5 & 0x1; + pDst->apsd = tmp30__ >> 6 & 0x1; + pDst->rrm = tmp30__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp31__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->DelayedBA = tmp31__ >> 0 & 0x1; + pDst->ImmBA = tmp31__ >> 1 & 0x1; + pDst->MobilityDomain = tmp31__ >> 2 & 0x1; + pDst->reserved = tmp31__ >> 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 (0x0023) + + +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 (0x0024) + + +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 (0x0025) + + +uint32_t dot11f_unpack_ie_vht_transmit_power_env(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEvht_transmit_power_env *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_bytes = (uint8_t)(ielen); + if (ielen > 5) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bytes, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_transmit_power_env. */ + +#define SigIevht_transmit_power_env (0x0026) + + +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 (0x0027) + + +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 (0x0028) + + +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 (0x0029) + + +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 (0x002a) + + +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, vht_transmit_power_env), + offsetof(tDot11fIEvht_transmit_power_env, present), 0, + "vht_transmit_power_env", 0, 4, 7, SigIevht_transmit_power_env, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHT_TRANSMIT_POWER_ENV, 0, 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 (0x002b) + + +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 (!ielen) { + pDst->num_triplets = 0U; + return 0U; + } else { + pDst->num_triplets = (uint8_t)(ielen / 3); + if (ielen > 84 * 3) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->triplets, pBuf, (ielen)); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_country. */ + +#define SigIeCountry (0x002c) + + +#define SigIeDSParams (0x002d) + + +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 tmp32__; + uint8_t tmp33__; + uint8_t tmp34__; + uint8_t tmp35__; + uint8_t tmp36__; + 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; + } + + 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; + } + + tmp32__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp32__ >> 0 & 0xf; + pDst->acbe_acm = tmp32__ >> 4 & 0x1; + pDst->acbe_aci = tmp32__ >> 5 & 0x3; + pDst->unused1 = tmp32__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp33__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp33__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp33__ >> 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; + } + + tmp34__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp34__ >> 0 & 0xf; + pDst->acbk_acm = tmp34__ >> 4 & 0x1; + pDst->acbk_aci = tmp34__ >> 5 & 0x3; + pDst->unused2 = tmp34__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp35__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp35__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp35__ >> 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; + } + + tmp36__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp36__ >> 0 & 0xf; + pDst->acvi_acm = tmp36__ >> 4 & 0x1; + pDst->acvi_aci = tmp36__ >> 5 & 0x3; + pDst->unused3 = tmp36__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp37__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp37__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp37__ >> 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; + } + + tmp38__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp38__ >> 0 & 0xf; + pDst->acvo_acm = tmp38__ >> 4 & 0x1; + pDst->acvo_aci = tmp38__ >> 5 & 0x3; + pDst->unused4 = tmp38__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp39__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp39__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp39__ >> 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 (0x002e) + + +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 tmp40__; + (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; + } + + tmp40__ = *pBuf; + pDst->non_erp_present = tmp40__ >> 0 & 0x1; + pDst->use_prot = tmp40__ >> 1 & 0x1; + pDst->barker_preamble = tmp40__ >> 2 & 0x1; + pDst->unused = tmp40__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_erp_info. */ + +#define SigIeERPInfo (0x002f) + + +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 (0x0030) + + +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 tmp41__; + (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; + } + + tmp41__ = *pBuf; + pDst->mbssid_mask = tmp41__ >> 0 & 0x7; + pDst->reserved = tmp41__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_rad_mgmt_cap. */ + +#define SigIeESERadMgmtCap (0x0031) + + +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 (0x0032) + + +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 (0x0033) + + +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 (0x0034) + + +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 (0x0035) + +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 (0x0036) + + +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 (0x0037) + + +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 (0x0038) + + +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 (0x0039) + + +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 (0x003a) + + +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 tmp42__; + (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, &tmp42__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->reserved = tmp42__ >> 0 & 0xff; + pDst->IECount = tmp42__ >> 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 (0x003b) + + +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 tmp43__; + uint8_t tmp44__; + uint16_t tmp45__; + uint32_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 < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp43__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->advCodingCap = tmp43__ >> 0 & 0x1; + pDst->supportedChannelWidthSet = tmp43__ >> 1 & 0x1; + pDst->mimoPowerSave = tmp43__ >> 2 & 0x3; + pDst->greenField = tmp43__ >> 4 & 0x1; + pDst->shortGI20MHz = tmp43__ >> 5 & 0x1; + pDst->shortGI40MHz = tmp43__ >> 6 & 0x1; + pDst->txSTBC = tmp43__ >> 7 & 0x1; + pDst->rxSTBC = tmp43__ >> 8 & 0x3; + pDst->delayedBA = tmp43__ >> 10 & 0x1; + pDst->maximalAMSDUsize = tmp43__ >> 11 & 0x1; + pDst->dsssCckMode40MHz = tmp43__ >> 12 & 0x1; + pDst->psmp = tmp43__ >> 13 & 0x1; + pDst->stbcControlFrame = tmp43__ >> 14 & 0x1; + pDst->lsigTXOPProtection = tmp43__ >> 15 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp44__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->maxRxAMPDUFactor = tmp44__ >> 0 & 0x3; + pDst->mpduDensity = tmp44__ >> 2 & 0x7; + pDst->reserved1 = tmp44__ >> 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, &tmp45__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->pco = tmp45__ >> 0 & 0x1; + pDst->transitionTime = tmp45__ >> 1 & 0x3; + pDst->reserved2 = tmp45__ >> 3 & 0x1f; + pDst->mcsFeedback = tmp45__ >> 8 & 0x3; + pDst->reserved3 = tmp45__ >> 10 & 0x3f; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp46__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->txBF = tmp46__ >> 0 & 0x1; + pDst->rxStaggeredSounding = tmp46__ >> 1 & 0x1; + pDst->txStaggeredSounding = tmp46__ >> 2 & 0x1; + pDst->rxZLF = tmp46__ >> 3 & 0x1; + pDst->txZLF = tmp46__ >> 4 & 0x1; + pDst->implicitTxBF = tmp46__ >> 5 & 0x1; + pDst->calibration = tmp46__ >> 6 & 0x3; + pDst->explicitCSITxBF = tmp46__ >> 8 & 0x1; + pDst->explicitUncompressedSteeringMatrix = tmp46__ >> 9 & 0x1; + pDst->explicitBFCSIFeedback = tmp46__ >> 10 & 0x7; + pDst->explicitUncompressedSteeringMatrixFeedback = tmp46__ >> 13 & 0x7; + pDst->explicitCompressedSteeringMatrixFeedback = tmp46__ >> 16 & 0x7; + pDst->csiNumBFAntennae = tmp46__ >> 19 & 0x3; + pDst->uncompressedSteeringMatrixBFAntennae = tmp46__ >> 21 & 0x3; + pDst->compressedSteeringMatrixBFAntennae = tmp46__ >> 23 & 0x3; + pDst->reserved4 = tmp46__ >> 25 & 0x7f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp47__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->antennaSelection = tmp47__ >> 0 & 0x1; + pDst->explicitCSIFeedbackTx = tmp47__ >> 1 & 0x1; + pDst->antennaIndicesFeedbackTx = tmp47__ >> 2 & 0x1; + pDst->explicitCSIFeedback = tmp47__ >> 3 & 0x1; + pDst->antennaIndicesFeedback = tmp47__ >> 4 & 0x1; + pDst->rxAS = tmp47__ >> 5 & 0x1; + pDst->txSoundingPPDUs = tmp47__ >> 6 & 0x1; + pDst->reserved5 = tmp47__ >> 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 (0x003c) + + +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 tmp48__; + uint16_t tmp49__; + uint16_t tmp50__; + (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; + } + + tmp48__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->secondaryChannelOffset = tmp48__ >> 0 & 0x3; + pDst->recommendedTxWidthSet = tmp48__ >> 2 & 0x1; + pDst->rifsMode = tmp48__ >> 3 & 0x1; + pDst->controlledAccessOnly = tmp48__ >> 4 & 0x1; + pDst->serviceIntervalGranularity = tmp48__ >> 5 & 0x7; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp49__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->opMode = tmp49__ >> 0 & 0x3; + pDst->nonGFDevicesPresent = tmp49__ >> 2 & 0x1; + pDst->transmitBurstLimit = tmp49__ >> 3 & 0x1; + pDst->obssNonHTStaPresent = tmp49__ >> 4 & 0x1; + pDst->reserved = tmp49__ >> 5 & 0x7ff; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp50__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->basicSTBCMCS = tmp50__ >> 0 & 0x7f; + pDst->dualCTSProtection = tmp50__ >> 7 & 0x1; + pDst->secondaryBeacon = tmp50__ >> 8 & 0x1; + pDst->lsigTXOPProtectionFullSupport = tmp50__ >> 9 & 0x1; + pDst->pcoActive = tmp50__ >> 10 & 0x1; + pDst->pcoPhase = tmp50__ >> 11 & 0x1; + pDst->reserved2 = tmp50__ >> 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 (0x003d) + + +uint32_t dot11f_unpack_ie_ibss_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEIBSSParams *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->atim, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ibss_params. */ + +#define SigIeIBSSParams (0x003e) + + +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 (0x003f) + + +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 (0x0040) + + +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, }, +}; + +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 tmp51__; + uint8_t tmp52__; + uint8_t tmp53__; + (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; + } + + tmp51__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->late = tmp51__ >> 0 & 0x1; + pDst->incapable = tmp51__ >> 1 & 0x1; + pDst->refused = tmp51__ >> 2 & 0x1; + pDst->unused = tmp51__ >> 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; + } + + tmp52__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Basic.bss = tmp52__ >> 0 & 0x1; + pDst->report.Basic.ofdm_preamble = tmp52__ >> 1 & 0x1; + pDst->report.Basic.unid_signal = tmp52__ >> 2 & 0x1; + pDst->report.Basic.rader = tmp52__ >> 3 & 0x1; + pDst->report.Basic.unmeasured = tmp52__ >> 4 & 0x1; + pDst->report.Basic.unused = tmp52__ >> 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 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; + } + + tmp53__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Beacon.condensed_PHY = tmp53__ >> 0 & 0x7f; + pDst->report.Beacon.reported_frame_type = tmp53__ >> 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; + } + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_report. */ + +#define SigIeMeasurementReport (0x0041) + + +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.BeaconReporting), + offsetof(tDot11fIEBeaconReporting, present), 0, "BeaconReporting", + 0, 4, 4, SigIeBeaconReporting, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BEACONREPORTING, 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.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 tmp54__; + (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; + } + + tmp54__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->parallel = tmp54__ >> 0 & 0x1; + pDst->enable = tmp54__ >> 1 & 0x1; + pDst->request = tmp54__ >> 2 & 0x1; + pDst->report = tmp54__ >> 3 & 0x1; + pDst->durationMandatory = tmp54__ >> 4 & 0x1; + pDst->unused = tmp54__ >> 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 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; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_request. */ + +#define SigIeMeasurementRequest (0x0042) + + +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 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, &pDst->MDID, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp55__ = *pBuf; + pDst->overDSCap = tmp55__ >> 0 & 0x1; + pDst->resourceReqCap = tmp55__ >> 1 & 0x1; + pDst->reserved = tmp55__ >> 2 & 0x3f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_mobility_domain. */ + +#define SigIeMobilityDomain (0x0043) + + +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 tmp56__; + uint8_t tmp57__; + (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; + } + + tmp56__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APReachability = tmp56__ >> 0 & 0x3; + pDst->Security = tmp56__ >> 2 & 0x1; + pDst->KeyScope = tmp56__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp56__ >> 4 & 0x1; + pDst->QosCap = tmp56__ >> 5 & 0x1; + pDst->apsd = tmp56__ >> 6 & 0x1; + pDst->rrm = tmp56__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp57__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->DelayedBA = tmp57__ >> 0 & 0x1; + pDst->ImmBA = tmp57__ >> 1 & 0x1; + pDst->MobilityDomain = tmp57__ >> 2 & 0x1; + pDst->reserved = tmp57__ >> 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 (0x0044) + + +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 (0x0045) + + +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 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; + } + + tmp58__ = *pBuf; + pDst->chanWidth = tmp58__ >> 0 & 0x3; + pDst->reserved = tmp58__ >> 2 & 0x3; + pDst->rxNSS = tmp58__ >> 4 & 0x7; + pDst->rxNSSType = tmp58__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_operating_mode. */ + +#define SigIeOperatingMode (0x0046) + + +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 (0x0047) + + +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 (0x0048) + + +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 (0x0049) + + +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 (0x004a) + + +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 (0x004b) + + +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 (0x004c) + + +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 (0x004d) + + +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 (0x004e) + + +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 (0x004f) + + +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 (0x0050) + + +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 tmp59__; + (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; + } + + tmp59__ = *pBuf; + pDst->ac_bk_traffic_aval = tmp59__ >> 0 & 0x1; + pDst->ac_be_traffic_aval = tmp59__ >> 1 & 0x1; + pDst->ac_vi_traffic_aval = tmp59__ >> 2 & 0x1; + pDst->ac_vo_traffic_aval = tmp59__ >> 3 & 0x1; + pDst->reserved = tmp59__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_pu_buffer_status. */ + +#define SigIePUBufferStatus (0x0051) + + +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 (0x0052) + + +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 (0x0053) + + +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 (0x0054) + + +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 */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->version, pBuf, 4); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_QCN_IE. */ + +#define SigIeQCN_IE (0x0055) + + +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 (0x0056) + + +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 tmp60__; + (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; + } + + tmp60__ = *pBuf; + pDst->count = tmp60__ >> 0 & 0xf; + pDst->qack = tmp60__ >> 4 & 0x1; + pDst->qreq = tmp60__ >> 5 & 0x1; + pDst->txopreq = tmp60__ >> 6 & 0x1; + pDst->reserved = tmp60__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_ap. */ + +#define SigIeQOSCapsAp (0x0057) + + +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 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; + } + + tmp61__ = *pBuf; + pDst->acvo_uapsd = tmp61__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp61__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp61__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp61__ >> 3 & 0x1; + pDst->qack = tmp61__ >> 4 & 0x1; + pDst->max_sp_length = tmp61__ >> 5 & 0x3; + pDst->more_data_ack = tmp61__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_station. */ + +#define SigIeQOSCapsStation (0x0058) + + +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 > 60) { + 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 (0x0059) + + +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 (0x005a) + + +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 (0x005b) + + +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 (0x005c) + + +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->RSN_Cap_present = 0U; + 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 (0x005d) + + +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 (0x005e) + + +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 (0x005f) + + +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 (0x0060) + + +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 (0x0061) + + +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 (0x0062) + + +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 (0x0063) + + +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 (0x0064) + + +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 (0x0065) + + +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 (0x0066) + + +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 (0x0067) + + +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 (0x0068) + + +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 (0x0069) + + +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 (0x006a) + + +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 tmp62__; + (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, &tmp62__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->preauth = tmp62__ >> 0 & 0x1; + pDst->reserved = tmp62__ >> 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 (0x006b) + + +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 (0x006c) + + +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 (0x006d) + + +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 (0x006e) + + +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 tmp63__; + (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; + } + + tmp63__ = *pBuf; + pDst->reserved = tmp63__ >> 0 & 0xf; + pDst->qack = tmp63__ >> 4 & 0x1; + pDst->queue_request = tmp63__ >> 5 & 0x1; + pDst->txop_request = tmp63__ >> 6 & 0x1; + pDst->more_ack = tmp63__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_caps. */ + +#define SigIeWMMCaps (0x006f) + + +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 tmp64__; + (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; + } + + tmp64__ = *pBuf; + pDst->param_set_count = tmp64__ >> 0 & 0xf; + pDst->reserved = tmp64__ >> 4 & 0x7; + pDst->uapsd = tmp64__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_ap. */ + +#define SigIeWMMInfoAp (0x0070) + + +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 tmp65__; + (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; + } + + tmp65__ = *pBuf; + pDst->acvo_uapsd = tmp65__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp65__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp65__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp65__ >> 3 & 0x1; + pDst->reserved1 = tmp65__ >> 4 & 0x1; + pDst->max_sp_length = tmp65__ >> 5 & 0x3; + pDst->reserved2 = tmp65__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_station. */ + +#define SigIeWMMInfoStation (0x0071) + + +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 tmp66__; + uint8_t tmp67__; + uint8_t tmp68__; + uint8_t tmp69__; + uint8_t tmp70__; + uint8_t tmp71__; + uint8_t tmp72__; + 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 (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; + } + + tmp66__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp66__ >> 0 & 0xf; + pDst->acbe_acm = tmp66__ >> 4 & 0x1; + pDst->acbe_aci = tmp66__ >> 5 & 0x3; + pDst->unused1 = tmp66__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp67__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp67__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp67__ >> 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; + } + + tmp68__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp68__ >> 0 & 0xf; + pDst->acbk_acm = tmp68__ >> 4 & 0x1; + pDst->acbk_aci = tmp68__ >> 5 & 0x3; + pDst->unused2 = tmp68__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp69__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp69__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp69__ >> 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; + } + + tmp70__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp70__ >> 0 & 0xf; + pDst->acvi_acm = tmp70__ >> 4 & 0x1; + pDst->acvi_aci = tmp70__ >> 5 & 0x3; + pDst->unused3 = tmp70__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp71__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp71__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp71__ >> 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; + } + + tmp72__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp72__ >> 0 & 0xf; + pDst->acvo_acm = tmp72__ >> 4 & 0x1; + pDst->acvo_aci = tmp72__ >> 5 & 0x3; + pDst->unused4 = tmp72__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp73__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp73__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp73__ >> 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 (0x0072) + + +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 (0x0073) + + +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 (0x0074) + + +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 (0x0075) + + +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 (0x0076) + + +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 (0x0077) + + +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 (0x0078) + + +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 (0x0079) + + +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 (0x007a) + + +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 (0x007b) + + +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 (0x007c) + + +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 (0x007d) + + +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 tmp74__; + (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; + } + + tmp74__ = *pBuf; + pDst->no_fragmentation = tmp74__ >> 0 & 0x1; + pDst->he_frag_operation = tmp74__ >> 1 & 0x3; + pDst->reserved = tmp74__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_addba_extn_element. */ + +#define SigIeaddba_extn_element (0x007e) + + +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 tmp75__; + (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; + } + + tmp75__ = *pBuf; + pDst->new_color = tmp75__ >> 0 & 0x3f; + pDst->reserved = tmp75__ >> 6 & 0x3; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bss_color_change. */ + +#define SigIebss_color_change (0x007f) + + +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 (0x0080) + + +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) + status = 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 (0x0081) + + +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) + status = 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 (0x0082) + + +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) + status = 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 (0x0083) + + +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 (0x0084) + + +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 tmp76__; + (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, &tmp76__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->public_key_identifiers_cnt = tmp76__ >> 0 & 0x7; + pDst->realm_identifiers_cnt = tmp76__ >> 3 & 0x7; + pDst->is_ip_config_supported = tmp76__ >> 6 & 0x1; + pDst->is_cache_id_present = tmp76__ >> 7 & 0x1; + pDst->is_hessid_present = tmp76__ >> 8 & 0x1; + pDst->is_fils_sk_auth_supported = tmp76__ >> 9 & 0x1; + pDst->is_fils_sk_auth_pfs_supported = tmp76__ >> 10 & 0x1; + pDst->is_pk_auth_supported = tmp76__ >> 11 & 0x1; + pDst->reserved = tmp76__ >> 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 (0x0085) + + +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 (0x0086) + + +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 (0x0087) + + +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 (0x0088) + + +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 (0x0089) + + +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 (0x008a) + + +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 (0x008b) + + +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 (0x008c) + + +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 tmp77__; + uint8_t tmp78__; + uint32_t tmp79__; + uint32_t tmp80__; + uint8_t tmp81__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp77__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->htc_he = tmp77__ >> 0 & 0x1; + pDst->twt_request = tmp77__ >> 1 & 0x1; + pDst->twt_responder = tmp77__ >> 2 & 0x1; + pDst->fragmentation = tmp77__ >> 3 & 0x3; + pDst->max_num_frag_msdu = tmp77__ >> 5 & 0x7; + pDst->min_frag_size = tmp77__ >> 8 & 0x3; + pDst->trigger_frm_mac_pad = tmp77__ >> 10 & 0x3; + pDst->multi_tid_aggr = tmp77__ >> 12 & 0x7; + pDst->he_link_adaptation = tmp77__ >> 15 & 0x3; + pDst->all_ack = tmp77__ >> 17 & 0x1; + pDst->ul_mu_rsp_sched = tmp77__ >> 18 & 0x1; + pDst->a_bsr = tmp77__ >> 19 & 0x1; + pDst->broadcast_twt = tmp77__ >> 20 & 0x1; + pDst->ba_32bit_bitmap = tmp77__ >> 21 & 0x1; + pDst->mu_cascade = tmp77__ >> 22 & 0x1; + pDst->ack_enabled_multitid = tmp77__ >> 23 & 0x1; + pDst->dl_mu_ba = tmp77__ >> 24 & 0x1; + pDst->omi_a_ctrl = tmp77__ >> 25 & 0x1; + pDst->ofdma_ra = tmp77__ >> 26 & 0x1; + pDst->max_ampdu_len = tmp77__ >> 27 & 0x3; + pDst->amsdu_frag = tmp77__ >> 29 & 0x1; + pDst->flex_twt_sched = tmp77__ >> 30 & 0x1; + pDst->rx_ctrl_frame = tmp77__ >> 31 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp78__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->bsrp_ampdu_aggr = tmp78__ >> 0 & 0x1; + pDst->qtp = tmp78__ >> 1 & 0x1; + pDst->a_bqr = tmp78__ >> 2 & 0x1; + pDst->sr_responder = tmp78__ >> 3 & 0x1; + pDst->ndp_feedback_supp = tmp78__ >> 4 & 0x1; + pDst->ops_supp = tmp78__ >> 5 & 0x1; + pDst->amsdu_in_ampdu = tmp78__ >> 6 & 0x1; + pDst->reserved1 = tmp78__ >> 7 & 0x1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp79__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->dual_band = tmp79__ >> 0 & 0x1; + pDst->chan_width_0 = tmp79__ >> 1 & 0x1; + pDst->chan_width_1 = tmp79__ >> 2 & 0x1; + pDst->chan_width_2 = tmp79__ >> 3 & 0x1; + pDst->chan_width_3 = tmp79__ >> 4 & 0x1; + pDst->chan_width_4 = tmp79__ >> 5 & 0x1; + pDst->chan_width_5 = tmp79__ >> 6 & 0x1; + pDst->chan_width_6 = tmp79__ >> 7 & 0x1; + pDst->rx_pream_puncturing = tmp79__ >> 8 & 0xf; + pDst->device_class = tmp79__ >> 12 & 0x1; + pDst->ldpc_coding = tmp79__ >> 13 & 0x1; + pDst->he_1x_ltf_800_gi_ppdu = tmp79__ >> 14 & 0x1; + pDst->midamble_rx_max_nsts = tmp79__ >> 15 & 0x3; + pDst->he_4x_ltf_3200_gi_ndp = tmp79__ >> 17 & 0x1; + pDst->tx_stbc_lt_80mhz = tmp79__ >> 18 & 0x1; + pDst->rx_stbc_lt_80mhz = tmp79__ >> 19 & 0x1; + pDst->doppler = tmp79__ >> 20 & 0x3; + pDst->ul_mu = tmp79__ >> 22 & 0x3; + pDst->dcm_enc_tx = tmp79__ >> 24 & 0x7; + pDst->dcm_enc_rx = tmp79__ >> 27 & 0x7; + pDst->ul_he_mu = tmp79__ >> 30 & 0x1; + pDst->su_beamformer = tmp79__ >> 31 & 0x1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp80__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->su_beamformee = tmp80__ >> 0 & 0x1; + pDst->mu_beamformer = tmp80__ >> 1 & 0x1; + pDst->bfee_sts_lt_80 = tmp80__ >> 2 & 0x7; + pDst->bfee_sts_gt_80 = tmp80__ >> 5 & 0x7; + pDst->num_sounding_lt_80 = tmp80__ >> 8 & 0x7; + pDst->num_sounding_gt_80 = tmp80__ >> 11 & 0x7; + pDst->su_feedback_tone16 = tmp80__ >> 14 & 0x1; + pDst->mu_feedback_tone16 = tmp80__ >> 15 & 0x1; + pDst->codebook_su = tmp80__ >> 16 & 0x1; + pDst->codebook_mu = tmp80__ >> 17 & 0x1; + pDst->beamforming_feedback = tmp80__ >> 18 & 0x7; + pDst->he_er_su_ppdu = tmp80__ >> 21 & 0x1; + pDst->dl_mu_mimo_part_bw = tmp80__ >> 22 & 0x1; + pDst->ppet_present = tmp80__ >> 23 & 0x1; + pDst->srp = tmp80__ >> 24 & 0x1; + pDst->power_boost = tmp80__ >> 25 & 0x1; + pDst->he_ltf_800_gi_4x = tmp80__ >> 26 & 0x1; + pDst->max_nc = tmp80__ >> 27 & 0x7; + pDst->tx_stbc_gt_80mhz = tmp80__ >> 30 & 0x1; + pDst->rx_stbc_gt_80mhz = tmp80__ >> 31 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp81__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->er_he_ltf_800_gi_4x = tmp81__ >> 0 & 0x1; + pDst->he_ppdu_20_in_40Mhz_2G = tmp81__ >> 1 & 0x1; + pDst->he_ppdu_20_in_160_80p80Mhz = tmp81__ >> 2 & 0x1; + pDst->he_ppdu_80_in_160_80p80Mhz = tmp81__ >> 3 & 0x1; + pDst->er_1x_he_ltf_gi = tmp81__ >> 4 & 0x1; + pDst->midamble_rx_1x_he_ltf = tmp81__ >> 5 & 0x1; + pDst->reserved2 = tmp81__ >> 6 & 0x3; + 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 (0x008d) + + +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; + uint32_t tmp82__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp82__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->bss_color = tmp82__ >> 0 & 0x3f; + pDst->default_pe = tmp82__ >> 6 & 0x7; + pDst->twt_required = tmp82__ >> 9 & 0x1; + pDst->rts_threshold = tmp82__ >> 10 & 0x3ff; + pDst->partial_bss_col = tmp82__ >> 20 & 0x1; + pDst->vht_oper_present = tmp82__ >> 21 & 0x1; + pDst->reserved1 = tmp82__ >> 22 & 0x3f; + pDst->mbssid_ap = tmp82__ >> 28 & 0x1; + pDst->tx_bssid_ind = tmp82__ >> 29 & 0x1; + pDst->bss_col_disabled = tmp82__ >> 30 & 0x1; + pDst->reserved2 = tmp82__ >> 31 & 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->mbssid_ap) { + 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; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_he_op. */ + +#define SigIehe_op (0x008e) + + +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 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; + } + + tmp83__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->dgaf_dis = tmp83__ >> 0 & 0x1; + pDst->hs_id_present = tmp83__ >> 1 & 0x3; + pDst->reserved = tmp83__ >> 3 & 0x1; + pDst->release_num = tmp83__ >> 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 (0x008f) + + +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 tmp84__; + (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; + } + + tmp84__ = *pBuf; + pDst->info_request = tmp84__ >> 0 & 0x1; + pDst->forty_mhz_intolerant = tmp84__ >> 1 & 0x1; + pDst->twenty_mhz_bsswidth_req = tmp84__ >> 2 & 0x1; + pDst->obss_scan_exemption_req = tmp84__ >> 3 & 0x1; + pDst->obss_scan_exemption_grant = tmp84__ >> 4 & 0x1; + pDst->unused = tmp84__ >> 5 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht2040_bss_coexistence. */ + +#define SigIeht2040_bss_coexistence (0x0090) + + +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 (0x0091) + + +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 tmp85__; + uint8_t tmp86__; + uint8_t tmp87__; + uint8_t tmp88__; + uint8_t tmp89__; + uint8_t tmp90__; + uint8_t tmp91__; + uint8_t tmp92__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = 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; + } + + tmp85__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp85__ >> 0 & 0xf; + pDst->acbe_acm = tmp85__ >> 4 & 0x1; + pDst->acbe_aci = tmp85__ >> 5 & 0x3; + pDst->unused1 = tmp85__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp86__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp86__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp86__ >> 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; + } + + tmp87__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp87__ >> 0 & 0xf; + pDst->acbk_acm = tmp87__ >> 4 & 0x1; + pDst->acbk_aci = tmp87__ >> 5 & 0x3; + pDst->unused2 = tmp87__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp88__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp88__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp88__ >> 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; + } + + tmp89__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp89__ >> 0 & 0xf; + pDst->acvi_acm = tmp89__ >> 4 & 0x1; + pDst->acvi_aci = tmp89__ >> 5 & 0x3; + pDst->unused3 = tmp89__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp90__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp90__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp90__ >> 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; + } + + tmp91__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp91__ >> 0 & 0xf; + pDst->acvo_acm = tmp91__ >> 4 & 0x1; + pDst->acvo_aci = tmp91__ >> 5 & 0x3; + pDst->unused4 = tmp91__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp92__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp92__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp92__ >> 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 (0x0092) + + +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 (0x0093) + + +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) + status = 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 (0x0094) + + +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 (0x0095) + + +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 (0x0096) + + +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, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 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, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 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, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 2, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, 0, }, + { 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, 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, 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, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fAssocRequest, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 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, 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, 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, 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, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fAssocRequest, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 20, 53, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 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, 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, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 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, 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, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 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, 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, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 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, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 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, 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, 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, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fAssocResponse, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 20, 53, 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, 12, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 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, 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, }, + {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, }, + {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, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 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, 5, 257, 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, 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, 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, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 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, 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, 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, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 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, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 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, 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, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 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, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 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, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 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, 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, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 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, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 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, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fBeacon, he_cap), offsetof(tDot11fIEhe_cap, present), 0, + "he_cap", 0, 20, 53, 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, 12, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 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, 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, }, + {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, }, + { offsetof(tDot11fBeacon1, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 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, 5, 257, 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, 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, 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, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 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, 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, 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, WscBeacon), offsetof(tDot11fIEWscBeacon, + present), 0, "WscBeacon", 0, 6, 84, SigIeWscBeacon, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACON, 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, 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, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 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, 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, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 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, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 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, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 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, 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, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 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, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fBeacon2, he_cap), offsetof(tDot11fIEhe_cap, present), 0, + "he_cap", 0, 20, 53, 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, 12, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 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, 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, }, + {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, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 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, 5, 257, 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, 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, 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, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 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, 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, 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, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 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, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 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, 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, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 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, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 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, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 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, 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, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 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, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, he_cap), offsetof(tDot11fIEhe_cap, present), + 0, "he_cap", 0, 20, 53, 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, 12, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 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, 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, }, + {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, 31, 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, 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, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 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, QCN_IE), offsetof(tDot11fIEQCN_IE, + present), 0, "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fProbeRequest, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 20, 53, 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_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, IBSSParams), + offsetof(tDot11fIEIBSSParams, present), 0, "IBSSParams", + 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, 0, }, + { offsetof(tDot11fProbeResponse, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, 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, 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, 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, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 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, 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, 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, WAPI), offsetof(tDot11fIEWAPI, present), + 0, "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 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, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 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, 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, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 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, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 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, 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, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 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, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 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, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fProbeResponse, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 20, 53, 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, 12, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 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, 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, }, + {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, 2, 62, 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", 4, 5, 31, 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", 2, 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, WPAOpaque), + offsetof(tDot11fIEWPAOpaque, present), 0, "WPAOpaque", + 0, 8, 255, SigIeWPAOpaque, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPAOPAQUE, 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, 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, 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, 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, ESECckmOpaque), + offsetof(tDot11fIEESECckmOpaque, present), 0, "ESECckmOpaque", + 0, 12, 26, SigIeESECckmOpaque, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESECCKMOPAQUE, 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, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 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, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 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, }, + { offsetof(tDot11fReAssocRequest, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 20, 53, 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_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, WPA), offsetof(tDot11fIEWPA, present), + 0, "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPA, 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, 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, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 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, 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, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 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, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 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, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 20, 53, 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, 12, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 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, 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, }, + {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[] = { + {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[] = { + {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, }, + {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, }, + {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, 5, 257, 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, }, + {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, 5, 257, 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, }, + {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, 5, 257, 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_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, }, + {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_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. */ + +/** + * 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; + 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 SigIeBeaconReporting: + status |= + dot11f_unpack_ie_beacon_reporting( + pCtx, pBufRemaining, len, + (tDot11fIEBeaconReporting *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBeaconReporting) * + 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 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 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 SigIeneighbor_rpt: + status |= + dot11f_unpack_ie_neighbor_rpt( + pCtx, pBufRemaining, len, + (tDot11fIEneighbor_rpt *) + (pFrm + pIe->offset + + sizeof(tDot11fIEneighbor_rpt) * + 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 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 SigIevht_transmit_power_env: + status |= + dot11f_unpack_ie_vht_transmit_power_env( + pCtx, pBufRemaining, len, + (tDot11fIEvht_transmit_power_env *) + (pFrm + pIe->offset + + sizeof(tDot11fIEvht_transmit_power_env) * + 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 SigIeIBSSParams: + status |= + dot11f_unpack_ie_ibss_params( + pCtx, pBufRemaining, len, + (tDot11fIEIBSSParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEIBSSParams) * + 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 SigIeQCN_IE: + status |= + dot11f_unpack_ie_QCN_IE( + pCtx, pBufRemaining, len, + (tDot11fIEQCN_IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQCN_IE) * + 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 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 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_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 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 SigIeosen_ie: + status |= + dot11f_unpack_ie_osen_ie( + pCtx, pBufRemaining, len, + (tDot11fIEosen_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEosen_ie) * + 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 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) { + framesntohs(pCtx, &len, pBufRemaining, pTlv->fMsb); + 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; + } + pBufRemaining += 2; + nBufRemaining -= 2; + } else { + len = *pBufRemaining; + pBufRemaining += 1; + nBufRemaining -= 1; + } + } else { + pBufRemaining += TLVs[0].sType; + nBufRemaining -= TLVs[0].sType; + framesntohs(pCtx, &len, pBufRemaining, (TLVs[0].sType == 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; + } + 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 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 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 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 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_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; + if (pIe->num_triplets) { + *pnNeeded += (pIe->num_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 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; + } + } 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 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; + } + 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 { + break; + } + *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_he_cap(tpAniSirGlobal pCtx, + tDot11fIEhe_cap *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 4; + *pnNeeded += 1; + *pnNeeded += 4; + *pnNeeded += 4; + *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 += 4; + *pnNeeded += 2; + if (pIe->vht_oper_present) { + switch (pIe->vht_oper_present) { + case 1: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + } + } else { + break; + } + if (pIe->mbssid_ap) { + switch (pIe->mbssid_ap) { + case 1: + *pnNeeded += 1; + break; + } + } else { + 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_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_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_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. */ + +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 SigIeBeaconReporting: + offset = sizeof(tDot11fIEBeaconReporting); + byteCount = 2; + pIePresent = ((tDot11fIEBeaconReporting *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeCondensedCountryStr: + offset = sizeof(tDot11fIECondensedCountryStr); + byteCount = 2; + pIePresent = ((tDot11fIECondensedCountryStr *) + (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 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 SigIeneighbor_rpt: + offset = sizeof(tDot11fIEneighbor_rpt); + status |= + dot11f_get_packed_ie_neighbor_rpt( + pCtx, (tDot11fIEneighbor_rpt *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIereq_mac_addr: + offset = sizeof(tDot11fIEreq_mac_addr); + byteCount = 6; + pIePresent = ((tDot11fIEreq_mac_addr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIetgt_mac_addr: + offset = sizeof(tDot11fIEtgt_mac_addr); + byteCount = 6; + pIePresent = ((tDot11fIEtgt_mac_addr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIevht_transmit_power_env: + offset = sizeof(tDot11fIEvht_transmit_power_env); + byteCount = ((tDot11fIEvht_transmit_power_env *) + (pFrm + pIe->offset + offset * i))-> + num_bytes; + pIePresent = ((tDot11fIEvht_transmit_power_env *) + (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 SigIeIBSSParams: + offset = sizeof(tDot11fIEIBSSParams); + byteCount = 2; + pIePresent = ((tDot11fIEIBSSParams *) + (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 SigIeQCN_IE: + offset = sizeof(tDot11fIEQCN_IE); + byteCount = 4; + pIePresent = ((tDot11fIEQCN_IE *) + (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 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 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_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 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 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 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 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 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 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 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 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 tmp93__; + tmp93__ = 0U; + tmp93__ |= (pSrc->ess << 0); + tmp93__ |= (pSrc->ibss << 1); + tmp93__ |= (pSrc->cfPollable << 2); + tmp93__ |= (pSrc->cfPollReq << 3); + tmp93__ |= (pSrc->privacy << 4); + tmp93__ |= (pSrc->shortPreamble << 5); + tmp93__ |= (pSrc->pbcc << 6); + tmp93__ |= (pSrc->channelAgility << 7); + tmp93__ |= (pSrc->spectrumMgt << 8); + tmp93__ |= (pSrc->qos << 9); + tmp93__ |= (pSrc->shortSlotTime << 10); + tmp93__ |= (pSrc->apsd << 11); + tmp93__ |= (pSrc->rrm << 12); + tmp93__ |= (pSrc->dsssOfdm << 13); + tmp93__ |= (pSrc->delayedBA << 14); + tmp93__ |= (pSrc->immediateBA << 15); + frameshtons(pCtx, pBuf, tmp93__, 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 tmp94__; + tmp94__ = 0U; + tmp94__ |= (pSrc->chanWidth << 0); + tmp94__ |= (pSrc->reserved << 2); + tmp94__ |= (pSrc->rxNSS << 4); + tmp94__ |= (pSrc->rxNSSType << 7); + *pBuf = tmp94__; + (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 tmp95__; + tmp95__ = 0U; + tmp95__ |= (pSrc->PowerSave_En << 0); + tmp95__ |= (pSrc->Mode << 1); + tmp95__ |= (pSrc->reserved << 2); + *pBuf = tmp95__; + (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 tmp96__; + tmp96__ = 0U; + tmp96__ |= (pSrc->traffic_type << 0); + tmp96__ |= (pSrc->tsid << 1); + tmp96__ |= (pSrc->direction << 5); + tmp96__ |= (pSrc->access_policy << 7); + tmp96__ |= (pSrc->aggregation << 9); + tmp96__ |= (pSrc->psb << 10); + tmp96__ |= (pSrc->user_priority << 11); + tmp96__ |= (pSrc->tsinfo_ack_pol << 14); + tmp96__ |= (pSrc->schedule << 16); + tmp96__ |= (pSrc->unused << 17); + frameshtonl(pCtx, pBuf, tmp96__, 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 tmp97__; + tmp97__ = 0U; + tmp97__ |= (pSrc->amsdu_supp << 0); + tmp97__ |= (pSrc->policy << 1); + tmp97__ |= (pSrc->tid << 2); + tmp97__ |= (pSrc->buff_size << 6); + frameshtons(pCtx, pBuf, tmp97__, 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 tmp98__; + tmp98__ = 0U; + tmp98__ |= (pSrc->frag_number << 0); + tmp98__ |= (pSrc->ssn << 4); + frameshtons(pCtx, pBuf, tmp98__, 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 tmp99__; + tmp99__ = 0U; + tmp99__ |= (pSrc->reserved << 0); + tmp99__ |= (pSrc->initiator << 11); + tmp99__ |= (pSrc->tid << 12); + frameshtons(pCtx, pBuf, tmp99__, 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 tmp100__; + tmp100__ = 0U; + tmp100__ |= (pSrc->switch_mode << 0); + tmp100__ |= (pSrc->op_class << 8); + tmp100__ |= (pSrc->new_channel << 16); + tmp100__ |= (pSrc->switch_count << 24); + frameshtonl(pCtx, pBuf, tmp100__, 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. */ + +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 tmp101__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 0; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp101__ = 0U; + tmp101__ |= (pSrc->minor << 0); + tmp101__ |= (pSrc->major << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp101__; + *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 tmp102__; + 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; + tmp102__ = 0U; + tmp102__ |= (pSrc->minor << 0); + tmp102__ |= (pSrc->major << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp102__; + *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_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 tmp103__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 101; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp103__ = 0U; + tmp103__ |= (pSrc->oce_release << 0); + tmp103__ |= (pSrc->is_sta_cfon << 3); + tmp103__ |= (pSrc->non_oce_ap_present << 4); + tmp103__ |= (pSrc->reserved << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp103__; + *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_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 tmp104__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 103; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp104__ = 0U; + tmp104__ |= (pSrc->downlink_av_cap << 0); + tmp104__ |= (pSrc->uplink_av_cap << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp104__; + *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_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_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 tmp105__; + nNeeded += (pSrc->num_key + 11); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp105__ = 0U; + tmp105__ |= (pSrc->keyId << 0); + tmp105__ |= (pSrc->reserved << 2); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp105__, 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_beacon_reporting(tpAniSirGlobal pCtx, + tDot11fIEBeaconReporting *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->reportingCondition; + *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_beacon_reporting. */ + +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_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 tmp106__; + uint8_t tmp107__; + uint8_t tmp108__; + uint8_t tmp109__; + uint8_t tmp110__; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 70; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp106__ = 0U; + tmp106__ |= (pSrc->LinkMeasurement << 0); + tmp106__ |= (pSrc->NeighborRpt << 1); + tmp106__ |= (pSrc->parallel << 2); + tmp106__ |= (pSrc->repeated << 3); + tmp106__ |= (pSrc->BeaconPassive << 4); + tmp106__ |= (pSrc->BeaconActive << 5); + tmp106__ |= (pSrc->BeaconTable << 6); + tmp106__ |= (pSrc->BeaconRepCond << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp106__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp107__ = 0U; + tmp107__ |= (pSrc->FrameMeasurement << 0); + tmp107__ |= (pSrc->ChannelLoad << 1); + tmp107__ |= (pSrc->NoiseHistogram << 2); + tmp107__ |= (pSrc->statistics << 3); + tmp107__ |= (pSrc->LCIMeasurement << 4); + tmp107__ |= (pSrc->LCIAzimuth << 5); + tmp107__ |= (pSrc->TCMCapability << 6); + tmp107__ |= (pSrc->triggeredTCM << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp107__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp108__ = 0U; + tmp108__ |= (pSrc->APChanReport << 0); + tmp108__ |= (pSrc->RRMMIBEnabled << 1); + tmp108__ |= (pSrc->operatingChanMax << 2); + tmp108__ |= (pSrc->nonOperatinChanMax << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp108__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp109__ = 0U; + tmp109__ |= (pSrc->MeasurementPilot << 0); + tmp109__ |= (pSrc->MeasurementPilotEnabled << 3); + tmp109__ |= (pSrc->NeighborTSFOffset << 4); + tmp109__ |= (pSrc->RCPIMeasurement << 5); + tmp109__ |= (pSrc->RSNIMeasurement << 6); + tmp109__ |= (pSrc->BssAvgAccessDelay << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp109__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp110__ = 0U; + tmp110__ |= (pSrc->BSSAvailAdmission << 0); + tmp110__ |= (pSrc->AntennaInformation << 1); + tmp110__ |= (pSrc->fine_time_meas_rpt << 2); + tmp110__ |= (pSrc->lci_capability << 3); + tmp110__ |= (pSrc->reserved << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp110__; + *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 tmp111__; + nNeeded += 14; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 15; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp111__ = 0U; + tmp111__ |= (pSrc->aggregation << 0); + tmp111__ |= (pSrc->tsid << 1); + tmp111__ |= (pSrc->direction << 5); + tmp111__ |= (pSrc->reserved << 7); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp111__, 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 tmp112__; + uint8_t tmp113__; + uint16_t tmp114__; + nNeeded += 55; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 13; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp112__ = 0U; + tmp112__ |= (pSrc->traffic_type << 0); + tmp112__ |= (pSrc->tsid << 1); + tmp112__ |= (pSrc->direction << 5); + tmp112__ |= (pSrc->access_policy << 7); + tmp112__ |= (pSrc->aggregation << 9); + tmp112__ |= (pSrc->psb << 10); + tmp112__ |= (pSrc->user_priority << 11); + tmp112__ |= (pSrc->tsinfo_ack_pol << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp112__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp113__ = 0U; + tmp113__ |= (pSrc->schedule << 0); + tmp113__ |= (pSrc->unused << 1); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp113__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp114__ = 0U; + tmp114__ |= (pSrc->size << 0); + tmp114__ |= (pSrc->fixed << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp114__, 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 tmp115__; + uint16_t tmp116__; + uint16_t tmp117__; + nNeeded += 12; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 191; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp115__ = 0U; + tmp115__ |= (pSrc->maxMPDULen << 0); + tmp115__ |= (pSrc->supportedChannelWidthSet << 2); + tmp115__ |= (pSrc->ldpcCodingCap << 4); + tmp115__ |= (pSrc->shortGI80MHz << 5); + tmp115__ |= (pSrc->shortGI160and80plus80MHz << 6); + tmp115__ |= (pSrc->txSTBC << 7); + tmp115__ |= (pSrc->rxSTBC << 8); + tmp115__ |= (pSrc->suBeamFormerCap << 11); + tmp115__ |= (pSrc->suBeamformeeCap << 12); + tmp115__ |= (pSrc->csnofBeamformerAntSup << 13); + tmp115__ |= (pSrc->numSoundingDim << 16); + tmp115__ |= (pSrc->muBeamformerCap << 19); + tmp115__ |= (pSrc->muBeamformeeCap << 20); + tmp115__ |= (pSrc->vhtTXOPPS << 21); + tmp115__ |= (pSrc->htcVHTCap << 22); + tmp115__ |= (pSrc->maxAMPDULenExp << 23); + tmp115__ |= (pSrc->vhtLinkAdaptCap << 26); + tmp115__ |= (pSrc->rxAntPattern << 28); + tmp115__ |= (pSrc->txAntPattern << 29); + tmp115__ |= (pSrc->reserved1 << 30); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp115__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + frameshtons(pCtx, pBuf, pSrc->rxMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp116__ = 0U; + tmp116__ |= (pSrc->rxHighSupDataRate << 0); + tmp116__ |= (pSrc->reserved2 << 13); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp116__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->txMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp117__ = 0U; + tmp117__ |= (pSrc->txSupDataRate << 0); + tmp117__ |= (pSrc->reserved3 << 13); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp117__, 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->chanCenterFreqSeg1; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->chanCenterFreqSeg2; + *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 tmp118__; + 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; + tmp118__ = 0U; + tmp118__ |= (pSrc->aggregation << 0); + tmp118__ |= (pSrc->tsid << 1); + tmp118__ |= (pSrc->direction << 5); + tmp118__ |= (pSrc->reserved << 7); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp118__, 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 tmp119__; + uint8_t tmp120__; + uint16_t tmp121__; + 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; + tmp119__ = 0U; + tmp119__ |= (pSrc->traffic_type << 0); + tmp119__ |= (pSrc->tsid << 1); + tmp119__ |= (pSrc->direction << 5); + tmp119__ |= (pSrc->access_policy << 7); + tmp119__ |= (pSrc->aggregation << 9); + tmp119__ |= (pSrc->psb << 10); + tmp119__ |= (pSrc->user_priority << 11); + tmp119__ |= (pSrc->tsinfo_ack_pol << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp119__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp120__ = 0U; + tmp120__ |= (pSrc->tsinfo_rsvd << 0); + tmp120__ |= (pSrc->burst_size_defn << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp120__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp121__ = 0U; + tmp121__ |= (pSrc->size << 0); + tmp121__ |= (pSrc->fixed << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp121__, 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 tmp122__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp122__ = 0U; + tmp122__ |= (pSrc->beacon_report_id << 0); + tmp122__ |= (pSrc->fragment_id_number << 8); + tmp122__ |= (pSrc->more_fragments << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp122__, 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_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_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 tmp123__; + uint8_t tmp124__; + 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; + tmp123__ = 0U; + tmp123__ |= (pSrc->APReachability << 0); + tmp123__ |= (pSrc->Security << 2); + tmp123__ |= (pSrc->KeyScope << 3); + tmp123__ |= (pSrc->SpecMgmtCap << 4); + tmp123__ |= (pSrc->QosCap << 5); + tmp123__ |= (pSrc->apsd << 6); + tmp123__ |= (pSrc->rrm << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp123__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp124__ = 0U; + tmp124__ |= (pSrc->DelayedBA << 0); + tmp124__ |= (pSrc->ImmBA << 1); + tmp124__ |= (pSrc->MobilityDomain << 2); + tmp124__ |= (pSrc->reserved << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp124__; + *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_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_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_vht_transmit_power_env(tpAniSirGlobal pCtx, + tDot11fIEvht_transmit_power_env *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 = 195; + ++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_vht_transmit_power_env. */ + +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; + if (pSrc->num_triplets) { + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->triplets), (pSrc->num_triplets * 3)); + *pnConsumed += (pSrc->num_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 tmp125__; + uint8_t tmp126__; + uint8_t tmp127__; + uint8_t tmp128__; + uint8_t tmp129__; + uint8_t tmp130__; + uint8_t tmp131__; + uint8_t tmp132__; + 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; + tmp125__ = 0U; + tmp125__ |= (pSrc->acbe_aifsn << 0); + tmp125__ |= (pSrc->acbe_acm << 4); + tmp125__ |= (pSrc->acbe_aci << 5); + tmp125__ |= (pSrc->unused1 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp125__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp126__ = 0U; + tmp126__ |= (pSrc->acbe_acwmin << 0); + tmp126__ |= (pSrc->acbe_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp126__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp127__ = 0U; + tmp127__ |= (pSrc->acbk_aifsn << 0); + tmp127__ |= (pSrc->acbk_acm << 4); + tmp127__ |= (pSrc->acbk_aci << 5); + tmp127__ |= (pSrc->unused2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp127__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp128__ = 0U; + tmp128__ |= (pSrc->acbk_acwmin << 0); + tmp128__ |= (pSrc->acbk_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp128__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp129__ = 0U; + tmp129__ |= (pSrc->acvi_aifsn << 0); + tmp129__ |= (pSrc->acvi_acm << 4); + tmp129__ |= (pSrc->acvi_aci << 5); + tmp129__ |= (pSrc->unused3 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp129__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp130__ = 0U; + tmp130__ |= (pSrc->acvi_acwmin << 0); + tmp130__ |= (pSrc->acvi_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp130__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp131__ = 0U; + tmp131__ |= (pSrc->acvo_aifsn << 0); + tmp131__ |= (pSrc->acvo_acm << 4); + tmp131__ |= (pSrc->acvo_aci << 5); + tmp131__ |= (pSrc->unused4 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp131__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp132__ = 0U; + tmp132__ |= (pSrc->acvo_acwmin << 0); + tmp132__ |= (pSrc->acvo_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp132__; + *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 tmp133__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 42; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp133__ = 0U; + tmp133__ |= (pSrc->non_erp_present << 0); + tmp133__ |= (pSrc->use_prot << 1); + tmp133__ |= (pSrc->barker_preamble << 2); + tmp133__ |= (pSrc->unused << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp133__; + *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 tmp134__; + 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; + tmp134__ = 0U; + tmp134__ |= (pSrc->mbssid_mask << 0); + tmp134__ |= (pSrc->reserved << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp134__; + *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 tmp135__; + 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); + tmp135__ = 0U; + tmp135__ |= (pSrc->reserved << 0); + tmp135__ |= (pSrc->IECount << 8); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp135__, 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 tmp136__; + uint8_t tmp137__; + uint16_t tmp138__; + uint32_t tmp139__; + uint8_t tmp140__; + nNeeded += (pSrc->num_rsvd + 26); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 45; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp136__ = 0U; + tmp136__ |= (pSrc->advCodingCap << 0); + tmp136__ |= (pSrc->supportedChannelWidthSet << 1); + tmp136__ |= (pSrc->mimoPowerSave << 2); + tmp136__ |= (pSrc->greenField << 4); + tmp136__ |= (pSrc->shortGI20MHz << 5); + tmp136__ |= (pSrc->shortGI40MHz << 6); + tmp136__ |= (pSrc->txSTBC << 7); + tmp136__ |= (pSrc->rxSTBC << 8); + tmp136__ |= (pSrc->delayedBA << 10); + tmp136__ |= (pSrc->maximalAMSDUsize << 11); + tmp136__ |= (pSrc->dsssCckMode40MHz << 12); + tmp136__ |= (pSrc->psmp << 13); + tmp136__ |= (pSrc->stbcControlFrame << 14); + tmp136__ |= (pSrc->lsigTXOPProtection << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp136__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp137__ = 0U; + tmp137__ |= (pSrc->maxRxAMPDUFactor << 0); + tmp137__ |= (pSrc->mpduDensity << 2); + tmp137__ |= (pSrc->reserved1 << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp137__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->supportedMCSSet, 16); + *pnConsumed += 16; + pBuf += 16; + tmp138__ = 0U; + tmp138__ |= (pSrc->pco << 0); + tmp138__ |= (pSrc->transitionTime << 1); + tmp138__ |= (pSrc->reserved2 << 3); + tmp138__ |= (pSrc->mcsFeedback << 8); + tmp138__ |= (pSrc->reserved3 << 10); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp138__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp139__ = 0U; + tmp139__ |= (pSrc->txBF << 0); + tmp139__ |= (pSrc->rxStaggeredSounding << 1); + tmp139__ |= (pSrc->txStaggeredSounding << 2); + tmp139__ |= (pSrc->rxZLF << 3); + tmp139__ |= (pSrc->txZLF << 4); + tmp139__ |= (pSrc->implicitTxBF << 5); + tmp139__ |= (pSrc->calibration << 6); + tmp139__ |= (pSrc->explicitCSITxBF << 8); + tmp139__ |= (pSrc->explicitUncompressedSteeringMatrix << 9); + tmp139__ |= (pSrc->explicitBFCSIFeedback << 10); + tmp139__ |= (pSrc->explicitUncompressedSteeringMatrixFeedback << 13); + tmp139__ |= (pSrc->explicitCompressedSteeringMatrixFeedback << 16); + tmp139__ |= (pSrc->csiNumBFAntennae << 19); + tmp139__ |= (pSrc->uncompressedSteeringMatrixBFAntennae << 21); + tmp139__ |= (pSrc->compressedSteeringMatrixBFAntennae << 23); + tmp139__ |= (pSrc->reserved4 << 25); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp139__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp140__ = 0U; + tmp140__ |= (pSrc->antennaSelection << 0); + tmp140__ |= (pSrc->explicitCSIFeedbackTx << 1); + tmp140__ |= (pSrc->antennaIndicesFeedbackTx << 2); + tmp140__ |= (pSrc->explicitCSIFeedback << 3); + tmp140__ |= (pSrc->antennaIndicesFeedback << 4); + tmp140__ |= (pSrc->rxAS << 5); + tmp140__ |= (pSrc->txSoundingPPDUs << 6); + tmp140__ |= (pSrc->reserved5 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp140__; + *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 tmp141__; + uint16_t tmp142__; + uint16_t tmp143__; + 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; + tmp141__ = 0U; + tmp141__ |= (pSrc->secondaryChannelOffset << 0); + tmp141__ |= (pSrc->recommendedTxWidthSet << 2); + tmp141__ |= (pSrc->rifsMode << 3); + tmp141__ |= (pSrc->controlledAccessOnly << 4); + tmp141__ |= (pSrc->serviceIntervalGranularity << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp141__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp142__ = 0U; + tmp142__ |= (pSrc->opMode << 0); + tmp142__ |= (pSrc->nonGFDevicesPresent << 2); + tmp142__ |= (pSrc->transmitBurstLimit << 3); + tmp142__ |= (pSrc->obssNonHTStaPresent << 4); + tmp142__ |= (pSrc->reserved << 5); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp142__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp143__ = 0U; + tmp143__ |= (pSrc->basicSTBCMCS << 0); + tmp143__ |= (pSrc->dualCTSProtection << 7); + tmp143__ |= (pSrc->secondaryBeacon << 8); + tmp143__ |= (pSrc->lsigTXOPProtectionFullSupport << 9); + tmp143__ |= (pSrc->pcoActive << 10); + tmp143__ |= (pSrc->pcoPhase << 11); + tmp143__ |= (pSrc->reserved2 << 12); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp143__, 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_ibss_params(tpAniSirGlobal pCtx, + tDot11fIEIBSSParams *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 = 6; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->atim, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ibss_params. */ + +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 tmp144__; + uint8_t tmp145__; + uint8_t tmp146__; + 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; + tmp144__ = 0U; + tmp144__ |= (pSrc->late << 0); + tmp144__ |= (pSrc->incapable << 1); + tmp144__ |= (pSrc->refused << 2); + tmp144__ |= (pSrc->unused << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp144__; + *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; + tmp145__ = 0U; + tmp145__ |= (pSrc->report.Basic.bss << 0); + tmp145__ |= (pSrc->report.Basic.ofdm_preamble << 1); + tmp145__ |= (pSrc->report.Basic.unid_signal << 2); + tmp145__ |= (pSrc->report.Basic.rader << 3); + tmp145__ |= (pSrc->report.Basic.unmeasured << 4); + tmp145__ |= (pSrc->report.Basic.unused << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp145__; + *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 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; + tmp146__ = 0U; + tmp146__ |= (pSrc->report.Beacon.condensed_PHY << 0); + tmp146__ |= (pSrc->report.Beacon.reported_frame_type << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp146__; + *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; + } + } 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 tmp147__; + 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; + tmp147__ = 0U; + tmp147__ |= (pSrc->parallel << 0); + tmp147__ |= (pSrc->enable << 1); + tmp147__ |= (pSrc->request << 2); + tmp147__ |= (pSrc->report << 3); + tmp147__ |= (pSrc->durationMandatory << 4); + tmp147__ |= (pSrc->unused << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp147__; + *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 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; + } + 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 tmp148__; + 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; + tmp148__ = 0U; + tmp148__ |= (pSrc->overDSCap << 0); + tmp148__ |= (pSrc->resourceReqCap << 1); + tmp148__ |= (pSrc->reserved << 2); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp148__; + *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 tmp149__; + uint8_t tmp150__; + 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; + tmp149__ = 0U; + tmp149__ |= (pSrc->APReachability << 0); + tmp149__ |= (pSrc->Security << 2); + tmp149__ |= (pSrc->KeyScope << 3); + tmp149__ |= (pSrc->SpecMgmtCap << 4); + tmp149__ |= (pSrc->QosCap << 5); + tmp149__ |= (pSrc->apsd << 6); + tmp149__ |= (pSrc->rrm << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp149__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp150__ = 0U; + tmp150__ |= (pSrc->DelayedBA << 0); + tmp150__ |= (pSrc->ImmBA << 1); + tmp150__ |= (pSrc->MobilityDomain << 2); + tmp150__ |= (pSrc->reserved << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp150__; + *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 tmp151__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 199; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp151__ = 0U; + tmp151__ |= (pSrc->chanWidth << 0); + tmp151__ |= (pSrc->reserved << 2); + tmp151__ |= (pSrc->rxNSS << 4); + tmp151__ |= (pSrc->rxNSSType << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp151__; + *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 tmp152__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 106; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp152__ = 0U; + tmp152__ |= (pSrc->ac_bk_traffic_aval << 0); + tmp152__ |= (pSrc->ac_be_traffic_aval << 1); + tmp152__ |= (pSrc->ac_vi_traffic_aval << 2); + tmp152__ |= (pSrc->ac_vo_traffic_aval << 3); + tmp152__ |= (pSrc->reserved << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp152__; + *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_QCN_IE(tpAniSirGlobal pCtx, + tDot11fIEQCN_IE *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 = 0x8c; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xfd; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->version, 4); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_QCN_IE. */ + +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 tmp153__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp153__ = 0U; + tmp153__ |= (pSrc->count << 0); + tmp153__ |= (pSrc->qack << 4); + tmp153__ |= (pSrc->qreq << 5); + tmp153__ |= (pSrc->txopreq << 6); + tmp153__ |= (pSrc->reserved << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp153__; + *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 tmp154__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp154__ = 0U; + tmp154__ |= (pSrc->acvo_uapsd << 0); + tmp154__ |= (pSrc->acvi_uapsd << 1); + tmp154__ |= (pSrc->acbk_uapsd << 2); + tmp154__ |= (pSrc->acbe_uapsd << 3); + tmp154__ |= (pSrc->qack << 4); + tmp154__ |= (pSrc->max_sp_length << 5); + tmp154__ |= (pSrc->more_data_ack << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp154__; + *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 { + break; + } + 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 tmp155__; + 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; + tmp155__ = 0U; + tmp155__ |= (pSrc->preauth << 0); + tmp155__ |= (pSrc->reserved << 1); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp155__, 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 tmp156__; + 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; + tmp156__ = 0U; + tmp156__ |= (pSrc->reserved << 0); + tmp156__ |= (pSrc->qack << 4); + tmp156__ |= (pSrc->queue_request << 5); + tmp156__ |= (pSrc->txop_request << 6); + tmp156__ |= (pSrc->more_ack << 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_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 tmp157__; + 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; + tmp157__ = 0U; + tmp157__ |= (pSrc->param_set_count << 0); + tmp157__ |= (pSrc->reserved << 4); + tmp157__ |= (pSrc->uapsd << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp157__; + *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 tmp158__; + 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; + tmp158__ = 0U; + tmp158__ |= (pSrc->acvo_uapsd << 0); + tmp158__ |= (pSrc->acvi_uapsd << 1); + tmp158__ |= (pSrc->acbk_uapsd << 2); + tmp158__ |= (pSrc->acbe_uapsd << 3); + tmp158__ |= (pSrc->reserved1 << 4); + tmp158__ |= (pSrc->max_sp_length << 5); + tmp158__ |= (pSrc->reserved2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp158__; + *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 tmp159__; + uint8_t tmp160__; + uint8_t tmp161__; + uint8_t tmp162__; + uint8_t tmp163__; + uint8_t tmp164__; + uint8_t tmp165__; + uint8_t tmp166__; + 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; + tmp159__ = 0U; + tmp159__ |= (pSrc->acbe_aifsn << 0); + tmp159__ |= (pSrc->acbe_acm << 4); + tmp159__ |= (pSrc->acbe_aci << 5); + tmp159__ |= (pSrc->unused1 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp159__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp160__ = 0U; + tmp160__ |= (pSrc->acbe_acwmin << 0); + tmp160__ |= (pSrc->acbe_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp160__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp161__ = 0U; + tmp161__ |= (pSrc->acbk_aifsn << 0); + tmp161__ |= (pSrc->acbk_acm << 4); + tmp161__ |= (pSrc->acbk_aci << 5); + tmp161__ |= (pSrc->unused2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp161__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp162__ = 0U; + tmp162__ |= (pSrc->acbk_acwmin << 0); + tmp162__ |= (pSrc->acbk_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp162__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp163__ = 0U; + tmp163__ |= (pSrc->acvi_aifsn << 0); + tmp163__ |= (pSrc->acvi_acm << 4); + tmp163__ |= (pSrc->acvi_aci << 5); + tmp163__ |= (pSrc->unused3 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp163__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp164__ = 0U; + tmp164__ |= (pSrc->acvi_acwmin << 0); + tmp164__ |= (pSrc->acvi_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp164__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp165__ = 0U; + tmp165__ |= (pSrc->acvo_aifsn << 0); + tmp165__ |= (pSrc->acvo_acm << 4); + tmp165__ |= (pSrc->acvo_aci << 5); + tmp165__ |= (pSrc->unused4 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp165__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp166__ = 0U; + tmp166__ |= (pSrc->acvo_acwmin << 0); + tmp166__ |= (pSrc->acvo_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp166__; + *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 tmp167__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 159; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp167__ = 0U; + tmp167__ |= (pSrc->no_fragmentation << 0); + tmp167__ |= (pSrc->he_frag_operation << 1); + tmp167__ |= (pSrc->reserved << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp167__; + *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 tmp168__; + 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; + tmp168__ = 0U; + tmp168__ |= (pSrc->new_color << 0); + tmp168__ |= (pSrc->reserved << 6); + 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_bss_color_change. */ + +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_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 tmp169__; + nNeeded += (pSrc->num_variable_data + 2); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 240; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp169__ = 0U; + tmp169__ |= (pSrc->public_key_identifiers_cnt << 0); + tmp169__ |= (pSrc->realm_identifiers_cnt << 3); + tmp169__ |= (pSrc->is_ip_config_supported << 6); + tmp169__ |= (pSrc->is_cache_id_present << 7); + tmp169__ |= (pSrc->is_hessid_present << 8); + tmp169__ |= (pSrc->is_fils_sk_auth_supported << 9); + tmp169__ |= (pSrc->is_fils_sk_auth_pfs_supported << 10); + tmp169__ |= (pSrc->is_pk_auth_supported << 11); + tmp169__ |= (pSrc->reserved << 12); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp169__, 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_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 tmp170__; + uint8_t tmp171__; + uint32_t tmp172__; + uint32_t tmp173__; + uint8_t tmp174__; + 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); + tmp170__ = 0U; + tmp170__ |= (pSrc->htc_he << 0); + tmp170__ |= (pSrc->twt_request << 1); + tmp170__ |= (pSrc->twt_responder << 2); + tmp170__ |= (pSrc->fragmentation << 3); + tmp170__ |= (pSrc->max_num_frag_msdu << 5); + tmp170__ |= (pSrc->min_frag_size << 8); + tmp170__ |= (pSrc->trigger_frm_mac_pad << 10); + tmp170__ |= (pSrc->multi_tid_aggr << 12); + tmp170__ |= (pSrc->he_link_adaptation << 15); + tmp170__ |= (pSrc->all_ack << 17); + tmp170__ |= (pSrc->ul_mu_rsp_sched << 18); + tmp170__ |= (pSrc->a_bsr << 19); + tmp170__ |= (pSrc->broadcast_twt << 20); + tmp170__ |= (pSrc->ba_32bit_bitmap << 21); + tmp170__ |= (pSrc->mu_cascade << 22); + tmp170__ |= (pSrc->ack_enabled_multitid << 23); + tmp170__ |= (pSrc->dl_mu_ba << 24); + tmp170__ |= (pSrc->omi_a_ctrl << 25); + tmp170__ |= (pSrc->ofdma_ra << 26); + tmp170__ |= (pSrc->max_ampdu_len << 27); + tmp170__ |= (pSrc->amsdu_frag << 29); + tmp170__ |= (pSrc->flex_twt_sched << 30); + tmp170__ |= (pSrc->rx_ctrl_frame << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp170__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp171__ = 0U; + tmp171__ |= (pSrc->bsrp_ampdu_aggr << 0); + tmp171__ |= (pSrc->qtp << 1); + tmp171__ |= (pSrc->a_bqr << 2); + tmp171__ |= (pSrc->sr_responder << 3); + tmp171__ |= (pSrc->ndp_feedback_supp << 4); + tmp171__ |= (pSrc->ops_supp << 5); + tmp171__ |= (pSrc->amsdu_in_ampdu << 6); + tmp171__ |= (pSrc->reserved1 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp171__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp172__ = 0U; + tmp172__ |= (pSrc->dual_band << 0); + tmp172__ |= (pSrc->chan_width_0 << 1); + tmp172__ |= (pSrc->chan_width_1 << 2); + tmp172__ |= (pSrc->chan_width_2 << 3); + tmp172__ |= (pSrc->chan_width_3 << 4); + tmp172__ |= (pSrc->chan_width_4 << 5); + tmp172__ |= (pSrc->chan_width_5 << 6); + tmp172__ |= (pSrc->chan_width_6 << 7); + tmp172__ |= (pSrc->rx_pream_puncturing << 8); + tmp172__ |= (pSrc->device_class << 12); + tmp172__ |= (pSrc->ldpc_coding << 13); + tmp172__ |= (pSrc->he_1x_ltf_800_gi_ppdu << 14); + tmp172__ |= (pSrc->midamble_rx_max_nsts << 15); + tmp172__ |= (pSrc->he_4x_ltf_3200_gi_ndp << 17); + tmp172__ |= (pSrc->tx_stbc_lt_80mhz << 18); + tmp172__ |= (pSrc->rx_stbc_lt_80mhz << 19); + tmp172__ |= (pSrc->doppler << 20); + tmp172__ |= (pSrc->ul_mu << 22); + tmp172__ |= (pSrc->dcm_enc_tx << 24); + tmp172__ |= (pSrc->dcm_enc_rx << 27); + tmp172__ |= (pSrc->ul_he_mu << 30); + tmp172__ |= (pSrc->su_beamformer << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp172__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp173__ = 0U; + tmp173__ |= (pSrc->su_beamformee << 0); + tmp173__ |= (pSrc->mu_beamformer << 1); + tmp173__ |= (pSrc->bfee_sts_lt_80 << 2); + tmp173__ |= (pSrc->bfee_sts_gt_80 << 5); + tmp173__ |= (pSrc->num_sounding_lt_80 << 8); + tmp173__ |= (pSrc->num_sounding_gt_80 << 11); + tmp173__ |= (pSrc->su_feedback_tone16 << 14); + tmp173__ |= (pSrc->mu_feedback_tone16 << 15); + tmp173__ |= (pSrc->codebook_su << 16); + tmp173__ |= (pSrc->codebook_mu << 17); + tmp173__ |= (pSrc->beamforming_feedback << 18); + tmp173__ |= (pSrc->he_er_su_ppdu << 21); + tmp173__ |= (pSrc->dl_mu_mimo_part_bw << 22); + tmp173__ |= (pSrc->ppet_present << 23); + tmp173__ |= (pSrc->srp << 24); + tmp173__ |= (pSrc->power_boost << 25); + tmp173__ |= (pSrc->he_ltf_800_gi_4x << 26); + tmp173__ |= (pSrc->max_nc << 27); + tmp173__ |= (pSrc->tx_stbc_gt_80mhz << 30); + tmp173__ |= (pSrc->rx_stbc_gt_80mhz << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp173__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp174__ = 0U; + tmp174__ |= (pSrc->er_he_ltf_800_gi_4x << 0); + tmp174__ |= (pSrc->he_ppdu_20_in_40Mhz_2G << 1); + tmp174__ |= (pSrc->he_ppdu_20_in_160_80p80Mhz << 2); + tmp174__ |= (pSrc->he_ppdu_80_in_160_80p80Mhz << 3); + tmp174__ |= (pSrc->er_1x_he_ltf_gi << 4); + tmp174__ |= (pSrc->midamble_rx_1x_he_ltf << 5); + tmp174__ |= (pSrc->reserved2 << 6); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp174__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 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; + uint32_t tmp175__; + 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); + tmp175__ = 0U; + tmp175__ |= (pSrc->bss_color << 0); + tmp175__ |= (pSrc->default_pe << 6); + tmp175__ |= (pSrc->twt_required << 9); + tmp175__ |= (pSrc->rts_threshold << 10); + tmp175__ |= (pSrc->partial_bss_col << 20); + tmp175__ |= (pSrc->vht_oper_present << 21); + tmp175__ |= (pSrc->reserved1 << 22); + tmp175__ |= (pSrc->mbssid_ap << 28); + tmp175__ |= (pSrc->tx_bssid_ind << 29); + tmp175__ |= (pSrc->bss_col_disabled << 30); + tmp175__ |= (pSrc->reserved2 << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp175__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + 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; + } + } else { + break; + } + if (pSrc->mbssid_ap) { + switch (pSrc->mbssid_ap) { + case 1: + *pBuf = pSrc->maxbssid_ind.info.data; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + } else { + 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 tmp176__; + 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); + tmp176__ = 0U; + tmp176__ |= (pSrc->dgaf_dis << 0); + tmp176__ |= (pSrc->hs_id_present << 1); + tmp176__ |= (pSrc->reserved << 3); + tmp176__ |= (pSrc->release_num << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp176__; + *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 tmp177__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 72; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp177__ = 0U; + tmp177__ |= (pSrc->info_request << 0); + tmp177__ |= (pSrc->forty_mhz_intolerant << 1); + tmp177__ |= (pSrc->twenty_mhz_bsswidth_req << 2); + tmp177__ |= (pSrc->obss_scan_exemption_req << 3); + tmp177__ |= (pSrc->obss_scan_exemption_grant << 4); + tmp177__ |= (pSrc->unused << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp177__; + *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_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 tmp178__; + uint8_t tmp179__; + uint8_t tmp180__; + uint8_t tmp181__; + uint8_t tmp182__; + uint8_t tmp183__; + uint8_t tmp184__; + uint8_t tmp185__; + 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; + tmp178__ = 0U; + tmp178__ |= (pSrc->acbe_aifsn << 0); + tmp178__ |= (pSrc->acbe_acm << 4); + tmp178__ |= (pSrc->acbe_aci << 5); + tmp178__ |= (pSrc->unused1 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp178__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp179__ = 0U; + tmp179__ |= (pSrc->acbe_acwmin << 0); + tmp179__ |= (pSrc->acbe_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp179__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->acbe_muedca_timer; + *pnConsumed += 1; + pBuf += 1; + tmp180__ = 0U; + tmp180__ |= (pSrc->acbk_aifsn << 0); + tmp180__ |= (pSrc->acbk_acm << 4); + tmp180__ |= (pSrc->acbk_aci << 5); + tmp180__ |= (pSrc->unused2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp180__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp181__ = 0U; + tmp181__ |= (pSrc->acbk_acwmin << 0); + tmp181__ |= (pSrc->acbk_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp181__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->acbk_muedca_timer; + *pnConsumed += 1; + pBuf += 1; + tmp182__ = 0U; + tmp182__ |= (pSrc->acvi_aifsn << 0); + tmp182__ |= (pSrc->acvi_acm << 4); + tmp182__ |= (pSrc->acvi_aci << 5); + tmp182__ |= (pSrc->unused3 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp182__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp183__ = 0U; + tmp183__ |= (pSrc->acvi_acwmin << 0); + tmp183__ |= (pSrc->acvi_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp183__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->acvi_muedca_timer; + *pnConsumed += 1; + pBuf += 1; + tmp184__ = 0U; + tmp184__ |= (pSrc->acvo_aifsn << 0); + tmp184__ |= (pSrc->acvo_acm << 4); + tmp184__ |= (pSrc->acvo_aci << 5); + tmp184__ |= (pSrc->unused4 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp184__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp185__ = 0U; + tmp185__ |= (pSrc->acvo_acwmin << 0); + tmp185__ |= (pSrc->acvo_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp185__; + *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_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_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_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_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_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. */ + +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; + 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 SigIeBeaconReporting: + status |= + dot11f_pack_ie_beacon_reporting( + pCtx, (tDot11fIEBeaconReporting *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBeaconReporting) * 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 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 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 SigIeneighbor_rpt: + status |= + dot11f_pack_ie_neighbor_rpt( + pCtx, (tDot11fIEneighbor_rpt *) + (pSrc + pIe->offset + + sizeof(tDot11fIEneighbor_rpt) * 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 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 SigIevht_transmit_power_env: + status |= + dot11f_pack_ie_vht_transmit_power_env( + pCtx, (tDot11fIEvht_transmit_power_env *) + (pSrc + pIe->offset + + sizeof(tDot11fIEvht_transmit_power_env) * 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 SigIeIBSSParams: + status |= + dot11f_pack_ie_ibss_params( + pCtx, (tDot11fIEIBSSParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEIBSSParams) * 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 SigIeQCN_IE: + status |= + dot11f_pack_ie_QCN_IE( + pCtx, (tDot11fIEQCN_IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQCN_IE) * 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 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 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_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 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 SigIeosen_ie: + status |= + dot11f_pack_ie_osen_ie( + pCtx, (tDot11fIEosen_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEosen_ie) * 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 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 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 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 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 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/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..2a5e4e73794d62cd88b0b558eb9bb7e08a5395c6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c @@ -0,0 +1,821 @@ +/* + * 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. + */ + +/**========================================================================= + + \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_neighbor_roam.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" + +/** + * mac_trace_get_neighbour_roam_state() - Get the neighbor roam state + * @neighbourroamstate: 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_neighbour_roam_state(uint16_t neighbourroamstate) +{ + switch (neighbourroamstate) { + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE); + CASE_RETURN_STRING(eNEIGHBOR_STATE_MAX); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * 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_JOIN_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_REASSOC_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + CASE_RETURN_STRING + (eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_AUTH_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_CONFIG); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DEAUTH_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_FORCED); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC); + CASE_RETURN_STRING + (eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC); + + 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_SCAN_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_LINK_EST_WT_SCAN_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); + CASE_RETURN_STRING(eLIM_SME_CHANNEL_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_CHANNEL_SCAN_STATE); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_mlm_state() - Get the lim mlm state + * @mlmstate: 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_PROBE_RESP_STATE); + CASE_RETURN_STRING(eLIM_MLM_PASSIVE_SCAN_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_LEARN_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_REQ); + 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_WM_STATUS_CHANGE_NTF); + CASE_RETURN_STRING(eWNI_SME_IBSS_NEW_PEER_IND); + CASE_RETURN_STRING(eWNI_SME_IBSS_PEER_DEPARTED_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_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_GET_STATISTICS_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_STATISTICS_RSP); + CASE_RETURN_STRING(eWNI_SME_GET_RSSI_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_ASSOC_STAS_REQ); + 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_ADD_STA_SELF_RSP); + CASE_RETURN_STRING(eWNI_SME_DEL_STA_SELF_RSP); + CASE_RETURN_STRING(eWNI_SME_FT_PRE_AUTH_REQ); + CASE_RETURN_STRING(eWNI_SME_FT_PRE_AUTH_RSP); + CASE_RETURN_STRING(eWNI_SME_FT_UPDATE_KEY); + 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_ROAM_SCAN_OFFLOAD_RSP); + CASE_RETURN_STRING(eWNI_SME_IBSS_PEER_INFO_RSP); + 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_CSA_OFFLOAD_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 WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(eWNI_SME_HO_FAIL_IND); +#endif +#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); + CASE_RETURN_STRING + (eWNI_SME_TDLS_CONNECTION_TRACKER_NOTIFICATION); +#endif + CASE_RETURN_STRING(eWNI_SME_RESET_AP_CAPS_CHANGED); +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING(eWNI_SME_UNPROT_MGMT_FRM_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_CANDIDATE_FOUND_IND); + CASE_RETURN_STRING(eWNI_SME_HANDOFF_REQ); + 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_READY_TO_SUSPEND_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_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_ROAM_SCAN_OFFLOAD_REQ); + CASE_RETURN_STRING(eWNI_SME_LOST_LINK_INFO_IND); + CASE_RETURN_STRING(eWNI_SME_GET_PEER_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_MSG_TYPES_END); + CASE_RETURN_STRING(eWNI_SME_HIDDEN_SSID_RESTART_RSP); + 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_ADD_STA_SELF_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_ADD_BSS_RSP); + 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_REQ); + CASE_RETURN_STRING(WMA_SET_BSSKEY_RSP); + CASE_RETURN_STRING(WMA_SET_STAKEY_REQ); + 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_UPDATE_CF_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_EXIT_PS_REQ); + CASE_RETURN_STRING(WMA_ENTER_PS_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_REGISTER_PE_CALLBACK); + + CASE_RETURN_STRING(WMA_IBSS_STA_ADD); + CASE_RETURN_STRING(WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND); + CASE_RETURN_STRING(WMA_SET_LINK_STATE); + CASE_RETURN_STRING(WMA_SET_LINK_STATE_RSP); + CASE_RETURN_STRING(WMA_SET_STA_BCASTKEY_REQ); + 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_TRANSMISSION_CONTROL_IND); + CASE_RETURN_STRING(WMA_ENABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_DISABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_GET_STATISTICS_REQ); + CASE_RETURN_STRING(WMA_GET_STATISTICS_RSP); + 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_ADD_STA_SELF_REQ); + CASE_RETURN_STRING(WMA_DEL_STA_SELF_REQ); + 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_SCAN_OFFLOAD_REQ); +#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_CONFIG_PARAM_UPDATE_REQ); + 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_IBSS_CESIUM_ENABLE_IND); + CASE_RETURN_STRING(WMA_GET_IBSS_PEER_INFO_REQ); + CASE_RETURN_STRING(WMA_TX_FAIL_MONITOR_IND); + CASE_RETURN_STRING(WMA_RMC_ENABLE_IND); + CASE_RETURN_STRING(WMA_RMC_DISABLE_IND); + CASE_RETURN_STRING(WMA_RMC_ACTION_PERIOD_IND); + CASE_RETURN_STRING(WMA_INIT_THERMAL_INFO_CMD); + CASE_RETURN_STRING(WMA_SET_THERMAL_LEVEL); + CASE_RETURN_STRING(WMA_SET_SAP_INTRABSS_DIS); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(WMA_ROAM_OFFLOAD_SYNCH_FAIL); +#endif + 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_LRO_CONFIG_CMD); + 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(WDA_APF_SET_INSTRUCTIONS_REQ); + CASE_RETURN_STRING(WMA_SET_PDEV_IE_REQ); + CASE_RETURN_STRING(WMA_UPDATE_WEP_DEFAULT_KEY); + CASE_RETURN_STRING(WMA_SEND_FREQ_RANGE_CONTROL_IND); + CASE_RETURN_STRING(WMA_POWER_DEBUG_STATS_REQ); + CASE_RETURN_STRING(WNI_CFG_DNLD_REQ); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(SIR_HAL_ROAM_INVOKE); +#endif + 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_PDEV_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); +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING(WMA_EXCLUDE_UNENCRYPTED_IND); +#endif + 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); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(WMA_ROAM_OFFLOAD_SYNCH_IND); +#endif + CASE_RETURN_STRING(WMA_HIDDEN_SSID_VDEV_RESTART); + CASE_RETURN_STRING(WMA_UPDATE_RX_NSS); +#ifdef WLAN_FEATURE_NAN + CASE_RETURN_STRING(WMA_NAN_REQUEST); +#endif + CASE_RETURN_STRING(WMA_RX_SCAN_EVENT); + CASE_RETURN_STRING(WMA_RX_CHN_STATUS_EVENT); + CASE_RETURN_STRING(WMA_IBSS_PEER_INACTIVITY_IND); + 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); + CASE_RETURN_STRING(WMA_TDLS_SET_OFFCHAN_MODE); + CASE_RETURN_STRING + (WMA_TDLS_CONNECTION_TRACKER_NOTIFICATION_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 + CASE_RETURN_STRING(WMA_PROCESS_FW_EVENT); +#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_SET_PER_ROAM_CONFIG_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); + 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_LIM_RETRY_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_BB_XPORT_MGMT_MSG); + CASE_RETURN_STRING(SIR_LIM_INV_KEY_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_KEY_ID_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_REPLAY_THRES_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_TD_DUMMY_CALLBACK_MSG); + CASE_RETURN_STRING(SIR_LIM_SCH_CLEAN_MSG); + CASE_RETURN_STRING(SIR_LIM_RADAR_DETECT_IND); + CASE_RETURN_STRING(SIR_LIM_DEL_TS_IND); + 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_PROBE_HB_FAILURE_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_CHANNEL_SWITCH_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_QUIET_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_QUIET_BSS_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_WPS_OVERLAP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_FT_PREAUTH_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_BEACON_GEN_IND); + CASE_RETURN_STRING(SIR_LIM_DISASSOC_ACK_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_DEAUTH_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_MSG_TYPES_END); + CASE_RETURN_STRING(LIM_MLM_SCAN_REQ); + CASE_RETURN_STRING(LIM_MLM_SCAN_CNF); + CASE_RETURN_STRING(LIM_MLM_START_REQ); + 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_REQ); + 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_REQ); + 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_cfg_msg_string() - Get the msg + * @cfg_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_cfg_msg_string(uint16_t cfg_msg) +{ + switch (cfg_msg) { + CASE_RETURN_STRING(WNI_CFG_PARAM_UPDATE_IND); + CASE_RETURN_STRING(WNI_CFG_DNLD_REQ); + CASE_RETURN_STRING(WNI_CFG_DNLD_CNF); + CASE_RETURN_STRING(WNI_CFG_GET_RSP); + CASE_RETURN_STRING(WNI_CFG_SET_CNF); + CASE_RETURN_STRING(WNI_CFG_GET_ATTRIB_RSP); + CASE_RETURN_STRING(WNI_CFG_ADD_GRP_ADDR_CNF); + CASE_RETURN_STRING(WNI_CFG_DEL_GRP_ADDR_CNF); + CASE_RETURN_STRING(SIR_CFG_PARAM_UPDATE_IND); + CASE_RETURN_STRING(SIR_CFG_DOWNLOAD_COMPLETE_IND); + CASE_RETURN_STRING(WNI_CFG_DNLD_RSP); + CASE_RETURN_STRING(WNI_CFG_GET_REQ); + 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; + } +} + +/** + * mac_trace() - Main function used for MAC Trace + * @mac_ctx: Global MAC context + * @code: code + * @session: session id + * @data: data to be traced. + * + * Return: None + **/ +void mac_trace(tpAniSirGlobal mac_ctx, uint8_t code, + uint16_t session, uint32_t data) +{ + /* + * Today mac_trace is being invoked by PE only, need to remove this + * function once PE is migrated to using new trace API. + */ + mac_trace_new(mac_ctx, QDF_MODULE_ID_PE, code, session, data); +} + +/** + * mac_trace_new() - New function used for MAC Trace + * @mac_ctx: Global MAC context + * @code: code + * @session: session id + * @data: data to be traced. + * + * Return: None + **/ +void mac_trace_new(tpAniSirGlobal mac_ctx, uint8_t module, uint8_t code, + uint16_t session, uint32_t data) +{ + qdf_trace(module, code, session, data); +} + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm new file mode 100644 index 0000000000000000000000000000000000000000..be649ea99d1e5cbf6440b8d7db8bec378a21a2c5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm @@ -0,0 +1,1000 @@ +;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. + +;parsemactrace.cmm - This script parses MAC trace table in UMAC layer +;This script relies on message id's placed in interface header file. +;If some message ID's are changed later, since they do not use enum, this script +;might show incorrect data. So message ID's should always be in sync +;Author: +;Date: 09/09/2013 +;History:- +;Date Modified by Modification Information +;-------------------------------------------------------------------- + + +ENTRY &FILE + +IF "&FILE"=="" +( +DIALOG.file *.txt +ENTRY &FILE +) + +OPEN #1 "&FILE" /Create /Write /Append + + +Var.NEW char [406][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" +Var.SET \halmsgtype[0x26]="SIR_HAL_ADD_BSS_RSP" +Var.SET \halmsgtype[0x27]="SIR_HAL_DELETE_BSS_REQ" +Var.SET \halmsgtype[0x28]="SIR_HAL_DELETE_BSS_RSP" +Var.SET \halmsgtype[0x29]="SIR_HAL_INIT_SCAN_REQ" +Var.SET \halmsgtype[0x2A]="SIR_HAL_INIT_SCAN_RSP" +Var.SET \halmsgtype[0x2B]="SIR_HAL_START_SCAN_REQ" +Var.SET \halmsgtype[0x2C]="SIR_HAL_START_SCAN_RSP" +Var.SET \halmsgtype[0x2D]="SIR_HAL_END_SCAN_REQ" +Var.SET \halmsgtype[0x2E]="SIR_HAL_END_SCAN_RSP" +Var.SET \halmsgtype[0x2F]="SIR_HAL_FINISH_SCAN_REQ" +Var.SET \halmsgtype[0x30]="SIR_HAL_FINISH_SCAN_RSP" +Var.SET \halmsgtype[0x31]="SIR_HAL_SEND_BEACON_REQ" +Var.SET \halmsgtype[0x32]="SIR_HAL_SET_BSSKEY_REQ" +Var.SET \halmsgtype[0x33]="SIR_HAL_SET_BSSKEY_RSP" +Var.SET \halmsgtype[0x34]="SIR_HAL_SET_STAKEY_REQ" +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" +Var.SET \halmsgtype[0x38]="SIR_HAL_UPDATE_CF_IND" +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" +Var.SET \halmsgtype[0x45]="SIR_HAL_REGISTER_PE_CALLBACK" +;38 to 42 unused +Var.SET \halmsgtype[0x4A]="SIR_HAL_IBSS_STA_ADD" +Var.SET \halmsgtype[0x4B]="SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND" +Var.SET \halmsgtype[0x4C]="SIR_HAL_SET_LINK_STATE" +Var.SET \halmsgtype[0x4D]="SIR_HAL_DELETE_BSS_HO_FAIL_REQ" +Var.SET \halmsgtype[0x4E]="SIR_HAL_DELETE_BSS_HO_FAIL_RSP" +;48 to 57 unused +Var.SET \halmsgtype[0x59]="SIR_HAL_SET_STA_BCASTKEY_REQ" +Var.SET \halmsgtype[0x5A]="SIR_HAL_SET_STA_BCASTKEY_RSP" +Var.SET \halmsgtype[0x5B]="SIR_HAL_ADD_TS_RSP" +Var.SET \halmsgtype[0x5C]="SIR_HAL_DPU_MIC_ERROR" +;62 unused +Var.SET \halmsgtype[0x5E]="SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT" +Var.SET \halmsgtype[0x5F]="SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ" +Var.SET \halmsgtype[0x60]="SIR_HAL_TIMER_ADC_RSSI_STATS" +;66 unused +Var.SET \halmsgtype[0x62]="SIR_HAL_SET_MIMOPS_REQ" +Var.SET \halmsgtype[0x63]="SIR_HAL_SET_MIMOPS_RSP" +Var.SET \halmsgtype[0x64]="SIR_HAL_SYS_READY_IND" +Var.SET \halmsgtype[0x65]="SIR_HAL_SET_TX_POWER_REQ" +Var.SET \halmsgtype[0x66]="SIR_HAL_SET_TX_POWER_RSP" +Var.SET \halmsgtype[0x67]="SIR_HAL_GET_TX_POWER_REQ" +Var.SET \halmsgtype[0x68]="SIR_HAL_GET_TX_POWER_RSP" +Var.SET \halmsgtype[0x69]="SIR_HAL_GET_NOISE_RSP" +Var.SET \halmsgtype[0x6A]="SIR_HAL_TRANSMISSION_CONTROL_IND" +;76 to 79 unused +Var.SET \halmsgtype[0x6F]="SIR_HAL_LOW_RSSI_IND" +Var.SET \halmsgtype[0x70]="SIR_HAL_BEACON_FILTER_IND" +Var.SET \halmsgtype[0x71]="SIR_HAL_WOW_ADD_PTRN" +Var.SET \halmsgtype[0x72]="SIR_HAL_WOW_DEL_PTRN" +Var.SET \halmsgtype[0x73]="SIR_HAL_WOWL_ENTER_REQ" +Var.SET \halmsgtype[0x74]="SIR_HAL_WOWL_ENTER_RSP" +Var.SET \halmsgtype[0x75]="SIR_HAL_WOWL_EXIT_REQ" +Var.SET \halmsgtype[0x76]="SIR_HAL_WOWL_EXIT_RSP" +Var.SET \halmsgtype[0x77]="SIR_HAL_GET_STATISTICS_REQ" +Var.SET \halmsgtype[0x78]="SIR_HAL_GET_STATISTICS_RSP" +Var.SET \halmsgtype[0x79]="SIR_HAL_SET_KEY_DONE" +Var.SET \halmsgtype[0x7A]="SIR_HAL_BTC_SET_CFG" +;92 unused +Var.SET \halmsgtype[0x7C]="SIR_HAL_HANDLE_FW_MBOX_RSP" +Var.SET \halmsgtype[0x7D]="SIR_HAL_SEND_PROBE_RSP_TMPL" +Var.SET \halmsgtype[0x7E]="SIR_LIM_ADDR2_MISS_IND" +Var.SET \halmsgtype[0x7F]="SIR_HAL_START_OEM_DATA_REQ" +Var.SET \halmsgtype[0x80]="SIR_HAL_START_OEM_DATA_RSP" +Var.SET \halmsgtype[0x81]="SIR_HAL_SET_MAX_TX_POWER_REQ" +Var.SET \halmsgtype[0x82]="SIR_HAL_SET_MAX_TX_POWER_RSP" +Var.SET \halmsgtype[0x83]="SIR_HAL_SET_HOST_OFFLOAD" +Var.SET \halmsgtype[0x84]="SIR_HAL_ADD_STA_SELF_REQ" +Var.SET \halmsgtype[0x85]="SIR_HAL_ADD_STA_SELF_RSP" +Var.SET \halmsgtype[0x86]="SIR_HAL_DEL_STA_SELF_REQ" +Var.SET \halmsgtype[0x87]="SIR_HAL_DEL_STA_SELF_RSP" +;105 unused +Var.SET \halmsgtype[0x88]="SIR_HAL_CFG_RXP_FILTER_REQ" +Var.SET \halmsgtype[0x89]="SIR_HAL_AGGR_ADD_TS_REQ" +Var.SET \halmsgtype[0x8A]="SIR_HAL_AGGR_ADD_TS_RSP" +Var.SET \halmsgtype[0x8B]="SIR_HAL_AGGR_QOS_REQ" +Var.SET \halmsgtype[0x8C]="SIR_HAL_AGGR_QOS_RSP" +Var.SET \halmsgtype[0x8D]="SIR_HAL_SET_P2P_GO_NOA_REQ" +Var.SET \halmsgtype[0x8E]="SIR_HAL_P2P_NOA_ATTR_IND" +Var.SET \halmsgtype[0x8F]="SIR_HAL_P2P_NOA_START_IND" +Var.SET \halmsgtype[0x90]="SIR_HAL_SET_LINK_STATE_RSP" +Var.SET \halmsgtype[0x91]="SIR_HAL_WLAN_SUSPEND_IND" +Var.SET \halmsgtype[0x92]="SIR_HAL_WLAN_RESUME_REQ" +Var.SET \halmsgtype[0x93]="SIR_HAL_SET_KEEP_ALIVE" +Var.SET \halmsgtype[0x94]="SIR_HAL_SET_NS_OFFLOAD" +Var.SET \halmsgtype[0x95]="SIR_HAL_SET_PNO_REQ" +Var.SET \halmsgtype[0x96]="SIR_HAL_SOC_ANTENNA_MODE_REQ" +Var.SET \halmsgtype[0x97]="SIR_HAL_SOC_ANTENNA_MODE_RESP" +;122 unused +Var.SET \halmsgtype[0x98]="SIR_HAL_8023_MULTICAST_LIST_REQ" +Var.SET \halmsgtype[0x99]="SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ" +Var.SET \halmsgtype[0x9A]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ" +Var.SET \halmsgtype[0x9B]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP" +Var.SET \halmsgtype[0x9C]="SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ" +;128 unused +Var.SET \halmsgtype[0x9F]="SIR_HAL_GTK_OFFLOAD_REQ" +Var.SET \halmsgtype[0xA0]="SIR_HAL_GTK_OFFLOAD_GETINFO_REQ" +Var.SET \halmsgtype[0xA1]="SIR_HAL_GTK_OFFLOAD_GETINFO_RSP" +Var.SET \halmsgtype[0xA2]="SIR_HAL_TSM_STATS_REQ" +Var.SET \halmsgtype[0xA3]="SIR_HAL_TSM_STATS_RSP" +Var.SET \halmsgtype[0xA4]="SIR_HAL_SET_TM_LEVEL_REQ" +Var.SET \halmsgtype[0xA5]="SIR_HAL_UPDATE_OP_MODE" +Var.SET \halmsgtype[0xA6]="SIR_HAL_TDLS_LINK_ESTABLISH" +Var.SET \halmsgtype[0xA7]="SIR_HAL_TDLS_LINK_TEARDOWN" +Var.SET \halmsgtype[0xA8]="SIR_HAL_ROAM_SCAN_OFFLOAD_REQ" +;139 and 140 unused +Var.SET \halmsgtype[0xAB]="SIR_HAL_TRAFFIC_STATS_IND" +Var.SET \halmsgtype[0xAC]="SIR_HAL_EXCLUDE_UNENCRYPTED_IND" +Var.SET \halmsgtype[0xAD]="SIR_HAL_TDLS_LINK_ESTABLISH_REQ" +Var.SET \halmsgtype[0xAE]="SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP" +Var.SET \halmsgtype[0xAF]="SIR_HAL_TDLS_IND" +Var.SET \halmsgtype[0xB0]="SIR_HAL_STOP_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xB1]="SIR_HAL_RX_SCAN_EVENT" +Var.SET \halmsgtype[0xB2]="SIR_HAL_DHCP_START_IND" +Var.SET \halmsgtype[0xB3]="SIR_HAL_DHCP_STOP_IND" +Var.SET \halmsgtype[0xB4]="SIR_HAL_IBSS_PEER_INACTIVITY_IND" +Var.SET \halmsgtype[0xB5]="SIR_HAL_LPHB_CONF_IND" +Var.SET \halmsgtype[0xB6]="SIR_HAL_ADD_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xB7]="SIR_HAL_DEL_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xB8]="SIR_HAL_PDEV_DUAL_MAC_CFG_REQ" +Var.SET \halmsgtype[0xB9]="SIR_HAL_PDEV_MAC_CFG_RESP" +;156 and 157 unused +Var.SET \halmsgtype[0xBC]="SIR_HAL_IBSS_PEER_INFO_REQ" +Var.SET \halmsgtype[0xBD]="SIR_HAL_RATE_UPDATE_IND" +Var.SET \halmsgtype[0xBE]="SIR_HAL_FLUSH_LOG_TO_FW" +Var.SET \halmsgtype[0xBF]="SIR_HAL_PDEV_SET_PCL_TO_FW" +;162 unused +Var.SET \halmsgtype[0xC1]="SIR_HAL_CLI_SET_CMD" +Var.SET \halmsgtype[0xC2]="SIR_HAL_PKTLOG_ENABLE_REQ" +Var.SET \halmsgtype[0xC3]="SIR_HAL_SME_SCAN_CACHE_UPDATED" +Var.SET \halmsgtype[0xC4]="SIR_HAL_START_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xC5]="SIR_HAL_UPDATE_CHAN_LIST_REQ" +;168 unused +Var.SET \halmsgtype[0xC7]="SIR_CSA_OFFLOAD_EVENT" +Var.SET \halmsgtype[0xC8]="SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ" +Var.SET \halmsgtype[0xC9]="SIR_HAL_TX_FAIL_MONITOR_IND" +Var.SET \halmsgtype[0xCA]="SIR_HAL_UPDATE_MEMBERSHIP" +Var.SET \halmsgtype[0xCB]="SIR_HAL_UPDATE_USERPOS" +Var.SET \halmsgtype[0xCC]="SIR_HAL_UPDATE_FW_TDLS_STATE" +Var.SET \halmsgtype[0xCD]="SIR_HAL_UPDATE_TDLS_PEER_STATE" +Var.SET \halmsgtype[0xCE]="SIR_HAL_TDLS_SHOULD_DISCOVER" +Var.SET \halmsgtype[0xCF]="SIR_HAL_TDLS_SHOULD_TEARDOWN" +Var.SET \halmsgtype[0xD0]="SIR_HAL_TDLS_PEER_DISCONNECTED" +Var.SET \halmsgtype[0xD1]="SIR_HAL_BEACON_TX_SUCCESS_IND" +Var.SET \halmsgtype[0xD2]="SIR_HAL_DFS_RADAR_IND" +Var.SET \halmsgtype[0xD3]="SIR_HAL_IBSS_CESIUM_ENABLE_IND" +Var.SET \halmsgtype[0xD4]="SIR_HAL_RMC_ENABLE_IND" +Var.SET \halmsgtype[0xD5]="SIR_HAL_RMC_DISABLE_IND" +Var.SET \halmsgtype[0xD6]="SIR_HAL_RMC_ACTION_PERIOD_IND" +Var.SET \halmsgtype[0xD7]="SIR_HAL_INIT_THERMAL_INFO_CMD" +Var.SET \halmsgtype[0xD8]="SIR_HAL_SET_THERMAL_LEVEL" +Var.SET \halmsgtype[0xD9]="SIR_HAL_SET_PLM_REQ" +Var.SET \halmsgtype[0xDA]="SIR_HAL_SET_TX_POWER_LIMIT" +Var.SET \halmsgtype[0xDB]="SIR_HAL_SET_SAP_INTRABSS_DIS" +Var.SET \halmsgtype[0xDC]="SIR_HAL_MODEM_POWER_STATE_IND" +Var.SET \halmsgtype[0xDD]="SIR_HAL_DISASSOC_TX_COMP" +Var.SET \halmsgtype[0xDE]="SIR_HAL_DEAUTH_TX_COMP" +Var.SET \halmsgtype[0xDF]="SIR_HAL_UPDATE_RX_NSS" +Var.SET \halmsgtype[0xE0]="SIR_HAL_STATS_EXT_REQUEST" +Var.SET \halmsgtype[0xE1]="SIR_HAL_STATS_EXT_EVENT" +Var.SET \halmsgtype[0xE2]="SIR_HAL_HIDE_SSID_VDEV_RESTART" +Var.SET \halmsgtype[0xE3]="SIR_HAL_GET_LINK_SPEED" +Var.SET \halmsgtype[0xE4]="SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ" +Var.SET \halmsgtype[0xE5]="SIR_HAL_EXTSCAN_START_REQ" +Var.SET \halmsgtype[0xE6]="SIR_HAL_EXTSCAN_STOP_REQ" +Var.SET \halmsgtype[0xE7]="SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ" +Var.SET \halmsgtype[0xE8]="SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ" +Var.SET \halmsgtype[0xE9]="SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ" +Var.SET \halmsgtype[0xEA]="SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ" +Var.SET \halmsgtype[0xEB]="SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ" +Var.SET \halmsgtype[0xEC]="SIR_HAL_CH_AVOID_UPDATE_REQ" +Var.SET \halmsgtype[0xED]="SIR_HAL_LL_STATS_CLEAR_REQ" +Var.SET \halmsgtype[0xEE]="SIR_HAL_LL_STATS_SET_REQ" +Var.SET \halmsgtype[0xEF]="SIR_HAL_LL_STATS_GET_REQ" +Var.SET \halmsgtype[0xF0]="SIR_HAL_LL_STATS_RESULTS_RSP" +Var.SET \halmsgtype[0xF1]="SIR_HAL_ROAM_OFFLOAD_SYNCH_CNF" +Var.SET \halmsgtype[0xF2]="SIR_HAL_NAN_REQUEST" +Var.SET \halmsgtype[0xF3]="SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ" +Var.SET \halmsgtype[0xF4]="SIR_HAL_SET_BASE_MACADDR_IND" +Var.SET \halmsgtype[0xF5]="SIR_HAL_SET_BASE_MACADDR_IND" +Var.SET \halmsgtype[0xF6]="SIR_HAL_LINK_STATUS_GET_REQ" +Var.SET \halmsgtype[0xF7]="SIR_HAL_CONFIG_EXT_WOW" +Var.SET \halmsgtype[0xF8]="SIR_HAL_CONFIG_APP_TYPE1_PARAMS" +Var.SET \halmsgtype[0xF9]="SIR_HAL_CONFIG_APP_TYPE2_PARAMS" +Var.SET \halmsgtype[0xFA]="SIR_HAL_GET_TEMPERATURE_REQ" +Var.SET \halmsgtype[0xFB]="SIR_HAL_SET_SCAN_MAC_OUI_REQ" +Var.SET \halmsgtype[0xFC]="SIR_HAL_SET_DHCP_SERVER_OFFLOAD" +Var.SET \halmsgtype[0xFD]="SIR_HAL_LED_FLASHING_REQ" +Var.SET \halmsgtype[0xFE]="SIR_HAL_LED_FLASHING_REQ" +Var.SET \halmsgtype[0xFF]="SIR_HAL_ROAM_OFFLOAD_SYNCH_IND" +Var.SET \halmsgtype[0x100]="SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL" +Var.SET \halmsgtype[0x101]="SIR_HAL_ROAM_INVOKE" +Var.SET \halmsgtype[0x102]="SIR_HAL_TDLS_SET_OFFCHAN_MODE" +Var.SET \halmsgtype[0x103]="SIR_HAL_TDLS_SET_OFFCHAN_MODE" +Var.SET \halmsgtype[0x104]="SIR_HAL_SET_MIRACAST" +Var.SET \halmsgtype[0x105]="SIR_HAL_UPDATE_Q2Q_IE_IND" +Var.SET \halmsgtype[0x106]="SIR_HAL_UPDATE_Q2Q_IE_IND" +Var.SET \halmsgtype[0x107]="SIR_HAL_CONFIG_GUARD_TIME" +Var.SET \halmsgtype[0x108]="SIR_HAL_IPA_OFFLOAD_ENABLE_DISABLE" +Var.SET \halmsgtype[0x109]="SIR_HAL_ENTER_PS_REQ" +Var.SET \halmsgtype[0x10A]="SIR_HAL_EXIT_PS_REQ" +Var.SET \halmsgtype[0x10B]="SIR_HAL_ENABLE_UAPSD_REQ" +Var.SET \halmsgtype[0x10C]="SIR_HAL_DISABLE_UAPSD_REQ" +Var.SET \halmsgtype[0x10D]="SIR_HAL_GATEWAY_PARAM_UPDATE_REQ" +;240 to 307 unused +Var.SET \halmsgtype[0x152]="SIR_HAL_RUNTIME_PM_SUSPEND_IND" +Var.SET \halmsgtype[0x153]="SIR_HAL_RUNTIME_PM_RESUME_IND" +;310 to 312 unused +Var.SET \halmsgtype[0x157]="SIR_HAL_SET_EPNO_LIST_REQ" +;314 and 315 unused +Var.SET \halmsgtype[0x15A]="SIR_HAL_SET_PASSPOINT_LIST_REQ" +Var.SET \halmsgtype[0x15B]="SIR_HAL_RESET_PASSPOINT_LIST_REQ" +;318 unused +Var.SET \halmsgtype[0x15D]="SIR_HAL_OCB_SET_CONFIG_CMD" +Var.SET \halmsgtype[0x15E]="SIR_HAL_OCB_SET_UTC_TIME_CMD" +Var.SET \halmsgtype[0x15F]="SIR_HAL_OCB_START_TIMING_ADVERT_CMD" +Var.SET \halmsgtype[0x160]="SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD" +Var.SET \halmsgtype[0x161]="SIR_HAL_OCB_GET_TSF_TIMER_CMD" +Var.SET \halmsgtype[0x162]="SIR_HAL_DCC_GET_STATS_CMD" +Var.SET \halmsgtype[0x163]="SIR_HAL_DCC_CLEAR_STATS_CMD" +Var.SET \halmsgtype[0x164]="SIR_HAL_DCC_UPDATE_NDL_CMD" +Var.SET \halmsgtype[0x165]="SIR_HAL_FW_MEM_DUMP_REQ" +Var.SET \halmsgtype[0x166]="SIR_HAL_START_STOP_LOGGING" +Var.SET \halmsgtype[0x167]="SIR_HAL_PDEV_SET_HW_MODE" +Var.SET \halmsgtype[0x168]="SIR_HAL_PDEV_SET_HW_MODE_RESP" +Var.SET \halmsgtype[0x169]="SIR_HAL_PDEV_HW_MODE_TRANS_IND" +Var.SET \halmsgtype[0x169]="SIR_HAL_BAD_PEER_TX_CTL_INI_CMD" +Var.SET \halmsgtype[0x16A]="SIR_HAL_SET_RSSI_MONITOR_REQ" +Var.SET \halmsgtype[0x16B]="SIR_HAL_SET_IE_INFO" +Var.SET \halmsgtype[0x16C]="SIR_HAL_LRO_CONFIG_CMD" +Var.SET \halmsgtype[0x16D]="SIR_HAL_SET_EGAP_CONF_PARAMS" +Var.SET \halmsgtype[0x16E]="SIR_HAL_HT40_OBSS_SCAN_IND" +Var.SET \halmsgtype[0x16F]="SIR_HAL_TSF_GPIO_PIN_REQ" +Var.SET \halmsgtype[0x170]="SIR_HAL_ADD_BCN_FILTER_CMDID" +Var.SET \halmsgtype[0x171]="SIR_HAL_REMOVE_BCN_FILTER_CMDID" +Var.SET \halmsgtype[0x172]="SIR_HAL_BPF_GET_CAPABILITIES_REQ" +Var.SET \halmsgtype[0x173]="SIR_HAL_BPF_SET_INSTRUCTIONS_REQ" +Var.SET \halmsgtype[0x174]="SIR_HAL_SET_WISA_PARAMS" +Var.SET \halmsgtype[0x175]="SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS" +Var.SET \halmsgtype[0x176]="SIR_HAL_SET_PDEV_IE_REQ" +Var.SET \halmsgtype[0x177]="SIR_HAL_TDLS_CONNECTION_TRACKER_NOTIFICATION" +Var.SET \halmsgtype[0x178]="SIR_HAL_NDP_GET_CAP_REQ" +Var.SET \halmsgtype[0x179]="SIR_HAL_NDP_INITIATOR_REQ" +Var.SET \halmsgtype[0x17A]="SIR_HAL_NDP_RESPONDER_REQ" +Var.SET \halmsgtype[0x17B]="SIR_HAL_NDP_END_REQ" +Var.SET \halmsgtype[0x17C]="SIR_HAL_NDI_CAP_RSP" +Var.SET \halmsgtype[0x17D]="SIR_HAL_IBSS_PEER_INFO_RSP" +Var.SET \halmsgtype[0x17E]="SIR_HAL_RATE_UPDATE_IND" +Var.SET \halmsgtype[0x17F]="SIR_HAL_NDP_INITIATOR_RSP" +Var.SET \halmsgtype[0x180]="SIR_HAL_NDP_RESPONDER_RSP" +Var.SET \halmsgtype[0x181]="SIR_HAL_NDP_END_RSP" +Var.SET \halmsgtype[0x182]="SIR_HAL_NDP_INDICATION" +Var.SET \halmsgtype[0x183]="SIR_HAL_NDP_CONFIRM" +Var.SET \halmsgtype[0x184]="SIR_HAL_NDP_END_IND" +Var.SET \halmsgtype[0x185]="SIR_HAL_UPDATE_WEP_DEFAULT_KEY" +;359 unused +Var.SET \halmsgtype[0x187]="SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND" +;361 unused +Var.SET \halmsgtype[0x189]="SIR_HAL_POWER_DBG_CMD" +Var.SET \halmsgtype[0x18A]="SIR_HAL_SET_DTIM_PERIOD" +Var.SET \halmsgtype[0x18B]="SIR_HAL_ENCRYPT_DECRYPT_MSG" +Var.SET \halmsgtype[0x18C]="SIR_HAL_SHORT_RETRY_LIMIT_CNT" +Var.SET \halmsgtype[0x18D]="SIR_HAL_LONG_RETRY_LIMIT_CNT" +Var.SET \halmsgtype[0x18E]="SIR_HAL_UPDATE_TX_FAIL_CNT_TH" +Var.SET \halmsgtype[0x18F]="SIR_HAL_POWER_DEBUG_STATS_REQ" +Var.SET \halmsgtype[0x190]="SIR_HAL_SET_WOW_PULSE_CMD" +Var.SET \halmsgtype[0x191]="SIR_HAL_SET_UDP_RESP_OFFLOAD" +Var.SET \halmsgtype[0x192]="SIR_HAL_SET_PER_ROAM_CONFIG_CMD" +Var.SET \halmsgtype[0x193]="SIR_HAL_GET_RCPI_REQ" +Var.SET \halmsgtype[0x194]="SIR_HAL_ENABLE_BCAST_FILTER" +Var.SET \halmsgtype[0x195]="SIR_HAL_DISABLE_BCAST_FILTER" + + +Var.NEW char [256][100] \smecodetype + +Var.SET \smecodetype[0x00]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ" +Var.SET \smecodetype[0x01]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS" +Var.SET \smecodetype[0x02]="TRACE_CODE_SME_RX_HDD_MSG_CONNECT" +Var.SET \smecodetype[0x03]="TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO" +Var.SET \smecodetype[0x04]="TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN" +Var.SET \smecodetype[0x05]="TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO" +Var.SET \smecodetype[0x06]="TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG" +Var.SET \smecodetype[0x07]="TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG" +Var.SET \smecodetype[0x08]="TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND" +Var.SET \smecodetype[0x09]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS" +Var.SET \smecodetype[0x0A]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS" +Var.SET \smecodetype[0x0B]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST" +Var.SET \smecodetype[0x0C]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT" +Var.SET \smecodetype[0x0D]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE" +Var.SET \smecodetype[0x0E]="TRACE_CODE_SME_RX_HDD_ROAM_REASSOC" +Var.SET \smecodetype[0x0F]="TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT" +Var.SET \smecodetype[0x10]="TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE" +Var.SET \smecodetype[0x11]="TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE" +Var.SET \smecodetype[0x12]="TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE" +Var.SET \smecodetype[0x12]="TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE" +Var.SET \smecodetype[0x13]="TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM" +Var.SET \smecodetype[0x14]="TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS" +Var.SET \smecodetype[0x15]="TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE" +Var.SET \smecodetype[0x16]="TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE" +Var.SET \smecodetype[0x17]="TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE" +Var.SET \smecodetype[0x18]="TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE" +Var.SET \smecodetype[0x19]="TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER" +Var.SET \smecodetype[0x1A]="TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER" +Var.SET \smecodetype[0x1B]="TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED" +Var.SET \smecodetype[0x1C]="TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER" +Var.SET \smecodetype[0x1D]="TRACE_CODE_SME_RX_HDD_REQUEST_BMPS" +Var.SET \smecodetype[0x1E]="TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG" +Var.SET \smecodetype[0x1F]="TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY" +Var.SET \smecodetype[0x20]="TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN" +Var.SET \smecodetype[0x21]="TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN" +Var.SET \smecodetype[0x22]="TRACE_CODE_SME_RX_HDD_ENTER_WOWL" +Var.SET \smecodetype[0x23]="TRACE_CODE_SME_RX_HDD_EXIT_WOWL" +Var.SET \smecodetype[0x24]="TRACE_CODE_SME_RX_HDD_SET_KEY" +Var.SET \smecodetype[0x25]="TRACE_CODE_SME_RX_HDD_REMOVE_KEY" +Var.SET \smecodetype[0x26]="TRACE_CODE_SME_RX_HDD_GET_STATS" +Var.SET \smecodetype[0x27]="TRACE_CODE_SME_RX_HDD_GET_RSSI" +Var.SET \smecodetype[0x28]="TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE" +Var.SET \smecodetype[0x29]="TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE" +Var.SET \smecodetype[0x2A]="TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE" +Var.SET \smecodetype[0x2B]="TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY" +Var.SET \smecodetype[0x2C]="TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ" +Var.SET \smecodetype[0x2D]="TRACE_CODE_SME_RX_HDD_DBG_READREG" +Var.SET \smecodetype[0x2E]="TRACE_CODE_SME_RX_HDD_DBG_WRITEREG" +Var.SET \smecodetype[0x2F]="TRACE_CODE_SME_RX_HDD_DBG_READMEM" +Var.SET \smecodetype[0x30]="TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM" +Var.SET \smecodetype[0x31]="TRACE_CODE_SME_RX_HDD_OPEN_SESSION" +Var.SET \smecodetype[0x32]="TRACE_CODE_SME_RX_HDD_CLOSE_SESSION" +Var.SET \smecodetype[0x33]="TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD" +Var.SET \smecodetype[0x34]="TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD" +Var.SET \smecodetype[0x35]="TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD" +Var.SET \smecodetype[0x36]="TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN" +Var.SET \smecodetype[0x37]="TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR" +Var.SET \smecodetype[0x38]="TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR" +Var.SET \smecodetype[0x39]="TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN" +Var.SET \smecodetype[0x3A]="TRACE_CODE_SME_RX_HDD_SEND_ACTION" +Var.SET \smecodetype[0x3B]="TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN" +Var.SET \smecodetype[0x3C]="TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL" +Var.SET \smecodetype[0x3D]="TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND" +Var.SET \smecodetype[0x3E]="TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ" +Var.SET \smecodetype[0x3F]="TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW" +Var.SET \smecodetype[0x40]="TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1" +Var.SET \smecodetype[0x41]="TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2" +Var.SET \smecodetype[0x42]="TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW" +Var.SET \smecodetype[0x43]="TRACE_CODE_SME_RX_HDD_SET_TXPOW" +Var.SET \smecodetype[0x44]="TRACE_CODE_SME_RX_HDD_SET_TMLEVEL" +Var.SET \smecodetype[0x45]="TRACE_CODE_SME_RX_HDD_CAPS_EXCH" +Var.SET \smecodetype[0x46]="TRACE_CODE_SME_RX_HDD_DISABLE_CAP" +Var.SET \smecodetype[0x47]="TRACE_CODE_SME_RX_HDD_GET_DEFCCNV" +Var.SET \smecodetype[0x48]="TRACE_CODE_SME_RX_HDD_GET_CURCC" +Var.SET \smecodetype[0x49]="TRACE_CODE_SME_RX_HDD_RESET_PW5G" +Var.SET \smecodetype[0x4A]="TRACE_CODE_SME_RX_HDD_UPDATE_RP5G" +Var.SET \smecodetype[0x4B]="TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND" +Var.SET \smecodetype[0x4C]="TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND" +Var.SET \smecodetype[0x4D]="TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF" +Var.SET \smecodetype[0x4E]="TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF" +Var.SET \smecodetype[0x4F]="TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED" +Var.SET \smecodetype[0x50]="TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE" +Var.SET \smecodetype[0x51]="TRACE_CODE_SME_RX_HDD_SET_SCANCTRL" +Var.SET \smecodetype[0x52]="TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE" +Var.SET \smecodetype[0x53]="TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES" +Var.SET \smecodetype[0x54]="TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME" +Var.SET \smecodetype[0x55]="TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ" +Var.SET \smecodetype[0x56]="TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ" +Var.SET \smecodetype[0x57]="TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ" +Var.SET \smecodetype[0x58]="TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA" +;#ifdef FEATURE_WLAN_TDLS //assuming this flag is enabled by default +Var.SET \smecodetype[0x59]="TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM" +Var.SET \smecodetype[0x5A]="TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ" +Var.SET \smecodetype[0x5B]="TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME" +Var.SET \smecodetype[0x5C]="TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA" +Var.SET \smecodetype[0x5D]="TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA" +Var.SET \smecodetype[0x5E]="TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA" +;#endif +Var.SET \smecodetype[0x5F]="TRACE_CODE_SME_RX_HDD_PREF_NET_LIST" +;#ifdef FEATURE_WLAN_LPHB //assuming this flag is enabled by default +Var.SET \smecodetype[0x60]="TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ" +;#endif /* FEATURE_WLAN_LPHB */ +Var.SET \smecodetype[0x61]="TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE" +;From here hardcoded to 250 in host code +Var.SET \smecodetype[0xFA]="TRACE_CODE_SME_COMMAND" +Var.SET \smecodetype[0xFB]="TRACE_CODE_SME_TX_WMA_MSG" +Var.SET \smecodetype[0xFC]="TRACE_CODE_SME_RX_WMA_MSG" + +Var.NEW char [256][50] \cfgmsgtype + +Var.SET \cfgmsgtype[0xB0]="SIR_CFG_PARAM_UPDATE_IND" +Var.SET \cfgmsgtype[0xB1]="SIR_CFG_DOWNLOAD_COMPLETE_IND" + + +Var.NEW char [256][50] \limmsgtype + +Var.SET \limmsgtype[0xB3]="SIR_LIM_RETRY_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB4]="SIR_BB_XPORT_MGMT_MSG" +;5 and 6 unused +Var.SET \limmsgtype[0xB7]="SIR_LIM_INV_KEY_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB8]="SIR_LIM_KEY_ID_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB9]="SIR_LIM_REPLAY_THRES_INTERRUPT_MSG" +Var.SET \limmsgtype[0xBA]="SIR_LIM_TD_DUMMY_CALLBACK_MSG" +Var.SET \limmsgtype[0xBB]="SIR_LIM_SCH_CLEAN_MSG" +Var.SET \limmsgtype[0xBC]="SIR_LIM_RADAR_DETECT_IND" +;0xD unused +Var.SET \limmsgtype[0xBE]="SIR_LIM_DEL_TS_IND" +;0xF and 0x10 unused +Var.SET \limmsgtype[0xC1]="SIR_LIM_DELETE_STA_CONTEXT_IND" +;0x12 unused +Var.SET \limmsgtype[0xC3]="SIR_LIM_UPDATE_BEACON" +;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" +Var.SET \limmsgtype[0xEA]="SIR_LIM_CHANNEL_SWITCH_TIMEOUT" +Var.SET \limmsgtype[0xEB]="SIR_LIM_QUIET_TIMEOUT" +Var.SET \limmsgtype[0xEC]="SIR_LIM_QUIET_BSS_TIMEOUT" +Var.SET \limmsgtype[0xED]="SIR_LIM_WPS_OVERLAP_TIMEOUT" +Var.SET \limmsgtype[0xEE]="SIR_LIM_FT_PREAUTH_RSP_TIMEOUT" +Var.SET \limmsgtype[0xEF]="SIR_LIM_REMAIN_CHN_TIMEOUT" +Var.SET \limmsgtype[0xF0]="SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT" +;0x21 and 0x22 unused +Var.SET \limmsgtype[0xF3]="SIR_LIM_BEACON_GEN_IND" +Var.SET \limmsgtype[0xF4]="SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT" +;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 and 0x2B unused +Var.SET \limmsgtype[0xFC]="SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE" +Var.SET \limmsgtype[0xFD]="SIR_LIM_AUTH_RETRY_TIMEOUT" +Var.SET \limmsgtype[0xFF]="SIR_LIM_MSG_TYPES_END" + + +Var.NEW char [256][50] \schmsgtype + +Var.SET \schmsgtype[0x0]="SIR_SCH_CHANNEL_SWITCH_REQUEST" +Var.SET \schmsgtype[0x1]="SIR_SCH_START_SCAN_REQ" +Var.SET \schmsgtype[0x2]="SIR_SCH_START_SCAN_RSP" +Var.SET \schmsgtype[0x3]="SIR_SCH_END_SCAN_NTF" +Var.SET \schmsgtype[0xFF]="SIR_SCH_MSG_TYPES_END" + +Var.NEW char [256][50] \pmmmsgtype + +Var.SET \pmmmsgtype[0x0]="SIR_PMM_CHANGE_PM_MODE" +Var.SET \pmmmsgtype[0xFF]="SIR_PMM_MSG_TYPES_END" + + +Var.NEW char [256][50] \mntmsgtype + +Var.SET \mntmsgtype[0x0]="SIR_MNT_RELEASE_BD" +Var.SET \mntmsgtype[0xFF]="SIR_MNT_MSG_TYPES_END" + +Var.NEW char [0x301][50] \pttmsgtype + +Var.SET \pttmsgtype[0x0]="SIR_PTT_MSG_TYPES_BEGIN" +Var.SET \pttmsgtype[0x300]="SIR_PTT_MSG_TYPES_END" + + +Var.NEW char [18][50] \code + +Var.SET \code[0]="TRACE_CODE_MLM_STATE" +Var.SET \code[1]="TRACE_CODE_SME_STATE" +Var.SET \code[2]="TRACE_CODE_TX_MGMT" +Var.SET \code[3]="TRACE_CODE_RX_MGMT" +Var.SET \code[4]="TRACE_CODE_RX_MGMT_TSF" +Var.SET \code[5]="TRACE_CODE_TX_COMPLETE" +Var.SET \code[6]="TRACE_CODE_TX_SME_MSG" +Var.SET \code[7]="TRACE_CODE_RX_SME_MSG" +Var.SET \code[8]="TRACE_CODE_TX_WMA_MSG" +Var.SET \code[9]="TRACE_CODE_RX_WMA_MSG" +Var.SET \code[10]="TRACE_CODE_TX_LIM_MSG" +Var.SET \code[11]="TRACE_CODE_RX_LIM_MSG" +Var.SET \code[12]="TRACE_CODE_TX_CFG_MSG" +Var.SET \code[13]="TRACE_CODE_RX_CFG_MSG" +Var.SET \code[14]="TRACE_CODE_RX_MGMT_DROP" +Var.SET \code[15]="TRACE_CODE_TIMER_ACTIVATE" +Var.SET \code[16]="TRACE_CODE_TIMER_DEACTIVATE" +Var.SET \code[17]="TRACE_CODE_INFO_LOG" + + +Var.NEW char [13][50] \module + +Var.SET \module[1]="QDF_MODULE_ID_TLSHIM" +Var.SET \module[2]="QDF_MODULE_ID_WMI" +Var.SET \module[3]="QDF_MODULE_ID_HTT" +Var.SET \module[4]="QDF_MODULE_ID_RSV4" +Var.SET \module[5]="QDF_MODULE_ID_HDD" +Var.SET \module[6]="QDF_MODULE_ID_SME" +Var.SET \module[7]="QDF_MODULE_ID_PE" +Var.SET \module[8]="QDF_MODULE_ID_WMA" +Var.SET \module[9]="QDF_MODULE_ID_SYS" +Var.SET \module[10]="QDF_MODULE_ID_QDF" +Var.SET \module[11]="QDF_MODULE_ID_SAP" +Var.SET \module[12]="QDF_MODULE_ID_HDD_SOFTAP" + +Var.NEW char [16][50] \mgmttype + +Var.SET \mgmttype[0]="SIR_MAC_MGMT_ASSOC_REQ" +Var.SET \mgmttype[1]="SIR_MAC_MGMT_ASSOC_RSP" +Var.SET \mgmttype[2]="SIR_MAC_MGMT_REASSOC_REQ" +Var.SET \mgmttype[3]="SIR_MAC_MGMT_REASSOC_RSP" +Var.SET \mgmttype[4]="SIR_MAC_MGMT_PROBE_REQ" +Var.SET \mgmttype[5]="SIR_MAC_MGMT_PROBE_RSP" +Var.SET \mgmttype[6]="SIR_MAC_MGMT_TIME_ADVERT" +Var.SET \mgmttype[8]="SIR_MAC_MGMT_BEACON" +Var.SET \mgmttype[9]="SIR_MAC_MGMT_ATIM" +Var.SET \mgmttype[10]="SIR_MAC_MGMT_DISASSOC" +Var.SET \mgmttype[11]="SIR_MAC_MGMT_AUTH" +Var.SET \mgmttype[12]="SIR_MAC_MGMT_DEAUTH" +Var.SET \mgmttype[13]="SIR_MAC_MGMT_ACTION" +Var.SET \mgmttype[15]="SIR_MAC_MGMT_RESERVED15" + +Var.NEW char [30][50] \limtimertype + +Var.SET \limtimertype[0]="eLIM_MIN_CHANNEL_TIMER" +Var.SET \limtimertype[1]="eLIM_MAX_CHANNEL_TIMER" +Var.SET \limtimertype[2]="eLIM_JOIN_FAIL_TIMER" +Var.SET \limtimertype[3]="eLIM_AUTH_FAIL_TIMER" +Var.SET \limtimertype[4]="eLIM_AUTH_RESP_TIMER" +Var.SET \limtimertype[5]="eLIM_ASSOC_FAIL_TIMER" +Var.SET \limtimertype[6]="eLIM_REASSOC_FAIL_TIMER" +Var.SET \limtimertype[7]="eLIM_PRE_AUTH_CLEANUP_TIMER" +Var.SET \limtimertype[8]="eLIM_CNF_WAIT_TIMER" +Var.SET \limtimertype[9]="eLIM_AUTH_RSP_TIMER" +Var.SET \limtimertype[10]="eLIM_UPDATE_OLBC_CACHE_TIMER" +Var.SET \limtimertype[11]="eLIM_PROBE_AFTER_HB_TIMER" +Var.SET \limtimertype[12]="eLIM_ADDTS_RSP_TIMER" +Var.SET \limtimertype[13]="eLIM_CHANNEL_SWITCH_TIMER" +Var.SET \limtimertype[14]="eLIM_LEARN_DURATION_TIMER" +Var.SET \limtimertype[15]="eLIM_QUIET_TIMER" +Var.SET \limtimertype[16]="eLIM_QUIET_BSS_TIMER" +Var.SET \limtimertype[17]="eLIM_WPS_OVERLAP_TIMER" +Var.SET \limtimertype[18]="eLIM_FT_PREAUTH_RSP_TIMER" +Var.SET \limtimertype[19]="eLIM_REMAIN_CHN_TIMER" +Var.SET \limtimertype[20]="eLIM_PERIODIC_PROBE_REQ_TIMER" +;#ifdef FEATURE_WLAN_CCX +;Var.SET \limtimertype[0]="eLIM_TSM_TIMER" +;#endif +Var.SET \limtimertype[22]="eLIM_DISASSOC_ACK_TIMER" +Var.SET \limtimertype[23]="eLIM_DEAUTH_ACK_TIMER" +Var.SET \limtimertype[24]="eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER" +Var.SET \limtimertype[25]="eLIM_INSERT_SINGLESHOT_NOA_TIMER" +Var.SET \limtimertype[26]="eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE" + + + +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" +;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[0x4B]="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) + +IF ((&HEAD>&TRACEMAXINDEX)||(&TAIL>&TRACEMAXINDEX)||(&TAIL==&HEAD)) +( + GOTO ENDSCRIPT +) + +&INDEX=&HEAD + +TRACESTART: + +&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) + + + WRITE #1 "TIME: " &TIME + Var.Write #1 %STRING \module[&MODULE] + +IF (&MODULE==0x7) +( +if (&CODE>=0)&&(&CODE<=0x12) +( + Var.Write #1 %STRING \code[&CODE] " [" %Hex &CODE "]" +) + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) + + +;0 TRACE_CODE_MLM_STATE +IF (&CODE==0x0) +( + Var.NEW tLimMlmStates \mlmstate + Var.Set \mlmstate=&DATA + ;Var.Write #1 \mlmstate " [" %Hex &DATA "]" +) + +;1 TRACE_CODE_SME_STATE +IF (&CODE==0x1) +( + Var.NEW tLimSmeStates \smestate + Var.Set \smestate=&DATA + Var.Write #1 \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 %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 %STRING \mgmttype[&DATA] " [" %Hex &DATA "]" +) + +;14 TRACE_CODE_RX_MGMT_DROP +IF (&CODE==0xE) +( + Var.NEW tMgmtFrmDropReason \dropreason + Var.Set \dropreason=&DATA + Var.Write #1 \dropreason " [" %Hex &DATA "]" +) + + +;15 TRACE_CODE_TIMER_ACTIVATE/DEACTIVATE +IF (&CODE==0xF)||(&CODE==0x10) +( + Var.Write #1 %STRING \limtimertype[&DATA] " [" %Hex &DATA "]" +) + +;6 TRACE_CODE_TX_SME_MSG +IF (&CODE==0x6) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" + ) +) + +;7 TRACE_CODE_RX_SME_MSG +IF (&CODE==0x7) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) +) + +;8 TRACE_CODE_TX_WMA_MSG +IF (&CODE==0x8) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x10) +( +Var.Write #1 %STRING \halmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +;9 TRACE_CODE_RX_WMA_MSG +IF (&CODE==0x9) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x10) +( +Var.Write #1 %STRING \halmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +;10 TRACE_CODE_TX_LIM_MSG +IF (&CODE==0xA) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) +) + +;11 TRACE_CODE_RX_LIM_MSG +IF (&CODE==0xB) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + &DATA=v.value(&DATA&0xFFFF) + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) +) + +;12 TRACE_CODE_TX_CFG_MSG +IF (&CODE==0xC) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x11)&&(&DATA>=0x11B0) +( +Var.Write #1 %STRING \cfgmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +;13 TRACE_CODE_RX_CFG_MSG +IF (&CODE==0xD) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x11)&&(&DATA>=0x11B0) +( +Var.Write #1 %STRING \cfgmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + &DATA=v.value(&DATA&0xFFFF) + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) + +) + + +IF (&MODULE==0x6) +( + + IF ((&CODE>=0x0)&&(&CODE<=0x61)) + ( + Var.Write #1 %STRING \smecodetype[&CODE] " [" %Hex &CODE "]" + ) + ELSE + ( + IF ((&CODE>=0xFA)&&(&CODE<=0xFC)) + ( + Var.Write #1 %STRING \smecodetype[&CODE] " [" %Hex &CODE "]" + ) + ELSE + ( + WRITE #1 "CODE: " &CODE + ) + ) + WRITE #1 "DATA: " &DATA + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +IF (&MODULE==0x5) +( + + IF ((&CODE>=0x0)&&(&CODE<=0x4A)) + ( + Var.Write #1 %STRING \hddcodetype[&CODE] " [" %Hex &CODE "]" + WRITE #1 "DATA: " &DATA + ) + ELSE + ( + IF (&CODE==0x4B) + ( + Var.Write #1 %STRING \hddcodetype[&CODE] " [" %Hex &CODE "]" + Var.NEW eRoamCmdStatus \csrstatus + Var.Set \csrstatus=&DATA + Var.Write #1 \csrstatus " [" %Hex &DATA "]" + ) + ELSE + ( + WRITE #1 "CODE: " &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/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c new file mode 100644 index 0000000000000000000000000000000000000000..dc3efe44ee07b22c73b9cd7bd4190116ef9f600b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -0,0 +1,6446 @@ +/* + * 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. + */ + +/* + * 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 "cfg_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" + + +#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(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pWmm) +{ + pe_debug("WMM Parameters Received:"); + pe_debug("BE: 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); + + pe_debug("BK: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d", + pWmm->acbk_aifsn, pWmm->acbk_acm, pWmm->acbk_aci, + pWmm->acbk_acwmin, pWmm->acbk_acwmax, pWmm->acbk_txoplimit); + + pe_debug("VI: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d", + pWmm->acvi_aifsn, pWmm->acvi_acm, pWmm->acvi_aci, + pWmm->acvi_acwmin, pWmm->acvi_acwmax, pWmm->acvi_txoplimit); + + pe_debug("VO: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d", + pWmm->acvo_aifsn, pWmm->acvo_acm, pWmm->acvo_aci, + pWmm->acvo_acwmin, pWmm->acvo_acwmax, pWmm->acvo_txoplimit); + + return; +} + +/* ////////////////////////////////////////////////////////////////////// */ +/* 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(tpAniSirGlobal pMac, 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[SIR_MAC_MAX_IE_LENGTH+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; + } else if (EID != pRsnIe->rsnIEdata[idx] && + /* & if no more IE, */ + bytesLeft <= (uint16_t) (ieLen)) { + pe_debug("No IE (%d) in find_ie_location", EID); + return ret_val; + } + bytesLeft -= ieLen; + ieLen = pRsnIe->rsnIEdata[idx + 1] + 2; + idx += ieLen; + } + + return ret_val; +} + +QDF_STATUS +populate_dot11f_capabilities(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + tpPESession psessionEntry) +{ + uint16_t cfg; + QDF_STATUS nSirStatus; + + nSirStatus = cfg_get_capability_info(pMac, &cfg, psessionEntry); + 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(tpAniSirGlobal mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + tpPESession session_entry) +{ + uint8_t ch_offset; + + if (session_entry->gLimChannelSwitch.ch_width == CH_WIDTH_80MHZ) + ch_offset = BW80; + else + ch_offset = session_entry->gLimChannelSwitch.sec_ch_offset; + + dot_11_ptr->switch_mode = session_entry->gLimChannelSwitch.switchMode; + dot_11_ptr->new_reg_class = wlan_reg_dmn_get_opclass_from_channel( + mac_ptr->scan.countryCodeCurrent, + session_entry->gLimChannelSwitch.primaryChannel, + 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; + + pe_debug("country:%s chan:%d width:%d reg:%d off:%d", + mac_ptr->scan.countryCodeCurrent, + session_entry->gLimChannelSwitch.primaryChannel, + session_entry->gLimChannelSwitch.ch_width, + dot_11_ptr->new_reg_class, + session_entry->gLimChannelSwitch.sec_ch_offset); +} + +void +populate_dot11f_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEChanSwitchAnn *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->switchMode = psessionEntry->gLimChannelSwitch.switchMode; + pDot11f->newChannel = psessionEntry->gLimChannelSwitch.primaryChannel; + pDot11f->switchCount = + (uint8_t) psessionEntry->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(tpAniSirGlobal mac_ptr, + tDot11fIESuppOperatingClasses *dot_11_ptr, + tpPESession session_entry) +{ + uint8_t ch_bandwidth; + + if (session_entry->ch_width == CH_WIDTH_80MHZ) { + ch_bandwidth = BW80; + } else { + switch (session_entry->htSecondaryChannelOffset) { + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_bandwidth = BW40_HIGH_PRIMARY; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_bandwidth = BW40_LOW_PRIMARY; + break; + default: + ch_bandwidth = BW20; + break; + } + } + + wlan_reg_dmn_get_curr_opclasses(&dot_11_ptr->num_classes, + &dot_11_ptr->classes[1]); + dot_11_ptr->classes[0] = wlan_reg_dmn_get_opclass_from_channel( + mac_ptr->scan.countryCodeCurrent, + session_entry->currentOperChannel, + ch_bandwidth); + dot_11_ptr->num_classes++; + dot_11_ptr->present = 1; +} + +void +populate_dot11f_chan_switch_wrapper(tpAniSirGlobal pMac, + tDot11fIEChannelSwitchWrapper *pDot11f, + tpPESession psessionEntry) +{ + const uint8_t *ie_ptr = NULL; + + /* + * 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 = + psessionEntry->gLimWiderBWChannelSwitch.newChanWidth; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq0 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq1 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq1; + pDot11f->WiderBWChanSwitchAnn.present = 1; + + /* + * Add the VHT Transmit power Envelope Sublement. + */ + ie_ptr = wlan_get_ie_ptr_from_eid( + DOT11F_EID_VHT_TRANSMIT_POWER_ENV, + psessionEntry->addIeParams.probeRespBCNData_buff, + psessionEntry->addIeParams.probeRespBCNDataLen); + if (ie_ptr) { + /* Ignore EID field */ + pDot11f->vht_transmit_power_env.present = 1; + pDot11f->vht_transmit_power_env.num_bytes = ie_ptr[1]; + qdf_mem_copy(pDot11f->vht_transmit_power_env.bytes, + &ie_ptr[2], pDot11f->vht_transmit_power_env.num_bytes); + } + +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +void +populate_dot11f_avoid_channel_ie(tpAniSirGlobal mac_ctx, + tDot11fIEQComVendorIE *dot11f, + tpPESession pe_session) +{ + if (!pe_session->sap_advertise_avoid_ch_ie) + return; + + dot11f->present = true; + dot11f->type = QCOM_VENDOR_IE_MCC_AVOID_CH; + dot11f->channel = pe_session->currentOperChannel; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +void +populate_dot11f_wider_bw_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEWiderBWChanSwitchAnn *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->present = 1; + pDot11f->newChanWidth = + psessionEntry->gLimWiderBWChannelSwitch.newChanWidth; + pDot11f->newCenterChanFreq0 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0; + pDot11f->newCenterChanFreq1 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq1; +} + +QDF_STATUS +populate_dot11f_country(tpAniSirGlobal pMac, + tDot11fIECountry *pDot11f, tpPESession psessionEntry) +{ + uint32_t len, maxlen; + uint16_t item; + QDF_STATUS nSirStatus; + enum band_info rfBand; + uint8_t temp[CFG_MAX_STR_LEN], code[3]; + + if (psessionEntry->lim11dEnabled) { + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (rfBand == BAND_5G) { + item = WNI_CFG_MAX_TX_POWER_5; + maxlen = WNI_CFG_MAX_TX_POWER_5_LEN; + } else { + item = WNI_CFG_MAX_TX_POWER_2_4; + maxlen = WNI_CFG_MAX_TX_POWER_2_4_LEN; + } + + CFG_GET_STR(nSirStatus, pMac, item, temp, len, maxlen); + + if (3 > len) { + /* no limit on tx power, cannot include the IE because at least */ + /* one (channel,num,tx power) must be present */ + return QDF_STATUS_SUCCESS; + } + + wlan_reg_read_current_country(pMac->psoc, code); + + qdf_mem_copy(pDot11f->country, code, 2); + + if (len > MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE) { + pe_err("len:%d is out of bounds, resetting", len); + len = MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE; + } + + pDot11f->num_triplets = (uint8_t) (len / 3); + qdf_mem_copy((uint8_t *) pDot11f->triplets, temp, len); + + pDot11f->present = 1; + } + + return QDF_STATUS_SUCCESS; +} /* 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 + * channel: channel number + * + * This routine will populate DS param in management frame like + * beacon, probe response, and etc. + * + * Return: Overall success + */ +QDF_STATUS +populate_dot11f_ds_params(tpAniSirGlobal mac_ctx, + tDot11fIEDSParams *dot11f_param, uint8_t channel) +{ + if (IS_24G_CH(channel)) { + /* .11b/g mode PHY => Include the DS Parameter Set IE: */ + dot11f_param->curr_channel = channel; + dot11f_param->present = 1; + } + + return QDF_STATUS_SUCCESS; +} + +#define SET_AIFSN(aifsn) (((aifsn) < 2) ? 2 : (aifsn)) + +void +populate_dot11f_edca_param_set(tpAniSirGlobal pMac, + tDot11fIEEDCAParamSet *pDot11f, + tpPESession psessionEntry) +{ + + if (psessionEntry->limQosEnabled) { + /* change to bitwise operation, after this is fixed in frames. */ + pDot11f->qos = + (uint8_t) (0xf0 & + (psessionEntry->gLimEdcaParamSetCount << 4)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pDot11f->acbe_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[0].aci.aifsn)); + pDot11f->acbe_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[0].aci.acm); + pDot11f->acbe_aci = (0x3 & SIR_MAC_EDCAACI_BESTEFFORT); + pDot11f->acbe_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.min); + pDot11f->acbe_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.max); + pDot11f->acbe_txoplimit = + psessionEntry->gLimEdcaParamsBC[0].txoplimit; + + pDot11f->acbk_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[1].aci.aifsn)); + pDot11f->acbk_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[1].aci.acm); + pDot11f->acbk_aci = (0x3 & SIR_MAC_EDCAACI_BACKGROUND); + pDot11f->acbk_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.min); + pDot11f->acbk_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.max); + pDot11f->acbk_txoplimit = + psessionEntry->gLimEdcaParamsBC[1].txoplimit; + + pDot11f->acvi_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[2].aci.aifsn)); + pDot11f->acvi_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[2].aci.acm); + pDot11f->acvi_aci = (0x3 & SIR_MAC_EDCAACI_VIDEO); + pDot11f->acvi_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.min); + pDot11f->acvi_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.max); + pDot11f->acvi_txoplimit = + psessionEntry->gLimEdcaParamsBC[2].txoplimit; + + pDot11f->acvo_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[3].aci.aifsn)); + pDot11f->acvo_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[3].aci.acm); + pDot11f->acvo_aci = (0x3 & SIR_MAC_EDCAACI_VOICE); + pDot11f->acvo_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.min); + pDot11f->acvo_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.max); + pDot11f->acvo_txoplimit = + psessionEntry->gLimEdcaParamsBC[3].txoplimit; + + pDot11f->present = 1; + } + +} /* End PopluateDot11fEDCAParamSet. */ + +QDF_STATUS +populate_dot11f_erp_info(tpAniSirGlobal pMac, + tDot11fIEERPInfo *pDot11f, tpPESession psessionEntry) +{ + QDF_STATUS nSirStatus; + uint32_t val; + enum band_info rfBand = BAND_UNKNOWN; + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (BAND_2G == rfBand) { + pDot11f->present = 1; + + val = psessionEntry->cfgProtection.fromllb; + if (!val) { + pe_err("11B protection not enabled. Not populating ERP IE %d", + val); + return QDF_STATUS_SUCCESS; + } + + if (psessionEntry->gLim11bParams.protectionEnabled) { + pDot11f->non_erp_present = 1; + pDot11f->use_prot = 1; + } + + if (psessionEntry->gLimOlbcParams.protectionEnabled) { + /* FIXME_PROTECTION: we should be setting non_erp present also. */ + /* check the test plan first. */ + pDot11f->use_prot = 1; + } + + if ((psessionEntry->gLimNoShortParams.numNonShortPreambleSta) + || !psessionEntry->beaconParams.fShortPreamble) { + pDot11f->barker_preamble = 1; + + } + /* if protection always flag is set, advertise protection enabled */ + /* regardless of legacy stations presence */ + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_11G_PROTECTION_ALWAYS, + val); + + if (val) { + pDot11f->use_prot = 1; + } + } + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_erp_info. */ + +QDF_STATUS +populate_dot11f_ext_supp_rates(tpAniSirGlobal pMac, uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f, + tpPESession psessionEntry) +{ + QDF_STATUS nSirStatus; + uint32_t nRates = 0; + uint8_t rates[SIR_MAC_RATESET_EID_MAX]; + + /* 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 (psessionEntry != NULL) { + nRates = psessionEntry->extRateSet.numRates; + qdf_mem_copy(rates, psessionEntry->extRateSet.rate, + nRates); + } else { + pe_err("no session context exists while populating Operational Rate Set"); + } + } else if (HIGHEST_24GHZ_CHANNEL_NUM >= nChannelNum) { + CFG_GET_STR(nSirStatus, pMac, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, rates, + nRates, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN); + } + + 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_ext_supp_rates. */ + +QDF_STATUS +populate_dot11f_ext_supp_rates1(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f) +{ + uint32_t nRates; + QDF_STATUS nSirStatus; + 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! */ + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + + 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(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEHTCaps *pDot11f) +{ + uint32_t nCfgValue, nCfgLen; + uint8_t nCfgValue8; + QDF_STATUS nSirStatus; + tSirMacHTParametersInfo *pHTParametersInfo; + uint8_t disable_high_ht_mcs_2x2 = 0; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_CAP_INFO, nCfgValue); + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->mimoPowerSave = uHTCapabilityInfo.htCapInfo.mimoPowerSave; + pDot11f->greenField = uHTCapabilityInfo.htCapInfo.greenField; + pDot11f->delayedBA = uHTCapabilityInfo.htCapInfo.delayedBA; + pDot11f->maximalAMSDUsize = + uHTCapabilityInfo.htCapInfo.maximalAMSDUsize; + pDot11f->dsssCckMode40MHz = + uHTCapabilityInfo.htCapInfo.dsssCckMode40MHz; + pDot11f->psmp = uHTCapabilityInfo.htCapInfo.psmp; + pDot11f->stbcControlFrame = + uHTCapabilityInfo.htCapInfo.stbcControlFrame; + pDot11f->lsigTXOPProtection = + uHTCapabilityInfo.htCapInfo.lsigTXOPProtection; + + /* All sessionized entries will need the check below */ + if (psessionEntry == NULL) { /* Only in case of NO session */ + pDot11f->supportedChannelWidthSet = + uHTCapabilityInfo.htCapInfo.supportedChannelWidthSet; + pDot11f->advCodingCap = + uHTCapabilityInfo.htCapInfo.advCodingCap; + pDot11f->txSTBC = uHTCapabilityInfo.htCapInfo.txSTBC; + pDot11f->rxSTBC = uHTCapabilityInfo.htCapInfo.rxSTBC; + pDot11f->shortGI20MHz = + uHTCapabilityInfo.htCapInfo.shortGI20MHz; + pDot11f->shortGI40MHz = + uHTCapabilityInfo.htCapInfo.shortGI40MHz; + } else { + pDot11f->advCodingCap = psessionEntry->htConfig.ht_rx_ldpc; + pDot11f->supportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + pDot11f->txSTBC = psessionEntry->htConfig.ht_tx_stbc; + pDot11f->rxSTBC = psessionEntry->htConfig.ht_rx_stbc; + pDot11f->shortGI20MHz = psessionEntry->htConfig.ht_sgi20; + pDot11f->shortGI40MHz = psessionEntry->htConfig.ht_sgi40; + } + + /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is + eHT_CHANNEL_WIDTH_20MHZ */ + if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { + pDot11f->shortGI40MHz = 0; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_AMPDU_PARAMS, nCfgValue); + + nCfgValue8 = (uint8_t) nCfgValue; + pHTParametersInfo = (tSirMacHTParametersInfo *) &nCfgValue8; + + pDot11f->maxRxAMPDUFactor = pHTParametersInfo->maxRxAMPDUFactor; + pDot11f->mpduDensity = pHTParametersInfo->mpduDensity; + pDot11f->reserved1 = pHTParametersInfo->reserved; + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_MCS_SET, + pDot11f->supportedMCSSet, nCfgLen, + SIZE_OF_SUPPORTED_MCS_SET); + + if (psessionEntry) { + disable_high_ht_mcs_2x2 = + pMac->roam.configParam.disable_high_ht_mcs_2x2; + pe_debug("disable HT high MCS INI param[%d]", + disable_high_ht_mcs_2x2); + if (psessionEntry->nss == NSS_1x1_MODE) { + pDot11f->supportedMCSSet[1] = 0; + } else if (IS_24G_CH(psessionEntry->currentOperChannel) && + disable_high_ht_mcs_2x2 && + (psessionEntry->pePersona == 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 (psessionEntry && + LIM_IS_STA_ROLE(psessionEntry) && + (psessionEntry->enableHtSmps) && + (!psessionEntry->supported_nss_1x1)) { + pe_debug("Add SM power save IE: %d", + psessionEntry->htSmpsvalue); + pDot11f->mimoPowerSave = psessionEntry->htSmpsvalue; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_EXT_HT_CAP_INFO, nCfgValue); + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; + pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; + pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_TX_BF_CAP, nCfgValue); + + 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; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_AS_CAP, nCfgValue); + + 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 = 1; + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_ht_caps. */ + +void lim_log_vht_cap(tpAniSirGlobal pMac, 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(tpAniSirGlobal pMac, + tDot11fIEVHTOperation *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + pe_debug("chanWidth: %d", pDot11f->chanWidth); + pe_debug("chanCenterFreqSeg1: %d", + pDot11f->chanCenterFreqSeg1); + pe_debug("chanCenterFreqSeg2: %d", + pDot11f->chanCenterFreqSeg2); + pe_debug("basicMCSSet: %d", pDot11f->basicMCSSet); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + pe_debug("muMIMOCapStaCount: %d", + pDot11f->muMIMOCapStaCount); + pe_debug("ssUnderUtil: %d", pDot11f->ssUnderUtil); + pe_debug("FortyMHzUtil: %d", pDot11f->FortyMHzUtil); + pe_debug("EightyMHzUtil: %d", pDot11f->EightyMHzUtil); + pe_debug("OneSixtyMHzUtil: %d", + pDot11f->OneSixtyMHzUtil); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_operating_mode(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, tSirQosMapSet *pQosMapSet) +{ + uint8_t i; + + 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); + for (i = 0; i < pQosMapSet->num_dscp_exceptions; i++) { + pe_debug("dscp value: %d", + pQosMapSet->dscp_exceptions[i][0]); + pe_debug("User priority value: %d", + pQosMapSet->dscp_exceptions[i][1]); + } + for (i = 0; i < 8; i++) { + pe_debug("dscp low for up %d: %d", i, + pQosMapSet->dscp_range[i][0]); + pe_debug("dscp high for up %d: %d", i, + pQosMapSet->dscp_range[i][1]); + } +} + +QDF_STATUS +populate_dot11f_vht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEVHTCaps *pDot11f) +{ + QDF_STATUS nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MAX_MPDU_LENGTH, nCfgValue); + pDot11f->maxMPDULen = (nCfgValue & 0x0003); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + nCfgValue); + pDot11f->supportedChannelWidthSet = (nCfgValue & 0x0003); + + nCfgValue = 0; + /* With VHT it suffices if we just examine HT */ + if (psessionEntry) { + if (psessionEntry->htConfig.ht_rx_ldpc) + pDot11f->ldpcCodingCap = + psessionEntry->vht_config.ldpc_coding; + if (psessionEntry->ch_width < CH_WIDTH_80MHZ) { + pDot11f->shortGI80MHz = 0; + } else { + pDot11f->shortGI80MHz = + psessionEntry->vht_config.shortgi80; + } + + if (psessionEntry->ch_width < CH_WIDTH_160MHZ) { + pDot11f->shortGI160and80plus80MHz = 0; + pDot11f->supportedChannelWidthSet = 0; + } else { + pDot11f->shortGI160and80plus80MHz = + psessionEntry->vht_config.shortgi160and80plus80; + } + + if (psessionEntry->htConfig.ht_tx_stbc) + pDot11f->txSTBC = psessionEntry->vht_config.tx_stbc; + + if (psessionEntry->htConfig.ht_rx_stbc) + pDot11f->rxSTBC = psessionEntry->vht_config.rx_stbc; + + pDot11f->suBeamformeeCap = + psessionEntry->vht_config.su_beam_formee; + if (psessionEntry->vht_config.su_beam_formee) { + pDot11f->muBeamformeeCap = + psessionEntry->vht_config.mu_beam_formee; + pDot11f->csnofBeamformerAntSup = + psessionEntry->vht_config.csnof_beamformer_antSup; + } else { + pDot11f->muBeamformeeCap = 0; + } + pDot11f->suBeamFormerCap = + psessionEntry->vht_config.su_beam_former; + + pDot11f->vhtTXOPPS = psessionEntry->vht_config.vht_txops; + + pDot11f->numSoundingDim = + psessionEntry->vht_config.num_soundingdim; + + pDot11f->htcVHTCap = psessionEntry->vht_config.htc_vhtcap; + + pDot11f->rxAntPattern = psessionEntry->vht_config.rx_antpattern; + + pDot11f->txAntPattern = psessionEntry->vht_config.tx_antpattern; + + pDot11f->maxAMPDULenExp = + psessionEntry->vht_config.max_ampdu_lenexp; + + pDot11f->vhtLinkAdaptCap = + psessionEntry->vht_config.vht_link_adapt; + } else { + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_LDPC_CODING_CAP, + nCfgValue); + pDot11f->ldpcCodingCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SHORT_GI_80MHZ, + nCfgValue); + pDot11f->shortGI80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + nCfgValue); + pDot11f->shortGI160and80plus80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TXSTBC, nCfgValue); + pDot11f->txSTBC = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RXSTBC, nCfgValue); + pDot11f->rxSTBC = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, nCfgValue); + pDot11f->suBeamformeeCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, nCfgValue); + pDot11f->muBeamformeeCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SU_BEAMFORMER_CAP, + nCfgValue); + pDot11f->suBeamFormerCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + nCfgValue); + pDot11f->csnofBeamformerAntSup = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_TXOP_PS, + nCfgValue); + pDot11f->vhtTXOPPS = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + nCfgValue); + pDot11f->numSoundingDim = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_HTC_VHTC_CAP, + nCfgValue); + pDot11f->htcVHTCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_RX_ANT_PATTERN, + nCfgValue); + pDot11f->rxAntPattern = nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_TX_ANT_PATTERN, + nCfgValue); + pDot11f->txAntPattern = nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + nCfgValue); + pDot11f->maxAMPDULenExp = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_LINK_ADAPTATION_CAP, + nCfgValue); + pDot11f->vhtLinkAdaptCap = (nCfgValue & 0x0003); + + } + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MU_BEAMFORMER_CAP, nCfgValue); + pDot11f->muBeamformerCap = (nCfgValue & 0x0001); + + pDot11f->reserved1 = 0; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RX_MCS_MAP, nCfgValue); + pDot11f->rxMCSMap = (nCfgValue & 0x0000FFFF); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + nCfgValue); + pDot11f->rxHighSupDataRate = (nCfgValue & 0x00001FFF); + + pDot11f->reserved2 = 0; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TX_MCS_MAP, nCfgValue); + pDot11f->txMCSMap = (nCfgValue & 0x0000FFFF); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + nCfgValue); + pDot11f->txSupDataRate = (nCfgValue & 0x00001FFF); + + pDot11f->reserved3 = 0; + if (psessionEntry) { + if (psessionEntry->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 (!psessionEntry->ch_width && + !pMac->roam.configParam.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); + } + } else { + if (!psessionEntry->ch_width && + !pMac->roam.configParam.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(pMac, pDot11f); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_vht_operation(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEVHTOperation *pDot11f) +{ + QDF_STATUS nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + if (psessionEntry->ch_width > CH_WIDTH_40MHZ) { + pDot11f->chanWidth = 1; + pDot11f->chanCenterFreqSeg1 = + psessionEntry->ch_center_freq_seg0; + if (psessionEntry->ch_width == CH_WIDTH_80P80MHZ || + psessionEntry->ch_width == CH_WIDTH_160MHZ) + pDot11f->chanCenterFreqSeg2 = + psessionEntry->ch_center_freq_seg1; + else + pDot11f->chanCenterFreqSeg2 = 0; + } else { + pDot11f->chanWidth = 0; + pDot11f->chanCenterFreqSeg1 = 0; + pDot11f->chanCenterFreqSeg2 = 0; + } + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_BASIC_MCS_SET, nCfgValue); + pDot11f->basicMCSSet = (uint16_t) nCfgValue; + + lim_log_vht_operation(pMac, pDot11f); + + return QDF_STATUS_SUCCESS; + +} + +QDF_STATUS +populate_dot11f_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f) +{ + QDF_STATUS nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + nCfgValue); + pDot11f->muMIMOCapStaCount = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SS_UNDER_UTIL, nCfgValue); + pDot11f->ssUnderUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_40MHZ_UTILIZATION, nCfgValue); + pDot11f->FortyMHzUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_80MHZ_UTILIZATION, nCfgValue); + pDot11f->EightyMHzUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_160MHZ_UTILIZATION, nCfgValue); + pDot11f->EightyMHzUtil = (uint8_t) nCfgValue; + + lim_log_vht_ext_bss_load(pMac, pDot11f); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_ext_cap(tpAniSirGlobal pMac, + bool isVHTEnabled, tDot11fIEExtCap *pDot11f, + tpPESession psessionEntry) +{ + uint32_t val = 0; + struct s_ext_cap *p_ext_cap; + + pDot11f->present = 1; + + if (!psessionEntry) { + pe_debug("11MC - enabled for non-SAP cases"); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else if (psessionEntry->sap_dot11mc) { + pe_debug("11MC support enabled"); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else { + if (eLIM_AP_ROLE != psessionEntry->limSystemRole) { + pe_debug("11MC support enabled"); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else { + pe_debug("11MC support disabled"); + 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 (wlan_cfg_get_int(pMac, WNI_CFG_RTT3_ENABLE, &val) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve RTT3 Variable from DAT File"); + return QDF_STATUS_E_FAILURE; + } + + if (val) { + uint32_t ftm = ucfg_wifi_pos_get_ftm_cap(pMac->psoc); + if (!psessionEntry || LIM_IS_STA_ROLE(psessionEntry)) { + 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(psessionEntry)) { + 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 (pMac->roam.configParam.obssEnabled) + p_ext_cap->bss_coexist_mgmt_support = 1; +#endif + p_ext_cap->ext_chan_switch = 1; + + if (psessionEntry && psessionEntry->enable_bcast_probe_rsp) + p_ext_cap->fils_capability = 1; + + if (pMac->roam.configParam.btm_offload_config & BTM_OFFLOAD_ENABLED_MASK) + p_ext_cap->bss_transition = 1; + + if (pDot11f->present) + pDot11f->num_bytes = lim_compute_ext_cap_ie_length(pDot11f); + + return QDF_STATUS_SUCCESS; +} + +void populate_dot11f_qcn_ie(tDot11fIEQCN_IE *pDot11f) +{ + pDot11f->present = 1; + pDot11f->version[0] = QCN_IE_VERSION_SUBATTR_ID; + pDot11f->version[1] = QCN_IE_VERSION_SUBATTR_DATA_LEN; + pDot11f->version[2] = QCN_IE_VERSION_SUPPORTED; + pDot11f->version[3] = QCN_IE_SUBVERSION_SUPPORTED; +} + +QDF_STATUS +populate_dot11f_operating_mode(tpAniSirGlobal pMac, + tDot11fIEOperatingMode *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->present = 1; + + pDot11f->chanWidth = psessionEntry->gLimOperatingMode.chanWidth; + pDot11f->rxNSS = psessionEntry->gLimOperatingMode.rxNSS; + pDot11f->rxNSSType = psessionEntry->gLimOperatingMode.rxNSSType; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pDot11f, tpPESession psessionEntry) +{ + uint32_t nCfgValue, nCfgLen; + uint8_t htInfoField1; + uint16_t htInfoField2; + QDF_STATUS nSirStatus; + tSirMacHTInfoField1 *pHTInfoField1; + tSirMacHTInfoField2 *pHTInfoField2; + union { + uint16_t nCfgValue16; + tSirMacHTInfoField3 infoField3; + } uHTInfoField; + union { + uint16_t nCfgValue16; + tSirMacHTInfoField2 infoField2; + } uHTInfoField2 = { + 0 + }; + + if (NULL == psessionEntry) { + pe_err("Invalid session entry in populate_dot11f_ht_info()"); + return QDF_STATUS_E_FAILURE; + } + + pDot11f->primaryChannel = psessionEntry->currentOperChannel; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD1, nCfgValue); + + htInfoField1 = (uint8_t) nCfgValue; + + pHTInfoField1 = (tSirMacHTInfoField1 *) &htInfoField1; + pHTInfoField1->rifsMode = psessionEntry->beaconParams.fRIFSMode; + pHTInfoField1->serviceIntervalGranularity = + pMac->lim.gHTServiceIntervalGranularity; + + pHTInfoField1->secondaryChannelOffset = + psessionEntry->htSecondaryChannelOffset; + pHTInfoField1->recommendedTxWidthSet = + psessionEntry->htRecommendedTxWidthSet; + + if ((psessionEntry) && LIM_IS_AP_ROLE(psessionEntry)) { + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD2, + nCfgValue); + + uHTInfoField2.nCfgValue16 = nCfgValue & 0xFFFF; /* this is added for fixing CRs on MDM9K platform - 257951, 259577 */ + + uHTInfoField2.infoField2.opMode = psessionEntry->htOperMode; + uHTInfoField2.infoField2.nonGFDevicesPresent = + psessionEntry->beaconParams.llnNonGFCoexist; + uHTInfoField2.infoField2.obssNonHTStaPresent = psessionEntry->beaconParams.gHTObssMode; /*added for Obss */ + + uHTInfoField2.infoField2.reserved = 0; + + } else { + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD2, + nCfgValue); + + htInfoField2 = (uint16_t) nCfgValue; + + pHTInfoField2 = (tSirMacHTInfoField2 *) &htInfoField2; + pHTInfoField2->opMode = pMac->lim.gHTOperMode; + pHTInfoField2->nonGFDevicesPresent = + pMac->lim.gHTNonGFDevicesPresent; + pHTInfoField2->obssNonHTStaPresent = pMac->lim.gHTObssMode; /*added for Obss */ + + pHTInfoField2->reserved = 0; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD3, nCfgValue); + + uHTInfoField.nCfgValue16 = nCfgValue & 0xFFFF; + + uHTInfoField.infoField3.basicSTBCMCS = pMac->lim.gHTSTBCBasicMCS; + uHTInfoField.infoField3.dualCTSProtection = + pMac->lim.gHTDualCTSProtection; + uHTInfoField.infoField3.secondaryBeacon = pMac->lim.gHTSecondaryBeacon; + uHTInfoField.infoField3.lsigTXOPProtectionFullSupport = + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport; + uHTInfoField.infoField3.pcoActive = pMac->lim.gHTPCOActive; + uHTInfoField.infoField3.pcoPhase = pMac->lim.gHTPCOPhase; + uHTInfoField.infoField3.reserved = 0; + + pDot11f->secondaryChannelOffset = pHTInfoField1->secondaryChannelOffset; + pDot11f->recommendedTxWidthSet = pHTInfoField1->recommendedTxWidthSet; + pDot11f->rifsMode = pHTInfoField1->rifsMode; + pDot11f->controlledAccessOnly = pHTInfoField1->controlledAccessOnly; + pDot11f->serviceIntervalGranularity = + pHTInfoField1->serviceIntervalGranularity; + + pDot11f->opMode = uHTInfoField2.infoField2.opMode; + pDot11f->nonGFDevicesPresent = + uHTInfoField2.infoField2.nonGFDevicesPresent; + pDot11f->obssNonHTStaPresent = + uHTInfoField2.infoField2.obssNonHTStaPresent; + pDot11f->reserved = uHTInfoField2.infoField2.reserved; + + pDot11f->basicSTBCMCS = uHTInfoField.infoField3.basicSTBCMCS; + pDot11f->dualCTSProtection = uHTInfoField.infoField3.dualCTSProtection; + pDot11f->secondaryBeacon = uHTInfoField.infoField3.secondaryBeacon; + pDot11f->lsigTXOPProtectionFullSupport = + uHTInfoField.infoField3.lsigTXOPProtectionFullSupport; + pDot11f->pcoActive = uHTInfoField.infoField3.pcoActive; + pDot11f->pcoPhase = uHTInfoField.infoField3.pcoPhase; + pDot11f->reserved2 = uHTInfoField.infoField3.reserved; + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_BASIC_MCS_SET, + pDot11f->basicMCSSet, nCfgLen, SIZE_OF_BASIC_MCS_SET); + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_ht_info. */ + +void +populate_dot11f_ibss_params(tpAniSirGlobal pMac, + tDot11fIEIBSSParams *pDot11f, + tpPESession psessionEntry) +{ + uint32_t val = 0; + + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + &val) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve IBSS ATIM WIN size"); + } + pDot11f->present = 1; + /* ATIM duration is always set to 0 */ + pDot11f->atim = val; + } + +} /* End populate_dot11f_ibss_params. */ + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +populate_dot11f_measurement_report0(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, tpPESession psessionEntry) +{ + if (nAssocType == LIM_REASSOC) { + pCaps->minTxPower = + psessionEntry->pLimReAssocReq->powerCap.minTxPower; + pCaps->maxTxPower = + psessionEntry->pLimReAssocReq->powerCap.maxTxPower; + } else { + pCaps->minTxPower = + psessionEntry->pLimJoinReq->powerCap.minTxPower; + pCaps->maxTxPower = + psessionEntry->pLimJoinReq->powerCap.maxTxPower; + + } + + pCaps->present = 1; +} /* End populate_dot11f_power_caps. */ + +QDF_STATUS +populate_dot11f_power_constraints(tpAniSirGlobal pMac, + tDot11fIEPowerConstraints *pDot11f) +{ + uint32_t cfg; + QDF_STATUS nSirStatus; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, cfg); + + pDot11f->localPowerConstraints = (uint8_t) cfg; + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_power_constraints. */ + +void +populate_dot11f_qos_caps_ap(tpAniSirGlobal pMac, + tDot11fIEQOSCapsAp *pDot11f, tpPESession psessionEntry) +{ + pDot11f->count = psessionEntry->gLimEdcaParamSetCount; + pDot11f->reserved = 0; + pDot11f->txopreq = 0; + pDot11f->qreq = 0; + pDot11f->qack = 0; + pDot11f->present = 1; +} /* End PopulatedDot11fQOSCaps. */ + +void +populate_dot11f_qos_caps_station(tpAniSirGlobal pMac, tpPESession pe_session, + tDot11fIEQOSCapsStation *pDot11f) +{ + uint32_t val = 0; + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve Max SP Length"); + + pDot11f->more_data_ack = 0; + pDot11f->max_sp_length = (uint8_t) val; + pDot11f->qack = 0; + + if (pMac->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(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_RSN); + if (0 <= idx) { + status = dot11f_unpack_ie_rsn(pMac, 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("dot11f_unpack_ie_rsn returned 0x%08x in populate_dot11f_rsn", + status); + } + + } + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_rsn. */ + +QDF_STATUS populate_dot11f_rsn_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIERSNOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, 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(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WAPI); + if (0 <= idx) { + status = dot11f_unpack_ie_wapi(pMac, pRsnIe->rsnIEdata + idx + 2, /* EID, length */ + pRsnIe->rsnIEdata[idx + 1], + pDot11f, false); + if (DOT11F_FAILED(status)) { + pe_err("Parse failure in populate_dot11f_wapi (0x%08x)", + status); + return QDF_STATUS_E_FAILURE; + } + pe_debug("dot11f_unpack_ie_rsn returned 0x%08x in populate_dot11f_wapi", + status); + } + } + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_wapi. */ + +QDF_STATUS populate_dot11f_wapi_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, tDot11fIESSID *pDot11f) +{ + uint32_t nCfg; + QDF_STATUS nSirStatus; + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SSID, pDot11f->ssid, nCfg, 32); + pDot11f->num_ssid = (uint8_t) nCfg; + 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(tpAniSirGlobal pMac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, tpPESession psessionEntry) +{ + uint8_t i; + uint8_t *p; + + if (nAssocType == LIM_REASSOC) { + p = (uint8_t *) psessionEntry->pLimReAssocReq-> + supportedChannels.channelList; + pDot11f->num_bands = + psessionEntry->pLimReAssocReq->supportedChannels.numChnl; + } else { + p = (uint8_t *) psessionEntry->pLimJoinReq->supportedChannels. + channelList; + pDot11f->num_bands = + psessionEntry->pLimJoinReq->supportedChannels.numChnl; + } + for (i = 0U; i < pDot11f->num_bands; ++i, ++p) { + pDot11f->bands[i][0] = *p; + pDot11f->bands[i][1] = 1; + } + + pDot11f->present = 1; + +} /* End populate_dot11f_supp_channels. */ + +QDF_STATUS +populate_dot11f_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, tpPESession psessionEntry) +{ + QDF_STATUS nSirStatus; + uint32_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 0 + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_OPERATIONAL_RATE_SET, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); +#endif /* TO SUPPORT BT-AMP */ + if (psessionEntry != NULL) { + nRates = psessionEntry->rateSet.numRates; + qdf_mem_copy(rates, psessionEntry->rateSet.rate, + nRates); + } else { + pe_err("no session context exists while populating Operational Rate Set"); + nRates = 0; + } + } else if (14 >= nChannelNum) { + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11B, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + } else { + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + } + + 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 gloabl - header. + * @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(tpAniSirGlobal p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates, + uint8_t curr_oper_channel) +{ + tSirMacRateSet temp_rateset; + tSirMacRateSet temp_rateset2; + uint32_t val, i; + uint32_t self_dot11mode = 0; + + wlan_cfg_get_int(p_mac, WNI_CFG_DOT11_MODE, &self_dot11mode); + + /** + * 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 == WNI_CFG_DOT11_MODE_ALL) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11A) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11N) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11G) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11B))) { + val = WNI_CFG_SUPPORTED_RATES_11B_LEN; + wlan_cfg_get_str(p_mac, WNI_CFG_SUPPORTED_RATES_11B, + (uint8_t *)&temp_rateset.rate, &val); + temp_rateset.numRates = (uint8_t) val; + } else { + temp_rateset.numRates = 0; + } + + /* Include 11a rates when the device configured in non-11b mode */ + if (!IS_DOT11_MODE_11B(self_dot11mode)) { + val = WNI_CFG_SUPPORTED_RATES_11A_LEN; + wlan_cfg_get_str(p_mac, WNI_CFG_SUPPORTED_RATES_11A, + (uint8_t *)&temp_rateset2.rate, &val); + temp_rateset2.numRates = (uint8_t) val; + } 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(tpAniSirGlobal pMac, + tDot11fIETPCReport *pDot11f, tpPESession psessionEntry) +{ + uint16_t staid; + uint8_t tx_power; + QDF_STATUS nSirStatus; + + nSirStatus = lim_get_mgmt_staid(pMac, &staid, psessionEntry); + 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; + } + /* FramesToDo: This function was "misplaced" in the move to Gen4_TVM... */ + /* txPower = halGetRateToPwrValue( pMac, staid, pMac->lim.gLimCurrentChannelId, isBeacon ); */ + tx_power = cfg_get_regulatory_max_transmit_power(pMac, + psessionEntry->currentOperChannel); + 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(tSirMacTSInfo *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(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, tpPESession psessionEntry) +{ + if (psessionEntry->limWmeEnabled) { + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + /* if ( ! sirIsPropCapabilityEnabled( pMac, SIR_MAC_PROP_CAPABILITY_WME ) ) */ + { + populate_dot11f_wmm_info_ap(pMac, pInfo, + psessionEntry); + } + } else { + { + populate_dot11f_wmm_params(pMac, pParams, + psessionEntry); + } + + if (psessionEntry->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 +void populate_dot11f_re_assoc_tspec(tpAniSirGlobal pMac, + tDot11fReAssocRequest *pReassoc, + tpPESession psessionEntry) +{ + uint8_t numTspecs = 0, idx; + tTspecInfo *pTspec = NULL; + + numTspecs = psessionEntry->pLimReAssocReq->eseTspecInfo.numTspecs; + pTspec = &psessionEntry->pLimReAssocReq->eseTspecInfo.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++; + } + } +} + +void ese_populate_wmm_tspec(tSirMacTspecIE *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(tpAniSirGlobal pMac, tDot11fIEWMMInfoAp *pInfo, + tpPESession psessionEntry) +{ + pInfo->version = SIR_MAC_OUI_VERSION_1; + + /* WMM Specification 3.1.3, 3.2.3 + * An IBSS station shall always use its default WMM parameters. + */ + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + pInfo->param_set_count = 0; + pInfo->uapsd = 0; + } else { + pInfo->param_set_count = + (0xf & psessionEntry->gLimEdcaParamSetCount); + if (LIM_IS_AP_ROLE(psessionEntry)) { + pInfo->uapsd = (0x1 & psessionEntry->apUapsdEnable); + } else + pInfo->uapsd = (0x1 & pMac->lim.gUapsdEnable); + } + pInfo->present = 1; +} + +void populate_dot11f_wmm_info_station_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEWMMInfoStation *pInfo) +{ + uint32_t val = 0; + + pInfo->version = SIR_MAC_OUI_VERSION_1; + pInfo->acvo_uapsd = + LIM_UAPSD_GET(ACVO, psessionEntry->gUapsdPerAcBitmask); + pInfo->acvi_uapsd = + LIM_UAPSD_GET(ACVI, psessionEntry->gUapsdPerAcBitmask); + pInfo->acbk_uapsd = + LIM_UAPSD_GET(ACBK, psessionEntry->gUapsdPerAcBitmask); + pInfo->acbe_uapsd = + LIM_UAPSD_GET(ACBE, psessionEntry->gUapsdPerAcBitmask); + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve Max SP Length"); + + pInfo->max_sp_length = (uint8_t) val; + pInfo->present = 1; +} + +void populate_dot11f_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pParams, + tpPESession psessionEntry) +{ + pParams->version = SIR_MAC_OUI_VERSION_1; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->qosInfo = + (psessionEntry-> + apUapsdEnable << 7) | ((uint8_t) (0x0f & psessionEntry-> + gLimEdcaParamSetCount)); + else + pParams->qosInfo = + (pMac->lim. + gUapsdEnable << 7) | ((uint8_t) (0x0f & psessionEntry-> + gLimEdcaParamSetCount)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pParams->acbe_aifsn = + (0xf & SET_AIFSN(psessionEntry->gLimEdcaParamsBC[0].aci.aifsn)); + pParams->acbe_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[0].aci.acm); + pParams->acbe_aci = (0x3 & SIR_MAC_EDCAACI_BESTEFFORT); + pParams->acbe_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.min); + pParams->acbe_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.max); + pParams->acbe_txoplimit = psessionEntry->gLimEdcaParamsBC[0].txoplimit; + + pParams->acbk_aifsn = + (0xf & SET_AIFSN(psessionEntry->gLimEdcaParamsBC[1].aci.aifsn)); + pParams->acbk_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[1].aci.acm); + pParams->acbk_aci = (0x3 & SIR_MAC_EDCAACI_BACKGROUND); + pParams->acbk_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.min); + pParams->acbk_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.max); + pParams->acbk_txoplimit = psessionEntry->gLimEdcaParamsBC[1].txoplimit; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->acvi_aifsn = + (0xf & psessionEntry->gLimEdcaParamsBC[2].aci.aifsn); + else + pParams->acvi_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[2].aci.aifsn)); + + pParams->acvi_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[2].aci.acm); + pParams->acvi_aci = (0x3 & SIR_MAC_EDCAACI_VIDEO); + pParams->acvi_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.min); + pParams->acvi_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.max); + pParams->acvi_txoplimit = psessionEntry->gLimEdcaParamsBC[2].txoplimit; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->acvo_aifsn = + (0xf & psessionEntry->gLimEdcaParamsBC[3].aci.aifsn); + else + pParams->acvo_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[3].aci.aifsn)); + + pParams->acvo_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[3].aci.acm); + pParams->acvo_aci = (0x3 & SIR_MAC_EDCAACI_VOICE); + pParams->acvo_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.min); + pParams->acvo_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.max); + pParams->acvo_txoplimit = psessionEntry->gLimEdcaParamsBC[3].txoplimit; + + pParams->present = 1; + +} /* End populate_dot11f_wmm_params. */ + +void populate_dot11f_wmm_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIEWMMSchedule *pDot11f) +{ + pDot11f->version = 1; + 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_wmm_schedule. */ + +QDF_STATUS +populate_dot11f_wpa(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WPA); + if (0 <= idx) { + status = dot11f_unpack_ie_wpa(pMac, 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(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWPAOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, 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(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirProbeReq pProbeReq) +{ + uint32_t status; + tDot11fProbeRequest pr; + + /* 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(pMac, 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); + 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(pMac, &pProbeReq->ssId, &pr.SSID); + } + + if (!pr.SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + return QDF_STATUS_E_FAILURE; + } else { + pProbeReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pProbeReq->supportedRates, + &pr.SuppRates); + } + + if (pr.ExtSuppRates.present) { + pProbeReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &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)); + pe_debug("11AX: HE cap IE present"); + } + 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(tpAniSirGlobal 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(tpAniSirGlobal 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.pbcc = caps.pbcc; + 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + tDot11fAssocRequest *frm, + tpPESession 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 +QDF_STATUS sir_convert_probe_frame2_struct(tpAniSirGlobal pMac, + 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 (NULL == pr) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_probe_response(pMac, 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(pMac, pr->Capabilities, pProbeResp); + + if (!pr->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + pProbeResp->ssidPresent = 1; + convert_ssid(pMac, &pProbeResp->ssId, &pr->SSID); + } + + if (!pr->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pProbeResp->suppRatesPresent = 1; + convert_supp_rates(pMac, &pProbeResp->supportedRates, + &pr->SuppRates); + } + + if (pr->ExtSuppRates.present) { + pProbeResp->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pProbeResp->extendedRates, + &pr->ExtSuppRates); + } + + if (pr->CFParams.present) { + pProbeResp->cfPresent = 1; + convert_cf_params(pMac, &pProbeResp->cfParamSet, &pr->CFParams); + } + + if (pr->Country.present) { + pProbeResp->countryInfoPresent = 1; + convert_country(pMac, &pProbeResp->countryInfoParam, + &pr->Country); + } + + if (pr->EDCAParamSet.present) { + pProbeResp->edcaPresent = 1; + convert_edca_param(pMac, &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->DSParams.present) { + pProbeResp->dsParamsPresent = 1; + pProbeResp->channelNumber = pr->DSParams.curr_channel; + } else if (pr->HTInfo.present) { + pProbeResp->channelNumber = pr->HTInfo.primaryChannel; + } + + if (pr->RSNOpaque.present) { + pProbeResp->rsnPresent = 1; + convert_rsn_opaque(pMac, &pProbeResp->rsn, &pr->RSNOpaque); + } + + if (pr->WPA.present) { + pProbeResp->wpaPresent = 1; + convert_wpa(pMac, &pProbeResp->wpa, &pr->WPA); + } + + if (pr->WMMParams.present) { + pProbeResp->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &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(pMac, &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) { + pProbeResp->QCN_IE.is_present = true; + + if (pr->QCN_IE.version[0] == QCN_IE_VERSION_SUBATTR_ID) { + pProbeResp->QCN_IE.version + = pr->QCN_IE.version[2]; + pProbeResp->QCN_IE.sub_version + = pr->QCN_IE.version[3]; + } + } + + if (pr->he_cap.present) { + pe_debug("11AX: HE cap IE present"); + qdf_mem_copy(&pProbeResp->he_cap, &pr->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (pr->he_op.present) { + pe_debug("11AX: HE operation IE present"); + qdf_mem_copy(&pProbeResp->he_op, &pr->he_op, + sizeof(tDot11fIEhe_op)); + } + + update_bss_color_change_ie_from_probe_rsp(pr, pProbeResp); + + qdf_mem_free(pr); + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_probe_frame2_struct. */ + +QDF_STATUS +sir_convert_assoc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + tDot11fAssocRequest *ar; + uint32_t status; + + ar = qdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (NULL == ar) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pAssocReq, sizeof(tSirAssocReq)); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_assoc_request(pMac, 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 QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking an Assoication 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.pbcc = ar->Capabilities.pbcc; + 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(pMac, &pAssocReq->ssId, &ar->SSID); + } + /* Supported Rates */ + if (ar->SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocReq->supportedRates, + &ar->SuppRates); + } + /* Extended Supported Rates */ + if (ar->ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocReq->extendedRates, + &ar->ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar->QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(pMac, &pAssocReq->qosCapability, + &ar->QOSCapsStation); + } + /* WPA */ + if (ar->WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(pMac, &pAssocReq->wpa, &ar->WPAOpaque); + } +#ifdef FEATURE_WLAN_WAPI + if (ar->WAPIOpaque.present) { + pAssocReq->wapiPresent = 1; + convert_wapi_opaque(pMac, &pAssocReq->wapi, &ar->WAPIOpaque); + } +#endif + /* RSN */ + if (ar->RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(pMac, &pAssocReq->rsn, &ar->RSNOpaque); + } + /* WSC IE */ + if (ar->WscIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wsc_opaque(pMac, &pAssocReq->addIE, &ar->WscIEOpaque); + } + + if (ar->P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(pMac, &pAssocReq->addIE, &ar->P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar->WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(pMac, &pAssocReq->addIE, &ar->WFDIEOpaque); + } +#endif + + /* Power Capabilities */ + if (ar->PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(pMac, &pAssocReq->powerCapability, + &ar->PowerCaps); + } + /* Supported Channels */ + if (ar->SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(pMac, &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 QDF_STATUS_E_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + pe_debug("Received Assoc without supp rate IE"); + qdf_mem_free(ar); + return QDF_STATUS_E_FAILURE; + } + if (ar->VHTCaps.present) { + qdf_mem_copy(&pAssocReq->VHTCaps, &ar->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + pe_debug("Received Assoc Req with VHT Cap"); + lim_log_vht_cap(pMac, &pAssocReq->VHTCaps); + } + if (ar->OperatingMode.present) { + qdf_mem_copy(&pAssocReq->operMode, &ar->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + pe_debug("Received Assoc Req with Operating Mode IE"); + lim_log_operating_mode(pMac, &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); + } + + 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)); + pe_debug("Received Assoc Request with Vendor specific VHT Cap"); + lim_log_vht_cap(pMac, &pAssocReq->VHTCaps); + } + } + if (ar->he_cap.present) { + qdf_mem_copy(&pAssocReq->he_cap, &ar->he_cap, + sizeof(tDot11fIEhe_cap)); + pe_debug("Received Assoc Req with HE Capability IE"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &pAssocReq->he_cap, sizeof(tDot11fIEhe_cap)); + } + qdf_mem_free(ar); + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_assoc_req_frame2_struct. */ + +/** + * 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 + */ +static QDF_STATUS dot11f_parse_assoc_response(tpAniSirGlobal 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 +sir_convert_assoc_resp_frame2_struct(tpAniSirGlobal pMac, + tpPESession session_entry, + uint8_t *pFrame, uint32_t nFrame, + tpSirAssocRsp pAssocRsp) +{ + tDot11fAssocResponse *ar; + uint32_t status; + uint8_t cnt = 0; + + ar = qdf_mem_malloc(sizeof(*ar)); + if (!ar) { + pe_err("Assoc rsp mem alloc fails"); + return QDF_STATUS_E_FAILURE; + } + + /* decrypt the cipher text using AEAD decryption */ + if (lim_is_fils_connection(session_entry)) { + status = aead_decrypt_assoc_rsp(pMac, session_entry, + ar, pFrame, &nFrame); + 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(pMac, pFrame, nFrame, 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.pbcc = ar->Capabilities.pbcc; + 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->statusCode = ar->Status.status; + pAssocRsp->aid = ar->AID.associd; +#ifdef WLAN_FEATURE_11W + if (ar->TimeoutInterval.present) { + pAssocRsp->TimeoutInterval.present = 1; + pAssocRsp->TimeoutInterval.timeoutType = + ar->TimeoutInterval.timeoutType; + pAssocRsp->TimeoutInterval.timeoutValue = + ar->TimeoutInterval.timeoutValue; + } +#endif + + if (!ar->SuppRates.present) { + pAssocRsp->suppRatesPresent = 0; + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pAssocRsp->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocRsp->supportedRates, + &ar->SuppRates); + } + + if (ar->ExtSuppRates.present) { + pAssocRsp->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocRsp->extendedRates, + &ar->ExtSuppRates); + } + + if (ar->EDCAParamSet.present) { + pAssocRsp->edcaPresent = 1; + convert_edca_param(pMac, &pAssocRsp->edca, &ar->EDCAParamSet); + } + if (ar->WMMParams.present) { + pAssocRsp->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pAssocRsp->edca, &ar->WMMParams); + pe_debug("Received Assoc Resp with WMM Param"); + __print_wmm_params(pMac, &ar->WMMParams); + } + + if (ar->HTCaps.present) { + pe_debug("Received Assoc Resp with HT Cap"); + qdf_mem_copy(&pAssocRsp->HTCaps, &ar->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar->HTInfo.present) { + pe_debug("Received Assoc Resp with HT Info"); + qdf_mem_copy(&pAssocRsp->HTInfo, &ar->HTInfo, + sizeof(tDot11fIEHTInfo)); + } + 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 (ar->FTInfo.present) { + pe_debug("FT Info present %d %d %d", + ar->FTInfo.R0KH_ID.num_PMK_R0_ID, + ar->FTInfo.R0KH_ID.present, 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(tSirMacESETSMIE)); + } +#endif + + if (ar->VHTCaps.present) { + qdf_mem_copy(&pAssocRsp->VHTCaps, &ar->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + pe_debug("Received Assoc Response with VHT Cap"); + lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps); + } + if (ar->VHTOperation.present) { + qdf_mem_copy(&pAssocRsp->VHTOperation, &ar->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + pe_debug("Received Assoc Response with VHT Operation"); + lim_log_vht_operation(pMac, &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->QosMapSet.present) { + pAssocRsp->QosMapSet.present = 1; + convert_qos_mapset_frame(pMac, &pAssocRsp->QosMapSet, + &ar->QosMapSet); + pe_debug("Received Assoc Response with Qos Map Set"); + lim_log_qos_map_set(pMac, &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)); + pe_debug("Received Assoc Response with Vendor specific VHT Cap"); + lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps); + } + if (ar->vendor_vht_ie.VHTOperation.present) { + qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTOperation, + &ar->vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + pe_debug("Received Assoc Response with Vendor specific VHT Oper"); + lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation); + } + + if (ar->he_cap.present) { + pe_debug("11AX: HE cap IE present"); + qdf_mem_copy(&pAssocRsp->he_cap, &ar->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (ar->he_op.present) { + pe_debug("11AX: HE Operation IE present"); + qdf_mem_copy(&pAssocRsp->he_op, &ar->he_op, + sizeof(tDot11fIEhe_op)); + pe_debug("bss_clr %d def_pe %d part_bss_clr %d bss_col_dis %d", + pAssocRsp->he_op.bss_color, + pAssocRsp->he_op.default_pe, + pAssocRsp->he_op.partial_bss_col, + pAssocRsp->he_op.bss_col_disabled); + } + + if (ar->mu_edca_param_set.present) { + pe_debug("11AX: HE MU EDCA param IE present"); + pAssocRsp->mu_edca_present = true; + convert_mu_edca_param(pMac, &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)); + pe_debug("Received Assoc Response with rssi based assoc rej"); + } + + fils_convert_assoc_rsp_frame2_struct(ar, pAssocRsp); + + qdf_mem_free(ar); + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_assoc_resp_frame2_struct. */ + +QDF_STATUS +sir_convert_reassoc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + static tDot11fReAssocRequest ar; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pAssocReq, sizeof(tSirAssocReq)); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_re_assoc_request(pMac, 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); + return QDF_STATUS_E_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.pbcc = ar.Capabilities.pbcc; + 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(pMac, &pAssocReq->ssId, &ar.SSID); + } + /* Supported Rates */ + if (ar.SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocReq->supportedRates, + &ar.SuppRates); + } + /* Extended Supported Rates */ + if (ar.ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocReq->extendedRates, + &ar.ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar.QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(pMac, &pAssocReq->qosCapability, + &ar.QOSCapsStation); + } + /* WPA */ + if (ar.WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(pMac, &pAssocReq->wpa, &ar.WPAOpaque); + } + /* RSN */ + if (ar.RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(pMac, &pAssocReq->rsn, &ar.RSNOpaque); + } + + /* Power Capabilities */ + if (ar.PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(pMac, &pAssocReq->powerCapability, + &ar.PowerCaps); + } + /* Supported Channels */ + if (ar.SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(pMac, &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"); + return QDF_STATUS_E_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + pe_debug("Received Assoc without supp rate IE"); + return QDF_STATUS_E_FAILURE; + } + /* 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(pMac, &pAssocReq->addIE, &ar.WscIEOpaque); + } + + if (ar.P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(pMac, &pAssocReq->addIE, &ar.P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar.WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(pMac, &pAssocReq->addIE, &ar.WFDIEOpaque); + } +#endif + + 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(pMac, &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)); + } + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_reassoc_req_frame2_struct. */ + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS +sir_beacon_ie_ese_bcn_report(tpAniSirGlobal pMac, + 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; + + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) &eseBcnReportMandatoryIe, + sizeof(eseBcnReportMandatoryIe)); + pBies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pBies) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(pMac, 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); + } + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'eseBcnReportMandatoryIe'... */ + if (!pBies->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + eseBcnReportMandatoryIe.ssidPresent = 1; + convert_ssid(pMac, &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(pMac, &eseBcnReportMandatoryIe.supportedRates, + &pBies->SuppRates); + numBytes += + 1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates; + } + + if (pBies->FHParamSet.present) { + eseBcnReportMandatoryIe.fhParamPresent = 1; + convert_fh_params(pMac, &eseBcnReportMandatoryIe.fhParamSet, + &pBies->FHParamSet); + numBytes += 1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX; + } + + if (pBies->DSParams.present) { + eseBcnReportMandatoryIe.dsParamsPresent = 1; + eseBcnReportMandatoryIe.dsParamSet.channelNumber = + pBies->DSParams.curr_channel; + numBytes += 1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX; + } + + if (pBies->CFParams.present) { + eseBcnReportMandatoryIe.cfPresent = 1; + convert_cf_params(pMac, &eseBcnReportMandatoryIe.cfParamSet, + &pBies->CFParams); + numBytes += 1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX; + } + + if (pBies->IBSSParams.present) { + eseBcnReportMandatoryIe.ibssParamPresent = 1; + eseBcnReportMandatoryIe.ibssParamSet.atim = + pBies->IBSSParams.atim; + numBytes += 1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX; + } + + 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 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX; + } + + *outIeBuf = qdf_mem_malloc(numBytes); + if (NULL == *outIeBuf) { + pe_err("Memory Allocation failure"); + 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 = SIR_MAC_SSID_EID; + 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 <= + SIR_MAC_RATESET_EID_MAX) { + *pos = SIR_MAC_RATESET_EID; + 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 + SIR_MAC_FH_PARAM_SET_EID_MAX)) { + pe_err("Insufficient memory to copy FHIE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_FH_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_FH_PARAM_SET_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.fhParamSet, + SIR_MAC_FH_PARAM_SET_EID_MAX); + pos += SIR_MAC_FH_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX); + } + + /* Fill DS Parameter set IE */ + if (eseBcnReportMandatoryIe.dsParamsPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX)) { + pe_err("Insufficient memory to copy DS IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_DS_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_DS_PARAM_SET_EID_MAX; + pos++; + *pos = eseBcnReportMandatoryIe.dsParamSet.channelNumber; + pos += SIR_MAC_DS_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX); + } + + /* Fill CF Parameter set */ + if (eseBcnReportMandatoryIe.cfPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX)) { + pe_err("Insufficient memory to copy CF IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_CF_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_CF_PARAM_SET_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.cfParamSet, + SIR_MAC_CF_PARAM_SET_EID_MAX); + pos += SIR_MAC_CF_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX); + } + + /* Fill IBSS Parameter set IE */ + if (eseBcnReportMandatoryIe.ibssParamPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX)) { + pe_err("Insufficient memory to copy IBSS IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_IBSS_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_IBSS_PARAM_SET_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.ibssParamSet. + atim, SIR_MAC_IBSS_PARAM_SET_EID_MAX); + pos += SIR_MAC_IBSS_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX); + } + + /* 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 = SIR_MAC_TIM_EID; + 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 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX)) { + pe_err("Insufficient memory to copy RRM IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_RM_ENABLED_CAPABILITY_EID; + pos++; + *pos = SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe. + rmEnabledCapabilities, + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX); + freeBytes -= (1 + 1 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX); + } + + 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(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t nPayload) +{ + tDot11fBeaconIEs *pBies; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon)); + + pBies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pBies) { + pe_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(pMac, 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("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):", + status, nPayload); + } + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'tSirProbeRespBeacon'... */ + if (!pBies->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + pBeaconStruct->ssidPresent = 1; + convert_ssid(pMac, &pBeaconStruct->ssId, &pBies->SSID); + } + + if (!pBies->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(pMac, &pBeaconStruct->supportedRates, + &pBies->SuppRates); + } + + if (pBies->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pBeaconStruct->extendedRates, + &pBies->ExtSuppRates); + } + + if (pBies->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(pMac, &pBeaconStruct->cfParamSet, + &pBies->CFParams); + } + + if (pBies->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(pMac, &pBeaconStruct->tim, &pBies->TIM); + } + + if (pBies->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(pMac, &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(pMac, &pBeaconStruct->edcaParams, + &pBies->EDCAParamSet); + } + /* QOS Capabilities: */ + if (pBies->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(pMac, &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->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->channelNumber = pBies->DSParams.curr_channel; + } else if (pBies->HTInfo.present) { + pBeaconStruct->channelNumber = pBies->HTInfo.primaryChannel; + } + + if (pBies->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(pMac, &pBeaconStruct->rsn, &pBies->RSN); + } + + if (pBies->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(pMac, &pBeaconStruct->wpa, &pBies->WPA); + } + + if (pBies->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pBeaconStruct->edcaParams, + &pBies->WMMParams); + } + + if (pBies->WMMInfoAp.present) { + pBeaconStruct->wmeInfoPresent = 1; + } + + if (pBies->WMMCaps.present) { + pBeaconStruct->wsmCapablePresent = 1; + } + + if (pBies->ERPInfo.present) { + pBeaconStruct->erpPresent = 1; + convert_erp_info(pMac, &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) { + pBeaconStruct->QCN_IE.is_present = true; + if (pBies->QCN_IE.version[0] == QCN_IE_VERSION_SUBATTR_ID) { + pBeaconStruct->QCN_IE.version + = pBies->QCN_IE.version[2]; + pBeaconStruct->QCN_IE.sub_version + = pBies->QCN_IE.version[3]; + } + } + + 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)); + } + + 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 + +QDF_STATUS +sir_convert_beacon_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + tpSirProbeRespBeacon pBeaconStruct) +{ + tDot11fBeacon *pBeacon; + uint32_t status, nPayload; + uint8_t *pPayload; + tpSirMacMgmtHdr pHdr; + uint8_t mappedRXCh; + + pPayload = WMA_GET_RX_MPDU_DATA(pFrame); + nPayload = WMA_GET_RX_PAYLOAD_LEN(pFrame); + pHdr = WMA_GET_RX_MAC_HEADER(pFrame); + mappedRXCh = WMA_GET_RX_CH(pFrame); + + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon)); + + pBeacon = qdf_mem_malloc(sizeof(tDot11fBeacon)); + if (NULL == pBeacon) { + pe_err("Failed to allocate memory"); + 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(pMac, 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; + } + /* & "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.pbcc = pBeacon->Capabilities.pbcc; + 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(pMac, &pBeaconStruct->ssId, &pBeacon->SSID); + } + + if (!pBeacon->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(pMac, &pBeaconStruct->supportedRates, + &pBeacon->SuppRates); + } + + if (pBeacon->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pBeaconStruct->extendedRates, + &pBeacon->ExtSuppRates); + } + + if (pBeacon->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(pMac, &pBeaconStruct->cfParamSet, + &pBeacon->CFParams); + } + + if (pBeacon->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(pMac, &pBeaconStruct->tim, &pBeacon->TIM); + } + + if (pBeacon->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(pMac, &pBeaconStruct->countryInfoParam, + &pBeacon->Country); + } + /* QOS Capabilities: */ + if (pBeacon->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(pMac, &pBeaconStruct->qosCapability, + &pBeacon->QOSCapsAp); + } + + if (pBeacon->EDCAParamSet.present) { + pBeaconStruct->edcaPresent = 1; + convert_edca_param(pMac, &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->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->channelNumber = pBeacon->DSParams.curr_channel; + } else if (pBeacon->HTInfo.present) { + pBeaconStruct->channelNumber = pBeacon->HTInfo.primaryChannel; + } else { + pBeaconStruct->channelNumber = mappedRXCh; + pe_debug_rl("In Beacon No Channel info"); + } + + if (pBeacon->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(pMac, &pBeaconStruct->rsn, &pBeacon->RSN); + } + + if (pBeacon->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(pMac, &pBeaconStruct->wpa, &pBeacon->WPA); + } + + if (pBeacon->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &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(pMac, &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)); + } + /* IBSS Peer Params */ + if (pBeacon->IBSSParams.present) { + pBeaconStruct->IBSSParams.present = 1; + qdf_mem_copy(&pBeaconStruct->IBSSParams, &pBeacon->IBSSParams, + sizeof(tDot11fIEIBSSParams)); + } + + 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) { + pBeaconStruct->QCN_IE.is_present = true; + if (pBeacon->QCN_IE.version[0] + == QCN_IE_VERSION_SUBATTR_ID) { + pBeaconStruct->QCN_IE.version + = pBeacon->QCN_IE.version[2]; + pBeaconStruct->QCN_IE.sub_version + = pBeacon->QCN_IE.version[3]; + } + } + + if (pBeacon->he_cap.present) { + pe_debug("11AX: HE cap IE present"); + qdf_mem_copy(&pBeaconStruct->he_cap, + &pBeacon->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (pBeacon->he_op.present) { + pe_debug("11AX: HE operation IE present"); + qdf_mem_copy(&pBeaconStruct->he_op, + &pBeacon->he_op, + sizeof(tDot11fIEhe_op)); + } + + convert_bcon_bss_color_change_ie(pBeacon, pBeaconStruct); + + qdf_mem_free(pBeacon); + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_beacon_frame2_struct. */ + +#ifdef WLAN_FEATURE_FILS_SK +/* 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; + } +} +#else +static void sir_update_auth_frame2_struct_fils_conf(tDot11fAuthentication *auth, + tpSirMacAuthFrameBody auth_frame) +{ } +#endif + +QDF_STATUS +sir_convert_auth_frame2_struct(tpAniSirGlobal pMac, + 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(pMac, 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 = SIR_MAC_CHALLENGE_TEXT_EID; + pAuth->length = auth.ChallengeText.num_text; + qdf_mem_copy(pAuth->challengeText, auth.ChallengeText.text, + auth.ChallengeText.num_text); + } + sir_update_auth_frame2_struct_fils_conf(&auth, pAuth); + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_auth_frame2_struct. */ + +QDF_STATUS +sir_convert_addts_req2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirAddtsReqInfo *pAddTs) +{ + tDot11fAddTSRequest addts = { {0} }; + tDot11fWMMAddTSRequest wmmaddts = { {0} }; + uint8_t j; + uint16_t i; + uint32_t status; + + if (SIR_MAC_QOS_ADD_TS_REQ != *(pFrame + 1)) { + pe_err("sir_convert_addts_req2_struct 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((uint8_t *) pAddTs, sizeof(tSirAddtsReqInfo)); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = dot11f_unpack_add_ts_request(pMac, pFrame, nFrame, + &addts, false); + break; + case SIR_MAC_ACTION_WME: + status = + dot11f_unpack_wmm_add_ts_request(pMac, pFrame, nFrame, + &wmmaddts, false); + break; + default: + pe_err("sir_convert_addts_req2_struct 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 Add 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 Add TS Request frame (0x%08x,%d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAddTSRequest' or a */ + /* 'tDot11WMMAddTSRequest' to a 'tSirMacAddtsReqInfo'... */ + if (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pAddTs->dialogToken = addts.DialogToken.token; + + if (addts.TSPEC.present) { + convert_tspec(pMac, &pAddTs->tspec, &addts.TSPEC); + } else { + pe_err("Mandatory TSPEC element missing in Add TS Request"); + 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(pMac, &(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; + } + + if (addts.WMMTSPEC.present) { + pAddTs->wsmTspecPresent = 1; + convert_wmmtspec(pMac, &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(pMac, + &(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; + + if (wmmaddts.WMMTSPEC.present) { + pAddTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, + &wmmaddts.WMMTSPEC); + } else { + pe_err("Mandatory WME TSPEC element missing!"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_addts_req2_struct. */ + +QDF_STATUS +sir_convert_addts_rsp2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirAddtsRspInfo *pAddTs) +{ + tDot11fAddTSResponse addts = { {0} }; + tDot11fWMMAddTSResponse wmmaddts = { {0} }; + uint8_t j; + uint16_t i; + uint32_t status; + + if (SIR_MAC_QOS_ADD_TS_RSP != *(pFrame + 1)) { + pe_err("sir_convert_addts_rsp2_struct 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((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 SIR_MAC_ACTION_QOS_MGMT: + status = + dot11f_unpack_add_ts_response(pMac, pFrame, nFrame, + &addts, false); + break; + case SIR_MAC_ACTION_WME: + status = + dot11f_unpack_wmm_add_ts_response(pMac, pFrame, nFrame, + &wmmaddts, false); + break; + default: + pe_err("sir_convert_addts_rsp2_struct 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 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 (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pAddTs->dialogToken = addts.DialogToken.token; + pAddTs->status = (tSirMacStatusCodes) addts.Status.status; + + if (addts.TSDelay.present) { + convert_ts_delay(pMac, &pAddTs->delay, &addts.TSDelay); + } + /* TS Delay is present iff status indicates its presence */ + if (eSIR_MAC_TS_NOT_CREATED_STATUS == pAddTs->status + && !addts.TSDelay.present) { + pe_warn("Missing TSDelay IE"); + } + + if (addts.TSPEC.present) { + convert_tspec(pMac, &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(pMac, &(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(tSirMacESETSMIE)); + } +#endif + if (addts.Schedule.present) { + pAddTs->schedulePresent = 1; + convert_schedule(pMac, &pAddTs->schedule, + &addts.Schedule); + } + + if (addts.WMMSchedule.present) { + pAddTs->schedulePresent = 1; + convert_wmm_schedule(pMac, &pAddTs->schedule, + &addts.WMMSchedule); + } + + if (addts.WMMTSPEC.present) { + pAddTs->wsmTspecPresent = 1; + convert_wmmtspec(pMac, &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(pMac, + &(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 = + (tSirMacStatusCodes) wmmaddts.StatusCode.statusCode; + + if (wmmaddts.WMMTSPEC.present) { + pAddTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &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(tSirMacESETSMIE)); + } +#endif + + } + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_addts_rsp2_struct. */ + +QDF_STATUS +sir_convert_delts_req2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirDeltsReqInfo *pDelTs) +{ + tDot11fDelTS delts = { {0} }; + tDot11fWMMDelTS wmmdelts = { {0} }; + uint32_t status; + + if (SIR_MAC_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((uint8_t *) pDelTs, sizeof(tSirDeltsReqInfo)); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = dot11f_unpack_del_ts(pMac, pFrame, nFrame, + &delts, false); + break; + case SIR_MAC_ACTION_WME: + status = dot11f_unpack_wmm_del_ts(pMac, 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 (SIR_MAC_ACTION_QOS_MGMT == *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(pMac, &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(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, + tSirQosMapSet *pQosMapSet) +{ + tDot11fQosMapConfigure mapConfigure; + uint32_t status; + + status = + dot11f_unpack_qos_map_configure(pMac, 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(pMac, pQosMapSet, &mapConfigure.QosMapSet); + lim_log_qos_map_set(pMac, pQosMapSet); + return QDF_STATUS_SUCCESS; +} + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +sir_convert_tpc_req_frame2_struct(tpAniSirGlobal pMac, + 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(pMac, 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 inalid 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(tpAniSirGlobal pMac, + 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(pMac, 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(tSirMacTspecIE *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. */ + +void populate_dot11f_wmmtspec(tSirMacTspecIE *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(tpAniSirGlobal pMac, + tpSirCCKMie pCCKMie, + tDot11fIEESECckmOpaque *pDot11f) +{ + int idx; + + if (pCCKMie->length) { + idx = find_ie_location(pMac, (tpSirRSNie) pCCKMie, + DOT11F_EID_ESECCKMOPAQUE); + if (0 <= idx) { + pDot11f->present = 1; + /* Dont include OUI */ + pDot11f->num_data = pCCKMie->cckmIEdata[idx + 1] - 4; + qdf_mem_copy(pDot11f->data, pCCKMie->cckmIEdata + idx + 2 + 4, /* EID,len,OUI */ + pCCKMie->cckmIEdata[idx + 1] - 4); /* Skip OUI */ + } + } + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_ese_cckm_opaque. */ + +void populate_dot11_tsrsie(tpAniSirGlobal pMac, + tSirMacESETSRSIE *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(tpAniSirGlobal pMac, + 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 in populate_dot11f_tclas", + pDot11f->classifier_type); + return QDF_STATUS_E_FAILURE; + } + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_tclas. */ + +QDF_STATUS +populate_dot11f_wmmtclas(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + + uint32_t wpsState; + + pDot11f->Version.present = 1; + pDot11f->Version.major = 0x01; + pDot11f->Version.minor = 0x00; + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_STATE, &wpsState) != + QDF_STATUS_SUCCESS) + pe_err("Failed to cfg get id %d", WNI_CFG_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(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(pMac->lim.wscIeInfo); + uint32_t devicepasswdId; + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + if (wlan_cfg_get_int + (pMac, (uint16_t) WNI_CFG_WPS_DEVICE_PASSWORD_ID, + &devicepasswdId) != QDF_STATUS_SUCCESS) + pe_err("Failed to cfg get id %d", + WNI_CFG_WPS_DEVICE_PASSWORD_ID); + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = (uint16_t) devicepasswdId; + + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f, + tpPESession psessionEntry) +{ + + tSirWPSProbeRspIE *pSirWPSProbeRspIE; + + pSirWPSProbeRspIE = &psessionEntry->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_assoc_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpPESession psessionEntry) +{ + tSirWPSProbeRspIE *pSirWPSProbeRspIE; + + pSirWPSProbeRspIE = &psessionEntry->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_RESPONSETYPE_PRESENT) { + pDot11f->ResponseType.present = 1; + pDot11f->ResponseType.resType = pSirWPSProbeRspIE->ResponseType; + } else + pDot11f->ResponseType.present = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_beacon_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f, + tpPESession psessionEntry) +{ + + tSirWPSBeaconIE *pSirWPSBeaconIE; + + pSirWPSBeaconIE = &psessionEntry->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(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f) +{ + uint32_t cfgMethods; + uint32_t cfgStrLen; + uint32_t val; + uint32_t wpsVersion, wpsState; + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_VERSION, &wpsVersion) != + QDF_STATUS_SUCCESS) + pe_err("Failed to cfg get id %d", WNI_CFG_WPS_VERSION); + + pDot11f->Version.present = 1; + pDot11f->Version.major = (uint8_t) ((wpsVersion & 0xF0) >> 4); + pDot11f->Version.minor = (uint8_t) (wpsVersion & 0x0F); + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_STATE, &wpsState) != + QDF_STATUS_SUCCESS) + pe_err("Failed to cfg get id %d", WNI_CFG_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 ((pMac->lim.wscIeInfo.reqType == REQ_TYPE_REGISTRAR) || + (pMac->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. Still use wlan_cfg_get_str to get it. */ + pDot11f->UUID_E.present = 1; + cfgStrLen = WNI_CFG_WPS_UUID_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_WPS_UUID, + pDot11f->UUID_E.uuid, &cfgStrLen) != QDF_STATUS_SUCCESS) { + *(pDot11f->UUID_E.uuid) = '\0'; + } + + pDot11f->Manufacturer.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_NAME, + 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 = WNI_CFG_MODEL_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MODEL_NAME, + 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 = WNI_CFG_MODEL_NUMBER_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MODEL_NUMBER, + 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 = WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + 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; + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get prim device category failed"); + } else + pDot11f->PrimaryDeviceType.primary_category = (uint16_t) val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_PIMARY_DEVICE_OUI, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get prim device OUI failed"); + } else { + *(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)); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_DEVICE_SUB_CATEGORY, &val) != + QDF_STATUS_SUCCESS) { + pe_err("cfg get prim device sub category failed"); + } else + pDot11f->PrimaryDeviceType.sub_category = (uint16_t) val; + + pDot11f->DeviceName.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_PRODUCT_NAME, + pDot11f->DeviceName.text, + &cfgStrLen) != QDF_STATUS_SUCCESS) { + pDot11f->DeviceName.num_text = 0; + } else { + pDot11f->DeviceName.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + if (wlan_cfg_get_int(pMac, + WNI_CFG_WPS_CFG_METHOD, + &cfgMethods) != QDF_STATUS_SUCCESS) { + pDot11f->ConfigMethods.present = 0; + pDot11f->ConfigMethods.methods = 0; + } else { + pDot11f->ConfigMethods.present = 1; + pDot11f->ConfigMethods.methods = + (uint16_t) (cfgMethods & 0x0000FFFF); + } + + pDot11f->RFBands.present = 0; + + pDot11f->present = 1; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(pMac->lim.wscIeInfo); + uint32_t devicepasswdId; + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + if (wlan_cfg_get_int + (pMac, (uint16_t) WNI_CFG_WPS_DEVICE_PASSWORD_ID, + &devicepasswdId) != QDF_STATUS_SUCCESS) + pe_err("Failed to cfg get id %d", + WNI_CFG_WPS_DEVICE_PASSWORD_ID); + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = (uint16_t) devicepasswdId; + + 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(tpAniSirGlobal pMac, + 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_dot11f_assoc_res_wsc_ie(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq) +{ + uint32_t ret; + const uint8_t *wscIe; + tDot11fIEWscAssocReq parsedWscAssocReq = { 0, }; + + wscIe = limGetWscIEPtr(pMac, pRcvdAssocReq->addIE.addIEdata, + pRcvdAssocReq->addIE.length); + if (wscIe != NULL) { + /* retrieve WSC IE from given AssocReq */ + ret = dot11f_unpack_ie_wsc_assoc_req(pMac, + /* EID, length, OUI */ + (uint8_t *)wscIe + 2 + 4, + /* length without OUI */ + wscIe[1] - 4, + &parsedWscAssocReq, false); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("unpack failed, ret: %d", ret); + return QDF_STATUS_E_INVAL; + } + + pDot11f->present = 1; + /* version has to be 0x10 */ + pDot11f->Version.present = 1; + pDot11f->Version.major = 0x1; + pDot11f->Version.minor = 0x0; + + pDot11f->ResponseType.present = 1; + + if ((parsedWscAssocReq.RequestType.reqType == + REQ_TYPE_REGISTRAR) + || (parsedWscAssocReq.RequestType.reqType == + REQ_TYPE_WLAN_MANAGER_REGISTRAR)) { + pDot11f->ResponseType.resType = + RESP_TYPE_ENROLLEE_OPEN_8021X; + } else { + pDot11f->ResponseType.resType = RESP_TYPE_AP; + } + /* Version infomration should be taken from our capability as well as peers */ + /* TODO: currently it takes from peers only */ + if (parsedWscAssocReq.VendorExtension.present && + parsedWscAssocReq.VendorExtension.Version2.present) { + pDot11f->VendorExtension.present = 1; + pDot11f->VendorExtension.vendorId[0] = 0x00; + pDot11f->VendorExtension.vendorId[1] = 0x37; + pDot11f->VendorExtension.vendorId[2] = 0x2A; + pDot11f->VendorExtension.Version2.present = 1; + pDot11f->VendorExtension.Version2.major = + parsedWscAssocReq.VendorExtension.Version2.major; + pDot11f->VendorExtension.Version2.minor = + parsedWscAssocReq.VendorExtension.Version2.minor; + } + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11_assoc_res_p2p_ie(tpAniSirGlobal pMac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq) +{ + const uint8_t *p2pIe; + + p2pIe = limGetP2pIEPtr(pMac, pRcvdAssocReq->addIE.addIEdata, + pRcvdAssocReq->addIE.length); + if (p2pIe != NULL) { + 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(tpAniSirGlobal pMac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin) +{ + pDot11f->txPower = txPower; + pDot11f->linkMargin = linkMargin; + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_beacon_report(tpAniSirGlobal pMac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport, + struct rrm_beacon_report_last_beacon_params + *last_beacon_report_params) +{ + + 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 (last_beacon_report_params && + last_beacon_report_params->last_beacon_ind) { + pe_debug("Including Last Beacon Report in RRM Frame, report_id %d, frag_id %d", + last_beacon_report_params->report_id, + last_beacon_report_params->frag_id); + pDot11f->report.Beacon.beacon_report_frm_body_fragment_id. + present = 1; + pDot11f->report.Beacon.beacon_report_frm_body_fragment_id. + beacon_report_id = last_beacon_report_params->report_id; + pDot11f->report.Beacon.beacon_report_frm_body_fragment_id. + fragment_id_number = last_beacon_report_params->frag_id; + + pDot11f->report.Beacon.last_beacon_report_indication.present = 1; + + if (last_beacon_report_params->frag_id == + (last_beacon_report_params->num_frags - 1)) { + pDot11f->report.Beacon. + beacon_report_frm_body_fragment_id. + more_fragments = 0; + pDot11f->report.Beacon.last_beacon_report_indication. + last_fragment = 1; + pe_debug("Last Fragment"); + } else { + pDot11f->report.Beacon. + beacon_report_frm_body_fragment_id. + more_fragments = 1; + pDot11f->report.Beacon.last_beacon_report_indication. + last_fragment = 0; + } + } + return QDF_STATUS_SUCCESS; + +} + +QDF_STATUS populate_dot11f_rrm_ie(tpAniSirGlobal pMac, + tDot11fIERRMEnabledCap *pDot11f, + tpPESession psessionEntry) +{ + tpRRMCaps pRrmCaps; + uint8_t *bytes; + + pRrmCaps = rrm_get_capabilities(pMac, psessionEntry); + + 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(tpAniSirGlobal pMac, + tDot11fIEMobilityDomain *pDot11f, + uint8_t mdie[SIR_MDIE_SIZE]) +{ + 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); + +} + +void populate_ft_info(tpAniSirGlobal pMac, tDot11fIEFTInfo *pDot11f) +{ + pDot11f->present = 1; + pDot11f->IECount = 0; /* TODO: put valid data during reassoc. */ + /* All other info is zero. */ + +} + +void populate_dot11f_assoc_rsp_rates(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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 + * @pMac: the MAC context + * @frame: pointer to the TA frame + * + * Return: The SIR status. + */ +QDF_STATUS +populate_dot11f_timing_advert_frame(tpAniSirGlobal mac_ctx, + tDot11fTimingAdvertisementFrame *frame) +{ + uint32_t val, len; + uint16_t item; + uint8_t temp[CFG_MAX_STR_LEN], code[3]; + QDF_STATUS nSirStatus; + + /* Capabilities */ + wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, &val); + if (val) + frame->Capabilities.privacy = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_SHORT_PREAMBLE, &val); + if (val) + frame->Capabilities.shortPreamble = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &val); + if (val) + frame->Capabilities.spectrumMgt = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_QOS_ENABLED, &val); + if (val) + frame->Capabilities.qos = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_APSD_ENABLED, &val); + if (val) + frame->Capabilities.apsd = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_BLOCK_ACK_ENABLED, &val); + 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 */ + item = WNI_CFG_MAX_TX_POWER_5; + CFG_GET_STR(nSirStatus, mac_ctx, item, temp, len, + WNI_CFG_MAX_TX_POWER_5_LEN); + wlan_reg_read_current_country(mac_ctx->psoc, code); + qdf_mem_copy(&frame->Country, code, 2); + if (len > MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE) + len = MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE; + + frame->Country.num_triplets = (uint8_t)(len / 3); + qdf_mem_copy((uint8_t *)&frame->Country.triplets, temp, len); + frame->Country.present = 1; + + /* PowerConstraints */ + wlan_cfg_get_int(mac_ctx, WNI_CFG_LOCAL_POWER_CONSTRAINT, &val); + frame->PowerConstraints.localPowerConstraints = (uint8_t)val; + frame->PowerConstraints.present = 1; + + /* TimeAdvertisement */ + frame->TimeAdvertisement.present = 1; + frame->TimeAdvertisement.timing_capabilities = 1; + + return nSirStatus; +} + +#ifdef WLAN_FEATURE_11AX +/** + * 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(tpAniSirGlobal mac_ctx, tpPESession session, + tDot11fIEhe_cap *he_cap) +{ + uint8_t *ppet; + uint32_t value = 0; + QDF_STATUS status; + + he_cap->present = 1; + + if (!session) { + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_CONTROL, value); + he_cap->htc_he = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_TWT_REQUESTOR, value); + he_cap->twt_request = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_TWT_RESPONDER, value); + he_cap->twt_responder = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_FRAGMENTATION, value); + he_cap->fragmentation = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MAX_FRAG_MSDU, value); + he_cap->max_num_frag_msdu = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MIN_FRAG_SIZE, value); + he_cap->min_frag_size = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_TRIG_PAD, value); + he_cap->trigger_frm_mac_pad = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MTID_AGGR, value); + he_cap->multi_tid_aggr = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_LINK_ADAPTATION, value); + he_cap->he_link_adaptation = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_ALL_ACK, value); + he_cap->all_ack = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_UL_MU_RSP_SCHEDULING, + value); + he_cap->ul_mu_rsp_sched = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_BUFFER_STATUS_RPT, + value); + he_cap->a_bsr = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_BCAST_TWT, value); + he_cap->broadcast_twt = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_BA_32BIT, value); + he_cap->ba_32bit_bitmap = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MU_CASCADING, value); + he_cap->mu_cascade = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MULTI_TID, value); + he_cap->ack_enabled_multitid = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_DL_MU_BA, value); + he_cap->dl_mu_ba = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_OMI, value); + he_cap->omi_a_ctrl = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_OFDMA_RA, value); + he_cap->ofdma_ra = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MAX_AMPDU_LEN, value); + he_cap->max_ampdu_len = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_AMSDU_FRAG, value); + he_cap->amsdu_frag = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_FLEX_TWT_SCHED, value); + he_cap->flex_twt_sched = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_RX_CTRL, value); + he_cap->rx_ctrl_frame = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_BSRP_AMPDU_AGGR, value); + he_cap->bsrp_ampdu_aggr = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_QTP, value); + he_cap->qtp = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_A_BQR, value); + he_cap->a_bqr = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_SR_RESPONDER, value); + he_cap->sr_responder = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_NDP_FEEDBACK_SUPP, + value); + he_cap->ndp_feedback_supp = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_OPS_SUPP, value); + he_cap->ops_supp = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_AMSDU_IN_AMPDU, value); + he_cap->amsdu_in_ampdu = value; + + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_DUAL_BAND, value); + he_cap->dual_band = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_CHAN_WIDTH, value); + he_cap->chan_width_0 = HE_CH_WIDTH_GET_BIT(value, 0); + he_cap->chan_width_1 = HE_CH_WIDTH_GET_BIT(value, 1); + he_cap->chan_width_2 = HE_CH_WIDTH_GET_BIT(value, 2); + he_cap->chan_width_3 = HE_CH_WIDTH_GET_BIT(value, 3); + he_cap->chan_width_4 = HE_CH_WIDTH_GET_BIT(value, 4); + he_cap->chan_width_5 = HE_CH_WIDTH_GET_BIT(value, 5); + he_cap->chan_width_6 = HE_CH_WIDTH_GET_BIT(value, 6); + + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_RX_PREAM_PUNC, value); + he_cap->rx_pream_puncturing = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_CLASS_OF_DEVICE, value); + he_cap->device_class = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_LDPC, value); + he_cap->ldpc_coding = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_LTF_PPDU, value); + he_cap->he_1x_ltf_800_gi_ppdu = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS, value); + he_cap->midamble_rx_max_nsts = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_LTF_NDP, value); + he_cap->he_4x_ltf_3200_gi_ndp = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_TX_STBC_LT80, value); + he_cap->tx_stbc_lt_80mhz = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_RX_STBC_LT80, value); + he_cap->rx_stbc_lt_80mhz = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_DOPPLER, value); + he_cap->doppler = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_UL_MUMIMO, value); + he_cap->ul_mu = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_DCM_TX, value); + he_cap->dcm_enc_tx = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_DCM_RX, value); + he_cap->dcm_enc_rx = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MU_PPDU, value); + he_cap->ul_he_mu = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_SU_BEAMFORMER, value); + he_cap->su_beamformer = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_SU_BEAMFORMEE, value); + he_cap->su_beamformee = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MU_BEAMFORMER, value); + he_cap->mu_beamformer = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_BFEE_STS_LT80, value); + he_cap->bfee_sts_lt_80 = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_BFEE_STS_GT80, value); + he_cap->bfee_sts_gt_80 = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_NUM_SOUND_LT80, value); + he_cap->num_sounding_lt_80 = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_NUM_SOUND_GT80, value); + he_cap->num_sounding_gt_80 = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_SU_FEED_TONE16, value); + he_cap->su_feedback_tone16 = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MU_FEED_TONE16, value); + he_cap->mu_feedback_tone16 = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_CODEBOOK_SU, value); + he_cap->codebook_su = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_CODEBOOK_MU, value); + he_cap->codebook_mu = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_BFRM_FEED, value); + he_cap->beamforming_feedback = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_ER_SU_PPDU, value); + he_cap->he_er_su_ppdu = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_DL_PART_BW, value); + he_cap->dl_mu_mimo_part_bw = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_PPET_PRESENT, value); + he_cap->ppet_present = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_SRP, value); + he_cap->srp = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_POWER_BOOST, value); + he_cap->power_boost = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_4x_LTF_GI, value); + he_cap->he_ltf_800_gi_4x = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_MAX_NC, value); + he_cap->max_nc = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_TX_STBC_GT80, value); + he_cap->tx_stbc_gt_80mhz = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_RX_STBC_GT80, value); + he_cap->rx_stbc_gt_80mhz = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_ER_4x_LTF_GI, value); + he_cap->er_he_ltf_800_gi_4x = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_PPDU_20_IN_40MHZ_2G, value); + he_cap->he_ppdu_20_in_40Mhz_2G = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ, value); + he_cap->he_ppdu_20_in_160_80p80Mhz = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ, value); + he_cap->he_ppdu_80_in_160_80p80Mhz = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_ER_1X_HE_LTF_GI, value); + he_cap->er_1x_he_ltf_gi = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF, value); + he_cap->midamble_rx_1x_he_ltf = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_RX_MCS_MAP_LT_80, value); + he_cap->rx_he_mcs_map_lt_80 = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_TX_MCS_MAP_LT_80, value); + he_cap->tx_he_mcs_map_lt_80 = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_RX_MCS_MAP_160, value); + *((uint16_t *)he_cap->rx_he_mcs_map_160) = value; + CFG_GET_INT(status, mac_ctx, WNI_CFG_HE_TX_MCS_MAP_160, value); + *((uint16_t *)he_cap->tx_he_mcs_map_160) = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_RX_MCS_MAP_80_80, value); + *((uint16_t *)he_cap->rx_he_mcs_map_80_80) = value; + CFG_GET_INT(status, mac_ctx, + WNI_CFG_HE_TX_MCS_MAP_80_80, value); + *((uint16_t *)he_cap->tx_he_mcs_map_80_80) = value; + + if (he_cap->ppet_present) { + value = WNI_CFG_HE_PPET_LEN; + /* if session less then take 5g cap */ + CFG_GET_STR(status, mac_ctx, WNI_CFG_HE_PPET_5G, + he_cap->ppet.ppe_threshold.ppe_th, + value, 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; + } + + return QDF_STATUS_SUCCESS; + } + + 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 (IS_5G_CH(session->currentOperChannel)) + CFG_GET_STR(status, mac_ctx, WNI_CFG_HE_PPET_5G, + he_cap->ppet.ppe_threshold.ppe_th, + value, value); + else + CFG_GET_STR(status, mac_ctx, WNI_CFG_HE_PPET_2G, + he_cap->ppet.ppe_threshold.ppe_th, + value, 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; + } + + lim_log_he_cap(mac_ctx, 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(tpAniSirGlobal mac_ctx, + tpPESession session, tDot11fIEhe_op *he_op) +{ + qdf_mem_copy(he_op, &session->he_op, sizeof(*he_op)); + + he_op->vht_oper_present = 1; + he_op->present = 1; + if (session->ch_width > CH_WIDTH_40MHZ) { + he_op->vht_oper.info.chan_width = 1; + he_op->vht_oper.info.center_freq_seg0 = + session->ch_center_freq_seg0; + if (session->ch_width == CH_WIDTH_80P80MHZ || + session->ch_width == CH_WIDTH_160MHZ) + he_op->vht_oper.info.center_freq_seg1 = + session->ch_center_freq_seg1; + else + he_op->vht_oper.info.center_freq_seg1 = 0; + } else { + he_op->vht_oper.info.chan_width = 0; + he_op->vht_oper.info.center_freq_seg0 = 0; + he_op->vht_oper.info.center_freq_seg1 = 0; + } + lim_log_he_op(mac_ctx, he_op); + + 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(tpAniSirGlobal mac_ctx, + tpPESession 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 +#endif + +#ifdef WLAN_SUPPORT_TWT +QDF_STATUS populate_dot11f_twt_extended_caps(tpAniSirGlobal mac_ctx, + tpPESession pe_session, + tDot11fIEExtCap *dot11f) +{ + uint32_t value = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct s_ext_cap *p_ext_cap; + + if (!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; + + if (pe_session->pePersona == QDF_STA_MODE) { + CFG_GET_INT(status, mac_ctx, WNI_CFG_TWT_REQUESTOR, value); + p_ext_cap->twt_requestor_support = value; + } + if (pe_session->pePersona == QDF_SAP_MODE) { + CFG_GET_INT(status, mac_ctx, WNI_CFG_TWT_RESPONDER, value); + p_ext_cap->twt_responder_support = value; + } + dot11f->num_bytes = lim_compute_ext_cap_ie_length(dot11f); + + return status; +} +#endif + +/* parser_api.c ends here. */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..da2f8a298276ec7c713282d6457ee49630af5ea8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c @@ -0,0 +1,685 @@ +/* + * 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. + */ + +/* + * + * 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(tpAniSirGlobal pMac, tSirMacSSid *pOld, tDot11fIESSID *pNew) +{ + pOld->length = pNew->num_ssid; + qdf_mem_copy(pOld->ssId, pNew->ssid, pNew->num_ssid); +} + +void convert_supp_rates(tpAniSirGlobal pMac, + tSirMacRateSet *pOld, tDot11fIESuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + qdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_ext_supp_rates(tpAniSirGlobal pMac, + tSirMacRateSet *pOld, tDot11fIEExtSuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + qdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_qos_caps(tpAniSirGlobal pMac, + tSirMacQosCapabilityIE *pOld, tDot11fIEQOSCapsAp *pNew) +{ + pOld->type = 46; + pOld->length = 1; + + pOld->qosInfo.count = pNew->count; +} + +void convert_qos_caps_station(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(pMac, 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tSirMacRsnInfo *pOld, tDot11fIERSN *pNew) +{ + uint8_t buffer[257]; + uint32_t status, written = 0, nbuffer = 257; + + status = dot11f_pack_ie_rsn(pMac, 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tSirMacPowerCapabilityIE *pOld, + tDot11fIEPowerCaps *pNew) +{ + pOld->type = 33; + pOld->length = 2; + pOld->minTxPower = pNew->minTxPower; + pOld->maxTxPower = pNew->maxTxPower; +} + +void convert_supp_channels(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, 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(tpAniSirGlobal pMac, + tSirCountryInformation *pOld, tDot11fIECountry *pNew) +{ + int i; + + qdf_mem_copy(pOld->countryString, pNew->country, COUNTRY_STRING_LENGTH); + + pOld->numIntervals = pNew->num_triplets; + + for (i = 0; i < pNew->num_triplets; ++i) { + pOld->channelTransmitPower[i].channelNumber = + pNew->triplets[i][0]; + pOld->channelTransmitPower[i].numChannel = pNew->triplets[i][1]; + pOld->channelTransmitPower[i].maxTransmitPower = + pNew->triplets[i][2]; + } +} + +void convert_wmm_params(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tSirMacErpInfo *pOld, tDot11fIEERPInfo *pNew) +{ + pOld->nonErpPresent = pNew->non_erp_present; + pOld->useProtection = pNew->use_prot; + pOld->barkerPreambleMode = pNew->barker_preamble; +} + +void convert_edca_param(tpAniSirGlobal pMac, + 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(tpAniSirGlobal 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(tpAniSirGlobal pMac, + tSirMacTspecIE *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(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_ietclas(pMac, 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(tpAniSirGlobal pMac, + tSirMacTspecIE *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(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_iewmmtclas(pMac, 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(tpAniSirGlobal pMac, + tSirMacTsDelayIE *pOld, tDot11fIETSDelay *pNew) +{ + pOld->type = DOT11F_EID_TSDELAY; + pOld->length = 4U; + pOld->delay = pNew->delay; +} + +void convert_schedule(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, tSirQosMapSet *Qos, + tDot11fIEQosMapSet *dot11fIE) +{ + uint8_t i, j = 0; + uint8_t qos_dscp_sz, dot11_dscp_sz; + + qos_dscp_sz = (sizeof(Qos->dscp_exceptions)/2); + dot11_dscp_sz = sizeof(dot11fIE->dscp_exceptions); + if (dot11fIE->num_dscp_exceptions > QOS_MAP_LEN_MAX) + dot11fIE->num_dscp_exceptions = QOS_MAP_LEN_MAX; + if (dot11fIE->num_dscp_exceptions < QOS_MAP_LEN_MIN) + return; + Qos->num_dscp_exceptions = + (dot11fIE->num_dscp_exceptions - QOS_MAP_LEN_MIN) / 2; + + for (i = 0; + i < Qos->num_dscp_exceptions && + i < qos_dscp_sz && j < dot11_dscp_sz; + i++) { + Qos->dscp_exceptions[i][0] = dot11fIE->dscp_exceptions[j]; + j++; + Qos->dscp_exceptions[i][1] = dot11fIE->dscp_exceptions[j]; + j++; + } + for (i = 0; i < 8 && j < dot11_dscp_sz; i++) { + Qos->dscp_range[i][0] = dot11fIE->dscp_exceptions[j]; + j++; + Qos->dscp_range[i][1] = dot11fIE->dscp_exceptions[j]; + j++; + } +} + +/* utils_parser.c ends here. */ diff --git a/drivers/staging/qcacld-3.0/core/pld/inc/pld_common.h b/drivers/staging/qcacld-3.0/core/pld/inc/pld_common.h new file mode 100644 index 0000000000000000000000000000000000000000..8f3a91fb6cc345eff8e1830e2a17bfcc54f57ec0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/inc/pld_common.h @@ -0,0 +1,662 @@ +/* + * 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. + */ + +#ifndef __PLD_COMMON_H__ +#define __PLD_COMMON_H__ + +#include +#include +#include +#include + +#ifdef CONFIG_CNSS_UTILS +#include +#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 "" + +#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC +#include +#endif + +/** + * 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 + */ +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 +}; + +#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_LOW: vote for low bus bandwidth + * @PLD_BUS_WIDTH_MEDIUM: vote for medium bus bandwidth + * @PLD_BUS_WIDTH_HIGH: vote for high bus bandwidth + */ +enum pld_bus_width_type { + PLD_BUS_WIDTH_NONE, + PLD_BUS_WIDTH_LOW, + PLD_BUS_WIDTH_MEDIUM, + PLD_BUS_WIDTH_HIGH +}; + +#define PLD_MAX_FILE_NAME NAME_MAX + +/** + * struct pld_fw_file - 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 + * + * 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 + */ +enum pld_platform_cap_flag { + PLD_HAS_EXTERNAL_SWREG = 0x01, + PLD_HAS_UART_ACCESS = 0x02, +}; + +/** + * 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 - WLAN FW status + * @PLD_RECOVERY: driver is recovering + * @PLD_FW_DOWN: FW is down + */ +enum pld_uevent { + PLD_RECOVERY, + PLD_FW_DOWN, +}; + +/** + * struct pld_uevent_data - uevent status received from platform driver + * @uevent: uevent type + * @fw_down: FW down info + */ +struct pld_uevent_data { + enum pld_uevent uevent; + union { + struct { + bool crashed; + } fw_down; + }; +}; + +/** + * 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; +}; + +/** + * 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 + * + * 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; +}; + +/** + * 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 + */ +enum pld_driver_mode { + PLD_MISSION, + PLD_FTM, + PLD_EPPING, + PLD_WALTEST, + PLD_OFF, + PLD_COLDBOOT_CALIBRATION = 7 +}; + +#define PLD_MAX_TIMESTAMP_LEN 32 + +/** + * 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 + * + * 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]; +}; + +/** + * 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 +}; + +/** + * 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 + * @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 + * @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 + * @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() + */ +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); + 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); + 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 (*idle_shutdown)(struct device *dev, + enum pld_bus_type bus_type); + int (*idle_restart)(struct device *dev, + enum pld_bus_type bus_type); +}; + +int pld_init(void); +void pld_deinit(void); + +int pld_register_driver(struct pld_driver_ops *ops); +void pld_unregister_driver(void); + +int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode); +int pld_set_fw_log_mode(struct device *dev, u8 fw_log_mode); +void pld_get_default_fw_files(struct pld_fw_files *pfw_files); +int pld_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); +void pld_is_pci_link_down(struct device *dev); +int pld_shadow_control(struct device *dev, bool enable); +void pld_schedule_recovery_work(struct device *dev, + enum pld_recovery_reason reason); +#ifdef CONFIG_CNSS_UTILS +/** + * 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_set_wlan_unsafe_channel(struct device *dev, + u16 *unsafe_ch_list, + u16 ch_count) +{ + return -EINVAL; +} +static inline int pld_get_wlan_unsafe_channel(struct device *dev, + u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + return -EINVAL; +} +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 +int pld_wlan_pm_control(struct device *dev, bool vote); +void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size); +void pld_device_crashed(struct device *dev); +void pld_device_self_recovery(struct device *dev, + enum pld_recovery_reason reason); +void pld_intr_notify_q6(struct device *dev); +void pld_request_pm_qos(struct device *dev, u32 qos_val); +void pld_remove_pm_qos(struct device *dev); +int pld_request_bus_bandwidth(struct device *dev, int bandwidth); +int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap); +int pld_get_sha_hash(struct device *dev, const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out); +void *pld_get_fw_ptr(struct device *dev); +int pld_auto_suspend(struct device *dev); +int pld_auto_resume(struct device *dev); + +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 pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx); +void pld_enable_irq(struct device *dev, unsigned int ce_id); +void pld_disable_irq(struct device *dev, unsigned int ce_id); +int pld_get_soc_info(struct device *dev, struct pld_soc_info *info); +int pld_get_ce_id(struct device *dev, int irq); +int pld_get_irq(struct device *dev, int ce_id); +void pld_lock_pm_sem(struct device *dev); +void pld_release_pm_sem(struct device *dev); +int pld_power_on(struct device *dev); +int pld_power_off(struct device *dev); +int pld_athdiag_read(struct device *dev, uint32_t offset, uint32_t memtype, + uint32_t datalen, uint8_t *output); +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)) +void *pld_smmu_get_domain(struct device *dev); +#else +void *pld_smmu_get_mapping(struct device *dev); +#endif +int pld_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size); +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 pld_get_msi_irq(struct device *dev, unsigned int vector); +void pld_get_msi_address(struct device *dev, uint32_t *msi_addr_low, + uint32_t *msi_addr_high); +unsigned int pld_socinfo_get_serial_number(struct device *dev); +int pld_is_qmi_disable(struct device *dev); +int pld_is_fw_down(struct device *dev); +int pld_force_assert_target(struct device *dev); +bool pld_is_fw_dump_skipped(struct device *dev); + +/** + * pld_is_pdr() - Check WLAN PD is Restarted + * + * 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 + * + * 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); + +#if defined(CONFIG_WCNSS_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 +/** + * 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)); +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_common.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_common.c new file mode 100644 index 0000000000000000000000000000000000000000..801fa48a9119700588c503768699cccabca22683 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_common.c @@ -0,0 +1,1659 @@ +/* + * Copyright (c) 2016-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. + */ + +#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 +#include +#endif +#ifdef CONFIG_PLD_SNOC_ICNSS +#include +#endif + +#include "pld_pcie.h" +#include "pld_snoc.h" +#include "pld_sdio.h" +#include "pld_usb.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_BUS_MASK 0xf + +static struct pld_context *pld_ctx; + +/** + * pld_init() - Initialize PLD module + * + * Return: 0 for success + * Non zero failure code for errors + */ +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; +} + +/** + * pld_deinit() - Uninitialize PLD module + * + * Return: void + */ +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; +} + +/** + * pld_get_global_context() - Get global context of PLD + * + * Return: PLD global context + */ +struct pld_context *pld_get_global_context(void) +{ + return pld_ctx; +} + +/** + * pld_add_dev() - Add dev node to global context + * @pld_context: PLD global context + * @dev: 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, enum pld_bus_type type) +{ + unsigned long flags; + struct dev_node *dev_node; + + dev_node = kzalloc(sizeof(*dev_node), GFP_KERNEL); + if (dev_node == NULL) + return -ENOMEM; + + dev_node->dev = dev; + 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; +} + +/** + * 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) +{ + 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); +} + +/** + * pld_get_bus_type() - Bus type of the device + * @dev: device + * + * Return: PLD bus type + */ +static enum pld_bus_type pld_get_bus_type(struct device *dev) +{ + struct pld_context *pld_context; + struct dev_node *dev_node; + unsigned long flags; + + pld_context = pld_get_global_context(); + + if (dev == NULL || pld_context == NULL) { + pr_err("Invalid info: dev %pK, context %pK\n", + dev, pld_context); + return PLD_BUS_TYPE_NONE; + } + + 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->bus_type; + } + } + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + + return PLD_BUS_TYPE_NONE; +} + +/** + * 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) +{ + int ret = 0; + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (pld_context == NULL) { + 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) { + pr_err("Fail to register pcie driver\n"); + goto fail_pcie; + } + pld_context->pld_driver_state |= PLD_PCIE_REGISTERED; + + ret = pld_snoc_register_driver(); + if (ret) { + pr_err("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_usb_register_driver(); + if (ret) { + pr_err("Fail to register usb driver\n"); + goto fail_usb; + } + pld_context->pld_driver_state |= PLD_USB_REGISTERED; + + return ret; + +fail_usb: + 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; +} + +/** + * 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) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (pld_context == NULL) { + pr_err("global context is NULL\n"); + return; + } + + if (pld_context->ops == NULL) { + pr_err("driver not registered\n"); + return; + } + + pld_pcie_unregister_driver(); + pld_snoc_unregister_driver(); + pld_sdio_unregister_driver(); + pld_usb_unregister_driver(); + + pld_context->pld_driver_state = 0; + + pld_context->ops = NULL; +} + +/** + * pld_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_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_enable(dev, config, mode, host_version); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_wlan_enable(dev, config, mode, host_version); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + memset(pfw_files, 0, sizeof(*pfw_files)); + + strlcpy(pfw_files->image_file, PLD_IMAGE_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->board_data, PLD_BOARD_DATA_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->otp_data, PLD_OTP_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_file, PLD_UTF_FIRMWARE_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_board_data, PLD_BOARD_DATA_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->epping_file, PLD_EPPING_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->setup_file, PLD_SETUP_FILE, + PLD_MAX_FILE_NAME); +} + +/** + * 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) +{ + 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_SNOC: + 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; +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_link_down(dev); + break; + case PLD_BUS_TYPE_SNOC: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_schedule_recovery_work(dev, reason); + break; + case PLD_BUS_TYPE_SNOC: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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 collaps control during suspend/resume. + * When PCIE power collaps 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) +{ + 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_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SNOC: + 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; +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_device_crashed(dev); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + pld_sdio_device_crashed(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_device_self_recovery(dev, reason); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + pld_sdio_device_self_recovery(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_intr_notify_q6(dev); + break; + case PLD_BUS_TYPE_SNOC: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_request_pm_qos(dev, qos_val); + break; + case PLD_BUS_TYPE_SNOC: + 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; + } +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_remove_pm_qos(dev); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + 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_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_fw_ptr() - Get secure FW memory address + * @dev: device + * + * Return: secure memory address + */ +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_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ptr; +} + +/** + * pld_auto_suspend() - Auto suspend + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +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_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_auto_resume() - Auto resume + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +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_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_PCIE: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_PCIE: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + pld_snoc_enable_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_PCIE: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + pld_snoc_disable_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_PCIE: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_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; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_PCIE: + ret = pld_pcie_get_ce_id(dev, irq); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_PCIE: + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_lock_pm_sem() - Lock PM semaphore + * @dev: device + * + * Return: void + */ +void pld_lock_pm_sem(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_lock_pm_sem(dev); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_release_pm_sem() - Release PM semaphore + * @dev: device + * + * Return: void + */ +void pld_release_pm_sem(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_release_pm_sem(dev); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * 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) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_power_on(dev); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_power_on(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +/** + * 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) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_power_off(dev); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_power_off(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +/** + * 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) +{ + 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: + case PLD_BUS_TYPE_USB: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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: + case PLD_BUS_TYPE_USB: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_smmu_get_domain() - Get SMMU domain + * @dev: device + * + * Return: Pointer to the domain + */ +#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; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ptr; +} +#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) +{ + 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: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ptr; +} +#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) +{ + 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: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * 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) +{ + 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_SNOC: + 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; + } +} + +/** + * 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) +{ + 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: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ret; +} + +/** + * 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) +{ + 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_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; +} + +/** + * 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: 1 FW is down + * 0 FW is not down + * Non zero failure code for errors + */ +int pld_is_fw_down(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_down(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_force_assert_target() - Send a force assert to FW. + * This can use various sideband requests available at platform to + * initiate a FW assert. + * @dev: device + * + * Return: 0 if force assert of target was triggered successfully + * Non zero failure code for errors + */ +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_SDIO: + return -EINVAL; + default: + pr_err("Invalid device type %d\n", type); + return -EINVAL; + } +} + +/** + * pld_is_fw_dump_skipped() - get fw dump skipped status. + * 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) +{ + 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; + 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; + 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; + default: + 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: + case PLD_BUS_TYPE_PCIE: + errno = shutdown_cb(dev); + break; + case PLD_BUS_TYPE_SNOC: + errno = pld_snoc_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: + case PLD_BUS_TYPE_PCIE: + errno = restart_cb(dev); + break; + case PLD_BUS_TYPE_SNOC: + errno = pld_snoc_idle_restart(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_internal.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..833c1630772b4b6c822f524f3880e07f0fd174d5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_internal.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 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 __PLD_COMMON_I_H__ +#define __PLD_COMMON_I_H__ + +#include "pld_common.h" + +struct dev_node { + struct device *dev; + 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; +}; + +struct pld_context *pld_get_global_context(void); +int pld_add_dev(struct pld_context *pld_context, + struct device *dev, enum pld_bus_type type); +void pld_del_dev(struct pld_context *pld_context, + struct device *dev); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.c new file mode 100644 index 0000000000000000000000000000000000000000..5442b1009ae8a68bab1713035394f1e7f453bc07 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.c @@ -0,0 +1,760 @@ +/* + * Copyright (c) 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. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PLD_PCIE_CNSS +#include +#endif + +#include "pld_internal.h" +#include "pld_pcie.h" + +#ifdef CONFIG_PCI + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define CE_COUNT_MAX 12 +#else +#define CE_COUNT_MAX 8 +#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, 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; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE); + + pld_del_dev(pld_context, &pdev->dev); +} + +#ifdef CONFIG_PLD_PCIE_CNSS +/** + * 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; + + pld_context = pld_get_global_context(); + if (!pld_context) + return; + + switch (status) { + case CNSS_RECOVERY: + data.uevent = PLD_RECOVERY; + break; + default: + goto out; + } + + if (pld_context->ops->uevent) + pld_context->ops->uevent(&pdev->dev, &data); + +out: + return; +} + +#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 +#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[] = { + { 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_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, + .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 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 +}; + +/** + * pld_pcie_register_driver() - Register PCIE device callback functions + * + * Return: int + */ +int pld_pcie_register_driver(void) +{ + return cnss_wlan_register_driver(&pld_pcie_ops); +} + +/** + * pld_pcie_unregister_driver() - Unregister PCIE device callback functions + * + * Return: void + */ +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 + +/** + * 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) +{ + int ce_id = irq - 100; + + if (ce_id < CE_COUNT_MAX && ce_id >= 0) + return ce_id; + + return -EINVAL; +} + +#ifdef CONFIG_PLD_PCIE_CNSS +/** + * 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) +{ + 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; + + 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); +} + +/** + * 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) +{ + return cnss_wlan_disable(dev, CNSS_OFF); +} + +/** + * 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) +{ + int ret = 0; + struct cnss_fw_files cnss_fw_files; + + if (pfw_files == NULL) + 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; + + strlcpy(pfw_files->image_file, cnss_fw_files.image_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->board_data, cnss_fw_files.board_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->otp_data, cnss_fw_files.otp_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_file, cnss_fw_files.utf_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_board_data, cnss_fw_files.utf_board_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->epping_file, cnss_fw_files.epping_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->evicted_data, cnss_fw_files.evicted_data, + PLD_MAX_FILE_NAME); + + return 0; +} + +/** + * 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) +{ + int ret = 0; + struct cnss_platform_cap cnss_cap; + + if (cap == NULL) + return -ENODEV; + + ret = cnss_get_platform_cap(dev, &cnss_cap); + if (ret) + return ret; + + memcpy(cap, &cnss_cap, sizeof(*cap)); + return 0; +} + +/** + * 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) +{ + int ret = 0; + struct cnss_soc_info cnss_info = {0}; + + if (info == NULL) + 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)); + + return 0; +} + +/** + * 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) +{ + 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); +} + +/** + * 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) +{ + 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); +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.h new file mode 100644 index 0000000000000000000000000000000000000000..1a4324cd10b396021b4d38731832c085bc81436f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.h @@ -0,0 +1,375 @@ +/* + * Copyright (c) 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 __PLD_PCIE_H__ +#define __PLD_PCIE_H__ + +#ifdef CONFIG_PLD_PCIE_CNSS +#include +#endif +#include "pld_internal.h" + +#ifndef HIF_PCI +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 +int pld_pcie_register_driver(void); +void pld_pcie_unregister_driver(void); +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; +} +#else +int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode); +#endif + +#if defined(CONFIG_PLD_PCIE_CNSS) && defined(QCA_WIFI_3_0_ADRASTEA) +static inline int pld_pcie_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + return cnss_set_fw_debug_mode(fw_log_mode); +} + +static inline void pld_pcie_intr_notify_q6(struct device *dev) +{ + cnss_intr_notify_q6(); +} +#elif 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 + +#if (!defined(CONFIG_PLD_PCIE_CNSS)) || (!defined(CONFIG_PCI_MSM)) +static inline int pld_pcie_wlan_pm_control(struct device *dev, bool vote) +{ + return 0; +} +#else +static inline int pld_pcie_wlan_pm_control(struct device *dev, bool vote) +{ + return cnss_wlan_pm_control(dev, vote); +} +#endif + +#ifndef CONFIG_PLD_PCIE_CNSS +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 void pld_pcie_link_down(struct device *dev) +{ +} + +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) +{ + return NULL; +} + +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 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 void pld_pcie_lock_pm_sem(struct device *dev) +{ +} + +static inline void pld_pcie_release_pm_sem(struct device *dev) +{ +} + +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_force_assert_target(struct device *dev) +{ + 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 0; +} + +static inline int pld_pcie_get_msi_irq(struct device *dev, unsigned int vector) +{ + return 0; +} + +static inline void pld_pcie_get_msi_address(struct device *dev, + uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ + return; +} +#else +int pld_pcie_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); +int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap); +int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info); +void pld_pcie_schedule_recovery_work(struct device *dev, + enum pld_recovery_reason reason); +void pld_pcie_device_self_recovery(struct device *dev, + enum pld_recovery_reason reason); + +static inline void pld_pcie_link_down(struct device *dev) +{ + cnss_pci_link_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_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); +} + +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 void pld_pcie_lock_pm_sem(struct device *dev) +{ + cnss_lock_pm_sem(dev); +} + +static inline void pld_pcie_release_pm_sem(struct device *dev) +{ + cnss_release_pm_sem(dev); +} + +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_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); +} + +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); +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.c new file mode 100644 index 0000000000000000000000000000000000000000..004743b22641256294b4be85b5392c45e03324ba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 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. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PLD_SDIO_CNSS +#include +#endif + +#include "pld_common.h" +#include "pld_internal.h" +#include "pld_sdio.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, 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; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SDIO); + pld_del_dev(pld_context, dev); +} + +#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_CNSS +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, +#ifdef CONFIG_PM + .suspend = pld_sdio_suspend, + .resume = pld_sdio_resume, +#endif +}; + +/** + * pld_sdio_register_driver() - Register SDIO device callback functions + * + * Return: int + */ +int pld_sdio_register_driver(void) +{ + return cnss_sdio_wlan_register_driver(&pld_sdio_ops); +} + +/** + * pld_sdio_unregister_driver() - Unregister SDIO device callback functions + * + * Return: void + */ +void pld_sdio_unregister_driver(void) +{ + cnss_sdio_wlan_unregister_driver(&pld_sdio_ops); +} +#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 +} + +/** + * 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) +{ + int ret = 0; + struct cnss_fw_files cnss_fw_files; + + if (pfw_files == NULL) + 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/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.h new file mode 100644 index 0000000000000000000000000000000000000000..66bbb22998b966fe1481698fd021910c0e1f8c4e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 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 __PLD_SDIO_H__ +#define __PLD_SDIO_H__ + +#ifdef CONFIG_PLD_SDIO_CNSS +#include +#endif +#include "pld_common.h" + +#ifdef MULTI_IF_NAME +#define PREFIX MULTI_IF_NAME "/" +#else +#define PREFIX "" +#endif + +#define PLD_QCA9377_REV1_1_VERSION 0x5020001 +#define PLD_QCA9379_REV1_VERSION 0x5040000 +#define TOTAL_DUMP_SIZE 0x00200000 + +#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 +int pld_sdio_register_driver(void); +void pld_sdio_unregister_driver(void); +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_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); +} +#else +static inline void *pld_sdio_get_virt_ramdump_mem(struct device *dev, + unsigned long *size) +{ + return NULL; +} + +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) +{ +} +#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 +/** + * 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 != NULL) + *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 != NULL) + kfree(address); +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.c new file mode 100644 index 0000000000000000000000000000000000000000..adca3f9f3bcc9848eb7ec0b396d2dfd0c5db34a5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 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. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_PLD_SNOC_ICNSS +#include +#endif + +#include "pld_internal.h" +#include "pld_snoc.h" + +#ifdef CONFIG_PLD_SNOC_ICNSS + +/** + * pld_snoc_idle_restart_cb() - Perform idle restart + * @pdev: 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 + * @pdev: PCIE device + * @id: PCIE device ID + * + * 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, 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; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC); + + pld_del_dev(pld_context, dev); +} + +/** + * 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 + * @pdev: 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() + * @pdev: 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; +} + +static int pld_snoc_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; + + 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_RECOVERY; + break; + case ICNSS_UEVENT_FW_DOWN: + if (uevent->data == NULL) + 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; +} + +#ifdef MULTI_IF_NAME +#define PLD_SNOC_OPS_NAME "pld_snoc_" MULTI_IF_NAME +#else +#define PLD_SNOC_OPS_NAME "pld_snoc" +#endif + +struct icnss_driver_ops pld_snoc_ops = { + .name = PLD_SNOC_OPS_NAME, + .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, +}; + +/** + * pld_snoc_register_driver() - Register platform device callback functions + * + * Return: int + */ +int pld_snoc_register_driver(void) +{ + return icnss_register_driver(&pld_snoc_ops); +} + +/** + * pld_snoc_unregister_driver() - Unregister platform device callback functions + * + * Return: void + */ +void pld_snoc_unregister_driver(void) +{ + icnss_unregister_driver(&pld_snoc_ops); +} + +/** + * 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) +{ + 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_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) +{ + if (!dev) + return -ENODEV; + + return icnss_wlan_disable(dev, ICNSS_OFF); +} + +/** + * 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) +{ + int ret = 0; + struct icnss_soc_info icnss_info; + + if (info == NULL || !dev) + return -ENODEV; + + ret = icnss_get_soc_info(dev, &icnss_info); + if (0 != ret) + return ret; + + 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/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.h new file mode 100644 index 0000000000000000000000000000000000000000..53084a06ed25c39e083a8a1d9f64f80d66c713e8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.h @@ -0,0 +1,297 @@ +/* + * 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. + */ + +#ifndef __PLD_SNOC_H__ +#define __PLD_SNOC_H__ + +#ifdef CONFIG_PLD_SNOC_ICNSS +#include +#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_smmu_map(struct device *dev, phys_addr_t paddr, + 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_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; +} +#else +int pld_snoc_register_driver(void); +void pld_snoc_unregister_driver(void); +int pld_snoc_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode); +int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info); + +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); +} +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(); +} + +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 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); +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.c new file mode 100644 index 0000000000000000000000000000000000000000..9b56c64300b3ce112ddd268d8145aee06f486b1b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 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. + */ + +#include "pld_usb.h" +#include "pld_internal.h" + +#include +#include +#include +#include +#include +#include + + +#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, 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; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + if (atomic_read(&pld_usb_reg_done) != true) { + pr_info("%s: already de-registered!\n", __func__); + return; + } + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_USB); + + pld_del_dev(pld_context, &pdev->dev); + + atomic_set(&pld_usb_reg_done, false); + 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); +} + +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, +}; + +/** + * pld_usb_register_driver() - registration routine for wlan usb driver + * + * Return: int negative error code on failure and 0 on success + */ +int pld_usb_register_driver(void) +{ + int status; + + usb_register(&pld_usb_ops); + + if (atomic_read(&pld_usb_reg_done) == true) + status = 0; + else + status = -1; + + pr_info("%s usb_register %s, status %d\n", __func__, + (status == 0) ? "done" : "failed", status); + + return status; +} + +/** + * pld_usb_unregister_driver() - de-registration routine for wlan usb driver + * + * Return: void + */ +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__); +} diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.h new file mode 100644 index 0000000000000000000000000000000000000000..2f4e9298268264c26fc830ce858dd6ca45bb5266 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 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 __PLD_USB_H__ +#define __PLD_USB_H__ + +#include "pld_common.h" + +#if !defined(CONFIG_PLD_USB_CNSS) +static inline int pld_usb_register_driver(void) +{ + return 0; +} + +static inline void pld_usb_unregister_driver(void) +{ +} + +static inline int pld_usb_get_ce_id(int irq) +{ + return 0; +} +#else +int pld_usb_register_driver(void); +void pld_usb_unregister_driver(void); +int pld_usb_get_ce_id(int irq); +#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/drivers/staging/qcacld-3.0/core/sap/inc/sap_api.h b/drivers/staging/qcacld-3.0/core/sap/inc/sap_api.h new file mode 100644 index 0000000000000000000000000000000000000000..5ed274bff0ac358094c49fee02c8d24d4fa457e1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/inc/sap_api.h @@ -0,0 +1,1532 @@ +/* + * 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_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_SSID_LEN 32 +#define MAX_ACL_MAC_ADDRESS 32 +#define AUTO_CHANNEL_SELECT 0 +#define MAX_ASSOC_IND_IE_LEN 255 + +/* 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 +#define QDF_MAX_NO_OF_SAP_MODE 2 /* max # of SAP */ +#define SAP_MAX_NUM_SESSION 5 +#define SAP_MAX_OBSS_STA_CNT 1 /* max # of OBSS STA */ +#define SAP_ACS_WEIGHT_MAX (26664) + +#define SAP_DEFAULT_24GHZ_CHANNEL (6) +#define SAP_DEFAULT_5GHZ_CHANNEL (40) +#define SAP_CHANNEL_NOT_SELECTED (0) + +/*-------------------------------------------------------------------------- + * 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 { + eSAP_BLACK_LIST = 0, /* List of mac addresses NOT allowed to assoc */ + eSAP_WHITE_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 */ +} 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 neeeds to allocate a context + */ + eSAP_STA_ASSOC_EVENT, + /* + * Event sent when we have successfully reassociated a station and + * upper layer neeeds 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 sent when user called wlansap_get_assoc_stations */ + eSAP_ASSOC_STA_CALLBACK_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 white list or black 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_PRE_CAC_END, + eSAP_DFS_RADAR_DETECT, + eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC, + /* 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 initated from CORE stack */ + eSAP_MAC_INITATED_DISASSOC = 0x10000, + /* + * Disassociation was internally initated 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; + uint8_t operatingChannel; + 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 assoId; + uint8_t staId; + uint8_t status; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + bool fWmmEnabled; + eCsrAuthType negotiatedAuthType; + eCsrEncryptionType negotiatedUCEncryptionType; + eCsrEncryptionType negotiatedMCEncryptionType; + bool fAuthRequired; + uint8_t ecsa_capable; +} tSap_StationAssocIndication; + +typedef struct sap_StationAssocReassocCompleteEvent_s { + struct qdf_mac_addr staMac; + eStationType staType; + uint8_t staId; + uint8_t status; + uint8_t ies[MAX_ASSOC_IND_IE_LEN]; + uint16_t iesLen; + uint32_t statusCode; + eSapAuthType SapAuthType; + bool wmmEnabled; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + uint32_t assocRespLength; + uint8_t *assocRespPtr; + uint8_t timingMeasCap; + tSirSmeChanInfo 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 rx_mcs_map; + uint8_t tx_mcs_map; + uint8_t ecsa_capable; + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tSirMacCapabilityInfo capability_info; + bool he_caps_present; +} 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 statusCode; + uint32_t reason_code; + eSapDisassocReason reason; + int rssi; + int tx_rate; + int rx_rate; +} 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; +/*Structure to return MAC address of associated stations */ +typedef struct sap_AssocMacAddr_s { + struct qdf_mac_addr staMac; /* Associated station's MAC address */ + uint8_t assocId; /* Associated station's Association ID */ + uint8_t staId; /* Allocated station Id */ + uint8_t ShortGI40Mhz; + uint8_t ShortGI20Mhz; + uint8_t Support40Mhz; + uint32_t requestedMCRate; + tSirSupportedRates supportedRates; +} tSap_AssocMacAddr, *tpSap_AssocMacAddr; + +/*struct corresponding to SAP_ASSOC_STA_CALLBACK_EVENT */ +typedef struct sap_AssocStaListEvent_s { + QDF_MODULE_ID module; + /* module id that was passed in wlansap_get_assoc_stations API */ + uint8_t noOfAssocSta; /* Number of associated stations */ + tpSap_AssocMacAddr pAssocStas; + /* + * Pointer to pre allocated memory to obtain list of + * associated stations passed in wlansap_get_assoc_stations API + */ +} tSap_AssocStaListEvent; + +typedef struct sap_GetWPSPBCSessionEvent_s { + uint8_t status; + /* module id that was passed in wlansap_get_assoc_stations API */ + QDF_MODULE_ID module; + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + struct qdf_mac_addr addr; + eWPSPBCOverlap wpsPBCOverlap; +} tSap_GetWPSPBCSessionEvent; + +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_ManagementFrameInfo_s { + uint32_t nFrameLength; + uint8_t frameType; + uint32_t rxChan; /* Channel of where packet is received */ + /* + * 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; +} tSap_ManagementFrameInfo; + +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; + +typedef struct sap_DfsNolInfo_s { + uint16_t sDfsList; /* size of pDfsList in byte */ + void *pDfsList; /* pointer to pDfsList buffer */ +} tSap_DfsNolInfo; + +/** + * sap_acs_ch_selected_s - the structure to hold the selected channels + * @pri_channel: Holds the ACS selected primary channel + * @sec_channel: Holds the ACS selected secondary channel + * + * Holds the primary and secondary channel selected by ACS and is + * used to send it to the HDD. + */ +struct sap_ch_selected_s { + uint16_t pri_ch; + uint16_t ht_sec_ch; + uint16_t vht_seg0_center_ch; + uint16_t vht_seg1_center_ch; + uint16_t ch_width; +}; + +/** + * sap_roc_ready_ind_s - the structure to hold the scan id + * @scan_id: scan identifier + * + * Holds scan identifier + */ +struct sap_roc_ready_ind_s { + uint32_t scan_id; +}; + +/** + * struct sap_acs_scan_complete_event - acs scan complete event + * @status: status of acs scan + * @channellist: acs scan channels + * @num_of_channels: number of channels + */ +struct sap_acs_scan_complete_event { + uint8_t status; + uint8_t *channellist; + uint8_t num_of_channels; +}; + +/** + * struct sap_ch_change_ind - channel change indication + * @new_chan: channel to change + */ +struct sap_ch_change_ind { + uint16_t new_chan; +}; + +/* + * This struct will be filled in and passed to tpWLAN_SAPEventCB 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 + */ + +typedef struct sap_Event_s { + 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; + /*SAP_ASSOC_STA_CALLBACK_EVENT */ + tSap_AssocStaListEvent sapAssocStaListEvent; + /*SAP_GET_WPSPBC_SESSION_EVENT */ + tSap_GetWPSPBCSessionEvent sapGetWPSPBCSessionEvent; + /*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; + /*eSAP_DFS_NOL_XXX */ + tSap_DfsNolInfo sapDfsNolInfo; + struct sap_ch_selected_s sap_ch_selected; + struct sap_roc_ready_ind_s sap_roc_ind; + struct sap_ch_change_ind sap_chan_cng_ind; + struct sap_acs_scan_complete_event sap_acs_scan_comp; + QDF_STATUS ch_change_rsp_status; + } sapevt; +} tSap_Event, *tpSap_Event; + +typedef struct sap_SSID { + uint8_t length; + uint8_t ssId[MAX_SSID_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 sap_acs_cfg { + /* ACS Algo Input */ + uint8_t acs_mode; + bool dfs_master_mode; + eCsrPhyMode hw_mode; + uint8_t start_ch; + uint8_t end_ch; + uint8_t *ch_list; + uint8_t ch_list_count; + uint8_t *master_ch_list; + uint8_t master_ch_list_count; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + uint8_t skip_scan_status; + uint8_t skip_scan_range1_stch; + uint8_t skip_scan_range1_endch; + uint8_t skip_scan_range2_stch; + uint8_t skip_scan_range2_endch; +#endif + + uint16_t ch_width; + uint8_t pcl_channels[QDF_MAX_NUM_CHAN]; + uint8_t pcl_channels_weight_list[QDF_MAX_NUM_CHAN]; + uint32_t pcl_ch_count; + uint8_t is_ht_enabled; + uint8_t is_vht_enabled; + /* ACS Algo Output */ + uint8_t pri_ch; + uint8_t ht_sec_ch; + uint8_t vht_seg0_center_ch; + uint8_t vht_seg1_center_ch; + uint32_t band; +}; + +/* + * enum vendor_ie_access_policy- access policy + * @ACCESS_POLICY_NONE: access policy attribute is not valid + * @ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT: respond to probe req/assoc req + * only if ie is present + * @ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT: do not respond to probe req/ + * assoc req if ie is present +*/ +enum vendor_ie_access_policy { + ACCESS_POLICY_NONE, + ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT, + ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT, +}; + +/* + * 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 +}; + +/** + * 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. + * + */ +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 +}; + +typedef struct sap_config { + tSap_SSIDInfo_t SSIDinfo; + eCsrPhyMode SapHw_mode; /* Wireless Mode */ + eSapMacAddrACL SapMacaddr_acl; + struct qdf_mac_addr accept_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + bool ieee80211d; /* Specify if 11D is enabled or disabled */ + bool protEnabled; /* Specify if protection is enabled or disabled */ + /* Specify if OBSS protection is enabled or disabled */ + bool obssProtEnabled; + struct qdf_mac_addr deny_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + struct qdf_mac_addr self_macaddr; /* self macaddress or BSSID */ + uint8_t channel; /* Operation channel */ + uint8_t sec_ch; + struct ch_params ch_params; + uint32_t ch_width_orig; + uint8_t max_num_sta; /* maximum number of STAs in station table */ + uint8_t dtim_period; /* dtim interval */ + uint8_t num_accept_mac; + uint8_t num_deny_mac; + /* Max ie length 255 * 2(WPA+RSN) + 2 bytes(vendor specific ID) * 2 */ + uint8_t RSNWPAReqIE[(SIR_MAC_MAX_IE_LENGTH * 2) + 4]; + /* it is ignored if [0] is 0. */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t RSNAuthType; + uint8_t RSNEncryptType; + uint8_t mcRSNEncryptType; + eSapAuthType authType; + bool privacy; + bool UapsdEnable; + bool fwdWPSPBCProbeReq; + /* 0 - disabled, 1 - not configured , 2 - configured */ + uint8_t wps_state; + uint16_t ht_capab; + uint16_t RSNWPAReqIELength; /* The byte count in the pWPAReqIE */ + uint32_t beacon_int; /* Beacon Interval */ + uint32_t ap_table_max_size; + uint32_t ap_table_expiration_time; + uint32_t ht_op_mode_fixed; + enum QDF_OPMODE persona; /* Tells us which persona, GO or AP */ + uint8_t disableDFSChSwitch; + bool enOverLapCh; +#ifdef WLAN_FEATURE_11W + bool mfpRequired; + bool mfpCapable; +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + uint32_t auto_channel_select_weight; + 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; + uint8_t sap_dot11mc; /* Specify if 11MC is enabled or disabled*/ + uint16_t beacon_tx_rate; + uint8_t *vendor_ie; + enum vendor_ie_access_policy vendor_ie_access_policy; + uint16_t sta_inactivity_timeout; + uint16_t tx_pkt_fail_cnt_threshold; + uint8_t short_retry_limit; + uint8_t long_retry_limit; + uint8_t ampdu_size; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + enum sap_acs_dfs_mode acs_dfs_mode; + struct hdd_channel_info *channel_info; + uint32_t channel_info_count; + bool dfs_cac_offload; + /* beacon count before channel switch */ + uint8_t sap_chanswitch_beacon_cnt; + uint8_t sap_chanswitch_mode; + bool chan_switch_hostapd_rate_enabled; + bool dfs_beacon_tx_enhanced; + uint16_t reduced_beacon_interval; +} tsap_config_t; + +#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; + uint8_t sap_radar_found_status; + /* + * New channel to move to when a Radar is + * detected on current Channel + */ + uint8_t target_channel; + uint8_t last_radar_found_channel; + uint8_t ignore_cac; + eSapDfsCACState_t cac_state; + uint8_t user_provided_target_channel; + + /* + * Requests for Channel Switch Announcement IE + * generation and transmission + */ + uint8_t csaIERequired; + uint8_t numCurrentRegDomainDfsChannels; + tSapDfsNolInfo sapDfsChannelNolList[NUM_5GHZ_CHANNELS]; + 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; + + /* + * INI param to enable/disable SAP W53 + * channel operation. + */ + uint8_t is_dfs_w53_disabled; + + /* + * 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; + bool dfs_beacon_tx_enhanced; + uint16_t reduced_beacon_interval; +} tSapDfsInfo; + +typedef struct tagSapCtxList { + uint8_t sessionID; + void *sap_context; + enum QDF_OPMODE sapPersona; +} tSapCtxList, tpSapCtxList; + +typedef struct tagSapStruct { + /* Information Required for SAP DFS Master mode */ + tSapDfsInfo SapDfsInfo; + tSapCtxList 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; + bool enable_etsi13_srd_chan_support; +} tSapStruct, *tpSapStruct; + +typedef struct sap_SoftapStats_s { + uint32_t txUCFcnt; + uint32_t txMCFcnt; + uint32_t txBCFcnt; + uint32_t txUCBcnt; + uint32_t txMCBcnt; + uint32_t txBCBcnt; + uint32_t rxUCFcnt; + uint32_t rxMCFcnt; + uint32_t rxBCFcnt; + uint32_t rxUCBcnt; + uint32_t rxMCBcnt; + uint32_t rxBCBcnt; + uint32_t rxBcnt; + uint32_t rxBcntCRCok; + uint32_t rxRate; +} tSap_SoftapStats, *tpSap_SoftapStats; + +#ifdef FEATURE_WLAN_CH_AVOID +/* Store channel safety information */ +typedef struct { + uint16_t channelNumber; + bool isSafe; +} sapSafeChannelType; +#endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * 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 + * @pContext: sap context + * @pCsrRoamInfo: pointer to SME CSR roam info structure + * @roamId: roam id being used + * @roamStatus: status of the event reported by SME to SAP + * @roamResult: 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 *pContext, + struct csr_roam_info *pCsrRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult); + +/** + * 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 accidently 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 (*tpWLAN_SAPEventCB)(tpSap_Event pSapEvent, + void *pUsrContext); + +/** + * wlansap_is_channel_in_nol_list() - This API checks if channel is + * in nol list + * @sap_ctx: SAP context pointer + * @channelNumber: channel number + * @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, + uint8_t channelNumber, + ePhyChanBondState chanBondState); + +/** + * wlansap_is_channel_leaking_in_nol() - This API checks if channel is leaking + * in nol list + * @sap_ctx: SAP context pointer + * @channel: channel + * @chan_bw: channel bandwidth + * + * Return: True/False + */ +bool wlansap_is_channel_leaking_in_nol(struct sap_context *sap_ctx, + uint8_t channel, + uint8_t chan_bw); + +/** + * wlansap_start_bss() - start BSS + * @sap_ctx: Pointer to the SAP context + * @pSapEventCallback: Callback function in HDD called by SAP to inform HDD + * about SAP results + * @pConfig: Pointer to configuration structure passed down from + * HDD(HostApd for Android) + * @pUsrContext: 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, + tpWLAN_SAPEventCB pSapEventCallback, + tsap_config_t *pConfig, void *pUsrContext); + +/** + * 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); + +/** + * wlan_sap_set_pre_cac_status() - Set the pre cac status + * @sap_ctx: SAP context + * @status: Status of pre cac + * @handle: Global MAC handle + * + * Sets the pre cac status in the MAC context and updates the state + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_set_pre_cac_status(struct sap_context *sap_ctx, + bool status, tHalHandle handle); + +/** + * wlan_sap_set_chan_before_pre_cac() - Save the channel before pre cac + * @sap_ctx: SAP context + * @chan_before_pre_cac: Channel before pre cac + * + * Saves the channel that was in use before pre cac operation + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_set_chan_before_pre_cac(struct sap_context *sap_ctx, + uint8_t chan_before_pre_cac); + +/** + * wlan_sap_set_pre_cac_complete_status() - Sets pre cac complete status + * @sap_ctx: SAP context + * @status: Status of pre cac complete + * + * Sets the status of pre cac i.e., whether pre cac is complete or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_set_pre_cac_complete_status(struct sap_context *sap_ctx, + bool status); + +bool wlan_sap_is_pre_cac_active(tHalHandle handle); +QDF_STATUS wlan_sap_get_pre_cac_vdev_id(tHalHandle handle, uint8_t *vdev_id); +#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 number 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 + * @pConfig: 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, + tsap_config_t *pConfig); + +/** + * 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 + * @pStaCtx : 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 + * @sapContext: Pointer to SAP context + * @targetChannel: Target channel + * @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 *sapContext, + uint32_t targetChannel, + enum phy_ch_width target_bw, + bool strict); + +/** + * wlansap_set_key_sta() - set keys for a stations. + * @sap_ctx: Pointer to the SAP context + * @pSetKeyInfo : tCsrRoamSetKey structure for the station + * + * This api function provides for Ap App/HDD to set key for a station. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_set_key_sta(struct sap_context *sap_ctx, + tCsrRoamSetKey *pSetKeyInfo); + +/** + * 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, + uint8_t *nAcceptList); + +/** + * 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, + uint8_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: white/Black list type. + * @cmd: command to be executed on ACL. + * + * This function is called when a peer needs to be added or deleted from the + * white/black ACL + * + * Return: Status + */ +QDF_STATUS wlansap_modify_acl(struct sap_context *sap_ctx, + uint8_t *peer_sta_mac, + eSapACLType list_type, eSapACLCmdType cmd); + +/** + * wlansap_register_mgmt_frame() - register management frame + * @sap_ctx: Pointer to SAP context + * @frame_type: frame type that needs to be registered with PE. + * @match_data: pointer to data which should be matched after @frame_type + * is matched. + * @match_len: Length of the @match_data + * + * HDD use this API to register specified type of frame with CORE stack. + * On receiving such kind of frame CORE stack should pass this frame to HDD + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise + */ +QDF_STATUS wlansap_register_mgmt_frame(struct sap_context *sap_ctx, + uint16_t frame_type, + uint8_t *match_data, + uint16_t match_len); + +/** + * wlansap_de_register_mgmt_frame() - de register management frame + * @sap_ctx: Pointer to SAP context + * @frame_type: frame type that needs to be de-registered with PE. + * @match_data: pointer to data which should be matched after @frame_type + * is matched. + * @match_len: Length of the @match_data + * + * HDD use this API to deregister a previously registered frame + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise + */ +QDF_STATUS wlansap_de_register_mgmt_frame(struct sap_context *sap_ctx, + uint16_t frame_type, + uint8_t *match_data, + uint16_t match_len); + +/** + * wlansap_channel_change_request() - Send channel change request + * @sapContext: Pointer to the SAP context + * @target_channel: 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 *sapContext, + uint8_t target_channel); + +/** + * wlansap_get_sec_channel() - get the secondary sap channel + * @sec_ch_offset: secondary channel offset. + * @op_channel: Operating sap channel. + * @sec_channel: channel 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, + uint8_t op_channel, + uint8_t *sec_channel); + +/** + * 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); + +QDF_STATUS wlansap_get_dfs_ignore_cac(tHalHandle hHal, uint8_t *pIgnore_cac); +QDF_STATUS wlansap_set_dfs_ignore_cac(tHalHandle hHal, uint8_t ignore_cac); +QDF_STATUS wlansap_set_dfs_restrict_japan_w53(tHalHandle hHal, + uint8_t disable_Dfs_JapanW3); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +QDF_STATUS +wlan_sap_set_channel_avoidance(tHalHandle hal, bool sap_channel_avoidance); +#endif + +QDF_STATUS wlansap_set_dfs_preferred_channel_location(tHalHandle hHal, + uint8_t dfs_Preferred_Channels_location); +QDF_STATUS wlansap_set_dfs_target_chnl(tHalHandle hHal, + uint8_t target_channel); + +/** + * wlan_sap_get_roam_profile() - Returns sap roam profile. + * @sap_ctx: Pointer to Sap Context. + * + * This function provides the SAP roam profile. + * + * Return: SAP RoamProfile + */ +struct csr_roam_profile *wlan_sap_get_roam_profile(struct sap_context *sap_ctx); + +/** + * 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_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_set_vht_ch_width() - Sets SAP VHT channel width. + * @sap_ctx: Pointer to Sap Context + * @vht_channel_width: SAP VHT channel width value. + * + * This function sets the SAP current VHT channel width. + * + * Return: None + */ +void wlan_sap_set_vht_ch_width(struct sap_context *sap_ctx, + uint32_t vht_channel_width); + +/** + * 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, + tsap_config_t *sap_config); + +void sap_config_acs_result(tHalHandle hal, struct sap_context *sap_ctx, + uint32_t sec_ch); + +QDF_STATUS wlansap_update_sap_config_add_ie(tsap_config_t *pConfig, + const uint8_t * + pAdditionIEBuffer, + uint16_t additionIELength, + eUpdateIEsType updateType); +QDF_STATUS wlansap_reset_sap_config_add_ie(tsap_config_t *pConfig, + eUpdateIEsType updateType); +void wlansap_extend_to_acs_range(tHalHandle hal, uint8_t *startChannelNum, + uint8_t *endChannelNum, uint8_t *bandStartChannel, + uint8_t *bandEndChannel); + +/** + * 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_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); + +void wlansap_populate_del_sta_params(const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype, + struct csr_del_sta_params *pDelStaParams); + +/** + * wlansap_acs_chselect() - Initiates acs channel selection + * @sap_context: Pointer to SAP context structure + * @pacs_event_callback: Callback function in hdd called by sap + * to inform hdd about channel selection result + * @pconfig: 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, + tpWLAN_SAPEventCB pacs_event_callback, + tsap_config_t *pconfig, + void *pusr_context); + +/** + * 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_set_tx_leakage_threshold() - set sap tx leakage threshold. + * @hal: HAL pointer + * @tx_leakage_threshold: sap tx leakage threshold + * + * This function set sap tx leakage threshold. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wlansap_set_tx_leakage_threshold(tHalHandle hal, + uint16_t tx_leakage_threshold); + +/* + * 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); + +/** + * 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_set_stop_bss_inprogress - sets the stop_bss_in_progress flag + * + * @sap_ctx: Pointer to the global SAP ctx + * @in_progress: the value to be set to the stop_bss_in_progress_flag + * + * This function sets the value in in_progress parameter to the + * stop_bss_in_progress flag in sap_context. + * + * Return: None + */ +void wlansap_set_stop_bss_inprogress(struct sap_context *sap_ctx, + bool in_progress); + + +/** + * wlansap_filter_ch_based_acs() -filter out channel based on acs + * @sap_ctx: sap context + * @ch_list: pointer to channel list + * @ch_cnt: channel number of channel list + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_filter_ch_based_acs(struct sap_context *sap_ctx, + uint8_t *ch_list, + uint32_t *ch_cnt); + +/** + * wlansap_get_safe_channel_from_pcl_and_acs_range() - Get safe channel for SAP + * restart + * @sap_ctx: sap context + * + * 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: Channel number to restart SAP in case of success. In case of any + * failure, the channel number returned is zero. + */ +uint8_t +wlansap_get_safe_channel_from_pcl_and_acs_range(struct sap_context *sap_ctx); +#ifdef __cplusplus +} +#endif +#endif /* #ifndef WLAN_QCT_WLANSAP_H */ diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_api_link_cntl.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_api_link_cntl.c new file mode 100644 index 0000000000000000000000000000000000000000..5c7c7677ab0cfcae7c7771d1e5f16c755a875e65 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_api_link_cntl.c @@ -0,0 +1,1275 @@ +/* + * 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. + */ + +/*=========================================================================== + + 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 + +/*---------------------------------------------------------------------------- + * 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 + * -------------------------------------------------------------------------*/ + +/** + * sap_config_acs_result : Generate ACS result params based on ch constraints + * @sap_ctx: pointer to SAP context data struct + * @hal: HAL Handle pointer + * + * 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(tHalHandle hal, struct sap_context *sap_ctx, + uint32_t sec_ch) +{ + uint32_t channel = sap_ctx->acs_cfg->pri_ch; + struct ch_params ch_params = {0}; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + ch_params.ch_width = sap_ctx->acs_cfg->ch_width; + wlan_reg_set_channel_params(mac_ctx->pdev, channel, sec_ch, + &ch_params); + sap_ctx->acs_cfg->ch_width = ch_params.ch_width; + if (sap_ctx->acs_cfg->ch_width > CH_WIDTH_40MHZ) + sap_ctx->acs_cfg->vht_seg0_center_ch = + ch_params.center_freq_seg0; + else + sap_ctx->acs_cfg->vht_seg0_center_ch = 0; + + if (sap_ctx->acs_cfg->ch_width == CH_WIDTH_80P80MHZ) + sap_ctx->acs_cfg->vht_seg1_center_ch = + ch_params.center_freq_seg1; + else + sap_ctx->acs_cfg->vht_seg1_center_ch = 0; + + if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch - 4; + else if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch + 4; + else + sap_ctx->acs_cfg->ht_sec_ch = 0; +} + +/** + * 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 (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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"; + } +} + +QDF_STATUS wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle, + struct sap_context *sap_ctx, + uint8_t sessionid, + uint32_t scanid, + eCsrScanStatus scan_status) +{ + tScanResultHandle presult = NULL; + QDF_STATUS scan_get_result_status = QDF_STATUS_E_FAILURE; + uint8_t oper_channel = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + host_log_acs_scan_done(acs_scan_done_status_str(scan_status), + sessionid, scanid); + if (eCSR_SCAN_SUCCESS != scan_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("CSR scan_status = eCSR_SCAN_ABORT/FAILURE (%d), choose default channel"), + scan_status); + oper_channel = + sap_select_default_oper_chan(sap_ctx->acs_cfg); + sap_ctx->channel = oper_channel; + sap_ctx->acs_cfg->pri_ch = oper_channel; + sap_config_acs_result(hal_handle, sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; + goto close_session; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR scan_status = eCSR_SCAN_SUCCESS (%d)"), scan_status); + /* + * Now do + * 1. Get scan results + * 2. Run channel selection algorithm + * select channel and store in sap_context->Channel + */ + scan_get_result_status = sme_scan_get_result(hal_handle, + sap_ctx->sessionId, + NULL, &presult); + if ((scan_get_result_status != QDF_STATUS_SUCCESS) && + (scan_get_result_status != QDF_STATUS_E_NULL_VALUE)) { + /* + * No scan results So, set the operation channel not selected + * to allow the default channel to be set when reporting to HDD + */ + oper_channel = SAP_CHANNEL_NOT_SELECTED; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Get scan result failed! ret = %d"), + scan_get_result_status); + } else { +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (scanid != 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Sending ACS Scan skip event")); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("ACS scanid: %d (skipped ACS SCAN)"), + scanid); + } +#endif + oper_channel = sap_select_channel(hal_handle, sap_ctx, presult); + sme_scan_result_purge(presult); + } + + if (oper_channel == SAP_CHANNEL_NOT_SELECTED) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("No suitable channel, so select default channel")); + sap_ctx->channel = + sap_select_default_oper_chan(sap_ctx->acs_cfg); + sap_ctx->acs_cfg->pri_ch = sap_ctx->channel; + } else { + /* Valid Channel Found from scan results. */ + sap_ctx->acs_cfg->pri_ch = oper_channel; + sap_ctx->channel = oper_channel; + } + sap_config_acs_result(hal_handle, sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel selected = %d"), sap_ctx->channel); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; +close_session: +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_ctx->channelList != NULL) { + /* + * Always free up the memory for + * channel selection whatever + * the result + */ + qdf_mem_free(sap_ctx->channelList); + sap_ctx->channelList = NULL; + sap_ctx->num_of_channel = 0; + } +#endif + sap_hdd_signal_event_handler(sap_ctx); + return status; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + struct sap_context *sap_ctx, + struct csr_roam_info *csr_roam_info, + QDF_STATUS *ret_status) +{ + tWLAN_SAPEvent sap_event; + QDF_STATUS qdf_status; + bool is_ch_dfs = false; + /* + * Channel change is successful. If the new channel is a DFS channel, + * then we will to perform channel availability check for 60 seconds + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: changing target channel to [%d]"), + mac_ctx->sap.SapDfsInfo.target_channel); + sap_ctx->channel = mac_ctx->sap.SapDfsInfo.target_channel; + + /* + * Identify if this is channel change in radar detected state + * Also if we are waiting for sap to stop, don't proceed further + * to restart SAP again. + */ + if ((sap_ctx->fsm_state != SAP_STOPPING) || + sap_ctx->stop_bss_in_progress) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("sapdfs: state [%d] Stop BSS in progress [%d], not starting SAP after channel change"), + sap_ctx->fsm_state, + sap_ctx->stop_bss_in_progress); + return; + } + + if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) { + is_ch_dfs = true; + } else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state(mac_ctx->pdev, + sap_ctx->channel) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state(mac_ctx->pdev, + sap_ctx->ch_params.center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + if (wlan_reg_get_channel_state(mac_ctx->pdev, + sap_ctx->channel) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } + + /* check if currently selected channel is a DFS channel */ + if (is_ch_dfs && sap_ctx->pre_cac_complete) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, FL( + "sapdfs: SAP_STOPPING => SAP_STARTING, on pre cac")); + /* Start beaconing on the new pre cac channel */ + wlansap_start_beacon_req(sap_ctx); + sap_ctx->fsm_state = SAP_STARTING; + mac_ctx->sap.SapDfsInfo.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 ((false == mac_ctx->sap.SapDfsInfo.ignore_cac) + && (eSAP_DFS_DO_NOT_SKIP_CAC == + mac_ctx->sap.SapDfsInfo.cac_state)) { + sap_ctx->fsm_state = SAP_INIT; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: sapdfs: from state SAP_STOPPING => DISCONNECTED with ignore cac false on sapctx[%pK]", + __func__, __LINE__, sap_ctx); + /* 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 { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: sapdfs: from state SAP_STOPPING => SAP_STARTING with ignore cac true on sapctx[%pK]", + __func__, __LINE__, sap_ctx); + + /* Start beaconing on the new channel */ + wlansap_start_beacon_req(sap_ctx); + sap_ctx->fsm_state = SAP_STARTING; + mac_ctx->sap.SapDfsInfo.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 { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: sapdfs: from state SAP_STOPPING => SAP_STARTING on sapctx[%pK]", + __func__, __LINE__, sap_ctx); + /* non-DFS channel */ + sap_ctx->fsm_state = SAP_STARTING; + mac_ctx->sap.SapDfsInfo.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() + * + * @hal: hal global context + * @sap_ctx: sap context + * @ret_status: update return status + * + * Return: void + */ +static void +wlansap_roam_process_dfs_chansw_update(tHalHandle hHal, + struct sap_context *sap_ctx, + QDF_STATUS *ret_status) +{ + tWLAN_SAPEvent sap_event; + uint8_t intf; + QDF_STATUS qdf_status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + uint8_t dfs_beacon_start_req = 0; + bool sap_scc_dfs; + + if (sap_ctx->csr_roamProfile.disableDFSChSwitch) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("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; + sap_ctx->pre_cac_complete = false; + *ret_status = sme_roam_start_beacon_req(hHal, 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 */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + FL("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state"), + sap_ctx->fsm_state); + return; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state SAP_STARTED => SAP_STOPPING")); + /* SAP to be moved to DISCONNECTING state */ + sap_ctx->fsm_state = SAP_STOPPING; + 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_channel) + wlan_reg_set_channel_params(mac_ctx->pdev, + mac_ctx->sap.SapDfsInfo.target_channel, + 0, &sap_ctx->ch_params); + + /* + * 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 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. + * + */ + sap_scc_dfs = sap_is_conc_sap_doing_scc_dfs(hHal, sap_ctx); + if (sap_get_total_number_sap_intf(hHal) <= 1 || + policy_mgr_is_current_hwmode_dbs(mac_ctx->psoc) || + !sap_scc_dfs) { + /* Send channel switch request */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Posting event eWNI_SME_CHANNEL_CHANGE_REQ to sapFSM")); + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + 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(hHal, sap_ctx)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("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) + && (mac_ctx->sap.sapCtxList[intf].sap_context != NULL))) + continue; + sap_context = mac_ctx->sap.sapCtxList[intf].sap_context; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs:issue chnl change for sapctx[%pK]"), + sap_context); + /* Send channel switch request */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + /* Handle event */ + qdf_status = sap_fsm(sap_context, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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(tpAniSirGlobal mac_ctx, + struct sap_context *sap_ctx, + QDF_STATUS *ret_status) +{ + QDF_STATUS qdf_status; + tWLAN_SAPEvent sap_event; + + if (sap_ctx->fsm_state == SAP_DFS_CAC_WAIT) { + if (sap_ctx->csr_roamProfile.disableDFSChSwitch) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "sapdfs: DFS channel switch disabled"); + return; + } + if (false == mac_ctx->sap.SapDfsInfo.sap_radar_found_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "sapdfs: sap_radar_found_status is false"); + return; + } + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("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; + + /* + * 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("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 */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("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); + sap_ctx->SapQosCfg.WmmIsEnabled = csr_roam_info->wmmEnabledSta; + /* 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)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") fail"), + roam_result, MAC_ADDR_ARRAY( + csr_roam_info->peerMac.bytes)); + *ret_status = QDF_STATUS_E_FAILURE; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") not allowed"), + roam_result, + MAC_ADDR_ARRAY(csr_roam_info->peerMac.bytes)); + *ret_status = QDF_STATUS_E_FAILURE; + } + return; +} + +static void wlansap_update_vendor_acs_chan(tpAniSirGlobal mac_ctx, + struct sap_context *sap_ctx) +{ + int intf; + tHalHandle hal; + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null hal")); + return; + } + + mac_ctx->sap.SapDfsInfo.target_channel = + 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_channel != 0) { + mac_ctx->sap.SapDfsInfo.cac_state = + eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hal); + return; + } + /* App failed to provide new channel, try random channel algo */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("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; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("sapdfs: no available channel for sapctx[%pK], StopBss"), + sap_context); + wlansap_stop_bss(sap_context); + } + } +} + +QDF_STATUS +wlansap_roam_callback(void *ctx, struct csr_roam_info *csr_roam_info, + uint32_t roamId, + eRoamCmdStatus roam_status, eCsrRoamResult roam_result) +{ + /* sap_ctx value */ + struct sap_context *sap_ctx; + /* State machine event */ + tWLAN_SAPEvent sap_event; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + tHalHandle hal; + tpAniSirGlobal mac_ctx = NULL; + uint8_t intf; + bool sta_sap_scc_on_dfs_chan; + + if (QDF_IS_STATUS_ERROR(wlansap_context_get(ctx))) + return QDF_STATUS_E_FAILURE; + + sap_ctx = ctx; + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid handle")); + wlansap_context_put(sap_ctx); + return QDF_STATUS_E_NOMEM; + } + + mac_ctx = PMAC_STRUCT(hal); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("roam_status = %d, roam_result = %d"), + roam_status, roam_result); + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(mac_ctx->psoc); + + switch (roam_status) { + case eCSR_ROAM_INFRA_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_INFRA_IND (%d)"), + roam_status); + 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_LOSTLINK (%d)"), + roam_status); + break; + case eCSR_ROAM_MIC_ERROR_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_MIC_ERROR_IND (%d)"), + roam_status); + break; + case eCSR_ROAM_SET_KEY_COMPLETE: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_SET_KEY_COMPLETE (%d)"), + roam_status); + 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_ASSOCIATION_COMPLETION: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_ASSOCIATION_COMPLETION (%d)"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_REASSOC_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_DISASSOCIATED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_DISASSOCIATED (%d)"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_MIC_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_WPS_PBC_PROBE_REQ_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_WPS_PBC_PROBE_REQ_IND (%d)"), + roam_status); + 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received new channel from app")); + wlansap_update_vendor_acs_chan(mac_ctx, sap_ctx); + break; + + case eCSR_ROAM_DFS_RADAR_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "Received Radar Indication on sap ch %d, session %d", + sap_ctx->channel, sap_ctx->sessionId); + + if (sta_sap_scc_on_dfs_chan) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_DEBUG, + FL("Ignore the Radar indication")); + goto EXIT; + } + + if (sap_ctx->fsm_state != SAP_STARTED && + sap_ctx->fsm_state != SAP_DFS_CAC_WAIT) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("Ignore Radar event in sap state %d"), + sap_ctx->fsm_state); + goto EXIT; + } + + if (!sap_chan_bond_dfs_sub_chan( + sap_ctx, sap_ctx->channel, + PHY_CHANNEL_BONDING_STATE_MAX)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "Ignore Radar event for sap ch %d", + sap_ctx->channel); + goto EXIT; + } + + if (sap_ctx->is_pre_cac_on) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("sapdfs: Radar detect on pre cac:%d"), + sap_ctx->sessionId); + 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; + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC, + (void *) eSAP_STATUS_SUCCESS); + break; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("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_channel = + sap_indicate_radar(sap_ctx); + /* if there is an assigned next channel hopping */ + if (0 < mac_ctx->sap.SapDfsInfo.user_provided_target_channel) { + mac_ctx->sap.SapDfsInfo.target_channel = + mac_ctx->sap.SapDfsInfo.user_provided_target_channel; + mac_ctx->sap.SapDfsInfo.user_provided_target_channel = + 0; + } + /* if external acs enabled */ + if (sap_ctx->vendor_acs_dfs_lte_enabled && + !mac_ctx->sap.SapDfsInfo.target_channel) { + /* Return from here, processing will be done later */ + goto EXIT; + } + if (mac_ctx->sap.SapDfsInfo.target_channel != 0) { + mac_ctx->sap.SapDfsInfo.cac_state = + eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hal); + break; + } + /* Issue stopbss for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context; + struct csr_roam_profile *profile; + + 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; + profile = &sap_context->csr_roamProfile; + if (!wlan_reg_is_passive_or_disable_ch( + mac_ctx->pdev, + profile->operationChannel)) + continue; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("sapdfs: no available channel for sapctx[%pK], StopBss"), + sap_context); + 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received Chan Sw Update Notification")); + break; + case eCSR_ROAM_SET_CHANNEL_RSP: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received set channel response")); + /* SAP channel change request processing is completed */ + sap_ctx->is_chan_change_inprogress = false; + break; + case eCSR_ROAM_CAC_COMPLETE_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received cac complete indication")); + break; + case eCSR_ROAM_EXT_CHG_CHNL_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received set channel Indication")); + 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "csr_roam_info is NULL"); + qdf_ret_status = QDF_STATUS_E_NULL_VALUE; + break; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF (%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); + + sap_ctx->SapQosCfg.WmmIsEnabled = + csr_roam_info->wmmEnabledSta; + /* 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_DEAUTH/DISASSOC_IND (%d)"), + roam_result); + /* 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP (%d)"), + roam_result); + /* + * 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST (%d)"), + roam_result); + /* + * 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_AUTHENTICATED (%d)"), + roam_result); + /* 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_ASSOCIATED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_ASSOCIATED (%d)"), + roam_result); + /* Fill in the event structure */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_REASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_INFRA_STARTED: + if (!csr_roam_info) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "csr_roam_info is NULL"); + qdf_ret_status = QDF_STATUS_E_NULL_VALUE; + break; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STARTED (%d)"), + roam_result); + /* + * 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STOPPED (%d)"), + roam_result); + /* 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND (%d)"), + roam_result); + /* + * 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_FORCED (%d)"), + roam_result); + /* + * 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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_NONE (%d)"), + roam_result); + /* + * 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); + break; + case eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED (%d)"), + roam_result); + /* 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 (sta_sap_scc_on_dfs_chan) + break; + wlansap_roam_process_dfs_radar_found(mac_ctx, sap_ctx, + &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS: + wlansap_roam_process_dfs_chansw_update(hal, sap_ctx, + &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_CAC_END_IND: + sap_dfs_cac_timer_callback(hal); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS: + wlansap_roam_process_ch_change_success(mac_ctx, sap_ctx, + csr_roam_info, &qdf_ret_status); + + qdf_ret_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_CHANNEL_CHANGE_RESP, + (void *)QDF_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE: + /* This is much more serious issue, we have to vacate the + * channel due to the presence of radar but our channel change + * failed, stop the BSS operation completely and inform hostapd + */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_RSP; + sap_event.params = 0; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE; + + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + + qdf_ret_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_CHANNEL_CHANGE_RESP, + (void *)QDF_STATUS_E_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: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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; + tHalHandle hal_handle; + + session_id = wlan_vdev_get_id(vdev); + scan_id = event->scan_id; + hal_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!hal_handle) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + FL("invalid h_hal")); + 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(hal_handle, + arg, session_id, + scan_id, scan_status); +} diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.c new file mode 100644 index 0000000000000000000000000000000000000000..c87745243290045777ff9f1479865b7065e7107f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.c @@ -0,0 +1,2796 @@ +/* + * 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. + */ + +/*=========================================================================== + + 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" +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#include "cds_utils.h" +#include "pld_common.h" +#include "wlan_reg_services_api.h" + +/*-------------------------------------------------------------------------- + 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 <= 14 && \ + sap_ctx->acs_cfg->end_ch <= 14) \ + acs_band = eCSR_DOT11_MODE_11g; \ + else if (sap_ctx->acs_cfg->start_ch >= 14)\ + 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)) + +/* + * 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) + +#ifdef FEATURE_WLAN_CH_AVOID +sapSafeChannelType safe_channels[NUM_CHANNELS] = { + {1, true}, + {2, true}, + {3, true}, + {4, true}, + {5, true}, + {6, true}, + {7, true}, + {8, true}, + {9, true}, + {10, true}, + {11, true}, + {12, true}, + {13, true}, + {14, true}, + {36, true}, + {40, true}, + {44, true}, + {48, true}, + {52, true}, + {56, true}, + {60, true}, + {64, true}, + {100, true}, + {104, true}, + {108, true}, + {112, true}, + {116, true}, + {120, true}, + {124, true}, + {128, true}, + {132, true}, + {136, true}, + {140, true}, + {144, true}, + {149, true}, + {153, true}, + {157, true}, + {161, true}, + {165, true}, + {169, true}, + {173, true}, +}; +#endif + +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_chnl: 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 + * @hal: hal handle + * @sap_ctx: sap context. + * @scan_result: 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(tHalHandle hal, + struct sap_context *sap_ctx, + tScanResultHandle scan_result, + tSapChSelSpectInfo *spect_info) +{ + uint32_t total_ie_len = 0; + uint8_t *temp_ptr = NULL; + uint8_t i = 0; + struct sAvoidChannelIE *avoid_ch_ie; + tCsrScanResultInfo *node = NULL; + tpAniSirGlobal mac_ctx = NULL; + tSapSpectChInfo *spect_ch = NULL; + + mac_ctx = PMAC_STRUCT(hal); + spect_ch = spect_info->pSpectCh; + node = sme_scan_result_get_first(hal, scan_result); + + while (node) { + total_ie_len = + GET_IE_LEN_IN_BSS(node->BssDescriptor.length); + temp_ptr = wlan_get_vendor_ie_ptr_from_oui( + SIR_MAC_QCOM_VENDOR_OUI, + SIR_MAC_QCOM_VENDOR_SIZE, + ((uint8_t *)&node->BssDescriptor.ieFields), + total_ie_len); + + if (temp_ptr) { + avoid_ch_ie = (struct sAvoidChannelIE *)temp_ptr; + if (avoid_ch_ie->type != + QCOM_VENDOR_IE_MCC_AVOID_CH) { + node = sme_scan_result_get_next(hal, + scan_result); + continue; + } + + sap_ctx->sap_detected_avoid_ch_ie.present = 1; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_DEBUG, + "Q2Q IE - avoid ch %d", + avoid_ch_ie->channel); + /* 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->numSpectChans; i++) + if (spect_ch[i].chNum == avoid_ch_ie->channel) { + /* + * 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; + } + } /* if (temp_ptr) */ + node = sme_scan_result_get_next(hal, scan_result); + } +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#ifdef FEATURE_WLAN_CH_AVOID +/*========================================================================== + FUNCTION sap_update_unsafe_channel_list + + DESCRIPTION + Function Undate unsafe channel list table + + DEPENDENCIES + NA. + + IN + SapContext pointer + + RETURN VALUE + NULL + ============================================================================*/ +void sap_update_unsafe_channel_list(tHalHandle hal, struct sap_context *sap_ctx) +{ + uint16_t i, j; + uint16_t unsafe_channel_list[NUM_CHANNELS]; + uint16_t unsafe_channel_count = 0; + tpAniSirGlobal mac_ctx = NULL; + + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + "qdf_ctx is NULL"); + return; + } + mac_ctx = PMAC_STRUCT(hal); + + /* Flush, default set all channel safe */ + for (i = 0; i < NUM_CHANNELS; i++) { + safe_channels[i].isSafe = true; + } + + /* Try to find unsafe channel */ +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) + for (i = 0; i < NUM_CHANNELS; i++) { + if (sap_ctx->dfs_ch_disable == true) { + if (wlan_reg_is_dfs_ch(mac_ctx->pdev, + safe_channels[i].channelNumber)) { + safe_channels[i].isSafe = false; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: DFS Ch %d is not safe in" + " Concurrent mode", + __func__, + safe_channels[i].channelNumber); + } + } + } +#endif + pld_get_wlan_unsafe_channel(qdf_ctx->dev, + unsafe_channel_list, + &unsafe_channel_count, + sizeof(unsafe_channel_list)); + + unsafe_channel_count = QDF_MIN(unsafe_channel_count, + (uint16_t)NUM_CHANNELS); + + for (i = 0; i < unsafe_channel_count; i++) { + for (j = 0; j < NUM_CHANNELS; j++) { + if (safe_channels[j].channelNumber == + unsafe_channel_list[i]) { + /* Found unsafe channel, update it */ + safe_channels[j].isSafe = false; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("CH %d is not safe"), + unsafe_channel_list[i]); + break; + } + } + } + + return; +} + +#endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * sap_channel_in_acs_channel_list() - check if channel in acs channel list + * @channel_num: channel to check + * @sap_ctx: struct ptSapContext + * @spect_info_params: strcut tSapChSelSpectInfo + * + * This function checks if specified channel is in the configured ACS channel + * list. + * + * Return: channel number if in acs channel list or SAP_CHANNEL_NOT_SELECTED + */ +uint8_t sap_channel_in_acs_channel_list(uint8_t channel_num, + struct sap_context *sap_ctx, + tSapChSelSpectInfo *spect_info_params) +{ + uint8_t i = 0; + + if ((NULL == sap_ctx->acs_cfg->master_ch_list) || + (NULL == spect_info_params)) + return channel_num; + + if (channel_num > 0 && channel_num <= 252) { + for (i = 0; i < sap_ctx->acs_cfg->master_ch_list_count; i++) { + if ((sap_ctx->acs_cfg->master_ch_list[i]) == + channel_num) + return channel_num; + } + return SAP_CHANNEL_NOT_SELECTED; + } else { + return SAP_CHANNEL_NOT_SELECTED; + } +} + +/** + * sap_select_preferred_channel_from_channel_list() - to calc best cahnnel + * @best_chnl: best channel already calculated among all the chanels + * @sap_ctx: sap context + * @spectinfo_param: Pointer to tSapChSelSpectInfo 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: uint8_t best channel + */ +static +uint8_t sap_select_preferred_channel_from_channel_list(uint8_t best_chnl, + struct sap_context *sap_ctx, + tSapChSelSpectInfo *spectinfo_param) +{ + uint8_t i = 0; + tpAniSirGlobal mac_ctx = sme_get_mac_context(); + + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "pmac Global Context is NULL"); + return SAP_CHANNEL_NOT_SELECTED; + } + + /* + * If Channel List is not Configured don't do anything + * Else return the Best Channel from the Channel List + */ + if ((NULL == sap_ctx->acs_cfg->ch_list) || + (NULL == spectinfo_param) || + (0 == sap_ctx->acs_cfg->ch_list_count)) + return best_chnl; + + if (best_chnl <= 0 || best_chnl > 252) + return SAP_CHANNEL_NOT_SELECTED; + + /* Select the best channel from allowed list */ + for (i = 0; i < sap_ctx->acs_cfg->ch_list_count; i++) { + if ((sap_ctx->acs_cfg->ch_list[i] == best_chnl) && + !(wlan_reg_is_dfs_ch(mac_ctx->pdev, best_chnl) && + policy_mgr_disallow_mcc(mac_ctx->psoc, best_chnl))) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "Best channel so far is: %d", + best_chnl); + return best_chnl; + } + } + + return SAP_CHANNEL_NOT_SELECTED; +} + +/*========================================================================== + FUNCTION sap_chan_sel_init + + DESCRIPTION + Function sap_chan_sel_init allocates the memory, initializes the + structures used by the channel selection algorithm + + DEPENDENCIES + NA. + + PARAMETERS + + IN + halHandle : Pointer to tHalHandle + *pSpectInfoParams : Pointer to tSapChSelSpectInfo structure + sap_ctx : Pointer to SAP Context + + RETURN VALUE + bool: Success or FAIL + + SIDE EFFECTS + ============================================================================*/ +static bool sap_chan_sel_init(tHalHandle halHandle, + tSapChSelSpectInfo *pSpectInfoParams, + struct sap_context *sap_ctx) +{ + tSapSpectChInfo *pSpectCh = NULL; + uint8_t *pChans = NULL; + uint16_t channelnum = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(halHandle); + bool chSafe = true; +#ifdef FEATURE_WLAN_CH_AVOID + uint16_t i; +#endif + uint32_t dfs_master_cap_enabled; + bool include_dfs_ch = true; + uint8_t chan_num; + bool sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(pMac->psoc); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, "In %s", + __func__); + + pSpectInfoParams->numSpectChans = + pMac->scan.base_channels.numChannels; + + /* Allocate memory for weight computation of 2.4GHz */ + pSpectCh = + (tSapSpectChInfo *)qdf_mem_malloc( + (pSpectInfoParams->numSpectChans) * + sizeof(*pSpectCh)); + + if (pSpectCh == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s, QDF_MALLOC_ERR", __func__); + return false; + } + + /* Initialize the pointers in the DfsParams to the allocated memory */ + pSpectInfoParams->pSpectCh = pSpectCh; + + pChans = pMac->scan.base_channels.channelList; + +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) + if (sap_ctx->dfs_ch_disable == true) + include_dfs_ch = false; +#endif + sme_cfg_get_int(halHandle, WNI_CFG_DFS_MASTER_ENABLED, + &dfs_master_cap_enabled); + if (dfs_master_cap_enabled == 0 || + 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 (channelnum = 0; + channelnum < pSpectInfoParams->numSpectChans; + channelnum++, pChans++, pSpectCh++) { + chSafe = true; + + pSpectCh->chNum = *pChans; + /* Initialise for all channels */ + pSpectCh->rssiAgr = SOFTAP_MIN_RSSI; + /* Initialise 20MHz for all the Channels */ + pSpectCh->channelWidth = SOFTAP_HT20_CHANNELWIDTH; + /* Initialise max ACS weight for all channels */ + pSpectCh->weight = SAP_ACS_WEIGHT_MAX; + + /* check if the channel is in NOL blacklist */ + if (sap_dfs_is_channel_in_nol_list( + sap_ctx, *pChans, + PHY_SINGLE_CHANNEL_CENTERED)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Ch %d is in NOL list", __func__, + *pChans); + chSafe = false; + continue; + } + + if (!include_dfs_ch || sta_sap_scc_on_dfs_chan) { + if (wlan_reg_is_dfs_ch(pMac->pdev, *pChans)) { + chSafe = false; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, DFS Ch %d not considered for ACS. include_dfs_ch %u, sta_sap_scc_on_dfs_chan %d", + __func__, *pChans, include_dfs_ch, + sta_sap_scc_on_dfs_chan); + continue; + } + } + +#ifdef FEATURE_WLAN_CH_AVOID + for (i = 0; i < NUM_CHANNELS; i++) { + if ((safe_channels[i].channelNumber == *pChans) && + (false == safe_channels[i].isSafe)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Ch %d is not safe", __func__, + *pChans); + chSafe = false; + break; + } + } +#endif /* FEATURE_WLAN_CH_AVOID */ + + /* OFDM rates are not supported on channel 14 */ + if (*pChans == 14 && + eCSR_DOT11_MODE_11b != sap_ctx->csr_roamProfile.phyMode) { + continue; + } + + /* Skip DSRC channels */ + if (wlan_reg_is_dsrc_chan(pMac->pdev, *pChans)) + continue; + + if (!pMac->sap.enable_etsi13_srd_chan_support && + wlan_reg_is_etsi13_srd_chan(pMac->pdev, *pChans)) + continue; + + if (true == chSafe) { + pSpectCh->valid = true; + for (chan_num = 0; chan_num < sap_ctx->num_of_channel; + chan_num++) { + if (pSpectCh->chNum != + sap_ctx->channelList[chan_num]) + continue; + + /* + * Initialize ACS weight to 0 for channels + * present in sap context scan channel list + */ + pSpectCh->weight = 0; + break; + } + } + } + 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 receieved 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; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, rssiWeight=%d, countWeight=%d, rssicountWeight=%d", + __func__, rssiWeight, countWeight, rssicountWeight); + + return rssicountWeight; +} + +/** + * sap_get_channel_status() - get channel info via channel number + * @p_mac: Pointer to Global MAC structure + * @channel_id: channel id + * + * Return: chan status info + */ +static struct lim_channel_status *sap_get_channel_status + (tpAniSirGlobal p_mac, uint32_t channel_id) +{ + return csr_get_channel_status(p_mac, channel_id); +} + +/** + * sap_clear_channel_status() - clear chan info + * @p_mac: Pointer to Global MAC structure + * + * Return: none + */ +static void sap_clear_channel_status(tpAniSirGlobal p_mac) +{ + csr_clear_channel_status(p_mac); +} + +/** + * sap_weight_channel_noise_floor() - compute noise floor weight + * @sap_ctx: sap context + * @chn_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 lim_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 == NULL || channel_stat->channelfreq == 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "In %s, sanity check failed return max weight", + __func__); + 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; + else if (noise_floor_weight < 0) + noise_floor_weight = 0; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, nf=%d, nfwc=%d, nfwl=%d, nfw=%d", + __func__, channel_stat->noise_floor, + softap_nf_weight_cfg, softap_nf_weight_local, + noise_floor_weight); + + return noise_floor_weight; +} + +/** + * sap_weight_channel_free() - compute channel free weight + * @sap_ctx: sap context + * @chn_stat: Pointer to chan status info + * + * Return: channel free weight + */ +static uint32_t sap_weight_channel_free(struct sap_context *sap_ctx, + struct lim_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 == NULL || channel_stat->channelfreq == 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "In %s, sanity check failed return max weight", + __func__); + 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; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, rcc=%d, cc=%d, tc=%d, rc=%d, cfwc=%d, cfwl=%d, cfw=%d", + __func__, 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 + * @chn_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 lim_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 == NULL || channel_stat->channelfreq == 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "In %s, sanity check failed return max weight", + __func__); + 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; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, tpr=%d, tprwc=%d, tprwl=%d, tprw=%d", + __func__, 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 + * @chn_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 lim_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 == NULL || channel_stat->channelfreq == 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "In %s, sanity check failed return max weight", + __func__); + 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; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, tpt=%d, tptwc=%d, tptwl=%d, tptw=%d", + __func__, 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 + * @chn_stat: Pointer to chan status info + * + * Return: chan status weight + */ +static +uint32_t sap_weight_channel_status(struct sap_context *sap_ctx, + struct lim_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_check_channels_same_band() - Check if two channels belong to same band + * @ch_num1: channel number + * @ch_num2: channel number + * + * Return: true if both channels belong to same band else false + */ +static bool sap_check_channels_same_band(uint16_t ch_num1, uint16_t ch_num2) +{ + if ((ch_num1 <= SIR_11B_CHANNEL_END && + ch_num2 <= SIR_11B_CHANNEL_END) || + (ch_num1 >= SIR_11A_CHANNEL_BEGIN && + ch_num2 >= SIR_11A_CHANNEL_BEGIN)) + return true; + + return false; +} + +/** + * sap_update_rssi_bsscount() - updates bss count and rssi effect. + * + * @pSpectCh: Channel Information + * @offset: Channel Offset + * @sap_24g: Channel is in 2.4G or 5G + * @spectch_start: the start of spect ch array + * @spectch_end: the end of spect ch array + * + * sap_update_rssi_bsscount updates bss count and rssi effect based + * on the channel offset. + * + * Return: None. + */ + +static void sap_update_rssi_bsscount(tSapSpectChInfo *pSpectCh, int32_t offset, + bool sap_24g, tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_end) +{ + tSapSpectChInfo *pExtSpectCh = NULL; + int32_t rssi, rsssi_effect; + + pExtSpectCh = (pSpectCh + offset); + if (pExtSpectCh != NULL && + pExtSpectCh >= spectch_start && + pExtSpectCh < spectch_end) { + if (!sap_check_channels_same_band(pSpectCh->chNum, + pExtSpectCh->chNum)) + return; + ++pExtSpectCh->bssCount; + 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 = pSpectCh->rssiAgr + rsssi_effect; + if (IS_RSSI_VALID(pExtSpectCh->rssiAgr, rssi)) + pExtSpectCh->rssiAgr = rssi; + if (pExtSpectCh->rssiAgr < SOFTAP_MIN_RSSI) + pExtSpectCh->rssiAgr = SOFTAP_MIN_RSSI; + } +} + +/** + * sap_upd_chan_spec_params() - sap_upd_chan_spec_params + * updates channel parameters obtained from Beacon + * @pBeaconStruct Beacon strucutre populated by parse_beacon function + * @channelWidth Channel width + * @secondaryChannelOffset Secondary Channel Offset + * @vhtSupport If channel supports VHT + * @centerFreq Central frequency for the given channel. + * + * sap_upd_chan_spec_params updates the spectrum channels based on the + * pBeaconStruct obtained from Beacon IE + * + * Return: NA. + */ + +static void sap_upd_chan_spec_params(tSirProbeRespBeacon *pBeaconStruct, + uint16_t *channelWidth, + uint16_t *secondaryChannelOffset, + uint16_t *vhtSupport, + uint16_t *centerFreq, + uint16_t *centerFreq_2) +{ + if (NULL == pBeaconStruct) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("pBeaconStruct is NULL")); + return; + } + + if (pBeaconStruct->HTCaps.present && pBeaconStruct->HTInfo.present) { + *channelWidth = pBeaconStruct->HTCaps.supportedChannelWidthSet; + *secondaryChannelOffset = + pBeaconStruct->HTInfo.secondaryChannelOffset; + if (!pBeaconStruct->VHTOperation.present) + return; + *vhtSupport = pBeaconStruct->VHTOperation.present; + if (pBeaconStruct->VHTOperation.chanWidth) { + *centerFreq = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + *centerFreq_2 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + /* + * LHS follows tSirMacHTChannelWidth, while RHS follows + * WNI_CFG_VHT_CHANNEL_WIDTH_X format hence following + * adjustment + */ + *channelWidth = + pBeaconStruct->VHTOperation.chanWidth + 1; + + } + } +} + +/** + * sap_update_rssi_bsscount_vht_5G() - updates bss count and rssi effect. + * + * @spect_ch: Channel Information + * @offset: Channel Offset + * @num_ch: no.of channels + * @spectch_start: the start of spect ch array + * @spectch_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(tSapSpectChInfo *spect_ch, + int32_t offset, + uint16_t num_ch, + tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_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, + spectch_start, spectch_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 + * @center_freq: Central frequency for the given channel. + * @channel_id: channel_id + * @spectch_start: the start of spect ch array + * @spectch_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(tSapSpectChInfo *spect_ch, + uint16_t chan_width, + uint16_t sec_chan_offset, + uint16_t center_freq, + uint16_t center_freq_2, + uint8_t channel_id, + tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_end) +{ + uint16_t num_ch; + int32_t offset = 0; + + if (NULL == spect_ch) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("spect_ch is NULL")); + return; + } + + /* Updating the received ChannelWidth */ + if (spect_ch->channelWidth != chan_width) + spect_ch->channelWidth = chan_width; + /* If received ChannelWidth is other than HT20, + * we need to update the extension channel Params as well + * chan_width == 0, HT20 + * chan_width == 1, HT40 + * chan_width == 2, VHT80 + * chan_width == 3, VHT160 + */ + + switch (spect_ch->channelWidth) { + case eHT_CHANNEL_WIDTH_40MHZ: /* HT40 */ + switch (sec_chan_offset) { + /* Above the Primary Channel */ + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + sap_update_rssi_bsscount(spect_ch, 1, false, + spectch_start, spectch_end); + return; + + /* Below the Primary channel */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + sap_update_rssi_bsscount(spect_ch, -1, false, + spectch_start, spectch_end); + return; + } + return; + case eHT_CHANNEL_WIDTH_80MHZ: /* VHT80 */ + num_ch = 3; + if ((center_freq - channel_id) == 6) { + offset = 1; + } else if ((center_freq - channel_id) == 2) { + offset = -1; + } else if ((center_freq - channel_id) == -2) { + offset = -2; + } else if ((center_freq - channel_id) == -6) { + offset = -3; + } + break; + case eHT_CHANNEL_WIDTH_160MHZ: /* VHT160 */ + num_ch = 7; + if ((center_freq - channel_id) == 14) + offset = 1; + else if ((center_freq - channel_id) == 10) + offset = -1; + else if ((center_freq - channel_id) == 6) + offset = -2; + else if ((center_freq - channel_id) == 2) + offset = -3; + else if ((center_freq - channel_id) == -2) + offset = -4; + else if ((center_freq - channel_id) == -6) + offset = -5; + else if ((center_freq - channel_id) == -10) + offset = -6; + else if ((center_freq - channel_id) == -14) + offset = -7; + break; + default: + return; + } + sap_update_rssi_bsscount_vht_5G(spect_ch, offset, num_ch, + spectch_start, spectch_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 + * @spectch_start: the start of spect ch array + * @spectch_end: the end of spect ch array + * + * 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(tSapSpectChInfo *spect_ch, + tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_end) +{ + if (NULL == spect_ch) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: spect_ch is NULL", __func__); + return; + } + + switch (spect_ch->chNum) { + case CHANNEL_1: + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + + case CHANNEL_2: + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + case CHANNEL_3: + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + case CHANNEL_4: + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_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, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + + case CHANNEL_11: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + break; + + case CHANNEL_12: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + break; + + case CHANNEL_13: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + break; + + case CHANNEL_14: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + break; + + default: + break; + } +} + +/** + * ch_in_pcl() - Is channel in the Preferred Channel List (PCL) + * @sap_ctx: SAP context which contains the current PCL + * @channel: Input channel number to be checked + * + * Check if a channel is in the preferred channel list + * + * Return: + * true: channel is in PCL, + * false: channel is not in PCL + */ +static bool ch_in_pcl(struct sap_context *sap_ctx, uint8_t channel) +{ + uint32_t i; + + for (i = 0; i < sap_ctx->acs_cfg->pcl_ch_count; i++) { + if (channel == sap_ctx->acs_cfg->pcl_channels[i]) + return true; + } + + return false; +} + +/** + * sap_compute_spect_weight() - Compute spectrum weight + * @pSpectInfoParams: Pointer to the tSpectInfoParams structure + * @halHandle: Pointer to HAL handle + * @pResult: Pointer to tScanResultHandle + * @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(tSapChSelSpectInfo *pSpectInfoParams, + tHalHandle halHandle, + tScanResultHandle pResult, + struct sap_context *sap_ctx) +{ + int8_t rssi = 0; + uint8_t chn_num = 0; + uint8_t channel_id = 0; + tCsrScanResultInfo *pScanResult; + tSapSpectChInfo *pSpectCh = pSpectInfoParams->pSpectCh; + uint32_t operatingBand; + uint16_t channelWidth; + uint16_t secondaryChannelOffset; + uint16_t centerFreq; + uint8_t i; + bool found; + uint16_t centerFreq_2 = 0; + uint16_t vhtSupport; + uint32_t ieLen = 0; + tSirProbeRespBeacon *pBeaconStruct; + tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle; + tSapSpectChInfo *spectch_start = pSpectInfoParams->pSpectCh; + tSapSpectChInfo *spectch_end = pSpectInfoParams->pSpectCh + + pSpectInfoParams->numSpectChans; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == pBeaconStruct) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "Unable to allocate memory in sap_compute_spect_weight"); + return; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Computing spectral weight", __func__); + + /** + * Soft AP specific channel weight calculation using DFS formula + */ + SET_ACS_BAND(operatingBand, sap_ctx); + + pScanResult = sme_scan_result_get_first(halHandle, pResult); + + while (pScanResult) { + pSpectCh = pSpectInfoParams->pSpectCh; + /* Defining the default values, so that any value will hold the default values */ + channelWidth = eHT_CHANNEL_WIDTH_20MHZ; + secondaryChannelOffset = PHY_SINGLE_CHANNEL_CENTERED; + vhtSupport = 0; + centerFreq = 0; + + + ieLen = GET_IE_LEN_IN_BSS( + pScanResult->BssDescriptor.length); + qdf_mem_zero((uint8_t *) pBeaconStruct, + sizeof(tSirProbeRespBeacon)); + + + if ((sir_parse_beacon_ie + (pMac, pBeaconStruct, (uint8_t *) + (pScanResult->BssDescriptor.ieFields), + ieLen)) == QDF_STATUS_SUCCESS) + sap_upd_chan_spec_params( + pBeaconStruct, + &channelWidth, + &secondaryChannelOffset, + &vhtSupport, ¢erFreq, + ¢erFreq_2); + + /* Processing for each tCsrScanResultInfo in the tCsrScanResult DLink list */ + for (chn_num = 0; chn_num < pSpectInfoParams->numSpectChans; + chn_num++) { + + /* + * If the Beacon has channel ID, use it other wise we + * will rely on the channelIdSelf + */ + if (pScanResult->BssDescriptor.channelId == 0) + channel_id = + pScanResult->BssDescriptor.channelIdSelf; + else + channel_id = + pScanResult->BssDescriptor.channelId; + + if (pSpectCh && (channel_id == pSpectCh->chNum)) { + if (pSpectCh->rssiAgr < + pScanResult->BssDescriptor.rssi) + pSpectCh->rssiAgr = + pScanResult->BssDescriptor.rssi; + + ++pSpectCh->bssCount; /* Increment the count of BSS */ + + /* + * Connsidering the Extension Channel + * only in a channels + */ + switch (operatingBand) { + case eCSR_DOT11_MODE_11a: + sap_interference_rssi_count_5G( + pSpectCh, channelWidth, + secondaryChannelOffset, + centerFreq, + centerFreq_2, + channel_id, + spectch_start, + spectch_end); + break; + + case eCSR_DOT11_MODE_11g: + sap_interference_rssi_count(pSpectCh, + spectch_start, spectch_end); + break; + + case eCSR_DOT11_MODE_abg: + if (pSpectCh->chNum >= + SIR_11A_CHANNEL_BEGIN) + sap_interference_rssi_count_5G( + pSpectCh, channelWidth, + secondaryChannelOffset, + centerFreq, + centerFreq_2, + channel_id, + spectch_start, + spectch_end); + else + sap_interference_rssi_count( + pSpectCh, + spectch_start, + spectch_end); + break; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, bssdes.ch_self=%d, bssdes.ch_ID=%d, bssdes.rssi=%d, SpectCh.bssCount=%d, pScanResult=%pK, ChannelWidth %d, secondaryChanOffset %d, center frequency %d", + __func__, + pScanResult->BssDescriptor. + channelIdSelf, + pScanResult->BssDescriptor.channelId, + pScanResult->BssDescriptor.rssi, + pSpectCh->bssCount, pScanResult, + pSpectCh->channelWidth, + secondaryChannelOffset, centerFreq); + pSpectCh++; + break; + } else { + pSpectCh++; + } + } + + pScanResult = sme_scan_result_get_next(halHandle, pResult); + } + + /* Calculate the weights for all channels in the spectrum pSpectCh */ + pSpectCh = pSpectInfoParams->pSpectCh; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Spectrum Channels Weight", __func__); + + for (chn_num = 0; chn_num < (pSpectInfoParams->numSpectChans); + chn_num++) { + + /* + rssi : Maximum received signal strength among all BSS on that channel + bssCount : Number of BSS on that channel + */ + + rssi = (int8_t) pSpectCh->rssiAgr; + if (ch_in_pcl(sap_ctx, pSpectCh->chNum)) + rssi -= PCL_RSSI_DISCOUNT; + + if (rssi < SOFTAP_MIN_RSSI) + rssi = SOFTAP_MIN_RSSI; + + if (pSpectCh->weight == SAP_ACS_WEIGHT_MAX) { + pSpectCh->weight_copy = pSpectCh->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 + * channles which were included in ACS scan list + */ + found = false; + for (i = 0; i < sap_ctx->num_of_channel; i++) { + if (pSpectCh->chNum == sap_ctx->channelList[i]) { + /* Scan channel was included in ACS scan list */ + found = true; + break; + } + } + + if (found) + pSpectCh->weight = + SAPDFS_NORMALISE_1000 * + (sapweight_rssi_count(sap_ctx, rssi, + pSpectCh->bssCount) + sap_weight_channel_status( + sap_ctx, sap_get_channel_status(pMac, + pSpectCh->chNum))); + else { + pSpectCh->weight = SAP_ACS_WEIGHT_MAX; + pSpectCh->rssiAgr = SOFTAP_MIN_RSSI; + rssi = SOFTAP_MIN_RSSI; + pSpectCh->bssCount = SOFTAP_MIN_COUNT; + } + + if (pSpectCh->weight > SAP_ACS_WEIGHT_MAX) + pSpectCh->weight = SAP_ACS_WEIGHT_MAX; + pSpectCh->weight_copy = pSpectCh->weight; + +debug_info: + /* ------ Debug Info ------ */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Chan=%d Weight= %d rssiAgr=%d rssi_pcl_discount: %d bssCount=%d", + __func__, pSpectCh->chNum, pSpectCh->weight, + pSpectCh->rssiAgr, rssi, pSpectCh->bssCount); + host_log_acs_chan_spect_weight(pSpectCh->chNum, + (uint16_t)pSpectCh->weight, + pSpectCh->rssiAgr, + pSpectCh->bssCount); + /* ------ Debug Info ------ */ + pSpectCh++; + } + sap_clear_channel_status(pMac); + qdf_mem_free(pBeaconStruct); +} + +/*========================================================================== + FUNCTION sap_chan_sel_exit + + DESCRIPTION + Exit function for free out the allocated memory, to be called + at the end of the dfsSelectChannel function + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_chan_sel_exit(tSapChSelSpectInfo *pSpectInfoParams) +{ + /* Free all the allocated memory */ + qdf_mem_free(pSpectInfoParams->pSpectCh); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight + + DESCRIPTION + Function to sort the channels with the least weight first for 20MHz channels + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_sort_chl_weight(tSapChSelSpectInfo *pSpectInfoParams) +{ + tSapSpectChInfo temp; + + tSapSpectChInfo *pSpectCh = NULL; + uint32_t i = 0, j = 0, minWeightIndex = 0; + + pSpectCh = pSpectInfoParams->pSpectCh; + for (i = 0; i < pSpectInfoParams->numSpectChans; i++) { + minWeightIndex = i; + for (j = i + 1; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectCh[j].weight < + pSpectCh[minWeightIndex].weight) { + minWeightIndex = j; + } else if (pSpectCh[j].weight == + pSpectCh[minWeightIndex].weight) { + if (pSpectCh[j].bssCount < + pSpectCh[minWeightIndex].bssCount) + minWeightIndex = j; + } + } + if (minWeightIndex != i) { + qdf_mem_copy(&temp, &pSpectCh[minWeightIndex], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[minWeightIndex], &pSpectCh[i], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[i], &temp, sizeof(*pSpectCh)); + } + } +} + +/** + * set_ht80_chl_bit() - to set available channel to ht80 channel bitmap + * @channel_bitmap: Pointer to the chan_bonding_bitmap structure + * @spect_info_params: Pointer to the tSapChSelSpectInfo structure + * + * Return: none + */ +static void set_ht80_chl_bit(chan_bonding_bitmap *channel_bitmap, + tSapChSelSpectInfo *spec_info_params) +{ + uint8_t i, j; + tSapSpectChInfo *spec_info; + int start_channel = 0; + + channel_bitmap->chanBondingSet[0].startChannel = + acs_ht80_channels[0].chStartNum; + channel_bitmap->chanBondingSet[1].startChannel = + acs_ht80_channels[1].chStartNum; + channel_bitmap->chanBondingSet[2].startChannel = + acs_ht80_channels[2].chStartNum; + channel_bitmap->chanBondingSet[3].startChannel = + acs_ht80_channels[3].chStartNum; + channel_bitmap->chanBondingSet[4].startChannel = + acs_ht80_channels[4].chStartNum; + channel_bitmap->chanBondingSet[5].startChannel = + acs_ht80_channels[5].chStartNum; + + spec_info = spec_info_params->pSpectCh; + for (j = 0; j < spec_info_params->numSpectChans; j++) { + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = + channel_bitmap->chanBondingSet[i].startChannel; + if (spec_info[j].chNum >= start_channel && + (spec_info[j].chNum <= start_channel + 12)) { + channel_bitmap->chanBondingSet[i].channelMap |= + 1 << ((spec_info[j].chNum - + start_channel)/4); + break; + } + } + } +} + +/** + * sap_sort_chl_weight_ht80() - to sort the channels with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Function to sort the channels with the least weight first for HT80 channels + * + * Return: none + */ +static void sap_sort_chl_weight_ht80(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j, n; + tSapSpectChInfo *pSpectInfo; + uint8_t minIdx; + int start_channel = 0; + chan_bonding_bitmap *channel_bitmap; + + channel_bitmap = qdf_mem_malloc(sizeof(chan_bonding_bitmap)); + if (NULL == channel_bitmap) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: Failed to allocate memory", __func__); + return; + } + pSpectInfo = pSpectInfoParams->pSpectCh; + /* for each HT80 channel, calculate the combined weight of the + four 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_ht80_channels); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht80_channels[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!(((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) && + ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) && + ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same HT80 width + */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 4) == + pSpectInfo[j + 1].chNum) + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) + pSpectInfo[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum) + pSpectInfo[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 4; + continue; + } + /*found the channel, add the 4 adjacent channels' weight */ + acs_ht80_channels[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight + pSpectInfo[j + 2].weight + + pSpectInfo[j + 3].weight; + /* find best channel among 4 channels as the primary channel */ + if ((pSpectInfo[j].weight + pSpectInfo[j + 1].weight) < + (pSpectInfo[j + 2].weight + pSpectInfo[j + 3].weight)) { + /* lower 2 channels are better choice */ + if (pSpectInfo[j].weight < pSpectInfo[j + 1].weight) + minIdx = 0; + else + minIdx = 1; + } else if (pSpectInfo[j + 2].weight <= + pSpectInfo[j + 3].weight) { + /* upper 2 channels are better choice */ + minIdx = 2; + } else { + minIdx = 3; + } + + /* + * set all 4 channels to max value first, then reset the + * best channel as the selected primary channel, update its + * weightage with the combined weight value + */ + for (n = 0; n < 4; n++) + pSpectInfo[j + n].weight = SAP_ACS_WEIGHT_MAX * 4; + + pSpectInfo[j + minIdx].weight = acs_ht80_channels[i].weight; + } + + /* + * mark the weight of the channel that can't satisfy 80MHZ + * as max value, so that it will be sorted to the bottom + */ + set_ht80_chl_bit(channel_bitmap, pSpectInfoParams); + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = + channel_bitmap->chanBondingSet[i].startChannel; + if (pSpectInfo[j].chNum >= start_channel && + (pSpectInfo[j].chNum <= + start_channel + 12) && + channel_bitmap->chanBondingSet[i].channelMap != + SAP_80MHZ_MASK) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + } + } + + /* + * Assign max weight(SAP_ACS_WEIGHT_MAX * 4) to 2.4 Ghz channels + * and channel 165 as they cannot be part of a 80Mhz channel bonding. + */ + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if ((pSpectInfo[j].chNum >= WLAN_REG_CH_NUM(CHAN_ENUM_1) && + pSpectInfo[j].chNum <= WLAN_REG_CH_NUM(CHAN_ENUM_14)) || + (pSpectInfo[j].chNum >= CHANNEL_165)) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + } + + sap_sort_chl_weight(pSpectInfoParams); + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d Weight= %d rssi=%d bssCount=%d"), + pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } + qdf_mem_free(channel_bitmap); +} + +/** + * sap_sort_chl_weight_vht160() - to sort the channels with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Function to sort the channels with the least weight first for VHT160 channels + * + * Return: none + */ +static void sap_sort_chl_weight_vht160(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j, n, idx; + tSapSpectChInfo *pSpectInfo; + uint8_t minIdx; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /* for each VHT160 channel, calculate the combined weight of the + 8 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_vht160_channels); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_vht160_channels[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!(((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) && + ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) && + ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum) && + ((pSpectInfo[j].chNum + 16) == + pSpectInfo[j + 4].chNum) && + ((pSpectInfo[j].chNum + 20) == + pSpectInfo[j + 5].chNum) && + ((pSpectInfo[j].chNum + 24) == + pSpectInfo[j + 6].chNum) && + ((pSpectInfo[j].chNum + 28) == + pSpectInfo[j + 7].chNum))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same VHT160 width + */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 4) == + pSpectInfo[j + 1].chNum) + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) + pSpectInfo[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum) + pSpectInfo[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 16) == + pSpectInfo[j + 4].chNum) + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 20) == + pSpectInfo[j + 5].chNum) + pSpectInfo[j + 5].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 24) == + pSpectInfo[j + 6].chNum) + pSpectInfo[j + 6].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 28) == + pSpectInfo[j + 7].chNum) + pSpectInfo[j + 7].weight = + SAP_ACS_WEIGHT_MAX * 8; + continue; + } + /*found the channel, add the 7 adjacent channels' weight */ + acs_vht160_channels[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight + pSpectInfo[j + 2].weight + + pSpectInfo[j + 3].weight + pSpectInfo[j + 4].weight + + pSpectInfo[j + 5].weight + pSpectInfo[j + 6].weight + + pSpectInfo[j + 7].weight; + + /* find best channel among 8 channels as the primary channel */ + if ((pSpectInfo[j].weight + pSpectInfo[j + 1].weight + + pSpectInfo[j + 2].weight + pSpectInfo[j + 3].weight) > + (pSpectInfo[j + 4].weight + pSpectInfo[j + 5].weight + + pSpectInfo[j + 6].weight + pSpectInfo[j + 7].weight)) + idx = 4; + else + idx = 0; + /* find best channel among 4 channels as the primary channel */ + if ((pSpectInfo[j + idx].weight + + pSpectInfo[j + idx + 1].weight) < + (pSpectInfo[j + idx + 2].weight + + pSpectInfo[j + idx + 3].weight)) { + /* lower 2 channels are better choice */ + if (pSpectInfo[j + idx].weight < + pSpectInfo[j + idx + 1].weight) + minIdx = 0 + idx; + else + minIdx = 1 + idx; + } else if (pSpectInfo[j + idx + 2].weight <= + pSpectInfo[j + idx + 3].weight) { + /* upper 2 channels are better choice */ + minIdx = 2 + idx; + } else { + minIdx = 3 + idx; + } + + /* + * set all 8 channels to max value first, then reset the + * best channel as the selected primary channel, update its + * weightage with the combined weight value + */ + for (n = 0; n < 8; n++) + pSpectInfo[j + n].weight = SAP_ACS_WEIGHT_MAX * 8; + + pSpectInfo[j + minIdx].weight = acs_vht160_channels[i].weight; + } + + /* + * Assign max weight(SAP_ACS_WEIGHT_MAX * 8) to 2.4 Ghz channels + * and channel 132-173 as they cannot be part of a 160Mhz channel + * bonding. + */ + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if ((pSpectInfo[j].chNum >= WLAN_REG_CH_NUM(CHAN_ENUM_1) && + pSpectInfo[j].chNum <= WLAN_REG_CH_NUM(CHAN_ENUM_14)) || + (pSpectInfo[j].chNum >= WLAN_REG_CH_NUM(CHAN_ENUM_132) && + pSpectInfo[j].chNum <= WLAN_REG_CH_NUM(CHAN_ENUM_173))) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 8; + } + + sap_sort_chl_weight(pSpectInfoParams); + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d Weight= %d rssi=%d bssCount=%d"), + pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } +} + +/** + * sap_allocate_max_weight_ht40_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_ht40_24_g( + tSapChSelSpectInfo *spect_info_params) +{ + tSapSpectChInfo *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->pSpectCh; + for (j = 0; j < spect_info_params->numSpectChans; j++) { + if ((spect_info[j].chNum >= WLAN_REG_CH_NUM(CHAN_ENUM_1) && + spect_info[j].chNum <= WLAN_REG_CH_NUM(CHAN_ENUM_14))) + spect_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } +} + +/** + * sap_allocate_max_weight_ht40_5_g() - 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_ht40_5_g( + tSapChSelSpectInfo *spect_info_params) +{ + tSapSpectChInfo *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->pSpectCh; + for (j = 0; j < spect_info_params->numSpectChans; j++) { + if ((spect_info[j].chNum >= WLAN_REG_CH_NUM(CHAN_ENUM_36) && + spect_info[j].chNum <= WLAN_REG_CH_NUM(CHAN_ENUM_173))) + spect_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } +} + +/** + * sap_sort_chl_weight_ht40_24_g() - to sort channel with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Function to sort the channels with the least weight first for HT40 channels + * + * Return: none + */ +static void sap_sort_chl_weight_ht40_24_g(tSapChSelSpectInfo *pSpectInfoParams, + v_REGDOMAIN_t domain) +{ + uint8_t i, j; + tSapSpectChInfo *pSpectInfo; + uint32_t tmpWeight1, tmpWeight2; + uint32_t ht40plus2gendch = 0; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /* + * 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 < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht40_channels24_g[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 4].chNum)) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + continue; + } + /* + * check if there is another channel combination possiblity + * e.g., {1, 5} & {5, 9} + */ + if ((pSpectInfo[j + 4].chNum + 4) == pSpectInfo[j + 8].chNum) { + /* need to compare two channel pairs */ + tmpWeight1 = pSpectInfo[j].weight + + pSpectInfo[j + 4].weight; + tmpWeight2 = pSpectInfo[j + 4].weight + + pSpectInfo[j + 8].weight; + if (tmpWeight1 <= tmpWeight2) { + if (pSpectInfo[j].weight <= + pSpectInfo[j + 4].weight) { + pSpectInfo[j].weight = + tmpWeight1; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 4].weight = + tmpWeight1; + /* for secondary channel selection */ + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } else { + if (pSpectInfo[j + 4].weight <= + pSpectInfo[j + 8].weight) { + pSpectInfo[j + 4].weight = + tmpWeight2; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + /* for secondary channel selection */ + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + } else { + pSpectInfo[j + 8].weight = + tmpWeight2; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } + } else { + tmpWeight1 = pSpectInfo[j].weight_copy + + pSpectInfo[j + 4].weight_copy; + if (pSpectInfo[j].weight_copy <= + pSpectInfo[j + 4].weight_copy) { + pSpectInfo[j].weight = tmpWeight1; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 4].weight = tmpWeight1; + pSpectInfo[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++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == i && + ((pSpectInfo[j].chNum + 4) != + pSpectInfo[j+4].chNum) && + ((pSpectInfo[j].chNum - 4) != + pSpectInfo[j-4].chNum)) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + } + for (i = ht40plus2gendch + 1; i <= HT40MINUS_2G_CH_END; i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == i && + (pSpectInfo[j].chNum - 4) != + pSpectInfo[j-4].chNum) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel=%d Weight= %d rssi=%d bssCount=%d", + __func__, pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } + + sap_sort_chl_weight(pSpectInfoParams); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight_ht40_5_g + + DESCRIPTION + Function to sort the channels with the least weight first for HT40 channels + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_sort_chl_weight_ht40_5_g(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j; + tSapSpectChInfo *pSpectInfo; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /*for each HT40 channel, calculate the combined weight of the + two 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels5_g); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht40_channels5_g[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + /* found the channel, add the two adjacent channels' weight */ + if ((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) { + acs_ht40_channels5_g[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight; + /* select better of the adjact channel as the primary channel */ + if (pSpectInfo[j].weight <= pSpectInfo[j + 1].weight) { + pSpectInfo[j].weight = + acs_ht40_channels5_g[i].weight; + /* mark the adjacent channel's weight as max value so + that it will be sorted to the bottom */ + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 1].weight = + acs_ht40_channels5_g[i].weight; + /* mark the adjacent channel's weight as max value so + that it will be sorted to the bottom */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + + } else + pSpectInfo[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 + */ + for (j = 1; j < pSpectInfoParams->numSpectChans; j++) { + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels5_g); i++) { + if (pSpectInfo[j].chNum == + (acs_ht40_channels5_g[i].chStartNum + + 4) && + pSpectInfo[j - 1].chNum != + acs_ht40_channels5_g[i].chStartNum) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + break; + } + } + } + /* avoid channel 165 by setting its weight to max */ + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum >= CHANNEL_165) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + break; + } + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel=%d Weight= %d rssi=%d bssCount=%d", + __func__, pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } + + sap_sort_chl_weight(pSpectInfoParams); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight_all + + DESCRIPTION + Function to sort the channels with the least weight first + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sap_ctx : Pointer to the struct sap_context *structure + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_sort_chl_weight_all(struct sap_context *sap_ctx, + tSapChSelSpectInfo *pSpectInfoParams, + uint32_t operatingBand, + v_REGDOMAIN_t domain) +{ + tSapSpectChInfo *pSpectCh = NULL; + uint32_t j = 0; +#ifndef SOFTAP_CHANNEL_RANGE + uint32_t i = 0; +#endif + + pSpectCh = pSpectInfoParams->pSpectCh; +#ifdef SOFTAP_CHANNEL_RANGE + + switch (sap_ctx->acs_cfg->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 == operatingBand) { + sap_sort_chl_weight_ht40_24_g(pSpectInfoParams, domain); + sap_allocate_max_weight_ht40_5_g(pSpectInfoParams); + } else { + sap_allocate_max_weight_ht40_24_g(pSpectInfoParams); + sap_sort_chl_weight_ht40_5_g(pSpectInfoParams); + } + break; + case CH_WIDTH_80MHZ: + case CH_WIDTH_80P80MHZ: + sap_sort_chl_weight_ht80(pSpectInfoParams); + break; + case CH_WIDTH_160MHZ: + sap_sort_chl_weight_vht160(pSpectInfoParams); + break; + case CH_WIDTH_20MHZ: + default: + /* Sorting the channels as per weights as 20MHz channels */ + sap_sort_chl_weight(pSpectInfoParams); + } + +#else + /* Sorting the channels as per weights */ + for (i = 0; i < SPECT_24GHZ_CH_COUNT; i++) { + minWeightIndex = i; + for (j = i + 1; j < SPECT_24GHZ_CH_COUNT; j++) { + if (pSpectCh[j].weight < + pSpectCh[minWeightIndex].weight) { + minWeightIndex = j; + } + } + if (minWeightIndex != i) { + qdf_mem_copy(&temp, &pSpectCh[minWeightIndex], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[minWeightIndex], &pSpectCh[i], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[i], &temp, sizeof(*pSpectCh)); + } + } +#endif + + /* For testing */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "In %s, Sorted Spectrum Channels Weight", __func__); + pSpectCh = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "In %s, Channel=%d Weight= %d rssi=%d bssCount=%d", + __func__, pSpectCh->chNum, pSpectCh->weight, + pSpectCh->rssiAgr, pSpectCh->bssCount); + pSpectCh++; + } + +} + +/** + * 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; +} + +/** + * sap_select_channel() - select SAP channel + * @hal: Pointer to HAL handle + * @sap_ctx: Sap context + * @scan_result: Pointer to tScanResultHandle + * + * Runs a algorithm to select the best channel to operate in based on BSS + * rssi and bss count on each channel + * + * Returns: channel number if success, 0 otherwise + */ +uint8_t sap_select_channel(tHalHandle hal, struct sap_context *sap_ctx, + tScanResultHandle scan_result) +{ + /* DFS param object holding all the data req by the algo */ + tSapChSelSpectInfo spect_info_obj = { NULL, 0 }; + tSapChSelSpectInfo *spect_info = &spect_info_obj; + uint8_t best_ch_num = SAP_CHANNEL_NOT_SELECTED; + uint32_t ht40plus2gendch = 0; + v_REGDOMAIN_t domain; + uint8_t country[CDS_COUNTRY_CODE_LEN + 1]; +#ifdef SOFTAP_CHANNEL_RANGE + uint8_t count; + uint32_t start_ch_num, end_ch_num, tmp_ch_num, operating_band = 0; +#endif + tpAniSirGlobal mac_ctx; + + mac_ctx = PMAC_STRUCT(hal); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Running SAP Ch Select", __func__); + +#ifdef FEATURE_WLAN_CH_AVOID + sap_update_unsafe_channel_list(hal, sap_ctx); +#endif + + /* + * If ACS weight is not enabled on noise_floor/channel_free/tx_power, + * then skip acs process if no bss found. + */ + if (NULL == scan_result && + !(sap_ctx->auto_channel_select_weight & 0xffff00)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("No external AP present")); + +#ifndef SOFTAP_CHANNEL_RANGE + return SAP_CHANNEL_NOT_SELECTED; +#else + return sap_select_default_oper_chan(sap_ctx->acs_cfg); +#endif + } + + /* Initialize the structure pointed by spect_info */ + if (sap_chan_sel_init(hal, spect_info, sap_ctx) != true) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Ch Select initialization failed")); + return SAP_CHANNEL_NOT_SELECTED; + } + /* Compute the weight of the entire spectrum in the operating band */ + sap_compute_spect_weight(spect_info, hal, scan_result, sap_ctx); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* process avoid channel IE to collect all channels to avoid */ + sap_process_avoid_ie(hal, sap_ctx, scan_result, spect_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); +#ifdef SOFTAP_CHANNEL_RANGE + start_ch_num = sap_ctx->acs_cfg->start_ch; + end_ch_num = sap_ctx->acs_cfg->end_ch; + SET_ACS_BAND(operating_band, sap_ctx); + + sap_ctx->acsBestChannelInfo.channelNum = 0; + sap_ctx->acsBestChannelInfo.weight = SAP_ACS_WEIGHT_MAX; + + /* Sort the ch lst as per the computed weights, lesser weight first. */ + sap_sort_chl_weight_all(sap_ctx, spect_info, operating_band, domain); + + /*Loop till get the best channel in the given range */ + for (count = 0; count < spect_info->numSpectChans; count++) { + if ((start_ch_num > spect_info->pSpectCh[count].chNum) || + (end_ch_num < spect_info->pSpectCh[count].chNum)) + continue; + + if (best_ch_num == SAP_CHANNEL_NOT_SELECTED) { + best_ch_num = spect_info->pSpectCh[count].chNum; + /* check if best_ch_num is in preferred channel list */ + best_ch_num = + sap_select_preferred_channel_from_channel_list( + best_ch_num, sap_ctx, spect_info); + /* if not in preferred ch lst, go to nxt best ch */ + if (best_ch_num == 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 (sap_check_in_avoid_ch_list(sap_ctx, best_ch_num)) { + best_ch_num = SAP_CHANNEL_NOT_SELECTED; + continue; + } +#endif + + sap_ctx->acsBestChannelInfo.channelNum = best_ch_num; + sap_ctx->acsBestChannelInfo.weight = + spect_info->pSpectCh[count].weight_copy; + } + + if (best_ch_num == SAP_CHANNEL_NOT_SELECTED) + continue; + + if (operating_band != eCSR_DOT11_MODE_11g) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "operating_band %d", operating_band); + continue; + } + + /* Give preference to Non-overlap channels */ + if (false == sap_is_ch_non_overlap(sap_ctx, + spect_info->pSpectCh[count].chNum)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("ch: %d skipped as its overlapping ch"), + spect_info->pSpectCh[count].chNum); + continue; + } + + if (wlan_reg_is_dfs_ch(mac_ctx->pdev, + spect_info->pSpectCh[count].chNum) && + policy_mgr_disallow_mcc(mac_ctx->psoc, + spect_info->pSpectCh[count].chNum)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "No DFS MCC"); + continue; + } + + if (spect_info->pSpectCh[count].weight_copy > + sap_ctx->acsBestChannelInfo.weight) + continue; + + tmp_ch_num = spect_info->pSpectCh[count].chNum; + tmp_ch_num = sap_channel_in_acs_channel_list( + tmp_ch_num, sap_ctx, spect_info); + if (tmp_ch_num == SAP_CHANNEL_NOT_SELECTED) + continue; + + best_ch_num = tmp_ch_num; + break; + } +#else + /* Sort the ch lst as per the computed weights, lesser weight first. */ + sap_sort_chl_weight_all(sap_ctx, hal, spect_info); + /* Get the first channel in sorted array as best 20M Channel */ + best_ch_num = (uint8_t) spect_info->pSpectCh[0].chNum; + /* Select Best Channel from Channel List if Configured */ + best_ch_num = sap_select_preferred_channel_from_channel_list( + best_ch_num, sap_ctx, spect_info); +#endif + + /* + * in case the best channel seleted is not in PCL and there is another + * channel which has same weightage and is in PCL, choose the one in + * PCL + */ + for (count = 0; count < spect_info->numSpectChans; count++) { + if (!ch_in_pcl(sap_ctx, spect_info->pSpectCh[count].chNum) || + (spect_info->pSpectCh[count].weight != + sap_ctx->acsBestChannelInfo.weight)) + continue; + + if (sap_select_preferred_channel_from_channel_list( + spect_info->pSpectCh[count].chNum, sap_ctx, spect_info) + == SAP_CHANNEL_NOT_SELECTED) + continue; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (sap_check_in_avoid_ch_list(sap_ctx, best_ch_num)) + continue; +#endif + best_ch_num = spect_info->pSpectCh[count].chNum; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("change best channel to %d in PCL"), best_ch_num); + break; + } + + sap_ctx->acs_cfg->pri_ch = best_ch_num; + /* 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; + 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; + tSapSpectChInfo *pspect_info; + + weight_below = weight_above = SAP_ACS_WEIGHT_MAX; + pspect_info = spect_info->pSpectCh; + for (i = 0; i < spect_info->numSpectChans; i++) { + if (pspect_info[i].chNum == (best_ch_num - 4)) + weight_below = pspect_info[i].weight; + if (pspect_info[i].chNum == (best_ch_num + 4)) + weight_above = pspect_info[i].weight; + } + + if (weight_below < weight_above) + sap_ctx->acs_cfg->ht_sec_ch = + sap_ctx->acs_cfg->pri_ch - 4; + else + sap_ctx->acs_cfg->ht_sec_ch = + sap_ctx->acs_cfg->pri_ch + 4; + } else if (best_ch_num >= 1 && best_ch_num <= 4) { + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch + 4; + } else if (best_ch_num >= ht40plus2gendch && best_ch_num <= + HT40MINUS_2G_CH_END) { + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch - 4; + } else if (best_ch_num == 14) { + sap_ctx->acs_cfg->ht_sec_ch = 0; + } + sap_ctx->secondary_ch = sap_ctx->acs_cfg->ht_sec_ch; + +sap_ch_sel_end: + /* Free all the allocated memory */ + sap_chan_sel_exit(spect_info); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Running SAP Ch select Completed, Ch=%d"), best_ch_num); + host_log_acs_best_chan(best_ch_num, sap_ctx->acsBestChannelInfo.weight); + + if (best_ch_num > 0 && best_ch_num <= 252) + return best_ch_num; + else + return SAP_CHANNEL_NOT_SELECTED; +} diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.h b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.h new file mode 100644 index 0000000000000000000000000000000000000000..35d2a6c2efbb51ad1b4b717af356120b988d5e54 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2012-2015, 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. + */ + +#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 SPECT_24GHZ_CH_COUNT (11) /* USA regulatory domain */ +#define SAPDFS_NORMALISE_1000 (1000/9) /* Case of spec20 with channel diff = 0 */ +/* Gen 5 values + #define SOFTAP_MIN_RSSI (-85) + #define SOFTAP_MAX_RSSI (-45) + */ +#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 SOFTAP_HT20_CHANNELWIDTH 0 +/* 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; + +#define MAX_80MHZ_BANDS 6 +#define SAP_80MHZ_MASK 0x0F +#define SAP_40MHZ_MASK_L 0x03 +#define SAP_40MHZ_MASK_H 0x0C + +/* + * structs for holding channel bonding bitmap + * used for finding new channel when SAP is on + * DFS channel and radar is detected. + */ +typedef struct sChannelBondingInfo { + uint8_t channelMap:4; + uint8_t rsvd:4; + uint8_t startChannel; +} tChannelBondingInfo; + +typedef struct __chan_bonding_bitmap { + tChannelBondingInfo chanBondingSet[MAX_80MHZ_BANDS]; +} chan_bonding_bitmap; + +/** + * Structure holding information of each channel in the spectrum, + * it contains the channel number, the computed weight + */ +typedef struct sChannelInfo { + uint8_t channel; + bool valid; /* if the channel is valid to be picked as new channel */ +} tChannelInfo; + +typedef struct sAll5GChannelList { + uint8_t numChannel; + tChannelInfo *channelList; +} tAll5GChannelList; + +typedef struct sSapChannelListInfo { + uint8_t numChannel; + uint8_t *channelList; +} tSapChannelListInfo; + +typedef struct { + uint16_t chNum; /* Channel Number */ + uint16_t channelWidth; /* Channel Width */ + uint16_t bssCount; /* bss found in scanresult for this channel */ + int32_t rssiAgr; /* Max value of rssi among all BSS(es) from scanresult for this channel */ + uint32_t weight; /* Weightage of this channel */ + uint32_t weight_copy; /* copy of the orignal weight */ + bool valid; /* Is this a valid center frequency for regulatory domain */ +} tSapSpectChInfo; /* tDfsSpectChInfo; */ + +/** + * Structure holding all the information required to make a + * decision for the best operating channel based on dfs formula + */ + +typedef struct { + tSapSpectChInfo *pSpectCh; /* tDfsSpectChInfo *pSpectCh; // Ptr to the channels in the entire spectrum band */ + uint8_t numSpectChans; /* Total num of channels in the spectrum */ +} tSapChSelSpectInfo; /* tDfsChSelParams; */ + +/** + * Structure for channel weight calculation parameters + */ +typedef struct sSapChSelParams { + void *pSpectInfoParams; /**pDfsParams; // Filled with tSapChSelSpectInfo */ + uint16_t numChannels; +} tSapChSelParams; + +#endif /* if !defined __SAP_CH_SELECT_H */ diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c new file mode 100644 index 0000000000000000000000000000000000000000..67d77ecfe33baeba5f6713c7d8bcd8b1342b98ba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c @@ -0,0 +1,3788 @@ +/* + * 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. + */ + +/*=========================================================================== + + 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 "cfg_api.h" +#include +#include +#include +#include +#include +#include +#include +#include "wlan_reg_services_api.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_CH_AVOID +extern sapSafeChannelType safe_channels[]; +#endif /* FEATURE_WLAN_CH_AVOID */ + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ +#ifdef SOFTAP_CHANNEL_RANGE +static QDF_STATUS sap_get_channel_list(struct sap_context *sapContext, + uint8_t **channelList, + uint8_t *numberOfChannels); +#endif + +/*========================================================================== + FUNCTION sapStopDfsCacTimer + + DESCRIPTION + Function to sttop the DFS CAC timer when SAP is stopped + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +static int sap_stop_dfs_cac_timer(struct sap_context *sapContext); + +/*========================================================================== + FUNCTION sapStartDfsCacTimer + + DESCRIPTION + Function to start the DFS CAC timer when SAP is started on DFS Channel + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +static int sap_start_dfs_cac_timer(struct sap_context *sapContext); + +/** 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. + */ +#ifdef WLAN_DEBUG +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_ASSOC_STA_CALLBACK_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_PRE_CAC_END); + CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT); + CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC); + 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"; + } +} +#endif + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +#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 number picked + **/ +static uint8_t sap_random_channel_sel(struct sap_context *sap_ctx) +{ + uint8_t ch; + uint8_t ch_wd; + struct wlan_objmgr_pdev *pdev = NULL; + tHalHandle hal; + struct ch_params *ch_params; + uint32_t hw_mode; + tpAniSirGlobal mac_ctx; + struct dfs_acs_info acs_info = {0}; + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null hal")); + return 0; + } + + mac_ctx = PMAC_STRUCT(hal); + + pdev = mac_ctx->pdev; + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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.channel_list = sap_ctx->acs_cfg->master_ch_list; + acs_info.num_of_channel = + sap_ctx->acs_cfg->master_ch_list_count; + } else { + acs_info.acs_mode = false; + } + if (QDF_IS_STATUS_ERROR(utils_dfs_get_random_channel( + pdev, 0, ch_params, &hw_mode, &ch, &acs_info))) { + /* No available channel found */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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 ch; +} +#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 + * + * Check if the current SAP operating channel is 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) +{ + if (IS_CH_BONDING_WITH_WEATHER_CH(sap_ctx->channel) && + (sap_ctx->ch_params.ch_width != CH_WIDTH_20MHZ)) + return true; + + return false; +} + +/* + * sap_get_bonding_channels() - get bonding channels from primary channel. + * @sapContext: Handle to SAP context. + * @channel: Channel to get bonded channels. + * @channels: Bonded channel 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 *sapContext, + uint8_t channel, + uint8_t *channels, uint8_t size, + ePhyChanBondState chanBondState) +{ + tHalHandle hHal = CDS_GET_HAL_CB(); + tpAniSirGlobal pMac; + uint8_t numChannel; + + if (channels == NULL) + return 0; + + if (size < MAX_BONDED_CHANNELS) + return 0; + + if (NULL != hHal) + pMac = PMAC_STRUCT(hHal); + else + return 0; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("cbmode: %d, channel: %d"), chanBondState, channel); + + switch (chanBondState) { + case PHY_SINGLE_CHANNEL_CENTERED: + numChannel = 1; + channels[0] = channel; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + numChannel = 2; + channels[0] = channel - 4; + channels[1] = channel; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + numChannel = 2; + channels[0] = channel; + channels[1] = channel + 4; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + numChannel = 4; + channels[0] = channel; + channels[1] = channel + 4; + channels[2] = channel + 8; + channels[3] = channel + 12; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + numChannel = 4; + channels[0] = channel - 4; + channels[1] = channel; + channels[2] = channel + 4; + channels[3] = channel + 8; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + numChannel = 4; + channels[0] = channel - 8; + channels[1] = channel - 4; + channels[2] = channel; + channels[3] = channel + 4; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + numChannel = 4; + channels[0] = channel - 12; + channels[1] = channel - 8; + channels[2] = channel - 4; + channels[3] = channel; + break; + default: + numChannel = 1; + channels[0] = channel; + break; + } + + return numChannel; +} + +/** + * sap_ch_params_to_bonding_channels() - get bonding channels from channel param + * @ch_params: channel params ( bw, pri and sec channel info) + * @channels: bonded channel list + * + * Return: Number of sub channels + */ +static uint8_t sap_ch_params_to_bonding_channels( + struct ch_params *ch_params, + uint8_t *channels) +{ + uint8_t center_chan = ch_params->center_freq_seg0; + uint8_t nchannels = 0; + + switch (ch_params->ch_width) { + case CH_WIDTH_160MHZ: + nchannels = 8; + center_chan = ch_params->center_freq_seg1; + channels[0] = center_chan - 14; + channels[1] = center_chan - 10; + channels[2] = center_chan - 6; + channels[3] = center_chan - 2; + channels[4] = center_chan + 2; + channels[5] = center_chan + 6; + channels[6] = center_chan + 10; + channels[7] = center_chan + 14; + break; + case CH_WIDTH_80P80MHZ: + nchannels = 8; + channels[0] = center_chan - 6; + channels[1] = center_chan - 2; + channels[2] = center_chan + 2; + channels[3] = center_chan + 6; + + center_chan = ch_params->center_freq_seg1; + channels[4] = center_chan - 6; + channels[5] = center_chan - 2; + channels[6] = center_chan + 2; + channels[7] = center_chan + 6; + break; + case CH_WIDTH_80MHZ: + nchannels = 4; + channels[0] = center_chan - 6; + channels[1] = center_chan - 2; + channels[2] = center_chan + 2; + channels[3] = center_chan + 6; + break; + case CH_WIDTH_40MHZ: + nchannels = 2; + channels[0] = center_chan - 2; + channels[1] = center_chan + 2; + break; + default: + nchannels = 1; + channels[0] = center_chan; + break; + } + + return nchannels; +} + +/** + * sap_get_cac_dur_dfs_region() - get cac duration and dfs region. + * @sap_ctxt: sap context + * @cac_duration_ms: pointer to cac duration + * @dfs_region: pointer to dfs region + * + * Get cac duration and dfs region. + * + * Return: None + */ +static void sap_get_cac_dur_dfs_region(struct sap_context *sap_ctx, + uint32_t *cac_duration_ms, + uint32_t *dfs_region) +{ + int i; + uint8_t channels[MAX_BONDED_CHANNELS]; + uint8_t num_channels; + struct ch_params *ch_params = &sap_ctx->ch_params; + tHalHandle hal = NULL; + tpAniSirGlobal mac = NULL; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: null sap_ctx", __func__); + return; + } + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: null hal", __func__); + return; + } + + mac = PMAC_STRUCT(hal); + wlan_reg_get_dfs_region(mac->pdev, dfs_region); + if (mac->sap.SapDfsInfo.ignore_cac) { + *cac_duration_ms = 0; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: ignore_cac is set", __func__); + return; + } + *cac_duration_ms = DEFAULT_CAC_TIMEOUT; + + if (*dfs_region != DFS_ETSI_REG) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("sapdfs: default cac duration")); + return; + } + + if (sap_is_channel_bonding_etsi_weather_channel(sap_ctx)) { + *cac_duration_ms = ETSI_WEATHER_CH_CAC_TIMEOUT; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("sapdfs: bonding_etsi_weather_channel")); + return; + } + + qdf_mem_zero(channels, sizeof(channels)); + num_channels = sap_ch_params_to_bonding_channels(ch_params, channels); + for (i = 0; i < num_channels; i++) { + if (IS_ETSI_WEATHER_CH(channels[i])) { + *cac_duration_ms = ETSI_WEATHER_CH_CAC_TIMEOUT; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("sapdfs: ch=%d is etsi weather channel"), + channels[i]); + return; + } + } + +} + +void sap_dfs_set_current_channel(void *ctx) +{ + struct sap_context *sap_ctx = ctx; + uint32_t ic_flags = 0; + uint16_t ic_flagext = 0; + uint8_t ic_ieee = sap_ctx->channel; + uint16_t ic_freq = utils_dfs_chan_to_freq(sap_ctx->channel); + uint8_t vht_seg0 = sap_ctx->csr_roamProfile.ch_params.center_freq_seg0; + uint8_t vht_seg1 = sap_ctx->csr_roamProfile.ch_params.center_freq_seg1; + struct wlan_objmgr_pdev *pdev; + tpAniSirGlobal mac_ctx; + tHalHandle hal; + uint32_t use_nol = 0; + int error; + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null hal")); + return; + } + + mac_ctx = PMAC_STRUCT(hal); + pdev = mac_ctx->pdev; + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null pdev")); + return; + } + + switch (sap_ctx->csr_roamProfile.ch_params.ch_width) { + case CH_WIDTH_20MHZ: + ic_flags |= IEEE80211_CHAN_VHT20; + break; + case CH_WIDTH_40MHZ: + ic_flags |= IEEE80211_CHAN_VHT40PLUS; + break; + case CH_WIDTH_80MHZ: + ic_flags |= IEEE80211_CHAN_VHT80; + break; + case CH_WIDTH_80P80MHZ: + ic_flags |= IEEE80211_CHAN_VHT80_80; + break; + case CH_WIDTH_160MHZ: + ic_flags |= IEEE80211_CHAN_VHT160; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid channel width=%d"), + sap_ctx->csr_roamProfile.ch_params.ch_width); + return; + } + + if (WLAN_REG_IS_24GHZ_CH(sap_ctx->channel)) + ic_flags |= IEEE80211_CHAN_2GHZ; + else + ic_flags |= IEEE80211_CHAN_5GHZ; + + if (wlan_reg_is_dfs_ch(pdev, sap_ctx->channel)) + ic_flagext |= IEEE80211_CHAN_DFS; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("freq=%d, channel=%d, seg0=%d, seg1=%d, flags=0x%x, ext flags=0x%x"), + ic_freq, ic_ieee, vht_seg0, vht_seg1, ic_flags, ic_flagext); + + tgt_dfs_set_current_channel(pdev, ic_freq, ic_flags, + ic_flagext, ic_ieee, vht_seg0, vht_seg1); + + if (wlan_reg_is_dfs_ch(pdev, sap_ctx->channel)) { + if (policy_mgr_concurrent_beaconing_sessions_running( + mac_ctx->psoc)) { + uint16_t con_ch; + + con_ch = + sme_get_beaconing_concurrent_operation_channel( + hal, sap_ctx->sessionId); + if (!con_ch || !wlan_reg_is_dfs_ch(pdev, con_ch)) + tgt_dfs_get_radars(pdev); + } else { + tgt_dfs_get_radars(pdev); + } + tgt_dfs_set_phyerr_filter_offload(pdev); + if (sap_ctx->csr_roamProfile.disableDFSChSwitch) + tgt_dfs_control(pdev, DFS_SET_USENOL, &use_nol, + sizeof(uint32_t), NULL, NULL, &error); + } +} + +/* + * FUNCTION sap_dfs_is_w53_invalid + * + * DESCRIPTION Checks if the passed channel is W53 and returns if + * SAP W53 opearation is allowed. + * + * DEPENDENCIES PARAMETERS + * IN hHAL : HAL pointer + * channelID: Channel Number to be verified + * + * RETURN VALUE : bool + * true: If W53 operation is disabled + * false: If W53 operation is enabled + * + * SIDE EFFECTS + */ +bool sap_dfs_is_w53_invalid(tHalHandle hHal, uint8_t channelID) +{ + tpAniSirGlobal pMac; + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return false; + } + + /* + * Check for JAPAN W53 Channel operation capability + */ + if (true == pMac->sap.SapDfsInfo.is_dfs_w53_disabled && + true == IS_CHAN_JAPAN_W53(channelID)) { + return true; + } + + return false; +} + +/* + * FUNCTION sap_dfs_is_channel_in_preferred_location + * + * DESCRIPTION Checks if the passed channel is in accordance with preferred + * Channel location settings. + * + * DEPENDENCIES PARAMETERS + * IN hHAL : HAL pointer + * channelID: Channel Number to be verified + * + * RETURN VALUE :bool + * true:If Channel location is same as the preferred location + * false:If Channel location is not same as the preferred location + * + * SIDE EFFECTS + */ +bool sap_dfs_is_channel_in_preferred_location(tHalHandle hHal, uint8_t channelID) +{ + tpAniSirGlobal pMac; + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return true; + } + if ((SAP_CHAN_PREFERRED_INDOOR == + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location) && + (true == IS_CHAN_JAPAN_OUTDOOR(channelID))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL + ("CHAN=%d is Outdoor so invalid,preferred Indoor only"), + channelID); + return false; + } else if ((SAP_CHAN_PREFERRED_OUTDOOR == + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location) + && (true == IS_CHAN_JAPAN_INDOOR(channelID))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL + ("CHAN=%d is Indoor so invalid,preferred Outdoor only"), + channelID); + return false; + } + + return true; +} + +#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_number: Channel 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, + uint8_t channel_number, + ePhyChanBondState chan_bondState) +{ + int i; + tHalHandle h_hal = CDS_GET_HAL_CB(); + tpAniSirGlobal mac_ctx; + uint8_t channels[MAX_BONDED_CHANNELS]; + uint8_t num_channels; + struct wlan_objmgr_pdev *pdev = NULL; + enum channel_state ch_state; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid h_hal")); + return false; + } else { + mac_ctx = PMAC_STRUCT(h_hal); + } + + /* get the bonded channels */ + if (channel_number == sap_context->channel && chan_bondState >= + PHY_CHANNEL_BONDING_STATE_MAX) + num_channels = sap_ch_params_to_bonding_channels( + &sap_context->ch_params, channels); + else + num_channels = sap_get_bonding_channels(sap_context, + channel_number, channels, + MAX_BONDED_CHANNELS, chan_bondState); + + pdev = mac_ctx->pdev; + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null pdev")); + return false; + } + + /* check for NOL, first on will break the loop */ + for (i = 0; i < num_channels; i++) { + ch_state = wlan_reg_get_channel_state(pdev, channels[i]); + if (CHANNEL_STATE_ENABLE != ch_state && + CHANNEL_STATE_DFS != ch_state) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid ch num=%d, ch state=%d"), + channels[i], ch_state); + return true; + } + } /* loop for bonded channels */ + + return false; +} + +bool +sap_chan_bond_dfs_sub_chan(struct sap_context *sap_context, + uint8_t channel_number, + ePhyChanBondState bond_state) +{ + int i; + tHalHandle h_hal = CDS_GET_HAL_CB(); + tpAniSirGlobal mac_ctx; + uint8_t channels[MAX_BONDED_CHANNELS]; + uint8_t num_channels; + struct wlan_objmgr_pdev *pdev; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid h_hal")); + return false; + } + mac_ctx = PMAC_STRUCT(h_hal); + pdev = mac_ctx->pdev; + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null pdev")); + return false; + } + + if (wlan_reg_chan_has_dfs_attribute(pdev, channel_number)) + return true; + + /* get the bonded channels */ + if (channel_number == sap_context->channel && bond_state >= + PHY_CHANNEL_BONDING_STATE_MAX) + num_channels = sap_ch_params_to_bonding_channels( + &sap_context->ch_params, channels); + else + num_channels = sap_get_bonding_channels( + sap_context, channel_number, channels, + MAX_BONDED_CHANNELS, bond_state); + + for (i = 0; i < num_channels; i++) { + if (wlan_reg_chan_has_dfs_attribute(pdev, channels[i])) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("sub ch num=%d is dfs in %d"), + channels[i], channel_number); + return true; + } + } + + return false; +} + +uint8_t sap_select_default_oper_chan(struct sap_acs_cfg *acs_cfg) +{ + if (!acs_cfg || !acs_cfg->ch_list) + return 0; + + return acs_cfg->ch_list[0]; +} + +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; + tpAniSirGlobal mac_ctx; + bool is_dfs; + bool is_safe; + tHalHandle h_hal; + uint8_t con_ch; + bool sta_sap_scc_on_dfs_chan; + + h_hal = cds_get_context(QDF_MODULE_ID_SME); + if (NULL == h_hal) { + /* we have a serious problem */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + FL("invalid h_hal")); + return QDF_STATUS_E_FAULT; + } + + mac_ctx = PMAC_STRUCT(h_hal); + if (!sap_context->channel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid channel")); + return QDF_STATUS_E_FAILURE; + } + + 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 = + sme_get_beaconing_concurrent_operation_channel( + h_hal, sap_context->sessionId); +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + if (con_ch && sap_context->channel != con_ch && + wlan_reg_is_dfs_ch(mac_ctx->pdev, + sap_context->channel)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("MCC DFS not supported in AP_AP Mode")); + return QDF_STATUS_E_ABORTED; + } +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (con_ch && (sap_context->cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_DISABLE)) { + /* + * For ACS request ,the sapContext->channel is 0, + * we skip below overlap checking. When the ACS + * finish and SAPBSS start, the sapContext->channel + * will not be 0. Then the overlap checking will be + * reactivated.If we use sapContext->channel = 0 + * to perform the overlap checking, an invalid overlap + * channel con_ch could becreated. That may cause + * SAP start failed. + */ + con_ch = sme_check_concurrent_channel_overlap(h_hal, + sap_context->channel, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode); + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + mac_ctx->psoc); + + if (sap_context->cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) + sta_sap_scc_on_dfs_chan = false; + + is_dfs = wlan_reg_is_dfs_ch(mac_ctx->pdev, con_ch); + is_safe = policy_mgr_is_safe_channel( + mac_ctx->psoc, con_ch); + + if (con_ch && is_safe && + (!is_dfs || (is_dfs && sta_sap_scc_on_dfs_chan))) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "%s: Override ch %d to %d due to CC Intf", + __func__, sap_context->channel, con_ch); + sap_context->channel = con_ch; + wlan_reg_set_channel_params(mac_ctx->pdev, + sap_context->channel, 0, + &sap_context->ch_params); + } + } +#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 + if (wlan_reg_is_dfs_ch(mac_ctx->pdev, + sap_context->channel)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("check for overlap: chan:%d mode:%d"), + sap_context->channel, + sap_context->csr_roamProfile.phyMode); + con_ch = sme_check_concurrent_channel_overlap(h_hal, + sap_context->channel, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("After check overlap: con_ch:%d"), + con_ch); + 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, + sap_context->channel))) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + FL("SAP can't start (no MCC)")); + return QDF_STATUS_E_ABORTED; + } + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("After check concurrency: con_ch:%d"), + con_ch); + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + mac_ctx->psoc); + if (con_ch && + (policy_mgr_sta_sap_scc_on_lte_coex_chan( + mac_ctx->psoc) || + policy_mgr_is_safe_channel(mac_ctx->psoc, + con_ch)) && + (!wlan_reg_is_dfs_ch(mac_ctx->pdev, con_ch) || + sta_sap_scc_on_dfs_chan)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "%s: Override ch %d to %d due to CC Intf", + __func__, sap_context->channel, con_ch); + sap_context->channel = con_ch; + wlan_reg_set_channel_params(mac_ctx->pdev, + sap_context->channel, 0, + &sap_context->ch_params); + } + } +#endif + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("for configured channel, Ch= %d"), + sap_context->channel); + 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->channel, + POLICY_MGR_UPDATE_REASON_START_AP); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + } + + if (pre_start_bss) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("ACS end due to Ch override. Sel Ch = %d"), + sap_context->channel); + sap_context->acs_cfg->pri_ch = sap_context->channel; + sap_context->acs_cfg->ch_width = + sap_context->ch_width_orig; + sap_config_acs_result(h_hal, sap_context, 0); + return QDF_STATUS_E_CANCELED; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_channel_sel(struct sap_context *sap_context) +{ + QDF_STATUS qdf_ret_status; + tpAniSirGlobal mac_ctx; + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev = NULL; + uint8_t i; + uint8_t pdev_id; + +#ifdef SOFTAP_CHANNEL_RANGE + uint8_t *channel_list = NULL; + uint8_t num_of_channels = 0; +#endif + tHalHandle h_hal; + uint8_t con_ch; + uint8_t vdev_id; + uint32_t scan_id; + uint8_t *self_mac; + + h_hal = cds_get_context(QDF_MODULE_ID_SME); + if (!h_hal) { + /* we have a serious problem */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + FL("invalid h_hal")); + return QDF_STATUS_E_FAULT; + } + + mac_ctx = PMAC_STRUCT(h_hal); + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return QDF_STATUS_E_FAILURE; + } + if (sap_context->channel) + 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 = sme_get_beaconing_concurrent_operation_channel( + h_hal, sap_context->sessionId); +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + if (con_ch) + 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 + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("%s skip_acs_status = %d "), __func__, + sap_context->acs_cfg->skip_scan_status); + if (sap_context->acs_cfg->skip_scan_status != + eSAP_SKIP_ACS_SCAN) { +#endif + + if (sap_context->channelList) { + qdf_mem_free(sap_context->channelList); + sap_context->channelList = NULL; + sap_context->num_of_channel = 0; + } + + sap_get_channel_list(sap_context, &channel_list, &num_of_channels); + if (!num_of_channels) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("No channel suitable for SAP, hotspot failed")); + return QDF_STATUS_E_NOSUPPORT; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(mac_ctx->pdev); + self_mac = sap_context->self_mac_addr; + vdev = wlan_objmgr_get_vdev_by_macaddr_from_psoc(mac_ctx->psoc, + pdev_id, + self_mac, + WLAN_LEGACY_SME_ID); + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid vdev objmgr")); + qdf_mem_free(req); + return QDF_STATUS_E_INVAL; + } + + /* Initiate a SCAN request */ + ucfg_scan_init_default_params(vdev, req); + scan_id = ucfg_scan_get_scan_id(mac_ctx->psoc); + req->scan_req.scan_id = scan_id; + vdev_id = wlan_vdev_get_id(vdev); + 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; + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (num_of_channels != 0) { +#endif + + req->scan_req.chan_list.num_chan = num_of_channels; + for (i = 0; i < num_of_channels; i++) + req->scan_req.chan_list.chan[i].freq = + wlan_chan_to_freq(channel_list[i]); + sap_context->channelList = channel_list; + sap_context->num_of_channel = num_of_channels; + /* Set requestType to Full scan */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("calling ucfg_scan_start")); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (sap_context->acs_cfg->skip_scan_status == + eSAP_DO_NEW_ACS_SCAN) +#endif + sme_scan_flush_result(h_hal); + qdf_ret_status = ucfg_scan_start(req); + if (qdf_ret_status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("scan request fail %d!!!"), + qdf_ret_status); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("SAP Configuring default channel, Ch=%d"), + sap_context->channel); + sap_context->channel = sap_select_default_oper_chan( + sap_context->acs_cfg); + +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_context->channelList != NULL) { + sap_context->channel = + sap_context->channelList[0]; + qdf_mem_free(sap_context-> + channelList); + sap_context->channelList = NULL; + sap_context->num_of_channel = 0; + } +#endif + /* + * 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 { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("return sme_ScanReq, scanID=%d, Ch=%d"), + scan_id, + sap_context->channel); + 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("## %s SKIPPED ACS SCAN"), __func__); + wlansap_pre_start_bss_acs_scan_callback(h_hal, + sap_context, sap_context->sessionId, 0, + eCSR_SCAN_SUCCESS); + } +#endif + + /* + * If scan failed, get default channel and advance state + * machine as success with default channel + * + * Have to wait for the call back to be called to get the + * channel cannot advance state machine here as said above + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("before exiting sap_channel_sel channel=%d"), + sap_context->channel); + + 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 + * @hal: pointer to hal abstration layer + * + * 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(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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 != NULL) { + sap_ctx = mac_ctx->sap.sapCtxList[intf].sap_context; + if (sap_ctx->fsm_state != SAP_INIT) + return sap_ctx; + } + } + + return NULL; +} + +static QDF_STATUS sap_clear_global_dfs_param(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (NULL != sap_find_valid_concurrent_session(hal)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_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 + */ + if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + qdf_mc_timer_stop(&mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + qdf_mc_timer_destroy( + &mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + } + mac_ctx->sap.SapDfsInfo.cac_state = eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hal); + qdf_mem_zero(&mac_ctx->sap, sizeof(mac_ctx->sap)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_set_session_param(tHalHandle hal, struct sap_context *sapctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + int i; + + sapctx->sessionId = session_id; + sapctx->is_pre_cac_on = false; + sapctx->pre_cac_complete = false; + sapctx->chan_before_pre_cac = 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].sessionID = + sapctx->sessionId; + mac_ctx->sap.sapCtxList[sapctx->sessionId].sap_context = sapctx; + mac_ctx->sap.sapCtxList[sapctx->sessionId].sapPersona = + sapctx->csr_roamProfile.csrPersona; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: Initializing sapContext = %pK with session = %d", __func__, + sapctx, session_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_clear_session_param(tHalHandle hal, struct sap_context *sapctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (sapctx->sessionId >= SAP_MAX_NUM_SESSION) + return QDF_STATUS_E_FAILURE; + + mac_ctx->sap.sapCtxList[sapctx->sessionId].sessionID = + CSR_SESSION_ID_INVALID; + 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(hal); + sap_free_roam_profile(&sapctx->csr_roamProfile); + qdf_mem_zero(sapctx, sizeof(*sapctx)); + sapctx->sessionId = CSR_SESSION_ID_INVALID; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: Initializing State: %d, sapContext value = %pK", __func__, + sapctx->fsm_state, sapctx); + + return QDF_STATUS_SUCCESS; +} + +/** + * 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 qdf_ret_status; + tHalHandle hal; + + hal = CDS_GET_HAL_CB(); + if (!hal) { + /* we have a serious problem */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s, invalid hal", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_free_roam_profile(&sap_ctx->csr_roamProfile); + qdf_ret_status = sme_roam_stop_bss(hal, sap_ctx->sessionId); + if (qdf_ret_status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sme_roam_stop_bss status = %d", + __func__, qdf_ret_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; + tWLAN_SAPEvent 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: tSap_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, + tSap_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.channellist = + sap_context->channelList; +} +#else +static void sap_handle_acs_scan_event(struct sap_context *sap_context, + tSap_Event *sap_event, eSapStatus status) +{ +} +#endif + +/** + * 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; + tSap_Event sap_ap_event = {0}; + tHalHandle hal = CDS_GET_HAL_CB(); + tpAniSirGlobal mac_ctx; + tSirSmeChanInfo *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 (NULL == sap_ctx->pfnSapEventCallback) { + return QDF_STATUS_E_FAILURE; + } + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + return QDF_STATUS_E_FAILURE; + } + mac_ctx = PMAC_STRUCT(hal); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("SAP event callback event = %s"), + sap_hdd_event_to_string(sap_hddevent)); + + switch (sap_hddevent) { + case eSAP_STA_ASSOC_IND: + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + 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->beaconLength = csr_roaminfo->beaconLength; + assoc_ind->beaconPtr = csr_roaminfo->beaconPtr; + 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->u.pConnectedProfile != NULL) { + assoc_ind->negotiatedAuthType = + csr_roaminfo->u.pConnectedProfile->AuthType; + assoc_ind->negotiatedUCEncryptionType = + csr_roaminfo->u.pConnectedProfile->EncryptionType; + assoc_ind->negotiatedMCEncryptionType = + csr_roaminfo->u.pConnectedProfile->mcEncryptionType; + assoc_ind->fAuthRequired = csr_roaminfo->fAuthRequired; + } + 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 == CSR_SESSION_ID_INVALID) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sessionId")); + return QDF_STATUS_E_INVAL; + } + + bss_complete->status = (eSapStatus) context; + bss_complete->staId = sap_ctx->sap_sta_id; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("(eSAP_START_BSS_EVENT): staId = %d"), + bss_complete->staId); + + bss_complete->operatingChannel = (uint8_t) sap_ctx->channel; + bss_complete->ch_width = sap_ctx->ch_params.ch_width; + break; + case eSAP_DFS_CAC_START: + case eSAP_DFS_CAC_INTERRUPTED: + case eSAP_DFS_CAC_END: + case eSAP_DFS_PRE_CAC_END: + case eSAP_DFS_RADAR_DETECT: + case eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC: + case eSAP_DFS_NO_AVAILABLE_CHANNEL: + sap_ap_event.sapHddEventCode = sap_hddevent; + sap_ap_event.sapevt.sapStopBssCompleteEvent.status = + (eSapStatus) context; + 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 = sap_ctx->acs_cfg->pri_ch; + acs_selected->ht_sec_ch = sap_ctx->acs_cfg->ht_sec_ch; + acs_selected->ch_width = sap_ctx->acs_cfg->ch_width; + acs_selected->vht_seg0_center_ch = + sap_ctx->acs_cfg->vht_seg0_center_ch; + acs_selected->vht_seg1_center_ch = + sap_ctx->acs_cfg->vht_seg1_center_ch; + } else if (eSAP_STATUS_FAILURE == (eSapStatus)context) { + acs_selected->pri_ch = 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + if (sap_ctx->fsm_state == SAP_STOPPING) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "SAP is stopping, not able to handle any incoming (re)assoc req"); + return QDF_STATUS_E_ABORTED; + } + + 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); + reassoc_complete->staId = csr_roaminfo->staId; + reassoc_complete->statusCode = csr_roaminfo->statusCode; + reassoc_complete->iesLen = csr_roaminfo->rsnIELen; + qdf_mem_copy(reassoc_complete->ies, csr_roaminfo->prsnIE, + csr_roaminfo->rsnIELen); + +#ifdef FEATURE_WLAN_WAPI + if (csr_roaminfo->wapiIELen) { + uint8_t len = reassoc_complete->iesLen; + + reassoc_complete->iesLen += csr_roaminfo->wapiIELen; + qdf_mem_copy(&reassoc_complete->ies[len], + csr_roaminfo->pwapiIE, + csr_roaminfo->wapiIELen); + } +#endif + if (csr_roaminfo->addIELen) { + uint8_t len = reassoc_complete->iesLen; + + reassoc_complete->iesLen += csr_roaminfo->addIELen; + qdf_mem_copy(&reassoc_complete->ies[len], + csr_roaminfo->paddIE, + 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; + } + } + + /* also fill up the channel info from the csr_roamInfo */ + chaninfo = &reassoc_complete->chan_info; + + chaninfo->chan_id = csr_roaminfo->chan_info.chan_id; + 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->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; + 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->capability_info = + csr_roaminfo->capability_info; + + break; + + case eSAP_STA_DISASSOC_EVENT: + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + 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->statusCode = csr_roaminfo->statusCode; + 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->reason_code = csr_roaminfo->disassoc_reason; + break; + + case eSAP_STA_SET_KEY_EVENT: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + 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_ASSOC_STA_CALLBACK_EVENT: + break; + + case eSAP_WPS_PBC_PROBE_REQ_EVENT: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + 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 = sap_ctx->channel; + sap_ctx->acs_cfg->ch_width = + sap_ctx->csr_roamProfile.ch_params.ch_width; + sap_config_acs_result(hal, sap_ctx, sap_ctx->secondary_ch); + + sap_ap_event.sapHddEventCode = eSAP_CHANNEL_CHANGE_EVENT; + + acs_selected = &sap_ap_event.sapevt.sap_ch_selected; + acs_selected->pri_ch = sap_ctx->channel; + acs_selected->ht_sec_ch = sap_ctx->secondary_ch; + acs_selected->ch_width = + sap_ctx->csr_roamProfile.ch_params.ch_width; + acs_selected->vht_seg0_center_ch = + sap_ctx->csr_roamProfile.ch_params.center_freq_seg0; + acs_selected->vht_seg1_center_ch = + sap_ctx->csr_roamProfile.ch_params.center_freq_seg1; + break; + + case eSAP_ECSA_CHANGE_CHAN_IND: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, SAP event callback event = %s", + __func__, "eSAP_ECSA_CHANGE_CHAN_IND"); + sap_ap_event.sapHddEventCode = eSAP_ECSA_CHANGE_CHAN_IND; + sap_ap_event.sapevt.sap_chan_cng_ind.new_chan = + csr_roaminfo->target_channel; + break; + case eSAP_DFS_NEXT_CHANNEL_REQ: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, SAP event callback event = %s", + __func__, "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; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("stopping session_id:%d, bssid:%pM, channel:%d"), + sap_ctx->sessionId, sap_ctx->self_mac_addr, + sap_ctx->channel); + break; + + case eSAP_CHANNEL_CHANGE_RESP: + sap_ap_event.sapHddEventCode = eSAP_CHANNEL_CHANGE_RESP; + sap_ap_event.sapevt.ch_change_rsp_status = (QDF_STATUS)context; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, SAP event callback event = %s", + __func__, "eSAP_CHANNEL_CHANGE_RESP"); + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("SAP Unknown callback event = %d"), + sap_hddevent); + break; + } + qdf_status = (*sap_ctx->pfnSapEventCallback) + (&sap_ap_event, sap_ctx->pUsrContext); + + return qdf_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(tHalHandle handle) +{ + tpAniSirGlobal mac = PMAC_STRUCT(handle); + uint8_t i = 0; + struct sap_context *sap_ctx; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "%s", __func__); + + 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_ctx) && + (sap_ctx->fsm_state == SAP_DFS_CAC_WAIT)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "%s: found SAP in cac wait state", __func__); + return sap_ctx; + } + if (sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: mode:%d intf:%d state:%d", + mac->sap.sapCtxList[i].sapPersona, i, + sap_ctx->fsm_state); + } + } + + return NULL; +} + +/*========================================================================== + FUNCTION sap_cac_reset_notify + + DESCRIPTION Function will be called up on stop bss indication to clean up + DFS global structure. + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : void. + + SIDE EFFECTS + ============================================================================*/ +void sap_cac_reset_notify(tHalHandle hHal) +{ + uint8_t intf = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context = + pMac->sap.sapCtxList[intf].sap_context; + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].sap_context != NULL) { + sap_context->isCacStartNotified = false; + sap_context->isCacEndNotified = false; + } + } +} + +/*========================================================================== + FUNCTION sap_cac_start_notify + + DESCRIPTION Function will be called to notify eSAP_DFS_CAC_START event + to HDD + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : QDF_STATUS. + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_cac_start_notify(tHalHandle hHal) +{ + uint8_t intf = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context = + pMac->sap.sapCtxList[intf].sap_context; + struct csr_roam_profile *profile; + + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].sap_context != NULL && + (false == sap_context->isCacStartNotified)) { + /* Don't start CAC for non-dfs channel, its violation */ + profile = &sap_context->csr_roamProfile; + if (!wlan_reg_is_dfs_ch(pMac->pdev, + profile->operationChannel)) + continue; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "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) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacStartNotified on interface[%d]", + __func__, intf); + return qdf_status; + } + sap_context->isCacStartNotified = true; + } + } + return qdf_status; +} + +/** + * wlansap_update_pre_cac_end() - 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: QDF_STATUS + */ +static QDF_STATUS wlansap_update_pre_cac_end(struct sap_context *sap_context, + tpAniSirGlobal mac, uint8_t intf) +{ + QDF_STATUS qdf_status; + + sap_context->isCacEndNotified = true; + mac->sap.SapDfsInfo.sap_radar_found_status = false; + sap_context->fsm_state = SAP_STARTED; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s, pre cac end notify on %d: from state %s => %s", + __func__, intf, "SAP_DFS_CAC_WAIT", + "SAP_STARTED"); + + qdf_status = sap_signal_hdd_event(sap_context, + NULL, eSAP_DFS_PRE_CAC_END, + (void *)eSAP_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, pre cac notify failed on intf %d", + __func__, intf); + return qdf_status; + } + + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION sap_cac_end_notify + + DESCRIPTION Function will be called to notify eSAP_DFS_CAC_END event + to HDD + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : QDF_STATUS. + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_cac_end_notify(tHalHandle hHal, + struct csr_roam_info *roamInfo) +{ + uint8_t intf; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + /* + * 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 = + pMac->sap.sapCtxList[intf].sap_context; + struct csr_roam_profile *profile; + + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].sap_context != NULL && + (false == sap_context->isCacEndNotified) && + (sap_context->fsm_state == SAP_DFS_CAC_WAIT)) { + sap_context = pMac->sap.sapCtxList[intf].sap_context; + /* Don't check CAC for non-dfs channel */ + profile = &sap_context->csr_roamProfile; + if (!wlan_reg_is_dfs_ch(pMac->pdev, + profile->operationChannel)) + 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 (sap_context->is_pre_cac_on) { + qdf_status = wlansap_update_pre_cac_end( + sap_context, pMac, intf); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + /* 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacEndNotified on interface[%d]", + __func__, intf); + return qdf_status; + } + sap_context->isCacEndNotified = true; + pMac->sap.SapDfsInfo.sap_radar_found_status = false; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "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) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: channel[%d] from state %s => %s", + sap_context->channel, "SAP_STARTING", + "SAP_STARTED"); + + sap_context->fsm_state = SAP_STARTED; + + /*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) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacEndNotified on interface[%d]", + __func__, intf); + return qdf_status; + } + + /* Transition from SAP_STARTING to SAP_STARTED + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, from state %s => %s", + __func__, "SAP_DFS_CAC_WAIT", + "SAP_STARTED"); + } + } + /* + * 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 beacause + * AP2 is already beaconing on this channel. This case will be handled + * by checking against eSAP_DFS_SKIP_CAC while starting the timer. + */ + pMac->sap.SapDfsInfo.cac_state = eSAP_DFS_SKIP_CAC; + return qdf_status; +} + +/** + * sap_goto_starting() - Trigger softap start + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * 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, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + bool b_leak_chan = false; + uint8_t temp_chan; + + temp_chan = sap_ctx->channel; + utils_dfs_mark_leaking_ch(mac_ctx->pdev, + sap_ctx->ch_params.ch_width, + 1, &temp_chan); + + /* + * if selelcted channel has leakage to channels + * in NOL, the temp_chan will be reset + */ + b_leak_chan = (temp_chan != sap_ctx->channel); + /* + * check if channel is in DFS_NOL or if the channel + * has leakage to the channels in NOL + */ + if (sap_dfs_is_channel_in_nol_list(sap_ctx, sap_ctx->channel, + PHY_CHANNEL_BONDING_STATE_MAX) || + b_leak_chan) { + uint8_t ch; + + /* find a new available channel */ + ch = sap_random_channel_sel(sap_ctx); + if (!ch) { + /* No available channel found */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("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; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("channel %d is in NOL, Start Bss on new chan %d"), + sap_ctx->channel, ch); + + sap_ctx->channel = ch; + wlan_reg_set_channel_params(mac_ctx->pdev, + sap_ctx->channel, + sap_ctx->secondary_ch, + &sap_ctx->ch_params); + } + if (sap_ctx->channel > 14 && + (sap_ctx->csr_roamProfile.phyMode == eCSR_DOT11_MODE_11g || + sap_ctx->csr_roamProfile.phyMode == + eCSR_DOT11_MODE_11g_ONLY)) + sap_ctx->csr_roamProfile.phyMode = eCSR_DOT11_MODE_11a; + + /* + * 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)) { + uint16_t con_ch; + + con_ch = sme_get_beaconing_concurrent_operation_channel( + hal, sap_ctx->sessionId); + if (con_ch && wlan_reg_is_dfs_ch(mac_ctx->pdev, con_ch)) { + sap_ctx->channel = con_ch; + wlan_reg_set_channel_params(mac_ctx->pdev, + sap_ctx->channel, 0, + &sap_ctx->ch_params); + } + } + + /* + * Transition from SAP_INIT to SAP_STARTING + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "SAP_INIT", "SAP_STARTING"); + /* Channel selected. Now can sap_goto_starting */ + sap_ctx->fsm_state = SAP_STARTING; + /* Specify the channel */ + sap_ctx->csr_roamProfile.ChannelInfo.numOfChannels = + 1; + sap_ctx->csr_roamProfile.ChannelInfo.ChannelList = + &sap_ctx->csr_roamProfile.operationChannel; + sap_ctx->csr_roamProfile.operationChannel = + (uint8_t)sap_ctx->channel; + sap_ctx->csr_roamProfile.ch_params.ch_width = + sap_ctx->ch_params.ch_width; + sap_ctx->csr_roamProfile.ch_params.center_freq_seg0 = + sap_ctx->ch_params.center_freq_seg0; + sap_ctx->csr_roamProfile.ch_params.center_freq_seg1 = + sap_ctx->ch_params.center_freq_seg1; + sap_ctx->csr_roamProfile.ch_params.sec_ch_offset = + sap_ctx->ch_params.sec_ch_offset; + sap_get_cac_dur_dfs_region(sap_ctx, + &sap_ctx->csr_roamProfile.cac_duration_ms, + &sap_ctx->csr_roamProfile.dfs_regdomain); + sap_ctx->csr_roamProfile.beacon_tx_rate = + sap_ctx->beacon_tx_rate; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("notify hostapd about channel selection: %d"), + sap_ctx->channel); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_CHANNEL_CHANGE_EVENT, + (void *)eSAP_STATUS_SUCCESS); + sap_dfs_set_current_channel(sap_ctx); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, "%s: session: %d", + __func__, sap_ctx->sessionId); + + qdf_status = sme_roam_connect(hal, sap_ctx->sessionId, + &sap_ctx->csr_roamProfile, + &sap_ctx->csr_roamId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to issue sme_roam_connect", __func__); + + return qdf_status; +} + +/** + * sap_fsm_state_init() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * 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, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + 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_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("channel is not valid!")); + goto exit; + } + + /* Transition from SAP_INIT to SAP_STARTING */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("new from state %s => %s: session:%d"), + "SAP_INIT", "SAP_STARTING", + sap_ctx->sessionId); + + qdf_status = sap_goto_starting(sap_ctx, sap_event, + mac_ctx, hal); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("sap_goto_starting failed")); + } else if (msg == eSAP_DFS_CHANNEL_CAC_START) { + /* + * No need of state check here, caller is expected to perform + * the checks before sending the event + */ + sap_ctx->fsm_state = SAP_DFS_CAC_WAIT; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("from state SAP_INIT => SAP_DFS_CAC_WAIT")); + if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running != true) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: starting dfs cac timer on sapctx[%pK]"), + sap_ctx); + sap_start_dfs_cac_timer(sap_ctx); + } + + qdf_status = sap_cac_start_notify(hal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, event msg %d"), + "SAP_INIT", msg); + } + +exit: + return qdf_status; +} + +/** + * sap_fsm_state_dfs_cac_wait() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "SAP_DFS_CAC_WAIT" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_dfs_cac_wait(struct sap_context *sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + struct csr_roam_info *roam_info = + (struct csr_roam_info *) (sap_event->params); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_DFS_CHANNEL_CAC_START) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "SAP_STARTING", "SAP_DFS_CAC_WAIT"); + if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running != true) + sap_start_dfs_cac_timer(sap_ctx); + qdf_status = sap_cac_start_notify(hal); + } else if (msg == eSAP_DFS_CHANNEL_CAC_RADAR_FOUND) { + uint8_t intf; + /* + * Radar found while performing channel availability + * check, need to switch the channel again + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "ENTERTRED CAC WAIT STATE-->SAP_STOPPING\n"); + if (mac_ctx->sap.SapDfsInfo.target_channel) { + wlan_reg_set_channel_params(mac_ctx->pdev, + mac_ctx->sap.SapDfsInfo.target_channel, 0, + &sap_ctx->ch_params); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid target channel %d"), + mac_ctx->sap.SapDfsInfo.target_channel); + return qdf_status; + } + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *t_sap_ctx; + struct csr_roam_profile *profile; + + 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 != NULL && + t_sap_ctx->fsm_state != SAP_INIT) { + profile = &t_sap_ctx->csr_roamProfile; + if (!wlan_reg_is_passive_or_disable_ch( + mac_ctx->pdev, + profile->operationChannel)) + continue; + /* SAP to be moved to STOPPING state */ + t_sap_ctx->fsm_state = SAP_STOPPING; + 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_channel); + } + } + } else if (msg == eSAP_DFS_CHANNEL_CAC_END) { + qdf_status = sap_cac_end_notify(hal, roam_info); + } else if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* Transition from SAP_DFS_CAC_WAIT to SAP_STOPPING */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "SAP_DFS_CAC_WAIT", "SAP_STOPPING"); + + /* + * Stop the CAC timer only in following conditions + * single AP: if there is a single AP then stop the timer + * mulitple APs: incase of multiple APs, make sure that + * all APs are down. + */ + if (NULL == sap_find_valid_concurrent_session(hal)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: no sessions are valid, stopping timer")); + sap_stop_dfs_cac_timer(sap_ctx); + } + + sap_ctx->fsm_state = SAP_STOPPING; + qdf_status = sap_goto_stopping(sap_ctx); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "SAP_DFS_CAC_WAIT", msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_starting() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * 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, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + 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; + + if (msg == eSAP_MAC_START_BSS_SUCCESS) { + /* + * Transition from SAP_STARTING to SAP_STARTED + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state channel = %d %s => %s ch_width %d"), + sap_ctx->channel, "SAP_STARTING", "SAP_STARTED", + sap_ctx->ch_params.ch_width); + sap_ctx->fsm_state = SAP_STARTED; + + /* Action code for transition */ + qdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("ap_ctx->ch_params.ch_width %d, channel %d"), + sap_ctx->ch_params.ch_width, + reg_get_channel_state(mac_ctx->pdev, + sap_ctx->channel)); + + /* + * 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) { + is_dfs = true; + } else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state(mac_ctx->pdev, + sap_ctx->channel) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state(mac_ctx->pdev, + sap_ctx->ch_params.center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_dfs = true; + } else { + if (wlan_reg_get_channel_state(mac_ctx->pdev, + sap_ctx->channel) == + CHANNEL_STATE_DFS) + is_dfs = true; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("is_dfs %d"), is_dfs); + if (is_dfs) { + sap_dfs_info = &mac_ctx->sap.SapDfsInfo; + if ((false == sap_dfs_info->ignore_cac) && + (eSAP_DFS_DO_NOT_SKIP_CAC == + sap_dfs_info->cac_state) && + !sap_ctx->pre_cac_complete) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("start cac timer")); + + /* Move the device in CAC_WAIT_STATE */ + sap_ctx->fsm_state = SAP_DFS_CAC_WAIT; + + /* + * Need to stop the OS transmit queues, + * so that no traffic can flow down the stack + */ + + /* Start CAC wait timer */ + if (sap_dfs_info->is_dfs_cac_timer_running != + true) + sap_start_dfs_cac_timer(sap_ctx); + qdf_status = sap_cac_start_notify(hal); + + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("skip cac timer")); + wlansap_start_beacon_req(sap_ctx); + } + } + } else if (msg == eSAP_MAC_START_FAILS || + msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * Transition from SAP_STARTING to SAP_INIT + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "SAP_STARTING", "SAP_INIT"); + + /* Advance outer statevar */ + sap_ctx->fsm_state = SAP_INIT; + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_FAILURE); + qdf_status = sap_goto_init(sap_ctx); + /* Close the SME session */ + } else if (msg == eSAP_OPERATING_CHANNEL_CHANGED) { + /* The operating channel has changed, update hostapd */ + sap_ctx->channel = + (uint8_t) mac_ctx->sap.SapDfsInfo.target_channel; + + sap_ctx->fsm_state = SAP_STARTED; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "SAP_STARTING", "SAP_STARTED"); + + /* 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 { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "SAP_STARTING", 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, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal 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) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "SAP_STARTED", "SAP_STOPPING"); + sap_ctx->fsm_state = SAP_STOPPING; + 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_channel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid target channel %d"), + mac_ctx->sap.SapDfsInfo.target_channel); + 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; + struct csr_roam_profile *profile; + + 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) { + temp_sap_ctx = + mac_ctx->sap.sapCtxList[intf].sap_context; + /* + * Radar won't come on non-dfs channel, so + * no need to move them + */ + profile = &temp_sap_ctx->csr_roamProfile; + if (!wlan_reg_is_passive_or_disable_ch( + mac_ctx->pdev, + profile->operationChannel)) + continue; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Sending CSAIE for sapctx[%pK]"), + temp_sap_ctx); + + qdf_status = + wlansap_dfs_send_csa_ie_request(temp_sap_ctx); + } + } + } else if (eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START == msg) { + enum QDF_OPMODE persona; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sap_ctx")); + return qdf_status; + } + + persona = mac_ctx->sap.sapCtxList[sap_ctx->sessionId]. + sapPersona; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("app trigger chan switch: mode:%d vdev:%d"), + persona, sap_ctx->sessionId); + + if ((QDF_SAP_MODE == persona) || (QDF_P2P_GO_MODE == persona)) + qdf_status = wlansap_dfs_send_csa_ie_request(sap_ctx); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "SAP_STARTED", 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 + * + * 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, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + 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) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "SAP_STOPPING", "SAP_INIT"); + sap_ctx->fsm_state = SAP_INIT; + + /* Close the SME session */ + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_STOP_BSS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } else if (msg == eWNI_SME_CHANNEL_CHANGE_REQ) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Send channel change request on sapctx[%pK]"), + sap_ctx); + + sap_get_cac_dur_dfs_region(sap_ctx, + &sap_ctx->csr_roamProfile.cac_duration_ms, + &sap_ctx->csr_roamProfile.dfs_regdomain); + /* + * 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_channel); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("Sending DFS eWNI_SME_CHANNEL_CHANGE_REQ")); + } else if (msg == eWNI_SME_CHANNEL_CHANGE_RSP) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("in state %s, event msg %d result %d"), + "SAP_STOPPING ", msg, sap_event->u2); + if (sap_event->u2 == eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE) + qdf_status = sap_goto_stopping(sap_ctx); + } else if ((msg == eSAP_HDD_STOP_INFRA_BSS) && + (sap_ctx->is_chan_change_inprogress)) { + /* stop bss is received while processing channel change */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("in state %s, event msg %d result %d"), + "SAP_STOPPING ", msg, sap_event->u2); + qdf_status = sap_goto_stopping(sap_ctx); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "SAP_STOPPING", msg); + } + + return qdf_status; +} + +/** + * sap_fsm() - SAP statem machine entry function + * @sap_ctx: SAP context + * @sap_event: SAP event + * + * SAP statem machine entry function + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_fsm(struct sap_context *sap_ctx, ptWLAN_SAPEvent 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; +#ifdef WLAN_DEBUG + uint32_t msg = sap_event->event; /* State machine input event message */ +#endif + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tHalHandle hal = CDS_GET_HAL_CB(); + tpAniSirGlobal mac_ctx; + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + return QDF_STATUS_E_FAILURE; + } + + mac_ctx = PMAC_STRUCT(hal); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("sap_ctx=%pK, state_var=%d, msg=0x%x"), + sap_ctx, state_var, msg); + + switch (state_var) { + case SAP_INIT: + qdf_status = sap_fsm_state_init(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case SAP_DFS_CAC_WAIT: + qdf_status = sap_fsm_state_dfs_cac_wait(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case SAP_STARTING: + qdf_status = sap_fsm_state_starting(sap_ctx, sap_event, + mac_ctx, hal); + 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, hal); + break; + } + return qdf_status; +} + +eSapStatus +sapconvert_to_csr_profile(tsap_config_t *pconfig_params, eCsrRoamBssType bssType, + struct csr_roam_profile *profile) +{ + /* Create Roam profile for SoftAP to connect */ + profile->BSSType = eCSR_BSS_TYPE_INFRA_AP; + profile->SSIDs.numOfSSIDs = 1; + profile->csrPersona = pconfig_params->persona; + profile->disableDFSChSwitch = pconfig_params->disableDFSChSwitch; + + qdf_mem_zero(profile->SSIDs.SSIDList[0].SSID.ssId, + sizeof(profile->SSIDs.SSIDList[0].SSID.ssId)); + + /* Flag to not broadcast the SSID information */ + profile->SSIDs.SSIDList[0].ssidHidden = + pconfig_params->SSIDinfo.ssidHidden; + + profile->SSIDs.SSIDList[0].SSID.length = + pconfig_params->SSIDinfo.ssid.length; + qdf_mem_copy(&profile->SSIDs.SSIDList[0].SSID.ssId, + pconfig_params->SSIDinfo.ssid.ssId, + sizeof(pconfig_params->SSIDinfo.ssid.ssId)); + + profile->negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + if (pconfig_params->authType == eSAP_OPEN_SYSTEM) { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + } else if (pconfig_params->authType == eSAP_SHARED_KEY) { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_SHARED_KEY; + } else { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_AUTOSWITCH; + } + + profile->AuthType.numEntries = 1; + profile->AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + /* Always set the Encryption Type */ + profile->EncryptionType.numEntries = 1; + profile->EncryptionType.encryptionType[0] = + pconfig_params->RSNEncryptType; + + profile->mcEncryptionType.numEntries = 1; + profile->mcEncryptionType.encryptionType[0] = + pconfig_params->mcRSNEncryptType; + + if (pconfig_params->privacy & eSAP_SHARED_KEY) { + profile->AuthType.authType[0] = eCSR_AUTH_TYPE_SHARED_KEY; + } + + profile->privacy = pconfig_params->privacy; + profile->fwdWPSPBCProbeReq = pconfig_params->fwdWPSPBCProbeReq; + + if (pconfig_params->authType == eSAP_SHARED_KEY) { + profile->csr80211AuthType = eSIR_SHARED_KEY; + } else if (pconfig_params->authType == eSAP_OPEN_SYSTEM) { + profile->csr80211AuthType = eSIR_OPEN_SYSTEM; + } else { + profile->csr80211AuthType = eSIR_AUTO_SWITCH; + } + + /* Initialize we are not going to use it */ + profile->pWPAReqIE = NULL; + profile->nWPAReqIELength = 0; + + if (profile->pRSNReqIE) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("pRSNReqIE already allocated.")); + qdf_mem_free(profile->pRSNReqIE); + profile->pRSNReqIE = NULL; + } + + /* set the RSN/WPA IE */ + profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength; + if (pconfig_params->RSNWPAReqIELength) { + profile->pRSNReqIE = + qdf_mem_malloc(pconfig_params->RSNWPAReqIELength); + if (NULL == profile->pRSNReqIE) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + " %s Fail to alloc memory", __func__); + return eSAP_STATUS_FAILURE; + } + qdf_mem_copy(profile->pRSNReqIE, pconfig_params->RSNWPAReqIE, + pconfig_params->RSNWPAReqIELength); + profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength; + } + + /* set the phyMode to accept anything */ + /* Best means everything because it covers all the things we support */ + /* eCSR_DOT11_MODE_BEST */ + profile->phyMode = pconfig_params->SapHw_mode; + + /* Configure beaconInterval */ + profile->beaconInterval = (uint16_t) pconfig_params->beacon_int; + + /* set DTIM period */ + profile->dtimPeriod = pconfig_params->dtim_period; + + /* set Uapsd enable bit */ + profile->ApUapsdEnable = pconfig_params->UapsdEnable; + + /* Enable protection parameters */ + profile->protEnabled = pconfig_params->protEnabled; + profile->obssProtEnabled = pconfig_params->obssProtEnabled; + profile->cfg_protection = pconfig_params->ht_capab; + + /* country code */ + if (pconfig_params->countryCode[0]) + qdf_mem_copy(profile->countryCode, pconfig_params->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + profile->ieee80211d = pconfig_params->ieee80211d; + /* wps config info */ + profile->wps_state = pconfig_params->wps_state; + +#ifdef WLAN_FEATURE_11W + /* MFP capable/required */ + profile->MFPCapable = pconfig_params->mfpCapable ? 1 : 0; + profile->MFPRequired = pconfig_params->mfpRequired ? 1 : 0; +#endif + + if (pconfig_params->probeRespIEsBufferLen > 0 && + pconfig_params->pProbeRespIEsBuffer != NULL) { + profile->addIeParams.probeRespDataLen = + pconfig_params->probeRespIEsBufferLen; + profile->addIeParams.probeRespData_buff = + pconfig_params->pProbeRespIEsBuffer; + } else { + profile->addIeParams.probeRespDataLen = 0; + profile->addIeParams.probeRespData_buff = NULL; + } + /*assoc resp IE */ + if (pconfig_params->assocRespIEsLen > 0 && + pconfig_params->pAssocRespIEsBuffer != NULL) { + profile->addIeParams.assocRespDataLen = + pconfig_params->assocRespIEsLen; + profile->addIeParams.assocRespData_buff = + pconfig_params->pAssocRespIEsBuffer; + } else { + profile->addIeParams.assocRespDataLen = 0; + profile->addIeParams.assocRespData_buff = NULL; + } + + if (pconfig_params->probeRespBcnIEsLen > 0 && + pconfig_params->pProbeRespBcnIEsBuffer != NULL) { + profile->addIeParams.probeRespBCNDataLen = + pconfig_params->probeRespBcnIEsLen; + profile->addIeParams.probeRespBCNData_buff = + pconfig_params->pProbeRespBcnIEsBuffer; + } else { + profile->addIeParams.probeRespBCNDataLen = 0; + profile->addIeParams.probeRespBCNData_buff = NULL; + } + profile->sap_dot11mc = pconfig_params->sap_dot11mc; + + if (pconfig_params->supported_rates.numRates) { + qdf_mem_copy(profile->supported_rates.rate, + pconfig_params->supported_rates.rate, + pconfig_params->supported_rates.numRates); + profile->supported_rates.numRates = + pconfig_params->supported_rates.numRates; + } + + if (pconfig_params->extended_rates.numRates) { + qdf_mem_copy(profile->extended_rates.rate, + pconfig_params->extended_rates.rate, + pconfig_params->extended_rates.numRates); + profile->extended_rates.numRates = + pconfig_params->extended_rates.numRates; + } + + profile->chan_switch_hostapd_rate_enabled = + pconfig_params->chan_switch_hostapd_rate_enabled; + + return eSAP_STATUS_SUCCESS; /* Success. */ +} + +void sap_free_roam_profile(struct csr_roam_profile *profile) +{ + if (profile->pRSNReqIE) { + qdf_mem_free(profile->pRSNReqIE); + profile->pRSNReqIE = NULL; + } +} + +void sap_sort_mac_list(struct qdf_mac_addr *macList, uint8_t size) +{ + uint8_t outer, inner; + struct qdf_mac_addr temp; + int32_t nRes = -1; + + if ((NULL == macList) || (size > MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("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, + uint8_t num_mac, uint8_t *peerMac, + uint8_t *index) +{ + int32_t nRes = -1; + int8_t nStart = 0, nEnd, nMiddle; + + nEnd = num_mac - 1; + + if ((NULL == macList) || (num_mac > MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "search SUCC"); + /* "index equals NULL" means the caller does not need the */ + /* index value of the peerMac being searched */ + if (index != NULL) { + *index = (uint8_t) nMiddle; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, "index %d", + *index); + } + return true; + } + if (nRes < 0) + nStart = nMiddle + 1; + else + nEnd = nMiddle - 1; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "search not succ"); + return false; +} + +void sap_add_mac_to_acl(struct qdf_mac_addr *macList, + uint8_t *size, uint8_t *peerMac) +{ + int32_t nRes = -1; + int i; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "add acl entered"); + + if (NULL == macList || *size > MAX_ACL_MAC_ADDRESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("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, + uint8_t *size, uint8_t index) +{ + int i; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "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 == NULL) || (*size == 0) || + (*size > MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("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 addesses 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, uint8_t size) +{ + int i; + uint8_t *macArray; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "print acl entered"); + + if ((NULL == macList) || (size == 0) || (size >= MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, either buffer is NULL or size %d is incorrect.", + __func__, size); + return; + } + + for (i = 0; i < size; i++) { + macArray = (macList + i)->bytes; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "** ACL entry %i - " MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY(macArray)); + } + return; +} + +QDF_STATUS sap_is_peer_mac_allowed(struct sap_context *sapContext, + uint8_t *peerMac) +{ + if (eSAP_ALLOW_ALL == sapContext->eSapMacAddrAclMode) + return QDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sapContext->acceptMacList, sapContext->nAcceptMac, peerMac, NULL)) + return QDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sapContext->denyMacList, sapContext->nDenyMac, peerMac, NULL)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR " in deny list", + __func__, MAC_ADDR_ARRAY(peerMac)); + return QDF_STATUS_E_FAILURE; + } + /* A new station CAN associate, unless in deny list. Less stringent mode */ + if (eSAP_ACCEPT_UNLESS_DENIED == sapContext->eSapMacAddrAclMode) + return QDF_STATUS_SUCCESS; + + /* A new station CANNOT associate, unless in accept list. More stringent mode */ + if (eSAP_DENY_UNLESS_ACCEPTED == sapContext->eSapMacAddrAclMode) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR + " denied, Mac filter mode is eSAP_DENY_UNLESS_ACCEPTED", + __func__, MAC_ADDR_ARRAY(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 == sapContext->eSapMacAddrAclMode) { + sap_signal_hdd_event(sapContext, NULL, eSAP_UNKNOWN_STA_JOIN, + (void *) peerMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR + " denied, Mac filter mode is eSAP_SUPPORT_ACCEPT_AND_DENY", + __func__, MAC_ADDR_ARRAY(peerMac)); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef SOFTAP_CHANNEL_RANGE +/** + * sap_get_channel_list() - get the list of channels + * @sap_ctx: sap context + * @ch_list: pointer to channel list array + * @num_ch: pointer to number of channels. + * + * This function populates the list of channels for scanning. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_get_channel_list(struct sap_context *sap_ctx, + uint8_t **ch_list, + uint8_t *num_ch) +{ + uint8_t loop_count; + uint8_t *list; + uint8_t ch_count; + uint8_t start_ch_num, band_start_ch; + uint8_t end_ch_num, band_end_ch; + uint32_t en_lte_coex; + tHalHandle hal = CDS_GET_HAL_CB(); +#ifdef FEATURE_WLAN_CH_AVOID + uint8_t i; +#endif + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tSapChSelSpectInfo spect_info_obj = { NULL, 0 }; + uint16_t ch_width; + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid HAL pointer from p_cds_gctx")); + *num_ch = 0; + *ch_list = NULL; + return QDF_STATUS_E_FAULT; + } + + start_ch_num = sap_ctx->acs_cfg->start_ch; + end_ch_num = sap_ctx->acs_cfg->end_ch; + ch_width = sap_ctx->acs_cfg->ch_width; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("startChannel %d, EndChannel %d, ch_width %d, HW:%d"), + start_ch_num, end_ch_num, ch_width, + sap_ctx->acs_cfg->hw_mode); + + wlansap_extend_to_acs_range(hal, &start_ch_num, &end_ch_num, + &band_start_ch, &band_end_ch); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("expanded startChannel %d,EndChannel %d"), + start_ch_num, end_ch_num); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("band_start_ch %d, band_end_ch %d"), + band_start_ch, band_end_ch); + + sme_cfg_get_int(hal, WNI_CFG_ENABLE_LTE_COEX, &en_lte_coex); + + /* Check if LTE coex is enabled and 2.4GHz is selected */ + if (en_lte_coex && (band_start_ch == CHAN_ENUM_1) && + (band_end_ch == CHAN_ENUM_14)) { + /* Set 2.4GHz upper limit to channel 9 for LTE COEX */ + band_end_ch = CHAN_ENUM_9; + } + + /* Allocate the max number of channel supported */ + list = (uint8_t *) qdf_mem_malloc(NUM_5GHZ_CHANNELS + + NUM_24GHZ_CHANNELS); + if (NULL == list) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Unable to allocate channel list")); + *num_ch = 0; + *ch_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++) { + /* go to next channel if rf_channel is out of range */ + if ((start_ch_num > WLAN_REG_CH_NUM(loop_count)) || + (end_ch_num < WLAN_REG_CH_NUM(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(mac_ctx->pdev, + WLAN_REG_CH_NUM(loop_count))) + || + ((false == mac_ctx->scan.fEnableDFSChnlScan) && + (CHANNEL_STATE_ENABLE == + wlan_reg_get_channel_state(mac_ctx->pdev, + WLAN_REG_CH_NUM(loop_count))) + ))) + continue; + + /* + * Skip the channels which are not in ACS config from user + * space + */ + if (SAP_CHANNEL_NOT_SELECTED == + sap_channel_in_acs_channel_list( + WLAN_REG_CH_NUM(loop_count), + sap_ctx, &spect_info_obj)) + 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_ch(mac_ctx->pdev, + WLAN_REG_CH_NUM(loop_count)) && + (policy_mgr_disallow_mcc(mac_ctx->psoc, + WLAN_REG_CH_NUM(loop_count)) || + !sap_ctx->acs_cfg->dfs_master_mode)) + continue; + + /* Dont scan ETSI13 SRD channels if the ETSI13 SRD channels + * are not enabled in master mode + */ + if (!wlan_reg_is_etsi13_srd_chan_allowed_master_mode(mac_ctx-> + pdev) && + wlan_reg_is_etsi13_srd_chan(mac_ctx->pdev, + WLAN_REG_CH_NUM(loop_count))) + continue; + /* + * If we have any 5Ghz channel in the channel list + * and bw is 40/80/160 Mhz then we don't want SAP to + * come up in 2.4Ghz as for 40Mhz, 2.4Ghz channel is + * not preferred and 80/160Mhz is not allowed for 2.4Ghz + * band. So, don't even scan on 2.4Ghz channels if bw is + * 40/80/160Mhz and channel list has any 5Ghz channel. + */ + if (end_ch_num >= WLAN_REG_CH_NUM(CHAN_ENUM_36) && + ((ch_width == CH_WIDTH_40MHZ) || + (ch_width == CH_WIDTH_80MHZ) || + (ch_width == CH_WIDTH_80P80MHZ) || + (ch_width == CH_WIDTH_160MHZ))) { + if (WLAN_REG_CH_NUM(loop_count) >= + WLAN_REG_CH_NUM(CHAN_ENUM_1) && + WLAN_REG_CH_NUM(loop_count) <= + WLAN_REG_CH_NUM(CHAN_ENUM_14)) + continue; + } + +#ifdef FEATURE_WLAN_CH_AVOID + for (i = 0; i < NUM_CHANNELS; i++) { + if (safe_channels[i].channelNumber == + WLAN_REG_CH_NUM(loop_count)) { + /* Check if channel is safe */ + if (true == safe_channels[i].isSafe) { +#endif +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + uint8_t ch; + + ch = WLAN_REG_CH_NUM(loop_count); + if ((sap_ctx->acs_cfg->skip_scan_status == + eSAP_DO_PAR_ACS_SCAN)) { + if ((ch >= sap_ctx->acs_cfg->skip_scan_range1_stch && + ch <= sap_ctx->acs_cfg->skip_scan_range1_endch) || + (ch >= sap_ctx->acs_cfg->skip_scan_range2_stch && + ch <= sap_ctx->acs_cfg->skip_scan_range2_endch)) { + list[ch_count] = + WLAN_REG_CH_NUM(loop_count); + ch_count++; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + FL("%d %d added to ACS ch range"), + ch_count, ch); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("%d %d skipped from ACS ch range"), + ch_count, ch); + } + } else { + list[ch_count] = + WLAN_REG_CH_NUM(loop_count); + ch_count++; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + FL("%d %d added to ACS ch range"), + ch_count, ch); + } +#else + list[ch_count] = WLAN_REG_CH_NUM(loop_count); + ch_count++; +#endif +#ifdef FEATURE_WLAN_CH_AVOID + } + break; + } + } +#endif + } + if (0 == ch_count) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("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_num > band_end_ch)) + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + FL("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) { + *ch_list = list; + } else { + *ch_list = NULL; + qdf_mem_free(list); + return QDF_STATUS_SUCCESS; + } + + for (loop_count = 0; loop_count < ch_count; loop_count++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("channel number: %d"), list[loop_count]); + sap_ctx->acs_cfg->ch_list[loop_count] = list[loop_count]; + } + sap_ctx->acs_cfg->ch_list_count = ch_count; + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef DFS_COMPONENT_ENABLE +uint8_t sap_indicate_radar(struct sap_context *sap_ctx) +{ + uint8_t target_channel = 0; + tHalHandle hal; + tpAniSirGlobal mac; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null sap_ctx")); + return 0; + } + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("null hal")); + return 0; + } + + mac = PMAC_STRUCT(hal); + + /* + * 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 (sap_ctx->csr_roamProfile.disableDFSChSwitch) + return sap_ctx->channel; + + /* set the Radar Found flag in SapDfsInfo */ + mac->sap.SapDfsInfo.sap_radar_found_status = true; + + if (sap_ctx->chan_before_pre_cac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("sapdfs: set chan before pre cac %d as target chan"), + sap_ctx->chan_before_pre_cac); + return sap_ctx->chan_before_pre_cac; + } + + 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; + + target_channel = sap_random_channel_sel(sap_ctx); + if (!target_channel) + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, (void *) eSAP_STATUS_SUCCESS); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("sapdfs: New selected target channel is [%d]"), + target_channel); + + return target_channel; +} +#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 *sapContext; + tWLAN_SAPEvent sapEvent; + tHalHandle hHal = (tHalHandle) data; + tpAniSirGlobal pMac; + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return; + } + pMac = PMAC_STRUCT(hHal); + sapContext = sap_find_cac_wait_session(hHal); + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: no SAP contexts in wait state", __func__); + 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 (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running == true) { + if (!sapContext->dfs_cac_offload) + qdf_mc_timer_destroy( + &pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + } + + /* + * CAC Complete, post eSAP_DFS_CHANNEL_CAC_END to sap_fsm + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Sending eSAP_DFS_CHANNEL_CAC_END for target_channel = %d on sapctx[%pK]", + sapContext->channel, sapContext); + + sapEvent.event = eSAP_DFS_CHANNEL_CAC_END; + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + + sap_fsm(sapContext, &sapEvent); +} + +/* + * Function to stop the DFS CAC Timer + */ +static int sap_stop_dfs_cac_timer(struct sap_context *sapContext) +{ + tHalHandle hHal; + tpAniSirGlobal pMac; + + if (sapContext == NULL) + return 0; + + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return 0; + } + pMac = PMAC_STRUCT(hHal); + + if (sapContext->dfs_cac_offload) { + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + return 0; + } + + if (QDF_TIMER_STATE_RUNNING != + qdf_mc_timer_get_current_state(&pMac->sap.SapDfsInfo. + sap_dfs_cac_timer)) { + return 0; + } + + qdf_mc_timer_stop(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + qdf_mc_timer_destroy(&pMac->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; + tHalHandle hal = NULL; + tpAniSirGlobal mac = NULL; + enum dfs_reg dfs_region; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: null sap_ctx", __func__); + return 0; + } + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: null hal", __func__); + return 0; + } + + mac = PMAC_STRUCT(hal); + if (sap_ctx->dfs_cac_offload) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: cac timer offloaded to firmware", __func__); + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = true; + return 1; + } + + sap_get_cac_dur_dfs_region(sap_ctx, &cac_dur, &dfs_region); + if (0 == cac_dur) + return 0; + +#ifdef QCA_WIFI_NAPIER_EMULATION + cac_dur = cac_dur / 100; +#endif + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: SAP_DFS_CHANNEL_CAC_START on CH-%d, CAC_DUR-%d sec", + sap_ctx->channel, cac_dur / 1000); + + qdf_mc_timer_init(&mac->sap.SapDfsInfo.sap_dfs_cac_timer, + QDF_TIMER_TYPE_SW, + sap_dfs_cac_timer_callback, (void *)hal); + + /* Start the CAC timer */ + status = qdf_mc_timer_start(&mac->sap.SapDfsInfo.sap_dfs_cac_timer, + cac_dur); + if (status == QDF_STATUS_SUCCESS) { + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = true; + return 1; + } else { + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + qdf_mc_timer_destroy(&mac->sap.SapDfsInfo.sap_dfs_cac_timer); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: failed to start cac timer", __func__); + return 0; + } +} + +/* + * 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 *sapContext) +{ + tHalHandle hHal; + tpAniSirGlobal pMac; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid sapContext pointer on sap_init_dfs_channel_nol_list"); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(); + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + utils_dfs_init_nol(pMac->pdev); + + return QDF_STATUS_SUCCESS; +} + +/* + * 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(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t intf = 0; + uint8_t intf_count = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].sap_context != NULL) { + intf_count++; + } + } + return intf_count; +} + +/** + * is_concurrent_sap_ready_for_channel_change() - to check all saps are ready + * for channel change + * @hHal: HAL pointer + * @sapContext: 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(tHalHandle hHal, + struct sap_context *sapContext) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct sap_context *sap_context; + uint8_t intf = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].sap_context != NULL) { + sap_context = + pMac->sap.sapCtxList[intf].sap_context; + if (sap_context == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("sapCtx matched [%pK]"), + sapContext); + continue; + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL + ("concurrent sapCtx[%pK] didn't matche with [%pK]"), + sap_context, sapContext); + 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 + * @hal: pointer to hal + * @sap_context: 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 entitity doing SCC DFS else false + */ +bool sap_is_conc_sap_doing_scc_dfs(tHalHandle hal, + struct sap_context *given_sapctx) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sap_context *sap_ctx; + uint8_t intf = 0, scc_dfs_counter = 0; + + /* + * 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_ch(mac->pdev, + given_sapctx->csr_roamProfile.operationChannel)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("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 same SAP contexts then skip to next context */ + if (sap_ctx == given_sapctx) + continue; + if (given_sapctx->csr_roamProfile.operationChannel == + sap_ctx->csr_roamProfile.operationChannel) + scc_dfs_counter++; + } + + /* Found atleast two of the beaconing entities doing SCC DFS */ + if (scc_dfs_counter) + return true; + + return false; +} diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm_ext.h b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm_ext.h new file mode 100644 index 0000000000000000000000000000000000000000..8f4b68fd7bd7719f07e2c6867adc31b32148a4fe --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm_ext.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 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 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_CHANNEL_SWITCH_ANNOUNCEMENT_START, + + eSAP_NO_MSG +} eSapMsg_t; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_internal.h b/drivers/staging/qcacld-3.0/core/sap/src/sap_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..0500023387af1b5bc0cdde2afcac06f822ad9271 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_internal.h @@ -0,0 +1,501 @@ +/* + * 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_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 + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------- + * Defines + * -------------------------------------------------------------------------*/ +/* DFS Non Occupancy Period =30 minutes, in microseconds */ +#define SAP_DFS_NON_OCCUPANCY_PERIOD (30 * 60 * 1000 * 1000) + +#define SAP_DEBUG +/* Used to enable or disable security on the BT-AMP link */ +#define WLANSAP_SECURITY_ENABLED_STATE true + +#define CDS_GET_HAL_CB() cds_get_context(QDF_MODULE_ID_PE) +/* MAC Address length */ +#define ANI_EAPOL_KEY_RSN_NONCE_SIZE 32 + +#define IS_ETSI_WEATHER_CH(_ch) ((_ch >= 120) && (_ch <= 130)) +#define IS_CH_BONDING_WITH_WEATHER_CH(_ch) (_ch == 116) +#define IS_CHAN_JAPAN_W53(_ch) ((_ch >= 52) && (_ch <= 64)) +#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 + +/*---------------------------------------------------------------------------- + * 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_DFS_CAC_WAIT: cac wait + * @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_DFS_CAC_WAIT, + SAP_STARTING, + SAP_STARTED, + SAP_STOPPING +}; + +/*---------------------------------------------------------------------------- + * SAP context Data Type Declaration + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Type Declarations - QOS related + * -------------------------------------------------------------------------*/ +/* SAP QOS config */ +typedef struct sSapQosCfg { + uint8_t WmmIsEnabled; +} tSapQosCfg; + +typedef struct sSapAcsChannelInfo { + uint32_t channelNum; + uint32_t weight; +} tSapAcsChannelInfo; + +#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[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +}; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +struct sap_context { + + /* Include the current channel of AP */ + uint32_t channel; + uint32_t secondary_ch; + + /* Include the SME(CSR) sessionId here */ + uint8_t sessionId; + + /* Include the associations MAC addresses */ + uint8_t self_mac_addr[CDS_MAC_ADDRESS_LEN]; + + /* Own SSID */ + uint8_t ownSsid[MAX_SSID_LEN]; + uint32_t ownSsidLen; + + /* Flag for signaling if security is enabled */ + uint8_t ucSecEnabled; + + /* Include the SME(CSR) context here */ + struct csr_roam_profile csr_roamProfile; + uint32_t csr_roamId; + + /* SAP event Callback to hdd */ + tpWLAN_SAPEventCB pfnSapEventCallback; + + /* + * 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]; + uint8_t nAcceptMac; + struct qdf_mac_addr denyMacList[MAX_ACL_MAC_ADDRESS]; + uint8_t nDenyMac; + + /* QOS config */ + tSapQosCfg SapQosCfg; + + void *pUsrContext; + + uint32_t nStaWPARSnReqIeLength; + uint8_t pStaWpaRsnReqIE[MAX_ASSOC_IND_IE_LEN]; + + uint8_t *channelList; + uint8_t num_of_channel; + uint16_t ch_width_orig; + struct ch_params ch_params; + + /* session to scan */ + bool isScanSessionOpen; + /* + * This list of channels will hold 5Ghz enabled,DFS in the + * Current RegDomain.This list will be used to select a channel, + * for SAP to start including any DFS channel and also to select + * any random channel[5Ghz-(NON-DFS/DFS)],if SAP is operating + * on a DFS channel and a RADAR is detected on the channel. + */ + tAll5GChannelList SapAllChnlList; + uint32_t auto_channel_select_weight; + tSapAcsChannelInfo acsBestChannelInfo; + bool enableOverLapCh; + struct sap_acs_cfg *acs_cfg; + +#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_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 anyother purposes. + */ + eSapHddEvent sap_state; + eSapStatus sap_status; + uint32_t roc_ind_scan_id; + bool is_pre_cac_on; + bool pre_cac_complete; + bool vendor_acs_dfs_lte_enabled; + uint8_t dfs_vendor_channel; + uint8_t dfs_vendor_chan_bw; + uint8_t chan_before_pre_cac; + uint16_t beacon_tx_rate; + tSirMacRateSet supp_rate_set; + tSirMacRateSet extended_rate_set; + 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; + bool stop_bss_in_progress; +}; + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * SAP state machine event definition + * -------------------------------------------------------------------------*/ +/* The event structure */ +typedef struct sWLAN_SAPEvent { + /* A VOID pointer type for all possible inputs */ + void *params; + /* State machine input event message */ + uint32_t event; + /* introduced to handle csr_roam_complete_cb roamStatus */ + uint32_t u1; + /* introduced to handle csr_roam_complete_cb roamResult */ + uint32_t u2; +} tWLAN_SAPEvent, *ptWLAN_SAPEvent; + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ +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 + * @hal_handle: the hal_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(tHalHandle hal_handle, + struct sap_context *sap_ctx, + uint8_t sessionid, + uint32_t scanid, + eCsrScanStatus scan_status); + +QDF_STATUS SapFsm(struct sap_context *sapContext, ptWLAN_SAPEvent sapEvent, + uint8_t *status); + +uint8_t sap_select_channel(tHalHandle halHandle, struct sap_context *sap_ctx, + tScanResultHandle pScanResult); + +QDF_STATUS +sap_signal_hdd_event(struct sap_context *sapContext, + struct csr_roam_info *pCsrRoamInfo, + eSapHddEvent sapHddevent, void *); + +QDF_STATUS sap_fsm(struct sap_context *sapContext, ptWLAN_SAPEvent sapEvent); + +eSapStatus +sapconvert_to_csr_profile(tsap_config_t *pconfig_params, + eCsrRoamBssType bssType, + struct csr_roam_profile *profile); + +void sap_free_roam_profile(struct csr_roam_profile *profile); + +QDF_STATUS +sap_is_peer_mac_allowed(struct sap_context *sapContext, uint8_t *peerMac); + +void +sap_sort_mac_list(struct qdf_mac_addr *macList, uint8_t size); + +void +sap_add_mac_to_acl(struct qdf_mac_addr *macList, uint8_t *size, + uint8_t *peerMac); + +void +sap_remove_mac_from_acl(struct qdf_mac_addr *macList, uint8_t *size, + uint8_t index); + +void +sap_print_acl(struct qdf_mac_addr *macList, uint8_t size); + +bool +sap_search_mac_list(struct qdf_mac_addr *macList, uint8_t num_mac, + uint8_t *peerMac, uint8_t *index); + +#ifdef FEATURE_WLAN_CH_AVOID +void sap_update_unsafe_channel_list(tHalHandle hal, + struct sap_context *sap_ctx); +#endif /* FEATURE_WLAN_CH_AVOID */ + +QDF_STATUS sap_init_dfs_channel_nol_list(struct sap_context *sapContext); + +bool sap_dfs_is_channel_in_nol_list(struct sap_context *sapContext, + uint8_t channelNumber, + ePhyChanBondState chanBondState); +void sap_dfs_cac_timer_callback(void *data); + +void sap_cac_reset_notify(tHalHandle hHal); + +bool +sap_channel_matrix_check(struct sap_context *sapContext, + ePhyChanBondState cbMode, + uint8_t target_channel); + +bool is_concurrent_sap_ready_for_channel_change(tHalHandle hHal, + struct sap_context *sapContext); +bool sap_is_conc_sap_doing_scc_dfs(tHalHandle hal, + struct sap_context *given_sapctx); +uint8_t sap_get_total_number_sap_intf(tHalHandle hHal); + +bool sap_dfs_is_w53_invalid(tHalHandle hHal, uint8_t channelID); + +bool sap_dfs_is_channel_in_preferred_location(tHalHandle hHal, + uint8_t channelID); + +/** + * 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 *sapContext); + +/** + * 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 + * @hal: pointer to hardware abstraction layer + * @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(tHalHandle hal, struct sap_context *sapctx, + uint32_t session_id); +/** + * sap_clear_session_param() - clear sap related param from sap context + * @hal: pointer to hardware abstraction layer + * @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(tHalHandle hal, 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: channel to which sap wishes to switch. + */ +uint8_t sap_indicate_radar(struct sap_context *sap_ctx); +#else +static inline uint8_t sap_indicate_radar(struct sap_context *sap_ctx) +{ + return 0; +} +#endif + +/** + * sap_select_default_oper_chan() - Select AP mode default operating channel + * @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 number + */ +uint8_t sap_select_default_oper_chan(struct sap_acs_cfg *acs_cfg); + +/** + * sap_channel_in_acs_channel_list() - check if channel in acs channel list + * @channel_num: channel to check + * @sap_ctx: struct ptSapContext + * @spect_info_params: strcut tSapChSelSpectInfo + * + * This function checks if specified channel is in the configured ACS channel + * list. + * + * Return: channel number if in acs channel list or SAP_CHANNEL_NOT_SELECTED + */ +uint8_t sap_channel_in_acs_channel_list(uint8_t channel_num, + struct sap_context *sap_ctx, + tSapChSelSpectInfo *spect_info_params); + +/** + * sap_chan_bond_dfs_sub_chan - check bonded channel includes dfs sub chan + * @sap_context: Handle to SAP context. + * @channel_number: 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, + uint8_t channel_number, + ePhyChanBondState bond_state); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_module.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_module.c new file mode 100644 index 0000000000000000000000000000000000000000..42acc736517a600d57b9f97bf8ba5fcc5b03ee82 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_module.c @@ -0,0 +1,2905 @@ +/* + * 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. + */ + +/** + * =========================================================================== + * sapModule.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 + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define SAP_DEBUG + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +/* No! Get this from CDS. */ +/* The main per-Physical Link (per WLAN association) context. */ +static struct sap_context *gp_sap_ctx[SAP_MAX_NUM_SESSION]; +static qdf_atomic_t sap_ctx_ref_count[SAP_MAX_NUM_SESSION]; + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ +static qdf_mutex_t sap_context_lock; + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/** + * 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))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "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]); + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: sap global context initialized", __func__); + + 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]) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "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))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "failed to destroy sap_context_lock"); + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: sap global context deinitialized", __func__); + + 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] == NULL) { + gp_sap_ctx[i] = ctx; + qdf_atomic_inc(&sap_ctx_ref_count[i]); + qdf_mutex_release(&sap_context_lock); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: sap context saved at index: %d", + __func__, i); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&sap_context_lock); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: failed to save sap context", __func__); + + 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); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: sap session is not valid", __func__); + 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->channelList) { + qdf_mem_free(ctx->channelList); + ctx->channelList = NULL; + ctx->num_of_channel = 0; + } + qdf_mem_free(ctx); + gp_sap_ctx[i] = NULL; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_DEBUG, + "%s: sap session freed: %d", + __func__, 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; + + /* dynamically allocate the sapContext */ + sap_ctx = qdf_mem_malloc(sizeof(*sap_ctx)); + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return NULL; + } + + /* Clean up SAP control block, initialize all values */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, FL("Enter")); + + /* Save the SAP context pointer */ + status = wlansap_save_context(sap_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: failed to save SAP context", __func__); + qdf_mem_free(sap_ctx); + return NULL; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, FL("Exit")); + + return sap_ctx; +} /* sap_create_ctx */ + +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 qdf_ret_status; + tHalHandle hal; + tpAniSirGlobal pmac; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_start invoked successfully"); + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + /*------------------------------------------------------------------------ + For now, presume security is not enabled. + -----------------------------------------------------------------------*/ + sap_ctx->ucSecEnabled = WLANSAP_SECURITY_ENABLED_STATE; + + /*------------------------------------------------------------------------ + Now configure the roaming profile links. To SSID and bssid. + ------------------------------------------------------------------------*/ + /* We have room for two SSIDs. */ + sap_ctx->csr_roamProfile.SSIDs.numOfSSIDs = 1; /* This is true for now. */ + sap_ctx->csr_roamProfile.SSIDs.SSIDList = sap_ctx->SSIDList; /* Array of two */ + sap_ctx->csr_roamProfile.SSIDs.SSIDList[0].SSID.length = 0; + sap_ctx->csr_roamProfile.SSIDs.SSIDList[0].handoffPermitted = false; + sap_ctx->csr_roamProfile.SSIDs.SSIDList[0].ssidHidden = + sap_ctx->SSIDList[0].ssidHidden; + + sap_ctx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; /* This is true for now. */ + sap_ctx->csa_reason = CSA_REASON_UNKNOWN; + sap_ctx->csr_roamProfile.BSSIDs.bssid = &sap_ctx->bssid; + sap_ctx->csr_roamProfile.csrPersona = mode; + qdf_mem_copy(sap_ctx->self_mac_addr, addr, QDF_MAC_ADDR_SIZE); + + /* Now configure the auth type in the roaming profile. To open. */ + sap_ctx->csr_roamProfile.negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; /* open is the default */ + + hal = (tHalHandle) CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", __func__); + return QDF_STATUS_E_INVAL; + } + pmac = PMAC_STRUCT(hal); + qdf_ret_status = sap_set_session_param(hal, sap_ctx, session_id); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s calling sap_set_session_param status = %d", + __func__, qdf_ret_status); + return QDF_STATUS_E_FAILURE; + } + /* Register with scan component only during init */ + if (!reinit) + sap_ctx->req_id = + ucfg_scan_register_requester(pmac->psoc, "SAP", + sap_scan_event_callback, sap_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_deinit_ctx(struct sap_context *sap_ctx) +{ + tHalHandle hal; + tpAniSirGlobal pmac; + + /* Sanity check - Extract SAP control block */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "wlansap_stop invoked successfully "); + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + hal = CDS_GET_HAL_CB(); + pmac = (tpAniSirGlobal) hal; + if (NULL == pmac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC context", __func__); + return QDF_STATUS_E_FAULT; + } + ucfg_scan_unregister_requester(pmac->psoc, sap_ctx->req_id); + + if (sap_ctx->channelList) { + qdf_mem_free(sap_ctx->channelList); + sap_ctx->channelList = NULL; + sap_ctx->num_of_channel = 0; + } + sap_free_roam_profile(&sap_ctx->csr_roamProfile); + if (sap_ctx->sessionId != CSR_SESSION_ID_INVALID) { + /* empty queues/lists/pkts if any */ + sap_clear_session_param(hal, sap_ctx, sap_ctx->sessionId); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_destroy_ctx(struct sap_context *sap_ctx) +{ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "sap_destroy_ctx invoked"); + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + /* Cleanup SAP control block */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, FL("Enter")); + /* + * wlansap_context_put will release actual sap_ctx memory + * allocated during sap_create_ctx + */ + wlansap_context_put(sap_ctx); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, FL("Exit")); + + return QDF_STATUS_SUCCESS; +} /* sap_destroy_ctx */ + +bool wlansap_is_channel_in_nol_list(struct sap_context *sap_ctx, + uint8_t channelNumber, + ePhyChanBondState chanBondState) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + return sap_dfs_is_channel_in_nol_list(sap_ctx, channelNumber, + chanBondState); +} + +static QDF_STATUS wlansap_mark_leaking_channel(struct wlan_objmgr_pdev *pdev, + uint8_t *leakage_adjusted_lst, + uint8_t chan_bw) +{ + + return utils_dfs_mark_leaking_ch(pdev, chan_bw, 1, + leakage_adjusted_lst); +} + +bool wlansap_is_channel_leaking_in_nol(struct sap_context *sap_ctx, + uint8_t channel, + uint8_t chan_bw) +{ + tpAniSirGlobal mac_ctx; + uint8_t leakage_adjusted_lst[1]; + void *handle = NULL; + + leakage_adjusted_lst[0] = channel; + handle = CDS_GET_HAL_CB(); + mac_ctx = PMAC_STRUCT(handle); + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid mac pointer", __func__); + 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) +{ + tHalHandle hHal; + uint16_t intf_ch; + + hHal = (tHalHandle) CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC context from p_cds_gctx", __func__); + return 0; + } + intf_ch = sme_check_concurrent_channel_overlap(hHal, sap_ctx->channel, + sap_ctx->csr_roamProfile.phyMode, + sap_ctx->cc_switch_mode); + return intf_ch; +} +#endif + + /** + * wlansap_set_scan_acs_channel_params() - Config scan and channel parameters. + * pconfig: 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(tsap_config_t *pconfig, + struct sap_context *psap_ctx, + void *pusr_context) +{ + tHalHandle h_hal = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == pconfig) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid pconfig passed ", __func__); + return QDF_STATUS_E_FAULT; + } + + if (NULL == psap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid pconfig passed ", __func__); + return QDF_STATUS_E_FAULT; + } + + /* Channel selection is auto or configured */ + psap_ctx->channel = pconfig->channel; + psap_ctx->dfs_mode = pconfig->acs_dfs_mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + psap_ctx->cc_switch_mode = pconfig->cc_switch_mode; +#endif + psap_ctx->auto_channel_select_weight = + pconfig->auto_channel_select_weight; + psap_ctx->pUsrContext = pusr_context; + psap_ctx->enableOverLapCh = pconfig->enOverLapCh; + psap_ctx->acs_cfg = &pconfig->acs_cfg; + psap_ctx->ch_width_orig = pconfig->acs_cfg.ch_width; + psap_ctx->secondary_ch = pconfig->sec_ch; + + /* + * Set the BSSID to your "self MAC Addr" read + * the mac address from Configuation ITEM received + * from HDD + */ + psap_ctx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; + + /* Save a copy to SAP context */ + qdf_mem_copy(psap_ctx->csr_roamProfile.BSSIDs.bssid, + pconfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(psap_ctx->self_mac_addr, + pconfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + + h_hal = (tHalHandle)CDS_GET_HAL_CB(); + if (NULL == h_hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from pvosGCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + return status; +} + +/** + * wlan_sap_get_roam_profile() - Returns sap roam profile. + * @sap_ctx: Pointer to Sap Context. + * + * This function provides the SAP roam profile. + * + * Return: SAP RoamProfile + */ +struct csr_roam_profile *wlan_sap_get_roam_profile(struct sap_context *sap_ctx) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from ctx")); + return NULL; + } + return &sap_ctx->csr_roamProfile; +} + +eCsrPhyMode wlan_sap_get_phymode(struct sap_context *sap_ctx) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from ctx")); + return 0; + } + return sap_ctx->csr_roamProfile.phyMode; +} + +uint32_t wlan_sap_get_vht_ch_width(struct sap_context *sap_ctx) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer")); + return 0; + } + + return sap_ctx->ch_params.ch_width; +} + +void wlan_sap_set_vht_ch_width(struct sap_context *sap_ctx, + uint32_t vht_channel_width) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer")); + return; + } + + sap_ctx->ch_params.ch_width = vht_channel_width; +} + +/** + * wlan_sap_validate_channel_switch() - validate target channel switch w.r.t + * concurreny rules set to avoid channel interference. + * @hal - Hal context + * @sap_ch - 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(tHalHandle hal, uint16_t sap_ch, + struct sap_context *sap_context) +{ + return sme_validate_sap_channel_switch( + hal, + sap_ch, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode, + sap_context->sessionId); +} +#else +static inline bool wlan_sap_validate_channel_switch(tHalHandle hal, + uint16_t sap_ch, struct sap_context *sap_context) +{ + return true; +} +#endif + +void wlan_sap_set_sap_ctx_acs_cfg(struct sap_context *sap_ctx, + tsap_config_t *sap_config) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer", + __func__); + return; + } + + sap_ctx->acs_cfg = &sap_config->acs_cfg; +} + +QDF_STATUS wlansap_start_bss(struct sap_context *sap_ctx, + tpWLAN_SAPEventCB pSapEventCallback, + tsap_config_t *pConfig, void *pUsrContext) +{ + tWLAN_SAPEvent sapEvent; /* State machine event */ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tHalHandle hHal; + tpAniSirGlobal pmac = NULL; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_start_bss: sapContext=%pK", sap_ctx); + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer", + __func__); + return QDF_STATUS_E_FAULT; + } + sap_ctx->fsm_state = SAP_INIT; + + /* Channel selection is auto or configured */ + sap_ctx->channel = pConfig->channel; + sap_ctx->dfs_mode = pConfig->acs_dfs_mode; + sap_ctx->ch_params.ch_width = pConfig->ch_params.ch_width; + sap_ctx->ch_params.center_freq_seg0 = + pConfig->ch_params.center_freq_seg0; + sap_ctx->ch_params.center_freq_seg1 = + pConfig->ch_params.center_freq_seg1; + sap_ctx->ch_params.sec_ch_offset = + pConfig->ch_params.sec_ch_offset; + sap_ctx->ch_width_orig = pConfig->ch_width_orig; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + sap_ctx->cc_switch_mode = pConfig->cc_switch_mode; +#endif + sap_ctx->auto_channel_select_weight = + pConfig->auto_channel_select_weight; + sap_ctx->pUsrContext = pUsrContext; + sap_ctx->enableOverLapCh = pConfig->enOverLapCh; + sap_ctx->acs_cfg = &pConfig->acs_cfg; + sap_ctx->secondary_ch = pConfig->sec_ch; + sap_ctx->dfs_cac_offload = pConfig->dfs_cac_offload; + sap_ctx->isCacEndNotified = false; + sap_ctx->is_chan_change_inprogress = false; + sap_ctx->stop_bss_in_progress = false; + /* Set the BSSID to your "self MAC Addr" read the mac address + from Configuation ITEM received from HDD */ + sap_ctx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy(sap_ctx->csr_roamProfile.BSSIDs.bssid, + sap_ctx->self_mac_addr, sizeof(struct qdf_mac_addr)); + + /* Save a copy to SAP context */ + qdf_mem_copy(sap_ctx->csr_roamProfile.BSSIDs.bssid, + pConfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(sap_ctx->self_mac_addr, + pConfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + + /* copy the configuration items to csrProfile */ + sapconvert_to_csr_profile(pConfig, eCSR_BSS_TYPE_INFRA_AP, + &sap_ctx->csr_roamProfile); + hHal = (tHalHandle) CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from p_cds_gctx", + __func__); + qdf_status = QDF_STATUS_E_FAULT; + goto fail; + } + pmac = PMAC_STRUCT(hHal); + if (NULL == pmac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from p_cds_gctx", + __func__); + qdf_status = QDF_STATUS_E_FAULT; + goto fail; + } + + /* + * Copy the DFS Test Mode setting to pmac for + * access in lower layers + */ + pmac->sap.SapDfsInfo.disable_dfs_ch_switch = + pConfig->disableDFSChSwitch; + pmac->sap.SapDfsInfo.sap_ch_switch_beacon_cnt = + pConfig->sap_chanswitch_beacon_cnt; + pmac->sap.SapDfsInfo.sap_ch_switch_mode = + pConfig->sap_chanswitch_mode; + + pmac->sap.sapCtxList[sap_ctx->sessionId].sap_context = sap_ctx; + pmac->sap.sapCtxList[sap_ctx->sessionId].sapPersona = + sap_ctx->csr_roamProfile.csrPersona; + pmac->sap.sapCtxList[sap_ctx->sessionId].sessionID = + sap_ctx->sessionId; + pmac->sap.SapDfsInfo.dfs_beacon_tx_enhanced = + pConfig->dfs_beacon_tx_enhanced; + pmac->sap.SapDfsInfo.reduced_beacon_interval = + pConfig->reduced_beacon_interval; + + /* Copy MAC filtering settings to sap context */ + sap_ctx->eSapMacAddrAclMode = pConfig->SapMacaddr_acl; + qdf_mem_copy(sap_ctx->acceptMacList, pConfig->accept_mac, + sizeof(pConfig->accept_mac)); + sap_ctx->nAcceptMac = pConfig->num_accept_mac; + sap_sort_mac_list(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + qdf_mem_copy(sap_ctx->denyMacList, pConfig->deny_mac, + sizeof(pConfig->deny_mac)); + sap_ctx->nDenyMac = pConfig->num_deny_mac; + sap_sort_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac); + sap_ctx->beacon_tx_rate = pConfig->beacon_tx_rate; + + /* Fill in the event structure for FSM */ + sapEvent.event = eSAP_HDD_START_INFRA_BSS; + sapEvent.params = 0; /* pSapPhysLinkCreate */ + + /* Store the HDD callback in SAP context */ + sap_ctx->pfnSapEventCallback = pSapEventCallback; + + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sapEvent); +fail: + if (QDF_IS_STATUS_ERROR(qdf_status)) + sap_free_roam_profile(&sap_ctx->csr_roamProfile); + + return qdf_status; +} /* wlansap_start_bss */ + +QDF_STATUS wlansap_set_mac_acl(struct sap_context *sap_ctx, + tsap_config_t *pConfig) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_set_mac_acl"); + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + /* Copy MAC filtering settings to sap context */ + sap_ctx->eSapMacAddrAclMode = pConfig->SapMacaddr_acl; + + if (eSAP_DENY_UNLESS_ACCEPTED == sap_ctx->eSapMacAddrAclMode) { + qdf_mem_copy(sap_ctx->acceptMacList, + pConfig->accept_mac, + sizeof(pConfig->accept_mac)); + sap_ctx->nAcceptMac = pConfig->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, pConfig->deny_mac, + sizeof(pConfig->deny_mac)); + sap_ctx->nDenyMac = pConfig->num_deny_mac; + sap_sort_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac); + } + + return qdf_status; +} /* wlansap_set_mac_acl */ + +void wlansap_set_stop_bss_inprogress(struct sap_context *sap_ctx, + bool in_progress) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from ctx", __func__); + return; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: Set stop_bss_in_progress to %d", + __func__, in_progress); + sap_ctx->stop_bss_in_progress = in_progress; +} + +QDF_STATUS wlansap_stop_bss(struct sap_context *sap_ctx) +{ + tWLAN_SAPEvent sapEvent; /* State machine event */ + QDF_STATUS qdf_status; + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + /* Fill in the event structure for FSM */ + sapEvent.event = eSAP_HDD_STOP_INFRA_BSS; + sapEvent.params = 0; + + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sapEvent); + + 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 (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + 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 (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + 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, + uint8_t *nAcceptList) +{ + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + 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, + uint8_t *nDenyList) +{ + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + 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) +{ + uint8_t i; + + if (NULL == sap_ctx) { + return QDF_STATUS_E_RESOURCES; + } + + for (i = 0; i < (sap_ctx->nDenyMac - 1); 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 - 1); 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_white_list = false, sta_black_list = false; + uint8_t staWLIndex, staBLIndex; + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP Context", __func__); + return QDF_STATUS_E_FAULT; + } + if (qdf_mem_cmp(sap_ctx->bssid.bytes, peer_sta_mac, + QDF_MAC_ADDR_SIZE) == 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "requested peer mac is" MAC_ADDRESS_STR + "our own SAP BSSID. Do not blacklist or whitelist this BSSID", + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAULT; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "Modify ACL entered\n" "Before modification of ACL\n" + "size of accept and deny lists %d %d", sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** WHITE LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** BLACK 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 responsiblity of userspace to + * ensure this + */ + sta_white_list = + sap_search_mac_list(sap_ctx->acceptMacList, sap_ctx->nAcceptMac, + peer_sta_mac, &staWLIndex); + sta_black_list = + sap_search_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac, + peer_sta_mac, &staBLIndex); + + if (sta_white_list && sta_black_list) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Peer mac " MAC_ADDRESS_STR + " found in white and black lists." + "Initial lists passed incorrect. Cannot execute this command.", + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "cmd %d", cmd); + + switch (list_type) { + case eSAP_WHITE_LIST: + if (cmd == ADD_STA_TO_ACL) { + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nAcceptMac == MAX_ACL_MAC_ADDRESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "White list is already maxed out. Cannot accept " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + if (sta_white_list) { + /* Do nothing if already present in white list. Just print a warning */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address already present in white list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_SUCCESS; + } + if (sta_black_list) { + /* remove it from black list before adding to the white list */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "STA present in black list so first remove from it"); + sap_remove_mac_from_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + } + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "... Now add to the white list"); + sap_add_mac_to_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + peer_sta_mac); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL) { + if (sta_white_list) { + + struct csr_del_sta_params delStaParams; + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "Delete from white list"); + sap_remove_mac_from_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + staWLIndex); + /* If a client is deleted from white list and it is connected, send deauth */ + wlansap_populate_del_sta_params(peer_sta_mac, + eCsrForcedDeauthSta, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); + wlansap_deauth_sta(sap_ctx, &delStaParams); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address to be deleted is not present in the white list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid cmd type passed"); + return QDF_STATUS_E_FAILURE; + } + break; + + case eSAP_BLACK_LIST: + + if (cmd == ADD_STA_TO_ACL) { + struct csr_del_sta_params delStaParams; + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nDenyMac == MAX_ACL_MAC_ADDRESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "Black list is already maxed out. Cannot accept " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + if (sta_black_list) { + /* Do nothing if already present in white list */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address already present in black list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_SUCCESS; + } + if (sta_white_list) { + /* remove it from white list before adding to the black list */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "Present in white 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 black list; if its connected, send deauth */ + wlansap_populate_del_sta_params(peer_sta_mac, + eCsrForcedDeauthSta, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); + wlansap_deauth_sta(sap_ctx, &delStaParams); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "... Now add to black list"); + sap_add_mac_to_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, peer_sta_mac); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL) { + if (sta_black_list) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "Delete from black list"); + sap_remove_mac_from_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "no accept and deny mac %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address to be deleted is not present in the black list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid cmd type passed"); + return QDF_STATUS_E_FAILURE; + } + break; + + default: + { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid list type passed %d", list_type); + return QDF_STATUS_E_FAILURE; + } + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "After modification of ACL"); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** WHITE LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** BLACK 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 *p_del_sta_params) +{ + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sme_roam_disconnect_sta(CDS_GET_HAL_CB(), + sap_ctx->sessionId, p_del_sta_params); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_deauth_sta(struct sap_context *sap_ctx, + struct csr_del_sta_params *pDelStaParams) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return qdf_status; + } + + qdf_ret_status = + sme_roam_deauth_sta(CDS_GET_HAL_CB(), + sap_ctx->sessionId, pDelStaParams); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + qdf_status = QDF_STATUS_SUCCESS; + } + return qdf_status; +} + +/** + * wlansap_update_csa_channel_params() - function to populate channel width and + * bonding modes. + * @sap_context: sap adapter context + * @channel: target channel + * + * Return: The QDF_STATUS code associated with performing the operation + */ +static QDF_STATUS +wlansap_update_csa_channel_params(struct sap_context *sap_context, + uint32_t channel) +{ + void *hal; + tpAniSirGlobal mac_ctx; + uint8_t bw; + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hal pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + + mac_ctx = PMAC_STRUCT(hal); + + if (channel <= CHAN_ENUM_14) { + /* + * 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. + */ + mac_ctx->sap.SapDfsInfo.new_chanWidth = 0; + + } else { + if (sap_context->csr_roamProfile.phyMode == + eCSR_DOT11_MODE_11ac || + sap_context->csr_roamProfile.phyMode == + eCSR_DOT11_MODE_11ac_ONLY) + bw = BW80; + else + bw = BW40_HIGH_PRIMARY; + + for (; bw >= BW20; bw--) { + uint16_t op_class; + + op_class = wlan_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, bw); + /* + * Do not continue if bw is 20. This mean channel is not + * found and thus set BW20 for the channel. + */ + if (!op_class && bw > BW20) + continue; + + if (bw == BW80) { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_80MHZ; + } else if (bw == BW40_HIGH_PRIMARY) { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_40MHZ; + } else if (bw == BW40_LOW_PRIMARY) { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_40MHZ; + } else { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_20MHZ; + } + break; + } + + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sap_get_csa_reason_str() - Get csa reason in string + * @reason: sap reason enum value + * + * Return: string reason + */ +#ifdef WLAN_DEBUG +static 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"; + default: + return "UNKNOWN"; + } +} +#endif + +/** + * wlansap_set_channel_change_with_csa() - Set channel change with CSA + * @sapContext: Pointer to SAP context + * @targetChannel: Target channel + * @target_bw: Target bandwidth + * @strict: if true switch to the requested channel always, + * SCC/MCC check will be ignored, + * 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 *sapContext, + uint32_t targetChannel, + enum phy_ch_width target_bw, + bool strict) +{ + + tWLAN_SAPEvent sapEvent; + tpAniSirGlobal pMac = NULL; + void *hHal = NULL; + bool valid; + QDF_STATUS status; + bool sta_sap_scc_on_dfs_chan; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + if (strict && !policy_mgr_is_safe_channel(pMac->psoc, targetChannel)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%u is unsafe channel", targetChannel); + return QDF_STATUS_E_FAULT; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap chan:%d target:%d conn on 5GHz:%d, csa_reason:%s(%d)", + __func__, sapContext->channel, targetChannel, + policy_mgr_is_any_mode_active_on_band_along_with_session( + pMac->psoc, sapContext->sessionId, POLICY_MGR_BAND_5), + sap_get_csa_reason_str(sapContext->csa_reason), + sapContext->csa_reason); + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(pMac->psoc); + /* + * Now, validate if the passed channel is valid in the + * current regulatory domain. + */ + if (sapContext->channel != targetChannel && + ((wlan_reg_get_channel_state(pMac->pdev, targetChannel) == + CHANNEL_STATE_ENABLE) || + (wlan_reg_get_channel_state(pMac->pdev, targetChannel) == + CHANNEL_STATE_DFS && + (!policy_mgr_is_any_mode_active_on_band_along_with_session( + pMac->psoc, sapContext->sessionId, + POLICY_MGR_BAND_5) || + sta_sap_scc_on_dfs_chan)))) { + /* + * validate target channel switch w.r.t various concurrency + * rules set. + */ + if (!strict) { + valid = wlan_sap_validate_channel_switch(hHal, + targetChannel, sapContext); + if (!valid) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("Channel switch to %u is not allowed due to concurrent channel interference"), + targetChannel); + 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 sapContext only, if SAP is in SAP_STARTED + * state. + */ + if (sapContext->fsm_state == SAP_STARTED) { + status = wlansap_update_csa_channel_params(sapContext, + targetChannel); + if (status != QDF_STATUS_SUCCESS) + return status; + + /* + * Copy the requested target channel + * to sap context. + */ + pMac->sap.SapDfsInfo.target_channel = targetChannel; + pMac->sap.SapDfsInfo.new_ch_params.ch_width = + pMac->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) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s: target bw:%d new width:%d", + __func__, target_bw, + pMac->sap.SapDfsInfo. + new_ch_params.ch_width); + pMac->sap.SapDfsInfo.new_ch_params.ch_width = + pMac->sap.SapDfsInfo.new_chanWidth = + QDF_MIN(pMac->sap.SapDfsInfo. + new_ch_params.ch_width, + target_bw); + } + wlan_reg_set_channel_params(pMac->pdev, targetChannel, + 0, &pMac->sap.SapDfsInfo.new_ch_params); + /* + * Set the CSA IE required flag. + */ + pMac->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. + */ + pMac->sap.SapDfsInfo.sap_radar_found_status = true; + pMac->sap.SapDfsInfo.cac_state = + eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hHal); + + /* + * Post the eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START + * to SAP state machine to process the channel + * request with CSA IE set in the beacons. + */ + sapEvent.event = + eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START; + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + + sap_fsm(sapContext, &sapEvent); + + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to request Channel Change, since SAP is not in SAP_STARTED state", + __func__); + return QDF_STATUS_E_FAULT; + } + + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Channel = %d is not valid in the current" + "regulatory domain", __func__, targetChannel); + + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Posted eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START successfully to sap_fsm for Channel = %d", + __func__, targetChannel); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_set_key_sta(struct sap_context *sap_ctx, + tCsrRoamSetKey *pSetKeyInfo) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + uint32_t roamId = INVALID_ROAM_ID; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", + __func__); + return QDF_STATUS_E_FAULT; + } + qdf_ret_status = + sme_roam_set_key(hHal, sap_ctx->sessionId, pSetKeyInfo, + &roamId); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) + qdf_status = QDF_STATUS_SUCCESS; + else + qdf_status = QDF_STATUS_E_FAULT; + + return qdf_status; +} + +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 (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer")); + return QDF_STATUS_E_FAULT; + } + + if (len) { + ie_len = *len; + *len = sap_ctx->nStaWPARSnReqIeLength; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("WPAIE len : %x"), *len); + if ((buf) && (ie_len >= sap_ctx->nStaWPARSnReqIeLength)) { + qdf_mem_copy(buf, + sap_ctx->pStaWpaRsnReqIE, + sap_ctx->nStaWPARSnReqIeLength); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("WPAIE: %02x:%02x:%02x:%02x:%02x:%02x"), + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5]); + 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->dfs_vendor_channel = channel; + sap_ctx->dfs_vendor_chan_bw = chan_bw; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_sap_set_pre_cac_status(struct sap_context *sap_ctx, + bool status, tHalHandle handle) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(handle); + + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid mac pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->is_pre_cac_on = status; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: is_pre_cac_on:%d", __func__, sap_ctx->is_pre_cac_on); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_sap_set_chan_before_pre_cac(struct sap_context *sap_ctx, + uint8_t chan_before_pre_cac) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->chan_before_pre_cac = chan_before_pre_cac; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_sap_set_pre_cac_complete_status(struct sap_context *sap_ctx, + bool status) +{ + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->pre_cac_complete = status; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: pre cac complete status:%d session:%d", + __func__, status, sap_ctx->sessionId); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_sap_is_pre_cac_active() - Checks if pre cac in in progress + * @handle: Global MAC handle + * + * Checks if pre cac is in progress in any of the SAP contexts + * + * Return: True is pre cac is active, false otherwise + */ +bool wlan_sap_is_pre_cac_active(tHalHandle handle) +{ + tpAniSirGlobal mac = NULL; + int i; + + mac = PMAC_STRUCT(handle); + if (!mac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid mac context", __func__); + return false; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + struct sap_context *context = + mac->sap.sapCtxList[i].sap_context; + if (context && context->is_pre_cac_on) + return true; + } + return false; +} + +/** + * wlan_sap_get_pre_cac_vdev_id() - Get vdev id of the pre cac interface + * @handle: Global handle + * @vdev_id: vdev id + * + * Fetches the vdev id of the pre cac interface + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_get_pre_cac_vdev_id(tHalHandle handle, uint8_t *vdev_id) +{ + tpAniSirGlobal mac = NULL; + uint8_t i; + + mac = PMAC_STRUCT(handle); + if (!mac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid mac context", __func__); + return QDF_STATUS_E_FAULT; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + struct sap_context *context = + mac->sap.sapCtxList[i].sap_context; + if (context && context->is_pre_cac_on) { + *vdev_id = i; + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wlansap_register_mgmt_frame(struct sap_context *sap_ctx, + uint16_t frameType, + uint8_t *matchData, + uint16_t matchLen) +{ + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("hal pointer null")); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = sme_register_mgmt_frame(hHal, sap_ctx->sessionId, + frameType, matchData, + matchLen); + + if (QDF_STATUS_SUCCESS == qdf_ret_status) { + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Failed to Register MGMT frame"); + + return QDF_STATUS_E_FAULT; +} + +QDF_STATUS wlansap_de_register_mgmt_frame(struct sap_context *sap_ctx, + uint16_t frameType, + uint8_t *matchData, + uint16_t matchLen) +{ + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("hal pointer null")); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = + sme_deregister_mgmt_frame(hHal, sap_ctx->sessionId, frameType, + matchData, matchLen); + + if (QDF_STATUS_SUCCESS == qdf_ret_status) { + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Failed to Deregister MGMT frame"); + + return QDF_STATUS_E_FAULT; +} + +void wlansap_get_sec_channel(uint8_t sec_ch_offset, + uint8_t op_channel, + uint8_t *sec_channel) +{ + switch (sec_ch_offset) { + case LOW_PRIMARY_CH: + *sec_channel = op_channel + 4; + break; + case HIGH_PRIMARY_CH: + *sec_channel = op_channel - 4; + break; + default: + *sec_channel = 0; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: sec channel offset %d, sec channel %d", + __func__, sec_ch_offset, *sec_channel); +} + +QDF_STATUS wlansap_channel_change_request(struct sap_context *sapContext, + uint8_t target_channel) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + tpAniSirGlobal mac_ctx = NULL; + eCsrPhyMode phy_mode; + struct ch_params *ch_params; + + if (!target_channel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: channel 0 requested", __func__); + return QDF_STATUS_E_FAULT; + } + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + mac_ctx = PMAC_STRUCT(hHal); + phy_mode = sapContext->csr_roamProfile.phyMode; + + /* Update phy_mode if the target channel is in the other band */ + if (WLAN_CHAN_IS_5GHZ(target_channel) && + ((phy_mode == eCSR_DOT11_MODE_11g) || + (phy_mode == eCSR_DOT11_MODE_11g_ONLY))) + phy_mode = eCSR_DOT11_MODE_11a; + else if (WLAN_CHAN_IS_2GHZ(target_channel) && + (phy_mode == eCSR_DOT11_MODE_11a)) + phy_mode = eCSR_DOT11_MODE_11g; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: phy_mode: %d, target_channel: %d new phy_mode: %d", + __func__, sapContext->csr_roamProfile.phyMode, + target_channel, phy_mode); + sapContext->csr_roamProfile.phyMode = phy_mode; + + if (sapContext->csr_roamProfile.ChannelInfo.numOfChannels == 0 || + sapContext->csr_roamProfile.ChannelInfo.ChannelList == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid channel list")); + return QDF_STATUS_E_FAULT; + } + sapContext->csr_roamProfile.ChannelInfo.ChannelList[0] = target_channel; + /* + * 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; + wlan_reg_set_channel_params(mac_ctx->pdev, target_channel, + 0, ch_params); + sapContext->ch_params = *ch_params; + /* Update the channel as this will be used to + * send event to supplicant + */ + sapContext->channel = target_channel; + wlansap_get_sec_channel(ch_params->sec_ch_offset, target_channel, + (uint8_t *)(&sapContext->secondary_ch)); + sapContext->csr_roamProfile.ch_params.ch_width = ch_params->ch_width; + sapContext->csr_roamProfile.ch_params.sec_ch_offset = + ch_params->sec_ch_offset; + sapContext->csr_roamProfile.ch_params.center_freq_seg0 = + ch_params->center_freq_seg0; + sapContext->csr_roamProfile.ch_params.center_freq_seg1 = + ch_params->center_freq_seg1; + sap_dfs_set_current_channel(sapContext); + + qdf_ret_status = sme_roam_channel_change_req(hHal, sapContext->bssid, + ch_params, &sapContext->csr_roamProfile); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: chan:%d phy_mode %d width:%d offset:%d seg0:%d seg1:%d", + __func__, sapContext->channel, phy_mode, ch_params->ch_width, + ch_params->sec_ch_offset, ch_params->center_freq_seg0, + ch_params->center_freq_seg1); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + sap_signal_hdd_event(sapContext, NULL, + eSAP_CHANNEL_CHANGE_EVENT, + (void *) eSAP_STATUS_SUCCESS); + + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAULT; +} + +QDF_STATUS wlansap_start_beacon_req(struct sap_context *sap_ctx) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + uint8_t dfsCacWaitStatus = 0; + tpAniSirGlobal pMac = NULL; + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + /* No Radar was found during CAC WAIT, So start Beaconing */ + if (pMac->sap.SapDfsInfo.sap_radar_found_status == false) { + /* CAC Wait done without any Radar Detection */ + dfsCacWaitStatus = true; + sap_ctx->pre_cac_complete = false; + qdf_ret_status = sme_roam_start_beacon_req(hHal, + sap_ctx->bssid, + dfsCacWaitStatus); + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAULT; + } + + return QDF_STATUS_E_FAULT; +} + +QDF_STATUS wlansap_dfs_send_csa_ie_request(struct sap_context *sap_ctx) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + tpAniSirGlobal pMac = NULL; + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + pMac->sap.SapDfsInfo.new_ch_params.ch_width = + pMac->sap.SapDfsInfo.new_chanWidth; + wlan_reg_set_channel_params(pMac->pdev, + pMac->sap.SapDfsInfo.target_channel, + 0, &pMac->sap.SapDfsInfo.new_ch_params); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: chan:%d req:%d width:%d off:%d", + __func__, pMac->sap.SapDfsInfo.target_channel, + pMac->sap.SapDfsInfo.csaIERequired, + pMac->sap.SapDfsInfo.new_ch_params.ch_width, + pMac->sap.SapDfsInfo.new_ch_params.sec_ch_offset); + + qdf_ret_status = sme_roam_csa_ie_request(hHal, + sap_ctx->bssid, + pMac->sap.SapDfsInfo.target_channel, + pMac->sap.SapDfsInfo.csaIERequired, + &pMac->sap.SapDfsInfo.new_ch_params); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_FAULT; +} + +/*========================================================================== + FUNCTION wlansap_get_dfs_ignore_cac + + DESCRIPTION + This API is used to get the value of ignore_cac value + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + pIgnore_cac : pointer to ignore_cac variable + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_get_dfs_ignore_cac(tHalHandle hHal, uint8_t *pIgnore_cac) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + *pIgnore_cac = pMac->sap.SapDfsInfo.ignore_cac; + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_ignore_cac + + DESCRIPTION + This API is used to Set the value of ignore_cac value + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + ignore_cac : value to set for ignore_cac variable in DFS global structure. + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_set_dfs_ignore_cac(tHalHandle hHal, uint8_t ignore_cac) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + pMac->sap.SapDfsInfo.ignore_cac = (ignore_cac >= true) ? + true : false; + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_dfs_restrict_japan_w53() - enable/disable dfS for japan + * @hHal : HAL pointer + * @disable_Dfs_JapanW3 :Indicates if Japan W53 is disabled when set to 1 + * Indicates if Japan W53 is enabled when set to 0 + * + * This API is used to enable or disable Japan W53 Band + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS +wlansap_set_dfs_restrict_japan_w53(tHalHandle hHal, uint8_t disable_Dfs_W53) +{ + tpAniSirGlobal pMac = NULL; + QDF_STATUS status; + enum dfs_reg dfs_region; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + wlan_reg_get_dfs_region(pMac->pdev, &dfs_region); + + /* + * Set the JAPAN W53 restriction only if the current + * regulatory domain is JAPAN. + */ + if (DFS_MKK_REG == dfs_region) { + pMac->sap.SapDfsInfo.is_dfs_w53_disabled = disable_Dfs_W53; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: SET DFS JAPAN W53 DISABLED = %d"), + pMac->sap.SapDfsInfo.is_dfs_w53_disabled); + + status = QDF_STATUS_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL + ("Regdomain not japan, set disable JP W53 not valid")); + + status = QDF_STATUS_E_FAULT; + } + + return status; +} + +bool sap_is_auto_channel_select(struct sap_context *sapcontext) +{ + if (NULL == sapcontext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return false; + } + return sapcontext->channel == AUTO_CHANNEL_SELECT; +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wlan_sap_set_channel_avoidance() - sets sap mcc channel avoidance ini param + * @hal: hal handle + * @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(tHalHandle hal, bool sap_channel_avoidance) +{ + tpAniSirGlobal mac_ctx = NULL; + + if (NULL != hal) { + mac_ctx = PMAC_STRUCT(hal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("hal 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 */ + +/** + * wlansap_set_dfs_preferred_channel_location() - set dfs preferred channel + * @hHal : HAL pointer + * @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. + * + * This API is used to set sap preferred channels location + * to resetrict the DFS random channel selection algorithm + * either Indoor/Outdoor channels 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(tHalHandle hHal, + uint8_t + dfs_Preferred_Channels_location) +{ + tpAniSirGlobal pMac = NULL; + QDF_STATUS status; + enum dfs_reg dfs_region; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + wlan_reg_get_dfs_region(pMac->pdev, &dfs_region); + + /* + * The Indoor/Outdoor only random channel selection + * restriction is currently enforeced only for + * JAPAN regulatory domain. + */ + if (DFS_MKK_REG == dfs_region) { + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location = + dfs_Preferred_Channels_location; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL + ("sapdfs:Set Preferred Operating Channel location=%d"), + pMac->sap.SapDfsInfo. + sap_operating_chan_preferred_location); + + status = QDF_STATUS_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL + ("sapdfs:NOT JAPAN REG, Invalid Set preferred chans location")); + + status = QDF_STATUS_E_FAULT; + } + + return status; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_target_chnl + + DESCRIPTION + This API is used to set next target chnl as provided channel. + you can provide any valid channel to this API. + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + target_channel : target channel to be set + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_set_dfs_target_chnl(tHalHandle hHal, uint8_t target_channel) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + if (target_channel > 0) { + pMac->sap.SapDfsInfo.user_provided_target_channel = + target_channel; + } else { + pMac->sap.SapDfsInfo.user_provided_target_channel = 0; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlansap_update_sap_config_add_ie(tsap_config_t *pConfig, + 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 (NULL == pConfig) { + return QDF_STATUS_E_FAULT; + } + + if ((pAdditionIEBuffer != NULL) && (additionIELength != 0)) { + /* initialize the buffer pointer so that pe can copy */ + if (additionIELength > 0) { + bufferLength = additionIELength; + pBuffer = qdf_mem_malloc(bufferLength); + if (NULL == pBuffer) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("Could not allocate the buffer ")); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pBuffer, pAdditionIEBuffer, bufferLength); + bufferValid = true; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("update_type: %d"), updateType); + qdf_trace_hex_dump(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, pBuffer, bufferLength); + } + } + + switch (updateType) { + case eUPDATE_IE_PROBE_BCN: + if (pConfig->pProbeRespBcnIEsBuffer) + qdf_mem_free(pConfig->pProbeRespBcnIEsBuffer); + if (bufferValid) { + pConfig->probeRespBcnIEsLen = bufferLength; + pConfig->pProbeRespBcnIEsBuffer = pBuffer; + } else { + pConfig->probeRespBcnIEsLen = 0; + pConfig->pProbeRespBcnIEsBuffer = NULL; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("No Probe Resp beacone IE received in set beacon")); + } + break; + case eUPDATE_IE_PROBE_RESP: + if (pConfig->pProbeRespIEsBuffer) + qdf_mem_free(pConfig->pProbeRespIEsBuffer); + if (bufferValid) { + pConfig->probeRespIEsBufferLen = bufferLength; + pConfig->pProbeRespIEsBuffer = pBuffer; + } else { + pConfig->probeRespIEsBufferLen = 0; + pConfig->pProbeRespIEsBuffer = NULL; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("No Probe Response IE received in set beacon")); + } + break; + case eUPDATE_IE_ASSOC_RESP: + if (pConfig->pAssocRespIEsBuffer) + qdf_mem_free(pConfig->pAssocRespIEsBuffer); + if (bufferValid) { + pConfig->assocRespIEsLen = bufferLength; + pConfig->pAssocRespIEsBuffer = pBuffer; + } else { + pConfig->assocRespIEsLen = 0; + pConfig->pAssocRespIEsBuffer = NULL; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("No Assoc Response IE received in set beacon")); + } + break; + default: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("No matching buffer type %d"), updateType); + if (pBuffer != NULL) + qdf_mem_free(pBuffer); + break; + } + + return status; +} + +QDF_STATUS +wlansap_reset_sap_config_add_ie(tsap_config_t *pConfig, eUpdateIEsType updateType) +{ + if (NULL == pConfig) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid Config pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + switch (updateType) { + case eUPDATE_IE_ALL: /*only used to reset */ + case eUPDATE_IE_PROBE_RESP: + if (pConfig->pProbeRespIEsBuffer) { + qdf_mem_free(pConfig->pProbeRespIEsBuffer); + pConfig->probeRespIEsBufferLen = 0; + pConfig->pProbeRespIEsBuffer = NULL; + } + if (eUPDATE_IE_ALL != updateType) + break; + + case eUPDATE_IE_ASSOC_RESP: + if (pConfig->pAssocRespIEsBuffer) { + qdf_mem_free(pConfig->pAssocRespIEsBuffer); + pConfig->assocRespIEsLen = 0; + pConfig->pAssocRespIEsBuffer = NULL; + } + if (eUPDATE_IE_ALL != updateType) + break; + + case eUPDATE_IE_PROBE_BCN: + if (pConfig->pProbeRespBcnIEsBuffer) { + qdf_mem_free(pConfig->pProbeRespBcnIEsBuffer); + pConfig->probeRespBcnIEsLen = 0; + pConfig->pProbeRespBcnIEsBuffer = NULL; + } + if (eUPDATE_IE_ALL != updateType) + break; + + default: + if (eUPDATE_IE_ALL != updateType) + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid buffer type %d"), updateType); + break; + } + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_extend_to_acs_range + + DESCRIPTION Function extends give channel range to consider ACS chan bonding + + DEPENDENCIES PARAMETERS + + IN /OUT + *startChannelNum : ACS extend start ch + *endChannelNum : ACS extended End ch + *bandStartChannel: Band start ch + *bandEndChannel : Band end ch + + RETURN VALUE NONE + + SIDE EFFECTS + ============================================================================*/ +void wlansap_extend_to_acs_range(tHalHandle hal, uint8_t *startChannelNum, + uint8_t *endChannelNum, uint8_t *bandStartChannel, + uint8_t *bandEndChannel) +{ +#define ACS_WLAN_20M_CH_INC 4 +#define ACS_2G_EXTEND ACS_WLAN_20M_CH_INC +#define ACS_5G_EXTEND (ACS_WLAN_20M_CH_INC * 3) + + uint8_t tmp_startChannelNum = 0, tmp_endChannelNum = 0; + tpAniSirGlobal mac_ctx; + + mac_ctx = PMAC_STRUCT(hal); + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid mac_ctx", __func__); + return; + } + if (*startChannelNum <= 14 && *endChannelNum <= 14) { + *bandStartChannel = CHAN_ENUM_1; + *bandEndChannel = CHAN_ENUM_14; + tmp_startChannelNum = *startChannelNum > 5 ? + (*startChannelNum - ACS_2G_EXTEND) : 1; + tmp_endChannelNum = (*endChannelNum + ACS_2G_EXTEND) <= 14 ? + (*endChannelNum + ACS_2G_EXTEND) : 14; + } else if (*startChannelNum >= 36 && *endChannelNum >= 36) { + *bandStartChannel = CHAN_ENUM_36; + *bandEndChannel = CHAN_ENUM_173; + tmp_startChannelNum = (*startChannelNum - ACS_5G_EXTEND) > 36 ? + (*startChannelNum - ACS_5G_EXTEND) : 36; + tmp_endChannelNum = (*endChannelNum + ACS_5G_EXTEND) <= + WNI_CFG_CURRENT_CHANNEL_STAMAX ? + (*endChannelNum + ACS_5G_EXTEND) : + WNI_CFG_CURRENT_CHANNEL_STAMAX; + } else { + *bandStartChannel = CHAN_ENUM_1; + *bandEndChannel = CHAN_ENUM_173; + tmp_startChannelNum = *startChannelNum > 5 ? + (*startChannelNum - ACS_2G_EXTEND) : 1; + tmp_endChannelNum = (*endChannelNum + ACS_5G_EXTEND) <= + WNI_CFG_CURRENT_CHANNEL_STAMAX ? + (*endChannelNum + ACS_5G_EXTEND) : + WNI_CFG_CURRENT_CHANNEL_STAMAX; + } + + /* 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 specturm channels which is due to emission spill. + * Remove the active channels from extend ACS range for DFS only range + */ + if (wlan_reg_is_dfs_ch(mac_ctx->pdev, *startChannelNum)) { + while (!wlan_reg_is_dfs_ch(mac_ctx->pdev, + tmp_startChannelNum) && + tmp_startChannelNum < *startChannelNum) + tmp_startChannelNum += ACS_WLAN_20M_CH_INC; + + *startChannelNum = tmp_startChannelNum; + } + if (wlan_reg_is_dfs_ch(mac_ctx->pdev, *endChannelNum)) { + while (!wlan_reg_is_dfs_ch(mac_ctx->pdev, + tmp_endChannelNum) && + tmp_endChannelNum > *endChannelNum) + tmp_endChannelNum -= ACS_WLAN_20M_CH_INC; + + *endChannelNum = tmp_endChannelNum; + } +} + +QDF_STATUS wlan_sap_set_vendor_acs(struct sap_context *sap_context, + bool is_vendor_acs) +{ + if (!sap_context) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + 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) +{ + void *hal = NULL; + tpAniSirGlobal mac = NULL; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + mac = PMAC_STRUCT(hal); + + if (conf == eSAP_DFS_NOL_CLEAR) { + struct wlan_objmgr_pdev *pdev; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: clear the DFS NOL", __func__); + + pdev = mac->pdev; + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: null pdev", __func__); + return QDF_STATUS_E_FAULT; + } + utils_dfs_clear_nol_channels(pdev); + } else if (conf == eSAP_DFS_NOL_RANDOMIZE) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Randomize the DFS NOL", __func__); + + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: unsupport type %d", __func__, conf); + } + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * 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. + * @pDelStaParams: Address where 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 *pDelStaParams) +{ + if (NULL == mac) + qdf_set_macaddr_broadcast(&pDelStaParams->peerMacAddr); + else + qdf_mem_copy(pDelStaParams->peerMacAddr.bytes, mac, + QDF_MAC_ADDR_SIZE); + + if (reason_code == 0) + pDelStaParams->reason_code = eSIR_MAC_DEAUTH_LEAVING_BSS_REASON; + else + pDelStaParams->reason_code = reason_code; + + if (subtype == (SIR_MAC_MGMT_DEAUTH >> 4) || + subtype == (SIR_MAC_MGMT_DISASSOC >> 4)) + pDelStaParams->subtype = subtype; + else + pDelStaParams->subtype = (SIR_MAC_MGMT_DEAUTH >> 4); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL( + "Delete STA with RC:%hu subtype:%hhu MAC::" + MAC_ADDRESS_STR), + pDelStaParams->reason_code, pDelStaParams->subtype, + MAC_ADDR_ARRAY(pDelStaParams->peerMacAddr.bytes)); +} + +QDF_STATUS wlansap_acs_chselect(struct sap_context *sap_context, + tpWLAN_SAPEventCB pacs_event_callback, + tsap_config_t *pconfig, + void *pusr_context) +{ + tHalHandle h_hal = NULL; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pmac = NULL; + + if (NULL == sap_context) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + + return QDF_STATUS_E_FAULT; + } + + h_hal = (tHalHandle)CDS_GET_HAL_CB(); + if (NULL == h_hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC context", __func__); + return QDF_STATUS_E_FAULT; + } + + pmac = PMAC_STRUCT(h_hal); + sap_context->acs_cfg = &pconfig->acs_cfg; + sap_context->ch_width_orig = pconfig->acs_cfg.ch_width; + sap_context->csr_roamProfile.phyMode = pconfig->acs_cfg.hw_mode; + + /* + * Now, configure the scan and ACS channel params + * to issue a scan request. + */ + wlansap_set_scan_acs_channel_params(pconfig, sap_context, + pusr_context); + + /* + * Copy the HDD callback function to report the + * ACS result after scan in SAP context callback function. + */ + sap_context->pfnSapEventCallback = pacs_event_callback; + /* + * init dfs channel nol + */ + sap_init_dfs_channel_nol_list(sap_context); + + /* + * 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) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s,DFS not supported in the current operating mode", + __func__); + 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 + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Scan Req Failed/ACS Overridden")); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Selected channel = %d"), + sap_context->channel); + + return sap_signal_hdd_event(sap_context, NULL, + eSAP_ACS_CHANNEL_SELECTED, + (void *) eSAP_STATUS_SUCCESS); + } else if (QDF_STATUS_SUCCESS == qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Successfully Issued a Pre Start Bss Scan Request")); + } + return qdf_status; +} + +/** + * wlan_sap_enable_phy_error_logs() - Enable DFS phy error logs + * @hal: global hal handle + * @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 eanble such logs temporarily. + * + * Return: void + */ +void wlan_sap_enable_phy_error_logs(tHalHandle hal, uint32_t enable_log) +{ + int error; + + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + 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); +} + +uint32_t wlansap_get_chan_width(struct sap_context *sap_ctx) +{ + return wlan_sap_get_vht_ch_width(sap_ctx); +} + +QDF_STATUS wlansap_set_tx_leakage_threshold(tHalHandle hal, + uint16_t tx_leakage_threshold) +{ + tpAniSirGlobal mac; + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + mac = PMAC_STRUCT(hal); + tgt_dfs_set_tx_leakage_threshold(mac->pdev, tx_leakage_threshold); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: leakage_threshold %d", __func__, + tx_leakage_threshold); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_set_invalid_session(struct sap_context *sap_ctx) +{ + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer")); + return QDF_STATUS_E_FAILURE; + } + + sap_ctx->sessionId = CSR_SESSION_ID_INVALID; + + return QDF_STATUS_SUCCESS; +} + +void wlansap_cleanup_cac_timer(struct sap_context *sap_ctx) +{ + tHalHandle hal; + tpAniSirGlobal pmac; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP context")); + return; + } + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid hal pointer")); + return; + } + + pmac = PMAC_STRUCT(hal); + if (pmac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + qdf_mc_timer_stop(&pmac->sap.SapDfsInfo. + sap_dfs_cac_timer); + pmac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + qdf_mc_timer_destroy( + &pmac->sap.SapDfsInfo.sap_dfs_cac_timer); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("sapdfs, force cleanup running dfs cac timer")); + } +} + +static bool +wlansap_is_channel_present_in_acs_list(uint8_t ch, + uint8_t *ch_list, + uint8_t ch_count) +{ + uint8_t i; + + for (i = 0; i < ch_count; i++) { + if (ch_list[i] == ch) { + /* + * channel was given by hostpad for ACS, and is present + * in PCL. + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("channel present in acs cfg channel list %d"), ch); + return true; + } + } + + return false; +} + +QDF_STATUS wlansap_filter_ch_based_acs(struct sap_context *sap_ctx, + uint8_t *ch_list, + uint32_t *ch_cnt) +{ + size_t ch_index; + size_t target_ch_cnt = 0; + + if (!sap_ctx || !ch_list || !ch_cnt || + !sap_ctx->acs_cfg->master_ch_list) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("NULL parameters")); + return QDF_STATUS_E_FAULT; + } + + for (ch_index = 0; ch_index < *ch_cnt; ch_index++) { + if (wlansap_is_channel_present_in_acs_list(ch_list[ch_index], + sap_ctx->acs_cfg->master_ch_list, + sap_ctx->acs_cfg->master_ch_list_count)) + ch_list[target_ch_cnt++] = ch_list[ch_index]; + } + + *ch_cnt = target_ch_cnt; + + return QDF_STATUS_SUCCESS; +} + +#if defined(FEATURE_WLAN_CH_AVOID) +/** + * wlansap_get_safe_channel() - Get safe channel from current regulatory + * @sap_ctx: Pointer to SAP context + * + * 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) +{ + tHalHandle hal; + tpAniSirGlobal mac; + struct sir_pcl_list pcl = {0}; + QDF_STATUS status; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("NULL parameters")); + return INVALID_CHANNEL_ID; + } + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + mac = PMAC_STRUCT(hal); + + /* get the channel list for current domain */ + status = policy_mgr_get_valid_chans(mac->psoc, + pcl.pcl_list, + &pcl.pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Error in getting valid channels")); + return INVALID_CHANNEL_ID; + } + + status = wlansap_filter_ch_based_acs(sap_ctx, + pcl.pcl_list, + &pcl.pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("failed to filter ch from acs %d"), status); + return INVALID_CHANNEL_ID; + } + + if (pcl.pcl_len) { + status = policy_mgr_get_valid_chans_from_range(mac->psoc, + pcl.pcl_list, + &pcl.pcl_len, + PM_SAP_MODE); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("get valid channel: %d failed"), status); + return INVALID_CHANNEL_ID; + } + + if (pcl.pcl_len) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("select %d from valid channel list"), + pcl.pcl_list[0]); + return pcl.pcl_list[0]; + } + } + + return INVALID_CHANNEL_ID; +} +#else +/** + * wlansap_get_safe_channel() - Get safe channel from current regulatory + * @sap_ctx: Pointer to SAP context + * + * 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) +{ + return 0; +} +#endif + +uint8_t +wlansap_get_safe_channel_from_pcl_and_acs_range(struct sap_context *sap_ctx) +{ + tHalHandle hal; + tpAniSirGlobal mac; + struct sir_pcl_list pcl = {0}; + QDF_STATUS status; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("NULL parameter")); + return INVALID_CHANNEL_ID; + } + + hal = CDS_GET_HAL_CB(); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + mac = PMAC_STRUCT(hal); + + status = policy_mgr_get_pcl_for_existing_conn( + mac->psoc, PM_SAP_MODE, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list), + false); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Get PCL failed")); + return INVALID_CHANNEL_ID; + } + + if (pcl.pcl_len) { + status = wlansap_filter_ch_based_acs(sap_ctx, + pcl.pcl_list, + &pcl.pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("failed filter ch from acs %d"), status); + return INVALID_CHANNEL_ID; + } + + if (pcl.pcl_len) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("select %d from valid channel list"), + pcl.pcl_list[0]); + return pcl.pcl_list[0]; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("no safe channel from PCL found in ACS range")); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("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); +} diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h new file mode 100644 index 0000000000000000000000000000000000000000..781de103d26d404ccbe3f16fe9cc9ebd45e59f71 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h @@ -0,0 +1,1789 @@ +/* + * 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. + */ + +/** + * \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" + +#define CSR_INVALID_SCANRESULT_HANDLE (NULL) +#define CSR_NUM_WLM_LATENCY_LEVEL 4 + +typedef enum { + /* 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_NUM_OF_SUPPORT_AUTH_TYPE, + eCSR_AUTH_TYPE_FAILED = 0xff, + eCSR_AUTH_TYPE_UNKNOWN = eCSR_AUTH_TYPE_FAILED, + +} eCsrAuthType; + +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; + +/*--------------------------------------------------------------------------- + Enumeration of the various Security types + ---------------------------------------------------------------------------*/ +typedef enum { + eCSR_SECURITY_TYPE_WPA, + eCSR_SECURITY_TYPE_RSN, +#ifdef FEATURE_WLAN_WAPI + eCSR_SECURITY_TYPE_WAPI, +#endif /* FEATURE_WLAN_WAPI */ + eCSR_SECURITY_TYPE_UNKNOWN, + +} eCsrSecurityType; + +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 + * except when it starts IBSS in 11B of 2.4GHz + * It is for CSR internal use + */ + eCSR_DOT11_MODE_AUTO = 0x0400, + eCSR_DOT11_MODE_11ax = 0x0800, + eCSR_DOT11_MODE_11ax_ONLY = 0x1000, + + /* specify the number of maximum bits for phyMode */ + eCSR_NUM_PHY_MODE = 16, +} eCsrPhyMode; + +/** + * enum eCsrRoamBssType - BSS type in CSR operations + * @eCSR_BSS_TYPE_INFRASTRUCTURE: Infrastructure station + * @eCSR_BSS_TYPE_INFRA_AP: SoftAP + * @eCSR_BSS_TYPE_IBSS: IBSS network we'll not start + * @eCSR_BSS_TYPE_START_IBSS: IBSS network we'll start if no partners found + * @eCSR_BSS_TYPE_NDI: NAN datapath interface + * @eCSR_BSS_TYPE_ANY: any BSS type (IBSS or Infrastructure) + */ +typedef enum { + eCSR_BSS_TYPE_INFRASTRUCTURE, + eCSR_BSS_TYPE_INFRA_AP, + eCSR_BSS_TYPE_IBSS, + eCSR_BSS_TYPE_START_IBSS, + 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_HIGH_PRIMARY, + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH, + eCSR_INI_CHANNEL_BONDING_STATE_MAX +} eIniChanBondState; + +#define CSR_RSN_PMKID_SIZE 16 +#define CSR_RSN_MAX_PMK_LEN 48 +#define CSR_MAX_PMKID_ALLOWED 32 +#define CSR_WEP40_KEY_LEN 5 +#define CSR_WEP104_KEY_LEN 13 +#define CSR_TKIP_KEY_LEN 32 +#define CSR_AES_KEY_LEN 16 +#define CSR_AES_GCMP_KEY_LEN 16 +#define CSR_AES_GCMP_256_KEY_LEN 32 +#define CSR_AES_GMAC_128_KEY_LEN 16 +#define CSR_AES_GMAC_256_KEY_LEN 32 +#define CSR_MAX_TX_POWER (WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX) +#define CSR_MAX_RSC_LEN 16 +#ifdef FEATURE_WLAN_WAPI +#define CSR_WAPI_BKID_SIZE 16 +#define CSR_MAX_BKID_ALLOWED 16 +#define CSR_WAPI_KEY_LEN 32 +#define CSR_MAX_KEY_LEN (CSR_WAPI_KEY_LEN) /* longest one is for WAPI */ +#else +#define CSR_MAX_KEY_LEN (CSR_TKIP_KEY_LEN) /* longest one is for TKIP */ +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE +#define CSR_KRK_KEY_LEN 16 +#endif + +typedef struct tagCsrChannelInfo { + uint8_t numOfChannels; + uint8_t *ChannelList; /* it will be an array of channels */ +} tCsrChannelInfo, *tpCsrChannelInfo; + +typedef enum { + eHIDDEN_SSID_NOT_IN_USE, + eHIDDEN_SSID_ZERO_LEN, + eHIDDEN_SSID_ZERO_CONTENTS +} tHiddenssId; + +typedef struct tagCsrSSIDInfo { + tSirMacSSid SSID; + bool handoffPermitted; + 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 tagCsrStaParams { + uint16_t capability; + uint8_t extn_capability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_len; + uint8_t supported_rates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap HTCap; + uint8_t vhtcap_present; + tSirVHTCap VHTCap; + uint8_t uapsd_queues; + uint8_t max_sp; + uint8_t supported_channels_len; + uint8_t supported_channels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supported_oper_classes_len; + uint8_t supported_oper_classes[REG_MAX_SUPP_OPER_CLASSES]; +} tCsrStaParams; + +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 tSirBssDescription is an + * array with nonknown size at this time */ + tSirBssDescription BssDescriptor; +} tCsrScanResultInfo; + +typedef struct tagCsrEncryptionList { + + uint32_t numEntries; + eCsrEncryptionType encryptionType[eCSR_NUM_OF_ENCRYPT_TYPE]; + +} tCsrEncryptionList, *tpCsrEncryptionList; + +typedef struct tagCsrAuthList { + uint32_t numEntries; + eCsrAuthType authType[eCSR_NUM_OF_SUPPORT_AUTH_TYPE]; +} tCsrAuthList, *tpCsrAuthList; + +typedef struct tagCsrMobilityDomainInfo { + uint8_t mdiePresent; + uint16_t mobilityDomain; +} tCsrMobilityDomainInfo; + +#ifdef FEATURE_WLAN_ESE +typedef struct tagCsrEseCckmInfo { + uint32_t reassoc_req_num; + bool krk_plumbed; + uint8_t krk[SIR_KRK_KEY_LEN]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t btk[SIR_BTK_KEY_LEN]; +#endif +} tCsrEseCckmInfo; + +typedef struct tagCsrEseCckmIe { + uint8_t cckmIe[DOT11F_IE_RSN_MAX_LEN]; + uint8_t cckmIeLen; +} tCsrEseCckmIe; +#endif /* FEATURE_WLAN_ESE */ + +typedef struct sCsrChannel_ { + uint8_t numChannels; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} sCsrChannel; + +typedef struct tagCsrScanResultFilter { + tCsrBSSIDs BSSIDs; + tCsrSSIDs SSIDs; + tCsrChannelInfo ChannelInfo; + tCsrAuthList authType; + tCsrEncryptionList EncryptionType; + /* + * eCSR_ENCRYPT_TYPE_ANY cannot be set in multicast encryption type. + * If caller doesn't case, put all supported encryption types in here + */ + tCsrEncryptionList mcEncryptionType; + eCsrRoamBssType BSSType; + /* its a bit mask of all the needed phy mode defined in eCsrPhyMode */ + eCsrPhyMode phyMode; + /* + * If countryCode[0] is not 0, countryCode is checked + * independent of fCheckUnknownCountryCode + */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t uapsd_mask; + /* For WPS filtering if true => auth and ecryption should be ignored */ + bool bWPSAssociation; + bool bOSENAssociation; + /* + * For measurement reports --> if set, only SSID, + * BSSID and channel is considered for filtering. + */ + bool fMeasurement; + tCsrMobilityDomainInfo MDID; + bool p2pResult; +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif + /* The following flag is used to distinguish the + * roaming case while building the scan filter and + * applying it on to the scan results. This is mainly + * used to support whitelist ssid feature. + */ + uint8_t scan_filter_for_roam; + struct sCsrChannel_ pcl_channels; + struct qdf_mac_addr bssid_hint; + enum QDF_OPMODE csrPersona; + bool realm_check; + uint8_t fils_realm[2]; + bool force_rsne_override; +} tCsrScanResultFilter; + +typedef struct sCsrChnPower_ { + uint8_t firstChannel; + uint8_t numChannels; + uint8_t maxtxPower; +} sCsrChnPower; + +typedef struct tagCsr11dinfo { + sCsrChannel Channels; + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN + 1]; + /* max power channel list */ + sCsrChnPower ChnPower[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tCsr11dinfo; + +typedef enum { + eCSR_ROAM_CANCELLED = 1, + /* it means error happens before assoc_start/roaming_start is called. */ + eCSR_ROAM_FAILED, + /* + * a CSR trigger roaming operation starts, + * callback may get a pointer to tCsrConnectedProfile + */ + eCSR_ROAM_ROAMING_START, + /* a CSR trigger roaming operation is completed */ + eCSR_ROAM_ROAMING_COMPLETION, + /* Connection completed status. */ + eCSR_ROAM_CONNECT_COMPLETION, + /* + * an association or start_IBSS operation starts, + * callback may get a pointer to struct csr_roam_profile and + * a pointer to tSirBssDescription + */ + eCSR_ROAM_ASSOCIATION_START, + /* + * a roaming operation is finish, see eCsrRoamResult for + * possible data passed back + */ + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_ASSOCIATION_FAILURE, + /* when callback with this flag. it gets a pointer to the BSS desc. */ + eCSR_ROAM_SHOULD_ROAM, + /* A new candidate for PMKID is found */ + eCSR_ROAM_SCAN_FOUND_NEW_BSS, + /* CSR is done lostlink roaming and still cannot reconnect */ + eCSR_ROAM_LOSTLINK, + /* a link lost is detected. CSR starts roaming. */ + eCSR_ROAM_LOSTLINK_DETECTED, + /* + * TKIP MIC error detected, callback gets a pointer + * to tpSirSmeMicFailureInd + */ + eCSR_ROAM_MIC_ERROR_IND, + /* IBSS indications. */ + eCSR_ROAM_IBSS_IND, + /* + * Update the connection status, useful for IBSS: new peer added, + * network is active etc. + */ + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_GEN_INFO, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_IBSS_LEAVE, /* IBSS indications. */ + /* BSS in SoftAP mode status indication */ + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_FT_RESPONSE, + eCSR_ROAM_FT_START, + /* this mean error happens before assoc_start/roam_start is called. */ + eCSR_ROAM_SESSION_OPENED, + eCSR_ROAM_FT_REASSOC_FAILED, + eCSR_ROAM_PMK_NOTIFY, + /* + * Following 4 enums are used by FEATURE_WLAN_LFR_METRICS + * but they are needed for compilation even when + * FEATURE_WLAN_LFR_METRICS is not defined. + */ + eCSR_ROAM_PREAUTH_INIT_NOTIFY, + eCSR_ROAM_PREAUTH_STATUS_SUCCESS, + eCSR_ROAM_PREAUTH_STATUS_FAILURE, + eCSR_ROAM_HANDOVER_SUCCESS, + /* + * TDLS callback events + */ + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND, + + /* Disaconnect all the clients */ + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS, + /* Stopbss triggered from SME due to different */ + eCSR_ROAM_SEND_P2P_STOP_BSS, + /* beacon interval */ +#ifdef WLAN_FEATURE_11W + eCSR_ROAM_UNPROT_MGMT_FRAME_IND, +#endif + + eCSR_ROAM_IBSS_PEER_INFO_COMPLETE, + +#ifdef FEATURE_WLAN_ESE + eCSR_ROAM_TSM_IE_IND, + eCSR_ROAM_CCKM_PREAUTH_NOTIFY, + eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, + eCSR_ROAM_ESE_BCN_REPORT_IND, +#endif /* FEATURE_WLAN_ESE */ + + /* Radar indication from lower layers */ + eCSR_ROAM_DFS_RADAR_IND, + eCSR_ROAM_SET_CHANNEL_RSP, + + /* Channel sw update notification */ + eCSR_ROAM_DFS_CHAN_SW_NOTIFY, + eCSR_ROAM_EXT_CHG_CHNL_IND, + eCSR_ROAM_STA_CHANNEL_SWITCH, + eCSR_ROAM_NDP_STATUS_UPDATE, + eCSR_ROAM_UPDATE_SCAN_RESULT, + eCSR_ROAM_START, + eCSR_ROAM_ABORT, + eCSR_ROAM_NAPI_OFF, + eCSR_ROAM_CHANNEL_COMPLETE_IND, + eCSR_ROAM_CAC_COMPLETE_IND, + eCSR_ROAM_SAE_COMPUTE, + /* LFR3 Roam sync complete */ + eCSR_ROAM_SYNCH_COMPLETE, +} 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 pBssDesc 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, + /* + * This means we starts an IBSS struct csr_roam_info's + * pBssDesc may pass back + */ + eCSR_ROAM_RESULT_IBSS_STARTED, + eCSR_ROAM_RESULT_IBSS_START_FAILED, + eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS, + eCSR_ROAM_RESULT_IBSS_JOIN_FAILED, + eCSR_ROAM_RESULT_IBSS_CONNECT, + eCSR_ROAM_RESULT_IBSS_INACTIVE, + /* + * If roamStatus is eCSR_ROAM_ASSOCIATION_COMPLETION struct + * csr_roam_info's pBssDesc may pass back and the peer's MAC + * address in peerMacOrBssid. If roamStatus is + * eCSR_ROAM_IBSS_IND, the peer's MAC address in + * peerMacOrBssid and a beacon frame of the IBSS in pbFrames + */ + eCSR_ROAM_RESULT_IBSS_NEW_PEER, + /* + * Peer departed from IBSS, Callback may get a pointer tSmeIbssPeerInd + * in pIbssPeerInd + */ + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED, + /* + * Coalescing in the IBSS network (joined an IBSS network) + * Callback pass a BSSID in peerMacOrBssid + */ + eCSR_ROAM_RESULT_IBSS_COALESCED, + /* + * If roamStatus is eCSR_ROAM_ROAMING_START, callback may get a pointer + * to tCsrConnectedProfile used to connect. + */ + eCSR_ROAM_RESULT_IBSS_STOP, + 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_IBSS_PEER_INFO_SUCCESS, + eCSR_ROAM_RESULT_IBSS_PEER_INFO_FAILED, + eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE, + 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 { + eCSR_DISCONNECT_REASON_UNSPECIFIED = 0, + eCSR_DISCONNECT_REASON_MIC_ERROR, + eCSR_DISCONNECT_REASON_DISASSOC, + eCSR_DISCONNECT_REASON_DEAUTH, + eCSR_DISCONNECT_REASON_HANDOFF, + eCSR_DISCONNECT_REASON_IBSS_LEAVE, + eCSR_DISCONNECT_REASON_STA_HAS_LEFT, + eCSR_DISCONNECT_REASON_NDI_DELETE, + eCSR_DISCONNECT_REASON_ROAM_HO_FAIL, +} eCsrRoamDisconnectReason; + +typedef enum { + /* Not associated in Infra or participating in an IBSS/Ad-hoc */ + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED, + /* Associated in an Infrastructure network. */ + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED, + /* Participating in IBSS network though disconnection */ + eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED, + /* Participating in IBSS network with partner stations also present */ + eCSR_ASSOC_STATE_TYPE_IBSS_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, + /* Disconnecting with AP or stop connecting process */ + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING, + /* NAN Data interface not started */ + eCSR_CONNECT_STATE_TYPE_NDI_NOT_STARTED, + /* NAN Data interface started */ + eCSR_CONNECT_STATE_TYPE_NDI_STARTED, + +} eCsrConnectState; + +/* + * This parameter is no longer supported in the Profile. + * Need to set this in the global properties for the adapter. + */ +typedef enum eCSR_MEDIUM_ACCESS { + eCSR_MEDIUM_ACCESS_AUTO = 0, + eCSR_MEDIUM_ACCESS_DCF, + eCSR_MEDIUM_ACCESS_eDCF, + eCSR_MEDIUM_ACCESS_HCF, + + eCSR_MEDIUM_ACCESS_WMM_eDCF_802dot1p, + eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP, + eCSR_MEDIUM_ACCESS_WMM_eDCF_NoClassify, + eCSR_MEDIUM_ACCESS_11e_eDCF = eCSR_MEDIUM_ACCESS_eDCF, + eCSR_MEDIUM_ACCESS_11e_HCF = eCSR_MEDIUM_ACCESS_HCF, +} eCsrMediaAccessType; + +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 { + eCSR_DOT11_FRAG_THRESH_AUTO = -1, + eCSR_DOT11_FRAG_THRESH_MIN = 256, + eCSR_DOT11_FRAG_THRESH_MAX = 2346, + eCSR_DOT11_FRAG_THRESH_DEFAULT = 2000 +} eCsrDot11FragThresh; + +/* + * For channel bonding, the channel number gap is 4, either up or down. + * For both 11a and 11g mode. + */ +#define CSR_CB_CHANNEL_GAP 4 +#define CSR_CB_CENTER_CHANNEL_OFFSET 2 +#define CSR_SEC_CHANNEL_OFFSET 4 + + +/* WEP keysize (in bits) */ +typedef enum { + /* 40 bit key + 24bit IV = 64bit WEP */ + eCSR_SECURITY_WEP_KEYSIZE_40 = 40, + /* 104bit key + 24bit IV = 128bit WEP */ + eCSR_SECURITY_WEP_KEYSIZE_104 = 104, + eCSR_SECURITY_WEP_KEYSIZE_MIN = eCSR_SECURITY_WEP_KEYSIZE_40, + eCSR_SECURITY_WEP_KEYSIZE_MAX = eCSR_SECURITY_WEP_KEYSIZE_104, + eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES = + (eCSR_SECURITY_WEP_KEYSIZE_MAX / 8), +} eCsrWEPKeySize; + +/* Possible values for the WEP static key ID */ +typedef enum { + + eCSR_SECURITY_WEP_STATIC_KEY_ID_MIN = 0, + eCSR_SECURITY_WEP_STATIC_KEY_ID_MAX = 3, + eCSR_SECURITY_WEP_STATIC_KEY_ID_DEFAULT = 0, + + eCSR_SECURITY_WEP_STATIC_KEY_ID_INVALID = -1, + +} eCsrWEPStaticKeyID; + +/* Two extra key indicies are used for the IGTK (which is used by BIP) */ +#define CSR_MAX_NUM_KEY (eCSR_SECURITY_WEP_STATIC_KEY_ID_MAX + 2 + 1) + +typedef enum { + eCSR_SECURITY_SET_KEY_ACTION_NO_CHANGE, + eCSR_SECURITY_SET_KEY_ACTION_SET_KEY, + eCSR_SECURITY_SET_KEY_ACTION_DELETE_KEY, +} eCsrSetKeyAction; + +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; + +typedef enum { + eCsrRoamWmmAuto = 0, + eCsrRoamWmmQbssOnly = 1, + eCsrRoamWmmNoQos = 2, + +} eCsrRoamWmmUserModeType; + +typedef enum { + eCSR_REQUESTER_MIN = 0, + eCSR_DIAG, + eCSR_UMA_GAN, + eCSR_HDD +} eCsrStatsRequesterType; + +/** + * enum csr_hi_rssi_scan_id - Parameter ids for hi rssi scan feature + * + * @eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: how many times scan can be performed + * @eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: rssi difference to trigger scan + * @eCSR_HI_RSSI_SCAN_DELAY_ID: delay in millseconds between scans + * @eCSR_HI_RSSI_SCAN_RSSI_UB_ID: rssi upper bound for scan trigger + */ +enum csr_hi_rssi_scan_id { + eCSR_HI_RSSI_SCAN_MAXCOUNT_ID, + eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID, + eCSR_HI_RSSI_SCAN_DELAY_ID, + eCSR_HI_RSSI_SCAN_RSSI_UB_ID +}; + +typedef struct tagPmkidCandidateInfo { + struct qdf_mac_addr BSSID; + bool preAuthSupported; +} tPmkidCandidateInfo; + +typedef struct tagPmkidCacheInfo { + struct qdf_mac_addr BSSID; + uint8_t PMKID[CSR_RSN_PMKID_SIZE]; + uint8_t pmk[CSR_RSN_MAX_PMK_LEN]; + uint8_t pmk_len; + uint8_t ssid_len; + uint8_t ssid[SIR_MAC_MAX_SSID_LENGTH]; + uint8_t cache_id[CACHE_ID_LEN]; +} tPmkidCacheInfo; + +#ifdef FEATURE_WLAN_WAPI +typedef struct tagBkidCandidateInfo { + struct qdf_mac_addr BSSID; + bool preAuthSupported; +} tBkidCandidateInfo; + +typedef struct tagBkidCacheInfo { + struct qdf_mac_addr BSSID; + uint8_t BKID[CSR_WAPI_BKID_SIZE]; +} tBkidCacheInfo; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct tagCsrKeys { + /* Also use to indicate whether the key index is set */ + uint8_t KeyLength[CSR_MAX_NUM_KEY]; + uint8_t KeyMaterial[CSR_MAX_NUM_KEY][CSR_MAX_KEY_LEN]; + uint8_t defaultIndex; +} tCsrKeys; + +/* + * Following fields which're part of tCsrRoamConnectedProfile 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; + /* HDD might ask to modify this field */ + uint16_t listen_interval; +} 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; + tCsrAuthList AuthType; + eCsrAuthType negotiatedAuthType; + tCsrEncryptionList EncryptionType; + /* This field is for output only, not for input */ + eCsrEncryptionType negotiatedUCEncryptionType; + /* + * eCSR_ENCRYPT_TYPE_ANY cannot be set in multicast encryption type. + * If caller doesn't case, put all supported encryption types in here + */ + tCsrEncryptionList mcEncryptionType; + /* This field is for output only, not for input */ + eCsrEncryptionType negotiatedMCEncryptionType; +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif + tAniEdType mgmt_encryption_type; + tCsrKeys Keys; + tCsrChannelInfo ChannelInfo; + uint8_t operationChannel; + 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 nWPAReqIELength; /* The byte count in the pWPAReqIE */ + uint8_t *pWPAReqIE; /* If not null,it's IE byte stream for WPA */ + uint32_t nRSNReqIELength; /* The byte count in the pRSNReqIE */ + uint8_t *pRSNReqIE; /* If not null,it's IE byte stream for RSN */ +#ifdef FEATURE_WLAN_WAPI + uint32_t nWAPIReqIELength;/* The byte count in the pWAPIReqIE */ + uint8_t *pWAPIReqIE; /* If not null,it's IE byte stream for WAPI */ +#endif /* FEATURE_WLAN_WAPI */ + + uint32_t nAddIEScanLength;/* pAddIE for scan (at the time of join) */ + /* + * If not null,it's the IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEScan; + uint32_t nAddIEAssocLength; /* The byte count in the pAddIE for assoc */ + /* + * If not null, it has the IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEAssoc; + /* it is ignored if [0] is 0. */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + /* WPS Association if true => auth and ecryption should be ignored */ + bool bWPSAssociation; + bool bOSENAssociation; + uint32_t nWSCReqIELength; /* The byte count in the pWSCReqIE */ + uint8_t *pWSCReqIE; /* If not null,it's IE byte stream for WSC */ + uint8_t ieee80211d; + uint8_t privacy; + bool fwdWPSPBCProbeReq; + tAniAuthType csr80211AuthType; + uint32_t dtimPeriod; + bool ApUapsdEnable; + bool protEnabled; + bool obssProtEnabled; + bool chan_switch_hostapd_rate_enabled; + uint16_t cfg_protection; + uint8_t wps_state; + tCsrMobilityDomainInfo MDID; + enum QDF_OPMODE csrPersona; + uint8_t disableDFSChSwitch; + /* addIe params */ + tSirAddIeParams addIeParams; + uint8_t sap_dot11mc; + uint16_t beacon_tx_rate; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + struct qdf_mac_addr bssid_hint; + bool force_24ghz_in_ht20; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; + bool supplicant_disabled_roaming; + bool driver_disabled_roaming; +#ifdef WLAN_FEATURE_FILS_SK + bool fils_connection; + uint8_t *hlp_ie; + uint32_t hlp_ie_len; + struct cds_fils_connection_info *fils_con_info; +#endif + bool force_rsne_override; +}; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +typedef struct tagCsrRoamHTProfile { + uint8_t phymode; + uint8_t htCapability; + uint8_t htSupportedChannelWidthSet; + uint8_t htRecommendedTxWidthSet; + ePhyChanBondState htSecondaryChannelOffset; + uint8_t vhtCapability; + uint8_t apCenterChan; + uint8_t apChanWidth; +} tCsrRoamHTProfile; +#endif +typedef struct tagCsrRoamConnectedProfile { + tSirMacSSid SSID; + bool handoffPermitted; + bool ssidHidden; + uint8_t operationChannel; + struct qdf_mac_addr bssid; + uint16_t beaconInterval; + eCsrRoamBssType BSSType; + eCsrAuthType AuthType; + tCsrAuthList AuthInfo; + eCsrEncryptionType EncryptionType; + tCsrEncryptionList EncryptionInfo; + eCsrEncryptionType mcEncryptionType; + tCsrEncryptionList mcEncryptionInfo; + uint32_t vht_channel_width; + tCsrKeys Keys; + /* + * meaningless on connect. It's an OUT param from CSR's point of view + * During assoc response carries the ACM bit-mask i.e. what + * ACs have ACM=1 (if any),(Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE + * all other bits are ignored) + */ + uint8_t acm_mask; + tCsrRoamModifyProfileFields modifyProfileFields; + bool qosConnection; /* A connection is QoS enabled */ + uint32_t nAddIEAssocLength; + /* + * If not null,it's IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEAssoc; + tSirBssDescription *pBssDesc; + bool qap; /* AP supports QoS */ + tCsrMobilityDomainInfo MDID; +#ifdef FEATURE_WLAN_ESE + tCsrEseCckmInfo eseCckmInfo; + bool isESEAssoc; +#endif + uint32_t dot11Mode; + uint8_t proxyARPService; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tCsrRoamHTProfile HTProfile; +#endif +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif +} tCsrRoamConnectedProfile; + +typedef struct tagCsrNeighborRoamConfigParams { + + uint32_t nNeighborScanTimerPeriod; + uint32_t neighbor_scan_min_timer_period; + uint8_t nNeighborLookupRssiThreshold; + int8_t rssi_thresh_offset_5g; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + sCsrChannel neighborScanChanList; + uint8_t nMaxNeighborRetries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; +} tCsrNeighborRoamConfigParams; + +/** + * enum sta_roam_policy_dfs_mode - state of DFS mode for STA ROME policy + * @CSR_STA_ROAM_POLICY_NONE: DFS mode attribute is not valid + * @CSR_STA_ROAM_POLICY_DFS_ENABLED: DFS mode is enabled + * @CSR_STA_ROAM_POLICY_DFS_DISABLED: DFS mode is disabled + * @CSR_STA_ROAM_POLICY_DFS_DEPRIORITIZE: Deprioritize DFS channels in scanning + */ +enum sta_roam_policy_dfs_mode { + CSR_STA_ROAM_POLICY_NONE, + CSR_STA_ROAM_POLICY_DFS_ENABLED, + CSR_STA_ROAM_POLICY_DFS_DISABLED, + CSR_STA_ROAM_POLICY_DFS_DEPRIORITIZE +}; + +/** + * struct csr_sta_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: Opearting band for SAP + */ +struct csr_sta_roam_policy_params { + enum sta_roam_policy_dfs_mode dfs_mode; + bool skip_unsafe_channels; + uint8_t sap_operating_band; +}; + +/** + * struct csr_mbo_thresholds - mbo related thresholds + * @mbo_candidate_rssi_thres - Candidate RSSI threshold + * @mbo_current_rssi_thres - Current RSSI threshold + * @mbo_current_rssi_mcc_thres - Current RSSI MCC threshold + * mbo_candidate_rssi_btc_thres - Candidate RSSI BTC threshold + */ +struct csr_mbo_thresholds { + 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 csr_neighbor_report_offload_params - neighbor report offload params + * @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 csr_neighbor_report_offload_params { + 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; +}; + +typedef struct tagCsrConfigParam { + uint32_t FragmentationThreshold; + /* keep this uint32_t. This gets converted to ePhyChannelBondState */ + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + eCsrPhyMode phyMode; + enum band_info eBand; + uint32_t RTSThreshold; + uint32_t HeartbeatThresh50; + uint32_t HeartbeatThresh24; + enum band_info bandCapability; /* indicate hw capability */ + eCsrRoamWmmUserModeType WMMSupportMode; + bool Is11eSupportEnabled; + bool Is11dSupportEnabled; + bool Is11hSupportEnabled; + bool shortSlotTime; + bool ProprietaryRatesEnabled; + uint8_t AdHocChannel24; + uint8_t AdHocChannel5G; + /* + * this number minus one is the number of times a scan doesn't find it + * before it is removed + */ + uint32_t nScanResultAgeCount; + /* to set the RSSI difference for each category */ + uint8_t bCatRssiOffset; + /* 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; + + /* Country Code Priority */ + bool fSupplicantCountryCodeHasPriority; + uint16_t vccRssiThreshold; + uint32_t vccUlMacLossThreshold; + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; + uint32_t nPassiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /*In units of milliseconds*/ + uint32_t min_rest_time_conc; + /*In units of milliseconds*/ + uint32_t idle_time_conc; + + /* + * in dBm, the maximum TX power The actual TX power is the lesser of + * this value and 11d. If 11d is disable, the lesser of this and + * default setting. + */ + uint8_t nTxPowerCap; + bool allow_tpc_from_ap; + /* stats request frequency from PE while in full power */ + uint32_t statsReqPeriodicity; + /* stats request frequency from PE while in power save */ + uint32_t statsReqPeriodicityInPS; +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif + uint8_t isFastRoamIniFeatureEnabled; + struct mawc_params csr_mawc_config; + uint8_t isFastTransitionEnabled; + uint8_t RoamRssiDiff; + int32_t rssi_abs_thresh; + bool isWESModeEnabled; + tCsrNeighborRoamConfigParams neighborRoamConfig; + /* + * Instead of Reassoc, send ADDTS/DELTS even when ACM is off for that AC + * This is mandated by WMM-AC certification + */ + bool addTSWhenACMIsOff; + /* + * Customer wants to start with an active scan based on the default + * country code. This optimization will minimize the driver load to + * association time. Based on this flag we will bypass the initial + * passive scan needed for 11d to determine the country code & domain + */ + bool fEnableBypass11d; + /* + * 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; + /* + * To enable/disable scanning 2.4Ghz channels twice on a single scan + * request from HDD + */ + bool fScanTwice; + uint32_t nVhtChannelWidth; + uint8_t enableTxBF; + bool enable_subfee_vendor_vhtie; + uint8_t enable_txbf_sap_mode; + uint8_t enable2x2; + bool enableVhtFor24GHz; + bool vendor_vht_sap; + uint8_t enableMuBformee; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + bool send_smps_action; + bool ignore_peer_erp_info; + /* + * To enable/disable scanning only 2.4Ghz channels on first scan + */ + bool fFirstScanOnly2GChnl; + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; + + bool isRoamOffloadScanEnabled; + bool bFastRoamInConIniFeatureEnabled; + uint8_t scanCfgAgingTime; + uint8_t enable_tx_ldpc; + uint8_t enable_rx_ldpc; + uint8_t disable_high_ht_mcs_2x2; + bool enable_vht20_mcs9; + uint8_t max_amsdu_num; + uint8_t nSelect5GHzMargin; + uint32_t ho_delay_for_rx; + uint32_t min_delay_btw_roam_scans; + uint32_t roam_trigger_reason_bitmask; + bool roaming_scan_policy; + uint8_t isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + uint8_t allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint32_t roam_preauth_retry_count; + uint32_t roam_preauth_no_ack_timeout; + bool isRoamOffloadEnabled; +#endif + bool obssEnabled; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + bool send_deauth_before_con; + + /* 802.11p enable */ + bool enable_dot11p; + uint8_t max_scan_count; + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + int8_t first_scan_bucket_threshold; + uint8_t fEnableDebugLog; + uint8_t max_intf_count; + bool enable5gEBT; + bool enableSelfRecovery; + 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 */ + bool acs_with_more_param; + uint8_t f_prefer_non_dfs_on_radar; + bool is_ps_enabled; + uint32_t auto_bmps_timer_val; + uint32_t dual_mac_feature_disable; + uint32_t sta_sap_scc_on_dfs_chan; + uint32_t roam_dense_traffic_thresh; + uint32_t roam_dense_rssi_thresh_offset; + uint32_t roam_dense_min_aps; + int8_t roam_bg_scan_bad_rssi_thresh; + uint8_t roam_bad_rssi_thresh_offset_2g; + uint32_t roam_bg_scan_client_bitmap; + uint32_t obss_width_interval; + uint32_t obss_active_dwelltime; + uint32_t obss_passive_dwelltime; + bool ignore_peer_ht_opmode; + bool enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; + bool enable_fatal_event; + enum scan_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum scan_dwelltime_adaptive_mode scan_adaptive_dwell_mode_nc; + enum scan_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + struct csr_sta_roam_policy_params sta_roam_policy_params; + 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; + struct wmi_per_roam_config per_roam_config; + bool enable_bcast_probe_rsp; + bool is_fils_enabled; +#ifdef WLAN_FEATURE_11AX + bool enable_ul_ofdma; + bool enable_ul_mimo; +#endif + uint16_t wlm_latency_enable; + uint16_t wlm_latency_level; + uint32_t wlm_latency_flags[CSR_NUM_WLM_LATENCY_LEVEL]; + bool qcn_ie_support; + uint8_t fils_max_chan_guard_time; + uint16_t pkt_err_disconn_th; + enum force_1x1_type is_force_1x1_enable; + uint16_t num_11b_tx_chains; + uint16_t num_11ag_tx_chains; + uint32_t disallow_duration; + uint32_t rssi_channel_penalization; + uint32_t num_disallowed_aps; + struct sir_score_config bss_score_params; + uint8_t oce_feature_bitmap; + struct csr_mbo_thresholds mbo_thresholds; + uint32_t btm_offload_config; + uint32_t btm_solicited_timeout; + uint32_t btm_max_attempt_cnt; + uint32_t btm_sticky_time; + uint32_t offload_11k_enable_bitmask; + bool wep_tkip_in_he; + struct csr_neighbor_report_offload_params neighbor_report_offload; + bool enable_ftopen; + bool roam_force_rssi_trigger; + uint32_t btm_validity_timer; + uint32_t btm_disassoc_timer_threshold; + bool enable_bss_load_roam_trigger; + uint32_t bss_load_threshold; + uint32_t bss_load_sample_time; +} tCsrConfigParam; + +/* Tush */ +typedef struct tagCsrUpdateConfigParam { + tCsr11dinfo Csr11dinfo; +} tCsrUpdateConfigParam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define csr_roamIsRoamOffloadEnabled(pMac) \ + (pMac->roam.configParam.isRoamOffloadEnabled) +#define DEFAULT_REASSOC_FAILURE_TIMEOUT 1000 +#else +#define csr_roamIsRoamOffloadEnabled(pMac) false +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* connected but not authenticated */ +#define CSR_ROAM_AUTH_STATUS_CONNECTED 0x1 +/* connected and authenticated */ +#define CSR_ROAM_AUTH_STATUS_AUTHENTICATED 0x2 +#endif + +struct csr_roam_info { + struct csr_roam_profile *pProfile; + tSirBssDescription *pBssDesc; + uint32_t nBeaconLength; + uint32_t nAssocReqLength; + uint32_t nAssocRspLength; + 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 */ + bool fReassocRsp; /* set to true if for re-association */ + struct qdf_mac_addr bssid; + /* + * Only valid in IBSS. this is the peers MAC address for + * eCSR_ROAM_RESULT_IBSS_NEW_PEER or PEER_DEPARTED + */ + struct qdf_mac_addr peerMac; + tSirResultCodes statusCode; + /* 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 sessionId; + uint8_t rsnIELen; + uint8_t *prsnIE; + uint8_t wapiIELen; + uint8_t *pwapiIE; + uint8_t addIELen; + uint8_t *paddIE; + union { + tSirMicFailureInfo *pMICFailureInfo; + tCsrRoamConnectedProfile *pConnectedProfile; + tSirWPSPBCProbeReq *pWPSPBCProbeReq; + } u; + bool wmmEnabledSta; /* set to true if WMM enabled STA */ + uint32_t dtimPeriod; +#ifdef FEATURE_WLAN_ESE + bool isESEAssoc; + tSirTsmIE tsmIe; + uint32_t timestamp[2]; + uint16_t tsmRoamDelay; + tSirEseBcnReportRsp *pEseBcnReportRsp; +#endif + void *pRemainCtx; + uint32_t roc_scan_id; + uint32_t rxChan; +#ifdef FEATURE_WLAN_TDLS + /* + * TDLS parameters to check whether TDLS + * and TDLS channel switch is allowed in the + * AP network + */ + uint8_t staType; + bool tdls_prohibited; /* per ExtCap in Assoc/Reassoc resp */ + bool tdls_chan_swit_prohibited; /* per ExtCap in Assoc/Reassoc resp */ +#endif + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + int8_t rxRssi; + tSirSmeDfsEventInd dfs_event; + tSirChanChangeResponse *channelChangeRespEvent; + /* Timing and fine Timing measurement capability clubbed together */ + uint8_t timingMeasCap; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t roamSynchInProgress; + uint8_t synchAuthStatus; + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN_FILS]; + uint8_t kek_len; + uint32_t pmk_len; + uint8_t pmk[SIR_PMK_LEN]; + uint8_t pmkid[SIR_PMKID_LEN]; + bool update_erp_next_seq_num; + uint16_t next_erp_seq_num; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + uint8_t subnet_change_status; +#endif + tSirSmeChanInfo chan_info; + uint8_t target_channel; + +#ifdef WLAN_FEATURE_NAN_DATAPATH + 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; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEVHTOperation vht_operation; + tDot11fIEHTInfo ht_operation; + bool reassoc; + 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 rx_mcs_map; + uint8_t tx_mcs_map; + /* Extended capabilities of STA */ + uint8_t ecsa_capable; + bool is_fils_connection; +#ifdef WLAN_FEATURE_FILS_SK + uint16_t fils_seq_num; + struct fils_join_rsp_params *fils_join_rsp; +#endif + int rssi; + int tx_rate; + int rx_rate; + tSirMacCapabilityInfo capability_info; +#ifdef WLAN_FEATURE_SAE + struct sir_sae_info *sae_info; +#endif + uint16_t roam_reason; +}; + +typedef struct tagCsrFreqScanInfo { + uint32_t nStartFreq; /* in unit of MHz */ + uint32_t nEndFreq; /* in unit of MHz */ + tSirScanType scanType; +} tCsrFreqScanInfo; + +typedef struct sSirSmeAssocIndToUpperLayerCnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + uint8_t sessionId; + tSirResultCodes statusCode; + tSirMacAddr bssId; /* Self BSSID */ + tSirMacAddr peerMacAddr; + uint16_t aid; + tSirMacAddr alternateBssId; + uint8_t alternateChannelId; + 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; + tSirSmeChanInfo 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 rx_mcs_map; + uint8_t tx_mcs_map; + /* Extended capabilities of STA */ + uint8_t ecsa_capable; + + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tSirMacCapabilityInfo capability_info; + bool he_caps_present; +} tSirSmeAssocIndToUpperLayerCnf, *tpSirSmeAssocIndToUpperLayerCnf; + +typedef struct tagCsrSummaryStatsInfo { + uint32_t snr; + uint32_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; + 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; + uint32_t tx_mcs_rate_flags; + uint32_t rx_mcs_rate_flags; + /* to diff between HT20 & HT40 rates;short & long guard interval */ + uint32_t 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 struct tagCsrRoamSetKey { + eCsrEncryptionType encType; + tAniKeyDirection keyDirection; /* Tx, Rx or Tx-and-Rx */ + struct qdf_mac_addr peerMac; /* Peer MAC. ALL 1's for group key */ + uint8_t paeRole; /* 0 for supplicant */ + uint8_t keyId; /* Key index */ + uint16_t keyLength; /* Number of bytes containing the key in pKey */ + uint8_t Key[CSR_MAX_KEY_LEN]; + uint8_t keyRsc[CSR_MAX_RSC_LEN]; +} tCsrRoamSetKey; + +typedef struct tagCsrRoamRemoveKey { + eCsrEncryptionType encType; + struct qdf_mac_addr peerMac; /* Peer MAC. ALL 1's for group key */ + uint8_t keyId; /* key index */ +} tCsrRoamRemoveKey; + +#ifdef FEATURE_WLAN_TDLS + +typedef struct tagCsrLinkEstablishParams { + tSirMacAddr peerMac; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t isResponder; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[REG_MAX_SUPP_OPER_CLASSES]; + uint8_t qos; +} tCsrTdlsLinkEstablishParams; + +typedef struct tagCsrTdlsSendMgmt { + tSirMacAddr peerMac; + uint8_t frameType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + uint8_t *buf; + uint8_t len; + enum wifi_traffic_ac ac; +} tCsrTdlsSendMgmt; +#endif + +typedef void *tScanResultHandle; + +typedef enum { + REASSOC = 0, + FASTREASSOC = 1, + CONNECT_CMD_USERSPACE = 2, +} handoff_src; + +typedef struct tagCsrHandoffRequest { + struct qdf_mac_addr bssid; + uint8_t channel; + uint8_t src; /* To check if its a REASSOC or a FASTREASSOC IOCTL */ +} tCsrHandoffRequest; + +#ifdef FEATURE_WLAN_ESE +typedef struct tagCsrEseBeaconReqParams { + uint16_t measurementToken; + uint8_t channel; + 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; + uint16_t reason_code; + uint8_t subtype; +}; + +/** + * struct wep_update_default_key_idx: wep default key index structure + * @session_id: session ID for the connection session + * @default_idx: default key index for wep + * + * structure includes sesssion id for connection and default key + * index used for wep + */ +struct wep_update_default_key_idx { + uint8_t session_id; + uint8_t default_idx; +}; + +typedef QDF_STATUS (*csr_roam_complete_cb)(void *context, + struct csr_roam_info *param, + uint32_t roam_id, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); +typedef QDF_STATUS (*csr_session_open_cb)(uint8_t session_id, + QDF_STATUS qdf_status); +typedef QDF_STATUS (*csr_session_close_cb)(uint8_t session_id); + +#define CSR_IS_START_IBSS(pProfile) (eCSR_BSS_TYPE_START_IBSS == \ + (pProfile)->BSSType) +#define CSR_IS_JOIN_TO_IBSS(pProfile) (eCSR_BSS_TYPE_IBSS == \ + (pProfile)->BSSType) +#define CSR_IS_IBSS(pProfile) (CSR_IS_START_IBSS(pProfile) || \ + CSR_IS_JOIN_TO_IBSS(pProfile)) +#define CSR_IS_INFRASTRUCTURE(pProfile) (eCSR_BSS_TYPE_INFRASTRUCTURE == \ + (pProfile)->BSSType) +#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_DATAPATH +#define CSR_IS_NDI(profile) (eCSR_BSS_TYPE_NDI == (profile)->BSSType) +#else +#define CSR_IS_NDI(profile) (false) +#endif +#define CSR_IS_CONN_INFRA_AP(pProfile) (eCSR_BSS_TYPE_INFRA_AP == \ + (pProfile)->BSSType) +#ifdef WLAN_FEATURE_NAN_DATAPATH +#define CSR_IS_CONN_NDI(profile) (eCSR_BSS_TYPE_NDI == (profile)->BSSType) +#else +#define CSR_IS_CONN_NDI(profile) (false) +#endif + +#ifdef WLAN_FEATURE_SAE +#define CSR_IS_AUTH_TYPE_SAE(auth_type) \ + (eCSR_AUTH_TYPE_SAE == auth_type) +#else +#define CSR_IS_AUTH_TYPE_SAE(auth_type) (false) +#endif + +QDF_STATUS csr_set_channels(tpAniSirGlobal pMac, tCsrConfigParam *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); +QDF_STATUS csr_set_phy_mode(tHalHandle hHal, uint32_t phyMode, + enum band_info eBand, bool *pfRestartNeeded); +typedef void (*tCsrStatsCallback)(void *stats, void *pContext); +typedef void (*tCsrRssiCallback)(int8_t rssi, uint32_t staId, void *pContext); + +#ifdef FEATURE_WLAN_ESE +typedef void (*tCsrTsmStatsCallback)(tAniTrafStrmMetrics tsmMetrics, + uint32_t staId, void *pContext); +#endif /* FEATURE_WLAN_ESE */ +typedef void (*tCsrSnrCallback)(int8_t snr, uint32_t staId, void *pContext); + +/** + * csr_roam_issue_ft_preauth_req() - Initiate Preauthentication request + * @max_ctx: Global MAC context + * @session_id: SME Session ID + * @bss_desc: BSS descriptor + * + * Return: Success or Failure + */ +#ifdef WLAN_FEATURE_HOST_ROAM +QDF_STATUS csr_roam_issue_ft_preauth_req(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tpSirBssDescription bss_desc); +#else +static inline +QDF_STATUS csr_roam_issue_ft_preauth_req(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tpSirBssDescription bss_desc) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +QDF_STATUS csr_set_band(tHalHandle hHal, uint8_t sessionId, + enum band_info eBand); +enum band_info csr_get_current_band(tHalHandle hHal); +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); +#ifdef FEATURE_WLAN_TDLS +void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, + struct csr_roam_info *roam_info, + tpSirSmeJoinRsp join_rsp); +#else +static inline void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, + struct csr_roam_info *roam_info, + tpSirSmeJoinRsp join_rsp) +{} +#endif +void csr_packetdump_timer_stop(void); + +/** + * csr_get_channel_status() - get chan info via channel number + * @mac: Pointer to Global MAC structure + * @channel_id: channel id + * + * Return: chan status info + */ +struct lim_channel_status * +csr_get_channel_status(tpAniSirGlobal mac, uint32_t channel_id); + +/** + * csr_clear_channel_status() - clear chan info + * @mac: Pointer to Global MAC structure + * + * Return: none + */ +void csr_clear_channel_status(tpAniSirGlobal mac); +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..c111a45930ca3cdb68f723ad75bc713c97557768 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h @@ -0,0 +1,1492 @@ +/* + * 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. + */ + +/** + * \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 "csr_neighbor_roam.h" + +#include "sir_types.h" + +/* define scan return criteria. LIM should use these define as well */ +#define CSR_SCAN_RETURN_AFTER_ALL_CHANNELS (0) +#define CSR_SCAN_RETURN_AFTER_FIRST_MATCH (0x01) +#define CSR_NUM_RSSI_CAT 15 +#define CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME 3 + +/* session ID invalid */ +#define CSR_SESSION_ID_INVALID 0xFF +/* No of sessions to be supported, and a session is for Infra, IBSS or BT-AMP */ +#define CSR_ROAM_SESSION_MAX SIR_MAX_SUPPORTED_BSS +#define CSR_IS_SESSION_VALID(pMac, sessionId) \ + (((sessionId) < CSR_ROAM_SESSION_MAX) && \ + ((pMac)->roam.roamSession[(sessionId)].sessionActive)) + +#define CSR_GET_SESSION(pMac, sessionId) \ + ( \ + (sessionId < CSR_ROAM_SESSION_MAX) ? \ + (&(pMac)->roam.roamSession[(sessionId)]) : NULL \ + ) + +#define CSR_IS_SESSION_ANY(sessionId) (sessionId == SME_SESSION_ID_ANY) +#define CSR_MAX_NUM_COUNTRY_CODE 100 +#define CSR_IS_DFS_CH_ROAM_ALLOWED(mac_ctx) \ + ( \ + (((mac_ctx)->roam.configParam.allowDFSChannelRoam) ? true : false) \ + ) +#define CSR_IS_SELECT_5GHZ_MARGIN(pMac) \ + ( \ + (((pMac)->roam.configParam.nSelect5GHzMargin) ? true : false) \ + ) +#define CSR_IS_SELECT_5G_PREFERRED(pMac) \ + ( \ + (((pMac)->roam.configParam.roam_params.is_5g_pref_enabled) ? \ + true : false) \ + ) +#define CSR_IS_ROAM_PREFER_5GHZ(pMac) \ + ( \ + (((pMac)->roam.configParam.nRoamPrefer5GHz) ? true : false) \ + ) +#define CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac) \ + ( \ + (((pMac)->roam.configParam.nRoamIntraBand) ? true : false) \ + ) +#define CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac) \ + ( \ + (((pMac)->roam.configParam.bFastRoamInConIniFeatureEnabled) ? \ + true : false) \ + ) +#define CSR_IS_CHANNEL_24GHZ(chnNum) \ + (((chnNum) > 0) && ((chnNum) <= 14)) +/* Support for "Fast roaming" (i.e., ESE, LFR, or 802.11r.) */ +#define CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN 15 + +/* Used to determine what to set to the WNI_CFG_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, +}; + +enum csr_scan_reason { + eCsrScanForSsid, +}; + +enum csr_roam_reason { + /* Roaming because we've not established the initial connection. */ + eCsrNoConnection, + /* roaming because LIM reported a cap change in the associated AP. */ + eCsrCapsChange, + /* roaming because someone asked us to Disassoc & stay disassociated. */ + eCsrForcedDisassoc, + /* roaming because an 802.11 request was issued to the driver. */ + eCsrHddIssued, + /* roaming because we need to force a Disassoc due to MIC failure */ + eCsrForcedDisassocMICFailure, + eCsrHddIssuedReassocToSameAP, + eCsrSmeIssuedReassocToSameAP, + /* roaming because someone asked us to deauth and stay disassociated. */ + eCsrForcedDeauth, + /* will be issued by Handoff logic to disconect from current AP */ + eCsrSmeIssuedDisassocForHandoff, + /* will be issued by Handoff logic to join a new AP with same profile */ + eCsrSmeIssuedAssocToSimilarAP, + eCsrForcedIbssLeave, + eCsrStopBss, + eCsrSmeIssuedFTReassoc, + eCsrForcedDisassocSta, + eCsrForcedDeauthSta, + eCsrPerformPreauth, + /* Roaming disabled from driver during connect/start BSS */ + ecsr_driver_disabled, +}; + +enum csr_roam_substate { + eCSR_ROAM_SUBSTATE_NONE = 0, + eCSR_ROAM_SUBSTATE_START_BSS_REQ, + eCSR_ROAM_SUBSTATE_JOIN_REQ, + eCSR_ROAM_SUBSTATE_REASSOC_REQ, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, + /* Continue the current roam command after disconnect */ + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + eCSR_ROAM_SUBSTATE_AUTH_REQ, + eCSR_ROAM_SUBSTATE_CONFIG, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, + eCSR_ROAM_SUBSTATE_DISASSOC_FORCED, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF, + eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC, + eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC, + eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC, + eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT, + /* 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, + eCsrStartIbss, + eCsrStartIbssSameIbss, + eCsrReassocToSelfNoCapChange, + eCsrStopRoamingDueToConcurrency, + +}; + +enum csr_roaming_reason { + eCsrNotRoaming, + eCsrLostlinkRoamingDisassoc, + eCsrLostlinkRoamingDeauth, + eCsrDynamicRoaming, + eCsrReassocRoaming, +}; + +enum csr_roam_wmstatus_changetypes { + eCsrDisassociated, + eCsrDeauthenticated +}; + +enum csr_roam_stats_classtypes { + eCsrSummaryStats = 0, + eCsrGlobalClassAStats, + eCsrGlobalClassDStats, + csr_per_chain_rssi_stats, + eCsrMaxStats +}; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +enum csr_diagwlan_status_eventsubtype { + eCSR_WLAN_STATUS_CONNECT = 0, + eCSR_WLAN_STATUS_DISCONNECT +}; + +enum csr_diagwlan_status_eventreason { + eCSR_REASON_UNSPECIFIED = 0, + eCSR_REASON_USER_REQUESTED, + eCSR_REASON_MIC_ERROR, + eCSR_REASON_DISASSOC, + eCSR_REASON_DEAUTH, + eCSR_REASON_HANDOFF, + eCSR_REASON_ROAM_SYNCH_IND, + eCSR_REASON_ROAM_SYNCH_CNF, + eCSR_REASON_ROAM_HO_FAIL, + +}; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +struct csr_channel { + uint8_t numChannels; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +}; + +struct scan_profile { + uint32_t minChnTime; + uint32_t maxChnTime; + /* In units of milliseconds, ignored when not connected */ + uint32_t restTime; + /* In units of milliseconds, ignored when not connected */ + uint32_t min_rest_time; + /* In units of milliseconds, ignored when not connected */ + uint32_t idle_time; + uint32_t numOfChannels; + uint8_t *pChannelList; + tSirScanType scanType; + eCsrRoamBssType bssType; + uint8_t ssid[WNI_CFG_SSID_LEN]; + uint8_t bReturnAfter1stMatch; + uint8_t fUniqueResult; + uint8_t freshScan; + struct qdf_mac_addr bssid; +}; + +struct bss_config_param { + eCsrMediaAccessType qosType; + tSirMacSSid SSID; + uint32_t uRTSThresh; + uint32_t uDeferThresh; + enum csr_cfgdot11mode uCfgDot11Mode; + enum band_info eBand; + tAniAuthType authType; + eCsrEncryptionType encType; + uint32_t uShortSlotTime; + uint32_t uHTSupport; + uint32_t uPowerLimit; + uint32_t uHeartBeatThresh; + uint32_t uJoinTimeOut; + tSirMacCapabilityInfo BssCap; + bool f11hSupport; + ePhyChanBondState cbMode; +}; + +struct csr_roamstart_bssparams { + tSirMacSSid ssId; + + /* + * This is the BSSID for the party we want to + * join (only use for IBSS or WDS). + */ + struct qdf_mac_addr bssid; + tSirNwType sirNwType; + ePhyChanBondState cbMode; + tSirMacRateSet operationalRateSet; + tSirMacRateSet extendedRateSet; + uint8_t operationChn; + struct ch_params ch_params; + enum csr_cfgdot11mode uCfgDot11Mode; + uint8_t privacy; + bool fwdWPSPBCProbeReq; + bool protEnabled; + bool obssProtEnabled; + tAniAuthType authType; + uint16_t beaconInterval; /* If this is 0, SME'll fill in for caller */ + uint16_t ht_protection; + uint32_t dtimPeriod; + uint8_t ApUapsdEnable; + uint8_t ssidHidden; + uint8_t wps_state; + enum QDF_OPMODE bssPersona; + uint16_t nRSNIELength; /* If 0, pRSNIE is ignored. */ + uint8_t *pRSNIE; /* If not null, it has IE byte stream for RSN */ + /* Flag used to indicate update beaconInterval */ + bool updatebeaconInterval; +#ifdef WLAN_FEATURE_11W + bool mfpCapable; + bool mfpRequired; +#endif + tSirAddIeParams addIeParams; + uint8_t sap_dot11mc; + uint16_t beacon_tx_rate; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; +}; + +struct roam_cmd { + uint32_t roamId; + enum csr_roam_reason roamReason; + struct csr_roam_profile roamProfile; + tScanResultHandle hBSSList; /* BSS list fits the profile */ + /* + * point to the current BSS in the list that is roaming. + * It starts from head to tail + * */ + tListElem *pRoamBssEntry; + tSirBssDescription *pLastRoamBss; /* the last BSS we try and failed */ + bool fReleaseBssList; /* whether to free hBSSList */ + bool fReleaseProfile; /* whether to free roamProfile */ + bool fReassoc; /* whether this cmd is for reassoc */ + /* whether pMac->roam.pCurRoamProfile needs to be updated */ + bool fUpdateCurRoamProfile; + /* + * this is for CSR internal used only. And it should not be assigned + * when creating the command. This causes the roam cmd not todo anything + */ + bool fReassocToSelfNoCapChange; + + bool fStopWds; + tSirMacAddr peerMac; + tSirMacReasonCodes reason; + eCsrRoamDisconnectReason disconnect_reason; +}; + +struct setkey_cmd { + uint32_t roamId; + eCsrEncryptionType encType; + eCsrAuthType authType; + tAniKeyDirection keyDirection; /* Tx, Rx or Tx-and-Rx */ + struct qdf_mac_addr peermac; /* Peer's MAC address. ALL 1's for group key */ + uint8_t paeRole; /* 0 for supplicant */ + uint8_t keyId; /* Kye index */ + uint8_t keyLength; /* Number of bytes containing the key in pKey */ + uint8_t Key[CSR_MAX_KEY_LEN]; + uint8_t keyRsc[CSR_MAX_RSC_LEN]; +}; + +struct wmstatus_changecmd { + enum csr_roam_wmstatus_changetypes Type; + union { + tSirSmeDeauthInd DeauthIndMsg; + tSirSmeDisassocInd DisassocIndMsg; + } u; + +}; + +struct addstafor_sessioncmd { + /* Session self mac addr */ + tSirMacAddr selfMacAddr; + enum QDF_OPMODE currDeviceMode; + uint32_t type; + uint32_t subType; + uint8_t sessionId; +}; + +struct delstafor_sessionCmd { + /* Session self mac addr */ + tSirMacAddr selfMacAddr; + csr_session_close_cb session_close_cb; + void *context; +}; + +struct csr_neighbor_roamconfig { + uint32_t nNeighborScanTimerPeriod; + uint32_t neighbor_scan_min_timer_period; + uint8_t nNeighborLookupRssiThreshold; + int8_t rssi_thresh_offset_5g; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + sCsrChannel neighborScanChanList; + uint8_t nMaxNeighborRetries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; +}; + +/* + * 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 + +struct csr_config { + uint32_t agingCount; + uint32_t FragmentationThreshold; + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + uint32_t RTSThreshold; + eCsrPhyMode phyMode; + enum csr_cfgdot11mode uCfgDot11Mode; + enum band_info eBand; + uint32_t HeartbeatThresh50; + uint32_t HeartbeatThresh24; + enum band_info bandCapability; /* indicate hw capability */ + eCsrRoamWmmUserModeType WMMSupportMode; + bool Is11eSupportEnabled; + bool Is11dSupportEnabled; + bool Is11hSupportEnabled; + bool shortSlotTime; + bool ProprietaryRatesEnabled; + bool fenableMCCMode; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + uint8_t fAllowMCCGODiffBI; + uint8_t AdHocChannel24; + uint8_t AdHocChannel5G; + /* each RSSI category has one value */ + uint32_t BssPreferValue[CSR_NUM_RSSI_CAT]; + int RSSICat[CSR_NUM_RSSI_CAT]; + uint8_t bCatRssiOffset; /* to set RSSI difference for each category */ + /* + * Whether to limit the channels to the ones set in Csr11dInfo. + * If true, the opertaional channels are limited to the default channel + * list. It is an "AND" operation between the default channels and + * the channels in the 802.11d IE. + */ + /* Country Code Priority */ + bool fSupplicantCountryCodeHasPriority; + + uint16_t vccRssiThreshold; + uint32_t vccUlMacLossThreshold; + + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; + uint32_t nPassiveMinChnTimeConc;/* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc;/* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /* In units of milliseconds */ + uint32_t min_rest_time_conc; + /* In units of milliseconds */ + uint32_t idle_time_conc; + /* + * in dBm, the max TX power. The actual TX power is the lesser of this + * value & 11d. If 11d is disable, the lesser of this & default setting. + */ + uint8_t nTxPowerCap; + bool allow_tpc_from_ap; + uint32_t statsReqPeriodicity; /* stats req freq while in fullpower */ + uint32_t statsReqPeriodicityInPS;/* stats req freq while in powersave */ + uint32_t dtimPeriod; + bool ssidHidden; + uint8_t isFastRoamIniFeatureEnabled; + struct mawc_params csr_mawc_config; + uint8_t isRoamOffloadScanEnabled; + bool bFastRoamInConIniFeatureEnabled; +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif + uint8_t isFastTransitionEnabled; + uint8_t RoamRssiDiff; + int32_t rssi_abs_thresh; + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + bool isWESModeEnabled; + bool nRoamScanControl; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; + + struct csr_neighbor_roamconfig neighborRoamConfig; + + /* + * Instead of Reassoc, send ADDTS/DELTS even when ACM is off for + * that AC This is mandated by WMM-AC certification + */ + bool addTSWhenACMIsOff; + /* + * Remove this code once SLM_Sessionization is supported + * BMPS_WORKAROUND_NOT_NEEDED + */ + bool doBMPSWorkaround; + /* To enable scanning 2g channels twice on single scan req from HDD */ + bool fScanTwice; + uint32_t nVhtChannelWidth; + bool enable_subfee_vendor_vhtie; + uint8_t enable_txbf_sap_mode; + bool enable_vht20_mcs9; + uint8_t enable2x2; + bool enableVhtFor24GHz; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + bool send_smps_action; + uint8_t tx_ldpc_enable; + uint8_t rx_ldpc_enable; + uint8_t disable_high_ht_mcs_2x2; + /* + * Enable/Disable heartbeat offload + */ + bool enableHeartBeatOffload; + uint8_t max_amsdu_num; + uint8_t nSelect5GHzMargin; + uint32_t ho_delay_for_rx; + uint32_t roam_preauth_retry_count; + uint32_t roam_preauth_no_ack_timeout; + uint32_t min_delay_btw_roam_scans; + uint32_t roam_trigger_reason_bitmask; + uint8_t isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + uint8_t allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + bool obssEnabled; + bool ignore_peer_erp_info; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + struct roam_ext_params roam_params; + bool send_deauth_before_con; + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + uint32_t obss_width_interval; + uint32_t obss_active_dwelltime; + uint32_t obss_passive_dwelltime; + bool ignore_peer_ht_opmode; + bool enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; + bool enable_fatal_event; + bool vendor_vht_sap; + enum scan_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum scan_dwelltime_adaptive_mode scan_adaptive_dwell_mode_nc; + enum scan_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + struct csr_sta_roam_policy_params sta_roam_policy; + 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; + struct wmi_per_roam_config per_roam_config; + bool enable_bcast_probe_rsp; + bool is_fils_enabled; +#ifdef WLAN_FEATURE_11AX + bool enable_ul_ofdma; + bool enable_ul_mimo; +#endif + bool qcn_ie_support; + uint8_t fils_max_chan_guard_time; + uint16_t pkt_err_disconn_th; + enum force_1x1_type is_force_1x1_enable; + uint16_t num_11b_tx_chains; + uint16_t num_11ag_tx_chains; + uint32_t disallow_duration; + uint32_t rssi_channel_penalization; + uint32_t num_disallowed_aps; + uint16_t wlm_latency_enable; + uint16_t wlm_latency_level; + uint32_t wlm_latency_flags[CSR_NUM_WLM_LATENCY_LEVEL]; + struct sir_score_config bss_score_params; + uint8_t oce_feature_bitmap; + struct csr_mbo_thresholds mbo_thresholds; + uint32_t btm_offload_config; + uint32_t btm_solicited_timeout; + uint32_t btm_max_attempt_cnt; + uint32_t btm_sticky_time; + uint32_t offload_11k_enable_bitmask; + bool wep_tkip_in_he; + struct csr_neighbor_report_offload_params neighbor_report_offload; + bool enable_ftopen; + bool roam_force_rssi_trigger; + uint32_t btm_validity_timer; + uint32_t btm_disassoc_timer_threshold; + bool enable_bss_load_roam_trigger; + uint32_t bss_load_threshold; + uint32_t bss_load_sample_time; + bool roaming_scan_policy; +}; + +struct csr_channel_powerinfo { + tListElem link; + uint8_t firstChannel; + uint8_t numChannels; + uint8_t txPower; + uint8_t interChannelOffset; +}; + +struct csr_roam_joinstatus { + tSirResultCodes statusCode; + /* + * this is set to unspecified if statusCode indicates timeout. + * Or it is the failed reason from the other BSS(per 802.11 spec) + */ + uint32_t reasonCode; + tSirMacAddr bssId; +}; + +struct csr_votes11d { + uint8_t votes; + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; +}; + +struct csr_scanstruct { + struct scan_profile scanProfile; + uint8_t scanResultCfgAgingTime; + tSirScanType curScanType; + struct csr_channel channels11d; + struct channel_power defaultPowerTable[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t numChannelsDefault; + struct csr_channel base_channels; /* The channel base to work on */ + tDblLinkList channelPowerInfoList24; + tDblLinkList channelPowerInfoList5G; + uint32_t nLastAgeTimeOut; + uint32_t nAgingCountDown; + uint8_t countryCodeDefault[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t countryCodeCurrent[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t countryCode11d[WNI_CFG_COUNTRY_CODE_LEN]; + v_REGDOMAIN_t domainIdDefault; /* default regulatory domain */ + v_REGDOMAIN_t domainIdCurrent; /* current regulatory domain */ + + uint8_t countryCodeCount; + /* counts for various advertized country codes */ + struct csr_votes11d votes11d[CSR_MAX_NUM_COUNTRY_CODE]; + /* + * in 11d IE from probe rsp or beacons of neighboring APs + * will use the most popular one (max count) + */ + uint8_t countryCodeElected[WNI_CFG_COUNTRY_CODE_LEN]; + /* + * Customer wants to start with an active scan based on the default + * country code. This optimization will minimize the driver load to + * association time. Based on this flag we will bypass the initial + * passive scan needed for 11d to determine the country code & domain + */ + bool fEnableBypass11d; + /* + * 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; + /* + * To enable/disable scanning only 2.4Ghz channels on first scan + */ + bool fFirstScanOnly2GChnl; + bool fDropScanCmd; /* true means we don't accept scan commands */ + + /* This includes all channels on which candidate APs are found */ + struct csr_channel occupiedChannels[CSR_ROAM_SESSION_MAX]; + int8_t roam_candidate_count[CSR_ROAM_SESSION_MAX]; + int8_t inScanResultBestAPRssi; + bool fcc_constraint; + uint8_t max_scan_count; + bool defer_update_channel_list; + wlan_scan_requester requester_id; +}; + +/* + * 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; + uint8_t staId; +}; + +#ifndef QCA_SUPPORT_CP_STATS +struct csr_pestats_reqinfo { + tListElem link; /* list links */ + uint32_t statsMask; + bool rspPending; + uint8_t staId; + uint8_t numClient; + tpAniSirGlobal pMac; + uint8_t sessionId; +}; + +struct csr_statsclient_reqinfo { + tListElem link; /* list links */ + eCsrStatsRequesterType requesterId; + tCsrStatsCallback callback; + void *pContext; + uint32_t statsMask; + struct csr_pestats_reqinfo *pPeStaEntry; + uint8_t staId; + qdf_mc_timer_t timer; + bool timerExpired; + tpAniSirGlobal pMac; /* TODO: Confirm this change BTAMP */ + uint8_t sessionId; +}; + +struct csr_tlstats_reqinfo { + uint8_t numClient; +}; +#endif /* QCA_SUPPORT_CP_STATS */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +enum csr_roamoffload_authstatus { + /* reassociation is done but couldn't finish security handshake */ + eSIR_ROAM_AUTH_STATUS_CONNECTED = 1, + /* roam successfully completed by firmware */ + eSIR_ROAM_AUTH_STATUS_AUTHENTICATED = 2, + /* unknown error */ + eSIR_ROAM_AUTH_STATUS_UNKNOWN = 0xff +}; +struct csr_roam_offload_synch_params { + uint8_t roamedVdevId; /* vdevId after roaming */ + int8_t txMgmtPower; /* HAL fills in the tx power used for */ + uint8_t rssi; /* RSSI */ + uint8_t roamReason; /* Roam reason */ + uint8_t nss; /* no of spatial streams */ + uint16_t chainMask; /* chainmask */ + uint16_t smpsMode; /* smps.mode */ + struct qdf_mac_addr bssid; /* MAC address of roamed AP */ + enum csr_roamoffload_authstatus authStatus; /* auth status */ + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN_FILS]; + uint32_t kek_len; + uint32_t pmk_len; + uint8_t pmk[SIR_PMK_LEN]; + uint8_t pmkid[SIR_PMKID_LEN]; + bool update_erp_next_seq_num; + uint16_t next_erp_seq_num; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + tpSirBssDescription bss_desc_ptr; /*BSS descriptor*/ +}; +#endif + +struct csr_roam_stored_profile { + uint32_t session_id; + struct csr_roam_profile profile; + tScanResultHandle bsslist_handle; + enum csr_roam_reason reason; + uint32_t roam_id; + bool imediate_flag; + bool clear_flag; +}; + +/** + * struct scan_cmd_info - Scan cache entry node + * @scan_id: scan id + * @scan_reason: scan reason + * @profile: roam profile + * @roam_id: Roam id + * @roambssentry: scan entries + */ +struct scan_cmd_info { + wlan_scan_id scan_id; + enum csr_scan_reason scan_reason; + struct csr_roam_profile *profile; + uint32_t roam_id; + tListElem *roambssentry; +}; + +/** + * 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 { + uint8_t sessionId; /* Session ID */ + bool sessionActive; /* true if it is used */ + + /* For BT-AMP station, this serve as BSSID for self-BSS. */ + struct qdf_mac_addr selfMacAddr; + + csr_session_open_cb session_open_cb; + csr_session_close_cb session_close_cb; + csr_roam_complete_cb callback; + void *pContext; + eCsrConnectState connectState; + struct rsn_caps rsn_caps; + tCsrRoamConnectedProfile connectedProfile; + struct csr_roam_connectedinfo connectedInfo; + struct csr_roam_profile *pCurRoamProfile; + tSirBssDescription *pConnectBssDesc; + uint16_t NumPmkidCache; /* valid number of pmkid in the cache*/ + uint16_t curr_cache_idx; /* the index in pmkidcache to write next to */ + tPmkidCacheInfo PmkidCacheInfo[CSR_MAX_PMKID_ALLOWED]; + uint8_t cJoinAttemps; + /* + * This may or may not have the up-to-date valid channel list. It is + * used to get WNI_CFG_VALID_CHANNEL_LIST and not alloc memory all time + */ + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + int32_t sPendingCommands; /* 0 means CSR is ok to low power */ +#ifdef FEATURE_WLAN_WAPI + uint16_t NumBkidCache; + tBkidCacheInfo BkidCacheInfo[CSR_MAX_BKID_ALLOWED]; +#endif /* FEATURE_WLAN_WAPI */ + /* + * indicate whether CSR is roaming + * (either via lostlink or dynamic roaming) + */ + bool fRoaming; + /* + * to remember some parameters needed for START_BSS. + * All member must be set every time we try to join or start an IBSS + */ + struct csr_roamstart_bssparams bssParams; + /* the byte count of pWpaRsnIE; */ + uint32_t nWpaRsnReqIeLength; + /* contain the WPA/RSN IE in assoc req or one sent in beacon(IBSS) */ + uint8_t *pWpaRsnReqIE; + /* the byte count for pWpaRsnRspIE */ + uint32_t nWpaRsnRspIeLength; + /* this contain the WPA/RSN IE in beacon/probe rsp */ + uint8_t *pWpaRsnRspIE; +#ifdef FEATURE_WLAN_WAPI + /* the byte count of pWapiReqIE; */ + uint32_t nWapiReqIeLength; + /* this contain the WAPI IE in assoc req or one sent in beacon (IBSS) */ + uint8_t *pWapiReqIE; + /* the byte count for pWapiRspIE */ + uint32_t nWapiRspIeLength; + /* this contain the WAPI IE in beacon/probe rsp */ + uint8_t *pWapiRspIE; +#endif /* FEATURE_WLAN_WAPI */ + uint32_t nAddIEScanLength; /* the byte count of pAddIeScanIE; */ + /* contains the additional IE in (unicast) probe req at time of join */ + uint8_t *pAddIEScan; + uint32_t nAddIEAssocLength; /* the byte count for pAddIeAssocIE */ + uint8_t *pAddIEAssoc; + tCsrTimerInfo roamingTimerInfo; + enum csr_roaming_reason roamingReason; + bool fCancelRoaming; + qdf_mc_timer_t hTimerRoaming; + /* the roamResult that is used when the roaming timer fires */ + eCsrRoamResult roamResult; + /* This is the reason code for join(assoc) failure */ + struct csr_roam_joinstatus joinFailStatusCode; + /* status from PE for deauth/disassoc(lostlink) or our own dyn roam */ + uint32_t roamingStatusCode; + uint16_t NumPmkidCandidate; + tPmkidCandidateInfo PmkidCandidateInfo[CSR_MAX_PMKID_ALLOWED]; +#ifdef FEATURE_WLAN_WAPI + uint16_t NumBkidCandidate; + tBkidCandidateInfo BkidCandidateInfo[CSR_MAX_BKID_ALLOWED]; +#endif + bool fWMMConnection; + bool fQOSConnection; +#ifdef FEATURE_WLAN_ESE + tCsrEseCckmInfo eseCckmInfo; + bool isPrevApInfoValid; + tSirMacSSid prevApSSID; + struct qdf_mac_addr prevApBssid; + uint8_t prevOpChannel; + uint16_t clientDissSecs; + uint32_t roamTS1; + tCsrEseCckmIe suppCckmIeInfo; +#endif + uint8_t bRefAssocStartCnt; /* Tracking assoc start indication */ + tSirHTConfig htConfig; + struct sir_vht_config vht_config; +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_config; + uint32_t he_sta_obsspd; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + struct csr_roam_offload_synch_params roamOffloadSynchParams; + uint8_t psk_pmk[SIR_ROAM_SCAN_PSK_SIZE]; + size_t pmk_len; + uint8_t RoamKeyMgmtOffloadEnabled; + roam_offload_synch_ind *roam_synch_data; + struct pmkid_mode_bits pmkid_modes; +#endif + tftSMEContext ftSmeContext; + /* This count represents the number of bssid's we try to join. */ + uint8_t join_bssid_count; + struct csr_roam_stored_profile stored_roam_profile; + bool ch_switch_in_progress; + bool roam_synch_in_progress; + bool supported_nss_1x1; + uint8_t vdev_nss; + uint8_t nss; + bool nss_forced_1x1; + bool disable_hi_rssi; + bool dhcp_done; + uint8_t disconnect_reason; + uint8_t uapsd_mask; + struct scan_cmd_info scan_info; + qdf_mc_timer_t roaming_offload_timer; + bool is_fils_connection; + uint16_t fils_seq_num; + bool discon_in_progress; + struct csr_disconnect_stats disconnect_stats; +}; + +struct csr_roamstruct { + uint32_t nextRoamId; + tDblLinkList channelList5G; + tDblLinkList channelList24; + struct csr_config configParam; + uint32_t numChannelsEeprom; /* total channels of eeprom */ + struct csr_channel baseChannels; /* The channel base to work on */ + enum csr_roam_state curState[CSR_ROAM_SESSION_MAX]; + enum csr_roam_substate curSubState[CSR_ROAM_SESSION_MAX]; + /* + * This may or may not have the up-to-date valid channel list. It is + * used to get WNI_CFG_VALID_CHANNEL_LIST and not alloc mem all time + */ + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t numValidChannels; /* total number of channels in CFG */ + int32_t sPendingCommands; + qdf_mc_timer_t hTimerWaitForKey; /* support timeout for WaitForKey */ +#ifndef QCA_SUPPORT_CP_STATS + tCsrSummaryStatsInfo summaryStatsInfo; + tCsrGlobalClassAStatsInfo classAStatsInfo; + tCsrGlobalClassDStatsInfo classDStatsInfo; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; + tDblLinkList statsClientReqList; + tDblLinkList peStatsReqList; + struct csr_tlstats_reqinfo tlStatsReqInfo; +#endif + tCsrTimerInfo WaitForKeyTimerInfo; + struct csr_roam_session *roamSession; + uint32_t transactionId; /* Current transaction ID for internal use. */ + tCsrNeighborRoamControlInfo neighborRoamInfo[CSR_ROAM_SESSION_MAX]; + uint8_t isFastRoamIniFeatureEnabled; +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif + uint8_t RoamRssiDiff; + bool isWESModeEnabled; + uint32_t deauthRspStatus; + uint8_t *pReassocResp; /* reassociation response from new AP */ + uint16_t reassocRespLen; /* length of reassociation response */ + qdf_mc_timer_t packetdump_timer; + qdf_list_t rssi_disallow_bssid; + qdf_mutex_t rssi_disallow_bssid_lock; + spinlock_t roam_state_lock; +}; + +#define GET_NEXT_ROAM_ID(pRoamStruct) (((pRoamStruct)->nextRoamId + 1 == 0) ? \ + 1 : (pRoamStruct)->nextRoamId) +#define CSR_IS_ROAM_STATE(pMac, state, sessionId) \ + ((state) == (pMac)->roam.curState[sessionId]) +#define CSR_IS_ROAM_STOP(pMac, sessionId) \ + CSR_IS_ROAM_STATE((pMac), eCSR_ROAMING_STATE_STOP, sessionId) +#define CSR_IS_ROAM_INIT(pMac, sessionId) \ + CSR_IS_ROAM_STATE((pMac), eCSR_ROAMING_STATE_INIT, sessionId) +#define CSR_IS_ROAM_JOINING(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_JOINING, sessionId) +#define CSR_IS_ROAM_IDLE(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_IDLE, sessionId) +#define CSR_IS_ROAM_JOINED(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_JOINED, sessionId) +#define CSR_IS_ROAM_SUBSTATE(pMac, subState, sessionId) \ + ((subState) == (pMac)->roam.curSubState[sessionId]) +#define CSR_IS_ROAM_SUBSTATE_JOIN_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_JOIN_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_AUTH_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_AUTH_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_REASSOC_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_REASSOC_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_DISASSOC_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN, sessionId) +#define CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_FORCED, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_START_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, sessionId) +#define CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_CONFIG, sessionId) +#define CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF, sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_NT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC, sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_NRT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC,\ + sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_RT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac),\ + eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC, sessionId) +#define CSR_IS_PHY_MODE_B_ONLY(pMac) \ + ((eCSR_DOT11_MODE_11b == (pMac)->roam.configParam.phyMode) || \ + (eCSR_DOT11_MODE_11b_ONLY == (pMac)->roam.configParam.phyMode)) + +#define CSR_IS_PHY_MODE_G_ONLY(pMac) \ + (eCSR_DOT11_MODE_11g == (pMac)->roam.configParam.phyMode \ + || eCSR_DOT11_MODE_11g_ONLY == (pMac)->roam.configParam.phyMode) + +#define CSR_IS_PHY_MODE_A_ONLY(pMac) \ + (eCSR_DOT11_MODE_11a == (pMac)->roam.configParam.phyMode) + +#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_AUTO & (phyMode))) + +#define CSR_IS_PHY_MODE_11n(phy_mode) \ + ((eCSR_DOT11_MODE_11n == phy_mode) || \ + (eCSR_DOT11_MODE_11n_ONLY == phy_mode) || \ + (eCSR_DOT11_MODE_11ac == phy_mode) || \ + (eCSR_DOT11_MODE_11ac_ONLY == phy_mode)) + +#define CSR_IS_PHY_MODE_11ac(phy_mode) \ + ((eCSR_DOT11_MODE_11ac == phy_mode) || \ + (eCSR_DOT11_MODE_11ac_ONLY == phy_mode)) + +/* + * 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(pMac) \ + (BAND_2G == (pMac)->roam.configParam.eBand) + +#define CSR_IS_5G_BAND_ONLY(pMac) \ + (BAND_5G == (pMac)->roam.configParam.eBand) + +#define CSR_IS_RADIO_DUAL_BAND(pMac) \ + (BAND_ALL == (pMac)->roam.configParam.bandCapability) + +#define CSR_IS_RADIO_BG_ONLY(pMac) \ + (BAND_2G == (pMac)->roam.configParam.bandCapability) + +/* + * 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(pMac) \ + (BAND_5G == (pMac)->roam.configParam.bandCapability) +/* this function returns true if the NIC is operating in both bands. */ +#define CSR_IS_OPEARTING_DUAL_BAND(pMac) \ + ((BAND_ALL == (pMac)->roam.configParam.bandCapability) && \ + (BAND_ALL == (pMac)->roam.configParam.eBand)) +/* + * 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(pMac) \ + (CSR_IS_OPEARTING_DUAL_BAND((pMac)) || \ + CSR_IS_RADIO_A_ONLY((pMac)) || CSR_IS_5G_BAND_ONLY((pMac))) + +/* + * 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(pMac) \ + (CSR_IS_OPEARTING_DUAL_BAND((pMac)) || \ + CSR_IS_RADIO_BG_ONLY((pMac)) || CSR_IS_24_BAND_ONLY((pMac))) +#define CSR_GET_BAND(ch_num) \ + ((WLAN_REG_IS_24GHZ_CH(ch_num)) ? BAND_2G : BAND_5G) +#define CSR_IS_11D_INFO_FOUND(pMac) \ + (0 != (pMac)->scan.channelOf11dInfo) +#define CSR_IS_ROAMING(pSession) \ + ((CSR_IS_LOSTLINK_ROAMING((pSession)->roamingReason)) || \ + (eCsrDynamicRoaming == (pSession)->roamingReason) || \ + (eCsrReassocRoaming == (pSession)->roamingReason)) +#define CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) \ + (pMac->roam.configParam.addTSWhenACMIsOff) +#define CSR_IS_LOSTLINK_ROAMING(reason) \ + ((eCsrLostlinkRoamingDisassoc == (reason)) || \ + (eCsrLostlinkRoamingDeauth == (reason))) + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/* bit-4 and bit-5 indicate the subnet status */ +#define CSR_GET_SUBNET_STATUS(roam_reason) (((roam_reason) & 0x30) >> 4) +#else +#define CSR_GET_SUBNET_STATUS(roam_reason) (0) +#endif + +QDF_STATUS csr_get_channel_and_power_list(tpAniSirGlobal pMac); + +QDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac); + +QDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +QDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +void csr_set_global_cfgs(tpAniSirGlobal pMac); +void csr_set_default_dot11_mode(tpAniSirGlobal pMac); +bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_connected_ibss(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_connected_infra(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_connected(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_infra(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_wds(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_connected_wds(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_disconnected_wds(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac); +bool csr_is_all_session_disconnected(tpAniSirGlobal pMac); +bool csr_is_sta_session_connected(tpAniSirGlobal pMac); +bool csr_is_p2p_session_connected(tpAniSirGlobal pMac); +bool csr_is_any_session_connected(tpAniSirGlobal pMac); +bool csr_is_infra_connected(tpAniSirGlobal pMac); + +/** + * csr_get_connected_infra() - get the session id of the connected infra + * @mac_ctx: pointer to global mac structure + * + * The function check if any infra is present in connected state and if present + * return the session id of the connected infra else if no infra is in connected + * state return CSR_SESSION_ID_INVALID + * + * Return: session id of the connected infra + */ +uint8_t csr_get_connected_infra(tpAniSirGlobal mac_ctx); +bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac); +bool csr_is_concurrent_session_running(tpAniSirGlobal pMac); +bool csr_is_infra_ap_started(tpAniSirGlobal pMac); +bool csr_is_ibss_started(tpAniSirGlobal pMac); +bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirBssDescription *pBssDesc); +bool csr_is_conn_state_connected_infra_ap(tpAniSirGlobal pMac, + uint32_t sessionId); +QDF_STATUS csr_get_statistics(tpAniSirGlobal pMac, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint8_t staId, void *pContext, uint8_t sessionId); +QDF_STATUS csr_get_rssi(tpAniSirGlobal pMac, tCsrRssiCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, int8_t lastRSSI, + void *pContext); +QDF_STATUS csr_get_snr(tpAniSirGlobal pMac, tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext); +QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, + tCsrConfigParam *pParam); +QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, + tCsrConfigParam *pParam); +QDF_STATUS csr_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +QDF_STATUS csr_open(tpAniSirGlobal pMac); +QDF_STATUS csr_init_chan_list(tpAniSirGlobal mac, uint8_t *alpha2); +QDF_STATUS csr_close(tpAniSirGlobal pMac); +QDF_STATUS csr_start(tpAniSirGlobal pMac); +QDF_STATUS csr_stop(tpAniSirGlobal pMac); +QDF_STATUS csr_ready(tpAniSirGlobal pMac); + +#ifdef FEATURE_WLAN_WAPI +QDF_STATUS csr_roam_get_wapi_req_ie(tpAniSirGlobal pMac, + uint32_t sessionId, uint32_t *pLen, uint8_t *pBuf); +QDF_STATUS csr_roam_get_wapi_rsp_ie(tpAniSirGlobal pMac, + uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); +uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe); +#endif /* FEATURE_WLAN_WAPI */ + +void csr_set_cfg_privacy(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + bool fPrivacy); +int8_t csr_get_infra_session_id(tpAniSirGlobal pMac); +uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, + uint8_t sessionId); +/** + * csr_get_concurrent_operation_channel() - To get concurrent operating channel + * @mac_ctx: Pointer to mac context + * + * This routine will return operating channel 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: uint8_t + */ +uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal mac_ctx); + +/** + * csr_get_beaconing_concurrent_channel() - To get concurrent operating channel + * 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 reqested mode is active it will return 0 + * + * Return: uint8_t + */ +uint8_t csr_get_beaconing_concurrent_channel(tpAniSirGlobal mac_ctx, + uint8_t vdev_id_to_skip); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t csr_check_concurrent_channel_overlap( + tpAniSirGlobal pMac, + uint16_t sap_ch, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode); +#endif +QDF_STATUS csr_roam_copy_connect_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamConnectedProfile *pProfile); +bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId); + +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId); + +#ifdef FEATURE_WLAN_ESE +/* Returns whether the current association is a ESE assoc or not */ +bool csr_roam_is_ese_assoc(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_roam_is_ese_ini_feature_enabled(tpAniSirGlobal pMac); +QDF_STATUS csr_get_tsm_stats(tpAniSirGlobal pMac, + tCsrTsmStatsCallback callback, + uint8_t staId, + struct qdf_mac_addr bssId, + void *pContext, uint8_t tid); +#endif + +/* Returns whether "Legacy Fast Roaming" is enabled...or not */ +bool csr_roam_is_fast_roam_enabled(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_roam_is_roam_offload_scan_enabled( + tpAniSirGlobal pMac); +bool csr_is_channel_present_in_list(uint8_t *pChannelList, + int numChannels, + uint8_t channel); +QDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList, + int numChannels, + uint8_t channel); +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp scanOffloadRsp); +#else +static inline QDF_STATUS csr_roam_offload_scan_rsp_hdlr( + tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp scanOffloadRsp) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +QDF_STATUS csr_handoff_request(tpAniSirGlobal pMac, uint8_t sessionId, + tCsrHandoffRequest + *pHandoffInfo); +bool csr_roam_is_sta_mode(tpAniSirGlobal pMac, uint32_t sessionId); + +/* Post Channel Change Indication */ +QDF_STATUS csr_roam_channel_change_req(tpAniSirGlobal pMac, + struct qdf_mac_addr + bssid, struct ch_params *ch_params, + struct csr_roam_profile *profile); + +/* Post Beacon Tx Start Indication */ +QDF_STATUS csr_roam_start_beacon_req(tpAniSirGlobal pMac, + struct qdf_mac_addr bssid, uint8_t dfsCacWaitStatus); + +QDF_STATUS csr_roam_send_chan_sw_ie_request(tpAniSirGlobal pMac, + struct qdf_mac_addr bssid, + uint8_t targetChannel, + uint8_t csaIeReqd, + struct ch_params *ch_params); +QDF_STATUS csr_roam_modify_add_ies(tpAniSirGlobal pMac, + tSirModifyIE *pModifyIE, + eUpdateIEsType updateType); +QDF_STATUS +csr_roam_update_add_ies(tpAniSirGlobal pMac, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_scan_save_roam_offload_ap_to_scan_cache( + tpAniSirGlobal pMac, + struct sSirSmeRoamOffloadSynchInd *roam_synch_ind_ptr, + tpSirBssDescription bss_desc_ptr); +void csr_process_ho_fail_ind(tpAniSirGlobal pMac, void *pMsgBuf); +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +void csr_roaming_report_diag_event(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_ind_ptr, + enum csr_diagwlan_status_eventreason reason); +#else +static inline void csr_roaming_report_diag_event( + tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_ind_ptr, + enum csr_diagwlan_status_eventreason reason) +{} +#endif + +bool csr_store_joinreq_param(tpAniSirGlobal mac_ctx, + struct csr_roam_profile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id); +bool csr_clear_joinreq_param(tpAniSirGlobal mac_ctx, + uint32_t session_id); +QDF_STATUS csr_issue_stored_joinreq(tpAniSirGlobal mac_ctx, + uint32_t *roam_id, + uint32_t session_id); +QDF_STATUS csr_get_channels_and_power(tpAniSirGlobal pMac); + +void csr_nonscan_pending_ll_unlock(struct sAniSirGlobal *mac_ctx); +void csr_nonscan_active_ll_unlock(struct sAniSirGlobal *mac_ctx); +void csr_nonscan_pending_ll_lock(struct sAniSirGlobal *mac_ctx); +void csr_nonscan_active_ll_lock(struct sAniSirGlobal *mac_ctx); +bool csr_nonscan_active_ll_is_list_empty( + struct sAniSirGlobal *mac_ctx, + bool inter_locked); +bool csr_nonscan_pending_ll_is_list_empty( + struct sAniSirGlobal *mac_ctx, + bool inter_locked); +bool csr_nonscan_active_ll_remove_entry( + struct sAniSirGlobal *mac_ctx, + tListElem *pEntryToRemove, bool inter_locked); +tListElem *csr_nonscan_active_ll_peek_head( + struct sAniSirGlobal *mac_ctx, + bool inter_locked); +tListElem *csr_nonscan_pending_ll_peek_head( + struct sAniSirGlobal *mac_ctx, + bool inter_locked); +tListElem *csr_nonscan_active_ll_remove_head( + struct sAniSirGlobal *mac_ctx, + bool inter_locked); +tListElem *csr_nonscan_pending_ll_remove_head( + struct sAniSirGlobal *mac_ctx, + bool inter_locked); +uint32_t csr_nonscan_pending_ll_count( + struct sAniSirGlobal *mac_ctx); +void csr_nonscan_pending_ll_insert_head( + struct sAniSirGlobal *mac_ctx, + tListElem *entry, bool inter_locked); +void csr_nonscan_pending_ll_insert_tail( + struct sAniSirGlobal *mac_ctx, + tListElem *entry, bool inter_locked); +uint32_t csr_nonscan_active_ll_count( + struct sAniSirGlobal *mac_ctx); +void csr_nonscan_active_ll_insert_head( + struct sAniSirGlobal *mac_ctx, + tListElem *entry, bool inter_locked); +tListElem *csr_nonscan_pending_ll_next( + struct sAniSirGlobal *mac_ctx, + tListElem *entry, bool inter_locked); + +/** + * csr_purge_vdev_pending_ser_cmd_list() - purge all scan and non-scan + * pending cmds for the vdev id + * @mac_ctx: pointer to global MAC context + * @vdev_id : vdev id for which the pending cmds need to be purged + * + * Return : none + */ +void csr_purge_vdev_pending_ser_cmd_list(struct sAniSirGlobal *mac_ctx, + uint32_t vdev_id); + +/** + * csr_purge_vdev_all_ser_cmd_list() - purge all scan and non-scan + * active and pending cmds for the vdev id + * @mac_ctx: pointer to global MAC context + * @vdev_id : vdev id for which cmds need to be purged + * + * Return : none + */ +void csr_purge_vdev_all_ser_cmd_list(struct sAniSirGlobal *mac_ctx, + uint32_t vdev_id); + +/** + * 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 sAniSirGlobal *mac_ctx); + +bool csr_wait_for_connection_update(tpAniSirGlobal mac, + bool do_release_reacquire_lock); +enum QDF_OPMODE csr_get_session_persona(tpAniSirGlobal pmac, + uint32_t session_id); +void csr_roam_substate_change( + tpAniSirGlobal pMac, enum csr_roam_substate + NewSubstate, uint32_t sessionId); + +void csr_neighbor_roam_process_scan_results( + tpAniSirGlobal mac_ctx, + uint8_t sessionid, tScanResultHandle *scan_results_list); + +void csr_neighbor_roam_trigger_handoff(tpAniSirGlobal mac_ctx, + uint8_t session_id); +bool csr_is_ndi_started(tpAniSirGlobal mac_ctx, uint32_t session_id); + +QDF_STATUS csr_roam_update_config( + tpAniSirGlobal 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 + * @channel : channel number to check for MCC scenario + * + * Return : true if channel causes MCC, else false + */ +bool csr_is_mcc_channel(tpAniSirGlobal mac_ctx, uint8_t channel); +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_link_list.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_link_list.h new file mode 100644 index 0000000000000000000000000000000000000000..bed69365ab6082d5b61bb0c722f9f15531eb1893 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_link_list.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011-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 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" + +#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) ((type *)( \ + (uint8_t *)(address) - \ + (uint8_t *)(&((type *)0)->field))) +/* To get the offset of (field) inside structure (type) */ +#define GET_FIELD_OFFSET(type, field) ((uintptr_t)(&(((type *)0)->field))) +#define GET_ROUND_UP(_Field, _Boundary) \ + (((_Field) + ((_Boundary) - 1)) & ~((_Boundary) - 1)) +#define BITS_ON(_Field, _Bitmask) ((_Field) |= (_Bitmask)) +#define BITS_OFF(_Field, _Bitmask) ((_Field) &= ~(_Bitmask)) +#define CSR_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define CSR_MIN(a, b) ((a) < (b) ? (a) : (b)) +#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/drivers/staging/qcacld-3.0/core/sme/inc/csr_neighbor_roam.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_neighbor_roam.h new file mode 100644 index 0000000000000000000000000000000000000000..7627a96e197ee6a6c371749e569ac1a11530839c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_neighbor_roam.h @@ -0,0 +1,436 @@ +/* + * 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. + */ + +/** + * \file csr_neighbor_roam.h + * + * Exports and types for the neighbor roaming algorithm which is sepcifically + * designed for Android. + */ + +#ifndef CSR_NEIGHBOR_ROAM_H +#define CSR_NEIGHBOR_ROAM_H + +#include "sme_api.h" + +#define ROAM_AP_AGE_LIMIT_MS 10000 + +/* Enumeration of various states in neighbor roam algorithm */ +typedef enum { + eCSR_NEIGHBOR_ROAM_STATE_CLOSED, + eCSR_NEIGHBOR_ROAM_STATE_INIT, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, + eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, + eNEIGHBOR_STATE_MAX +} eCsrNeighborRoamState; + +/* Parameters that are obtained from CFG */ +typedef struct sCsrNeighborRoamCfgParams { + uint8_t maxNeighborRetries; + uint32_t neighborScanPeriod; + uint32_t neighbor_scan_min_period; + tCsrChannelInfo channelInfo; + uint8_t neighborLookupThreshold; + int8_t rssi_thresh_offset_5g; + uint8_t neighborReassocThreshold; + uint32_t minChannelScanTime; + uint32_t maxChannelScanTime; + uint16_t neighborResultsRefreshPeriod; + uint16_t emptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + 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; +} tCsrNeighborRoamCfgParams, *tpCsrNeighborRoamCfgParams; + +#define CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX 255 +typedef struct sCsrNeighborRoamChannelInfo { + /* Flag to mark reception of IAPP Neighbor list */ + bool IAPPNeighborListReceived; + /* Current channel index that is being scanned */ + uint8_t currentChanIndex; + /* Max number of channels in channel list and the list of channels */ + tCsrChannelInfo currentChannelListInfo; +} tCsrNeighborRoamChannelInfo, *tpCsrNeighborRoamChannelInfo; + +typedef struct sCsrNeighborRoamBSSInfo { + tListElem List; + uint8_t apPreferenceVal; + tpSirBssDescription pBssDescription; +} tCsrNeighborRoamBSSInfo, *tpCsrNeighborRoamBSSInfo; + +#define CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT 1000 /* in milliseconds */ +#define CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER 10 /* in milliseconds */ +/* Max number of MAC addresses with which the pre-auth was failed */ +#define MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS 10 +#define MAX_BSS_IN_NEIGHBOR_RPT 15 +#define CSR_NEIGHBOR_ROAM_MAX_NUM_PREAUTH_RETRIES 3 + +/* Black listed APs. List of MAC Addresses with which the Preauth was failed */ +typedef struct sCsrPreauthFailListInfo { + uint8_t numMACAddress; + tSirMacAddr macAddress[MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS]; +} tCsrPreauthFailListInfo, *tpCsrPreauthFailListInfo; + +typedef struct sCsrNeighborReportBssInfo { + uint8_t channelNum; + uint8_t neighborScore; + tSirMacAddr neighborBssId; +} tCsrNeighborReportBssInfo, *tpCsrNeighborReportBssInfo; + +typedef struct sCsr11rAssocNeighborInfo { + bool preauthRspPending; + bool neighborRptPending; + uint8_t currentNeighborRptRetryNum; + tCsrPreauthFailListInfo preAuthFailList; + uint32_t neighborReportTimeout; + uint32_t PEPreauthRespTimeout; + uint8_t numPreAuthRetries; + tDblLinkList preAuthDoneList; /* llist which consists/preauth nodes */ + uint8_t numBssFromNeighborReport; + /* Contains info needed during REPORT_SCAN State */ + tCsrNeighborReportBssInfo neighboReportBssInfo[MAX_BSS_IN_NEIGHBOR_RPT]; +} tCsr11rAssocNeighborInfo, *tpCsr11rAssocNeighborInfo; + +typedef enum { + eFirstEmptyScan = 1, + eSecondEmptyScan, + eThirdEmptyScan, + eFourthEmptyScan, + eFifthEmptyScan, + eMaxEmptyScan = eFifthEmptyScan, +} eNeighborRoamEmptyScanCount; + +typedef enum { + DEFAULT_SCAN = 0, + SPLIT_SCAN_OCCUPIED_LIST = 1, +} eNeighborRoamScanMode; + +/* Complete control information for neighbor roam algorithm */ +typedef struct sCsrNeighborRoamControlInfo { + eCsrNeighborRoamState neighborRoamState; + eCsrNeighborRoamState prevNeighborRoamState; + tCsrNeighborRoamCfgParams cfgParams; + struct qdf_mac_addr currAPbssid; /* current assoc AP */ + uint8_t currAPoperationChannel; /* current assoc AP */ + tCsrNeighborRoamChannelInfo roamChannelInfo; + uint8_t currentNeighborLookupThreshold; + uint8_t currentOpportunisticThresholdDiff; + uint8_t currentRoamRescanRssiDiff; + tDblLinkList roamableAPList; /* List of current FT candidates */ + struct csr_roam_profile csrNeighborRoamProfile; + bool is11rAssoc; + tCsr11rAssocNeighborInfo FTRoamInfo; +#ifdef FEATURE_WLAN_ESE + bool isESEAssoc; + bool isVOAdmitted; + uint16_t MinQBssLoadRequired; +#endif + /* + * Previous connected profile. + * If the new profile does not match previous we re-initialize + * occupied channel list + */ + tCsrRoamConnectedProfile prevConnProfile; + /* upper layer requested a reassoc */ + uint8_t uOsRequestedHandoff; + /* handoff related info came with upper layer's req for reassoc */ + tCsrHandoffRequest handoffReqInfo; + uint8_t currentRoamBmissFirstBcnt; + uint8_t currentRoamBmissFinalBcnt; + uint8_t currentRoamBeaconRssiWeight; + uint8_t last_sent_cmd; + bool b_roam_scan_offload_started; +} tCsrNeighborRoamControlInfo, *tpCsrNeighborRoamControlInfo; + +/* All the necessary Function declarations are here */ +QDF_STATUS csr_neighbor_roam_indicate_connect(tpAniSirGlobal pMac, + uint8_t sessionId, QDF_STATUS status); +QDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId); +void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_transit_to_cfg_chan_scan(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csrNeighborRoamTransitionToPreauthDone(tpAniSirGlobal pMac); +QDF_STATUS csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac, + tCsrScanResultFilter *pScanFilter, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_preauth_rsp_handler(tpAniSirGlobal pMac, + uint8_t sessionId, QDF_STATUS limStatus); +bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId); +#ifdef WLAN_FEATURE_HOST_ROAM +void csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId); +void csr_neighbor_roam_free_roamable_bss_list(tpAniSirGlobal mac_ctx, + tDblLinkList *llist); +bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo pHandoffNode, uint8_t sessionId); +QDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, struct csr_roam_profile *pProfile); +void csr_neighbor_roam_request_handoff(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr(tpAniSirGlobal pMac, + void *pMsg); +QDF_STATUS csr_neighbor_roam_process_scan_complete(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, + uint8_t sessionId); +void csr_neighbor_roam_reset_preauth_control_info( + tpAniSirGlobal mac_ctx, uint8_t session_id); +void csr_neighbor_roam_purge_preauth_failed_list(tpAniSirGlobal pMac); +#else +static inline bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + return false; +} +static inline QDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline QDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, struct csr_roam_profile *pProfile) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline QDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr( + tpAniSirGlobal pMac, void *pMsg) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline QDF_STATUS csr_neighbor_roam_process_scan_complete( + tpAniSirGlobal pMac, uint8_t sessionId) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline void csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + tpAniSirGlobal pMac, uint8_t sessionId) +{} +static inline void csr_neighbor_roam_free_roamable_bss_list( + tpAniSirGlobal mac_ctx, tDblLinkList *llist) +{} +static inline void csr_neighbor_roam_request_handoff(tpAniSirGlobal pMac, + uint8_t sessionId) +{} +static inline void csr_neighbor_roam_reset_preauth_control_info( + tpAniSirGlobal mac_ctx, uint8_t session_id) +{} +static inline void csr_neighbor_roam_purge_preauth_failed_list( + tpAniSirGlobal pMac) +{} +static inline bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo pHandoffNode, uint8_t sessionId) +{ + return false; +} +static inline bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + return false; +} +#endif +bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_update_config(tpAniSirGlobal mac_ctx, + uint8_t session_id, uint8_t value, uint8_t reason); +QDF_STATUS csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal pMac, + uint8_t sessionId, const bool fastRoamEnabled); +QDF_STATUS csr_neighbor_roam_channels_filter_by_current_band( + tpAniSirGlobal pMac, uint8_t sessionId, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t *pMergedOutputNumOfChannels); +QDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t outputNumOfChannels, + uint8_t *pMergedOutputNumOfChannels); +void csr_roam_reset_roam_params(tpAniSirGlobal mac_ptr); +#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_BEACON_RSSI_WEIGHT_CHANGED 22 +#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_BLACKLIST_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 + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS csr_roam_offload_scan(tpAniSirGlobal pMac, uint8_t sessionId, + uint8_t command, uint8_t reason); +#else +static inline QDF_STATUS csr_roam_offload_scan(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t command, uint8_t reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * csr_get_roam_enabled_sta_sessionid() - get the session id of the sta on which + * roaming is enabled. + * @mac_ctx: pointer to global mac structure + * + * The function check if any sta 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 CSR_SESSION_ID_INVALID + * + * Return: session id of STA on which roaming is enabled + */ +uint8_t csr_get_roam_enabled_sta_sessionid( + tpAniSirGlobal mac_ctx); + +#if defined(WLAN_FEATURE_FILS_SK) +/** + * csr_update_fils_config - Update FILS config to CSR roam session + * @mac: MAC context + * @session_id: session id + * @src_profile: Source profile having latest FILS config + * + * API to update FILS config to roam csr session + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_update_fils_config(tpAniSirGlobal mac, uint8_t session_id, + struct csr_roam_profile *src_profile); +#endif + +QDF_STATUS csr_neighbor_roam_handoff_req_hdlr(tpAniSirGlobal pMac, void *pMsg); +QDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac, + uint8_t sessionId, QDF_STATUS status); +QDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, + uint8_t sessionId); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS csr_set_cckm_ie(tpAniSirGlobal pMac, const uint8_t sessionId, + const uint8_t *pCckmIe, const uint8_t ccKmIeLen); +QDF_STATUS csr_roam_read_tsf(tpAniSirGlobal pMac, uint8_t *pTimestamp, + const uint8_t sessionId); +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_roam_synch_callback(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, enum sir_roam_op_code reason); +#else +static inline QDF_STATUS csr_roam_synch_callback(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, enum sir_roam_op_code reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +void csr_neighbor_roam_state_transition(tpAniSirGlobal mac_ctx, + uint8_t newstate, uint8_t session); +uint8_t *csr_neighbor_roam_state_to_string(uint8_t state); +tpCsrNeighborRoamBSSInfo csr_neighbor_roam_next_roamable_ap( + tpAniSirGlobal mac_ctx, tDblLinkList *llist, + tpCsrNeighborRoamBSSInfo neighbor_entry); +bool csr_neighbor_roam_remove_roamable_ap_list_entry(tpAniSirGlobal pMac, + tDblLinkList *pList, tpCsrNeighborRoamBSSInfo pNeighborEntry); +void csr_neighbor_roam_free_neighbor_roam_bss_node(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo neighborRoamBSSNode); +QDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_is_preauth_candidate(tpAniSirGlobal pMac, + uint8_t sessionId, tSirMacAddr bssId); +#ifdef FEATURE_WLAN_LFR_METRICS +void csr_neighbor_roam_send_lfr_metric_event(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirMacAddr bssid, eRoamCmdStatus status); +#else +static inline void csr_neighbor_roam_send_lfr_metric_event( + tpAniSirGlobal mac_ctx, uint8_t session_id, + tSirMacAddr bssid, eRoamCmdStatus status) +{} +#endif +QDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac); +QDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, + uint32_t sessionId, struct csr_roam_profile *pDstProfile); + +/** + * 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); + +#endif /* CSR_NEIGHBOR_ROAM_H */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_support.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_support.h new file mode 100644 index 0000000000000000000000000000000000000000..a076aa19250270e6ff6e0ff95f2613f1e0db3246 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_support.h @@ -0,0 +1,360 @@ +/* + * 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. + */ + +/** + * \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) +#define CSR_WAPI_VERSION_SUPPORTED (1) +#define CSR_WAPI_MAX_AUTH_SUITES (2) +#define CSR_WAPI_MAX_CYPHERS (5) +#define CSR_WAPI_MAX_UNICAST_CYPHERS (5) +#define CSR_WAPI_MAX_MULTICAST_CYPHERS (1) +#endif /* FEATURE_WLAN_WAPI */ + +#define CSR_RSN_OUI_SIZE (4) +#define CSR_RSN_VERSION_SUPPORTED (1) +#define CSR_RSN_MAX_AUTH_SUITES (4) +#define CSR_RSN_MAX_CYPHERS (5) +#define CSR_RSN_MAX_UNICAST_CYPHERS (5) +#define CSR_RSN_MAX_MULTICAST_CYPHERS (1) + +#define CSR_WPA_OUI_SIZE (4) +#define CSR_WPA_VERSION_SUPPORTED (1) +#define CSR_WME_OUI_SIZE (4) +#define CSR_WPA_MAX_AUTH_SUITES (2) +#define CSR_WPA_MAX_CYPHERS (5) +#define CSR_WPA_MAX_UNICAST_CYPHERS (5) +#define CSR_WPA_MAX_MULTICAST_CYPHERS (1) +/* minimum size of the IE->length is the size of the Oui + Version. */ +#define CSR_WPA_IE_MIN_SIZE (6) +#define CSR_WPA_IE_MIN_SIZE_W_MULTICAST (HDD_WPA_IE_MIN_SIZE + HDD_WPA_OUI_SIZE) +#define CSR_WPA_IE_MIN_SIZE_W_UNICAST (HDD_WPA_IE_MIN_SIZE + \ + HDD_WPA_OUI_SIZE + sizeof(pWpaIe->cUnicastCyphers)) + +#define CSR_DOT11_SUPPORTED_RATES_MAX (12) +#define CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX (8) + +#define CSR_DOT11_BASIC_RATE_MASK (0x80) + +/* NOTE these index are use as array index for csr_rsn_oui */ +#define CSR_OUI_USE_GROUP_CIPHER_INDEX 0x00 +#define CSR_OUI_WEP40_OR_1X_INDEX 0x01 +#define CSR_OUI_TKIP_OR_PSK_INDEX 0x02 +#define CSR_OUI_RESERVED_INDEX 0x03 +#define CSR_OUI_AES_INDEX 0x04 +#define CSR_OUI_WEP104_INDEX 0x05 +/* ENUM_FILS_SHA384 9 */ +/* ENUM_FILS_SHA384 10 */ +/* ENUM_FT_FILS_SHA256 11 */ +/* ENUM_FT_FILS_SHA384 12 */ +#define CSR_OUI_AES_GCMP_INDEX 0x0D +#define CSR_OUI_AES_GCMP_256_INDEX 0x0E + +#ifdef FEATURE_WLAN_WAPI +#define CSR_OUI_WAPI_RESERVED_INDEX 0x00 +#define CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX 0x01 +#define CSR_OUI_WAPI_WAI_PSK_INDEX 0x02 +/* max idx, should be last & highest */ +#define CSR_OUI_WAPI_WAI_MAX_INDEX 0x03 +#endif /* FEATURE_WLAN_WAPI */ + +typedef enum { + /* 11b rates */ + eCsrSuppRate_1Mbps = 1 * 2, + eCsrSuppRate_2Mbps = 2 * 2, + eCsrSuppRate_5_5Mbps = 11, /* 5.5 * 2 */ + eCsrSuppRate_11Mbps = 11 * 2, + + /* 11a / 11g rates */ + eCsrSuppRate_6Mbps = 6 * 2, + eCsrSuppRate_9Mbps = 9 * 2, + eCsrSuppRate_12Mbps = 12 * 2, + eCsrSuppRate_18Mbps = 18 * 2, + eCsrSuppRate_24Mbps = 24 * 2, + eCsrSuppRate_36Mbps = 36 * 2, + eCsrSuppRate_48Mbps = 48 * 2, + eCsrSuppRate_54Mbps = 54 * 2, + + /* airgo proprietary rates */ + eCsrSuppRate_10Mbps = 10 * 2, + eCsrSuppRate_10_5Mbps = 21, /* 10.5 * 2 */ + eCsrSuppRate_20Mbps = 20 * 2, + eCsrSuppRate_21Mbps = 21 * 2, + eCsrSuppRate_40Mbps = 40 * 2, + eCsrSuppRate_42Mbps = 42 * 2, + eCsrSuppRate_60Mbps = 60 * 2, + eCsrSuppRate_63Mbps = 63 * 2, + eCsrSuppRate_72Mbps = 72 * 2, + eCsrSuppRate_80Mbps = 80 * 2, + eCsrSuppRate_84Mbps = 84 * 2, + eCsrSuppRate_96Mbps = 96 * 2, + eCsrSuppRate_108Mbps = 108 * 2, + eCsrSuppRate_120Mbps = 120 * 2, + eCsrSuppRate_126Mbps = 126 * 2, + eCsrSuppRate_144Mbps = 144 * 2, + eCsrSuppRate_160Mbps = 160 * 2, + eCsrSuppRate_168Mbps = 168 * 2, + eCsrSuppRate_192Mbps = 192 * 2, + eCsrSuppRate_216Mbps = 216 * 2, + eCsrSuppRate_240Mbps = 240 * 2 +} eCsrSupportedRates; + +/* Generic Information Element Structure */ +typedef struct sDot11IEHeader { + uint8_t ElementID; + uint8_t Length; +} qdf_packed tDot11IEHeader; + +typedef struct tagCsrWpaIe { + tDot11IEHeader IeHeader; + uint8_t Oui[CSR_WPA_OUI_SIZE]; + uint16_t Version; + uint8_t MulticastOui[CSR_WPA_OUI_SIZE]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_WPA_OUI_SIZE]; + } qdf_packed UnicastOui[1]; +} qdf_packed tCsrWpaIe; + +typedef struct tagCsrWpaAuthIe { + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_WPA_OUI_SIZE]; + } qdf_packed AuthOui[1]; +} qdf_packed tCsrWpaAuthIe; + +typedef struct tagCsrRSNIe { + tDot11IEHeader IeHeader; + uint16_t Version; + uint8_t MulticastOui[CSR_RSN_OUI_SIZE]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_RSN_OUI_SIZE]; + } qdf_packed UnicastOui[1]; +} qdf_packed tCsrRSNIe; + +typedef struct tagCsrRSNAuthIe { + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_RSN_OUI_SIZE]; + } qdf_packed AuthOui[1]; +} qdf_packed tCsrRSNAuthIe; + +typedef struct tagCsrRSNPMKIe { + uint16_t cPMKIDs; + struct { + uint8_t PMKID[CSR_RSN_PMKID_SIZE]; + } qdf_packed PMKIDList[1]; +} qdf_packed tCsrRSNPMKIe; + +typedef struct tCsrIELenInfo { + uint8_t min; + uint8_t max; +} qdf_packed tCsrIELenInfo; + +#ifdef FEATURE_WLAN_WAPI +typedef struct tagCsrWapiIe { + tDot11IEHeader IeHeader; + uint16_t Version; + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_WAPI_OUI_SIZE]; + } qdf_packed AuthOui[1]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_WAPI_OUI_SIZE]; + } qdf_packed UnicastOui[1]; + uint8_t MulticastOui[CSR_WAPI_OUI_SIZE]; + struct { + uint16_t PreAuthSupported:1; + uint16_t Reserved:15; + } qdf_packed tCsrWapiCapabilities; +} qdf_packed tCsrWapiIe; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct tagRoamingTimerInfo { + tpAniSirGlobal pMac; + uint8_t sessionId; +} tCsrTimerInfo; + +#define CSR_IS_11A_BSS(pBssDesc) (eSIR_11A_NW_TYPE == (pBssDesc)->nwType) +#define CSR_IS_BASIC_RATE(rate) ((rate) & CSR_DOT11_BASIC_RATE_MASK) +#define CSR_IS_QOS_BSS(pIes) \ + ((pIes)->WMMParams.present || (pIes)->WMMInfoAp.present) +#define CSR_IS_UAPSD_BSS(pIes) \ + (((pIes)->WMMParams.present && \ + ((pIes)->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD)) || \ + ((pIes)->WMMInfoAp.present && (pIes)->WMMInfoAp.uapsd)) + +bool csr_get_bss_id_bss_desc(tSirBssDescription *pSirBssDesc, + struct qdf_mac_addr *pBssId); +bool csr_is_bss_id_equal(tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2); +eCsrMediaAccessType csr_get_qos_from_bss_desc(tpAniSirGlobal mac_ctx, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes); +bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len); +bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc); +bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc); +bool csr_is_privacy(tSirBssDescription *pSirBssDesc); +tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp * + pSmeDisassocRsp); +tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp); +uint32_t csr_get_frag_thresh(tpAniSirGlobal mac_ctx); +uint32_t csr_get_rts_thresh(tpAniSirGlobal mac_ctx); +eCsrPhyMode csr_get_phy_mode_from_bssDesc(tSirBssDescription *pSirBssDesc); +uint32_t csr_get11h_power_constraint(tpAniSirGlobal mac_ctx, + tDot11fIEPowerConstraints *constraints); +uint8_t csr_construct_rsn_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe); + +uint8_t csr_construct_wpa_ie(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe); + +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(struct csr_roam_profile *pProfile); +#endif /* FEATURE_WLAN_WAPI */ +/* + * If a WPAIE exists in the profile, just use it. + * Or else construct one from the BSS Caller allocated memory for pWpaIe and + * guarrantee it can contain a max length WPA IE + */ +uint8_t csr_retrieve_wpa_ie(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe); + +bool csr_is_ssid_equal(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2); + +/* Null ssid means match */ +bool csr_is_ssid_in_list(tSirMacSSid *pSsid, tCsrSSIDs *pSsidList); +bool csr_is_profile_wpa(struct csr_roam_profile *pProfile); +bool csr_is_profile_rsn(struct csr_roam_profile *pProfile); +/* + * If a RSNIE exists in the profile, just use it. Or + * else construct one from the BSS Caller allocated memory for pWpaIe and + * guarantee it can contain a max length WPA IE + */ +uint8_t csr_retrieve_rsn_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe); +#ifdef FEATURE_WLAN_WAPI +/* + * If a WAPI IE exists in the profile, just use it. + * Or else construct one from the BSS. Caller allocated memory for pWapiIe and + * guarrantee it can contain a max length WAPI IE + */ +uint8_t csr_retrieve_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe); +#endif /* FEATURE_WLAN_WAPI */ +bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate); +bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate); +tAniEdType csr_translate_encrypt_type_to_ed_type( + eCsrEncryptionType EncryptType); +/* + * pIes shall contain IEs from pSirBssDesc. + * It shall be returned from function csr_get_parsed_bss_description_ies + */ +bool csr_is_security_match(tpAniSirGlobal mac_ctx, tCsrAuthList *authType, + tCsrEncryptionList *pUCEncryptionType, + tCsrEncryptionList *pMCEncryptionType, bool *pMFPEnabled, + uint8_t *pMFPRequired, uint8_t *pMFPCapable, + tSirBssDescription *pSirBssDesc, tDot11fBeaconIEs *pIes, + eCsrAuthType *negotiatedAuthtype, + eCsrEncryptionType *negotiatedUCCipher, + eCsrEncryptionType *negotiatedMCCipher); +bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2); +bool csr_is_bss_type_ibss(eCsrRoamBssType bssType); +bool csr_is_bssid_match(struct qdf_mac_addr *pProfBssid, + struct qdf_mac_addr *BssBssid); +void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap); +bool csr_check_rate_bitmap(uint8_t rate, uint16_t RateBitmap); +bool csr_rates_is_dot11_rate_supported(tpAniSirGlobal mac_ctx, uint8_t rate); +uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates, + tSirMacRateSet *pExtRates, tSirMacPropRateSet *pPropRates); +tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype); +/* Caller allocates memory for pIEStruct */ +QDF_STATUS csr_parse_bss_description_ies(tpAniSirGlobal mac_ctx, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIEStruct); +/* + * 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(tpAniSirGlobal mac_ctx, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIEStruct); + +tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId); +uint8_t csr_to_upper(uint8_t ch); +QDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBSSDescription, + eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes); +/* + * fForce -- force reassoc regardless of whether there is any change. + * The reason is that for UAPSD-bypass, the code underneath this call determine + * whether to allow UAPSD. The information in pModProfileFields reflects what + * the user wants. There may be discrepency in it. UAPSD-bypass logic should + * decide if it needs to reassoc + */ +QDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields *pModProfileFields, + uint32_t *pRoamId, bool fForce); + +/* BeaconInterval validation for MCC support */ +QDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal pMac, uint8_t channelId, + uint16_t *beaconInterval, uint32_t cursessionId, + enum QDF_OPMODE currBssPersona); +bool csr_is_profile11r(tpAniSirGlobal mac, struct csr_roam_profile *pProfile); +bool csr_is_auth_type11r(tpAniSirGlobal mac, eCsrAuthType AuthType, + uint8_t mdiePresent); +#ifdef FEATURE_WLAN_ESE +bool csr_is_profile_ese(struct csr_roam_profile *pProfile); +#endif + +/** + * 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(eCsrAuthType AuthType); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/nan_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/nan_api.h new file mode 100644 index 0000000000000000000000000000000000000000..eb63cb2b5073ff3142009eec89b34e5b52400292 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/nan_api.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +/** + * + * Name: nan_api.h + * + * Description: NAN FSM defines. + * + */ + +#ifndef __NAN_API_H__ +#define __NAN_API_H__ + +#include "qdf_types.h" +#include "sir_types.h" + +typedef void (*nan_callback)(hdd_handle_t hdd_handle, tSirNanEvent *event); + +#ifdef WLAN_FEATURE_NAN +typedef struct sNanRequestReq { + uint16_t request_data_len; + const uint8_t *request_data; +} tNanRequestReq, *tpNanRequestReq; + +void sme_nan_register_callback(tHalHandle hHal, nan_callback callback); +void sme_nan_deregister_callback(tHalHandle hHal); +QDF_STATUS sme_nan_request(tpNanRequestReq input); +#else +static inline void sme_nan_register_callback(tHalHandle hHal, + nan_callback callback) +{ +} +static inline void sme_nan_deregister_callback(tHalHandle hHal) +{ +} +#endif /* WLAN_FEATURE_NAN */ + +#endif /* __NAN_API_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_api.h new file mode 100644 index 0000000000000000000000000000000000000000..5147a9778e2a572ccbca3914af2ab80a4d5068db --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_api.h @@ -0,0 +1,2595 @@ +/* + * 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. + */ + +#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 "sme_rrm_internal.h" +#include "sir_types.h" +#include "scheduler_api.h" +#include "wlan_serialization_legacy_api.h" +#include "wmi_unified.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +#define SME_SUMMARY_STATS (1 << eCsrSummaryStats) +#define SME_GLOBAL_CLASSA_STATS (1 << eCsrGlobalClassAStats) +#define SME_GLOBAL_CLASSD_STATS (1 << eCsrGlobalClassDStats) +#define SME_PER_CHAIN_RSSI_STATS (1 << csr_per_chain_rssi_stats) + +#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_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() sme_debug("enter") +#define SME_EXIT() sme_debug("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 SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE (30*1000) +#define SME_CMD_TIMEOUT_VALUE (SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE + 1000) + +/* SME timeout for Start/Stop BSS commands is set to 10 secs */ +#define SME_START_STOP_BSS_CMD_TIMEOUT (10 * 1000) +#define SME_CMD_START_STOP_BSS_TIMEOUT (SME_START_STOP_BSS_CMD_TIMEOUT + 1000) + +/* SME timeout for vdev delete is set to 10 secs */ +#define SME_VDEV_DELETE_CMD_TIMEOUT (10 * 1000) +#define SME_CMD_VDEV_CREATE_DELETE_TIMEOUT (SME_VDEV_DELETE_CMD_TIMEOUT + 5000) + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef struct _smeConfigParams { + tCsrConfigParam csrConfig; + struct rrm_config_param rrmConfig; + bool snr_monitor_enabled; +} tSmeConfigParams, *tpSmeConfigParams; + +#ifdef FEATURE_WLAN_TDLS +#define SME_TDLS_MAX_SUPP_CHANNELS 128 +#define SME_TDLS_MAX_SUPP_OPER_CLASSES 32 + +typedef struct _smeTdlsPeerCapParams { + uint8_t isPeerResponder; + uint8_t peerUapsdQueue; + uint8_t peerMaxSp; + uint8_t peerBuffStaSupport; + uint8_t peerOffChanSupport; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t peerChanLen; + uint8_t peerChan[SME_TDLS_MAX_SUPP_CHANNELS]; + uint8_t peerOperClassLen; + uint8_t peerOperClass[SME_TDLS_MAX_SUPP_OPER_CLASSES]; + uint8_t prefOffChanNum; + uint8_t prefOffChanBandwidth; + uint8_t opClassForPrefOffChan; +} tSmeTdlsPeerCapParams; + +/** + * eSmeTdlsPeerState - tdls peer state + * @eSME_TDLS_PEER_STATE_PEERING: tdls connection in progress + * @eSME_TDLS_PEER_STATE_CONNECTED: tdls peer is connected + * @eSME_TDLS_PEER_STATE_TEARDOWN: tdls peer is tear down + * @eSME_TDLS_PEER_ADD_MAC_ADDR: add peer mac into connection table + * @eSME_TDLS_PEER_REMOVE_MAC_ADDR: remove peer mac from connection table + */ +typedef enum { + eSME_TDLS_PEER_STATE_PEERING, + eSME_TDLS_PEER_STATE_CONNECTED, + eSME_TDLS_PEER_STATE_TEARDOWN, + eSME_TDLS_PEER_ADD_MAC_ADDR, + eSME_TDLS_PEER_REMOVE_MAC_ADDR, +} eSmeTdlsPeerState; + +typedef struct _smeTdlsPeerStateParams { + uint32_t vdevId; + tSirMacAddr peerMacAddr; + uint32_t peerState; + tSmeTdlsPeerCapParams peerCap; +} tSmeTdlsPeerStateParams; + +#define ENABLE_CHANSWITCH 1 +#define DISABLE_CHANSWITCH 2 +#define BW_20_OFFSET_BIT 0 +#define BW_40_OFFSET_BIT 1 +#define BW_80_OFFSET_BIT 2 +#define BW_160_OFFSET_BIT 3 +typedef struct sme_tdls_chan_switch_param_struct { + uint32_t vdev_id; + tSirMacAddr peer_mac_addr; + uint16_t tdls_off_ch_bw_offset;/* Target Off Channel Bandwidth offset */ + uint8_t tdls_off_channel; /* Target Off Channel */ + uint8_t tdls_off_ch_mode; /* TDLS Off Channel Mode */ + uint8_t is_responder; /* is peer responder or initiator */ + uint8_t opclass; /* tdls operating class */ +} sme_tdls_chan_switch_params; +#endif /* FEATURE_WLAN_TDLS */ + +/* Thermal Mitigation*/ +typedef struct { + uint16_t smeMinTempThreshold; + uint16_t smeMaxTempThreshold; +} tSmeThermalLevelInfo; + +#define SME_MAX_THERMAL_LEVELS (4) +#define SME_MAX_THROTTLE_LEVELS (4) + +typedef struct { + /* Array of thermal levels */ + tSmeThermalLevelInfo smeThermalLevels[SME_MAX_THERMAL_LEVELS]; + uint8_t smeThermalMgmtEnabled; + uint32_t smeThrottlePeriod; + uint8_t sme_throttle_duty_cycle_tbl[SME_MAX_THROTTLE_LEVELS]; +} tSmeThermalParams; + +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; +}; + +/** + * struct sme_session_params: Session creation params passed by HDD layer + * @session_open_cb: callback to be registered with SME for opening the session + * @session_close_cb: callback to be registered with SME for closing the session + * @callback: callback to be invoked for roaming events + * @callback_ctx: user-supplied context to be passed back on roaming events + * @self_mac_addr: Self mac address + * @sme_session_id: SME session id + * @type_of_persona: person type + * @subtype_of_persona: sub type of persona + */ +struct sme_session_params { + csr_session_open_cb session_open_cb; + csr_session_close_cb session_close_cb; + csr_roam_complete_cb callback; + void *callback_ctx; + uint8_t *self_mac_addr; + uint8_t sme_session_id; + uint32_t type_of_persona; + uint32_t subtype_of_persona; +}; + +#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 documenation + ------------------------------------------------------------------------*/ +QDF_STATUS sme_open(tHalHandle hHal); +QDF_STATUS sme_init_chan_list(tHalHandle hal, uint8_t *alpha2, + enum country_src cc_src); +QDF_STATUS sme_close(tHalHandle hHal); +QDF_STATUS sme_start(tHalHandle hHal); + +/** + * 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_open_session() - Open a session for given persona + * + * This is a synchronous API. For any protocol stack related activity + * requires session to be opened. This API needs to be called to open + * the session in SME module. + * + * hal: The handle returned by mac_open. + * params: to initialize the session open params + * + * Return: + * QDF_STATUS_SUCCESS - session is opened. + * Other status means SME is failed to open the session. + */ +QDF_STATUS sme_open_session(tHalHandle hal, struct sme_session_params *params); + +/* + * sme_close_session() - Close a session for given persona + * + * This is a synchronous API. This API needs to be called to close the session + * in SME module before terminating the session completely. + * + * hal: The handle returned by mac_open. + * session_id: A previous opened session's ID. + * + * Return: + * QDF_STATUS_SUCCESS - session is closed. + * Other status means SME is failed to open the session. + */ +QDF_STATUS sme_close_session(tHalHandle hal, uint8_t sessionId); +void sme_set_curr_device_mode(tHalHandle hHal, + enum QDF_OPMODE currDeviceMode); +QDF_STATUS sme_update_roam_params(tHalHandle hHal, uint8_t session_id, + struct roam_ext_params *roam_params_src, int update_param); +QDF_STATUS sme_update_config(tHalHandle hHal, + tpSmeConfigParams pSmeConfigParams); + +QDF_STATUS sme_set11dinfo(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams); +QDF_STATUS sme_get_soft_ap_domain(tHalHandle hHal, + v_REGDOMAIN_t *domainIdSoftAp); +QDF_STATUS sme_hdd_ready_ind(tHalHandle hHal); +/** + * 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_purge_pdev_all_ser_cmd_list_sync() - purge all scan and non-scan + * active and pending cmds for pdev + * @mac_handle: pointer to global MAC context + * @cb: callback to hdd + * + * Return : QDF_STATUS + */ +QDF_STATUS sme_purge_pdev_all_ser_cmd_list_sync(mac_handle_t mac_handle, + sir_purge_pdev_cmd_cb cb); + +/* + * 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(tpAniSirGlobal pMac, struct scheduler_msg *pMsg); + +QDF_STATUS sme_mc_process_handler(struct scheduler_msg *msg); +QDF_STATUS sme_scan_get_result(tHalHandle hHal, uint8_t sessionId, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult); +QDF_STATUS sme_get_ap_channel_from_scan_cache( + struct csr_roam_profile *profile, + tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id); +QDF_STATUS sme_get_ap_channel_from_scan(void *profile, + tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id); +bool sme_store_joinreq_param(tHalHandle hal_handle, + struct csr_roam_profile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id); +bool sme_clear_joinreq_param(tHalHandle hal_handle, + uint32_t session_id); +QDF_STATUS sme_issue_stored_joinreq(tHalHandle hal_handle, + uint32_t *roam_id, + uint32_t session_id); +QDF_STATUS sme_scan_flush_result(tHalHandle hHal); +QDF_STATUS sme_filter_scan_results(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_scan_flush_p2p_result(tHalHandle hHal, uint8_t sessionId); +tCsrScanResultInfo *sme_scan_result_get_first(tHalHandle, + tScanResultHandle hScanResult); +tCsrScanResultInfo *sme_scan_result_get_next(tHalHandle, + tScanResultHandle hScanResult); +QDF_STATUS sme_scan_result_purge(tScanResultHandle hScanResult); +QDF_STATUS sme_roam_connect(tHalHandle hHal, uint8_t sessionId, + struct csr_roam_profile *pProfile, uint32_t *pRoamId); +QDF_STATUS sme_roam_reassoc(tHalHandle hHal, uint8_t sessionId, + struct csr_roam_profile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId, bool fForce); +QDF_STATUS sme_roam_connect_to_last_profile(tHalHandle hHal, uint8_t sessionId); + +/** + * sme_roam_disconnect() - API to request CSR to disconnect + * @hal: HAL context + * @session: SME session identifier + * @reason: Reason to disconnect + * + * Return: QDF Status success or failure + */ +QDF_STATUS sme_roam_disconnect(tHalHandle hal, uint8_t session, + eCsrRoamDisconnectReason reason); + +void sme_dhcp_done_ind(tHalHandle hal, uint8_t session_id); +QDF_STATUS sme_roam_stop_bss(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_roam_get_associated_stas(tHalHandle hHal, uint8_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); +QDF_STATUS sme_roam_disconnect_sta(tHalHandle hHal, uint8_t sessionId, + struct csr_del_sta_params *p_del_sta_params); +QDF_STATUS sme_roam_deauth_sta(tHalHandle hHal, uint8_t sessionId, + struct csr_del_sta_params *pDelStaParams); +QDF_STATUS sme_roam_get_connect_state(tHalHandle hHal, uint8_t sessionId, + eCsrConnectState *pState); +QDF_STATUS sme_roam_get_connect_profile(tHalHandle hHal, uint8_t sessionId, + tCsrRoamConnectedProfile *pProfile); +void sme_roam_free_connect_profile(tCsrRoamConnectedProfile *profile); +QDF_STATUS sme_roam_set_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, + bool update_entire_cache); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_get_pmk_info(): A wrapper function to request CSR to save PMK + * @hal: Global structure + * @session_id: SME session_id + * @pmk_cache: pointer to a structure of pmk + * + * Return: none + */ +void sme_get_pmk_info(tHalHandle hal, uint8_t session_id, + tPmkidCacheInfo *pmk_cache); + +QDF_STATUS sme_roam_set_psk_pmk(tHalHandle hHal, uint8_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len); +#endif + +/** + * sme_roam_get_wpa_rsn_req_ie() - Retrieve WPA/RSN Request IE + * @hal: HAL handle + * @session_id: ID of the specific session + * @len: Caller allocated memory that has the length of @buf as input. + * Upon returned, @len has the length of the IE store in @buf + * @buf: Caller allocated memory that contain the IE field, if any, + * upon return + * + * A wrapper function to request CSR to return the WPA or RSN IE CSR + * passes to PE to JOIN request or START_BSS request + * This is a synchronous call. + * + * Return: QDF_STATUS - when fail, it usually means the buffer allocated is not + * big enough + */ +QDF_STATUS sme_roam_get_wpa_rsn_req_ie(tHalHandle hal, uint8_t session_id, + uint32_t *len, uint8_t *buf); + +/** + * sme_roam_get_wpa_rsn_rsp_ie() - Retrieve WPA/RSN Response IE + * @hal: HAL handle + * @session_id: ID of the specific session + * @len: Caller allocated memory that has the length of @buf as input. + * Upon returned, @len has the length of the IE store in @buf + * @buf: Caller allocated memory that contain the IE field, if any, + * upon return + * + * A wrapper function to request CSR to return the WPA or RSN IE CSR + * passes to PE to JOIN request or START_BSS request + * This is a synchronous call. + * + * Return: QDF_STATUS - when fail, it usually means the buffer allocated is not + * big enough + */ +QDF_STATUS sme_roam_get_wpa_rsn_rsp_ie(tHalHandle hal, uint8_t session_id, + uint32_t *len, uint8_t *buf); + +uint32_t sme_roam_get_num_pmkid_cache(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_roam_get_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + uint32_t *pNum, + tPmkidCacheInfo *pPmkidCache); +QDF_STATUS sme_get_config_param(tHalHandle hHal, tSmeConfigParams *pParam); +#ifndef QCA_SUPPORT_CP_STATS +QDF_STATUS sme_get_statistics(tHalHandle hHal, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint8_t staId, void *pContext, uint8_t sessionId); +#endif +QDF_STATUS sme_get_rssi(tHalHandle hHal, + tCsrRssiCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, int8_t lastRSSI, + void *pContext); +QDF_STATUS sme_get_snr(tHalHandle hHal, + tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext); +#ifdef FEATURE_WLAN_ESE +QDF_STATUS sme_get_tsm_stats(tHalHandle hHal, + tCsrTsmStatsCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, + void *pContext, uint8_t tid); +QDF_STATUS sme_set_cckm_ie(tHalHandle hHal, + uint8_t sessionId, + uint8_t *pCckmIe, uint8_t cckmIeLen); +QDF_STATUS sme_set_ese_beacon_request(tHalHandle hHal, const uint8_t sessionId, + const tCsrEseBeaconReq *pEseBcnReq); +QDF_STATUS sme_set_plm_request(tHalHandle hHal, tpSirPlmReq pPlm); +#endif /*FEATURE_WLAN_ESE */ +QDF_STATUS sme_cfg_set_int(tHalHandle hal, uint16_t cfg_id, uint32_t value); +QDF_STATUS sme_cfg_set_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t length); +QDF_STATUS sme_cfg_get_int(tHalHandle hal, uint16_t cfg_id, + uint32_t *cfg_value); +QDF_STATUS sme_cfg_get_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t *length); +QDF_STATUS sme_get_modify_profile_fields(tHalHandle hHal, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields); + +extern QDF_STATUS sme_set_host_power_save(tHalHandle hHal, bool psMode); + +void sme_set_dhcp_till_power_active_flag(tHalHandle hHal, uint8_t flag); + +#ifdef FEATURE_OEM_DATA_SUPPORT +extern QDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle h_hal, + sme_send_oem_data_rsp_msg callback); +void sme_deregister_oem_data_rsp_callback(tHalHandle h_hal); + +#else +static inline QDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle hal, + void *callback) +{ + return QDF_STATUS_SUCCESS; +} +static inline void sme_deregister_oem_data_rsp_callback(tHalHandle h_hal) +{ +} + +#endif + +QDF_STATUS sme_roam_set_key(tHalHandle, uint8_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t *pRoamId); +QDF_STATUS sme_get_country_code(tHalHandle hHal, uint8_t *pBuf, uint8_t *pbLen); + + +/* some support functions */ +bool sme_is11d_supported(tHalHandle hHal); +bool sme_is11h_supported(tHalHandle hHal); +bool sme_is_wmm_supported(tHalHandle hHal); + +QDF_STATUS sme_generic_change_country_code(tHalHandle hHal, + uint8_t *pCountry); + +/** + * 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 mlme_nss_chains *vdev_ini_cfg); + +/** + * 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 mlme_nss_chains *user_cfg, + uint8_t vdev_id); + +/** + * sme_update_channel_list() - Update configured channel list to fwr + * This is a synchronous API. + * @hal: HAL handle returned by mac_open. + * + * Return: QDF_STATUS SUCCESS. + * FAILURE or RESOURCES The API finished and failed. + */ +QDF_STATUS sme_update_channel_list(tHalHandle hal); + +QDF_STATUS sme_tx_fail_monitor_start_stop_ind(tHalHandle hHal, + uint8_t tx_fail_count, + void *txFailIndCallback); +QDF_STATUS sme_dhcp_start_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +QDF_STATUS sme_dhcp_stop_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +void sme_get_recovery_stats(tHalHandle hHal); +QDF_STATUS sme_neighbor_report_request(tHalHandle hHal, uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); +QDF_STATUS sme_get_wcnss_wlan_compiled_version(tHalHandle hHal, + tSirVersionType * pVersion); +QDF_STATUS sme_get_wcnss_wlan_reported_version(tHalHandle hHal, + tSirVersionType *pVersion); +QDF_STATUS sme_get_wcnss_software_version(tHalHandle hHal, + uint8_t *pVersion, uint32_t versionBufferSize); +QDF_STATUS sme_get_wcnss_hardware_version(tHalHandle hHal, + uint8_t *pVersion, uint32_t versionBufferSize); +#ifdef FEATURE_OEM_DATA_SUPPORT +QDF_STATUS sme_oem_data_req(tHalHandle hHal, struct oem_data_req *); +QDF_STATUS sme_oem_update_capability(tHalHandle hHal, + struct sme_oem_capability *cap); +QDF_STATUS sme_oem_get_capability(tHalHandle hHal, + 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(tHalHandle hHal, uint8_t sessionId, + tpSirHostOffloadReq pRequest); +QDF_STATUS sme_set_keep_alive(tHalHandle hHal, uint8_t sessionId, + tpSirKeepAliveReq pRequest); +QDF_STATUS sme_get_operation_channel(tHalHandle hHal, uint32_t *pChannel, + uint8_t sessionId); +QDF_STATUS sme_register_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +QDF_STATUS sme_deregister_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +QDF_STATUS sme_ConfigureAppsCpuWakeupState(tHalHandle hHal, bool isAppsAwake); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +QDF_STATUS sme_configure_ext_wow(tHalHandle hHal, + tpSirExtWoWParams wlanExtParams, + csr_readyToSuspendCallback callback, + void *callbackContext); +QDF_STATUS sme_configure_app_type1_params(tHalHandle hHal, + tpSirAppType1Params wlanAppType1Params); +QDF_STATUS sme_configure_app_type2_params(tHalHandle hHal, + tpSirAppType2Params wlanAppType2Params); +#endif +int8_t sme_get_infra_session_id(tHalHandle hHal); +uint8_t sme_get_infra_operation_channel(tHalHandle hHal, uint8_t sessionId); +uint8_t sme_get_concurrent_operation_channel(tHalHandle hHal); +/** + * sme_get_beaconing_concurrent_operation_channel() - To get concurrent + * operating channel of beaconing interface + * @hal: Pointer to hal 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 reqested mode is active it will return 0 + * + * Return: uint8_t + */ +uint8_t sme_get_beaconing_concurrent_operation_channel(tHalHandle hal, + uint8_t vdev_id_to_skip); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t sme_check_concurrent_channel_overlap(tHalHandle hHal, uint16_t sap_ch, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode); +#endif +QDF_STATUS sme_get_cfg_valid_channels(uint8_t *aValidChannels, + uint32_t *len); +#ifdef WLAN_FEATURE_PACKET_FILTERING +QDF_STATUS sme_8023_multicast_list(tHalHandle hHal, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs); +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel); +QDF_STATUS sme_set_freq_band(tHalHandle hHal, uint8_t sessionId, + enum band_info eBand); +QDF_STATUS sme_get_freq_band(tHalHandle hHal, enum band_info *pBand); +uint16_t sme_chn_to_freq(uint8_t chanNum); +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel); +QDF_STATUS sme_set_max_tx_power(tHalHandle hHal, 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(tHalHandle hHal, 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(tHalHandle hHal, uint8_t sessionId, + uint8_t ssidHidden); +QDF_STATUS sme_set_tm_level(tHalHandle hHal, uint16_t newTMLevel, + uint16_t tmMode); +void sme_feature_caps_exchange(tHalHandle hHal); +void sme_disable_feature_capablity(uint8_t feature_index); +void sme_reset_power_values_for5_g(tHalHandle hHal); +QDF_STATUS sme_update_roam_prefer5_g_hz(tHalHandle hHal, bool nRoamPrefer5GHz); +QDF_STATUS sme_set_roam_intra_band(tHalHandle hHal, const bool nRoamIntraBand); +QDF_STATUS sme_update_roam_scan_n_probes(tHalHandle hHal, uint8_t sessionId, + const uint8_t nProbes); +QDF_STATUS sme_update_roam_scan_home_away_time(tHalHandle hHal, + uint8_t sessionId, + const uint16_t nRoamScanHomeAwayTime, + const bool bSendOffloadCmd); + +bool sme_get_roam_intra_band(tHalHandle hHal); +uint8_t sme_get_roam_scan_n_probes(tHalHandle hHal); +uint16_t sme_get_roam_scan_home_away_time(tHalHandle hHal); +QDF_STATUS sme_update_roam_rssi_diff(tHalHandle hHal, uint8_t sessionId, + uint8_t RoamRssiDiff); +QDF_STATUS sme_update_fast_transition_enabled(tHalHandle hHal, + bool isFastTransitionEnabled); +QDF_STATUS sme_update_wes_mode(tHalHandle hHal, bool isWESModeEnabled, + uint8_t sessionId); +QDF_STATUS sme_set_roam_scan_control(tHalHandle hHal, uint8_t sessionId, + bool roamScanControl); + +QDF_STATUS sme_update_is_fast_roam_ini_feature_enabled(tHalHandle hHal, + uint8_t sessionId, + const bool + isFastRoamIniFeatureEnabled); + +QDF_STATUS sme_config_fast_roaming(tHalHandle hal, uint8_t session_id, + const bool is_fast_roam_enabled); + +QDF_STATUS sme_update_is_mawc_ini_feature_enabled(tHalHandle hHal, + const bool MAWCEnabled); +QDF_STATUS sme_stop_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason); + +QDF_STATUS sme_start_roaming(tHalHandle hHal, uint8_t sessionId, + uint8_t reason); +QDF_STATUS sme_update_enable_fast_roam_in_concurrency(tHalHandle hHal, + bool bFastRoamInConIniFeatureEnabled); +#ifdef FEATURE_WLAN_ESE +QDF_STATUS sme_update_is_ese_feature_enabled(tHalHandle hHal, uint8_t sessionId, + const bool isEseIniFeatureEnabled); +#endif /* FEATURE_WLAN_ESE */ +QDF_STATUS sme_set_roam_rescan_rssi_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff); +uint8_t sme_get_roam_rescan_rssi_diff(tHalHandle hHal); + +QDF_STATUS sme_set_roam_opportunistic_scan_threshold_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nOpportunisticThresholdDiff); +uint8_t sme_get_roam_opportunistic_scan_threshold_diff(tHalHandle hHal); +QDF_STATUS sme_set_neighbor_lookup_rssi_threshold(tHalHandle hHal, + uint8_t sessionId, uint8_t neighborLookupRssiThreshold); +QDF_STATUS sme_set_delay_before_vdev_stop(tHalHandle hHal, + uint8_t sessionId, uint8_t delay_before_vdev_stop); +uint8_t sme_get_neighbor_lookup_rssi_threshold(tHalHandle hHal); +QDF_STATUS sme_set_neighbor_scan_refresh_period(tHalHandle hHal, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod); +uint16_t sme_get_neighbor_scan_refresh_period(tHalHandle hHal); +uint16_t sme_get_empty_scan_refresh_period(tHalHandle hHal); +QDF_STATUS sme_update_empty_scan_refresh_period(tHalHandle hHal, + uint8_t sessionId, uint16_t nEmptyScanRefreshPeriod); +QDF_STATUS sme_set_neighbor_scan_min_chan_time(tHalHandle hHal, + const uint16_t nNeighborScanMinChanTime, + uint8_t sessionId); +QDF_STATUS sme_set_neighbor_scan_max_chan_time(tHalHandle hHal, + uint8_t sessionId, const uint16_t nNeighborScanMaxChanTime); +uint16_t sme_get_neighbor_scan_min_chan_time(tHalHandle hHal, + uint8_t sessionId); +uint32_t sme_get_neighbor_roam_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_current_roam_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_current_roam_sub_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_sme_state(tHalHandle hHal); +uint32_t sme_get_lim_mlm_state(tHalHandle hHal); +bool sme_is_lim_session_valid(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_sme_session_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_mlm_session_state(tHalHandle hHal, uint8_t sessionId); +uint16_t sme_get_neighbor_scan_max_chan_time(tHalHandle hHal, + uint8_t sessionId); +QDF_STATUS sme_set_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId, + const uint16_t nNeighborScanPeriod); +uint16_t sme_get_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_set_neighbor_scan_min_period(tHalHandle h_hal, + uint8_t session_id, const uint16_t neighbor_scan_min_period); +QDF_STATUS sme_set_roam_bmiss_first_bcnt(tHalHandle hHal, + uint8_t sessionId, const uint8_t nRoamBmissFirstBcnt); +uint8_t sme_get_roam_bmiss_first_bcnt(tHalHandle hHal); +QDF_STATUS sme_set_roam_bmiss_final_bcnt(tHalHandle hHal, uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt); +uint8_t sme_get_roam_bmiss_final_bcnt(tHalHandle hHal); +QDF_STATUS sme_set_roam_beacon_rssi_weight(tHalHandle hHal, uint8_t sessionId, + const uint8_t nRoamBeaconRssiWeight); +uint8_t sme_get_roam_beacon_rssi_weight(tHalHandle hHal); +uint8_t sme_get_roam_rssi_diff(tHalHandle hHal); +QDF_STATUS sme_change_roam_scan_channel_list(tHalHandle hHal, uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels); +QDF_STATUS sme_set_ese_roam_scan_channel_list(tHalHandle hHal, + uint8_t sessionId, uint8_t *pChannelList, + uint8_t numChannels); +QDF_STATUS sme_get_roam_scan_channel_list(tHalHandle hHal, + uint8_t *pChannelList, uint8_t *pNumChannels, + uint8_t sessionId); +bool sme_get_is_ese_feature_enabled(tHalHandle hHal); +bool sme_get_wes_mode(tHalHandle hHal); +bool sme_get_roam_scan_control(tHalHandle hHal); +bool sme_get_is_lfr_feature_enabled(tHalHandle hHal); +bool sme_get_is_ft_feature_enabled(tHalHandle hHal); +QDF_STATUS sme_update_roam_scan_offload_enabled(tHalHandle hHal, + bool nRoamScanOffloadEnabled); +bool sme_is_feature_supported_by_fw(enum cap_bitmap feature); + +/* + * SME API to enable/disable WLAN driver initiated SSR + */ +void sme_update_enable_ssr(tHalHandle hHal, bool enableSSR); +QDF_STATUS sme_set_phy_mode(tHalHandle hHal, eCsrPhyMode phyMode); +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal); +QDF_STATUS sme_handoff_request(tHalHandle hHal, uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo); +QDF_STATUS sme_is_sta_p2p_client_connected(tHalHandle hHal); +QDF_STATUS sme_add_periodic_tx_ptrn(tHalHandle hHal, tSirAddPeriodicTxPtrn + *addPeriodicTxPtrnParams); +QDF_STATUS sme_del_periodic_tx_ptrn(tHalHandle hHal, tSirDelPeriodicTxPtrn + *delPeriodicTxPtrnParams); +QDF_STATUS sme_send_rate_update_ind(tHalHandle hHal, + tSirRateUpdateInd *rateUpdateParams); +QDF_STATUS sme_roam_del_pmkid_from_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pmksa, bool flush_cache); +void sme_get_command_q_status(tHalHandle hHal); + +QDF_STATUS sme_enable_rmc(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_disable_rmc(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_send_rmc_action_period(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_request_ibss_peer_info(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, bool allPeerInfoReqd, uint8_t staIdx); +QDF_STATUS sme_send_cesium_enable_ind(tHalHandle hHal, uint32_t sessionId); + +/** + * sme_set_wlm_latency_level_ind() - Used to set the latency level to fw + * @hal + * @session_id + * @latency_level + * + * Return QDF_STATUS + */ +QDF_STATUS sme_set_wlm_latency_level(tHalHandle hal, + uint16_t session_id, + uint16_t latency_level); +/* + * 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(tHalHandle hHal, uint32_t value); + +/*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(tHalHandle hHal, uint8_t sessionId, uint16_t htCapab, + int value); +int16_t sme_get_ht_config(tHalHandle hHal, uint8_t session_id, + uint16_t ht_capab); +#ifdef QCA_HT_2040_COEX +QDF_STATUS sme_notify_ht2040_mode(tHalHandle hHal, uint16_t staId, + struct qdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type); +QDF_STATUS sme_set_ht2040_mode(tHalHandle hHal, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled); +#endif +QDF_STATUS sme_get_reg_info(tHalHandle hHal, uint8_t chanId, + uint32_t *regInfo1, uint32_t *regInfo2); +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS sme_update_fw_tdls_state(tHalHandle hHal, void *psmeTdlsParams, + bool useSmeLock); +#endif /* FEATURE_WLAN_TDLS */ + +#ifdef FEATURE_WLAN_CH_AVOID +QDF_STATUS sme_ch_avoid_update_req(tHalHandle hal_handle); +#else +static inline +QDF_STATUS sme_ch_avoid_update_req(tHalHandle hal_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +QDF_STATUS sme_set_auto_shutdown_cb(tHalHandle hHal, void (*pCallbackfn)(void)); +QDF_STATUS sme_set_auto_shutdown_timer(tHalHandle hHal, uint32_t timer_value); +#endif +QDF_STATUS sme_roam_channel_change_req(tHalHandle hHal, + struct qdf_mac_addr bssid, + struct ch_params *ch_params, + struct csr_roam_profile *profile); + +QDF_STATUS sme_roam_start_beacon_req(tHalHandle hHal, + struct qdf_mac_addr bssid, uint8_t dfsCacWaitStatus); +QDF_STATUS sme_roam_csa_ie_request(tHalHandle hHal, struct qdf_mac_addr bssid, + uint8_t targetChannel, uint8_t csaIeReqd, + struct ch_params *ch_params); + +/** + * sme_set_addba_accept() - Allow/Reject the ADDBA req session + * @hal: 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(tHalHandle hal, uint8_t session_id, int value); + +QDF_STATUS sme_init_thermal_info(tHalHandle hHal, + tSmeThermalParams thermalParam); + +QDF_STATUS sme_set_thermal_level(tHalHandle hHal, uint8_t level); +QDF_STATUS sme_txpower_limit(tHalHandle hHal, tSirTxPowerLimit *psmetx); +QDF_STATUS sme_get_link_speed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, + void *plsContext, + void (*pCallbackfn)(tSirLinkSpeedInfo *indParam, + void *pContext)); +QDF_STATUS sme_modify_add_ie(tHalHandle hHal, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType); +QDF_STATUS sme_update_add_ie(tHalHandle hHal, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); +QDF_STATUS sme_update_connect_debug(tHalHandle hHal, uint32_t set_value); +const char *sme_bss_type_to_string(const uint8_t bss_type); +QDF_STATUS sme_ap_disable_intra_bss_fwd(tHalHandle hHal, uint8_t sessionId, + bool disablefwd); +QDF_STATUS sme_get_channel_bonding_mode5_g(tHalHandle hHal, uint32_t *mode); +QDF_STATUS sme_get_channel_bonding_mode24_g(tHalHandle hHal, uint32_t *mode); +#ifdef WLAN_FEATURE_STATS_EXT +typedef struct sStatsExtRequestReq { + uint32_t request_data_len; + uint8_t *request_data; +} tStatsExtRequestReq, *tpStatsExtRequestReq; +typedef void (*StatsExtCallback)(void *, tStatsExtEvent *); +void sme_stats_ext_register_callback(tHalHandle hHal, + StatsExtCallback callback); +/** + * sme_register_stats_ext2_callback() - Register stats ext2 register + * @hal_handle: hal handle for getting global mac struct + * @stats_ext2_cb: callback to be registered + * + * This function will register a callback for frame aggregation failure + * indications processing. + * + * Return: void + */ +void sme_stats_ext2_register_callback(tHalHandle hal_handle, + void (*stats_ext2_cb)(void *, struct sir_sme_rx_aggr_hole_ind *)); +/** + * 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); +void sme_stats_ext_deregister_callback(tHalHandle hhal); +QDF_STATUS sme_stats_ext_request(uint8_t session_id, + tpStatsExtRequestReq input); +#endif +QDF_STATUS sme_update_dfs_scan_mode(tHalHandle hHal, + uint8_t sessionId, + uint8_t allowDFSChannelRoam); +uint8_t sme_get_dfs_scan_mode(tHalHandle hHal); + +#ifdef FEATURE_WLAN_EXTSCAN +QDF_STATUS sme_get_valid_channels_by_band(tHalHandle hHal, uint8_t wifiBand, + uint32_t *aValidChannels, + uint8_t *pNumChannels); +QDF_STATUS sme_ext_scan_get_capabilities(tHalHandle hHal, + tSirGetExtScanCapabilitiesReqParams *pReq); +QDF_STATUS sme_ext_scan_start(tHalHandle hHal, + tSirWifiScanCmdReqParams *pStartCmd); +QDF_STATUS sme_ext_scan_stop(tHalHandle hHal, + tSirExtScanStopReqParams *pStopReq); + +/** + * 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); + +QDF_STATUS sme_get_cached_results(tHalHandle hHal, + tSirExtScanGetCachedResultsReqParams * + pCachedResultsReq); + +QDF_STATUS sme_set_epno_list(tHalHandle hal, + struct wifi_epno_params *req_msg); +QDF_STATUS sme_set_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *req_msg); +QDF_STATUS sme_reset_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *req_msg); + +QDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, const uint16_t, void *)); +#else +static inline QDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, const uint16_t, void *)) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_EXTSCAN */ +QDF_STATUS sme_abort_roam_scan(tHalHandle hHal, uint8_t sessionId); +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +QDF_STATUS sme_ll_stats_clear_req(tHalHandle hHal, + tSirLLStatsClearReq * pclearStatsReq); +QDF_STATUS sme_ll_stats_set_req(tHalHandle hHal, + tSirLLStatsSetReq *psetStatsReq); +QDF_STATUS sme_ll_stats_get_req(mac_handle_t mac_handle, + tSirLLStatsGetReq *get_stats_req, + void *context); +QDF_STATUS sme_set_link_layer_stats_ind_cb(mac_handle_t mac_handle, + void (*callback_routine)( + void *callback_ctx, int ind_type, + void *rsp, void *cookie)); +QDF_STATUS sme_set_link_layer_ext_cb(tHalHandle hal, + void (*ll_stats_ext_cb)(hdd_handle_t callback_ctx, + tSirLLStatsResults * rsp)); +QDF_STATUS sme_reset_link_layer_stats_ind_cb(tHalHandle hhal); +QDF_STATUS sme_ll_stats_set_thresh(tHalHandle hal, + struct sir_ll_ext_stats_threshold *threshold); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +QDF_STATUS sme_set_wisa_params(tHalHandle hal, + struct sir_wisa_params *wisa_params); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_update_roam_offload_enabled(tHalHandle hHal, + bool nRoamOffloadEnabled); +QDF_STATUS sme_update_roam_key_mgmt_offload_enabled(tHalHandle hal_ctx, + uint8_t session_id, + bool key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes); +#endif +#ifdef WLAN_FEATURE_NAN +QDF_STATUS sme_nan_event(tHalHandle hHal, void *pMsg); +#endif /* WLAN_FEATURE_NAN */ +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(tHalHandle hHal, + void *tempContext, + void (*pCallbackfn)(int temperature, + void *pContext)); +QDF_STATUS sme_set_scanning_mac_oui(tHalHandle hHal, + tSirScanMacOui *pScanMacOui); + +#ifdef DHCP_SERVER_OFFLOAD +QDF_STATUS sme_set_dhcp_srv_offload(tHalHandle hHal, + tSirDhcpSrvOffloadInfo * pDhcpSrvInfo); +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +QDF_STATUS sme_set_led_flashing(tHalHandle hHal, uint8_t type, + uint32_t x0, uint32_t x1); +#endif +QDF_STATUS sme_handle_dfs_chan_scan(tHalHandle hHal, uint8_t dfs_flag); +QDF_STATUS sme_enable_dfs_chan_scan(tHalHandle hHal, uint8_t dfs_flag); +QDF_STATUS sme_set_mas(uint32_t val); +QDF_STATUS sme_set_miracast(tHalHandle hal, uint8_t filter_type); +QDF_STATUS sme_ext_change_channel(tHalHandle hHal, uint32_t channel, + uint8_t session_id); + +QDF_STATUS sme_configure_stats_avg_factor(tHalHandle hal, uint8_t session_id, + uint16_t stats_avg_factor); + +QDF_STATUS sme_configure_guard_time(tHalHandle hal, uint8_t session_id, + uint32_t guard_time); + +QDF_STATUS sme_wifi_start_logger(tHalHandle hal, + struct sir_wifi_start_log start_log); + +bool sme_neighbor_middle_of_roaming(tHalHandle hHal, + uint8_t sessionId); + +/* + * sme_is_any_session_in_middle_of_roaming() - check if roaming is in progress + * @hal: 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 hal); + +/** + * sme_enable_uapsd_for_ac() - enable uapsd for access category request to WMA + * @sta_id: station id + * @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(uint8_t sta_id, + 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 + * @sta_id: station id + * @ac: access category + * @sessionId: session id + * + * Return: QDF status + */ +QDF_STATUS sme_disable_uapsd_for_ac(uint8_t sta_id, + sme_ac_enum_type ac, + uint32_t sessionId); + +QDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, + struct rssi_monitor_req *input); +QDF_STATUS sme_set_rssi_threshold_breached_cb(tHalHandle hal, + void (*cb)(void *, struct rssi_breach_event *)); +QDF_STATUS sme_reset_rssi_threshold_breached_cb(tHalHandle hal); + +QDF_STATUS sme_register_mgmt_frame_ind_callback(tHalHandle hal, + sir_mgmt_frame_ind_callback callback); + +QDF_STATUS sme_update_nss(tHalHandle h_hal, uint8_t nss); +void sme_update_user_configured_nss(tHalHandle hal, uint8_t nss); + +bool sme_is_any_session_in_connected_state(tHalHandle h_hal); + +QDF_STATUS sme_pdev_set_pcl(struct policy_mgr_pcl_list *msg); +QDF_STATUS sme_pdev_set_hw_mode(struct policy_mgr_hw_mode msg); +void sme_register_hw_mode_trans_cb(tHalHandle hal, + hw_mode_transition_cb callback); +QDF_STATUS sme_nss_update_request(uint32_t vdev_id, + uint8_t new_nss, 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); + +typedef void (*sme_peer_authorized_fp) (uint32_t vdev_id); +QDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + sme_peer_authorized_fp auth_fp, + 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(tHalHandle hal, + struct sir_antenna_mode_param *msg); + +void sme_set_scan_disable(tHalHandle h_hal, int value); +void sme_setdef_dot11mode(tHalHandle hal); + +QDF_STATUS sme_handle_set_fcc_channel(tHalHandle hHal, + bool fcc_constraint, + bool scan_pending); + +QDF_STATUS sme_update_roam_scan_hi_rssi_scan_params(tHalHandle hal_handle, + uint8_t session_id, + uint32_t notify_id, + int32_t val); + +/** + * sme_update_tx_bfee_supp() - sets the Tx Bfee support + * @hal: Pointer to HAL + * @session_id: SME session id + * @cfg_val: Tx Bfee config value + * + * Return: 0 on success else err code + */ +int sme_update_tx_bfee_supp(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val); + +void wlan_sap_enable_phy_error_logs(tHalHandle hal, uint32_t enable_log); +#ifdef WLAN_FEATURE_DSRC +void sme_set_dot11p_config(tHalHandle hal, bool enable_dot11p); + +int sme_ocb_gen_timing_advert_frame(tHalHandle hHal, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, + uint32_t *time_value_offset); + +static inline void +sme_set_etsi13_srd_ch_in_master_mode(tHalHandle hal, + bool etsi13_srd_chan_support) +{ +} +#else +static inline void sme_set_dot11p_config(tHalHandle hal, bool enable_dot11p) +{ + return; +} + +static inline int sme_ocb_gen_timing_advert_frame(tHalHandle hHal, + tSirMacAddr self_addr, uint8_t **buf, + uint32_t *timestamp_offset, + uint32_t *time_value_offset) +{ + return 0; +} + +/** + * sme_set_etsi13_srd_ch_in_master_mode() - master mode UNI-III band ch support + * @hal: HAL pointer + * @srd_chan_support: ETSI SRD channel support + * + * This function set master ETSI SRD channel support + * + * Return: None + */ +void sme_set_etsi13_srd_ch_in_master_mode(tHalHandle hal, + bool etsi13_srd_chan_support); +#endif + +void sme_add_set_thermal_level_callback(tHalHandle hal, + sme_set_thermal_level_callback callback); + +void sme_update_tgt_services(tHalHandle hal, struct wma_tgt_services *cfg); +bool sme_validate_sap_channel_switch(tHalHandle hal, + uint16_t sap_ch, eCsrPhyMode sap_phy_mode, + uint8_t cc_switch_mode, uint8_t session_id); + +bool sme_is_session_id_valid(tHalHandle hal, uint32_t session_id); + +#ifdef FEATURE_WLAN_TDLS +void sme_get_opclass(tHalHandle hal, uint8_t channel, uint8_t bw_offset, + uint8_t *opclass); +#else +static inline void +sme_get_opclass(tHalHandle hal, uint8_t channel, uint8_t bw_offset, + uint8_t *opclass) +{ +} +#endif + +#ifdef FEATURE_LFR_SUBNET_DETECTION +QDF_STATUS sme_gateway_param_update(tHalHandle hHal, + struct gateway_param_update_req *request); +#endif + +void sme_update_fine_time_measurement_capab(tHalHandle hal, uint8_t session_id, + uint32_t val); +QDF_STATUS sme_ht40_stop_obss_scan(tHalHandle hHal, uint32_t vdev_id); +QDF_STATUS sme_set_fw_test(struct set_fwtest_params *fw_test); +QDF_STATUS sme_set_tsfcb(tHalHandle hHal, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx); + +QDF_STATUS sme_reset_tsfcb(tHalHandle h_hal); + +#if defined(WLAN_FEATURE_TSF) && !defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) +QDF_STATUS sme_set_tsf_gpio(tHalHandle h_hal, uint32_t pinvalue); +#endif + +QDF_STATUS sme_update_mimo_power_save(tHalHandle hHal, + uint8_t is_ht_smps_enabled, + uint8_t ht_smps_mode, + bool send_smps_action); + +bool sme_is_sta_smps_allowed(tHalHandle hHal, uint8_t session_id); +QDF_STATUS sme_add_beacon_filter(tHalHandle hal, + uint32_t session_id, uint32_t *ie_map); +QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id); + +#ifdef FEATURE_WLAN_APF +/** + * sme_get_apf_capabilities() - Get APF capabilities + * @hal: Global HAL handle + * @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(tHalHandle hal, + apf_get_offload_cb callback, + void *context); + +/** + * sme_set_apf_instructions() - Set APF apf filter instructions. + * @hal: HAL handle + * @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(tHalHandle hal, + struct sir_apf_set_offload + *apf_set_offload); + +/** + * sme_set_apf_enable_disable - Send apf enable/disable cmd + * @hal: global hal handle + * @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(tHalHandle hal, uint8_t vdev_id, + bool apf_enable); + +/** + * sme_apf_write_work_memory - Write into the apf work memory + * @hal: global hal handle + * @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(tHalHandle hal, + struct wmi_apf_write_memory_params + *write_params); + +/** + * sme_apf_read_work_memory - Read part of apf work memory + * @hal: global hal handle + * @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(tHalHandle hal, + struct wmi_apf_read_memory_params *read_params, + apf_read_mem_cb callback); + +#endif /* FEATURE_WLAN_APF */ + +uint32_t sme_get_wni_dot11_mode(tHalHandle hal); +QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid); +QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, + struct adaptive_dwelltime_params *dwelltime_params); + +void sme_set_vdev_ies_per_band(tHalHandle hal, uint8_t vdev_id); +void sme_set_pdev_ht_vht_ies(tHalHandle hHal, bool enable2x2); + +void sme_update_vdev_type_nss(tHalHandle hal, uint8_t max_supp_nss, + uint32_t vdev_type_nss, enum band_info band); +void sme_update_hw_dbs_capable(tHalHandle hal, uint8_t hw_dbs_capable); +void sme_register_p2p_lo_event(tHalHandle hHal, void *context, + p2p_lo_callback callback); + +QDF_STATUS sme_remove_bssid_from_scan_list(tHalHandle hal, + tSirMacAddr bssid); + +QDF_STATUS sme_process_mac_pwr_dbg_cmd(tHalHandle hal, 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); +QDF_STATUS sme_roam_set_default_key_index(tHalHandle hal, uint8_t session_id, + uint8_t default_idx); +void sme_send_disassoc_req_frame(tHalHandle hal, uint8_t session_id, uint8_t + *peer_mac, uint16_t reason, uint8_t + wait_for_ack); +QDF_STATUS sme_update_access_policy_vendor_ie(tHalHandle hal, + 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(tHalHandle hal, + 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(tHalHandle hal, + uint8_t set_value); +QDF_STATUS sme_set_default_scan_ie(tHalHandle hal, uint16_t session_id, + uint8_t *ie_data, uint16_t ie_len); +/** + * sme_update_session_param() - API to update PE session param + * @hal: HAL handle for device + * @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(tHalHandle hal, uint8_t session_id, + uint32_t param_type, uint32_t param_val); + +/** + * sme_update_fils_setting() - API to update PE FILS setting + * @hal: HAL handle for device + * @session_id: Session ID + * @param_val: Param value to be update + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_fils_setting(tHalHandle hal, uint8_t session_id, + uint8_t param_val); +#ifdef WLAN_FEATURE_FIPS +/** + * sme_fips_request() - Perform a FIPS certification operation + * @hal: Hal handle for 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 sme_fips_request(tHalHandle hal, struct fips_params *param, + wma_fips_cb callback, void *context); +#else +static inline +QDF_STATUS sme_fips_request(tHalHandle hal, 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 parms to FW. + * @hal: reference to the HAL + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_cts2self_for_p2p_go(tHalHandle hal); +void sme_set_prefer_80MHz_over_160MHz(tHalHandle hal, + bool sta_prefer_80MHz_over_160MHz); +QDF_STATUS sme_update_tx_fail_cnt_threshold(tHalHandle hal_handle, + uint8_t session_id, uint32_t tx_fail_count); +QDF_STATUS sme_update_short_retry_limit_threshold(tHalHandle hal_handle, + struct sme_short_retry_limit *short_retry_limit_th); +QDF_STATUS sme_update_long_retry_limit_threshold(tHalHandle hal_handle, + struct sme_long_retry_limit *long_retry_limit_th); +/** + * sme_roam_is_ese_assoc() - Check if association type is ESE + * @roam_info: Pointer to roam info + * + * Return: true if ESE Association, false otherwise. + */ +#ifdef FEATURE_WLAN_ESE +bool sme_roam_is_ese_assoc(struct csr_roam_info *roam_info); +#else +static inline bool sme_roam_is_ese_assoc(struct csr_roam_info *roam_info) +{ + return false; +} +#endif +/** + * sme_neighbor_roam_is11r_assoc() - Check if association type is 11R + * @hal_ctx: HAL handle + * @session_id: session id + * + * Return: true if 11r Association, false otherwise. + */ +bool sme_neighbor_roam_is11r_assoc(tHalHandle hal_ctx, uint8_t session_id); + +/** + * sme_update_sta_inactivity_timeout(): Update sta_inactivity_timeout to FW + * @hal: 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(tHalHandle hal_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 + * @hal: HAL handle + * @session_id: session id + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. + */ +QDF_STATUS sme_update_new_channel_event(tHalHandle hal, uint8_t session_id); +#ifdef WLAN_POWER_DEBUGFS +QDF_STATUS sme_power_debug_stats_req(tHalHandle hal, 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 + * @hal: HAL handle + * @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(tHalHandle hal, + wma_sar_cb callback, void *context); + +/** + * sme_set_sar_power_limits() - set sar limits + * @hal: HAL handle + * @sar_limit_cmd: struct to send sar limit cmd. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_sar_power_limits(tHalHandle hal, + 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); + +void sme_set_cc_src(tHalHandle hal_handle, enum country_src); + + +#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(tHalHandle hal, + struct set_arp_stats_params + *set_stats_param); +QDF_STATUS sme_get_nud_debug_stats(tHalHandle hal, + struct get_arp_stats_params + *get_stats_param); +QDF_STATUS sme_set_nud_debug_stats_cb(tHalHandle hal, + void (*cb)(void *, struct rsp_stats *, void *context), + void *context); + +/** + * sme_set_chan_info_callback() - Register chan info callback + * @hal - 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(tHalHandle hal_handle, + void (*callback)(struct scan_chan_info *chan_info)); + +/** + * sme_get_rssi_snr_by_bssid() - gets the rssi and snr by bssid from scan cache + * @hal: handle returned by mac_open + * @profile: current connected profile + * @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(tHalHandle hal, + struct csr_roam_profile *profile, + const uint8_t *bssid, int8_t *rssi, + int8_t *snr); + +/** + * sme_get_beacon_frm() - gets the bss descriptor from scan cache and prepares + * beacon frame + * @hal: handle returned by mac_open + * @profile: current connected profile + * @bssid: bssid to look for in scan cache + * @frame_buf: frame buffer to populate + * @frame_len: length of constructed frame + * @channel: Pointer to channel info to be filled + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_beacon_frm(tHalHandle hal, struct csr_roam_profile *profile, + const tSirMacAddr bssid, + uint8_t **frame_buf, uint32_t *frame_len, + int *channel); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_fast_reassoc() - invokes FAST REASSOC command + * @hal: handle returned by mac_open + * @profile: current connected profile + * @bssid: bssid to look for in scan cache + * @channel: channel on which reassoc should be send + * @vdev_id: vdev id + * @connected_bssid: bssid of currently connected profile + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_fast_reassoc(tHalHandle hal, struct csr_roam_profile *profile, + const tSirMacAddr bssid, int channel, + uint8_t vdev_id, const tSirMacAddr connected_bssid); +#endif +/** + * sme_congestion_register_callback() - registers congestion callback + * @hal: handler for HAL + * @congestion_cb: congestion callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_congestion_register_callback(tHalHandle hal, + congestion_cb congestion_cb); + +/** + * sme_register_tx_queue_cb(): Register tx queue callback + * @hal: handler for HAL + * @tx_queue_cb: Transmit Queues callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_register_tx_queue_cb(tHalHandle hal, + void (*tx_queue_cb)(void *, + uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason)); + +/** + * sme_deregister_tx_queue_cb() - Deregister the tx queue callback + * @hal: HAL handle + * + * Return: QDF status + */ +QDF_STATUS sme_deregister_tx_queue_cb(tHalHandle hal); + +/** + * 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 + * @hal - 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(tHalHandle hHal, + 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 + * @hal: 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(tHalHandle hal, + struct wmi_dbs_scan_sel_params *params); + +/** + * sme_store_pdev() - store pdev + * @hal - MAC global handle + * @pdev - pdev ptr + * + * Return: QDF_STATUS + */ +void sme_store_pdev(tHalHandle hal, struct wlan_objmgr_pdev *pdev); + +/** + * sme_ipa_uc_stat_request() - set ipa config parameters + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @param_val: parameter value + * @req_cat: parameter category + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_ipa_uc_stat_request(tHalHandle hal, + uint32_t vdev_id, uint32_t param_id, + uint32_t param_val, uint32_t req_cat); + +/** + * sme_set_reorder_timeout() - set reorder timeout value + * including Voice,Video,Besteffort,Background parameters + * @hal: hal handle for getting global mac struct + * @reg: struct sir_set_rx_reorder_timeout_val + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. + */ +QDF_STATUS sme_set_reorder_timeout(tHalHandle hal, + struct sir_set_rx_reorder_timeout_val *req); + +/** + * sme_set_rx_set_blocksize() - set blocksize value + * including mac_addr and win_limit parameters + * @hal: hal handle for getting global mac struct + * @reg: struct sir_peer_set_rx_blocksize + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. + */ + +QDF_STATUS sme_set_rx_set_blocksize(tHalHandle hal, + struct sir_peer_set_rx_blocksize *req); + +/** + * sme_get_rcpi() - gets the rcpi value for peer mac addr + * @hal: 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(tHalHandle hal, 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_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_peer_stats() - sme api to post peer info request + * @mac: mac handle + * @req: peer info request struct send to wma + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ + +QDF_STATUS sme_get_peer_stats(tpAniSirGlobal mac, + struct sir_peer_info_req req); + +/** + * sme_get_peer_info() - sme api to get peer info + * @hal: hal handle for getting global mac struct + * @req: peer info request struct send to wma + * @context: context of callback function + * @callbackfn: hdd callback function when receive response + * + * This function will send WMA_GET_PEER_INFO to WMA + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_get_peer_info(tHalHandle hal, + struct sir_peer_info_req req, + void *context, + void (*callbackfn)(struct sir_peer_info_resp *param, + void *pcontext)); + +/** + * sme_get_peer_info_ext() - sme api to get peer ext info + * @hal: hal handle for getting global mac struct + * @req: peer ext info request struct send to wma + * @context: context of callback function + * @callbackfn: hdd callback function when receive response + * + * This function will send WMA_GET_PEER_INFO_EXT to WMA + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_get_peer_info_ext(tHalHandle hal, + struct sir_peer_info_ext_req *req, + void *context, + void (*callbackfn)(struct sir_peer_info_ext_resp *param, + void *pcontext)); + +/** + * sme_set_5g_band_pref() - sme api to set 5Ghz preference + * @hal: hal handle for getting global mac struct + * @pref_params: preference info request struct + * + * This function will set 5Ghz preference for STA connection + * + * Return: None + */ +void sme_set_5g_band_pref(tHalHandle hal_handle, + struct sme_5g_band_pref_params *pref_params); +/** + * sme_get_chain_rssi() - Get chain rssi + * @hal: Global HAL handle + * @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(tHalHandle hal, + 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); + +/** + * sme_get_valid_channels() - sme api to get valid channels for + * current regulatory domain + * @chan_list: list of the valid channels + * @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 sme_get_valid_channels(uint8_t *chan_list, uint32_t *list_len); + +/** + * sme_get_mac_context() - sme api to get the pmac context + * + * This function will return the pmac context + * + * Return: pointer to pmac context + */ +tpAniSirGlobal sme_get_mac_context(void); + +/** + * sme_display_disconnect_stats() - Display per session Disconnect stats + * @hal: hal global context + * session_id: SME session id + * + * Return: None + */ +void sme_display_disconnect_stats(tHalHandle hal, uint8_t session_id); + +/** + * 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(tpAniSirGlobal 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 + * @hal: global hal handle + * @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(tHalHandle hal, uint8_t vdev_id, + bool is_tos_active, uint32_t max_off_chan_time, + uint32_t rest_time, bool skip_dfs_chan); + +/** + * 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); + +/** + * sme_set_del_pmkid_cache() - API to update PMKID cache + * @hal: HAL handle for device + * @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(tHalHandle hal, uint8_t session_id, + tPmkidCacheInfo *pmk_cache_info, + bool is_add); + +/** + * sme_send_hlp_ie_info() - API to send HLP IE info to fw + * @hal: HAL handle for device + * @session_id: Session id + * @profile: CSR Roam profile + * @if_addr: IP address + * + * This API is used to send HLP IE info along with IP address + * to fw if LFR3 is enabled. + * + * Return: QDF_STATUS + */ +void sme_send_hlp_ie_info(tHalHandle hal, uint8_t session_id, + struct csr_roam_profile *profile, uint32_t if_addr); + +#if defined(WLAN_FEATURE_FILS_SK) +/** + * sme_update_fils_config - Update FILS config to CSR roam session + * @hal: HAL handle for device + * @session_id: session id + * @src_profile: Source profile having latest FILS config + * + * API to update FILS config to roam csr session and update the same + * to fw if LFR3 is enabled. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_fils_config(tHalHandle hal, uint8_t session_id, + struct csr_roam_profile *src_profile); + +/** + * sme_free_join_rsp_fils_params - free fils params + * @roam_info: roam info + * + * Return: void + */ +void sme_free_join_rsp_fils_params(struct csr_roam_info *roam_info); +#else +static inline QDF_STATUS sme_update_fils_config(tHalHandle hal, + uint8_t session_id, + struct csr_roam_profile *src_profile) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void sme_free_join_rsp_fils_params(struct csr_roam_info *roam_info) +{} + +#endif + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +/** + * sme_set_he_bss_color() - Sets the HE BSS color + * + * @hal: 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(tHalHandle hal, uint8_t session_id, + uint8_t bss_color); +#else +static inline QDF_STATUS sme_set_he_bss_color(tHalHandle hal, + uint8_t session_id, uint8_t bss_color) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_is_conn_state_connected() -- check if SME connection state is connected + * @hal: global hal handle + * @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 hal, uint8_t session_id); + +/** + * sme_scan_get_result_for_bssid - gets the scan result from scan cache for the + * bssid specified + * @hal: handle returned by mac_open + * @bssid: bssid to get the scan result for + * @res: pointer to tCsrScanResultInfo allocated from caller + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_scan_get_result_for_bssid(tHalHandle hal_handle, + struct qdf_mac_addr *bssid, + tCsrScanResultInfo *res); + +/** + * sme_get_bss_transition_status() - get bss transition status all cadidates + * @hal: 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 : 0 on success otherwise errno + */ +int sme_get_bss_transition_status(tHalHandle hal, + 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. + * @hal: 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(tHalHandle hal, uint8_t *buf, + uint8_t buf_len, tDot11fIERSN *rsn_ie, + bool append_ie); +/** + * 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_enable_roaming_on_connected_sta() - Enable roaming on an connected sta + * @hal: handle returned by mac_open + * + * The function check if any connected STA is present on which roaming is not + * enabled and if present enabled roaming on that STA. + * + * Return: none + */ +void sme_enable_roaming_on_connected_sta(tHalHandle hal); + +/** + * sme_send_mgmt_tx() - Sends mgmt frame from CSR to LIM + * @hal: 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(tHalHandle hal, 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 + * @hal: The handle returned by mac_open + * @session_id: session id + * @sae_status: status of SAE authentication + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_handle_sae_msg(tHalHandle hal, uint8_t session_id, + uint8_t sae_status); +#else +static inline QDF_STATUS sme_handle_sae_msg(tHalHandle hal, uint8_t session_id, + uint8_t sae_status) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_set_ba_buff_size() - sets BA buffer size + * @hal: Pointer to HAL + * @session_id: SME session id + * @buff_size: BA buffer size + * + * Return: 0 on success else err code + */ +int sme_set_ba_buff_size(tHalHandle hal, uint8_t session_id, + uint16_t buff_size); + +/** + * sme_send_addba_req() - send ADDBA request with user config + * @hal: Pointer to HAL + * @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(tHalHandle hal, uint8_t session_id, uint8_t tid, + uint16_t buff_size); + +/** + * sme_set_no_ack_policy() - Sets no ack policy for AC + * @hal: Pointer to HAL + * @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(tHalHandle hal, uint8_t session_id, + uint8_t val, uint8_t ac); + +/** + * sme_set_auto_rate_he_sgi() - Sets SGI for auto rate + * @hal: Pointer to HAL + * @session_id: SME session id + * @cfg_val: SGI configuration value + * + * Return: 0 on success else err code + */ +int sme_set_auto_rate_he_sgi(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_set_auto_rate_he_ltf() - Sets HE LTF for auto rate + * @hal: Pointer to HAL + * @session_id: SME session id + * @cfg_val: LTF configuration value + * + * Return: 0 on success else err code + */ +int sme_set_auto_rate_he_ltf(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val); + +#ifdef WLAN_FEATURE_11AX +/** + * sme_update_he_cap_nss() - sets the nss based on user request + * @hal: Pointer to HAL + * @session_id: SME session id + * @nss: no.of spatial streams value + * + * Return: None + */ +void sme_update_he_cap_nss(tHalHandle hal, uint8_t session_id, + uint8_t nss); + +/** + * sme_update_he_tx_bfee_supp() - sets the HE Tx Bfee support + * @hal: Pointer to HAL + * @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(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val); +/** + * sme_update_he_mcs() - sets the HE MCS based on user request + * @hal: Pointer to HAL + * @session_id: SME session id + * @he_mcs: HE MCS value + * + * Return: 0 on success else err code + */ +int sme_update_he_mcs(tHalHandle hal, uint8_t session_id, uint16_t he_mcs); +/** + * sme_update_he_tx_stbc_cap() - Sets the HE Tx STBC capability + * @hal: Pointer to HAL + * @session_id: SME session id + * @value: set value + * + * Return: 0 on success else err code + */ +int sme_update_he_tx_stbc_cap(tHalHandle hal, uint8_t session_id, int value); + +/** + * sme_update_he_rx_stbc_cap() - Sets the HE Rx STBC capability + * @hal: Pointer to HAL + * @session_id: SME session id + * @value: set value + * + * Return: 0 on success else err code + */ +int sme_update_he_rx_stbc_cap(tHalHandle hal, uint8_t session_id, int value); + +/** + * sme_update_he_frag_supp() - sets the HE fragmentation support + * @hal: Pointer to HAL + * @session_id: SME session id + * @he_frag: HE fragmention support value + * + * Return: 0 on success else err code + */ +int sme_update_he_frag_supp(tHalHandle hal, uint8_t session_id, + uint16_t he_frag); + +/** + * sme_update_he_ldpc_supp() - sets the HE LDPC support + * @hal: Pointer to HAL + * @session_id: SME session id + * @he_ldpc: HE LDPC support value + * + * Return: 0 on success else err code + */ +int sme_update_he_ldpc_supp(tHalHandle hal, uint8_t session_id, + uint16_t he_ldpc); +#else +static inline void sme_update_he_cap_nss(tHalHandle hal, uint8_t session_id, + uint8_t nss) +{} +static inline int sme_update_he_mcs(tHalHandle hal, uint8_t session_id, + uint16_t he_mcs) +{ + return 0; +} +static inline int sme_update_he_tx_stbc_cap(tHalHandle hal, uint8_t session_id, + int value) +{ + return 0; +} + +static inline int sme_update_he_rx_stbc_cap(tHalHandle hal, uint8_t session_id, + int value) +{ + return 0; +} + +static inline int sme_update_he_frag_supp(tHalHandle hal, uint8_t session_id, + uint16_t he_frag) +{ + return 0; +} + +static inline int sme_update_he_ldpc_supp(tHalHandle hal, uint8_t session_id, + uint16_t he_ldpc) +{ + return 0; +} + +static inline int sme_update_he_tx_bfee_supp(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} +#endif + +/** + * sme_is_sta_key_exchange_in_progress() - checks whether the STA/P2P client + * session has key exchange in progress + * + * @hal: global hal handle + * @session_id: session id + * + * Return: true - if key exchange in progress + * false - if not in progress + */ +bool sme_is_sta_key_exchange_in_progress(tHalHandle hal, uint8_t session_id); + +/* + * sme_validate_channel_list() - Validate the given channel list + * @hal: handle to global hal context + * @chan_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(tHalHandle hal, + uint8_t *chan_list, + uint8_t num_channels); +/** + * sme_set_amsdu() - set amsdu enable/disable based on user cfg + * @hal: Pointer to HAL + * @enable: enable or disable + * + * Return: None + */ +void sme_set_amsdu(tHalHandle hal, bool enable); + +/** + * sme_get_mcs_idx() - gets mcs index + * @max_rate: max rate + * @rate_flags: rate flags + * @nss: number of nss + * @mcs_rate_flags: mcs rate flag + * + * Return: return mcs index + */ +uint8_t sme_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags, + uint8_t *nss, uint8_t *mcs_rate_flags); + +#ifdef WLAN_SUPPORT_TWT +/** + * sme_register_twt_enable_complete_cb() - TWT enable registrar + * @hal: HAL handle + * @twt_enable_cb: Function callback to handle enable event + * @hdd_ctx: Global HDD Context + * + * Return: QDF Status + */ +QDF_STATUS sme_register_twt_enable_complete_cb(tHalHandle hal, + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params)); + +/** + * sme_register_twt_disable_complete_cb - TWT disable registrar + * @hal: HAL handle + * @twt_disable_cb: Function callback to handle disable event + * + * Return: QDF Status + */ +QDF_STATUS sme_register_twt_disable_complete_cb(tHalHandle hal, + void (*twt_disable_cb)(void *hdd_ctx)); + +/** + * sme_deregister_twt_enable_complete_cb() - TWT enable deregistrar + * @hal: HAL handle + * + * Return: QDF Status + */ +QDF_STATUS sme_deregister_twt_enable_complete_cb(tHalHandle hal); + +/** + * sme_deregister_twt_disable_complete_cb - TWT disable deregistrar + * @hal: HAL handle + * + * Return: QDF Status + */ +QDF_STATUS sme_deregister_twt_disable_complete_cb(tHalHandle hal); + +#else +static inline QDF_STATUS sme_register_twt_enable_complete_cb(tHalHandle hal, + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_register_twt_disable_complete_cb(tHalHandle hal, + void (*twt_disable_cb)(void *hdd_ctx)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_deregister_twt_enable_complete_cb(tHalHandle hal) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_deregister_twt_disable_complete_cb(tHalHandle hal) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_get_roam_scan_stats() - Send roam scan stats cmd to wma + * @hal: 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(tHalHandle hal, roam_scan_stats_cb cb, void *context, + uint32_t vdev_id); + +/** + * 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); + +#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 +#endif /* #if !defined( __SME_API_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_ft_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_ft_api.h new file mode 100644 index 0000000000000000000000000000000000000000..f64d0391343458578f5e82ed67ba8efa69681e09 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_ft_api.h @@ -0,0 +1,109 @@ +/* + * 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. + */ + +#if !defined(__SME_FTAPI_H) +#define __SME_FTAPI_H + +typedef enum eFTIEState { + eFT_START_READY, /* Start before and after 11r assoc */ + eFT_AUTH_REQ_READY, /* When we have recvd the 1st or nth auth req */ + /* + * Sent auth1 and waiting auth2 We are now ready for FT phase, + * send auth1, recd auth2 + */ + eFT_WAIT_AUTH2, + eFT_AUTH_COMPLETE, + /* Now we have sent Auth Rsp to the supplicant and waiting */ + /* Reassoc Req from the supplicant. */ + eFT_REASSOC_REQ_WAIT, + /* + * We have received the Reassoc request from supplicant. + * Waiting for the keys. + */ + eFT_SET_KEY_WAIT, +} tFTIEStates; + +/* FT neighbor roam callback user context */ +typedef struct sFTRoamCallbackUsrCtx { + tpAniSirGlobal pMac; + uint8_t sessionId; +} tFTRoamCallbackUsrCtx, *tpFTRoamCallbackUsrCtx; + +typedef struct sFTSMEContext { + /* Received and processed during pre-auth */ + uint8_t *auth_ft_ies; + uint32_t auth_ft_ies_length; + /* Received and processed during re-assoc */ + uint8_t *reassoc_ft_ies; + uint16_t reassoc_ft_ies_length; + /* Pre-Auth info */ + tFTIEStates FTState; /* The state of FT in the current 11rAssoc */ + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + uint32_t smeSessionId; + /* Saved pFTPreAuthRsp */ + tpSirFTPreAuthRsp psavedFTPreAuthRsp; + bool setFTPreAuthState; + bool setFTPTKState; + /* Time to trigger reassoc once pre-auth is successful */ + qdf_mc_timer_t preAuthReassocIntvlTimer; + bool addMDIE; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint32_t r0kh_id_len; + uint8_t r0kh_id[SIR_ROAM_R0KH_ID_MAX_LEN]; +#endif + /* User context for the timer callback */ + tpFTRoamCallbackUsrCtx pUsrCtx; +} tftSMEContext, *tpftSMEContext; + +/*-------------------------------------------------------------------------- + Prototype functions + ------------------------------------------------------------------------*/ +void sme_ft_open(tHalHandle hHal, uint32_t sessionId); +void sme_ft_close(tHalHandle hHal, uint32_t sessionId); +void sme_ft_reset(tHalHandle hHal, uint32_t sessionId); +void sme_set_ft_ies(tHalHandle hHal, uint32_t sessionId, const uint8_t *ft_ies, + uint16_t ft_ies_length); +QDF_STATUS sme_ft_update_key(tHalHandle hHal, uint32_t sessionId, + tCsrRoamSetKey *pFTKeyInfo); +void sme_get_ft_pre_auth_response(tHalHandle hHal, uint32_t sessionId, + uint8_t *ft_ies, uint32_t ft_ies_ip_len, + uint16_t *ft_ies_length); +void sme_get_rici_es(tHalHandle hHal, uint32_t sessionId, uint8_t *ric_ies, + uint32_t ric_ies_ip_len, uint32_t *ric_ies_length); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_reset_key() -Reset key information + * @mac_handle: MAC handle + * @vdev_id: vdev identifier + * + * Return: None + */ +void sme_reset_key(mac_handle_t mac_handle, uint32_t vdev_id); +#else +static inline void sme_reset_key(mac_handle_t mac_handle, uint32_t vdev_id) +{ +} +#endif + +void sme_preauth_reassoc_intvl_timer_callback(void *context); +void sme_set_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId, bool state); +bool sme_get_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId); +bool sme_get_ftptk_state(tHalHandle hHal, uint32_t sessionId); +void sme_set_ftptk_state(tHalHandle hHal, uint32_t sessionId, bool state); +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_inside.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_inside.h new file mode 100644 index 0000000000000000000000000000000000000000..34875e6577342d2db8872c2cc262954915c95097 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_inside.h @@ -0,0 +1,268 @@ +/* + * 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. + */ + +#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) +/* default sme timeout is set to 30 secs */ +#define SME_DEFAULT_CMD_TIMEOUT 30000 + +typedef struct sGenericQosCmd { + struct sme_qos_wmmtspecinfo tspecInfo; + sme_QosEdcaAcType ac; + uint8_t tspec_mask; +} tGenericQosCmd; + +typedef struct sRemainChlCmd { + uint8_t chn; + uint8_t phyMode; + uint32_t duration; + uint8_t isP2PProbeReqAllowed; + uint32_t scan_id; + void *callback; + void *callbackCtx; +} tRemainChlCmd; + +#ifdef FEATURE_WLAN_TDLS +typedef struct TdlsSendMgmtInfo { + tSirMacAddr peerMac; + uint8_t frameType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + uint8_t *buf; + uint8_t len; + enum wifi_traffic_ac ac; +} tTdlsSendMgmtCmdInfo; + +typedef struct TdlsLinkEstablishInfo { + struct qdf_mac_addr peermac; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t isResponder; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[REG_MAX_SUPP_OPER_CLASSES]; +} tTdlsLinkEstablishCmdInfo; + +typedef struct TdlsAddStaInfo { + eTdlsAddOper tdlsAddOper; + struct qdf_mac_addr peermac; + uint16_t capability; + uint8_t extnCapability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supportedRatesLen; + uint8_t supportedRates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap HTCap; + uint8_t vhtcap_present; + tSirVHTCap VHTCap; + uint8_t uapsdQueues; + uint8_t maxSp; +} tTdlsAddStaCmdInfo; + +typedef struct TdlsDelStaInfo { + struct qdf_mac_addr peermac; +} tTdlsDelStaCmdInfo; +/* + * TDLS cmd info, CMD from SME to PE. + */ +typedef struct s_tdls_cmd { + uint32_t size; + union { + tTdlsLinkEstablishCmdInfo tdlsLinkEstablishCmdInfo; + tTdlsSendMgmtCmdInfo tdlsSendMgmtCmdInfo; + tTdlsAddStaCmdInfo tdlsAddStaCmdInfo; + tTdlsDelStaCmdInfo tdlsDelStaCmdInfo; + } u; +} tTdlsCmd; +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct s_nss_update_cmd - Format of nss update request + * @new_nss: new nss value + * @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 + */ +struct s_nss_update_cmd { + uint32_t new_nss; + 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; +}; + +typedef struct tagSmeCmd { + tListElem Link; + eSmeCommandType command; + uint32_t cmd_id; + uint32_t sessionId; + union { + struct roam_cmd roamCmd; + struct wmstatus_changecmd wmStatusChangeCmd; + tGenericQosCmd qosCmd; + tRemainChlCmd remainChlCmd; + struct addstafor_sessioncmd addStaSessionCmd; + struct delstafor_sessionCmd delStaSessionCmd; +#ifdef FEATURE_WLAN_TDLS + tTdlsCmd tdlsCmd; +#endif + 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; + } 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(tpAniSirGlobal mac_ctx, + tSmeCmd *sme_cmd, struct wlan_serialization_command *cmd, + uint8_t high_priority); +tSmeCmd *sme_get_command_buffer(tpAniSirGlobal pMac); +void sme_release_command(tpAniSirGlobal pMac, tSmeCmd *pCmd); +bool qos_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void qos_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +QDF_STATUS csr_process_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +QDF_STATUS csr_roam_process_command(tpAniSirGlobal pMac, 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(tpAniSirGlobal mac_ctx, + uint8_t session_id); +void csr_roam_process_wm_status_change_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +/** + * csr_process_del_sta_session_command() - Post WMA_DEL_STA_SELF_REQ to wma + * + * @mac_ctx: global mac context + * @sme_command: received Delete Self station request command + * + * This API sends the WMA_DEL_STA_SELF_REQ msg to WMA. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE + */ +QDF_STATUS csr_process_del_sta_session_command(tpAniSirGlobal mac_ctx, + tSmeCmd *sme_command); +void csr_reinit_roam_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_reinit_wm_status_change_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +QDF_STATUS csr_roam_send_set_key_cmd(tpAniSirGlobal mac_ctx, + uint32_t session_id, struct setkey_cmd *set_key_cmd); +QDF_STATUS csr_is_valid_channel(tpAniSirGlobal pMac, uint8_t chnNum); + +QDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme); +QDF_STATUS sme_release_global_lock(tSmeStruct *psSme); + +QDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); +QDF_STATUS csr_process_del_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); + +bool csr_roamGetConcurrencyConnectStatusForBmps(tpAniSirGlobal pMac); + +QDF_STATUS csr_flush_cfg_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_create_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, const uint8_t *pChannelList, + const uint8_t numChannels); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS csr_create_roam_scan_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels, + const enum band_info eBand); +#endif + +QDF_STATUS p2p_process_remain_on_channel_cmd(tpAniSirGlobal pMac, + tSmeCmd *p2pRemainonChn); +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue); +void csr_process_set_dual_mac_config(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_set_antenna_mode(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_nss_update_req(tpAniSirGlobal mac, tSmeCmd *command); +#endif /* #if !defined( __SMEINSIDE_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..d1bf055313600fab35ddf0d7427f00fc5cf68024 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_internal.h @@ -0,0 +1,327 @@ +/* + * 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. + */ + +#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 "nan_api.h" +#include "wmi_unified.h" + +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, + e_sme_command_del_sta_session, + /* 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, +} eSmeCommandType; + +typedef enum eSmeState { + SME_STATE_STOP, + SME_STATE_START, + SME_STATE_READY, +} eSmeState; + +#define SME_IS_START(pMac) (SME_STATE_STOP != (pMac)->sme.state) +#define SME_IS_READY(pMac) (SME_STATE_READY == (pMac)->sme.state) + +/* HDD Callback function */ +typedef void (*pIbssPeerInfoCb)(void *pUserData, + tSirPeerInfoRspParams *infoParam); + +/* Peer info */ +typedef struct tagSmePeerInfoHddCbkInfo { + void *pUserData; + pIbssPeerInfoCb peerInfoCbk; +} tSmePeerInfoHddCbkInfo; + +typedef struct sStatsExtEvent { + uint32_t vdev_id; + uint32_t event_data_len; + uint8_t event_data[]; +} tStatsExtEvent, *tpStatsExtEvent; + +#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 (*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 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 sme_encrypt_decrypt_callback - encrypt/decrypt callback + * signature + * @context: Opaque context that the client can use to associate the + * callback with the request + * @response: Encrypt/Decrypt response from firmware + */ +struct sir_encrypt_decrypt_rsp_params; +typedef void (*sme_encrypt_decrypt_callback)( + void *context, + struct sir_encrypt_decrypt_rsp_params *response); + +/** + * 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); + +/** + * 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 congestion_cb - congestion callback function + * @hdd_handle: HDD handle registered with SME + * @congestion: Current congestion value + * @vdev_id: ID of the vdev for which congestion is being reported + */ +typedef void (*congestion_cb)(hdd_handle_t hdd_handle, uint32_t congestion, + uint32_t vdev_id); + +/** + * 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 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); + +typedef struct tagSmeStruct { + eSmeState state; + qdf_mutex_t lkSmeGlobalLock; + uint32_t totalSmeCmd; + /* following pointer contains array of pointers for tSmeCmd* */ + void **pSmeCmdBufAddr; + tDblLinkList smeCmdFreeList; /* preallocated roam cmd list */ + enum QDF_OPMODE currDeviceMode; + tSmePeerInfoHddCbkInfo peerInfoParams; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_event_wlan_status_payload_type eventPayload; +#endif +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + void *ll_stats_context; + void (*pLinkLayerStatsIndCallback)(void *callback_ctx, int ind_type, + void *rsp, void *context); + void (*link_layer_stats_ext_cb)(hdd_handle_t callback_ctx, + tSirLLStatsResults *rsp); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_POWER_DEBUGFS + void *power_debug_stats_context; + void (*power_stats_resp_callback)(struct power_stats_response *rsp, + void *callback_context); +#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 (*pAutoShutdownNotificationCb)(void); +#endif + /* Maximum interfaces allowed by the host */ + uint8_t max_intf_count; + void (*StatsExtCallback)(void *, tStatsExtEvent *); + /* linkspeed callback */ + void (*pLinkSpeedIndCb)(tSirLinkSpeedInfo *indParam, + void *pDevContext); + void *pLinkSpeedCbContext; + /* get peer info callback */ + void (*pget_peer_info_ind_cb)(struct sir_peer_info_resp *param, + void *pcontext); + void *pget_peer_info_cb_context; + /* get extended peer info callback */ + void (*pget_peer_info_ext_ind_cb)(struct sir_peer_info_ext_resp *param, + void *pcontext); + void *pget_peer_info_ext_cb_context; + sme_get_isolation_cb get_isolation_cb; + void *get_isolation_cb_context; +#ifdef FEATURE_WLAN_EXTSCAN + void (*pExtScanIndCb)(void *, const uint16_t, void *); +#endif /* FEATURE_WLAN_EXTSCAN */ +#ifdef WLAN_FEATURE_NAN + nan_callback nan_callback; +#endif + bool enableSelfRecovery; + 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 *pTemperatureCbContext; + void (*pGetTemperatureCb)(int temperature, void *context); + uint8_t miracast_value; + struct ps_global_info ps_global_info; + void (*rssi_threshold_breached_cb)(void *, struct rssi_breach_event *); + hw_mode_transition_cb sme_hw_mode_trans_cb; + sme_set_thermal_level_callback set_thermal_level_cb; + void *apf_get_offload_context; + p2p_lo_callback p2p_lo_event_callback; + void *p2p_lo_event_context; +#ifdef FEATURE_OEM_DATA_SUPPORT + sme_send_oem_data_rsp_msg oem_data_rsp_callback; +#endif + sme_encrypt_decrypt_callback encrypt_decrypt_cb; + void *encrypt_decrypt_context; + 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; + congestion_cb congestion_cb; + void (*stats_ext2_cb)(void *, struct sir_sme_rx_aggr_hole_ind *); + 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; + void (*tx_queue_cb)(void *, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason); + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params); + void (*twt_disable_cb)(void *hdd_ctx); +#ifdef FEATURE_WLAN_APF + apf_get_offload_cb apf_get_offload_cb; + apf_read_mem_cb apf_read_mem_cb; +#endif + /* 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 */ +} tSmeStruct, *tpSmeStruct; + +#endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_nan_datapath.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..817055bc9f241650d4adb64ff8967f7ea3917445 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_nan_datapath.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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_DATAPATH +/* Start NDI BSS */ +QDF_STATUS csr_roam_start_ndi(tpAniSirGlobal mac_ctx, uint32_t session_id, + struct csr_roam_profile *profile); + +void csr_roam_save_ndi_connected_info(tpAniSirGlobal mac_ctx, + uint32_t session_id, + struct csr_roam_profile *roam_profile, + tSirBssDescription *bss_desc); + +void csr_roam_update_ndp_return_params(tpAniSirGlobal mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct csr_roam_info *roam_info); + +#else +/* Start NDI BSS */ +static inline QDF_STATUS csr_roam_start_ndi(tpAniSirGlobal mac_ctx, + uint32_t session_id, + struct csr_roam_profile *profile) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void csr_roam_save_ndi_connected_info(tpAniSirGlobal mac_ctx, + uint32_t session_id, + struct csr_roam_profile *roam_profile, + tSirBssDescription *bss_desc) +{ +} + +static inline void csr_roam_update_ndp_return_params(tpAniSirGlobal mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct csr_roam_info *roam_info) +{ +} + +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +#endif /* __SME_NAN_DATAPATH_H */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save.h new file mode 100644 index 0000000000000000000000000000000000000000..d044d9a679505170e237e254f66c4a83b5ba76b4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save.h @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#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" + +#define MAX_SME_SESSIONS 5 + +/* + * 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 + +/** + * 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 +}; + +/** + * 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; + +}; + +/** + * struct ps_global_info - global struct for Power save information + * @ps_enabled: Power Save is enabled or not in ini + * @ps_params: maintain power save state and USAPD params + */ +struct ps_global_info { + bool ps_enabled; + uint32_t auto_bmps_timer_val; + struct ps_params ps_params[MAX_SME_SESSIONS]; + /* Remain in Power active till DHCP completes */ + bool remain_in_power_active_till_dhcp; +}; + +/** + * 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/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save_api.h new file mode 100644 index 0000000000000000000000000000000000000000..5340dca8fb1f1f3edeb9b24281529e62f835421c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save_api.h @@ -0,0 +1,89 @@ +/* + * 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. + */ + +#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(tHalHandle hal_ctx, uint32_t session_id, + enum sme_ps_cmd command); + +QDF_STATUS sme_ps_timer_flush_sync(tHalHandle hal, uint8_t session_id); + +QDF_STATUS sme_ps_uapsd_enable(tHalHandle hal_ctx, uint32_t session_id); + +QDF_STATUS sme_ps_uapsd_disable(tHalHandle hal_ctx, uint32_t session_id); + +/* Condition check if driver is ready to enter in PS */ +QDF_STATUS sme_enable_sta_ps_check(tpAniSirGlobal mac_ctx, uint32_t session_id); + +QDF_STATUS sme_ps_process_command(tpAniSirGlobal mac_ctx, + uint32_t session_id, + enum sme_ps_cmd command); + +void sme_set_tspec_uapsd_mask_per_session(tpAniSirGlobal mac_ctx, + tSirMacTSInfo *ts_info, + uint8_t session_id); +/* Full Power Req Callback */ +typedef void (*uapsd_start_indication_cb)(void *callback_context, + uint32_t session_id, QDF_STATUS status); + +QDF_STATUS sme_ps_start_uapsd(tHalHandle hal_ctx, uint32_t session_id); +QDF_STATUS sme_set_ps_host_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id); + +#ifdef WLAN_NS_OFFLOAD +QDF_STATUS sme_set_ps_ns_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id); + +#endif /* WLAN_NS_OFFLOAD */ +/* / Post a message to PE module */ +QDF_STATUS sme_post_pe_message(tpAniSirGlobal mac_ctx, + struct scheduler_msg *pMsg); + +/** + * sme_ps_enable_auto_ps_timer(): Enable power-save auto timer with timeout + * @hal_ctx: HAL context + * @session_id: adapter session Id + * @timeout: timeout period in ms + * + * Returns: QDF_STATUS + */ +QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t sessionId, uint32_t timeout); +QDF_STATUS sme_ps_disable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t sessionId); + +QDF_STATUS sme_ps_open(tHalHandle hal_ctx); + +QDF_STATUS sme_ps_open_per_session(tHalHandle hal_ctx, uint32_t session_id); + +void sme_auto_ps_entry_timer_expired(void *ps_param); +QDF_STATUS sme_ps_close(tHalHandle hal_ctx); +QDF_STATUS sme_ps_close_per_session(tHalHandle hal_ctx, uint32_t sessionId); + +bool sme_is_auto_ps_timer_running(tHalHandle hal_ctx, + uint32_t session_id); + +#endif /* #if !defined(__SME_POWER_SAVE_API_H) */ + diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_api.h new file mode 100644 index 0000000000000000000000000000000000000000..de71f94feb7ccf073a88a050bbc3de7c5fc05e56 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_api.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 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. + */ + +#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, + +}; + +/* + * 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; +}; + +/* External APIs */ +typedef QDF_STATUS (*sme_QosCallback)(tHalHandle hHal, void *HDDcontext, + struct sme_qos_wmmtspecinfo *pCurrentQoSInfo, + enum sme_qos_statustype status, uint32_t QosFlowID); +enum sme_qos_statustype sme_qos_setup_req(tHalHandle hHal, 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(tHalHandle hHal, + struct sme_qos_wmmtspecinfo *pQoSInfo, uint32_t QosFlowID); +enum sme_qos_statustype sme_qos_release_req(tHalHandle hHal, 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(tHalHandle hHal, + enum sme_qos_wmmuptype *dscpmapping, uint8_t sessionId); + +QDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(tpAniSirGlobal mac_ctx, + uint32_t session_id); +QDF_STATUS sme_offload_qos_process_into_uapsd_mode(tpAniSirGlobal mac_ctx, + uint32_t session_id); + + +#endif /* #if !defined( __SME_QOSAPI_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..4592abf3ccd45f30cb7026cd3dc617837e8997f4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_internal.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 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. + */ + +#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 EDCA Access Categories: + Based on AC to ACI mapping in 802.11e spec (identical to WMM) + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_EDCA_AC_BE = 0, /* Best effort access category */ + SME_QOS_EDCA_AC_BK = 1, /* Background access category */ + SME_QOS_EDCA_AC_VI = 2, /* Video access category */ + SME_QOS_EDCA_AC_VO = 3, /* Voice access category */ + + SME_QOS_EDCA_AC_MAX +} sme_QosEdcaAcType; + +/*--------------------------------------------------------------------------- + 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_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 { + tSirBssDescription *pBssDesc; + struct csr_roam_profile *pProfile; +} sme_QosAssocInfo; + +/*-------------------------------------------------------------------------- + External APIs for CSR - Internal to SME + ------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_open(tpAniSirGlobal pMac); +QDF_STATUS sme_qos_close(tpAniSirGlobal pMac); +QDF_STATUS sme_qos_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); + +/*-------------------------------------------------------------------------- + Internal APIs for CSR + ------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_validate_params(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +QDF_STATUS sme_qos_csr_event_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info); +uint8_t sme_qos_get_acm_mask(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, tDot11fBeaconIEs *pIes); +#ifdef FEATURE_WLAN_ESE +uint8_t sme_qos_ese_retrieve_tspec_info(tpAniSirGlobal pMac, uint8_t sessionId, + tTspecInfo * pTspecInfo); +#endif + +#endif /* #if !defined( __SMEQOSINTERNAL_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_api.h new file mode 100644 index 0000000000000000000000000000000000000000..5898023a12cd602abceec4311b0f0378e6fd03d5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_api.h @@ -0,0 +1,70 @@ +/* + * 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. + */ + +#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(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); +QDF_STATUS rrm_close(tpAniSirGlobal pMac); +QDF_STATUS rrm_open(tpAniSirGlobal pMac); +QDF_STATUS rrm_change_default_config_param(tpAniSirGlobal pMac, + struct rrm_config_param *rrm_config); +QDF_STATUS sme_rrm_neighbor_report_request(tpAniSirGlobal pMac, + uint8_t sessionId, tpRrmNeighborReq pNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); +QDF_STATUS sme_rrm_process_beacon_report_req_ind(tpAniSirGlobal pMac, + void *pMsgBuf); + +/** + * 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..c590b4d7e4d756512fead7efee5b04d8fab9b83a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_internal.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +#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; + +typedef struct sRrmSMEContext { + uint16_t token; + struct qdf_mac_addr sessionBssId; + uint8_t regClass; + /* 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]; + struct rrm_config_param rrmConfig; + qdf_mc_timer_t IterMeasTimer; + 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; + +#endif /* #if !defined( __SMERRMINTERNAL_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_trace.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..241282d3cfc52ef7879f79e79e3225360787f227 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_trace.h @@ -0,0 +1,145 @@ +/* + * 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. + */ + +/** + * \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 { + 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_STATS, + TRACE_CODE_SME_RX_HDD_GET_RSSI, + 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_GET_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(tpAniSirGlobal pMac); +#endif /* __SME_TRACE_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h b/drivers/staging/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h new file mode 100644 index 0000000000000000000000000000000000000000..4702eb2ce90e88094fb1890282896263f24c675f --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c new file mode 100644 index 0000000000000000000000000000000000000000..1fc3edca8b3178f2d962fea95b280ff4ad589e52 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c @@ -0,0 +1,16199 @@ +/* + * 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: smeApi.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_fips_api.h" +#include "qdf_trace.h" +#include "sme_trace.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "sap_api.h" +#include "mac_trace.h" +#ifdef WLAN_FEATURE_NAN +#include "nan_api.h" +#endif +#include "cds_regdomain.h" +#include "cfg_api.h" +#include "sme_power_save_api.h" +#include "wma.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 +#include +#include + +static tSelfRecoveryStats g_self_recovery_stats; + +static QDF_STATUS init_sme_cmd_list(tpAniSirGlobal pMac); + +static void sme_disconnect_connected_sessions(tpAniSirGlobal pMac); + +static QDF_STATUS sme_handle_generic_change_country_code(tpAniSirGlobal pMac, + void *pMsgBuf); + +static QDF_STATUS sme_process_nss_update_resp(tpAniSirGlobal mac, uint8_t *msg); + +/* Channel Change Response Indication Handler */ +static QDF_STATUS sme_process_channel_change_resp(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf); + +static QDF_STATUS sme_stats_ext_event(tpAniSirGlobal mac, + tpStatsExtEvent msg); + +/* Internal SME APIs */ +QDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (psSme) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_acquire(&psSme->lkSmeGlobalLock))) + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +void +sme_store_nss_chains_cfg_in_vdev(struct wlan_objmgr_vdev *vdev, + struct mlme_nss_chains *vdev_ini_cfg) +{ + struct mlme_nss_chains *ini_cfg; + struct mlme_nss_chains *dynamic_cfg; + + 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; +} + +QDF_STATUS sme_release_global_lock(tSmeStruct *psSme) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (psSme) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_release(&psSme->lkSmeGlobalLock))) + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +tpAniSirGlobal sme_get_mac_context(void) +{ + tpAniSirGlobal mac_ctx; + tHalHandle h_hal; + + h_hal = cds_get_context(QDF_MODULE_ID_SME); + if (NULL == h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + FL("invalid h_hal")); + return NULL; + } + + mac_ctx = PMAC_STRUCT(h_hal); + + 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(tpAniSirGlobal 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; + struct csr_roam_session *session; + uint32_t session_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; + + 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); + if (!CSR_IS_SESSION_VALID(mac, session_id)) { + sme_err("session %d is invalid", session_id); + goto end; + } + session = CSR_GET_SESSION(mac, session_id); + if (reason == POLICY_MGR_UPDATE_REASON_HIDDEN_STA) { + /* In the case of hidden SSID, connection update + * (set hw mode) is done after the scan with reason + * code eCsrScanForSsid completes. The connect/failure + * needs to be handled after the response of set hw + * mode + */ + if (param->status == SET_HW_MODE_STATUS_OK) { + sme_debug("search for ssid success"); + csr_scan_handle_search_for_ssid(mac, + session_id); + } else { + sme_debug("search for ssid failure"); + csr_scan_handle_search_for_ssid_failure(mac, + session_id); + } + csr_saved_scan_cmd_free_fields(mac, session); + } + +end: + found = csr_nonscan_active_ll_remove_entry(mac, entry, + LL_ACCESS_LOCK); + if (found) + /* Now put this command back on the avilable 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(tpAniSirGlobal mac, + uint8_t *msg) +{ + struct sir_hw_mode_trans_ind *param; + + param = (struct sir_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, mac->psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_purge_pdev_all_ser_cmd_list_sync(mac_handle_t mac_handle, + sir_purge_pdev_cmd_cb cb) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(mac_handle); + struct scheduler_msg msg = {0}; + struct sir_purge_pdev_cmd_req *req; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_release_global_lock(&mac_ctx->sme); + sme_err("failed to get req"); + return QDF_STATUS_E_NOMEM; + } + + req->message_type = eWNI_SME_PURGE_ALL_PDEV_CMDS_REQ; + req->length = (uint16_t) sizeof(tAniGetRssiReq); + req->purge_complete_cb = cb; + msg.type = eWNI_SME_PURGE_ALL_PDEV_CMDS_REQ; + msg.bodyptr = req; + status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(req); + sme_err("Failed to post eWNI_SME_PURGE_ALL_PDEV_CMDS_REQ to self"); + } + sme_release_global_lock(&mac_ctx->sme); + + return status; +} + +/** + * 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(tpAniSirGlobal mac_ctx) +{ + uint32_t idx; + + if (NULL == mac_ctx->sme.pSmeCmdBufAddr) + return; + + for (idx = 0; idx < mac_ctx->sme.totalSmeCmd; idx++) + qdf_mem_free(mac_ctx->sme.pSmeCmdBufAddr[idx]); + + qdf_mem_free(mac_ctx->sme.pSmeCmdBufAddr); + mac_ctx->sme.pSmeCmdBufAddr = NULL; +} + +static QDF_STATUS init_sme_cmd_list(tpAniSirGlobal pMac) +{ + QDF_STATUS status; + tSmeCmd *pCmd; + uint32_t cmd_idx; + uint32_t sme_cmd_ptr_ary_sz; + + pMac->sme.totalSmeCmd = SME_TOTAL_COMMAND; + + + status = csr_ll_open(&pMac->sme.smeCmdFreeList); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + + /* following pointer contains array of pointers for tSmeCmd* */ + sme_cmd_ptr_ary_sz = sizeof(void *) * pMac->sme.totalSmeCmd; + pMac->sme.pSmeCmdBufAddr = qdf_mem_malloc(sme_cmd_ptr_ary_sz); + if (NULL == pMac->sme.pSmeCmdBufAddr) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + status = QDF_STATUS_SUCCESS; + for (cmd_idx = 0; cmd_idx < pMac->sme.totalSmeCmd; 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.pSmeCmdBufAddr. This will later facilitate + * freeing up of all SME CMDs with just a for loop. + */ + pMac->sme.pSmeCmdBufAddr[cmd_idx] = + qdf_mem_malloc(sizeof(tSmeCmd)); + if (NULL == pMac->sme.pSmeCmdBufAddr[cmd_idx]) { + status = QDF_STATUS_E_NOMEM; + free_sme_cmds(pMac); + goto end; + } + pCmd = (tSmeCmd *)pMac->sme.pSmeCmdBufAddr[cmd_idx]; + csr_ll_insert_tail(&pMac->sme.smeCmdFreeList, + &pCmd->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(tpAniSirGlobal mac_ctx, tSmeCmd *sme_cmd) +{ + sme_cmd->command = eSmeNoCommand; + csr_ll_insert_tail(&mac_ctx->sme.smeCmdFreeList, &sme_cmd->Link, + LL_ACCESS_LOCK); +} + +static QDF_STATUS free_sme_cmd_list(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_ll_close(&pMac->sme.smeCmdFreeList); + + status = qdf_mutex_acquire(&pMac->sme.lkSmeGlobalLock); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Failed to acquire the lock status: %d", status); + goto done; + } + + free_sme_cmds(pMac); + + status = qdf_mutex_release(&pMac->sme.lkSmeGlobalLock); + if (status != QDF_STATUS_SUCCESS) + sme_err("Failed to release the lock status: %d", status); +done: + return status; +} + +static void dump_csr_command_info(tpAniSirGlobal pMac, 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; + + case e_sme_command_del_sta_session: + sme_debug("Issue del STA command for session:%d", + pCmd->sessionId); + break; + + default: + sme_debug("default: Unhandled command %d", + pCmd->command); + break; + } +} + +tSmeCmd *sme_get_command_buffer(tpAniSirGlobal pMac) +{ + tSmeCmd *pRetCmd = NULL, *pTempCmd = NULL; + tListElem *pEntry; + static int sme_command_queue_full; + + pEntry = csr_ll_remove_head(&pMac->sme.smeCmdFreeList, 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 tfhe 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(pMac, 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(pMac, pTempCmd); + } /* if(pTempCmd) */ + + /* dump what is in the pending queue */ + csr_nonscan_pending_ll_lock(pMac); + pEntry = + csr_nonscan_pending_ll_peek_head(pMac, + 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(pMac, pTempCmd); + pEntry = csr_nonscan_pending_ll_next(pMac, pEntry, + LL_ACCESS_NOLOCK); + } + csr_nonscan_pending_ll_unlock(pMac); + + if (pMac->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + false, + pMac->sme.enableSelfRecovery ? true : false); + 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->sessionId, + sizeof(pRetCmd->sessionId)); + 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; + tHalHandle hal; + tpAniSirGlobal mac_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool do_continue; + + if (!cmd) { + sme_err("No serialization command found"); + return QDF_STATUS_E_FAILURE; + } + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (NULL != hal) { + mac_ctx = PMAC_STRUCT(hal); + } else { + sme_err("No hal found"); + 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 e_sme_command_del_sta_session: + csr_process_del_sta_session_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; + default: + /* something is wrong */ + sme_err("unknown command %d", sme_cmd->command); + status = QDF_STATUS_E_FAILURE; + break; + } + return status; +} + +QDF_STATUS sme_ser_cmd_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + tHalHandle hal; + tpAniSirGlobal mac_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *sme_cmd; + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (hal != NULL) { + mac_ctx = PMAC_STRUCT(hal); + } else { + sme_err("hal is null"); + 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: + sme_debug("WLAN_SER_CB_ACTIVATE_CMD callback"); + status = sme_ser_handle_active_cmd(cmd); + break; + case WLAN_SER_CB_CANCEL_CMD: + sme_debug("WLAN_SER_CB_CANCEL_CMD callback"); + break; + case WLAN_SER_CB_RELEASE_MEM_CMD: + sme_debug("WLAN_SER_CB_RELEASE_MEM_CMD callback"); + 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_debug("WLAN_SER_CB_ACTIVE_CMD_TIMEOUT callback"); + break; + default: + sme_debug("STOP: unknown reason code"); + return QDF_STATUS_E_FAILURE; + } + return status; +} + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +/** + * sme_get_sessionid_from_activelist() - gets session id + * @mac: mac context + * + * This function is used to get session id from sme command + * active list + * + * Return: returns session id + */ +static uint32_t sme_get_sessionid_from_activelist(tpAniSirGlobal mac) +{ + tListElem *entry; + tSmeCmd *command; + uint32_t session_id = CSR_SESSION_ID_INVALID; + + entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (entry) { + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + session_id = command->sessionId; + } + + return session_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) +{ + uint32_t session_id, active_session_id; + tHalHandle hal; + tpAniSirGlobal mac; + uint16_t len = 0; + char *buf = *buf_ptr; + eCsrConnectState connect_state; + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + + active_session_id = sme_get_sessionid_from_activelist(mac); + if (active_session_id != CSR_SESSION_ID_INVALID) { + len += qdf_scnprintf(buf + len, *size - len, + "\n active command sessionid %d", active_session_id); + } + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (CSR_IS_SESSION_VALID(mac, session_id)) { + connect_state = + mac->roam.roamSession[session_id].connectState; + if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED == + connect_state) + || (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED == + connect_state)) { + len += qdf_scnprintf(buf + len, *size - len, + "\n NeighborRoamState: %d", + mac->roam.neighborRoamInfo[session_id]. + neighborRoamState); + len += qdf_scnprintf(buf + len, *size - len, + "\n RoamState: %d", mac->roam. + curState[session_id]); + len += qdf_scnprintf(buf + len, *size - len, + "\n RoamSubState: %d", mac->roam. + curSubState[session_id]); + len += qdf_scnprintf(buf + len, *size - len, + "\n ConnectState: %d", + connect_state); + } + } + } + + *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 */ + +/* Global APIs */ + +/** + * sme_open() - Initialze all SME modules and put them at idle state + * @hHal: 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(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->sme.state = SME_STATE_STOP; + pMac->sme.currDeviceMode = QDF_STA_MODE; + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create( + &pMac->sme.lkSmeGlobalLock))) { + sme_err("sme_open failed init lock"); + return QDF_STATUS_E_FAILURE; + } + status = csr_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("csr_open failed, status: %d", status); + return status; + } + + status = sme_ps_open(hHal); + 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(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Qos open, status: %d", status); + return status; + } +#endif + status = init_sme_cmd_list(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + status = rrm_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("rrm_open failed, status: %d", status); + return status; + } + sme_trace_init(pMac); + sme_register_debug_callback(); + + return status; +} + +/* + * sme_init_chan_list, triggers channel setup based on country code. + */ +QDF_STATUS sme_init_chan_list(tHalHandle hal, uint8_t *alpha2, + enum country_src cc_src) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + if ((cc_src == SOURCE_USERSPACE) && + (pmac->roam.configParam.fSupplicantCountryCodeHasPriority)) { + pmac->roam.configParam.Is11dSupportEnabled = false; + } + + return csr_init_chan_list(pmac, alpha2); +} + +/* + * 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 + * + * hHal - The handle returned by mac_open. + * pSmeConfigParams - a pointer to a caller allocated object of + * typedef struct _smeConfigParams. + * + * 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(tHalHandle hal, tpSmeConfigParams pSmeConfigParams) +{ + tpAniSirGlobal mac_ctx = MAC_CONTEXT(hal); + 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 (NULL == pSmeConfigParams) { + sme_err("SME config params empty"); + return status; + } + + status = csr_set_channels(mac_ctx, &pSmeConfigParams->csrConfig); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("csr_set_channels failed with status: %d", status); + + return status; +} + +/** + * sme_set_scan_disable() - Dynamically enable/disable scan + * @h_hal: Handle to HAL + * + * This command gives the user an option to dynamically + * enable or disable scans. + * + * Return: None + */ +void sme_set_scan_disable(tHalHandle h_hal, int value) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + + sme_info("scan disable %d", value); + ucfg_scan_set_enable(mac_ctx->psoc, !value); +} +/* + * sme_get_soft_ap_domain() - Get the current regulatory domain of softAp. + * This is a synchronous call + * + * hHal - The handle returned by HostapdAdapter. + * v_REGDOMAIN_t - The current Regulatory Domain requested for SoftAp. + * Return QDF_STATUS_SUCCESS - SME successfully completed the request. + * Other status means, failed to get the current regulatory domain. + */ + +QDF_STATUS sme_get_soft_ap_domain(tHalHandle hHal, v_REGDOMAIN_t + *domainIdSoftAp) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN, + NO_SESSION, 0)); + if (NULL == domainIdSoftAp) { + sme_err("Uninitialized domain Id"); + return status; + } + + *domainIdSoftAp = pMac->scan.domainIdCurrent; + status = QDF_STATUS_SUCCESS; + + return status; +} + +/** + * sme_update_fine_time_measurement_capab() - Update the FTM capabitlies from + * incoming val + * @hal: Handle for Hal layer + * @val: New FTM capability value + * + * Return: None + */ +void sme_update_fine_time_measurement_capab(tHalHandle hal, uint8_t session_id, + uint32_t val) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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.rrmSmeContext. + rrmConfig.rm_capability)->fine_time_meas_rpt = 0; + } else { + mac_ctx->rrm.rrmPEContext.rrmEnabledCaps.fine_time_meas_rpt = 1; + ((tpRRMCaps)mac_ctx->rrm.rrmSmeContext. + 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)) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CONNECT_IES_CHANGED); + sme_release_global_lock(&mac_ctx->sme); + } else { + sme_err("Failed to acquire SME lock"); + } +} + +/* + * sme_update_config() - Change configurations for all SME moduels + * 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 + * + * hHal - The handle returned by mac_open. + * pSmeConfigParams - a pointer to a caller allocated object of + * typedef struct _smeConfigParams. + * 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(tHalHandle hHal, tpSmeConfigParams + pSmeConfigParams) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG, NO_SESSION, + 0)); + if (NULL == pSmeConfigParams) { + sme_err("SME config params empty"); + return status; + } + + status = csr_change_default_config_param(pMac, &pSmeConfigParams-> + csrConfig); + + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("csr_change_default_config_param failed status: %d", + status); + + status = rrm_change_default_config_param(pMac, &pSmeConfigParams-> + rrmConfig); + + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("rrm_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(pMac)) + csr_set_global_cfgs(pMac); + + /* + * If scan offload is enabled then lim has allow the sending of + * scan request to firmware even in powersave mode. The firmware has + * to take care of exiting from power save mode + */ + status = sme_cfg_set_int(hHal, WNI_CFG_SCAN_IN_POWERSAVE, true); + + if (QDF_STATUS_SUCCESS != status) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Could not pass on WNI_CFG_SCAN_IN_POWERSAVE to CFG"); + + pMac->snr_monitor_enabled = pSmeConfigParams->snr_monitor_enabled; + + return status; +} + +/** + * sme_update_scan_roam_params() - Update the scan roaming params + * @mac_ctx: mac ctx + * + * Return: void. + */ +static void sme_update_scan_roam_params(tpAniSirGlobal mac_ctx) +{ + struct roam_filter_params scan_params = {0}; + struct roam_ext_params *roam_params_src; + uint8_t i; + QDF_STATUS status; + + roam_params_src = &mac_ctx->roam.configParam.roam_params; + + scan_params.num_bssid_avoid_list = + roam_params_src->num_bssid_avoid_list; + + if (scan_params.num_bssid_avoid_list > + MAX_AVOID_LIST_BSSID) + scan_params.num_bssid_avoid_list = + MAX_AVOID_LIST_BSSID; + + for (i = 0; i < scan_params.num_bssid_avoid_list; i++) { + qdf_copy_macaddr(&scan_params.bssid_avoid_list[i], + &roam_params_src->bssid_avoid_list[i]); + } + + status = ucfg_scan_update_roam_params(mac_ctx->psoc, &scan_params); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("ailed to update scan roam params with status=%d", + status); +} + +/** + * sme_update_roam_params() - Store/Update the roaming params + * @hal: Handle for Hal layer + * @session_id: SME Session ID + * @roam_params_src: The source buffer to copy + * @update_param: Type of parameter to be updated + * + * Return: Return the status of the updation. + */ +QDF_STATUS sme_update_roam_params(tHalHandle hal, + uint8_t session_id, struct roam_ext_params *roam_params_src, + int update_param) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct roam_ext_params *roam_params_dst; + QDF_STATUS status; + uint8_t i; + + roam_params_dst = &mac_ctx->roam.configParam.roam_params; + switch (update_param) { + case REASON_ROAM_EXT_SCAN_PARAMS_CHANGED: + roam_params_dst->raise_rssi_thresh_5g = + roam_params_src->raise_rssi_thresh_5g; + roam_params_dst->drop_rssi_thresh_5g = + roam_params_src->drop_rssi_thresh_5g; + roam_params_dst->raise_factor_5g = + roam_params_src->raise_factor_5g; + roam_params_dst->drop_factor_5g = + roam_params_src->drop_factor_5g; + roam_params_dst->max_raise_rssi_5g = + roam_params_src->max_raise_rssi_5g; + roam_params_dst->max_drop_rssi_5g = + roam_params_src->max_drop_rssi_5g; + roam_params_dst->alert_rssi_threshold = + roam_params_src->alert_rssi_threshold; + roam_params_dst->is_5g_pref_enabled = true; + break; + case REASON_ROAM_SET_SSID_ALLOWED: + qdf_mem_zero(&roam_params_dst->ssid_allowed_list, + sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST); + roam_params_dst->num_ssid_allowed_list = + roam_params_src->num_ssid_allowed_list; + for (i = 0; i < roam_params_dst->num_ssid_allowed_list; i++) { + roam_params_dst->ssid_allowed_list[i].length = + roam_params_src->ssid_allowed_list[i].length; + qdf_mem_copy(roam_params_dst->ssid_allowed_list[i].ssId, + roam_params_src->ssid_allowed_list[i].ssId, + roam_params_dst->ssid_allowed_list[i].length); + } + break; + case REASON_ROAM_SET_FAVORED_BSSID: + qdf_mem_zero(&roam_params_dst->bssid_favored, + sizeof(tSirMacAddr) * MAX_BSSID_FAVORED); + roam_params_dst->num_bssid_favored = + roam_params_src->num_bssid_favored; + for (i = 0; i < roam_params_dst->num_bssid_favored; i++) { + qdf_mem_copy(&roam_params_dst->bssid_favored[i], + &roam_params_src->bssid_favored[i], + sizeof(tSirMacAddr)); + roam_params_dst->bssid_favored_factor[i] = + roam_params_src->bssid_favored_factor[i]; + } + break; + case REASON_ROAM_SET_BLACKLIST_BSSID: + qdf_mem_zero(&roam_params_dst->bssid_avoid_list, + QDF_MAC_ADDR_SIZE * MAX_BSSID_AVOID_LIST); + roam_params_dst->num_bssid_avoid_list = + roam_params_src->num_bssid_avoid_list; + for (i = 0; i < roam_params_dst->num_bssid_avoid_list; i++) { + qdf_copy_macaddr(&roam_params_dst->bssid_avoid_list[i], + &roam_params_src->bssid_avoid_list[i]); + } + break; + case REASON_ROAM_GOOD_RSSI_CHANGED: + roam_params_dst->good_rssi_roam = + roam_params_src->good_rssi_roam; + break; + default: + break; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + update_param); + sme_release_global_lock(&mac_ctx->sme); + } else { + sme_err("Failed to acquire SME lock"); + } + + sme_update_scan_roam_params(mac_ctx); + + return 0; +} + +/** + * sme_process_ready_to_suspend() - + * @mac: Global MAC context + * @pReadyToSuspend: Parameter received along with ready to suspend + * indication from WMA. + * + * On getting ready to suspend indication, this function calls + * callback registered (HDD callbacks) with SME to inform ready + * to suspend indication. + * + * Return: None + */ +static void sme_process_ready_to_suspend(tpAniSirGlobal mac, + tpSirReadyToSuspendInd pReadyToSuspend) +{ + if (NULL == mac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: mac is null", __func__); + return; + } + + if (NULL != mac->readyToSuspendCallback) { + mac->readyToSuspendCallback(mac->readyToSuspendContext, + pReadyToSuspend->suspended); + mac->readyToSuspendCallback = NULL; + } +} + +#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(tpAniSirGlobal mac, + tpSirReadyToExtWoWInd indication) +{ + if (!mac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: mac is null", __func__); + return; + } + + if (NULL != 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 + * + * @hHal - 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(tHalHandle hHal) +{ + tSirSmeReadyReq *msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + 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) { + sme_err("Memory allocation failed! for msg"); + return QDF_STATUS_E_NOMEM; + } + msg->messageType = eWNI_SME_SYS_READY_IND; + msg->length = sizeof(*msg); + msg->csr_roam_synch_cb = csr_roam_synch_callback; + msg->sme_msg_cb = sme_process_msg_callback; + msg->stop_roaming_cb = sme_stop_roaming; + + status = u_mac_post_ctrl_msg(hHal, (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(pMac); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("csr_ready failed with status: %d", status); + break; + } + + pMac->sme.state = SME_STATE_READY; + } while (0); + + return status; +} + +QDF_STATUS sme_get_valid_channels(uint8_t *chan_list, uint32_t *list_len) +{ + tpAniSirGlobal mac_ctx = sme_get_mac_context(); + + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return QDF_STATUS_E_FAILURE; + } + + return wlan_cfg_get_str(mac_ctx, WNI_CFG_VALID_CHANNEL_LIST, + chan_list, list_len); +} + +#ifdef WLAN_CONV_SPECTRAL_ENABLE +static QDF_STATUS sme_register_spectral_cb(tpAniSirGlobal mac_ctx) +{ + struct spectral_legacy_cbacks spectral_cb; + 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(tpAniSirGlobal 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 + * + * hHal - 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(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct policy_mgr_sme_cbacks sme_cbacks; + + do { + status = csr_start(pMac); + 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_get_valid_channels = sme_get_valid_channels; + 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_pdev_set_pcl = sme_pdev_set_pcl; + 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_get_ap_channel_from_scan = + sme_get_ap_channel_from_scan; + sme_cbacks.sme_scan_result_purge = sme_scan_result_purge; + status = policy_mgr_register_sme_cb(pMac->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(pMac); + pMac->sme.state = SME_STATE_START; + + /* START RRM */ + status = rrm_start(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to start RRM"); + break; + } + } while (0); + return status; +} + +static QDF_STATUS dfs_msg_processor(tpAniSirGlobal mac, + struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info roam_info = { 0 }; + tSirSmeCSAIeTxCompleteRsp *csa_ie_tx_complete_rsp; + uint32_t session_id = 0; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + + switch (msg->type) { + case eWNI_SME_DFS_RADAR_FOUND: + { + session_id = msg->bodyval; + roam_status = eCSR_ROAM_DFS_RADAR_IND; + roam_result = eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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"); + 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND session=%d", + session_id); + 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "sapdfs: Received eWNI_SME_DFS_CAC_COMPLETE vdevid%d", + session_id); + break; + } + default: + { + sme_err("Invalid DFS message: 0x%x", msg->type); + status = QDF_STATUS_E_FAILURE; + return status; + } + } + + /* Indicate Radar Event to SAP */ + csr_roam_call_callback(mac, session_id, &roam_info, 0, + roam_status, roam_result); + return status; +} + + +#ifdef WLAN_FEATURE_11W +/* + * Handle the unprotected management frame indication from LIM and + * forward it to HDD. + */ +static QDF_STATUS +sme_unprotected_mgmt_frm_ind(tpAniSirGlobal mac, + tpSirSmeUnprotMgmtFrameInd pSmeMgmtFrm) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info roam_info = { 0 }; + uint32_t SessionId = pSmeMgmtFrm->sessionId; + + 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, 0, + eCSR_ROAM_UNPROT_MGMT_FRAME_IND, 0); + + return status; +} +#endif + +QDF_STATUS sme_update_new_channel_event(tHalHandle hal, uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct csr_roam_info *roamInfo; + eRoamCmdStatus roamStatus; + eCsrRoamResult roamResult; + + roamInfo = qdf_mem_malloc(sizeof(*roamInfo)); + if (!roamInfo) { + sme_err("mem alloc failed for roam info"); + return QDF_STATUS_E_FAILURE; + } + roamInfo->dfs_event.sessionId = session_id; + + roamStatus = eCSR_ROAM_CHANNEL_COMPLETE_IND; + roamResult = eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "sapdfs: Updated new channel event"); + + /* Indicate channel Event to SAP */ + csr_roam_call_callback(mac, session_id, roamInfo, 0, + 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(tpAniSirGlobal 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 roamInfo = {0}; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + + ext_chan_ind = msg_buf; + if (NULL == ext_chan_ind) { + sme_err("ext_chan_ind is NULL"); + return QDF_STATUS_E_FAILURE; + } + session_id = ext_chan_ind->session_id; + roamInfo.target_channel = ext_chan_ind->new_channel; + 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, &roamInfo, 0, + roam_status, roam_result); + return status; +} + +#ifdef FEATURE_WLAN_ESE +/** + * sme_update_is_ese_feature_enabled() - enable/disable ESE support at runtime + * @hHal: HAL handle + * @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(tHalHandle hHal, + uint8_t sessionId, const bool isEseIniFeatureEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status; + + if (pMac->roam.configParam.isEseIniFeatureEnabled == + isEseIniFeatureEnabled) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: ESE Mode is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + __func__, + pMac->roam.configParam.isEseIniFeatureEnabled, + isEseIniFeatureEnabled); + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: EseEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.isEseIniFeatureEnabled, + isEseIniFeatureEnabled); + pMac->roam.configParam.isEseIniFeatureEnabled = isEseIniFeatureEnabled; + csr_neighbor_roam_update_fast_roaming_enabled( + pMac, sessionId, isEseIniFeatureEnabled); + + if (true == isEseIniFeatureEnabled) + sme_update_fast_transition_enabled(hHal, true); + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ESE_INI_CFG_CHANGED); + sme_release_global_lock(&pMac->sme); + } else { + sme_err("Failed to acquire SME lock"); + return status; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_plm_request() - set plm request + * @hHal: HAL handle + * @pPlmReq: Pointer to input plm request + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_plm_request(tHalHandle hHal, tpSirPlmReq pPlmReq) +{ + QDF_STATUS status; + bool ret = false; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t ch_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t count, valid_count = 0; + struct scheduler_msg msg = {0}; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, + pPlmReq->sessionId); + + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + if (!pSession) { + sme_err("session %d not found", pPlmReq->sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid Sessionid")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!pPlmReq->enable) + goto send_plm_start; + /* validating channel numbers */ + for (count = 0; count < pPlmReq->plmNumCh; count++) { + ret = csr_is_supported_channel(pMac, pPlmReq->plmChList[count]); + if (ret && pPlmReq->plmChList[count] > 14) { + if (CHANNEL_STATE_DFS == wlan_reg_get_channel_state( + pMac->pdev, + pPlmReq->plmChList[count])) { + /* DFS channel is provided, no PLM bursts can be + * transmitted. Ignoring these channels. + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("DFS channel %d ignored for PLM"), + pPlmReq->plmChList[count]); + continue; + } + } else if (!ret) { + /* Not supported, ignore the channel */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Unsupported channel %d ignored for PLM"), + pPlmReq->plmChList[count]); + continue; + } + ch_list[valid_count] = pPlmReq->plmChList[count]; + valid_count++; + } /* End of for () */ + + /* Copying back the valid channel list to plm struct */ + qdf_mem_zero((void *)pPlmReq->plmChList, + pPlmReq->plmNumCh); + if (valid_count) + qdf_mem_copy(pPlmReq->plmChList, ch_list, + valid_count); + /* All are invalid channels, FW need to send the PLM + * report with "incapable" bit set. + */ + pPlmReq->plmNumCh = valid_count; + +send_plm_start: + /* PLM START */ + msg.type = WMA_SET_PLM_REQ; + msg.reserved = 0; + msg.bodyptr = pPlmReq; + + if (!QDF_IS_STATUS_SUCCESS(scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_PLM_REQ to WMA")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + return status; +} + +/** + * 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(tpAniSirGlobal mac, + tSirSmeTsmIEInd *pSmeTsmIeInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info roam_info = { 0 }; + uint32_t SessionId = pSmeTsmIeInd->sessionId; + + roam_info.tsmIe.tsid = pSmeTsmIeInd->tsmIe.tsid; + roam_info.tsmIe.state = pSmeTsmIeInd->tsmIe.state; + roam_info.tsmIe.msmt_interval = pSmeTsmIeInd->tsmIe.msmt_interval; + /* forward the tsm ie information to HDD */ + csr_roam_call_callback(mac, SessionId, &roam_info, 0, + eCSR_ROAM_TSM_IE_IND, 0); + return status; +} + +/** + * sme_set_cckm_ie() - set cckm ie + * @hHal: HAL handle + * @sessionId: session id + * @pCckmIe: Pointer to CCKM Ie + * @cckmIeLen: Length of @pCckmIe + * + * Function to store the CCKM IE passed from supplicant and use + * it while packing reassociation request. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_cckm_ie(tHalHandle hHal, uint8_t sessionId, + uint8_t *pCckmIe, uint8_t cckmIeLen) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_set_cckm_ie(pMac, sessionId, pCckmIe, cckmIeLen); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_ese_beacon_request() - set ese beacon request + * @hHal: HAL handle + * @sessionId: session id + * @pEseBcnReq: Ese beacon report + * + * function to set ESE beacon request parameters + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_ese_beacon_request(tHalHandle hHal, const uint8_t sessionId, + const tCsrEseBeaconReq *pEseBcnReq) +{ + QDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpSirBeaconReportReqInd pSmeBcnReportReq = NULL; + tCsrEseBeaconReqParams *pBeaconReq = NULL; + uint8_t counter = 0; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + + if (pSmeRrmContext->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(&pSmeRrmContext->eseBcnReqInfo, pEseBcnReq, + sizeof(tCsrEseBeaconReq)); + + /* Prepare the request to send to SME. */ + pSmeBcnReportReq = qdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (NULL == pSmeBcnReportReq) { + sme_err("Memory Allocation Failure!!! ESE BcnReq Ind to SME"); + return QDF_STATUS_E_NOMEM; + } + + pSmeRrmContext->eseBcnReqInProgress = true; + + sme_debug("Sending Beacon Report Req to SME"); + + pSmeBcnReportReq->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + pSmeBcnReportReq->length = sizeof(tSirBeaconReportReqInd); + qdf_mem_copy(pSmeBcnReportReq->bssId, + pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + pSmeBcnReportReq->channelInfo.channelNum = 255; + pSmeBcnReportReq->channelList.numChannels = pEseBcnReq->numBcnReqIe; + pSmeBcnReportReq->msgSource = eRRM_MSG_SOURCE_ESE_UPLOAD; + + for (counter = 0; counter < pEseBcnReq->numBcnReqIe; counter++) { + pBeaconReq = + (tCsrEseBeaconReqParams *) &pEseBcnReq->bcnReq[counter]; + pSmeBcnReportReq->fMeasurementtype[counter] = + pBeaconReq->scanMode; + pSmeBcnReportReq->measurementDuration[counter] = + SYS_TU_TO_MS(pBeaconReq->measurementDuration); + pSmeBcnReportReq->channelList.channelNumber[counter] = + pBeaconReq->channel; + } + + status = sme_rrm_process_beacon_report_req_ind(pMac, pSmeBcnReportReq); + + if (status != QDF_STATUS_SUCCESS) + pSmeRrmContext->eseBcnReqInProgress = false; + + qdf_mem_free(pSmeBcnReportReq); + + return status; +} + +/** + * sme_get_tsm_stats() - SME get tsm stats + * @hHal: HAL handle + * @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(tHalHandle hHal, + tCsrTsmStatsCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, + void *pContext, uint8_t tid) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_tsm_stats(pMac, callback, + staId, bssId, pContext, + tid); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_ese_roam_scan_channel_list() - To set ese roam scan channel list + * @hHal: pointer HAL handle returned by mac_open + * @sessionId: sme session id + * @pChannelList: Output channel list + * @numChannels: Output number of channels + * + * This routine is called to set ese roam scan channel list. + * This is a synchronous call + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_ese_roam_scan_channel_list(tHalHandle hHal, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tpCsrChannelInfo curchnl_list_info = NULL; + uint8_t oldChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t newChannelList[128] = { 0 }; + uint8_t i = 0, j = 0; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + curchnl_list_info = + &pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo; + + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to acquire SME lock"); + return status; + } + if (NULL != curchnl_list_info->ChannelList) { + for (i = 0; i < curchnl_list_info->numOfChannels; i++) { + j += snprintf(oldChannelList + j, + sizeof(oldChannelList) - j, "%d", + curchnl_list_info->ChannelList[i]); + } + } + status = csr_create_roam_scan_channel_list(pMac, sessionId, + pChannelList, numChannels, + csr_get_current_band(hHal)); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (NULL != curchnl_list_info->ChannelList) { + j = 0; + for (i = 0; i < curchnl_list_info->numOfChannels; i++) { + j += snprintf(newChannelList + j, + sizeof(newChannelList) - j, "%d", + curchnl_list_info->ChannelList[i]); + } + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "ESE roam scan chnl list successfully set to %s-old value is %s-roam state is %d", + newChannelList, oldChannelList, + pNeighborRoamInfo->neighborRoamState); + } + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + + sme_release_global_lock(&pMac->sme); + return status; +} + +#endif /* FEATURE_WLAN_ESE */ + +static +QDF_STATUS sme_ibss_peer_info_response_handler(tpAniSirGlobal pMac, + tpSirIbssGetPeerInfoRspParams + pIbssPeerInfoParams) +{ + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return QDF_STATUS_E_FAILURE; + } + if (pMac->sme.peerInfoParams.peerInfoCbk == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: HDD callback is null", __func__); + return QDF_STATUS_E_FAILURE; + } + pMac->sme.peerInfoParams.peerInfoCbk(pMac->sme.peerInfoParams.pUserData, + &pIbssPeerInfoParams-> + ibssPeerInfoRspParams); + return QDF_STATUS_SUCCESS; +} + +/** + * 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(tpAniSirGlobal 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; +} + +/** + * 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(tpAniSirGlobal 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; +} + +QDF_STATUS sme_process_msg(tpAniSirGlobal pMac, struct scheduler_msg *pMsg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_peer_info *peer_stats; + struct sir_peer_info_resp *peer_info_rsp; + + if (pMsg == NULL) { + sme_err("Empty message for SME"); + return status; + } + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_warn("Locking failed, bailing out"); + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + return status; + } + if (!SME_IS_START(pMac)) { + 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) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case eWNI_SME_HO_FAIL_IND: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("LFR3: Rcvd eWNI_SME_HO_FAIL_IND")); + csr_process_ho_fail_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; +#endif + case WNI_CFG_SET_CNF: + case WNI_CFG_DNLD_CNF: + case WNI_CFG_GET_RSP: + case WNI_CFG_ADD_GRP_ADDR_CNF: + case WNI_CFG_DEL_GRP_ADDR_CNF: + break; + 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(pMac, 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: + if (pMsg->bodyptr) { + status = sme_rrm_msg_processor(pMac, pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_ADD_STA_SELF_RSP: + if (pMsg->bodyptr) { + status = csr_process_add_sta_session_rsp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_DEL_STA_SELF_RSP: + if (pMsg->bodyptr) { + status = csr_process_del_sta_session_rsp(pMac, + pMsg->bodyptr); + qdf_mem_free(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 *)pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + +#ifdef WLAN_FEATURE_11W + case eWNI_SME_UNPROT_MGMT_FRM_IND: + if (pMsg->bodyptr) { + sme_unprotected_mgmt_frm_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; +#endif +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_TSM_IE_IND: + if (pMsg->bodyptr) { + sme_tsm_ie_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_ROAM_SCAN_OFFLOAD_RSP: + status = csr_roam_offload_scan_rsp_hdlr((void *)pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_IBSS_PEER_INFO_RSP: + if (pMsg->bodyptr) { + sme_ibss_peer_info_response_handler(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_READY_TO_SUSPEND_IND: + if (pMsg->bodyptr) { + sme_process_ready_to_suspend(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + case eWNI_SME_READY_TO_EXTWOW_IND: + if (pMsg->bodyptr) { + sme_process_ready_to_ext_wow(pMac, 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 (pMac->sme.pAutoShutdownNotificationCb) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Auto shutdown notification")); + pMac->sme.pAutoShutdownNotificationCb(); + } + qdf_mem_free(pMsg->bodyptr); + break; +#endif + case eWNI_SME_DFS_RADAR_FOUND: + case eWNI_SME_DFS_CAC_COMPLETE: + case eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND: + status = dfs_msg_processor(pMac, pMsg); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_CHANNEL_CHANGE_RSP: + if (pMsg->bodyptr) { + status = sme_process_channel_change_resp(pMac, + 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(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_GET_PEER_INFO_IND: + if (pMac->sme.pget_peer_info_ind_cb) + pMac->sme.pget_peer_info_ind_cb(pMsg->bodyptr, + pMac->sme.pget_peer_info_cb_context); + if (pMsg->bodyptr) { + peer_info_rsp = (struct sir_peer_info_resp *) + (pMsg->bodyptr); + peer_stats = (struct sir_peer_info *) + (peer_info_rsp->info); + if (peer_stats) { + pMac->peer_rssi = peer_stats[0].rssi; + pMac->peer_txrate = peer_stats[0].tx_rate; + pMac->peer_rxrate = peer_stats[0].rx_rate; + } + } + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_GET_PEER_INFO_EXT_IND: + if (pMac->sme.pget_peer_info_ext_ind_cb) + pMac->sme.pget_peer_info_ext_ind_cb(pMsg->bodyptr, + pMac->sme.pget_peer_info_ext_cb_context); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_CSA_OFFLOAD_EVENT: + if (pMsg->bodyptr) { + csr_scan_flush_bss_entry(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } + break; + case eWNI_SME_TSF_EVENT: + if (pMac->sme.get_tsf_cb) { + pMac->sme.get_tsf_cb(pMac->sme.get_tsf_cxt, + (struct stsf *)pMsg->bodyptr); + } + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + break; +#ifdef WLAN_FEATURE_NAN + case eWNI_SME_NAN_EVENT: + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_WMA_MSG, + NO_SESSION, pMsg->type)); + if (pMsg->bodyptr) { + sme_nan_event(MAC_HANDLE(pMac), pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } + break; +#endif /* WLAN_FEATURE_NAN */ + case eWNI_SME_LINK_STATUS_IND: + { + tAniGetLinkStatus *pLinkStatus = + (tAniGetLinkStatus *) pMsg->bodyptr; + if (pLinkStatus) { + if (pMac->sme.link_status_callback) + pMac->sme.link_status_callback( + pLinkStatus->linkStatus, + pMac->sme.link_status_context); + + pMac->sme.link_status_callback = NULL; + pMac->sme.link_status_context = NULL; + qdf_mem_free(pLinkStatus); + } + break; + } + case eWNI_SME_MSG_GET_TEMPERATURE_IND: + if (pMac->sme.pGetTemperatureCb) + pMac->sme.pGetTemperatureCb(pMsg->bodyval, + pMac->sme.pTemperatureCbContext); + break; + case eWNI_SME_SNR_IND: + { + tAniGetSnrReq *pSnrReq = (tAniGetSnrReq *) pMsg->bodyptr; + + if (pSnrReq) { + if (pSnrReq->snrCallback) { + ((tCsrSnrCallback) + (pSnrReq->snrCallback)) + (pSnrReq->snr, pSnrReq->staId, + pSnrReq->pDevContext); + } + qdf_mem_free(pSnrReq); + } + break; + } +#ifdef FEATURE_WLAN_EXTSCAN + case eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND: + if (pMac->sme.pExtScanIndCb) + pMac->sme.pExtScanIndCb(pMac->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 (pMac->sme.pExtScanIndCb) + pMac->sme.pExtScanIndCb(pMac->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(pMac, + 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(pMac, + 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(pMac, + 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(pMac, + 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 (pMac->sme.set_thermal_level_cb) + pMac->sme.set_thermal_level_cb(pMac->hdd_handle, + pMsg->bodyval); + break; + case eWNI_SME_EXT_CHANGE_CHANNEL_IND: + status = sme_extended_change_channel_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_SET_ANTENNA_MODE_RESP: + if (pMsg->bodyptr) { + status = sme_process_antenna_mode_resp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_LOST_LINK_INFO_IND: + if (pMac->sme.lost_link_info_cb) + pMac->sme.lost_link_info_cb(pMac->hdd_handle, + (struct sir_lost_link_info *)pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_RSO_CMD_STATUS_IND: + if (pMac->sme.rso_cmd_status_cb) + pMac->sme.rso_cmd_status_cb(pMac->hdd_handle, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWMI_SME_LL_STATS_IND: + if (pMac->sme.link_layer_stats_ext_cb) + pMac->sme.link_layer_stats_ext_cb(pMac->hdd_handle, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_BT_ACTIVITY_INFO_IND: + if (pMac->sme.bt_activity_info_cb) + pMac->sme.bt_activity_info_cb(pMac->hdd_handle, + pMsg->bodyval); + break; + case eWNI_SME_HIDDEN_SSID_RESTART_RSP: + if (pMac->sme.hidden_ssid_cb) + pMac->sme.hidden_ssid_cb(pMac->hdd_handle, pMsg->bodyval); + else + sme_err("callback is NULL"); + break; + case eWNI_SME_ANTENNA_ISOLATION_RSP: + if (pMsg->bodyptr) { + if (pMac->sme.get_isolation_cb) + pMac->sme.get_isolation_cb( + (struct sir_isolation_resp *)pMsg->bodyptr, + pMac->sme.get_isolation_cb_context); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + 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(pMac, 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(&pMac->sme); + return status; +} + +QDF_STATUS sme_mc_process_handler(struct scheduler_msg *msg) +{ + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + + if (mac_ctx == NULL) { + 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(tpAniSirGlobal 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); + } else { + sme_err("Callback does not exisit"); + } + + found = csr_nonscan_active_ll_remove_entry(mac, entry, LL_ACCESS_LOCK); + if (found) { + /* Now put this command back on the avilable 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; + tpAniSirGlobal 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 + * + * hHal - 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(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS fail_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (!pMac) + return QDF_STATUS_E_FAILURE; + + /* Note: pSession will be invalid from here on, do not access */ + status = csr_close(pMac); + 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(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Qos close failed with status: %d", status); + fail_status = status; + } +#endif + status = sme_ps_close(hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_ps_close failed status: %d", status); + fail_status = status; + } + + status = rrm_close(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("RRM close failed with status: %d", status); + fail_status = status; + } + + free_sme_cmd_list(pMac); + + if (!QDF_IS_STATUS_SUCCESS + (qdf_mutex_destroy(&pMac->sme.lkSmeGlobalLock))) + fail_status = QDF_STATUS_E_FAILURE; + + if (!QDF_IS_STATUS_SUCCESS(fail_status)) + status = fail_status; + + pMac->sme.state = SME_STATE_STOP; + + return status; +} + +/** + * sme_remove_bssid_from_scan_list() - wrapper to remove the bssid from + * scan list + * @hal: hal context. + * @bssid: bssid to be removed + * + * This function remove the given bssid from scan list. + * + * Return: QDF status. + */ +QDF_STATUS sme_remove_bssid_from_scan_list(tHalHandle hal, + tSirMacAddr bssid) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_remove_bssid_from_scan_list(mac_ctx, bssid); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + + +/* + * sme_scan_get_result + * A wrapper function to request scan results from CSR. + * This is a synchronous call + * + * pFilter - If pFilter is NULL, all cached results are returned + * phResult - an object for the result. + * Return QDF_STATUS + */ +QDF_STATUS sme_scan_get_result(tHalHandle hHal, uint8_t sessionId, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_get_result(pMac, pFilter, phResult); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_scan_get_result_for_bssid(tHalHandle hal_handle, + struct qdf_mac_addr *bssid, + tCsrScanResultInfo *res) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_get_result_for_bssid(mac_ctx, bssid, res); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +/** + * sme_get_ap_channel_from_scan() - a wrapper function to get + * AP's channel id from + * CSR by filtering the + * result which matches + * our roam profile. + * @profile: SAP profile + * @ap_chnl_id: pointer to channel id of SAP. Fill the value after finding the + * best ap from scan cache. + * + * This function is written to get AP's channel id from CSR by filtering + * the result which matches our roam profile. This is a synchronous call. + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_get_ap_channel_from_scan(void *profile, + tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id) +{ + return sme_get_ap_channel_from_scan_cache((struct csr_roam_profile *) + profile, + scan_cache, + ap_chnl_id); +} + +/** + * sme_get_ap_channel_from_scan_cache() - a wrapper function to get AP's + * channel id from CSR by filtering the + * result which matches our roam profile. + * @profile: SAP adapter + * @ap_chnl_id: pointer to channel id of SAP. Fill the value after finding the + * best ap from scan cache. + * + * This function is written to get AP's channel id from CSR by filtering + * the result which matches our roam profile. This is a synchronous call. + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_get_ap_channel_from_scan_cache( + struct csr_roam_profile *profile, tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = sme_get_mac_context(); + tCsrScanResultFilter *scan_filter = NULL; + tScanResultHandle filtered_scan_result = NULL; + tSirBssDescription first_ap_profile; + + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("mac_ctx is NULL")); + return QDF_STATUS_E_FAILURE; + } + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("scan_filter mem alloc failed")); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&first_ap_profile, sizeof(tSirBssDescription)); + if (NULL == profile) { + scan_filter->EncryptionType.numEntries = 1; + scan_filter->EncryptionType.encryptionType[0] + = eCSR_ENCRYPT_TYPE_NONE; + } else { + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(mac_ctx, + profile, + scan_filter); + } + + if (QDF_STATUS_SUCCESS == status) { + /* Save the WPS info */ + if (NULL != profile) { + scan_filter->bWPSAssociation = + profile->bWPSAssociation; + scan_filter->bOSENAssociation = + profile->bOSENAssociation; + } else { + scan_filter->bWPSAssociation = 0; + scan_filter->bOSENAssociation = 0; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Preparing the profile filter failed")); + qdf_mem_free(scan_filter); + return QDF_STATUS_E_FAILURE; + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + status = csr_scan_get_result(mac_ctx, scan_filter, + &filtered_scan_result); + if (QDF_STATUS_SUCCESS == status) { + csr_get_bssdescr_from_scan_handle(filtered_scan_result, + &first_ap_profile); + *scan_cache = filtered_scan_result; + if (0 != first_ap_profile.channelId) { + *ap_chnl_id = first_ap_profile.channelId; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("Found best AP & its on chnl[%d]"), + first_ap_profile.channelId); + } else { + /* + * This means scan result is empty + * so set the channel to zero, caller should + * take of zero channel id case. + */ + *ap_chnl_id = 0; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Scan is empty, set chnl to 0")); + status = QDF_STATUS_E_FAILURE; + } + } else { + sme_err("Failed to get scan get result"); + status = QDF_STATUS_E_FAILURE; + } + csr_free_scan_filter(mac_ctx, scan_filter); + sme_release_global_lock(&mac_ctx->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Aquiring lock failed")); + csr_free_scan_filter(mac_ctx, scan_filter); + status = QDF_STATUS_E_FAILURE; + } + qdf_mem_free(scan_filter); + return status; +} + +/** + * sme_store_joinreq_param() - This function will pass station's join + * request to store to csr. + * @hal_handle: pointer to hal context. + * @profile: pointer to station's roam profile. + * @scan_cache: pointer to station's scan cache. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will pass station's join request further down to csr + * to store it. this stored parameter will be used later. + * + * Return: true or false based on function's overall success. + **/ +bool sme_store_joinreq_param(tHalHandle hal_handle, + struct csr_roam_profile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool ret_status = true; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + if (false == csr_store_joinreq_param(mac_ctx, profile, + scan_cache, roam_id, session_id)) + ret_status = false; + sme_release_global_lock(&mac_ctx->sme); + } else { + ret_status = false; + } + + return ret_status; +} + +/** + * sme_clear_joinreq_param() - This function will pass station's clear + * the join request to csr. + * @hal_handle: pointer to hal context. + * @session_id: station's session id. + * + * This function will pass station's clear join request further down to csr + * to cleanup. + * + * Return: true or false based on function's overall success. + **/ +bool sme_clear_joinreq_param(tHalHandle hal_handle, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool ret_status = true; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + if (false == csr_clear_joinreq_param(mac_ctx, + session_id)) + ret_status = false; + sme_release_global_lock(&mac_ctx->sme); + } else { + ret_status = false; + } + + return ret_status; +} + +/** + * sme_issue_stored_joinreq() - This function will issues station's stored + * the join request to csr. + * @hal_handle: pointer to hal context. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will issue station's stored join request further down to csr + * to proceed forward. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + **/ +QDF_STATUS sme_issue_stored_joinreq(tHalHandle hal_handle, + uint32_t *roam_id, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS ret_status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + if (QDF_STATUS_SUCCESS != csr_issue_stored_joinreq(mac_ctx, + roam_id, + session_id)) { + ret_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + csr_clear_joinreq_param(mac_ctx, session_id); + ret_status = QDF_STATUS_E_FAILURE; + } + return ret_status; +} + +/* + * sme_scan_flush_result() - + * A wrapper function to request CSR to clear scan results. + * This is a synchronous call + * + * Return QDF_STATUS + */ +QDF_STATUS sme_scan_flush_result(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + 0, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_flush_result(pMac); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_filter_scan_results() - + * A wrapper function to request CSR to clear scan results. + * This is a synchronous call + * + * tHalHandle - HAL context handle + * sessionId - session id + * Return QDF_STATUS + */ +QDF_STATUS sme_filter_scan_results(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_scan_filter_results(pMac); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_scan_flush_p2p_result(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_flush_selective_result(pMac, true); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_scan_result_get_first() - + * A wrapper function to request CSR to returns the first element of + * scan result. + * This is a synchronous call + * + * hScanResult - returned from csr_scan_get_result + * Return tCsrScanResultInfo * - NULL if no result + */ +tCsrScanResultInfo *sme_scan_result_get_first(tHalHandle hHal, + tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrScanResultInfo *pRet = NULL; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pRet = csr_scan_result_get_first(pMac, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return pRet; +} + +/* + * sme_scan_result_get_next() - + * A wrapper function to request CSR to returns the next element of + * scan result. It can be called without calling csr_scan_result_get_first first + * This is a synchronous call + * + * hScanResult - returned from csr_scan_get_result + * Return Null if no result or reach the end + */ +tCsrScanResultInfo *sme_scan_result_get_next(tHalHandle hHal, + tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrScanResultInfo *pRet = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pRet = csr_scan_result_get_next(pMac, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return pRet; +} + +/* + * sme_scan_result_purge() - + * A wrapper function to request CSR to remove all items(tCsrScanResult) + * in the list and free memory for each item + * This is a synchronous call + * + * hScanResult - returned from csr_scan_get_result. hScanResult is + * considered gone by + * calling this function and even before this function reutrns. + * Return QDF_STATUS + */ +QDF_STATUS sme_scan_result_purge(tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = sme_get_mac_context(); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_result_purge(mac_ctx, hScanResult); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.phyMode; +} + +/* + * sme_get_channel_bonding_mode5_g() - get the channel bonding mode for 5G band + * + * hHal - HAL handle + * mode - channel bonding mode + * + * Return QDF_STATUS + */ +QDF_STATUS sme_get_channel_bonding_mode5_g(tHalHandle hHal, uint32_t *mode) +{ + tSmeConfigParams *smeConfig; + + if (!mode) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: invalid mode", __func__); + return QDF_STATUS_E_FAILURE; + } + + smeConfig = qdf_mem_malloc(sizeof(*smeConfig)); + if (!smeConfig) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to alloc smeConfig", __func__); + return QDF_STATUS_E_NOMEM; + } + + if (sme_get_config_param(hHal, smeConfig) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_get_config_param failed", __func__); + qdf_mem_free(smeConfig); + return QDF_STATUS_E_FAILURE; + } + + *mode = smeConfig->csrConfig.channelBondingMode5GHz; + qdf_mem_free(smeConfig); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_get_channel_bonding_mode24_g() - get the channel bonding mode for 2.4G + * band + * + * hHal - HAL handle + * mode - channel bonding mode + * + * Return QDF_STATUS + */ +QDF_STATUS sme_get_channel_bonding_mode24_g(tHalHandle hHal, uint32_t *mode) +{ + tSmeConfigParams *smeConfig; + + if (!mode) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: invalid mode", __func__); + return QDF_STATUS_E_FAILURE; + } + + smeConfig = qdf_mem_malloc(sizeof(*smeConfig)); + if (!smeConfig) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to alloc smeConfig", __func__); + return QDF_STATUS_E_NOMEM; + } + + if (sme_get_config_param(hHal, smeConfig) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_get_config_param failed", __func__); + qdf_mem_free(smeConfig); + return QDF_STATUS_E_FAILURE; + } + + *mode = smeConfig->csrConfig.channelBondingMode24GHz; + qdf_mem_free(smeConfig); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_roam_connect() - + * A wrapper function to request CSR to inititiate an association + * This is an asynchronous call. + * + * sessionId - the sessionId returned by sme_open_session. + * pProfile - description of the network to which to connect + * hBssListIn - a list of BSS descriptor to roam to. It is returned + * from csr_scan_get_result + * pRoamId - to get back the request ID + * Return QDF_STATUS + */ +QDF_STATUS sme_roam_connect(tHalHandle hHal, uint8_t sessionId, + struct csr_roam_profile *pProfile, + uint32_t *pRoamId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (!pMac) + return QDF_STATUS_E_FAILURE; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_CONNECT, sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_connect(pMac, sessionId, pProfile, + pRoamId); + } else { + sme_err("Invalid sessionID: %d", sessionId); + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } else { + sme_err("sme_acquire_global_lock failed"); + } + + return status; +} + +/* + * sme_set_phy_mode() - + * Changes the PhyMode. + * + * hHal - The handle returned by mac_open. + * phyMode new phyMode which is to set + * Return QDF_STATUS SUCCESS. + */ +QDF_STATUS sme_set_phy_mode(tHalHandle hHal, eCsrPhyMode phyMode) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->roam.configParam.phyMode = phyMode; + pMac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(NULL, + pMac->roam.configParam.phyMode, + pMac->roam.configParam. + ProprietaryRatesEnabled); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_roam_reassoc() - + * A wrapper function to request CSR to inititiate a re-association + * + * pProfile - can be NULL to join the currently connected AP. In that + * case modProfileFields should carry the modified field(s) which could trigger + * reassoc + * modProfileFields - fields which are part of tCsrRoamConnectedProfile + * that might need modification dynamically once STA is up & running and this + * could trigger a reassoc + * pRoamId - to get back the request ID + * Return QDF_STATUS + */ +QDF_STATUS sme_roam_reassoc(tHalHandle hHal, uint8_t sessionId, + struct csr_roam_profile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId, bool fForce) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_REASSOC, sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + if ((NULL == pProfile) && (fForce == 1)) + status = csr_reassoc(pMac, sessionId, + &modProfileFields, pRoamId, + fForce); + else + status = csr_roam_reassoc(pMac, sessionId, + pProfile, + modProfileFields, pRoamId); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_roam_connect_to_last_profile() - + * A wrapper function to request CSR to disconnect and reconnect with + * the same profile + * This is an asynchronous call. + * + * Return QDF_STATUS. It returns fail if currently connected + */ +QDF_STATUS sme_roam_connect_to_last_profile(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_connect_to_last_profile(pMac, + sessionId); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_roam_disconnect(tHalHandle hal, uint8_t session_id, + eCsrRoamDisconnectReason reason) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT, session_id, + reason)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id)) + status = csr_roam_disconnect(mac_ctx, session_id, + reason); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +/* sme_dhcp_done_ind() - send dhcp done ind + * @hal: hal context + * @session_id: session id + * + * Return: void. + */ +void sme_dhcp_done_ind(tHalHandle hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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; +} + +/* + * sme_roam_stop_bss() - + * To stop BSS for Soft AP. This is an asynchronous API. + * + * hHal - Global structure + * sessionId - sessionId of SoftAP + * Return QDF_STATUS SUCCESS Roam callback will be called to indicate + * actual results + */ +QDF_STATUS sme_roam_stop_bss(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_issue_stop_bss_cmd(pMac, sessionId, + false); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_roam_disconnect_sta() - disassociate a station + * @hHal: 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(tHalHandle hHal, uint8_t sessionId, + struct csr_del_sta_params *p_del_sta_params) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_issue_disassociate_sta_cmd(pMac, + sessionId, p_del_sta_params); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_roam_deauth_sta() - deauthenticate a station + * @hHal: 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(tHalHandle hHal, uint8_t sessionId, + struct csr_del_sta_params *pDelStaParams) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + 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(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = + csr_roam_issue_deauth_sta_cmd(pMac, sessionId, + pDelStaParams); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_roam_get_associated_stas() - + * To probe the list of associated stations from various modules + * of CORE stack. + * This is an asynchronous API. + * + * sessionId - sessionId of SoftAP + * modId - Module from whom list of associtated stations is + * to be probed. If an invalid module is passed then + * by default QDF_MODULE_ID_PE will be probed. + * pUsrContext - Opaque HDD context + * pfnSapEventCallback - Sap event callback in HDD + * pAssocBuf - Caller allocated memory to be filled with associatd + * stations info + * Return QDF_STATUS + */ +QDF_STATUS sme_roam_get_associated_stas(tHalHandle hHal, uint8_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = + csr_roam_get_associated_stas(pMac, sessionId, + modId, + pUsrContext, + pfnSapEventCallback, + pAssocStasBuf); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_roam_get_connect_state() - + * A wrapper function to request CSR to return the current connect state + * of Roaming + * This is a synchronous call. + * + * Return QDF_STATUS + */ +QDF_STATUS sme_roam_get_connect_state(tHalHandle hHal, uint8_t sessionId, + eCsrConnectState *pState) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_get_connect_state(pMac, sessionId, + pState); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_roam_get_connect_profile() - + * A wrapper function to request CSR to return the current connect + * profile. Caller must call csr_roam_free_connect_profile after it is done + * and before reuse for another csr_roam_get_connect_profile call. + * This is a synchronous call. + * + * pProfile - pointer to a caller allocated structure + * tCsrRoamConnectedProfile + * eturn QDF_STATUS. Failure if not connected + */ +QDF_STATUS sme_roam_get_connect_profile(tHalHandle hHal, uint8_t sessionId, + tCsrRoamConnectedProfile *pProfile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_get_connect_profile(pMac, sessionId, + pProfile); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_roam_free_connect_profile - a wrapper function to request CSR to free and + * reinitialize the profile returned previously by csr_roam_get_connect_profile. + * + * @profile - pointer to a caller allocated structure tCsrRoamConnectedProfile + * + * Return: none + */ +void sme_roam_free_connect_profile(tCsrRoamConnectedProfile *profile) +{ + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE, + NO_SESSION, 0)); + csr_roam_free_connect_profile(profile); +} + +/* + * sme_roam_set_pmkid_cache() - + * A wrapper function to request CSR to return the PMKID candidate list + * This is a synchronous call. + + * pPMKIDCache - caller allocated buffer point to an array of + * tPmkidCacheInfo + * numItems - a variable that has the number of tPmkidCacheInfo + * allocated when retruning, this is either the number needed + * or number of items put into pPMKIDCache + * update_entire_cache - this bool value specifies if the entire pmkid + * cache should be overwritten or should it be + * updated entry by entry. + * Return QDF_STATUS - when fail, it usually means the buffer allocated is not + * big enough and pNumItems has the number of + * tPmkidCacheInfo. + * \Note: pNumItems is a number of tPmkidCacheInfo, + * not sizeof(tPmkidCacheInfo) * something + */ +QDF_STATUS sme_roam_set_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, bool update_entire_cache) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE, sessionId, + numItems)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_set_pmkid_cache(pMac, sessionId, + pPMKIDCache, + numItems, update_entire_cache); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_roam_del_pmkid_from_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pmksa, + bool flush_cache) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE, + sessionId, flush_cache)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_del_pmkid_from_cache(pMac, sessionId, + pmksa, flush_cache); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void sme_get_pmk_info(tHalHandle hal, uint8_t session_id, + tPmkidCacheInfo *pmk_cache) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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); + } +} +#else +static inline +void sme_get_pmk_info(tHalHandle hal, uint8_t session_id, + tPmkidCacheInfo *pmk_cache) +{} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * \fn sme_roam_set_psk_pmk + * \brief a wrapper function to request CSR to save PSK/PMK + * This is a synchronous call. + * \param hHal - Global structure + * \param sessionId - SME sessionId + * \param pPSK_PMK - pointer to an array of Psk[]/Pmk + * \param pmk_len - Length could be only 16 bytes in case if LEAP + * connections. Need to pass this information to + * firmware. + * \return QDF_STATUS -status whether PSK/PMK is set or not + */ +QDF_STATUS sme_roam_set_psk_pmk(tHalHandle hHal, uint8_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_set_psk_pmk(pMac, sessionId, pPSK_PMK, + pmk_len); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif + +QDF_STATUS sme_roam_get_wpa_rsn_req_ie(tHalHandle hal, uint8_t session_id, + uint32_t *len, uint8_t *buf) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac, session_id)) + status = csr_roam_get_wpa_rsn_req_ie(mac, session_id, + len, buf); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +QDF_STATUS sme_roam_get_wpa_rsn_rsp_ie(tHalHandle hal, uint8_t session_id, + uint32_t *len, uint8_t *buf) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac, session_id)) + status = csr_roam_get_wpa_rsn_rsp_ie(mac, session_id, + len, buf); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/* + * sme_roam_get_num_pmkid_cache() - + * A wrapper function to request CSR to return number of PMKID cache + * entries + * This is a synchronous call. + * + * Return uint32_t - the number of PMKID cache entries + */ +uint32_t sme_roam_get_num_pmkid_cache(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint32_t numPmkidCache = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + numPmkidCache = + csr_roam_get_num_pmkid_cache(pMac, sessionId); + status = QDF_STATUS_SUCCESS; + } else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return numPmkidCache; +} + +/* + * sme_roam_get_pmkid_cache() - + * A wrapper function to request CSR to return PMKID cache from CSR + * This is a synchronous call. + * + * pNum - caller allocated memory that has the space of the number of + * pBuf tPmkidCacheInfo as input. Upon returned, *pNum has the + * needed or actually number in tPmkidCacheInfo. + * pPmkidCache - Caller allocated memory that contains PMKID cache, if + * any, upon return + * Return QDF_STATUS - when fail, it usually means the buffer allocated is not + * big enough + */ +QDF_STATUS sme_roam_get_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_roam_get_pmkid_cache(pMac, sessionId, pNum, + pPmkidCache); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * 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(tHalHandle hHal, tSmeConfigParams *pParam) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_config_param(pMac, &pParam->csrConfig); + if (status != QDF_STATUS_SUCCESS) { + sme_err("csr_get_config_param failed"); + sme_release_global_lock(&pMac->sme); + return status; + } + qdf_mem_copy(&pParam->rrmConfig, + &pMac->rrm.rrmSmeContext.rrmConfig, + sizeof(pMac->rrm.rrmSmeContext.rrmConfig)); + pParam->snr_monitor_enabled = pMac->snr_monitor_enabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_cfg_set_int() - Sets the cfg parameter value. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @value: value to be saved in the cfg parameter. + * + * This function sets the string value in cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_set_int(tHalHandle hal, uint16_t cfg_id, uint32_t value) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS != cfg_set_int(pmac, cfg_id, value)) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_set_str() - Sets the cfg parameter string. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @str: Pointer to the string buffer. + * @length: Length of the string. + * + * This function sets the string value in cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_set_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t length) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS != cfg_set_str(pmac, cfg_id, str, length)) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_get_int() - Gets the cfg parameter value. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @cfg_value: Pointer to variable in which cfg value + * will be saved. + * + * This function gets the value of the cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_get_int(tHalHandle hal, uint16_t cfg_id, uint32_t *cfg_value) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_int(pmac, cfg_id, cfg_value)) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_get_str() - Gets the cfg parameter string. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @str: Pointer to the string buffer. + * @length: Pointer to length of the string. + * + * This function gets the string value of the cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_get_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t *length) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS != wlan_cfg_get_str(pmac, cfg_id, str, length)) + status = QDF_STATUS_E_INVAL; + + return status; +} + +/* + * sme_get_modify_profile_fields() - + * HDD or SME - QOS calls this function to get the current values of + * connected profile fields, changing which can cause reassoc. + * This function must be called after CFG is downloaded and STA is in connected + * state. Also, make sure to call this function to get the current profile + * fields before calling the reassoc. So that pModifyProfileFields will have + * all the latest values plus the one(s) has been updated as part of reassoc + * request. + * + * pModifyProfileFields - pointer to the connected profile fields + * changing which can cause reassoc + * Return QDF_STATUS + */ +QDF_STATUS sme_get_modify_profile_fields(tHalHandle hHal, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + status = csr_get_modify_profile_fields(pMac, sessionId, + pModifyProfileFields); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_set_dhcp_till_power_active_flag() - + * Sets/Clears DHCP related flag to disable/enable auto PS + * + * hal - The handle returned by mac_open. + */ +void sme_set_dhcp_till_power_active_flag(tHalHandle hal, uint8_t flag) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct ps_global_info *ps_global_info = &mac->sme.ps_global_info; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG, NO_SESSION, + flag)); + /* Set/Clear the DHCP flag which will disable/enable auto PS */ + ps_global_info->remain_in_power_active_till_dhcp = flag; +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * sme_register_oem_data_rsp_callback() - Register a routine of + * type send_oem_data_rsp_msg + * @h_hal: 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(tHalHandle h_hal, + sme_send_oem_data_rsp_msg callback) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(h_hal); + + pmac->sme.oem_data_rsp_callback = callback; + + return status; + +} + +/** + * sme_deregister_oem_data_rsp_callback() - De-register OEM datarsp callback + * @h_hal: 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(tHalHandle h_hal) +{ + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + pmac = PMAC_STRUCT(h_hal); + + pmac->sme.oem_data_rsp_callback = NULL; +} + +/** + * sme_oem_update_capability() - update UMAC's oem related capability. + * @hal: 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(tHalHandle hal, + struct sme_oem_capability *cap) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + uint8_t *bytes; + + bytes = pmac->rrm.rrmSmeContext.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 + * @hal: 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(tHalHandle hal, + struct sme_oem_capability *cap) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + uint8_t *bytes; + + bytes = pmac->rrm.rrmSmeContext.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_roam_set_key() - To set encryption key. + * @hal: hal global context + * @session_id: session id + * @set_key: pointer to a caller allocated object of tCsrSetContextInfo + * @ptr_roam_id: Upon success return, this is the id caller can use to + * identify the request in roamcallback + * + * This function should be called only when connected. This is an asynchronous + * API. + * + * Return: Status of operation + */ +QDF_STATUS sme_roam_set_key(tHalHandle hal, uint8_t session_id, + tCsrRoamSetKey *set_key, uint32_t *ptr_roam_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint32_t roam_id; + struct csr_roam_session *session = NULL; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_SET_KEY, + session_id, 0)); + if (set_key->keyLength > CSR_MAX_KEY_LEN) { + sme_err("Invalid key length: %d", set_key->keyLength); + return QDF_STATUS_E_FAILURE; + } + /*Once Setkey is done, we can go in BMPS */ + if (set_key->keyLength) + ps_global_info->remain_in_power_active_till_dhcp = false; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + if (ptr_roam_id) + *ptr_roam_id = roam_id; + + sme_debug("keyLength: %d", set_key->keyLength); + + sme_debug("Session_id: %d roam_id: %d", session_id, roam_id); + 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 QDF_STATUS_E_FAILURE; + } + if (CSR_IS_INFRA_AP(&session->connectedProfile) + && set_key->keyDirection == eSIR_TX_DEFAULT) { + if ((eCSR_ENCRYPT_TYPE_WEP40 == set_key->encType) + || (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + set_key->encType)) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + if ((eCSR_ENCRYPT_TYPE_WEP104 == set_key->encType) + || (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + set_key->encType)) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } + } + status = csr_roam_set_key(mac_ctx, session_id, set_key, roam_id); + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/** + * sme_roam_set_default_key_index - To set default wep key idx + * @hal: pointer to hal handler + * @session_id: session id + * @default_idx: default wep key index + * + * This function prepares a message and post to WMA to set wep default + * key index + * + * Return: Success:QDF_STATUS_SUCCESS Failure: Error value + */ +QDF_STATUS sme_roam_set_default_key_index(tHalHandle hal, uint8_t session_id, + uint8_t default_idx) +{ + struct scheduler_msg msg = {0}; + struct wep_update_default_key_idx *update_key; + + update_key = qdf_mem_malloc(sizeof(*update_key)); + if (!update_key) { + sme_err("Failed to allocate memory for update key"); + return QDF_STATUS_E_NOMEM; + } + + update_key->session_id = session_id; + update_key->default_idx = default_idx; + + msg.type = WMA_UPDATE_WEP_DEFAULT_KEY; + msg.reserved = 0; + msg.bodyptr = (void *)update_key; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + sme_err("Failed to post WMA_UPDATE_WEP_DEFAULT_KEY to WMA"); + qdf_mem_free(update_key); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + + +/** + * sme_get_rssi() - API to retrieve current RSSI + * @hHal: HAL handle for device + * @callback: SME sends back the requested stats using the callback + * @staId: The station ID for which the RSSI is requested for + * @bssid: The bssid of the connected session + * @lastRSSI: RSSI value at time of request. In case fw cannot provide + * RSSI, do not hold up but return this value. + * @pContext: user context to be passed back along with the callback + * + * A wrapper function that client calls to register a callback to get RSSI + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_rssi(tHalHandle hHal, + tCsrRssiCallback callback, uint8_t staId, + struct qdf_mac_addr bssId, int8_t lastRSSI, + void *pContext) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_RSSI, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_rssi(pMac, callback, + staId, bssId, lastRSSI, + pContext); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * 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(tHalHandle hHal, + tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_snr(pMac, callback, staId, bssId, pContext); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifndef QCA_SUPPORT_CP_STATS +/* + * sme_get_statistics() - + * A wrapper function that client calls to register a callback to get + * different PHY level statistics from CSR. + * + * requesterId - different client requesting for statistics, + * HDD, UMA/GAN etc + * statsMask - The different category/categories of stats requester + * is looking for + * callback - SME sends back the requested stats using the callback + * periodicity - If requester needs periodic update in millisec, 0 means + * it's an one time request + * cache - If requester is happy with cached stats + * staId - The station ID for which the stats is requested for + * pContext - user context to be passed back along with the callback + * sessionId - sme session interface + * Return QDF_STATUS + */ +QDF_STATUS sme_get_statistics(tHalHandle hHal, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint8_t staId, void *pContext, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_statistics(pMac, requesterId, statsMask, + callback, staId, pContext, + sessionId); + sme_release_global_lock(&pMac->sme); + } + + return status; + +} +#endif + +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; + tpAniSirGlobal 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_err("Malloc failure"); + 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_get_country_code() - + * To return the current country code. If no country code is applied, + * default country code is used to fill the buffer. + * If 11d supported is turned off, an error is return and the last + * applied/default country code is used. + * This is a synchronous API. + * + * pBuf - pointer to a caller allocated buffer for returned country code. + * pbLen For input, this parameter indicates how big is the buffer. + * Upon return, this parameter has the number of bytes for + * country. If pBuf doesn't have enough space, this function + * returns fail status and this parameter contains the number + * that is needed. + * + * Return QDF_STATUS SUCCESS. + * + * FAILURE or RESOURCES The API finished and failed. + */ +QDF_STATUS sme_get_country_code(tHalHandle hHal, uint8_t *pBuf, uint8_t *pbLen) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE, NO_SESSION, 0)); + + return csr_get_country_code(pMac, pBuf, pbLen); +} + +/* some support functions */ +bool sme_is11d_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return wlan_reg_11d_enabled_on_host(pMac->psoc); +} + +bool sme_is11h_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is11h_supported(pMac); +} + +bool sme_is_wmm_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is_wmm_supported(pMac); +} + +/* + * sme_generic_change_country_code() - + * Change Country code from upperlayer during WLAN driver operation. + * This is a synchronous API. + * + * hHal - 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(tHalHandle hHal, + uint8_t *pCountry) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg msg = {0}; + tAniGenericChangeCountryCodeReq *pMsg; + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg = qdf_mem_malloc(sizeof(tAniGenericChangeCountryCodeReq)); + + if (NULL == pMsg) { + sme_err("sme_generic_change_country_code: failed to allocate mem for req"); + sme_release_global_lock(&pMac->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)) { + sme_err("sme_generic_change_country_code failed to post msg to self"); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_dhcp_start_ind() - + * API to signal the FW about the DHCP Start event. + * + * hHal - HAL handle for device. + * 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(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + tAniDHCPInd *pMsg; + struct csr_roam_session *pSession; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("Session: %d not found", sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + pSession->dhcp_done = false; + + pMsg = (tAniDHCPInd *) qdf_mem_malloc(sizeof(tAniDHCPInd)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp start", + __func__); + sme_release_global_lock(&pMac->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); + qdf_copy_macaddr(&pMsg->peerMacAddr, + &pSession->connectedProfile.bssid); + + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post DHCP Start MSG fail", __func__); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_dhcp_stop_ind() - + * API to signal the FW about the DHCP complete event. + * + * hHal - HAL handle for device. + * 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(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + tAniDHCPInd *pMsg; + struct csr_roam_session *pSession; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("Session: %d not found", sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + pSession->dhcp_done = true; + + pMsg = (tAniDHCPInd *) qdf_mem_malloc(sizeof(tAniDHCPInd)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp stop", + __func__); + sme_release_global_lock(&pMac->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); + qdf_copy_macaddr(&pMsg->peerMacAddr, + &pSession->connectedProfile.bssid); + + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post DHCP Stop MSG fail", __func__); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_TXFailMonitorStopInd() - + * API to signal the FW to start monitoring TX failures + * + * Return QDF_STATUS SUCCESS. + * FAILURE or RESOURCES The API finished and failed. + */ +QDF_STATUS sme_tx_fail_monitor_start_stop_ind(tHalHandle hHal, uint8_t + tx_fail_count, + void *txFailIndCallback) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + tAniTXFailMonitorInd *pMsg; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pMsg = (tAniTXFailMonitorInd *) + qdf_mem_malloc(sizeof(tAniTXFailMonitorInd)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to allocate memory", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_TX_FAIL_MONITOR_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniTXFailMonitorInd); + + /* tx_fail_count = 0 should disable the Monitoring in FW */ + pMsg->tx_fail_count = tx_fail_count; + pMsg->txFailIndCallback = txFailIndCallback; + + message.type = WMA_TX_FAIL_MONITOR_IND; + message.bodyptr = pMsg; + message.reserved = 0; + + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post TX Fail monitor Start MSG fail", + __func__); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_neighbor_report_request() - + * API to request neighbor report. + * + * hHal - 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(tHalHandle hHal, uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + 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(&pMac->sme)) { + status = + sme_rrm_neighbor_report_request(pMac, sessionId, + pRrmNeighborReq, callbackInfo); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_get_wcnss_wlan_compiled_version() - + * This API returns the version of the WCNSS WLAN API with + * which the HOST driver was built + * + * hHal - The handle returned by mac_open. + * pVersion - Points to the Version structure to be filled + * Return QDF_STATUS + * QDF_STATUS_E_INVAL - failure + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS sme_get_wcnss_wlan_compiled_version(tHalHandle hHal, + tSirVersionType *pVersion) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_get_wcnss_wlan_reported_version() - + * This API returns the version of the WCNSS WLAN API with + * which the WCNSS driver reports it was built + * hHal - The handle returned by mac_open. + * pVersion - Points to the Version structure to be filled + * Return QDF_STATUS + * QDF_STATUS_E_INVAL - failure + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS sme_get_wcnss_wlan_reported_version(tHalHandle hHal, + tSirVersionType *pVersion) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_get_wcnss_software_version() - + * This API returns the version string of the WCNSS driver + * + * hHal - The handle returned by mac_open. + * pVersion - Points to the Version string buffer to be filled + * versionBufferSize - THe size of the Version string buffer + * Return QDF_STATUS + * QDF_STATUS_E_INVAL - failure + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS sme_get_wcnss_software_version(tHalHandle hHal, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = + wma_get_wcnss_software_version( + pVersion, + versionBufferSize); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_get_wcnss_hardware_version() - + * This API returns the version string of the WCNSS hardware + * + * hHal - The handle returned by mac_open. + * pVersion - Points to the Version string buffer to be filled + * versionBufferSize - THe size of the Version string buffer + * Return QDF_STATUS + * QDF_STATUS_E_INVAL - failure + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS sme_get_wcnss_hardware_version(tHalHandle hHal, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * sme_oem_data_req() - send oem data request to WMA + * @hal: HAL handle + * @hdd_oem_req: OEM data request from HDD + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_data_req(tHalHandle hal, struct oem_data_req *hdd_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) { + sme_err("wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + oem_data_req = qdf_mem_malloc(sizeof(*oem_data_req)); + if (!oem_data_req) { + sme_err("mem alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + oem_data_req->data_len = hdd_oem_req->data_len; + oem_data_req->data = qdf_mem_malloc(oem_data_req->data_len); + if (!oem_data_req->data) { + sme_err("mem alloc failed"); + qdf_mem_free(oem_data_req); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(oem_data_req->data, hdd_oem_req->data, + oem_data_req->data_len); + + status = wma_start_oem_data_req(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 */ + +QDF_STATUS sme_open_session(tHalHandle hal, struct sme_session_params *params) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct cdp_pdev *pdev; + ol_txrx_peer_handle peer; + uint8_t peer_id; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: type=%d, session_id %d subType=%d addr:%pM", + __func__, params->type_of_persona, + params->sme_session_id, params->subtype_of_persona, + params->self_mac_addr); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to get pdev handler", __func__); + return status; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + peer = cdp_peer_find_by_addr(soc, pdev, params->self_mac_addr, + &peer_id); + if (peer) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Peer=%d exist with same MAC", + __func__, peer_id); + status = QDF_STATUS_E_INVAL; + } else { + status = csr_roam_open_session(mac_ctx, params); + } + sme_release_global_lock(&mac_ctx->sme); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_OPEN_SESSION, + params->sme_session_id, 0)); + + return status; +} + +QDF_STATUS sme_close_session(tHalHandle hal, uint8_t session_id) +{ + QDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, session_id, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_close_session(pMac, session_id, false); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +static void +sme_populate_user_config(struct mlme_nss_chains *dynamic_cfg, + struct mlme_nss_chains *user_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 = + dynamic_cfg->num_tx_chains_11a; + + if (!user_cfg->num_tx_chains_11b) + user_cfg->num_tx_chains_11b = + dynamic_cfg->num_tx_chains_11b; + + if (!user_cfg->num_tx_chains_11g) + user_cfg->num_tx_chains_11g = + dynamic_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 mlme_nss_chains *user_cfg, + struct 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 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 mlme_nss_chains *user_cfg, + struct mlme_nss_chains *dynamic_cfg) +{ + enum nss_chains_band_info band; + struct 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, 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; +} + +QDF_STATUS +sme_nss_chains_update(mac_handle_t mac_handle, + struct mlme_nss_chains *user_cfg, + uint8_t vdev_id) +{ + struct sAniSirGlobal *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + struct 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); + if (!vdev) { + sme_err("Got NULL vdev obj, returning"); + return QDF_STATUS_E_FAILURE; + } + + 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); + if (QDF_IS_STATUS_ERROR(status)) + goto release_lock; + + if (!qdf_mem_cmp(dynamic_cfg, user_cfg, + sizeof(struct 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; +} + +/* + * 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; + tpAniSirGlobal 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; +} + +/** + * sme_set_host_offload(): API to set the host offload feature. + * @hHal: The handle returned by mac_open. + * @sessionId: Session Identifier + * @request: Pointer to the offload request. + * + * Return QDF_STATUS + */ +QDF_STATUS sme_set_host_offload(tHalHandle hHal, uint8_t sessionId, + tpSirHostOffloadReq request) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + 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(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { +#ifdef WLAN_NS_OFFLOAD + if (SIR_IPV6_NS_OFFLOAD == request->offloadType) { + status = sme_set_ps_ns_offload(hHal, request, + sessionId); + } else +#endif /* WLAN_NS_OFFLOAD */ + { + status = sme_set_ps_host_offload(hHal, request, + sessionId); + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_set_keep_alive() - + * API to set the Keep Alive feature. + * + * hHal - The handle returned by mac_open. + * request - Pointer to the Keep Alive request. + * Return QDF_STATUS + */ +QDF_STATUS sme_set_keep_alive(tHalHandle hHal, uint8_t session_id, + tpSirKeepAliveReq request) +{ + tpSirKeepAliveReq request_buf; + struct scheduler_msg msg = {0}; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, session_id); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("WMA_SET_KEEP_ALIVE message")); + + if (pSession == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Session not Found")); + return QDF_STATUS_E_FAILURE; + } + request_buf = qdf_mem_malloc(sizeof(tSirKeepAliveReq)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Not able to allocate memory for keep alive request"); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&request->bssid, &pSession->connectedProfile.bssid); + qdf_mem_copy(request_buf, request, sizeof(tSirKeepAliveReq)); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "buff TP %d input TP %d ", 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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 or IBSS station + * + * hHal, pointer to memory location and sessionId + * Returns QDF_STATUS_SUCCESS + * QDF_STATUS_E_FAILURE + */ +QDF_STATUS sme_get_operation_channel(tHalHandle hHal, uint32_t *pChannel, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if ((pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_INFRASTRUCTURE) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_IBSS) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_INFRA_AP) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_START_IBSS)) { + *pChannel = pSession->connectedProfile.operationChannel; + 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. + * + * @hal: hal pointer + * @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(tHalHandle hal, + sir_mgmt_frame_ind_callback callback) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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 (NULL == msg) { + sme_err("Not able to allocate memory"); + 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(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + tSirRegisterMgmtFrame *pMsg; + uint16_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, + sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sme_err("Session %d not found", sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && + !pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s Invalid Sessionid", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(tSirRegisterMgmtFrame) + matchLen; + + pMsg = qdf_mem_malloc(len); + if (NULL == 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(&pMac->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(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + tSirRegisterMgmtFrame *pMsg; + uint16_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, + sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sme_err("Session %d not found", sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && + !pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s Invalid Sessionid", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(tSirRegisterMgmtFrame) + matchLen; + + pMsg = qdf_mem_malloc(len); + if (NULL == 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(&pMac->sme); + } + return status; +} + +/** + * sme_prepare_mgmt_tx() - Prepares mgmt frame + * @hal: The handle returned by mac_open + * @session_id: session id + * @buf: pointer to frame + * @len: frame length + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_prepare_mgmt_tx(tHalHandle hal, uint8_t session_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 == NULL) { + status = QDF_STATUS_E_NOMEM; + } else { + msg->type = eWNI_SME_SEND_MGMT_FRAME_TX; + msg->msg_len = msg_len; + msg->session_id = session_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(tHalHandle hal, uint8_t session_id, + const uint8_t *buf, uint32_t len) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = sme_prepare_mgmt_tx(hal, session_id, buf, len); + sme_release_global_lock(&mac->sme); + } + + return status; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * sme_configure_ext_wow() - configure Extr WoW + * @hHal - 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(tHalHandle hHal, + tpSirExtWoWParams wlanExtParams, + csr_readyToExtWoWCallback callback, + void *callback_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + 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)); + + pMac->readyToExtWoWCallback = callback; + pMac->readyToExtWoWContext = callback_context; + + status = sme_acquire_global_lock(&pMac->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)) { + pMac->readyToExtWoWCallback = NULL; + pMac->readyToExtWoWContext = NULL; + qdf_mem_free(MsgPtr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + pMac->readyToExtWoWCallback = NULL; + pMac->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. + * + * hHal - 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(tHalHandle hHal, + tpSirAppType1Params wlanAppType1Params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + 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(&pMac->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(&pMac->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. + * + * hHal - 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(tHalHandle hHal, + tpSirAppType2Params wlanAppType2Params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + 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(&pMac->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(&pMac->sme); + } else { + qdf_mem_free(MsgPtr); + } + + return status; +} +#endif + +/* + * sme_get_infra_session_id + * To get the session ID for infra session, if connected + * This is a synchronous API. + * + * hHal - The handle returned by mac_open. + * sessionid, -1 if infra session is not connected + */ +int8_t sme_get_infra_session_id(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int8_t sessionid = -1; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + sessionid = csr_get_infra_session_id(pMac); + + sme_release_global_lock(&pMac->sme); + } + + return sessionid; +} + +/* + * sme_get_infra_operation_channel() - + * To get the operating channel for infra session, if connected + * This is a synchronous API. + * + * hHal - The handle returned by mac_open. + * sessionId - the sessionId returned by sme_open_session. + * Return operating channel, 0 if infra session is not connected + */ +uint8_t sme_get_infra_operation_channel(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t channel = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + channel = csr_get_infra_operation_channel(pMac, sessionId); + + sme_release_global_lock(&pMac->sme); + } + + return channel; +} + +uint8_t sme_get_beaconing_concurrent_operation_channel(tHalHandle hal, + uint8_t vdev_id_to_skip) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + uint8_t channel = 0; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + channel = csr_get_beaconing_concurrent_channel(mac, + vdev_id_to_skip); + sme_info("Other Concurrent Channel: %d skipped vdev_id %d", + channel, vdev_id_to_skip); + sme_release_global_lock(&mac->sme); + } + + return channel; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t sme_check_concurrent_channel_overlap(tHalHandle hHal, uint16_t sap_ch, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint16_t channel = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + channel = + csr_check_concurrent_channel_overlap(pMac, sap_ch, + sapPhyMode, + cc_switch_mode); + sme_release_global_lock(&pMac->sme); + } + + return channel; +} +#endif + +/** + * sme_set_tsfcb() - Set callback for TSF capture + * @h_hal: Handler return by mac_open + * @cb_fn: Callback function pointer + * @db_ctx: Callback data + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_tsfcb(tHalHandle h_hal, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx) +{ + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + 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 + * @h_hal: Handler return by mac_open + * + * This function reset the tsf capture callback to SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_reset_tsfcb(tHalHandle h_hal) +{ + tpAniSirGlobal mac; + QDF_STATUS status; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("h_hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(h_hal); + + 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 + * @h_hal: Handler return by mac_open + * @pinvalue: gpio pin id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_tsf_gpio(tHalHandle h_hal, uint32_t pinvalue) +{ + QDF_STATUS status; + struct scheduler_msg tsf_msg = {0}; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + + 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(uint8_t *aValidChannels, + uint32_t *len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = sme_get_mac_context(); + + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return QDF_STATUS_E_FAILURE; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_cfg_valid_channels(mac_ctx, + aValidChannels, len); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +#ifdef WLAN_DEBUG +static uint8_t *sme_reg_hint_to_str(const enum country_src src) +{ + switch (src) { + case SOURCE_CORE: + return "WORLD MODE"; + + case SOURCE_DRIVER: + return "BDF file"; + + case SOURCE_USERSPACE: + return "user-space"; + + case SOURCE_11D: + return "802.11D IEs in beacons"; + + default: + return "unknown"; + } +} +#endif + +void sme_set_cc_src(tHalHandle hHal, enum country_src cc_src) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + + mac_ctx->reg_hint_src = cc_src; + + sme_debug("Country source is %s", + sme_reg_hint_to_str(cc_src)); +} + +/** + * 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(tpAniSirGlobal mac_ctx, + void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + v_REGDOMAIN_t reg_domain_id = 0; + bool user_ctry_priority = + mac_ctx->roam.configParam.fSupplicantCountryCodeHasPriority; + tAniGenericChangeCountryCodeReq *msg = pMsgBuf; + + if (SOURCE_11D != mac_ctx->reg_hint_src) { + if (SOURCE_DRIVER != mac_ctx->reg_hint_src) { + if (user_ctry_priority) + mac_ctx->roam.configParam.Is11dSupportEnabled = + false; + else { + if (mac_ctx->roam.configParam. + Is11dSupportEnabled && + mac_ctx->scan.countryCode11d[0] != 0) { + + sme_debug("restore 11d"); + + status = + csr_get_regulatory_domain_for_country( + mac_ctx, + mac_ctx->scan.countryCode11d, + ®_domain_id, + SOURCE_11D); + return QDF_STATUS_E_FAILURE; + } + } + } + } else { + /* if kernel gets invalid country code; it + * resets the country code to world + */ + if (('0' != msg->countryCode[0]) || + ('0' != msg->countryCode[1])) + qdf_mem_copy(mac_ctx->scan.countryCode11d, + msg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } + + qdf_mem_copy(mac_ctx->scan.countryCodeCurrent, + msg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + + /* 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_scan_filter_results(mac_ctx); + + /* scans after the country is set by User hints or + * Country IE + */ + mac_ctx->scan.curScanType = eSIR_ACTIVE_SCAN; + + mac_ctx->reg_hint_src = SOURCE_UNKNOWN; + + sme_disconnect_connected_sessions(mac_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_update_channel_list(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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_disconnect_connected_sessions(mac_ctx); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +static bool +sme_search_in_base_ch_lst(tpAniSirGlobal mac_ctx, uint8_t curr_ch) +{ + 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->channelList[i] == curr_ch) + return true; + } + + return false; +} +/** + * sme_disconnect_connected_sessions() - Disconnect STA and P2P client session + * if channel is not supported + * @mac_ctx: mac global context + * + * If new country code does not support the channel on which STA/P2P client + * is connetced, it sends the disconnect to the AP/P2P GO + * + * Return: void + */ +static void sme_disconnect_connected_sessions(tpAniSirGlobal mac_ctx) +{ + uint8_t session_id, found = false; + uint8_t curr_ch; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (!csr_is_session_client_and_connected(mac_ctx, session_id)) + continue; + found = false; + /* Session is connected.Check the channel */ + curr_ch = csr_get_infra_operation_channel(mac_ctx, + session_id); + sme_debug("Current Operating channel : %d, session :%d", + curr_ch, session_id); + found = sme_search_in_base_ch_lst(mac_ctx, curr_ch); + if (!found) { + sme_debug("Disconnect Session: %d", session_id); + csr_roam_disconnect(mac_ctx, session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + } +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +QDF_STATUS sme_8023_multicast_list(tHalHandle hHal, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs) +{ + tpSirRcvFltMcAddrList request_buf; + struct scheduler_msg msg = {0}; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = NULL; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: ulMulticastAddrCnt: %d, multicastAddr[0]: %pK", __func__, + pMulticastAddrs->ulMulticastAddrCnt, + pMulticastAddrs->multicastAddr[0].bytes); + + /* Find the connected Infra / P2P_client connected session */ + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!CSR_IS_SESSION_VALID(pMac, sessionId) || + (!csr_is_conn_state_infra(pMac, sessionId) && + !csr_is_ndi_started(pMac, sessionId))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to find the session Id: %d", __func__, + sessionId); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirRcvFltMcAddrList)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for 8023 Multicast List request", + __func__); + return QDF_STATUS_E_NOMEM; + } + + if (!csr_is_conn_state_connected_infra(pMac, sessionId) && + !csr_is_ndi_started(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Request ignored, session %d is not connected or started", + __func__, sessionId); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(request_buf, pMulticastAddrs, + sizeof(tSirRcvFltMcAddrList)); + + qdf_copy_macaddr(&request_buf->self_macaddr, &pSession->selfMacAddr); + qdf_copy_macaddr(&request_buf->bssid, + &pSession->connectedProfile.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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_8023_MULTICAST_LIST message to WMA", + __func__); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* + * sme_is_channel_valid() - + * To check if the channel is valid for currently established domain + * This is a synchronous API. + * + * hHal - The handle returned by mac_open. + * channel - channel to verify + * Return true/false, true if channel is valid + */ +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool valid = false; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + valid = csr_roam_is_channel_valid(pMac, channel); + + sme_release_global_lock(&pMac->sme); + } + + return valid; +} + +/* + * sme_set_freq_band() - + * Used to set frequency band. + * + * hHal + * sessionId - Session Identifier + * band value to be configured + * Return QDF_STATUS + */ +QDF_STATUS sme_set_freq_band(tHalHandle hHal, uint8_t sessionId, + enum band_info eBand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_band(hHal, sessionId, eBand); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_get_freq_band() - + * Used to get the current band settings. + * + * hHal + * pBand pointer to hold band value + * Return QDF_STATUS + */ +QDF_STATUS sme_get_freq_band(tHalHandle hHal, enum band_info *pBand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + *pBand = csr_get_current_band(hHal); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * 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 (NULL == pMaxTxPowerPerBandParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:Not able to allocate memory for pMaxTxPowerPerBandParams", + __func__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:Not able to post WMA_SET_MAX_TX_POWER_PER_BAND_REQ", + __func__); + 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. + * + * hHal + * 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(tHalHandle hHal, 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 (NULL == pMaxTxParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for pMaxTxParams", + __func__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_MAX_TX_POWER_REQ message to WMA", + __func__); + qdf_mem_free(pMaxTxParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * 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 (NULL == pBaseMacAddr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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. + * + * hHal + * 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(tHalHandle hHal, 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: error, invalid power = %d", __func__, dBm); + return QDF_STATUS_E_FAILURE; + } + + pTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pTxParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for pTxParams", + __func__); + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post WMA_SET_TX_POWER_REQ to WMA", + __func__); + qdf_mem_free(pTxParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_update_fils_setting(tHalHandle hal, uint8_t session_id, + uint8_t param_val) +{ + QDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + + pMac->roam.configParam.is_fils_enabled = !param_val; + + pMac->roam.configParam.enable_bcast_probe_rsp = !param_val; + status = wma_cli_set_command((int)session_id, + (int)WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, + !param_val, VDEV_CMD); + if (status) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to set enable bcast probe setting", + __func__); + + return status; +} + +QDF_STATUS sme_update_session_param(tHalHandle hal, uint8_t session_id, + uint32_t param_type, uint32_t param_val) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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 (param_type == SIR_PARAM_IGNORE_ASSOC_DISALLOWED) + mac_ctx->ignore_assoc_disallowed = param_val; + + 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->session_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; +} + +/* + * sme_set_tm_level() - + * Set Thermal Mitigation Level to RIVA + * + * hHal - The handle returned by mac_open. + * newTMLevel - new Thermal Mitigation Level + * tmMode - Thermal Mitigation handle mode, default 0 + * Return QDF_STATUS + */ +QDF_STATUS sme_set_tm_level(tHalHandle hHal, uint16_t newTMLevel, uint16_t + tmMode) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + tAniSetTmLevelReq *setTmLevelReq = NULL; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_TMLEVEL, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + setTmLevelReq = + (tAniSetTmLevelReq *) + qdf_mem_malloc(sizeof(tAniSetTmLevelReq)); + if (NULL == setTmLevelReq) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for sme_set_tm_level", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + setTmLevelReq->tmMode = tmMode; + setTmLevelReq->newTmLevel = newTMLevel; + + /* serialize the req through MC thread */ + message.bodyptr = setTmLevelReq; + message.type = WMA_SET_TM_LEVEL_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_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post Set TM Level MSG fail", __func__); + qdf_mem_free(setTmLevelReq); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_feature_caps_exchange() - SME interface to exchange capabilities between + * Host and FW. + * + * hHal - HAL handle for device + * Return NONE + */ +void sme_feature_caps_exchange(tHalHandle hHal) +{ + MTRACE(qdf_trace + (QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_CAPS_EXCH, + NO_SESSION, 0)); +} + +/* + * sme_disable_feature_capablity() - SME interface to disable Active mode + * offload capablity in Host. + * + * hHal - HAL handle for device + * Return NONE + */ +void sme_disable_feature_capablity(uint8_t feature_index) +{ +} + +/* + * sme_reset_power_values_for5_g + * Reset the power values for 5G band with default power values. + * + * hHal - HAL handle for device + * Return NONE + */ +void sme_reset_power_values_for5_g(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_RESET_PW5G, NO_SESSION, 0)); + csr_save_channel_power_for_band(pMac, true); + /* Store the channel+power info in the global place: Cfg */ + csr_apply_power2_current(pMac); +} + +/* + * sme_update_roam_prefer5_g_hz() - + * Enable/disable Roam prefer 5G runtime option + * This function is called through dynamic setConfig callback function + * to configure the Roam prefer 5G runtime option + * + * hHal - HAL handle for device + * nRoamPrefer5GHz Enable/Disable Roam prefer 5G runtime option + * Return Success or failure + */ + +QDF_STATUS sme_update_roam_prefer5_g_hz(tHalHandle hHal, + bool nRoamPrefer5GHz) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_RP5G, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: gRoamPrefer5GHz is changed from %d to %d", + __func__, pMac->roam.configParam.nRoamPrefer5GHz, + nRoamPrefer5GHz); + pMac->roam.configParam.nRoamPrefer5GHz = nRoamPrefer5GHz; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_set_roam_intra_band() - + * enable/disable Intra band roaming + * This function is called through dynamic setConfig callback function + * to configure the intra band roaming + * hHal - HAL handle for device + * nRoamIntraBand Enable/Disable Intra band roaming + * Return Success or failure + */ +QDF_STATUS sme_set_roam_intra_band(tHalHandle hHal, const bool nRoamIntraBand) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: gRoamIntraBand is changed from %d to %d", + __func__, pMac->roam.configParam.nRoamIntraBand, + nRoamIntraBand); + pMac->roam.configParam.nRoamIntraBand = nRoamIntraBand; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_update_roam_scan_n_probes() - + * Function to update roam scan N probes + * This function is called through dynamic setConfig callback function + * to update roam scan N probes + * hHal - HAL handle for device + * sessionId - Session Identifier + * nProbes number of probe requests to be sent out + * Return Success or failure + */ +QDF_STATUS sme_update_roam_scan_n_probes(tHalHandle hHal, uint8_t sessionId, + const uint8_t nProbes) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: gRoamScanNProbes is changed from %d to %d", + __func__, pMac->roam.configParam.nProbes, nProbes); + pMac->roam.configParam.nProbes = nProbes; + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_NPROBES_CHANGED); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_update_roam_scan_home_away_time() - + * Function to update roam scan Home away time + * This function is called through dynamic setConfig callback function + * to update roam scan home away time + * + * hHal - HAL handle for device + * sessionId - Session Identifier + * nRoamScanAwayTime Scan home away time + * bSendOffloadCmd If true then send offload command to firmware + * If false then command is not sent to firmware + * Return Success or failure + */ +QDF_STATUS sme_update_roam_scan_home_away_time(tHalHandle hHal, + uint8_t sessionId, + const uint16_t nRoamScanHomeAwayTime, + const bool bSendOffloadCmd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: gRoamScanHomeAwayTime is changed from %d to %d", + __func__, + pMac->roam.configParam.nRoamScanHomeAwayTime, + nRoamScanHomeAwayTime); + pMac->roam.configParam.nRoamScanHomeAwayTime = + nRoamScanHomeAwayTime; + + if (pMac->roam.configParam.isRoamOffloadScanEnabled && + bSendOffloadCmd) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_HOME_AWAY_TIME_CHANGED); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_ext_change_channel()- function to post send ECSA + * action frame to csr. + * @hHal: Hal context + * @channel: new channel 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_channel(tHalHandle h_hal, uint32_t channel, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + uint8_t channel_state; + + sme_err("Set Channel: %d", channel); + channel_state = + wlan_reg_get_channel_state(mac_ctx->pdev, channel); + + if (CHANNEL_STATE_DISABLE == channel_state) { + sme_err("Invalid channel: %d", channel); + 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_channel(mac_ctx, + channel, session_id); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +/* + * sme_get_roam_intra_band() - + * get Intra band roaming + * + * hHal - HAL handle for device + * Return Success or failure + */ +bool sme_get_roam_intra_band(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND, NO_SESSION, 0)); + return pMac->roam.configParam.nRoamIntraBand; +} + +/* + * sme_get_roam_scan_n_probes() - + * get N Probes + * + * hHal - HAL handle for device + * Return Success or failure + */ +uint8_t sme_get_roam_scan_n_probes(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.nProbes; +} + +/* + * sme_get_roam_scan_home_away_time() - + * get Roam scan home away time + * + * hHal - HAL handle for device + * Return Success or failure + */ +uint16_t sme_get_roam_scan_home_away_time(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.nRoamScanHomeAwayTime; +} + +/* + * sme_update_roam_rssi_diff() - + * Update RoamRssiDiff + * This function is called through dynamic setConfig callback function + * to configure RoamRssiDiff + * Usage: adb shell iwpriv wlan0 setConfig RoamRssiDiff=[0 .. 125] + * + * hHal - HAL handle for device + * sessionId - Session Identifier + * RoamRssiDiff - minimum rssi difference between potential + * candidate and current AP. + * Return Success or failure + */ + +QDF_STATUS sme_update_roam_rssi_diff(tHalHandle hHal, uint8_t sessionId, + uint8_t RoamRssiDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam rssi diff to %d - old value is %d - roam state is %s", + RoamRssiDiff, + pMac->roam.configParam.RoamRssiDiff, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.RoamRssiDiff = RoamRssiDiff; + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_RSSI_DIFF_CHANGED); + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_FILS_SK +QDF_STATUS sme_update_fils_config(tHalHandle hal, uint8_t session_id, + struct csr_roam_profile *src_profile) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac->roam.neighborRoamInfo[session_id]; + + if (session_id >= CSR_ROAM_SESSION_MAX) { + sme_err("Invalid sme session id: %d", session_id); + return QDF_STATUS_E_INVAL; + } + + if (!src_profile) { + sme_err("src roam profile NULL"); + return QDF_STATUS_E_INVAL; + } + + if (!mac->roam.configParam.isFastRoamIniFeatureEnabled || + (neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED)) { + sme_info("Fast roam is disabled or not connected(%d)", + neighbor_roam_info->neighborRoamState); + return QDF_STATUS_E_PERM; + } + + csr_update_fils_config(mac, session_id, src_profile); + if (csr_roamIsRoamOffloadEnabled(mac)) { + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("Updating fils config to fw"); + csr_roam_offload_scan(mac, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_FILS_PARAMS_CHANGED); + sme_release_global_lock(&mac->sme); + } else { + sme_err("Failed to acquire SME lock"); + } + } else { + sme_info("LFR3 not enabled"); + return QDF_STATUS_E_INVAL; + } + + return status; +} + +void sme_send_hlp_ie_info(tHalHandle hal, uint8_t session_id, + struct csr_roam_profile *profile, uint32_t if_addr) +{ + int i; + struct scheduler_msg msg; + QDF_STATUS status; + struct hlp_params *params; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct csr_roam_session *session = CSR_GET_SESSION(mac, session_id); + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac->roam.neighborRoamInfo[session_id]; + + if (!session) { + sme_err("session NULL"); + return; + } + + if (!mac->roam.configParam.isFastRoamIniFeatureEnabled || + (neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED)) { + sme_debug("Fast roam is disabled or not connected(%d)", + neighbor_roam_info->neighborRoamState); + return; + } + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) { + sme_err("Mem alloc for HLP IE fails"); + return; + } + if ((profile->hlp_ie_len + + SIR_IPV4_ADDR_LEN) > FILS_MAX_HLP_DATA_LEN) { + sme_err("HLP IE len exceeds %d", + profile->hlp_ie_len); + qdf_mem_free(params); + return; + } + + params->vdev_id = session_id; + params->hlp_ie_len = profile->hlp_ie_len + SIR_IPV4_ADDR_LEN; + + for (i = 0; i < SIR_IPV4_ADDR_LEN; i++) + params->hlp_ie[i] = (if_addr >> (i * 8)) & 0xFF; + + qdf_mem_copy(params->hlp_ie + SIR_IPV4_ADDR_LEN, + profile->hlp_ie, profile->hlp_ie_len); + + 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); +} + +void sme_free_join_rsp_fils_params(struct csr_roam_info *roam_info) +{ + struct fils_join_rsp_params *roam_fils_params; + + if (!roam_info) { + sme_err("FILS Roam Info NULL"); + return; + } + + roam_fils_params = roam_info->fils_join_rsp; + if (!roam_fils_params) { + sme_err("FILS Roam Param NULL"); + return; + } + + if (roam_fils_params->fils_pmk) + qdf_mem_free(roam_fils_params->fils_pmk); + + qdf_mem_free(roam_fils_params); + + roam_info->fils_join_rsp = NULL; +} + +#else +inline void sme_send_hlp_ie_info(tHalHandle hal, uint8_t session_id, + struct csr_roam_profile *profile, uint32_t if_addr) +{} +#endif + +/* + * sme_update_fast_transition_enabled() - enable/disable Fast Transition + * support at runtime + * It is used at in the REG_DYNAMIC_VARIABLE macro definition of + * isFastTransitionEnabled. + * This is a synchronous call + * + * hHal - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS - SME update isFastTransitionEnabled config + * successfully. + * Other status means SME is failed to update isFastTransitionEnabled. + */ +QDF_STATUS sme_update_fast_transition_enabled(tHalHandle hHal, + bool isFastTransitionEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED, NO_SESSION, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: FastTransitionEnabled is changed from %d to %d", + __func__, + pMac->roam.configParam.isFastTransitionEnabled, + isFastTransitionEnabled); + pMac->roam.configParam.isFastTransitionEnabled = + isFastTransitionEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_update_wes_mode() - + * Update WES Mode + * This function is called through dynamic setConfig callback function + * to configure isWESModeEnabled + * + * hHal - HAL handle for device + * 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(tHalHandle hHal, bool isWESModeEnabled, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set WES Mode to %d - old value is %d - roam state is %s", + isWESModeEnabled, + pMac->roam.configParam.isWESModeEnabled, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.isWESModeEnabled = isWESModeEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_set_roam_scan_control() - + * Set roam scan control + * This function is called to set roam scan control + * if roam scan control is set to 0, roaming scan cache is cleared + * any value other than 0 is treated as invalid value + * hHal - HAL handle for device + * sessionId - Session Identifier + * Return QDF_STATUS_SUCCESS - SME update config successfully. + * Other status means SME failure to update + */ +QDF_STATUS sme_set_roam_scan_control(tHalHandle hHal, uint8_t sessionId, + bool roamScanControl) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_SCANCTRL, NO_SESSION, 0)); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan control to %d - old value is %d - roam state is %s", + roamScanControl, + pMac->roam.configParam.nRoamScanControl, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.nRoamScanControl = roamScanControl; + if (0 == roamScanControl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully cleared roam scan cache"); + csr_flush_cfg_bg_scan_roam_channel_list(pMac, + sessionId); + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_FLUSH_CHANNEL_LIST); + } + } + sme_release_global_lock(&pMac->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 + * + * hHal - 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(tHalHandle hHal, + uint8_t sessionId, const bool isFastRoamIniFeatureEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->roam.configParam.isFastRoamIniFeatureEnabled == + isFastRoamIniFeatureEnabled) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: FastRoam is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + __func__, + pMac->roam.configParam.isFastRoamIniFeatureEnabled, + isFastRoamIniFeatureEnabled); + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: FastRoamEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.isFastRoamIniFeatureEnabled, + isFastRoamIniFeatureEnabled); + pMac->roam.configParam.isFastRoamIniFeatureEnabled = + isFastRoamIniFeatureEnabled; + csr_neighbor_roam_update_fast_roaming_enabled(pMac, sessionId, + isFastRoamIniFeatureEnabled); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_config_fast_roaming() - enable/disable LFR support at runtime + * @hal - The handle returned by macOpen. + * @session_id - Session Identifier + * @is_fast_roam_enabled - flag to enable/disable roaming + * + * When Supplicant issues enabled/disable fast roaming on the basis + * of the Bssid modification in network block (e.g. AutoJoin mode N/W block) + * + * Return: QDF_STATUS + */ + +QDF_STATUS sme_config_fast_roaming(tHalHandle hal, uint8_t session_id, + const bool is_fast_roam_enabled) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + QDF_STATUS status; + + /* + * supplicant_disabled_roaming flag is set to true in + * wlan_hdd_cfg80211_connect_start when supplicant initiate connect + * request with BSSID. This flag is reset when supplicant sends + * vendor command to enable roaming after association. + * + * This request from wpa_supplicant will be skipped in this function + * if roaming is disabled using driver command or INI and + * supplicant_disabled_roaming flag remains set. So make sure to set + * supplicant_disabled_roaming flag as per wpa_supplicant even if roam + * request from wpa_supplicant ignored. + */ + if (session && session->pCurRoamProfile) + session->pCurRoamProfile->supplicant_disabled_roaming = + !is_fast_roam_enabled; + + if (!mac_ctx->roam.configParam.isFastRoamIniFeatureEnabled) { + sme_debug("Fast roam is disabled through ini"); + if (!is_fast_roam_enabled) + return QDF_STATUS_SUCCESS; + return QDF_STATUS_E_FAILURE; + } + + status = csr_neighbor_roam_update_fast_roaming_enabled(mac_ctx, + session_id, is_fast_roam_enabled); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("update fast roaming failed. status: %d", status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_update_is_mawc_ini_feature_enabled() - + * Enable/disable LFR MAWC support at runtime + * It is used at in the REG_DYNAMIC_VARIABLE macro definition of + * isMAWCIniFeatureEnabled. + * This is a synchronous call + * + * hHal - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS - SME update MAWCEnabled config successfully. + * Other status means SME is failed to update MAWCEnabled. + */ +QDF_STATUS sme_update_is_mawc_ini_feature_enabled(tHalHandle hHal, + const bool MAWCEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: MAWCEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.csr_mawc_config.mawc_enabled, + MAWCEnabled); + pMac->roam.configParam.csr_mawc_config.mawc_enabled = + MAWCEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/** + * sme_stop_roaming() - Stop roaming for a given sessionId + * This is a synchronous call + * + * @hHal - The handle returned by mac_open + * @sessionId - Session Identifier + * + * Return QDF_STATUS_SUCCESS on success + * Other status on failure + */ +QDF_STATUS sme_stop_roaming(tHalHandle hal, uint8_t session_id, uint8_t reason) +{ + struct scheduler_msg wma_msg = {0}; + QDF_STATUS status; + tSirRoamOffloadScanReq *req; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tpCsrNeighborRoamControlInfo roam_info; + struct csr_roam_session *session; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("incorrect session/vdev ID"); + return QDF_STATUS_E_INVAL; + } + + session = CSR_GET_SESSION(mac_ctx, session_id); + + /* + * set the driver_disabled_roaming flag to true even if roaming + * is not enabled on this session so that roam start requests for + * this session can be blocked until driver enables roaming + */ + if (reason == ecsr_driver_disabled && session->pCurRoamProfile && + session->pCurRoamProfile->csrPersona == QDF_STA_MODE) { + session->pCurRoamProfile->driver_disabled_roaming = true; + sme_debug("driver_disabled_roaming set for session %d", + session_id); + } + + roam_info = &mac_ctx->roam.neighborRoamInfo[session_id]; + if (!roam_info->b_roam_scan_offload_started) { + sme_debug("Roaming already disabled for session %d", session_id); + return QDF_STATUS_SUCCESS; + } + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_err("failed to allocated memory"); + return QDF_STATUS_E_NOMEM; + } + + req->Command = ROAM_SCAN_OFFLOAD_STOP; + if ((reason == eCsrForcedDisassoc) || reason == ecsr_driver_disabled) + req->reason = REASON_ROAM_STOP_ALL; + else + req->reason = REASON_SME_ISSUED; + req->sessionId = session_id; + if (csr_neighbor_middle_of_roaming(mac_ctx, session_id)) + req->middle_of_roaming = 1; + else + csr_roam_reset_roam_params(mac_ctx); + + /* Disable offload_11k_params and btm_offload_config for current vdev */ + req->offload_11k_params.offload_11k_bitmask = 0; + req->btm_offload_config = 0; + req->offload_11k_params.vdev_id = session_id; + + wma_msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ; + wma_msg.bodyptr = req; + + status = wma_post_ctrl_msg(mac_ctx, &wma_msg); + if (QDF_STATUS_SUCCESS != status) { + sme_err("WMA_ROAM_SCAN_OFFLOAD_REQ failed, session_id: %d", + session_id); + qdf_mem_zero(req, sizeof(*req)); + qdf_mem_free(req); + return QDF_STATUS_E_FAULT; + } + roam_info->b_roam_scan_offload_started = false; + roam_info->last_sent_cmd = ROAM_SCAN_OFFLOAD_STOP; + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_start_roaming() - Start roaming for a given sessionId + * This is a synchronous call + * + * hHal - The handle returned by mac_open + * sessionId - Session Identifier + * Return QDF_STATUS_SUCCESS on success + * Other status on failure + */ +QDF_STATUS sme_start_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START, + reason); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_update_enable_fast_roam_in_concurrency() - enable/disable LFR if + * Concurrent session exists + * This is a synchronuous call + * + * hHal - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS + * Other status means SME is failed + */ +QDF_STATUS sme_update_enable_fast_roam_in_concurrency(tHalHandle hHal, + bool + bFastRoamInConIniFeatureEnabled) +{ + + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + bFastRoamInConIniFeatureEnabled; + if (0 == pMac->roam.configParam.isRoamOffloadScanEnabled) { + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + 0; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_set_roam_opportunistic_scan_threshold_diff() - + * Update Opportunistic Scan threshold diff + * This function is called through dynamic setConfig callback function + * to configure nOpportunisticThresholdDiff + * + * hHal - HAL handle for device + * 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(tHalHandle hHal, + uint8_t sessionId, + const uint8_t + nOpportunisticThresholdDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nOpportunisticThresholdDiff, + REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff = + nOpportunisticThresholdDiff; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_get_roam_opportunistic_scan_threshold_diff() + * gets Opportunistic Scan threshold diff + * This is a synchronous call + * + * hHal - The handle returned by mac_open + * Return uint8_t - nOpportunisticThresholdDiff + */ +uint8_t sme_get_roam_opportunistic_scan_threshold_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff; +} + +/* + * sme_set_roam_rescan_rssi_diff() - Update roam rescan rssi diff + * This function is called through dynamic setConfig callback function + * to configure nRoamRescanRssiDiff + * + * hHal - HAL handle for device + * 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(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamRescanRssiDiff, + REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamRescanRssiDiff = nRoamRescanRssiDiff; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_get_roam_rescan_rssi_diff() + * gets roam rescan rssi diff + * This is a synchronous call + * + * hHal - The handle returned by mac_open + * Return int8_t - nRoamRescanRssiDiff + */ +uint8_t sme_get_roam_rescan_rssi_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff; +} + +/* + * 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 + * hHal - HAL handle for device + * 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(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBmissFirstBcnt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamBmissFirstBcnt, + REASON_ROAM_BMISS_FIRST_BCNT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFirstBcnt = nRoamBmissFirstBcnt; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_get_roam_bmiss_first_bcnt() - + * get neighbor roam beacon miss first count + * + * hHal - The handle returned by mac_open. + * Return uint8_t - neighbor roam beacon miss first count + */ +uint8_t sme_get_roam_bmiss_first_bcnt(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt; +} + +/* + * 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 + * hHal - HAL handle for device + * 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(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamBmissFinalBcnt, + REASON_ROAM_BMISS_FINAL_BCNT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFinalBcnt = nRoamBmissFinalBcnt; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_get_roam_bmiss_final_bcnt() - + * gets Roam count for final beacon miss + * This is a synchronous call + * + * hHal - The handle returned by mac_open + * Return uint8_t - nRoamBmissFinalBcnt + */ +uint8_t sme_get_roam_bmiss_final_bcnt(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt; +} + +/* + * sme_set_roam_beacon_rssi_weight() - + * Update Roam beacon rssi weight + * This function is called through dynamic setConfig callback function + * to configure nRoamBeaconRssiWeight + * + * hHal - HAL handle for device + * sessionId - Session Identifier + * nRoamBeaconRssiWeight - Roam beacon rssi weight + * Return QDF_STATUS_SUCCESS - SME update nRoamBeaconRssiWeight config + * successfully. + * else SME is failed to update nRoamBeaconRssiWeight + */ +QDF_STATUS sme_set_roam_beacon_rssi_weight(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBeaconRssiWeight) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamBeaconRssiWeight, + REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamBeaconRssiWeight = nRoamBeaconRssiWeight; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_get_roam_beacon_rssi_weight() - + * gets Roam beacon rssi weight + * This is a synchronous call + * + * hHal - The handle returned by mac_open + * Return uint8_t - nRoamBeaconRssiWeight + */ +uint8_t sme_get_roam_beacon_rssi_weight(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight; +} + +/* + * sme_set_neighbor_lookup_rssi_threshold() - update neighbor lookup + * rssi threshold + * This is a synchronous call + * + * hHal - 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_lookup_rssi_threshold(tHalHandle hHal, + uint8_t sessionId, uint8_t neighborLookupRssiThreshold) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, + sessionId, neighborLookupRssiThreshold, + REASON_LOOKUP_THRESH_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold = + neighborLookupRssiThreshold; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_set_delay_before_vdev_stop() - update delay before VDEV_STOP + * This is a synchronous call + * + * hal - The handle returned by macOpen. + * session_id - Session Identifier + * delay_before_vdev_stop - value to be set + * Return QDF_STATUS_SUCCESS - SME update config successful. + * Other status means SME is failed to update + */ +QDF_STATUS sme_set_delay_before_vdev_stop(tHalHandle hal, + uint8_t session_id, + uint8_t delay_before_vdev_stop) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (session_id >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), session_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR param delay_before_vdev_stop changed from %d to %d", + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop, + delay_before_vdev_stop); + pMac->roam.neighborRoamInfo[session_id].cfgParams. + delay_before_vdev_stop = delay_before_vdev_stop; + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop = delay_before_vdev_stop; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_get_neighbor_lookup_rssi_threshold() - get neighbor lookup + * rssi threshold + * This is a synchronous call + * + * hHal - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS - SME update config successful. + * Other status means SME is failed to update + */ +uint8_t sme_get_neighbor_lookup_rssi_threshold(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold; +} + +/* + * sme_set_neighbor_scan_refresh_period() - set neighbor scan results + * refresh period + * This is a synchronous call + * + * hHal - 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(tHalHandle hHal, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_neighbor_roamconfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan refresh period to %d- old value is %d - roam state is %s", + neighborScanResultsRefreshPeriod, + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborResultsRefreshPeriod = + neighborScanResultsRefreshPeriod; + pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod = + neighborScanResultsRefreshPeriod; + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_NEIGHBOR_SCAN_REFRESH_PERIOD_CHANGED); + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_update_roam_scan_offload_enabled() - enable/disable roam scan + * offload feaure + * It is used at in the REG_DYNAMIC_VARIABLE macro definition of + * gRoamScanOffloadEnabled. + * This is a synchronous call + * + * hHal - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS - SME update config successfully. + * Other status means SME is failed to update. + */ +QDF_STATUS sme_update_roam_scan_offload_enabled(tHalHandle hHal, + bool nRoamScanOffloadEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "gRoamScanOffloadEnabled is changed from %d to %d", + pMac->roam.configParam.isRoamOffloadScanEnabled, + nRoamScanOffloadEnabled); + pMac->roam.configParam.isRoamOffloadScanEnabled = + nRoamScanOffloadEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_get_neighbor_scan_refresh_period() - get neighbor scan results + * refresh period + * This is a synchronous call + * + * \param hHal - The handle returned by mac_open. + * \return uint16_t - Neighbor scan results refresh period value + */ +uint16_t sme_get_neighbor_scan_refresh_period(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod; +} + +/* + * sme_get_empty_scan_refresh_period() - get empty scan refresh period + * This is a synchronuous call + * + * hHal - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS - SME update config successful. + * Other status means SME is failed to update + */ +uint16_t sme_get_empty_scan_refresh_period(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod; +} + +/* + * sme_update_empty_scan_refresh_period + * Update nEmptyScanRefreshPeriod + * This function is called through dynamic setConfig callback function + * to configure nEmptyScanRefreshPeriod + * Usage: adb shell iwpriv wlan0 setConfig + * nEmptyScanRefreshPeriod=[0 .. 60] + * + * hHal - HAL handle for device + * sessionId - Session Identifier + * nEmptyScanRefreshPeriod - scan period following empty scan results. + * Return Success or failure + */ + +QDF_STATUS sme_update_empty_scan_refresh_period(tHalHandle hHal, uint8_t + sessionId, uint16_t + nEmptyScanRefreshPeriod) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_neighbor_roamconfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan period to %d -old value is %d - roam state is %s", + nEmptyScanRefreshPeriod, + pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nEmptyScanRefreshPeriod = + nEmptyScanRefreshPeriod; + pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod = + nEmptyScanRefreshPeriod; + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_EMPTY_SCAN_REF_PERIOD_CHANGED); + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * 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] + * + * hHal - HAL handle for device + * nNeighborScanMinChanTime - Channel minimum dwell time + * sessionId - Session Identifier + * Return Success or failure + */ +QDF_STATUS sme_set_neighbor_scan_min_chan_time(tHalHandle hHal, + const uint16_t + nNeighborScanMinChanTime, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set channel min dwell time to %d - old value is %d - roam state is %s", + nNeighborScanMinChanTime, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime = nNeighborScanMinChanTime; + pMac->roam.neighborRoamInfo[sessionId].cfgParams. + minChannelScanTime = nNeighborScanMinChanTime; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * 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] + * + * hHal - HAL handle for device + * sessionId - Session Identifier + * nNeighborScanMinChanTime - Channel maximum dwell time + * Return Success or failure + */ +QDF_STATUS sme_set_neighbor_scan_max_chan_time(tHalHandle hHal, uint8_t + sessionId, + const uint16_t + nNeighborScanMaxChanTime) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_neighbor_roamconfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set channel max dwell time to %d - old value is %d - roam state is %s", + nNeighborScanMaxChanTime, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMaxChanTime, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborScanMaxChanTime = + nNeighborScanMaxChanTime; + pNeighborRoamInfo->cfgParams.maxChannelScanTime = + nNeighborScanMaxChanTime; + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_SCAN_CH_TIME_CHANGED); + } + sme_release_global_lock(&pMac->sme); + } + + + return status; +} + +/* + * sme_get_neighbor_scan_min_chan_time() - + * get neighbor scan min channel time + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint16_t - channel min time value + */ +uint16_t sme_get_neighbor_scan_min_chan_time(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + minChannelScanTime; +} + +/* + * sme_get_neighbor_roam_state() - + * get neighbor roam state + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - neighbor roam state + */ +uint32_t sme_get_neighbor_roam_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].neighborRoamState; +} + +/* + * sme_get_current_roam_state() - + * get current roam state + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - current roam state + */ +uint32_t sme_get_current_roam_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.curState[sessionId]; +} + +/* + * sme_get_current_roam_sub_state() - + * \brief get neighbor roam sub state + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - current roam sub state + */ +uint32_t sme_get_current_roam_sub_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.curSubState[sessionId]; +} + +/* + * sme_get_lim_sme_state() - + * get Lim Sme state + * + * hHal - The handle returned by mac_open. + * Return uint32_t - Lim Sme state + */ +uint32_t sme_get_lim_sme_state(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->lim.gLimSmeState; +} + +/* + * sme_get_lim_mlm_state() - + * get Lim Mlm state + * + * hHal - The handle returned by mac_open. + * Return uint32_t - Lim Mlm state + */ +uint32_t sme_get_lim_mlm_state(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->lim.gLimMlmState; +} + +/* + * sme_is_lim_session_valid() - + * is Lim session valid + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return bool - true or false + */ +bool sme_is_lim_session_valid(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId > pMac->lim.maxBssId) + return false; + + return pMac->lim.gpSession[sessionId].valid; +} + +/* + * sme_get_lim_sme_session_state() - + * get Lim Sme session state + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - Lim Sme session state + */ +uint32_t sme_get_lim_sme_session_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->lim.gpSession[sessionId].limSmeState; +} + +/* + * sme_get_lim_mlm_session_state() - + * \brief get Lim Mlm session state + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - Lim Mlm session state + */ +uint32_t sme_get_lim_mlm_session_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->lim.gpSession[sessionId].limMlmState; +} + +/* + * sme_get_neighbor_scan_max_chan_time() - + * get neighbor scan max channel time + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint16_t - channel max time value + */ +uint16_t sme_get_neighbor_scan_max_chan_time(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + maxChannelScanTime; +} + +/* + * 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] + * + * hHal - HAL handle for device + * sessionId - Session Identifier + * nNeighborScanPeriod - neighbor scan period + * Return Success or failure + */ +QDF_STATUS sme_set_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId, + const uint16_t nNeighborScanPeriod) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_neighbor_roamconfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set neighbor scan period to %d - old value is %d - roam state is %s", + nNeighborScanPeriod, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanTimerPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborScanTimerPeriod = + nNeighborScanPeriod; + pNeighborRoamInfo->cfgParams.neighborScanPeriod = + nNeighborScanPeriod; + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_SCAN_HOME_TIME_CHANGED); + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_get_neighbor_scan_period() - + * get neighbor scan period + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint16_t - neighbor scan period + */ +uint16_t sme_get_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + neighborScanPeriod; +} + +/** + * sme_set_neighbor_scan_min_period() - Update neighbor_scan_min_period + * This function is called through dynamic setConfig callback function + * to configure neighbor_scan_min_period + * + * @hal - HAL handle for device + * @session_id - Session Identifier + * @neighbor_scan_min_period - neighbor scan min period + * + * Return - QDF_STATUS + */ +QDF_STATUS sme_set_neighbor_scan_min_period(tHalHandle hal, + uint8_t session_id, + const uint16_t + neighbor_scan_min_period) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_neighbor_roamconfig *p_neighbor_roam_config = NULL; + tpCsrNeighborRoamControlInfo p_neighbor_roam_info = NULL; + + if (session_id >= CSR_ROAM_SESSION_MAX) { + sme_err("Invalid sme session id: %d", session_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pmac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + p_neighbor_roam_config = + &pmac->roam.configParam.neighborRoamConfig; + p_neighbor_roam_info = &pmac-> + roam.neighborRoamInfo[session_id]; + sme_debug("LFR:set neighbor scan min period, old:%d, " + "new: %d, state: %s", + pmac->roam.configParam.neighborRoamConfig. + neighbor_scan_min_timer_period, + neighbor_scan_min_period, + mac_trace_get_neighbour_roam_state(pmac->roam. + neighborRoamInfo[session_id]. + neighborRoamState)); + p_neighbor_roam_config->neighbor_scan_min_timer_period = + neighbor_scan_min_period; + p_neighbor_roam_info->cfgParams.neighbor_scan_min_period = + neighbor_scan_min_period; + sme_release_global_lock(&pmac->sme); + } + + return status; +} + +/* + * sme_get_roam_rssi_diff() - get Roam rssi diff + * This is a synchronous call + * + * hHal - The handle returned by mac_open. + * Return uint16_t - Rssi diff value + */ +uint8_t sme_get_roam_rssi_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.RoamRssiDiff; +} + +/** + * sme_change_roam_scan_channel_list() - to change scan channel list + * @hHal: pointer HAL handle returned by mac_open + * @sessionId: sme session id + * @pChannelList: Output channel list + * @numChannels: Output number of channels + * + * This routine is called to Change roam scan channel list. + * This is a synchronous call + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_change_roam_scan_channel_list(tHalHandle hHal, uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + uint8_t oldChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t newChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t i = 0, j = 0; + tCsrChannelInfo *chan_info; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to acquire SME lock"); + return status; + } + chan_info = &pNeighborRoamInfo->cfgParams.channelInfo; + + if (NULL != chan_info->ChannelList) { + for (i = 0; i < chan_info->numOfChannels; i++) { + if (j < sizeof(oldChannelList)) + j += snprintf(oldChannelList + j, + sizeof(oldChannelList) - + j, "%d", + chan_info->ChannelList[i]); + else + break; + } + } + csr_flush_cfg_bg_scan_roam_channel_list(pMac, sessionId); + csr_create_bg_scan_roam_channel_list(pMac, sessionId, pChannelList, + numChannels); + sme_set_roam_scan_control(hHal, sessionId, 1); + if (NULL != chan_info->ChannelList) { + j = 0; + for (i = 0; i < chan_info->numOfChannels; i++) { + if (j < sizeof(newChannelList)) + j += snprintf(newChannelList + j, + sizeof(newChannelList) - + j, " %d", + chan_info->ChannelList[i]); + else + break; + } + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan channels to %s - old value is %s - roam state is %d", + newChannelList, oldChannelList, + pMac->roam.neighborRoamInfo[sessionId].neighborRoamState); + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + + sme_release_global_lock(&pMac->sme); + return status; +} + +/** + * sme_get_roam_scan_channel_list() - To get roam scan channel list + * @hHal: HAL pointer + * @pChannelList: Output channel 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(tHalHandle hHal, + uint8_t *pChannelList, uint8_t *pNumChannels, + uint8_t sessionId) +{ + int i = 0; + uint8_t *pOutPtr = pChannelList; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("Roam Scan channel list is NOT yet initialized")); + *pNumChannels = 0; + sme_release_global_lock(&pMac->sme); + return status; + } + + *pNumChannels = pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels; + for (i = 0; i < (*pNumChannels); i++) + pOutPtr[i] = + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList[i]; + + pOutPtr[i] = '\0'; + sme_release_global_lock(&pMac->sme); + return status; +} + +/* + * sme_get_is_ese_feature_enabled() - get ESE feature enabled or not + * This is a synchronuous call + * + * hHal - The handle returned by mac_open. + * Return true (1) - if the ESE feature is enabled + * false (0) - if feature is disabled (compile or runtime) + */ +bool sme_get_is_ese_feature_enabled(tHalHandle hHal) +{ +#ifdef FEATURE_WLAN_ESE + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_roam_is_ese_ini_feature_enabled(pMac); +#else + return false; +#endif +} + +/* + * sme_get_wes_mode() - get WES Mode + * This is a synchronous call + * + * hHal - The handle returned by mac_open + * Return uint8_t - WES Mode Enabled(1)/Disabled(0) + */ +bool sme_get_wes_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.isWESModeEnabled; +} + +/* + * sme_get_roam_scan_control() - get scan control + * This is a synchronous call + * + * hHal - The handle returned by mac_open. + * Return bool - Enabled(1)/Disabled(0) + */ +bool sme_get_roam_scan_control(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.nRoamScanControl; +} + +/* + * sme_get_is_lfr_feature_enabled() - get LFR feature enabled or not + * This is a synchronuous call + * hHal - The handle returned by mac_open. + * Return true (1) - if the feature is enabled + * false (0) - if feature is disabled (compile or runtime) + */ +bool sme_get_is_lfr_feature_enabled(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.isFastRoamIniFeatureEnabled; +} + +/* + * sme_get_is_ft_feature_enabled() - get FT feature enabled or not + * This is a synchronuous call + * + * hHal - The handle returned by mac_open. + * Return true (1) - if the feature is enabled + * false (0) - if feature is disabled (compile or runtime) + */ +bool sme_get_is_ft_feature_enabled(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.isFastTransitionEnabled; +} + +/** + * sme_is_feature_supported_by_fw() - check if feature is supported by FW + * @feature: enum value of requested feature. + * + * Retrun: 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(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, + void *plsContext, + void (*pCallbackfn)(tSirLinkSpeedInfo *indParam, + void *pContext)) +{ + + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac; + void *wma_handle; + + if (!hHal || !pCallbackfn || !lsReq) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid parameter")); + return QDF_STATUS_E_FAILURE; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Failed to acquire global lock"); + return QDF_STATUS_E_FAILURE; + } + + pMac->sme.pLinkSpeedCbContext = plsContext; + pMac->sme.pLinkSpeedIndCb = pCallbackfn; + status = wma_get_link_speed(wma_handle, lsReq); + sme_release_global_lock(&pMac->sme); + return status; +} + +QDF_STATUS sme_get_peer_stats(tpAniSirGlobal mac, + struct sir_peer_info_req req) +{ + QDF_STATUS qdf_status; + struct scheduler_msg message = {0}; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_debug("Failed to get Lock"); + return qdf_status; + } + /* serialize the req through MC thread */ + message.bodyptr = qdf_mem_malloc(sizeof(req)); + if (NULL == message.bodyptr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation failed.", __func__); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(message.bodyptr, &req, sizeof(req)); + message.type = WMA_GET_PEER_INFO; + message.reserved = 0; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post get peer info msg fail", __func__); + qdf_mem_free(message.bodyptr); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return qdf_status; +} + +QDF_STATUS sme_get_peer_info(tHalHandle hal, struct sir_peer_info_req req, + void *context, + void (*callbackfn)(struct sir_peer_info_resp *param, + void *pcontext)) +{ + + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + if (NULL == callbackfn) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Indication Call back is NULL", + __func__); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + mac->sme.pget_peer_info_ind_cb = callbackfn; + mac->sme.pget_peer_info_cb_context = context; + + /* serialize the req through MC thread */ + message.bodyptr = qdf_mem_malloc(sizeof(req)); + if (NULL == message.bodyptr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation failed.", __func__); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(message.bodyptr, &req, sizeof(req)); + message.type = WMA_GET_PEER_INFO; + message.reserved = 0; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post get peer info msg fail", __func__); + qdf_mem_free(message.bodyptr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS sme_get_peer_info_ext(tHalHandle hal, + struct sir_peer_info_ext_req *req, + void *context, + void (*callbackfn)(struct sir_peer_info_ext_resp *param, + void *pcontext)) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + if (NULL == callbackfn) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Indication Call back is NULL", + __func__); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + mac->sme.pget_peer_info_ext_ind_cb = callbackfn; + mac->sme.pget_peer_info_ext_cb_context = context; + + /* serialize the req through MC thread */ + message.bodyptr = + qdf_mem_malloc(sizeof(struct sir_peer_info_ext_req)); + if (NULL == message.bodyptr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation failed.", __func__); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(message.bodyptr, + req, + sizeof(struct sir_peer_info_ext_req)); + message.type = WMA_GET_PEER_INFO_EXT; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post get rssi msg fail", __func__); + qdf_mem_free(message.bodyptr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * SME API to enable/disable WLAN driver initiated SSR + */ +void sme_update_enable_ssr(tHalHandle hHal, bool enableSSR) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("SSR level is changed %d", enableSSR); + /* not serializing this message, as this is only going + * to set a variable in WMA/WDI + */ + WMA_SetEnableSSR(enableSSR); + sme_release_global_lock(&pMac->sme); + } +} + +QDF_STATUS sme_get_isolation(mac_handle_t mac_handle, void *context, + sme_get_isolation_cb callbackfn) +{ + QDF_STATUS status; + tpAniSirGlobal 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_set_curr_device_mode() - Sets the current operating device mode. + * + * hHal - The handle returned by mac_open. + * currDeviceMode - Current operating device mode. + */ +void sme_set_curr_device_mode(tHalHandle hHal, + enum QDF_OPMODE currDeviceMode) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->sme.currDeviceMode = currDeviceMode; +} + +/* + * sme_handoff_request() - a wrapper function to Request a handoff from CSR. + * This is a synchronous call + * + * hHal - The handle returned by mac_open + * sessionId - Session Identifier + * pHandoffInfo - info provided by HDD with the handoff request (namely: + * BSSID, channel etc.) + * Return QDF_STATUS_SUCCESS - SME passed the request to CSR successfully. + * Other status means SME is failed to send the request. + */ + +QDF_STATUS sme_handoff_request(tHalHandle hHal, + uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: invoked", __func__); + status = csr_handoff_request(pMac, sessionId, pHandoffInfo); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * SME API to check if there is any infra station or + * P2P client is connected + */ +QDF_STATUS sme_is_sta_p2p_client_connected(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (csr_is_infra_connected(pMac)) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; +} + +/** + * sme_add_periodic_tx_ptrn() - Add Periodic TX Pattern + * @hal: global hal handle + * @addPeriodicTxPtrnParams: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +sme_add_periodic_tx_ptrn(tHalHandle hal, + struct sSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirAddPeriodicTxPtrn *req_msg; + struct scheduler_msg msg = {0}; + + SME_ENTER(); + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sme_err("memory allocation failed"); + 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 + * @hal: global hal handle + * @delPeriodicTxPtrnParams: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +sme_del_periodic_tx_ptrn(tHalHandle hal, + struct sSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirDelPeriodicTxPtrn *req_msg; + struct scheduler_msg msg = {0}; + + SME_ENTER(); + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sme_err("memory allocation failed"); + 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; +} + +/* + * sme_enable_rmc() - enables RMC + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_rmc(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + SME_ENTER(); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + message.bodyptr = NULL; + message.type = WMA_RMC_ENABLE_IND; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_disable_rmc() - disables RMC + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_disable_rmc(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + SME_ENTER(); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + message.bodyptr = NULL; + message.type = WMA_RMC_DISABLE_IND; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_send_rmc_action_period() - sends RMC action period param to target + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_rmc_action_period(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + message.bodyptr = NULL; + message.type = WMA_RMC_ACTION_PERIOD_IND; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_request_ibss_peer_info() - request ibss peer info + * @hHal : Pointer to global HAL handle + * @pUserData : Pointer to user data + * @peerInfoCbk : Peer info callback + * @allPeerInfoReqd : All peer info required or not + * @staIdx : sta index + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_request_ibss_peer_info(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, + bool allPeerInfoReqd, uint8_t staIdx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + tSirIbssGetPeerInfoReqParams *pIbssInfoReqParams; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pMac->sme.peerInfoParams.peerInfoCbk = peerInfoCbk; + pMac->sme.peerInfoParams.pUserData = pUserData; + + pIbssInfoReqParams = (tSirIbssGetPeerInfoReqParams *) + qdf_mem_malloc(sizeof(tSirIbssGetPeerInfoReqParams)); + if (NULL == pIbssInfoReqParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp start", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + pIbssInfoReqParams->allPeerInfoReqd = allPeerInfoReqd; + pIbssInfoReqParams->staIdx = staIdx; + + message.type = WMA_GET_IBSS_PEER_INFO_REQ; + message.bodyptr = pIbssInfoReqParams; + message.reserved = 0; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post WMA_GET_IBSS_PEER_INFO_REQ MSG failed", + __func__); + qdf_mem_free(pIbssInfoReqParams); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return qdf_status; +} + +/* + * sme_send_cesium_enable_ind() - + * Used to send proprietary cesium enable indication to fw + * + * hHal + * sessionId + * Return QDF_STATUS + */ +QDF_STATUS sme_send_cesium_enable_ind(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + message.bodyptr = NULL; + message.type = WMA_IBSS_CESIUM_ENABLE_IND; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_set_wlm_latency_level(tHalHandle hal, uint16_t session_id, + uint16_t latency_level) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct wlm_latency_level_param params; + void *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_FAILURE; + + if (!mac_ctx->roam.configParam.wlm_latency_enable) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: WLM latency level setting is disabled", + __func__); + return QDF_STATUS_E_FAILURE; + } + if (!wma) { + sme_err("wma is NULL"); + return QDF_STATUS_E_FAILURE; + } + + params.wlm_latency_level = latency_level; + params.wlm_latency_flags = + mac_ctx->roam.configParam.wlm_latency_flags[latency_level]; + params.vdev_id = session_id; + + status = wma_set_wlm_latency_level(wma, ¶ms); + if (!QDF_IS_STATUS_SUCCESS(status)) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to set latency level", + __func__); + + return status; +} + +void sme_get_command_q_status(tHalHandle hHal) +{ + tSmeCmd *pTempCmd = NULL; + tListElem *pEntry; + tpAniSirGlobal pMac; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return; + } + pEntry = csr_nonscan_active_ll_peek_head(pMac, LL_ACCESS_LOCK); + if (pEntry) + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + + sme_err("WLAN_BUG_RCA: Currently smeCmdActiveList has command (0x%X)", + (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(pMac, pTempCmd); + } /* if(pTempCmd) */ + + sme_err("Currently smeCmdPendingList has %d commands", + csr_nonscan_pending_ll_count(pMac)); + +} +/** + * sme_set_prefer_80MHz_over_160MHz() - API to set sta_prefer_80MHz_over_160MHz + * @hal: The handle returned by macOpen + * @sta_prefer_80MHz_over_160MHz: sta_prefer_80MHz_over_160MHz config param + */ +void sme_set_prefer_80MHz_over_160MHz(tHalHandle hal, + bool sta_prefer_80MHz_over_160MHz) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + mac_ctx->sta_prefer_80MHz_over_160MHz = sta_prefer_80MHz_over_160MHz; +} + +#ifdef WLAN_FEATURE_DSRC +/** + * sme_set_dot11p_config() - API to set the 802.11p config + * @hHal: The handle returned by macOpen + * @enable_dot11p: 802.11p config param + */ +void sme_set_dot11p_config(tHalHandle hHal, bool enable_dot11p) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->enable_dot11p = enable_dot11p; +} + +/** + * sme_ocb_gen_timing_advert_frame() - generate TA frame and populate the buffer + * @hal_handle: reference to the HAL + * @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. + */ +int sme_ocb_gen_timing_advert_frame(tHalHandle hal_handle, + tSirMacAddr self_addr, uint8_t **buf, + uint32_t *timestamp_offset, + uint32_t *time_value_offset) +{ + int template_length; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + + template_length = sch_gen_timing_advert_frame(mac_ctx, self_addr, buf, + timestamp_offset, + time_value_offset); + return template_length; +} + +#else +void sme_set_etsi13_srd_ch_in_master_mode(tHalHandle hal, + bool etsi13_srd_chan_support) +{ + tpAniSirGlobal mac; + + mac = PMAC_STRUCT(hal); + mac->sap.enable_etsi13_srd_chan_support = etsi13_srd_chan_support; + sme_debug("srd_ch_support %d", mac->sap.enable_etsi13_srd_chan_support); +} +#endif + +void sme_get_recovery_stats(tHalHandle hHal) +{ + uint8_t i; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Self Recovery Stats"); + for (i = 0; i < MAX_ACTIVE_CMD_STATS; i++) { + if (eSmeNoCommand != + g_self_recovery_stats.activeCmdStats[i].command) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "timestamp %llu: command 0x%0X: reason %d: session %d", + g_self_recovery_stats.activeCmdStats[i]. + timestamp, + g_self_recovery_stats.activeCmdStats[i].command, + g_self_recovery_stats.activeCmdStats[i].reason, + g_self_recovery_stats.activeCmdStats[i]. + sessionId); + } + } +} + +QDF_STATUS sme_notify_modem_power_state(tHalHandle hHal, uint32_t value) +{ + struct scheduler_msg msg = {0}; + tpSirModemPowerStateInd request_buf; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) + return QDF_STATUS_E_FAILURE; + + request_buf = qdf_mem_malloc(sizeof(tSirModemPowerStateInd)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for MODEM POWER STATE IND", + __func__); + 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_MODEM_POWER_STATE_IND message to WMA", + __func__); + 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(tHalHandle hHal, uint16_t staId, + struct qdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type) +{ + struct scheduler_msg msg = {0}; + tUpdateVHTOpMode *pHtOpMode = NULL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) + return QDF_STATUS_E_FAILURE; + + pHtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pHtOpMode) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for setting OP mode", + __func__); + 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid OP mode", __func__); + qdf_mem_free(pHtOpMode); + return QDF_STATUS_E_FAILURE; + } + + pHtOpMode->staId = staId, + 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_SUCCESS + (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_UPDATE_OP_MODE message to WMA", + __func__); + qdf_mem_free(pHtOpMode); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Notified FW about OP mode: %d for staId=%d", + __func__, pHtOpMode->opMode, staId); + + 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(tHalHandle hHal, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + ePhyChanBondState cbMode; + struct csr_roam_session *session = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sme_err("Session not valid for session id %d", sessionId); + return QDF_STATUS_E_INVAL; + } + session = CSR_GET_SESSION(pMac, sessionId); + sme_debug("Update HT operation beacon IE, channel_type=%d cur cbmode %d", + channel_type, session->bssParams.cbMode); + + switch (channel_type) { + case eHT_CHAN_HT20: + if (!session->bssParams.cbMode) + return QDF_STATUS_SUCCESS; + cbMode = PHY_SINGLE_CHANNEL_CENTERED; + break; + case eHT_CHAN_HT40MINUS: + if (session->bssParams.cbMode) + return QDF_STATUS_SUCCESS; + cbMode = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + case eHT_CHAN_HT40PLUS: + if (session->bssParams.cbMode) + return QDF_STATUS_SUCCESS; + cbMode = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + default: + sme_err("Error!!! Invalid HT20/40 mode !"); + return QDF_STATUS_E_FAILURE; + } + session->bssParams.cbMode = cbMode; + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_ht2040_mode(pMac, sessionId, + cbMode, obssEnabled); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#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 (NULL == wmaContext) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: wmaContext is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + " Idle Ps Set Value %d", value); + + if (QDF_STATUS_SUCCESS != wma_set_idle_ps_config(wmaContext, value)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + " Failed to Set Idle Ps Value %d", value); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +int16_t sme_get_ht_config(tHalHandle hHal, uint8_t session_id, + uint16_t ht_capab) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, session_id); + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: pSession is NULL", __func__); + return -EIO; + } + switch (ht_capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + return pSession->htConfig.ht_rx_ldpc; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + return pSession->htConfig.ht_tx_stbc; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + return pSession->htConfig.ht_rx_stbc; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + return pSession->htConfig.ht_sgi20; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + return pSession->htConfig.ht_sgi40; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "invalid ht capability"); + return -EIO; + } +} + +int sme_update_ht_config(tHalHandle hHal, uint8_t sessionId, uint16_t htCapab, + int value) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: pSession is NULL", __func__); + return -EIO; + } + + if (QDF_STATUS_SUCCESS != wma_set_htconfig(sessionId, htCapab, value)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to set ht capability in target"); + return -EIO; + } + + switch (htCapab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + pSession->htConfig.ht_rx_ldpc = value; + pMac->roam.configParam.rx_ldpc_enable = value; + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + pSession->htConfig.ht_tx_stbc = value; + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + pSession->htConfig.ht_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 */ + pSession->htConfig.ht_sgi20 = value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + value = value ? 1 : 0; /* HT SGI can be only 1 or 0 */ + pSession->htConfig.ht_sgi40 = value; + break; + } + + csr_roam_update_config(pMac, sessionId, htCapab, value); + return 0; +} + +int sme_set_addba_accept(tHalHandle hal, 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) { + sme_err("mem alloc failed for 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(tHalHandle hal, uint8_t session_id, + uint16_t buff_size) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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(tHalHandle hal, uint8_t session_id, uint8_t tid, + uint16_t buff_size) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint16_t ba_buff = 0; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct send_add_ba_req *send_ba_req; + struct csr_roam_session *csr_session = NULL; + + if (!csr_is_conn_state_connected_infra(mac_ctx, session_id)) { + sme_err("STA not infra/connected state session_id: %d", + session_id); + return -EINVAL; + } + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + if (!csr_session) { + sme_err("CSR session is NULL"); + return -EINVAL; + } + send_ba_req = qdf_mem_malloc(sizeof(*send_ba_req)); + if (!send_ba_req) { + sme_err("mem alloc failed"); + return -EIO; + } + qdf_mem_copy(send_ba_req->mac_addr, + csr_session->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + 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) { + sme_err("Failed to post WMA_SEND_ADDBA_REQ"); + 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(tHalHandle hal, uint8_t session_id, + uint8_t val, uint8_t ac) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint8_t i, set_val; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + if (ac > MAX_NUM_AC) { + sme_err("invalid ac val %d", ac); + return -EINVAL; + } + if (val) + set_val = 1; + else + set_val = 0; + if (ac == MAX_NUM_AC) { + 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(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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; +} + +#define HT20_SHORT_GI_MCS7_RATE 722 +/* + * sme_send_rate_update_ind() - + * API to Update rate + * + * hHal - The handle returned by mac_open + * rateUpdateParams - Pointer to rate update params + * Return QDF_STATUS + */ +QDF_STATUS sme_send_rate_update_ind(tHalHandle hHal, + tSirRateUpdateInd *rateUpdateParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status; + struct scheduler_msg msg = {0}; + tSirRateUpdateInd *rate_upd = qdf_mem_malloc(sizeof(tSirRateUpdateInd)); + + if (rate_upd == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Rate update struct alloc failed"); + 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(&pMac->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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_RATE_UPDATE_IND to WMA!", + __func__); + qdf_mem_free(rate_upd); + status = QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_update_access_policy_vendor_ie() - update vendor ie and access policy. + * @hal: Pointer to the mac context + * @session_id: sme session 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(tHalHandle hal, + uint8_t session_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) { + sme_err("failed to allocate memory for sme_update_access_policy_vendor_ie"); + return QDF_STATUS_E_FAILURE; + } + + 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->sme_session_id = session_id; + msg->access_policy = access_policy; + + sme_debug("sme_session_id: %hu, access_policy: %d", session_id, + access_policy); + + status = umac_send_mb_message_to_mac(msg); + + return status; +} + +/** + * sme_update_short_retry_limit_threshold() - update short frame retry limit TH + * @hal: Handle returned by mac_open + * @session_id: Session ID on which short frame retry limit needs to be + * updated to FW + * @short_limit_count_th: Retry count TH to retry short frame. + * + * This function is used to configure count to retry short frame. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_short_retry_limit_threshold(tHalHandle hal_handle, + struct sme_short_retry_limit *short_retry_limit_th) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sme_short_retry_limit *srl; + struct scheduler_msg msg = {0}; + + srl = qdf_mem_malloc(sizeof(*srl)); + if (NULL == srl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc short retry limit", __func__); + return QDF_STATUS_E_FAILURE; + } + sme_debug("session_id %d short retry limit count: %d", + short_retry_limit_th->session_id, + short_retry_limit_th->short_retry_limit); + + srl->session_id = short_retry_limit_th->session_id; + srl->short_retry_limit = short_retry_limit_th->short_retry_limit; + + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = SIR_HAL_SHORT_RETRY_LIMIT_CNT; + msg.reserved = 0; + msg.bodyptr = srl; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post short retry limit count to WDA")); + qdf_mem_free(srl); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * sme_update_long_retry_limit_threshold() - update long retry limit TH + * @hal: Handle returned by mac_open + * @session_id: Session ID on which long frames retry TH needs to be updated + * to FW + * @long_limit_count_th: Retry count to retry long frame. + * + * This function is used to configure TH to retry long frame. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_long_retry_limit_threshold(tHalHandle hal_handle, + struct sme_long_retry_limit *long_retry_limit_th) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sme_long_retry_limit *lrl; + struct scheduler_msg msg = {0}; + + lrl = qdf_mem_malloc(sizeof(*lrl)); + if (NULL == lrl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc long retry limit", __func__); + return QDF_STATUS_E_FAILURE; + } + sme_debug("session_id %d long retry limit count: %d", + long_retry_limit_th->session_id, + long_retry_limit_th->long_retry_limit); + + lrl->session_id = long_retry_limit_th->session_id; + lrl->long_retry_limit = long_retry_limit_th->long_retry_limit; + + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = SIR_HAL_LONG_RETRY_LIMIT_CNT; + msg.reserved = 0; + msg.bodyptr = lrl; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post long retry limit count to WDA")); + qdf_mem_free(lrl); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * sme_update_sta_inactivity_timeout(): Update sta_inactivity_timeout to FW + * @hal: 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(tHalHandle hal_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 (NULL == inactivity_time) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc inactivity_time", __func__); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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; +} + +/** + * sme_get_reg_info() - To get registration info + * @hHal: HAL context + * @chanId: channel id + * @regInfo1: first reg info to fill + * @regInfo2: second reg info to fill + * + * This routine will give you reg info + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_reg_info(tHalHandle hHal, uint8_t chanId, + uint32_t *regInfo1, uint32_t *regInfo2) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status; + uint8_t i; + bool found = false; + + status = sme_acquire_global_lock(&pMac->sme); + *regInfo1 = 0; + *regInfo2 = 0; + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + for (i = 0; i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (pMac->scan.defaultPowerTable[i].chan_num == chanId) { + SME_SET_CHANNEL_REG_POWER(*regInfo1, + pMac->scan.defaultPowerTable[i].tx_power); + + SME_SET_CHANNEL_MAX_TX_POWER(*regInfo2, + pMac->scan.defaultPowerTable[i].tx_power); + found = true; + break; + } + } + if (!found) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + return status; +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/* + * sme_auto_shutdown_cb() - + * Used to plug in callback function for receiving auto shutdown evt + * + * hHal + * pCallbackfn : callback function pointer should be plugged in + * Return QDF_STATUS + */ +QDF_STATUS sme_set_auto_shutdown_cb(tHalHandle hHal, void (*pCallbackfn)(void) + ) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Plug in Auto shutdown event callback", __func__); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + if (NULL != pCallbackfn) + pMac->sme.pAutoShutdownNotificationCb = pCallbackfn; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * sme_set_auto_shutdown_timer() - + * API to set auto shutdown timer value in FW. + * + * hHal - 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(tHalHandle hHal, uint32_t timer_val) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirAutoShutdownCmdParams *auto_sh_cmd; + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + auto_sh_cmd = (tSirAutoShutdownCmdParams *) + qdf_mem_malloc(sizeof(tSirAutoShutdownCmdParams)); + if (auto_sh_cmd == NULL) { + sme_err("Request Buffer Alloc Fail"); + sme_release_global_lock(&pMac->sme); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post Auto shutdown MSG fail", __func__); + qdf_mem_free(auto_sh_cmd); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Posted Auto shutdown MSG", __func__); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif + +#ifdef FEATURE_WLAN_CH_AVOID +/* + * sme_ch_avoid_update_req() - + * API to request channel avoidance update from FW. + * + * hHal - 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(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirChAvoidUpdateReq *cauReq; + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + cauReq = (tSirChAvoidUpdateReq *) + qdf_mem_malloc(sizeof(tSirChAvoidUpdateReq)); + if (NULL == cauReq) { + sme_err("Request Buffer Alloc Fail"); + sme_release_global_lock(&pMac->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_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post Ch Avoid Update MSG fail", + __func__); + qdf_mem_free(cauReq); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Posted Ch Avoid Update MSG", __func__); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif + +/** + * sme_set_miracast() - Function to set miracast value to UMAC + * @hal: 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(tHalHandle hal, uint8_t filter_type) +{ + struct scheduler_msg msg = {0}; + uint32_t *val; + tpAniSirGlobal mac_ptr = PMAC_STRUCT(hal); + + if (!mac_ptr) { + sme_err("Invalid pointer"); + return QDF_STATUS_E_NOMEM; + } + + val = qdf_mem_malloc(sizeof(*val)); + if (!val) { + sme_err("Mem allocation failed"); + 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!", + __func__); + 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 (NULL == ptr_val) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: could not allocate ptr_val", __func__); + 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!", + __func__); + qdf_mem_free(ptr_val); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_roam_channel_change_req() - Channel change to new target channel + * @hHal: handle returned by mac_open + * @bssid: mac address of BSS + * @ch_params: target channel information + * @profile: CSR profile + * + * API to Indicate Channel change to new target channel + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_roam_channel_change_req(tHalHandle hHal, + struct qdf_mac_addr bssid, + struct ch_params *ch_params, + struct csr_roam_profile *profile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + status = csr_roam_channel_change_req(pMac, bssid, ch_params, + profile); + sme_release_global_lock(&pMac->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(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info proam_info = { 0 }; + eCsrRoamResult roamResult; + tpSwitchChannelParams pChnlParams = (tpSwitchChannelParams) pMsgBuf; + uint32_t SessionId = pChnlParams->peSessionId; + + proam_info.channelChangeRespEvent = + (tSirChanChangeResponse *) + qdf_mem_malloc(sizeof(tSirChanChangeResponse)); + if (NULL == proam_info.channelChangeRespEvent) { + status = QDF_STATUS_E_NOMEM; + sme_err("Channel Change Event Allocation Failed: %d\n", status); + return status; + } + if (msg_type == eWNI_SME_CHANNEL_CHANGE_RSP) { + proam_info.channelChangeRespEvent->sessionId = SessionId; + proam_info.channelChangeRespEvent->newChannelNumber = + pChnlParams->channelNumber; + + if (pChnlParams->status == QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "sapdfs: Received success eWNI_SME_CHANNEL_CHANGE_RSP for sessionId[%d]", + SessionId); + proam_info.channelChangeRespEvent->channelChangeStatus = + 1; + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "sapdfs: Received failure eWNI_SME_CHANNEL_CHANGE_RSP for sessionId[%d]", + SessionId); + proam_info.channelChangeRespEvent->channelChangeStatus = + 0; + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE; + } + + csr_roam_call_callback(pMac, SessionId, &proam_info, 0, + eCSR_ROAM_SET_CHANNEL_RSP, roamResult); + + } else { + status = QDF_STATUS_E_FAILURE; + sme_err("Invalid Channel Change Resp Message: %d", + status); + } + qdf_mem_free(proam_info.channelChangeRespEvent); + + return status; +} + +/* + * sme_roam_start_beacon_req() - + * API to Indicate LIM to start Beacon Tx after SAP CAC Wait is completed. + * + * hHal - The handle returned by mac_open + * sessionId - session ID + * dfsCacWaitStatus - CAC WAIT status flag + * Return QDF_STATUS + */ +QDF_STATUS sme_roam_start_beacon_req(tHalHandle hHal, struct qdf_mac_addr bssid, + uint8_t dfsCacWaitStatus) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_start_beacon_req(pMac, bssid, + dfsCacWaitStatus); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_roam_csa_ie_request() - request CSA IE transmission from PE + * @hHal: handle returned by mac_open + * @bssid: SAP bssid + * @targetChannel: target channel information + * @csaIeReqd: CSA IE Request + * @ch_params: channel information + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_roam_csa_ie_request(tHalHandle hHal, struct qdf_mac_addr bssid, + uint8_t targetChannel, uint8_t csaIeReqd, + struct ch_params *ch_params) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_send_chan_sw_ie_request(pMac, bssid, + targetChannel, csaIeReqd, ch_params); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_init_thermal_info() - + * SME API to initialize the thermal mitigation parameters + * + * hHal + * thermalParam : thermal mitigation parameters + * Return QDF_STATUS + */ +QDF_STATUS sme_init_thermal_info(tHalHandle hHal, tSmeThermalParams + thermalParam) +{ + t_thermal_mgmt *pWmaParam; + struct scheduler_msg msg = {0}; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pWmaParam = (t_thermal_mgmt *) qdf_mem_malloc(sizeof(t_thermal_mgmt)); + if (NULL == pWmaParam) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: could not allocate tThermalMgmt", __func__); + return QDF_STATUS_E_NOMEM; + } + + pWmaParam->thermalMgmtEnabled = thermalParam.smeThermalMgmtEnabled; + pWmaParam->throttlePeriod = thermalParam.smeThrottlePeriod; + + pWmaParam->throttle_duty_cycle_tbl[0] = + thermalParam.sme_throttle_duty_cycle_tbl[0]; + pWmaParam->throttle_duty_cycle_tbl[1] = + thermalParam.sme_throttle_duty_cycle_tbl[1]; + pWmaParam->throttle_duty_cycle_tbl[2] = + thermalParam.sme_throttle_duty_cycle_tbl[2]; + pWmaParam->throttle_duty_cycle_tbl[3] = + thermalParam.sme_throttle_duty_cycle_tbl[3]; + + pWmaParam->thermalLevels[0].minTempThreshold = + thermalParam.smeThermalLevels[0].smeMinTempThreshold; + pWmaParam->thermalLevels[0].maxTempThreshold = + thermalParam.smeThermalLevels[0].smeMaxTempThreshold; + pWmaParam->thermalLevels[1].minTempThreshold = + thermalParam.smeThermalLevels[1].smeMinTempThreshold; + pWmaParam->thermalLevels[1].maxTempThreshold = + thermalParam.smeThermalLevels[1].smeMaxTempThreshold; + pWmaParam->thermalLevels[2].minTempThreshold = + thermalParam.smeThermalLevels[2].smeMinTempThreshold; + pWmaParam->thermalLevels[2].maxTempThreshold = + thermalParam.smeThermalLevels[2].smeMaxTempThreshold; + pWmaParam->thermalLevels[3].minTempThreshold = + thermalParam.smeThermalLevels[3].smeMinTempThreshold; + pWmaParam->thermalLevels[3].maxTempThreshold = + thermalParam.smeThermalLevels[3].smeMaxTempThreshold; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_THERMAL_INFO_CMD to WMA!", + __func__); + qdf_mem_free(pWmaParam); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->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 + * @hal: 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(tHalHandle hal, + sme_set_thermal_level_callback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + + pMac->sme.set_thermal_level_cb = callback; +} + +/** + * sme_set_thermal_level() - SME API to set the thermal mitigation level + * @hal: Handler to HAL + * @level: Thermal mitigation level + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_thermal_level(tHalHandle hal, uint8_t level) +{ + struct scheduler_msg msg = {0}; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_THERMAL_LEVEL to WMA!", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAILURE; +} + +/* + * sme_txpower_limit() - + * SME API to set txpower limits + * + * hHal + * psmetx : power limits for 2g/5g + * Return QDF_STATUS + */ +QDF_STATUS sme_txpower_limit(tHalHandle hHal, tSirTxPowerLimit *psmetx) +{ + QDF_STATUS status; + struct scheduler_msg message = {0}; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirTxPowerLimit *tx_power_limit; + + tx_power_limit = qdf_mem_malloc(sizeof(*tx_power_limit)); + if (!tx_power_limit) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation for TxPowerLimit failed!", + __func__); + return QDF_STATUS_E_FAILURE; + } + + *tx_power_limit = *psmetx; + + status = sme_acquire_global_lock(&pMac->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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_TX_POWER_LIMIT", + __func__); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(tx_power_limit); + } + + sme_release_global_lock(&pMac->sme); + + return status; +} + +QDF_STATUS sme_update_connect_debug(tHalHandle hHal, uint32_t set_value) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->fEnableDebugLog = set_value; + return status; +} + +/* + * sme_ap_disable_intra_bss_fwd() - + * SME will send message to WMA to set Intra BSS in txrx + * + * hHal - 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(tHalHandle hHal, uint8_t sessionId, + bool disablefwd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + 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 (NULL == pSapDisableIntraFwd) { + sme_err("Memory Allocation Failure!!!"); + return QDF_STATUS_E_NOMEM; + } + + pSapDisableIntraFwd->sessionId = sessionId; + pSapDisableIntraFwd->disableintrabssfwd = disablefwd; + + status = sme_acquire_global_lock(&pMac->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(qdf_status)) { + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(pSapDisableIntraFwd); + } + sme_release_global_lock(&pMac->sme); + + return status; +} + +#ifdef WLAN_FEATURE_STATS_EXT + +/* + * sme_stats_ext_register_callback() - + * This function called to register the callback that send vendor event for + * stats ext + * + * callback - callback to be registered + */ +void sme_stats_ext_register_callback(tHalHandle hHal, StatsExtCallback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->sme.StatsExtCallback = callback; +} + +void sme_stats_ext2_register_callback(tHalHandle hal_handle, + void (*stats_ext2_cb)(void *, struct sir_sme_rx_aggr_hole_ind *)) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal_handle); + + pmac->sme.stats_ext2_cb = stats_ext2_cb; +} + +/** + * sme_stats_ext_deregister_callback() - De-register ext stats callback + * @h_hal: Hal Handle + * + * This function is called to de initialize the HDD NAN feature. Currently + * the only operation required is to de-register a callback with SME. + * + * Return: None + */ +void sme_stats_ext_deregister_callback(tHalHandle h_hal) +{ + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + + pmac = PMAC_STRUCT(h_hal); + pmac->sme.StatsExtCallback = NULL; +} + + +/* + * 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 == NULL) + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_STATS_EXT_REQUEST message to WMA", + __func__); + 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(tpAniSirGlobal mac, + tpStatsExtEvent msg) +{ + if (!msg) { + sme_err("Null msg"); + return QDF_STATUS_E_FAILURE; + } + + if (mac->sme.StatsExtCallback) + mac->sme.StatsExtCallback(mac->hdd_handle, msg); + + return QDF_STATUS_SUCCESS; +} + +#else + +static QDF_STATUS sme_stats_ext_event(tpAniSirGlobal mac, + tpStatsExtEvent msg) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + +/* + * sme_update_dfs_scan_mode() - + * Update DFS roam scan mode + * This function is called through dynamic setConfig callback function + * to configure allowDFSChannelRoam. + * hHal - HAL handle for device + * 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(tHalHandle hHal, uint8_t sessionId, + uint8_t allowDFSChannelRoam) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set AllowDFSChannelRoam Mode to %d - old value is %d - roam state is %s", + allowDFSChannelRoam, + pMac->roam.configParam.allowDFSChannelRoam, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.allowDFSChannelRoam = + allowDFSChannelRoam; + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_DFS_SCAN_MODE_CHANGED); + } + sme_release_global_lock(&pMac->sme); + } + + + return status; +} + +/* + * sme_get_dfs_scan_mode() - get DFS roam scan mode + * This is a synchronous call + * + * hHal - The handle returned by mac_open. + * Return DFS roaming scan mode 0 (disable), 1 (passive), 2 (active) + */ +uint8_t sme_get_dfs_scan_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.allowDFSChannelRoam; +} + +/* + * sme_modify_add_ie() - + * This function sends msg to updates the additional IE buffers in PE + * + * hHal - global structure + * pModifyIE - pointer to tModifyIE structure + * updateType - type of buffer + * Return Success or failure + */ +QDF_STATUS sme_modify_add_ie(tHalHandle hHal, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_modify_add_ies(pMac, pModifyIE, updateType); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_update_add_ie() - + * This function sends msg to updates the additional IE buffers in PE + * + * hHal - global structure + * pUpdateIE - pointer to structure tUpdateIE + * updateType - type of buffer + * Return Success or failure + */ +QDF_STATUS sme_update_add_ie(tHalHandle hHal, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_update_add_ies(pMac, pUpdateIE, updateType); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_update_dsc_pto_up_mapping() + * @hHal: HAL 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(tHalHandle hHal, + enum sme_qos_wmmuptype *dscpmapping, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i, j, peSessionId; + struct csr_roam_session *pCsrSession = NULL; + tpPESession pSession = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + pCsrSession = CSR_GET_SESSION(pMac, sessionId); + if (pCsrSession == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Session lookup fails for CSR session")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid session Id %u"), sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + pSession = pe_find_session_by_bssid(pMac, + pCsrSession->connectedProfile.bssid.bytes, + &peSessionId); + + if (pSession == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL(" Session lookup fails for BSSID")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!pSession->QosMapSet.present) { + sme_debug("QOS Mapping IE not present"); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + for (i = 0; i < SME_QOS_WMM_UP_MAX; i++) { + for (j = pSession->QosMapSet.dscp_range[i][0]; + j <= pSession->QosMapSet.dscp_range[i][1]; + j++) { + if ((pSession->QosMapSet.dscp_range[i][0] == 255) + && (pSession->QosMapSet.dscp_range[i][1] == + 255)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("User Priority %d isn't used"), i); + break; + } else { + dscpmapping[j] = i; + } + } + } + for (i = 0; i < pSession->QosMapSet.num_dscp_exceptions; i++) + if (pSession->QosMapSet.dscp_exceptions[i][0] != 255) + dscpmapping[pSession->QosMapSet.dscp_exceptions[i][0]] = + pSession->QosMapSet.dscp_exceptions[i][1]; + + sme_release_global_lock(&pMac->sme); + return status; +} + +/* + * sme_abort_roam_scan() - + * API to abort current roam scan cycle by roam scan offload module. + * + * hHal - The handle returned by mac_open. + * sessionId - Session Identifier + * Return QDF_STATUS + */ + +QDF_STATUS sme_abort_roam_scan(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_ABORT_SCAN, + REASON_ROAM_ABORT_ROAM_SCAN); + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + } + + return status; +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * sme_get_valid_channels_by_band() - to fetch valid channels filtered by band + * @hHal: HAL context + * @wifiBand: RF band information + * @aValidChannels: output array to store channel info + * @pNumChannels: 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(tHalHandle hHal, + uint8_t wifiBand, + uint32_t *aValidChannels, + uint8_t *pNumChannels) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t chanList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t numChannels = 0; + uint8_t i = 0; + uint32_t totValidChannels = WNI_CFG_VALID_CHANNEL_LIST_LEN; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + + if (!aValidChannels || !pNumChannels) { + sme_err("Output channel list/NumChannels is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (wifiBand >= WIFI_BAND_MAX) { + sme_err("Invalid wifiBand: %d", wifiBand); + return QDF_STATUS_E_INVAL; + } + + status = sme_get_cfg_valid_channels(&chanList[0], + &totValidChannels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Fail to get valid channel list (err=%d)", status); + return status; + } + + switch (wifiBand) { + case WIFI_BAND_UNSPECIFIED: + sme_debug("Unspec Band, return all %d valid channels", + totValidChannels); + numChannels = totValidChannels; + for (i = 0; i < totValidChannels; i++) + aValidChannels[i] = cds_chan_to_freq(chanList[i]); + break; + + case WIFI_BAND_BG: + sme_debug("WIFI_BAND_BG (2.4 GHz)"); + for (i = 0; i < totValidChannels; i++) { + if (WLAN_REG_IS_24GHZ_CH(chanList[i])) + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + break; + + case WIFI_BAND_A: + sme_debug("WIFI_BAND_A (5 GHz without DFS)"); + for (i = 0; i < totValidChannels; i++) { + if (WLAN_REG_IS_5GHZ_CH(chanList[i]) && + !wlan_reg_is_dfs_ch(mac_ctx->pdev, chanList[i])) + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + break; + + case WIFI_BAND_ABG: + sme_debug("WIFI_BAND_ABG (2.4 GHz + 5 GHz; no DFS)"); + for (i = 0; i < totValidChannels; i++) { + if ((WLAN_REG_IS_24GHZ_CH(chanList[i]) || + WLAN_REG_IS_5GHZ_CH(chanList[i])) && + !wlan_reg_is_dfs_ch(mac_ctx->pdev, chanList[i])) + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + break; + + case WIFI_BAND_A_DFS_ONLY: + sme_debug("WIFI_BAND_A_DFS (5 GHz DFS only)"); + for (i = 0; i < totValidChannels; i++) { + if (WLAN_REG_IS_5GHZ_CH(chanList[i]) && + wlan_reg_is_dfs_ch(mac_ctx->pdev, chanList[i])) + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + break; + + case WIFI_BAND_A_WITH_DFS: + sme_debug("WIFI_BAND_A_WITH_DFS (5 GHz with DFS)"); + for (i = 0; i < totValidChannels; i++) { + if (WLAN_REG_IS_5GHZ_CH(chanList[i])) + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[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 < totValidChannels; i++) { + if (WLAN_REG_IS_24GHZ_CH(chanList[i]) || + WLAN_REG_IS_5GHZ_CH(chanList[i])) + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + break; + + default: + sme_err("Unknown wifiBand: %d", wifiBand); + return QDF_STATUS_E_INVAL; + } + *pNumChannels = numChannels; + + return status; +} + +/* + * sme_ext_scan_get_capabilities() - + * SME API to fetch extscan capabilities + * + * hHal + * pReq: extscan capabilities structure + * Return QDF_STATUS + */ +QDF_STATUS sme_ext_scan_get_capabilities(tHalHandle hHal, + tSirGetExtScanCapabilitiesReqParams * + pReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = pReq; + message.type = WMA_EXTSCAN_GET_CAPABILITIES_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_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_ext_scan_start() - + * SME API to issue extscan start + * + * hHal + * pStartCmd: extscan start structure + * Return QDF_STATUS + */ +QDF_STATUS sme_ext_scan_start(tHalHandle hHal, + tSirWifiScanCmdReqParams *pStartCmd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = pStartCmd; + message.type = WMA_EXTSCAN_START_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_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_ext_scan_stop() - + * SME API to issue extscan stop + * + * hHal + * pStopReq: extscan stop structure + * Return QDF_STATUS + */ +QDF_STATUS sme_ext_scan_stop(tHalHandle hHal, tSirExtScanStopReqParams + *pStopReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = pStopReq; + message.type = WMA_EXTSCAN_STOP_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_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +QDF_STATUS +sme_set_bss_hotlist(mac_handle_t mac_handle, + struct extscan_bssid_hotlist_set_params *params) +{ + QDF_STATUS status; + tpAniSirGlobal 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) { + sme_err("buffer allocation failure"); + 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; + tpAniSirGlobal 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) { + sme_err("buffer allocation failure"); + 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; + tpAniSirGlobal 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) { + sme_err("buffer allocation failure"); + 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; + tpAniSirGlobal 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) { + sme_err("buffer allocation failure"); + 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; +} + +/* + * sme_get_cached_results() - + * SME API to get cached results + * + * hHal + * pCachedResultsReq: extscan get cached results structure + * Return QDF_STATUS + */ +QDF_STATUS sme_get_cached_results(tHalHandle hHal, + tSirExtScanGetCachedResultsReqParams * + pCachedResultsReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = pCachedResultsReq; + message.type = WMA_EXTSCAN_GET_CACHED_RESULTS_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_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_epno_list() - set epno network list + * @hal: global hal handle + * @input: request message + * + * This function constructs the cds message and fill in message type, + * bodyptr with %input and posts it to WDA queue. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_epno_list(tHalHandle hal, + struct wifi_epno_params *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct scheduler_msg message = {0}; + struct wifi_epno_params *req_msg; + int len, i; + + SME_ENTER(); + len = sizeof(*req_msg) + + (input->num_networks * sizeof(struct wifi_epno_network)); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + sme_err("qdf_mem_malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + req_msg->num_networks = input->num_networks; + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + + /* Fill only when num_networks are non zero */ + if (req_msg->num_networks) { + req_msg->min_5ghz_rssi = input->min_5ghz_rssi; + req_msg->min_24ghz_rssi = input->min_24ghz_rssi; + req_msg->initial_score_max = input->initial_score_max; + req_msg->same_network_bonus = input->same_network_bonus; + req_msg->secure_bonus = input->secure_bonus; + req_msg->band_5ghz_bonus = input->band_5ghz_bonus; + req_msg->current_connection_bonus = + input->current_connection_bonus; + + for (i = 0; i < req_msg->num_networks; i++) { + req_msg->networks[i].flags = input->networks[i].flags; + req_msg->networks[i].auth_bit_field = + input->networks[i].auth_bit_field; + req_msg->networks[i].ssid.length = + input->networks[i].ssid.length; + qdf_mem_copy(req_msg->networks[i].ssid.ssId, + input->networks[i].ssid.ssId, + req_msg->networks[i].ssid.length); + } + } + + 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); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_set_passpoint_list() - set passpoint network list + * @hal: global hal handle + * @input: request message + * + * This function constructs the cds message and fill in message type, + * bodyptr with @input and posts it to WDA queue. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct scheduler_msg message = {0}; + struct wifi_passpoint_req *req_msg; + int len, i; + + SME_ENTER(); + len = sizeof(*req_msg) + + (input->num_networks * sizeof(struct wifi_passpoint_network)); + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + sme_err("qdf_mem_malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + req_msg->num_networks = input->num_networks; + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + for (i = 0; i < req_msg->num_networks; i++) { + req_msg->networks[i].id = + input->networks[i].id; + qdf_mem_copy(req_msg->networks[i].realm, + input->networks[i].realm, + strlen(input->networks[i].realm) + 1); + qdf_mem_copy(req_msg->networks[i].plmn, + input->networks[i].plmn, + SIR_PASSPOINT_PLMN_LEN); + qdf_mem_copy(req_msg->networks[i].roaming_consortium_ids, + input->networks[i].roaming_consortium_ids, + sizeof(req_msg->networks[i].roaming_consortium_ids)); + } + + 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); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_reset_passpoint_list() - reset passpoint network list + * @hHal: global hal handle + * @input: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_reset_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct scheduler_msg message = {0}; + struct wifi_passpoint_req *req_msg; + + SME_ENTER(); + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sme_err("qdf_mem_malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + + 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); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +QDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, + const uint16_t, + void *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.pExtScanIndCb = pExtScanIndCb; + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif /* FEATURE_WLAN_EXTSCAN */ + +/** + * sme_send_wisa_params(): Pass WISA mode to WMA + * @hal: HAL 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(tHalHandle hal, + struct sir_wisa_params *wisa_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + 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); + sme_release_global_lock(&mac->sme); + + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(cds_msg_wisa_params); + + return status; +} + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/* + * sme_ll_stats_clear_req() - + * SME API to clear Link Layer Statistics + * + * hHal + * pclearStatsReq: Link Layer clear stats request params structure + * Return QDF_STATUS + */ +QDF_STATUS sme_ll_stats_clear_req(tHalHandle hHal, + tSirLLStatsClearReq *pclearStatsReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + tSirLLStatsClearReq *clear_stats_req; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "staId = %u", pclearStatsReq->staId); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "statsClearReqMask = 0x%X", + pclearStatsReq->statsClearReqMask); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "stopReq = %u", pclearStatsReq->stopReq); + if (!sme_is_session_id_valid(hHal, pclearStatsReq->staId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: invalid staId %d", + __func__, pclearStatsReq->staId); + return QDF_STATUS_E_INVAL; + } + + clear_stats_req = qdf_mem_malloc(sizeof(*clear_stats_req)); + + if (!clear_stats_req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_CLEAR_REQ", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *clear_stats_req = *pclearStatsReq; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* 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_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_CLEAR_REQ", + __func__); + qdf_mem_free(clear_stats_req); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error", __func__); + qdf_mem_free(clear_stats_req); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/* + * sme_ll_stats_set_req() - + * SME API to set the Link Layer Statistics + * + * hHal + * psetStatsReq: Link Layer set stats request params structure + * Return QDF_STATUS + */ +QDF_STATUS sme_ll_stats_set_req(tHalHandle hHal, tSirLLStatsSetReq + *psetStatsReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + tSirLLStatsSetReq *set_stats_req; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: MPDU Size = %u", __func__, + psetStatsReq->mpduSizeThreshold); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + " Aggressive Stats Collections = %u", + psetStatsReq->aggressiveStatisticsGathering); + + set_stats_req = qdf_mem_malloc(sizeof(*set_stats_req)); + + if (!set_stats_req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_SET_REQ", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *set_stats_req = *psetStatsReq; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* 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_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_SET_REQ", + __func__); + qdf_mem_free(set_stats_req); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error", __func__); + qdf_mem_free(set_stats_req); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * 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 for ll stats + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ll_stats_get_req(mac_handle_t mac_handle, + tSirLLStatsGetReq *get_stats_req, + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_GET_REQ", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *ll_stats_get_req = *get_stats_req; + + mac->sme.ll_stats_context = context; + if (sme_acquire_global_lock(&mac->sme) == QDF_STATUS_SUCCESS) { + /* Serialize the req through MC thread */ + message.bodyptr = ll_stats_get_req; + message.type = WMA_LINK_LAYER_STATS_GET_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_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_GET_REQ", + __func__); + + qdf_mem_free(ll_stats_get_req); + status = QDF_STATUS_E_FAILURE; + + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error", __func__); + qdf_mem_free(ll_stats_get_req); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * sme_set_link_layer_stats_ind_cb() - Link layer stats indication callback + * @hHal: handle in hdd context + * @callback_routine: HDD callback which needs to be invoked after + * getting status notification from FW + * + * SME API to trigger the stats are available after get request. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_link_layer_stats_ind_cb(tHalHandle hHal, + void (*callback_routine)( + void *callback_ctx, int ind_type, + void *rsp, void *cookie)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.pLinkLayerStatsIndCallback = callback_routine; + sme_release_global_lock(&pMac->sme); + } else + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error", __func__); + + return status; +} + +/** + * sme_set_link_layer_ext_cb() - Register callback for link layer statistics + * @hal: Mac global handle + * @ll_stats_ext_cb: HDD callback which needs to be invoked after getting + * status notification from FW + * + * Return: eHalStatus + */ +QDF_STATUS sme_set_link_layer_ext_cb(tHalHandle hal, void (*ll_stats_ext_cb) + (hdd_handle_t callback_ctx, tSirLLStatsResults + *rsp)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + 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 + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_qcquire_global_lock error", __func__); + return status; +} + +/** + * sme_reset_link_layer_stats_ind_cb() - SME API to reset link layer stats + * indication + * @h_hal: Hal Handle + * + * This function reset's the link layer stats indication + * + * Return: QDF_STATUS Enumeration + */ + +QDF_STATUS sme_reset_link_layer_stats_ind_cb(tHalHandle h_hal) +{ + QDF_STATUS status; + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + pmac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&pmac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pmac->sme.pLinkLayerStatsIndCallback = NULL; + sme_release_global_lock(&pmac->sme); + } else + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error", __func__); + + return status; +} + +/** + * sme_ll_stats_set_thresh - set threshold for mac counters + * @hal, hal layer handle + * @threshold, threshold for mac counters + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_ll_stats_set_thresh(tHalHandle hal, + struct sir_ll_ext_stats_threshold *threshold) +{ + QDF_STATUS status; + tpAniSirGlobal mac; + struct scheduler_msg message = {0}; + struct sir_ll_ext_stats_threshold *thresh; + + if (!threshold) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("threshold is not valid")); + return QDF_STATUS_E_INVAL; + } + + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(hal); + + thresh = qdf_mem_malloc(sizeof(*thresh)); + if (!thresh) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Fail to alloc mem", __func__); + return QDF_STATUS_E_NOMEM; + } + *thresh = *threshold; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* 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_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WDA_LL_STATS_GET_REQ", + __func__); + qdf_mem_free(thresh); + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + qdf_mem_free(thresh); + } + return status; +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_POWER_DEBUGFS +/** + * sme_power_debug_stats_req() - SME API to collect Power debug stats + * @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(tHalHandle hal, void (*callback_fn) + (struct power_stats_response *response, + void *context), void *power_stats_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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; + } + + 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 sAniSirGlobal *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->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 + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * sme_update_roam_offload_enabled() - enable/disable roam offload feaure + * It is used at in the REG_DYNAMIC_VARIABLE macro definition of + * + * hHal - The handle returned by mac_open. + * nRoamOffloadEnabled - The bool to update with + * Return QDF_STATUS_SUCCESS - SME update config successfully. + * Other status means SME is failed to update. + */ + +QDF_STATUS sme_update_roam_offload_enabled(tHalHandle hHal, + bool nRoamOffloadEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: LFR3:gRoamOffloadEnabled is changed from %d to %d", + __func__, pMac->roam.configParam.isRoamOffloadEnabled, + nRoamOffloadEnabled); + pMac->roam.configParam.isRoamOffloadEnabled = + nRoamOffloadEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_update_roam_key_mgmt_offload_enabled() - enable/disable key mgmt offload + * This is a synchronous call + * @hal_ctx: The handle returned by mac_open. + * @session_id: Session Identifier + * @key_mgmt_offload_enabled: key mgmt enable/disable flag + * @pmkid_modes: PMKID modes of PMKSA caching and OKC + * Return: QDF_STATUS_SUCCESS - SME updated config successfully. + * Other status means SME is failed to update. + */ + +QDF_STATUS sme_update_roam_key_mgmt_offload_enabled(tHalHandle hal_ctx, + uint8_t session_id, + bool key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: LFR3: key_mgmt_offload_enabled changed to %d", + __func__, key_mgmt_offload_enabled); + status = csr_roam_set_key_mgmt_offload(mac_ctx, + session_id, + key_mgmt_offload_enabled, + pmkid_modes); + } else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} +#endif + +/* + * sme_get_temperature() - + * SME API to get the pdev temperature + * + * hHal + * temperature context + * pCallbackfn: callback fn with response (temperature) + * Return QDF_STATUS + */ +QDF_STATUS sme_get_temperature(tHalHandle hHal, + void *tempContext, + void (*pCallbackfn)(int temperature, + void *pContext)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + if ((NULL == pCallbackfn) && + (NULL == pMac->sme.pGetTemperatureCb)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Indication Call back did not registered"); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } else if (NULL != pCallbackfn) { + pMac->sme.pTemperatureCbContext = tempContext; + pMac->sme.pGetTemperatureCb = pCallbackfn; + } + /* 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Post Get Temperature msg fail")); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* + * sme_set_scanning_mac_oui() - + * SME API to set scanning mac oui + * + * hHal + * pScanMacOui: Scanning Mac Oui (input 3 bytes) + * Return QDF_STATUS + */ +QDF_STATUS sme_set_scanning_mac_oui(tHalHandle hHal, tSirScanMacOui + *pScanMacOui) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + message.bodyptr = pScanMacOui; + message.type = WMA_SET_SCAN_MAC_OUI_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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Msg post Set Scan Mac OUI failed")); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef DHCP_SERVER_OFFLOAD +/* + * sme_set_dhcp_srv_offload() - + * SME API to set DHCP server offload info + * + * hHal + * pDhcpSrvInfo : DHCP server offload info struct + * Return QDF_STATUS + */ +QDF_STATUS sme_set_dhcp_srv_offload(tHalHandle hHal, + tSirDhcpSrvOffloadInfo *pDhcpSrvInfo) +{ + struct scheduler_msg message = {0}; + tSirDhcpSrvOffloadInfo *pSmeDhcpSrvInfo; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pSmeDhcpSrvInfo = qdf_mem_malloc(sizeof(*pSmeDhcpSrvInfo)); + + if (!pSmeDhcpSrvInfo) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_SET_DHCP_SERVER_OFFLOAD_CMD", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *pSmeDhcpSrvInfo = *pDhcpSrvInfo; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + /* serialize the req through MC thread */ + message.type = WMA_SET_DHCP_SERVER_OFFLOAD_CMD; + message.bodyptr = pSmeDhcpSrvInfo; + + if (!QDF_IS_STATUS_SUCCESS + (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:WMA_SET_DHCP_SERVER_OFFLOAD_CMD failed", + __func__); + qdf_mem_free(pSmeDhcpSrvInfo); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", __func__); + qdf_mem_free(pSmeDhcpSrvInfo); + } + + 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. + * + * hHal - The handle returned by mac_open. + * x0, x1 - led flashing parameters + * Return QDF_STATUS + */ +QDF_STATUS sme_set_led_flashing(tHalHandle hHal, uint8_t type, + uint32_t x0, uint32_t x1) +{ + QDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct scheduler_msg message = {0}; + struct flashing_req_params *ledflashing; + + ledflashing = qdf_mem_malloc(sizeof(*ledflashing)); + if (!ledflashing) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Not able to allocate memory for WMA_LED_TIMING_REQ"); + 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(&pMac->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(&pMac->sme); + } + if (!QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(ledflashing); + + return status; +} +#endif + +/** + * sme_handle_dfS_chan_scan() - handle DFS channel configuration + * @h_hal: corestack handler + * @dfs_flag: flag indicating dfs channel enable/disable + * Return: QDF_STATUS + */ +QDF_STATUS sme_handle_dfs_chan_scan(tHalHandle h_hal, uint8_t dfs_flag) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_STATUS_SUCCESS == status) { + + mac->scan.fEnableDFSChnlScan = dfs_flag; + + /* update the channel list to the firmware */ + status = csr_update_channel_list(mac); + + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/** + * sme_enable_dfS_chan_scan() - set DFS channel scan enable/disable + * @h_hal: corestack handler + * @dfs_flag: flag indicating dfs channel enable/disable + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_dfs_chan_scan(tHalHandle h_hal, uint8_t dfs_flag) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!h_hal) { + sme_err("hal is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac = PMAC_STRUCT(h_hal); + + 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. + * @hal - Hal context + * @sap_ch - channel to switch + * @sap_phy_mode - phy mode of SAP + * @cc_switch_mode - concurreny switch mode + * @session_id - sme session id. + * + * Return: true if there is no channel interference else return false + */ +bool sme_validate_sap_channel_switch(tHalHandle hal, + uint16_t sap_ch, eCsrPhyMode sap_phy_mode, uint8_t cc_switch_mode, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct csr_roam_session *session = CSR_GET_SESSION(mac, session_id); + uint16_t intf_channel = 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 = csr_check_concurrent_channel_overlap(mac, sap_ch, + sap_phy_mode, + cc_switch_mode); + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error!")); + session->ch_switch_in_progress = false; + return false; + } + + session->ch_switch_in_progress = false; + return (intf_channel == 0) ? true : false; +} +#endif + +/** + * sme_configure_stats_avg_factor() - function to config avg. stats factor + * @hal: hal + * @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(tHalHandle hal, uint8_t session_id, + uint16_t stats_avg_factor) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sir_stats_avg_factor *stats_factor; + + stats_factor = qdf_mem_malloc(sizeof(*stats_factor)); + + if (!stats_factor) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for SIR_HAL_CONFIG_STATS_FACTOR", + __func__); + 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post SIR_HAL_CONFIG_STATS_FACTOR to WMA!", + __func__); + qdf_mem_free(stats_factor); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + qdf_mem_free(stats_factor); + } + + return status; +} + +/** + * sme_configure_guard_time() - function to configure guard time + * @hal: hal + * @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(tHalHandle hal, uint8_t session_id, + uint32_t guard_time) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sir_guard_time_request *g_time; + + g_time = qdf_mem_malloc(sizeof(*g_time)); + + if (!g_time) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for SIR_HAL_CONFIG_GUARD_TIME", + __func__); + 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post SIR_HAL_CONFIG_GUARD_TIME to WMA!", + __func__); + qdf_mem_free(g_time); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + qdf_mem_free(g_time); + } + + return status; +} + +/* + * sme_wifi_start_logger() - Send the start/stop logging command to WMA + * to either start/stop logging + * @hal: HAL 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(tHalHandle hal, + struct sir_wifi_start_log start_log) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + 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) { + sme_err("qdf_mem_malloc failed"); + 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; + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + 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 = 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; + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_neighbor_middle_of_roaming() - Function to know if + * STA is in the middle of roaming states + * @hal: Handle returned by macOpen + * @sessionId: sessionId of the STA session + * + * This function is a wrapper to call + * csr_neighbor_middle_of_roaming to know STA is in the + * middle of roaming states + * + * Return: True or False + * + */ +bool sme_neighbor_middle_of_roaming(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + bool val = false; + + if (CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + val = csr_neighbor_middle_of_roaming(mac_ctx, sessionId); + else + sme_debug("Invalid Session: %d", sessionId); + + return val; +} + +bool sme_is_any_session_in_middle_of_roaming(mac_handle_t hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint8_t session_id; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id) && + csr_neighbor_middle_of_roaming(mac_ctx, session_id)) + return true; + } + + return false; +} + +/* + * sme_send_flush_logs_cmd_to_fw() - Flush FW logs + * @mac: MAC handle + * + * 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(tpAniSirGlobal mac) +{ + 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(uint8_t sta_id, + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to Trigger Uapsd params for sessionId %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_disable_uapsd_for_ac(uint8_t sta_id, + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_STATUS_SUCCESS != + wma_disable_uapsd_per_ac(wma_handle, sessionId, access_category)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to disable uapsd for ac %d for sessionId %d", + ac, sessionId); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_update_nss() - SME API to change the number for spatial streams + * (1 or 2) + * @hal: 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(tHalHandle h_hal, uint8_t nss) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + uint32_t i, value = 0; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } uHTCapabilityInfo; + struct csr_roam_session *csr_session; + + status = sme_acquire_global_lock(&mac_ctx->sme); + + if (QDF_STATUS_SUCCESS == status) { + mac_ctx->roam.configParam.enable2x2 = (nss == 1) ? 0 : 1; + + /* get the HT capability info*/ + sme_cfg_get_int(h_hal, WNI_CFG_HT_CAP_INFO, &value); + uHTCapabilityInfo.cfg_value16 = (0xFFFF & value); + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i)) { + csr_session = &mac_ctx->roam.roamSession[i]; + csr_session->htConfig.ht_tx_stbc = + uHTCapabilityInfo.ht_cap_info.txSTBC; + } + } + + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +/** + * sme_update_user_configured_nss() - sets the nss based on user request + * @hal: Pointer to HAL + * @nss: number of streams + * + * Return: None + */ +void sme_update_user_configured_nss(tHalHandle hal, uint8_t nss) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + mac_ctx->user_configured_nss = nss; +} + +int sme_update_tx_bfee_supp(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val) +{ + QDF_STATUS status; + + status = sme_cfg_set_int(hal, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + cfg_val); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Failed to set SU BFEE CFG"); + return -EFAULT; + } + + return sme_update_he_tx_bfee_supp(hal, session_id, cfg_val); +} +#ifdef WLAN_FEATURE_11AX +void sme_update_he_cap_nss(tHalHandle hal, uint8_t session_id, + uint8_t nss) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct csr_roam_session *csr_session; + uint32_t tx_mcs_map = 0; + uint32_t rx_mcs_map = 0; + + if (!nss || (nss > 2)) { + sme_err("invalid Nss value %d", nss); + } + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + sme_cfg_get_int(hal, WNI_CFG_HE_RX_MCS_MAP_LT_80, &rx_mcs_map); + sme_cfg_get_int(hal, WNI_CFG_HE_TX_MCS_MAP_LT_80, &tx_mcs_map); + 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, HE_MCS_0_11, 2); + rx_mcs_map = HE_SET_MCS_4_NSS(rx_mcs_map, HE_MCS_0_11, 2); + } + sme_info("new HE Nss MCS MAP: Rx 0x%0X, Tx: 0x%0X", + rx_mcs_map, tx_mcs_map); + sme_cfg_set_int(hal, WNI_CFG_HE_RX_MCS_MAP_LT_80, rx_mcs_map); + sme_cfg_set_int(hal, WNI_CFG_HE_TX_MCS_MAP_LT_80, tx_mcs_map); + csr_update_session_he_cap(mac_ctx, csr_session); + +} + +int sme_update_he_mcs(tHalHandle hal, uint8_t session_id, uint16_t he_mcs) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct csr_roam_session *csr_session; + uint16_t mcs_val = 0; + uint16_t mcs_map = HE_MCS_ALL_DISABLED; + uint32_t wni_cfg_tx_param = 0; + uint32_t wni_cfg_rx_param = 0; + + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + if (!csr_session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + 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: + if (mac_ctx->roam.configParam.enable2x2) { + mcs_map = HE_SET_MCS_4_NSS(mcs_map, mcs_val, 1); + mcs_map = HE_SET_MCS_4_NSS(mcs_map, mcs_val, 2); + } else { + mcs_map = HE_SET_MCS_4_NSS(mcs_map, mcs_val, 1); + } + wni_cfg_tx_param = WNI_CFG_HE_TX_MCS_MAP_LT_80; + wni_cfg_rx_param = WNI_CFG_HE_RX_MCS_MAP_LT_80; + break; + + case HE_160_MCS0_7: + case HE_160_MCS0_9: + case HE_160_MCS0_11: + mcs_map = HE_SET_MCS_4_NSS(mcs_map, mcs_val, 1); + wni_cfg_tx_param = WNI_CFG_HE_TX_MCS_MAP_160; + wni_cfg_rx_param = WNI_CFG_HE_RX_MCS_MAP_160; + 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); + wni_cfg_tx_param = WNI_CFG_HE_TX_MCS_MAP_80_80; + wni_cfg_rx_param = WNI_CFG_HE_RX_MCS_MAP_80_80; + break; + + default: + sme_err("Invalid HE MCS 0x%0x", he_mcs); + return -EINVAL; + } + sme_info("new HE MCS 0x%0x", mcs_map); + sme_cfg_set_int(hal, wni_cfg_tx_param, mcs_map); + sme_cfg_set_int(hal, wni_cfg_rx_param, mcs_map); + csr_update_session_he_cap(mac_ctx, csr_session); + + return 0; +} + +static int sme_update_he_cap(tHalHandle hal, uint8_t session_id, + uint16_t he_cap, int value) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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; + } + sme_cfg_set_int(hal, he_cap, value); + csr_update_session_he_cap(mac_ctx, session); + + return 0; +} + +int sme_update_he_tx_bfee_supp(tHalHandle hal, uint8_t session_id, + uint8_t cfg_val) +{ + return sme_update_he_cap(hal, session_id, WNI_CFG_HE_SU_BEAMFORMEE, + cfg_val); +} + +int sme_update_he_tx_stbc_cap(tHalHandle hal, uint8_t session_id, int value) +{ + int ret; + uint32_t he_cap_val = 0; + + he_cap_val = value ? 1 : 0; + + ret = sme_update_he_cap(hal, session_id, + WNI_CFG_HE_TX_STBC_LT80, he_cap_val); + if (ret) + return ret; + + return sme_update_he_cap(hal, session_id, + WNI_CFG_HE_TX_STBC_GT80, he_cap_val); +} + +int sme_update_he_rx_stbc_cap(tHalHandle hal, uint8_t session_id, int value) +{ + int ret; + uint32_t he_cap_val = 0; + + he_cap_val = value ? 1 : 0; + + ret = sme_update_he_cap(hal, session_id, + WNI_CFG_HE_RX_STBC_LT80, he_cap_val); + if (ret) + return ret; + + return sme_update_he_cap(hal, session_id, + WNI_CFG_HE_RX_STBC_GT80, he_cap_val); +} + +int sme_update_he_frag_supp(tHalHandle hal, uint8_t session_id, + uint16_t he_frag) +{ + return sme_update_he_cap(hal, session_id, + WNI_CFG_HE_FRAGMENTATION, he_frag); +} + +int sme_update_he_ldpc_supp(tHalHandle hal, uint8_t session_id, + uint16_t he_ldpc) +{ + return sme_update_he_cap(hal, session_id, WNI_CFG_HE_LDPC, he_ldpc); +} +#endif + +/** + * sme_set_nud_debug_stats_cb() - set nud debug stats callback + * @hal: global hal handle + * @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(tHalHandle hal, + void (*cb)(void *, struct rsp_stats *, void *), + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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_set_rssi_threshold_breached_cb() - set rssi threshold breached callback + * @h_hal: global hal handle + * @cb: callback function pointer + * @context: callback context + * + * This function stores the rssi threshold breached callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_rssi_threshold_breached_cb(tHalHandle h_hal, + void (*cb)(void *, struct rssi_breach_event *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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; +} + +/** + * sme_set_rssi_threshold_breached_cb() - Reset rssi threshold breached callback + * @hal: global hal handle + * + * This function de-registers the rssi threshold breached callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_reset_rssi_threshold_breached_cb(tHalHandle hal) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + 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 = NULL; + 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. + * + * @hal: 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(tHalHandle h_hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + 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; + tpAniSirGlobal 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; +} + +/** + * sme_set_rssi_monitoring() - set rssi monitoring + * @hal: global hal handle + * @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(tHalHandle hal, + struct rssi_monitor_req *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct scheduler_msg message = {0}; + struct rssi_monitor_req *req_msg; + + SME_ENTER(); + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sme_err("memory allocation failed"); + 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; +} + +static enum band_info sme_get_connected_roaming_vdev_band(void) +{ + enum band_info band = BAND_ALL; + tpAniSirGlobal mac = sme_get_mac_context(); + struct csr_roam_session *session; + uint8_t session_id, channel; + + if (!mac) { + sme_debug("MAC Context is NULL"); + return band; + } + session_id = csr_get_roam_enabled_sta_sessionid(mac); + if (session_id != CSR_SESSION_ID_INVALID) { + session = CSR_GET_SESSION(mac, session_id); + channel = session->connectedProfile.operationChannel; + band = csr_get_rf_band(channel); + return band; + } + + return band; +} + +/* + * sme_pdev_set_pcl() - Send WMI_PDEV_SET_PCL_CMDID to the WMA + * @hal: Handle returned by macOpen + * @msg: PCL channel list and length structure + * + * Sends the command to WMA to send WMI_PDEV_SET_PCL_CMDID to FW + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_pdev_set_pcl(struct policy_mgr_pcl_list *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = sme_get_mac_context(); + struct scheduler_msg message = {0}; + struct set_pcl_req *req_msg; + uint32_t i; + + if (!mac) { + sme_err("mac is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!msg) { + sme_err("msg is NULL"); + return QDF_STATUS_E_FAILURE; + } + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sme_err("qdf_mem_malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + req_msg->band = BAND_ALL; + if (CSR_IS_ROAM_INTRA_BAND_ENABLED(mac)) { + req_msg->band = sme_get_connected_roaming_vdev_band(); + sme_debug("Connected STA band %d", req_msg->band); + } + 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; + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + 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 = SIR_HAL_PDEV_SET_PCL_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); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/* + * sme_pdev_set_hw_mode() - Send WMI_PDEV_SET_HW_MODE_CMDID to the WMA + * @hal: 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; + tpAniSirGlobal 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->sessionId = 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.context = msg.context; + + sme_debug("Queuing set hw mode to CSR, session: %d reason: %d", + cmd->u.set_hw_mode_cmd.session_id, + cmd->u.set_hw_mode_cmd.reason); + csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_register_hw_mode_trans_cb() - HW mode transition callback registration + * @hal: Handle returned by macOpen + * @callback: HDD callback to be registered + * + * Registers the HDD callback with SME. This callback will be invoked when + * HW mode transition event is received from the FW + * + * Return: None + */ +void sme_register_hw_mode_trans_cb(tHalHandle hal, + hw_mode_transition_cb callback) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + mac->sme.sme_hw_mode_trans_cb = callback; +} + +/** + * sme_nss_update_request() - Send beacon templete update to FW with new + * nss value + * @hal: Handle returned by macOpen + * @vdev_id: the session id + * @new_nss: the new nss 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 + * + * 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, 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) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal 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->sessionId = vdev_id; + cmd->u.nss_update_cmd.new_nss = new_nss; + 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; + + sme_debug("Queuing e_sme_command_nss_update to CSR:vdev (%d %d) ss %d r %d", + vdev_id, original_vdev_id, new_nss, 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 + * @hal: 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; + tpAniSirGlobal 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); + csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * sme_gateway_param_update() - to update gateway parameters with WMA + * @Hal: hal handle + * @gw_params: request parameters from HDD + * + * Return: QDF_STATUS + * + * This routine will update gateway parameters to WMA + */ +QDF_STATUS sme_gateway_param_update(tHalHandle Hal, + struct gateway_param_update_req *gw_params) +{ + QDF_STATUS qdf_status; + struct scheduler_msg message = {0}; + struct gateway_param_update_req *request_buf; + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Not able to allocate memory for gw param update request"); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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 + * @hal: 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(tHalHandle hal, + struct sir_antenna_mode_param *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tSmeCmd *cmd; + + if (NULL == 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 + * @auth_cb: auth callback + * @vdev_id: vdev id + * + * Return: QDF Status + */ +QDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + sme_peer_authorized_fp auth_cb, + uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wma_set_peer_authorized_cb(wma_handle, auth_cb); + return wma_set_peer_param(wma_handle, peer_addr, WMI_PEER_AUTHORIZE, + 1, vdev_id); +} + +/* + * sme_handle_set_fcc_channel() - set spec. tx power for non-fcc channel + * @hal: HAL pointer + * @fcc_constraint: flag to enable/disable the constraint + * @scan_pending: whether there is pending scan + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_handle_set_fcc_channel(tHalHandle hal, bool fcc_constraint, + bool scan_pending) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ptr = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac_ptr->sme); + + if (QDF_STATUS_SUCCESS == status) { + + if (fcc_constraint != mac_ptr->scan.fcc_constraint) { + mac_ptr->scan.fcc_constraint = fcc_constraint; + if (scan_pending) + mac_ptr->scan.defer_update_channel_list = true; + else + status = csr_update_channel_list(mac_ptr); + } + + sme_release_global_lock(&mac_ptr->sme); + } + + return status; +} +/** + * sme_setdef_dot11mode() - Updates pMac with default dot11mode + * @hal: Global MAC pointer + * + * Return: NULL. + */ +void sme_setdef_dot11mode(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + csr_set_default_dot11_mode(mac_ctx); +} + +/** + * sme_update_roam_scan_hi_rssi_scan_params() - update high rssi scan + * params + * @hal_handle - The handle returned by macOpen. + * @session_id - Session Identifier + * @notify_id - Identifies 1 of the 4 parameters to be modified + * @val New value of the parameter + * + * Return: QDF_STATUS - SME update config successful. + * Other status means SME failed to update + */ + +QDF_STATUS sme_update_roam_scan_hi_rssi_scan_params(tHalHandle hal_handle, + uint8_t session_id, + uint32_t notify_id, + int32_t val) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_neighbor_roamconfig *nr_config = NULL; + tpCsrNeighborRoamControlInfo nr_info = NULL; + uint32_t reason = 0; + + if (session_id >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), session_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + nr_config = &mac_ctx->roam.configParam.neighborRoamConfig; + nr_info = &mac_ctx->roam.neighborRoamInfo[session_id]; + switch (notify_id) { + case eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: gRoamScanHirssiMaxCount %d => %d", + __func__, nr_config->nhi_rssi_scan_max_count, + val); + nr_config->nhi_rssi_scan_max_count = val; + nr_info->cfgParams.hi_rssi_scan_max_count = val; + reason = REASON_ROAM_SCAN_HI_RSSI_MAXCOUNT_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("gRoamScanHiRssiDelta %d => %d"), + nr_config->nhi_rssi_scan_rssi_delta, + val); + nr_config->nhi_rssi_scan_rssi_delta = val; + nr_info->cfgParams.hi_rssi_scan_rssi_delta = val; + reason = REASON_ROAM_SCAN_HI_RSSI_DELTA_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_DELAY_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("gRoamScanHiRssiDelay %d => %d"), + nr_config->nhi_rssi_scan_delay, + val); + nr_config->nhi_rssi_scan_delay = val; + nr_info->cfgParams.hi_rssi_scan_delay = val; + reason = REASON_ROAM_SCAN_HI_RSSI_DELAY_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_UB_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("gRoamScanHiRssiUpperBound %d => %d"), + nr_config->nhi_rssi_scan_rssi_ub, + val); + nr_config->nhi_rssi_scan_rssi_ub = val; + nr_info->cfgParams.hi_rssi_scan_rssi_ub = val; + reason = REASON_ROAM_SCAN_HI_RSSI_UB_CHANGED; + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("invalid parameter notify_id %d"), + notify_id); + status = QDF_STATUS_E_INVAL; + break; + } + + if (mac_ctx->roam.configParam.isRoamOffloadScanEnabled && + status == QDF_STATUS_SUCCESS) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, reason); + } + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +/** + * sme_update_tgt_services() - update the target services config. + * @hal: HAL pointer. + * @cfg: wma_tgt_services parameters. + * + * update the target services config. + * + * Return: None. + */ +void sme_update_tgt_services(tHalHandle hal, struct wma_tgt_services *cfg) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + mac_ctx->lteCoexAntShare = cfg->lte_coex_ant_share; + mac_ctx->beacon_offload = cfg->beacon_offload; + mac_ctx->pmf_offload = cfg->pmf_offload; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("mac_ctx->pmf_offload: %d"), mac_ctx->pmf_offload); + mac_ctx->is_fils_roaming_supported = + cfg->is_fils_roaming_supported; + mac_ctx->is_11k_offload_supported = + cfg->is_11k_offload_supported; + sme_debug("pmf_offload: %d fils_roam support %d 11k_offload %d", + mac_ctx->pmf_offload, mac_ctx->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 + * @hal: Pointer to HAL + * @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(tHalHandle hal, uint32_t session_id) +{ + tpAniSirGlobal mac; + + if (NULL != hal) { + mac = PMAC_STRUCT(hal); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: null mac pointer", __func__); + return false; + } + + if (CSR_IS_SESSION_VALID(mac, session_id)) + return true; + + return false; +} + +#ifdef FEATURE_WLAN_TDLS + +/** + * sme_get_opclass() - determine operating class + * @hal: Pointer to HAL + * @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(tHalHandle hal, uint8_t channel, uint8_t bw_offset, + uint8_t *opclass) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + /* 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( + mac_ctx->scan.countryCodeCurrent, + channel, BW40_LOW_PRIMARY); + if (!(*opclass)) { + *opclass = wlan_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, BW40_HIGH_PRIMARY); + } + } else if (bw_offset & (1 << BW_20_OFFSET_BIT)) { + *opclass = wlan_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, BW20); + } else { + *opclass = wlan_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + wma_process_fw_test_cmd(wma_handle, fw_test); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ht40_stop_obss_scan() - ht40 obss stop scan + * @hal: mac handel + * @vdev_id: vdev identifier + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_ht40_stop_obss_scan(tHalHandle hal, uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + wma_ht40_stop_obss_scan(wma_handle, vdev_id); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_update_mimo_power_save() - Update MIMO power save + * configuration + * @hal: The handle returned by macOpen + * @is_ht_smps_enabled: enable/disable ht smps + * @ht_smps_mode: smps mode disabled/static/dynamic + * @send_smps_action: flag to send smps force mode command + * to FW + * + * Return: QDF_STATUS if SME update mimo power save + * configuration success else failure status + */ +QDF_STATUS sme_update_mimo_power_save(tHalHandle hal, + uint8_t is_ht_smps_enabled, + uint8_t ht_smps_mode, + bool send_smps_action) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + sme_debug("SMPS enable: %d mode: %d send action: %d", + is_ht_smps_enabled, ht_smps_mode, + send_smps_action); + mac_ctx->roam.configParam.enableHtSmps = + is_ht_smps_enabled; + mac_ctx->roam.configParam.htSmps = ht_smps_mode; + mac_ctx->roam.configParam.send_smps_action = + send_smps_action; + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_is_sta_smps_allowed() - check if the supported nss for + * the session is greater than 1x1 to enable sta SMPS + * @hal: The handle returned by macOpen + * @session_id: session id + * + * Return: bool returns true if supported nss is greater than + * 1x1 else false + */ +bool sme_is_sta_smps_allowed(tHalHandle hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct csr_roam_session *csr_session; + + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == csr_session) { + sme_err("SME session not valid: %d", 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 (csr_session->supported_nss_1x1 == true) ? false : true; +} + +/** + * sme_add_beacon_filter() - set the beacon filter configuration + * @hal: 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(tHalHandle hal, + uint32_t session_id, + uint32_t *ie_map) +{ + struct scheduler_msg message = {0}; + QDF_STATUS qdf_status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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 (NULL == filter_param) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc filter_param", __func__); + return QDF_STATUS_E_FAILURE; + } + + filter_param->vdev_id = session_id; + + qdf_mem_copy(filter_param->ie_map, ie_map, + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + + qdf_mem_free(filter_param); + } + return qdf_status; +} + +/** + * sme_remove_beacon_filter() - set the beacon filter configuration + * @hal: The handle returned by macOpen + * @session_id: session id + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id) +{ + struct scheduler_msg message = {0}; + QDF_STATUS qdf_status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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 (NULL == filter_param) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc filter_param", __func__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + + qdf_mem_free(filter_param); + } + return qdf_status; +} + +/** + * sme_send_disassoc_req_frame - send disassoc req + * @hal: handler to hal + * @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(tHalHandle hal, 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; + A_UINT8 *buf; + A_UINT16 tmp; + + msg = qdf_mem_malloc(sizeof(struct sme_send_disassoc_frm_req)); + + if (NULL == msg) + qdf_status = QDF_STATUS_E_FAILURE; + else + qdf_status = QDF_STATUS_SUCCESS; + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + return; + + msg->msg_type = (uint16_t) eWNI_SME_SEND_DISASSOC_FRAME; + + msg->length = (uint16_t) sizeof(struct sme_send_disassoc_frm_req); + + buf = &msg->session_id; + + /* session id */ + *buf = (A_UINT8) session_id; + buf += sizeof(A_UINT8); + + /* transaction id */ + *buf = 0; + *(buf + 1) = 0; + buf += sizeof(A_UINT16); + + /* Set the peer MAC address before sending the message to LIM */ + qdf_mem_copy(buf, peer_mac, QDF_MAC_ADDR_SIZE); + + buf += QDF_MAC_ADDR_SIZE; + + /* reasoncode */ + tmp = (uint16_t) reason; + qdf_mem_copy(buf, &tmp, sizeof(uint16_t)); + buf += sizeof(uint16_t); + + *buf = wait_for_ack; + buf += sizeof(uint8_t); + + qdf_status = umac_send_mb_message_to_mac(msg); + + if (qdf_status != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("cds_send_mb_message Failed")); +} + +#ifdef FEATURE_WLAN_APF +QDF_STATUS sme_get_apf_capabilities(tHalHandle hal, + apf_get_offload_cb callback, + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Post apf get offload msg fail")); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + } + SME_EXIT(); + return status; +} + +QDF_STATUS sme_set_apf_instructions(tHalHandle hal, + struct sir_apf_set_offload *req) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_set_apf_instructions(wma_handle, req); +} + +QDF_STATUS sme_set_apf_enable_disable(tHalHandle hal, uint8_t vdev_id, + bool apf_enable) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_send_apf_enable_cmd(wma_handle, vdev_id, apf_enable); +} + +QDF_STATUS +sme_apf_write_work_memory(tHalHandle hal, + struct wmi_apf_write_memory_params *write_params) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_send_apf_write_work_memory_cmd(wma_handle, write_params); +} + +QDF_STATUS +sme_apf_read_work_memory(tHalHandle hal, + struct wmi_apf_read_memory_params *read_params, + apf_read_mem_cb callback) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + 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 { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + 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 + * @hal: hal pointer + * + * Return: wni dot11 mode. + */ +uint32_t sme_get_wni_dot11_mode(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + 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 + * @hal_handle: Handle to the HAL + * @bssid: pointer to bssid + * + * Return: QDF_STATUS_SUCCESS on success, non-zero error code on failure. + */ +QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, tSirMacAddr bss_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_create_session *msg; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL != msg) { + msg->type = eWNI_SME_MON_INIT_SESSION; + 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; +} + +void sme_set_chan_info_callback(tHalHandle hal_handle, + void (*callback)(struct scan_chan_info *chan_info)) +{ + tpAniSirGlobal mac; + + if (hal_handle == NULL) { + QDF_ASSERT(0); + return; + } + mac = PMAC_STRUCT(hal_handle); + mac->chan_info_cb = callback; +} + +/** + * sme_set_adaptive_dwelltime_config() - Update Adaptive dwelltime configuration + * @hal: The handle returned by macOpen + * @params: adaptive_dwelltime_params config + * + * Return: QDF_STATUS if adaptive dwell time update + * configuration success else failure status + */ +QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, + struct adaptive_dwelltime_params *params) +{ + struct scheduler_msg message = {0}; + QDF_STATUS status; + struct adaptive_dwelltime_params *dwelltime_params; + + dwelltime_params = qdf_mem_malloc(sizeof(*dwelltime_params)); + if (NULL == dwelltime_params) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc dwelltime_params", __func__); + return QDF_STATUS_E_NOMEM; + } + + dwelltime_params->is_enabled = params->is_enabled; + dwelltime_params->dwelltime_mode = params->dwelltime_mode; + dwelltime_params->lpf_weight = params->lpf_weight; + dwelltime_params->passive_mon_intval = params->passive_mon_intval; + dwelltime_params->wifi_act_threshold = params->wifi_act_threshold; + + message.type = WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS; + message.bodyptr = dwelltime_params; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WMA!", __func__); + + qdf_mem_free(dwelltime_params); + } + return status; +} + +/** + * sme_set_vdev_ies_per_band() - sends the per band IEs to vdev + * @hal: Pointer to HAL + * @vdev_id: vdev_id for which IE is targeted + * + * Return: None + */ +void sme_set_vdev_ies_per_band(tHalHandle hal, uint8_t vdev_id) +{ + struct sir_set_vdev_ies_per_band *p_msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p_msg = qdf_mem_malloc(sizeof(*p_msg)); + if (NULL == p_msg) { + sme_err("mem alloc failed for sme msg"); + return; + } + + p_msg->vdev_id = vdev_id; + p_msg->msg_type = eWNI_SME_SET_VDEV_IES_PER_BAND; + p_msg->len = sizeof(*p_msg); + sme_debug("sending eWNI_SME_SET_VDEV_IES_PER_BAND: vdev_id: %d", + vdev_id); + 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"); +} + +/** + * sme_set_pdev_ht_vht_ies() - sends the set pdev IE req + * @hal: Pointer to HAL + * @enable2x2: 1x1 or 2x2 mode. + * + * Sends the set pdev IE req with Nss value. + * + * Return: None + */ +void sme_set_pdev_ht_vht_ies(tHalHandle hal, bool enable2x2) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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 (NULL == ht_vht_cfg) { + sme_err("mem alloc failed for 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); + } +} + +/** + * sme_update_vdev_type_nss() - sets the nss per vdev type + * @hal: Pointer to HAL + * @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(tHalHandle hal, uint8_t max_supp_nss, + uint32_t vdev_type_nss, enum band_info band) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct vdev_type_nss *vdev_nss; + + if (BAND_5G == band) + 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(vdev_type_nss, + STA_NSS_CHAINS_SHIFT)); + vdev_nss->sap = QDF_MIN(max_supp_nss, + GET_VDEV_NSS_CHAIN(vdev_type_nss, + SAP_NSS_CHAINS_SHIFT)); + vdev_nss->p2p_go = QDF_MIN(max_supp_nss, + GET_VDEV_NSS_CHAIN(vdev_type_nss, + P2P_GO_NSS_CHAINS_SHIFT)); + + vdev_nss->p2p_cli = QDF_MIN(max_supp_nss, + GET_VDEV_NSS_CHAIN(vdev_type_nss, + P2P_CLI_CHAINS_SHIFT)); + + vdev_nss->p2p_dev = + QDF_MIN(max_supp_nss, + GET_VDEV_NSS_CHAIN(vdev_type_nss, + P2P_DEV_NSS_CHAINS_SHIFT)); + + vdev_nss->ibss = QDF_MIN(max_supp_nss, + GET_VDEV_NSS_CHAIN(vdev_type_nss, + IBSS_NSS_CHAINS_SHIFT)); + vdev_nss->tdls = QDF_MIN(max_supp_nss, + GET_VDEV_NSS_CHAIN(vdev_type_nss, + TDLS_NSS_CHAINS_SHIFT)); + vdev_nss->ocb = QDF_MIN(max_supp_nss, + GET_VDEV_NSS_CHAIN(vdev_type_nss, + OCB_NSS_CHAINS_SHIFT)); + + sme_debug("band %d NSS:sta %d sap %d cli %d go %d dev %d ibss %d tdls %d ocb %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); +} + +#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(tHalHandle hal, uint8_t session_id, + uint8_t bss_color) + +{ + struct sir_set_he_bss_color *bss_color_msg; + uint8_t len; + + if (!hal) { + sme_err("Invalid hal 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) { + sme_err("mem alloc failed"); + return QDF_STATUS_E_NOMEM; + } + bss_color_msg->message_type = eWNI_SME_SET_HE_BSS_COLOR; + bss_color_msg->length = len; + bss_color_msg->session_id = session_id; + bss_color_msg->bss_color = bss_color; + return umac_send_mb_message_to_mac(bss_color_msg); +} +#endif + +/** + * sme_update_hw_dbs_capable() - sets the HW DBS capability + * @hal: Pointer to HAL + * @hw_dbs_capable: HW DBS capability + * + * Sets HW DBS capability based on INI and fw capability. + * + * Return: None + */ +void sme_update_hw_dbs_capable(tHalHandle hal, uint8_t hw_dbs_capable) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + mac_ctx->hw_dbs_capable = hw_dbs_capable; +} + +/** + * sme_register_p2p_lo_event() - Register for the p2p lo event + * @hHal: reference to the HAL + * @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(tHalHandle hHal, void *context, + p2p_lo_callback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&pMac->sme); + pMac->sme.p2p_lo_event_callback = callback; + pMac->sme.p2p_lo_event_context = context; + sme_release_global_lock(&pMac->sme); +} + +/** + * sme_process_mac_pwr_dbg_cmd() - enable mac pwr debugging + * @hal: 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(tHalHandle hal, uint32_t session_id, + struct sir_mac_pwr_dbg_cmd* + dbg_args) +{ + struct scheduler_msg message = {0}; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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 (NULL == req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc mac_pwr_dbg_args", __func__); + 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + 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) +{ + tpAniSirGlobal mac_ctx = sme_get_mac_context(); + + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return; + } + csr_get_vdev_type_nss(mac_ctx, dev_mode, nss_2g, nss_5g); +} + +/** + * sme_update_sta_roam_policy() - update sta roam policy for + * unsafe and DFS channels. + * @hal_handle: hal handle for getting global mac struct + * @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. + * @param session_id: sme_session_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(tHalHandle hal_handle, + enum sta_roam_policy_dfs_mode dfs_mode, + bool skip_unsafe_channels, + uint8_t session_id, uint8_t sap_operating_band) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeConfigParams *sme_config; + + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: mac_ctx is null", __func__); + return QDF_STATUS_E_FAILURE; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("failed to allocate memory for sme_config")); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(sme_config, sizeof(*sme_config)); + sme_get_config_param(hal_handle, sme_config); + + sme_config->csrConfig.sta_roam_policy_params.dfs_mode = + dfs_mode; + sme_config->csrConfig.sta_roam_policy_params.skip_unsafe_channels = + skip_unsafe_channels; + sme_config->csrConfig.sta_roam_policy_params.sap_operating_band = + sap_operating_band; + + sme_update_config(hal_handle, sme_config); + + status = csr_update_channel_list(mac_ctx); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("failed to update the supported channel list")); + } + + if (mac_ctx->roam.configParam.isRoamOffloadScanEnabled) { + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_SCAN_STA_ROAM_POLICY_CHANGED); + sme_release_global_lock(&mac_ctx->sme); + } else { + sme_err("Failed to acquire SME lock"); + } + } + qdf_mem_free(sme_config); + return status; +} + +/** + * sme_enable_disable_chanavoidind_event - configure ca event ind + * @hal: handler to hal + * @set_value: enable/disable + * + * function to enable/disable chan avoidance indication + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_disable_chanavoidind_event(tHalHandle hal, + uint8_t set_value) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct scheduler_msg msg = {0}; + + 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 + * @hal: reference to the HAL + * @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(tHalHandle hal, uint16_t session_id, + uint8_t *ie_data, uint16_t ie_len) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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->session_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(tHalHandle hal, + wma_sar_cb callback, void *context) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_get_sar_limit(wma_handle, callback, context); +} + +QDF_STATUS sme_set_sar_power_limits(tHalHandle hal, + struct sar_limit_cmd_params *sar_limit_cmd) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + 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) { + sme_err("wma handle is NULL"); + 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(tHalHandle hal, 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) { + sme_err("wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_fips_request(wma_handle, param, callback, context); +} +#endif + +QDF_STATUS sme_set_cts2self_for_p2p_go(tHalHandle hal_handle) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_STATUS_SUCCESS != + wma_set_cts2self_for_p2p_go(wma_handle, true)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to set cts2self for p2p GO to firmware", + __func__); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_update_tx_fail_cnt_threshold() - update tx fail count Threshold + * @hal: 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(tHalHandle hal_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 (NULL == tx_fail_cnt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc filter_param", __func__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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; + tpAniSirGlobal 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); + } else { + sme_err("sme_acquire_global_lock error status: %d", status); + } + + return status; +} + +#ifdef FEATURE_WLAN_ESE +bool sme_roam_is_ese_assoc(struct csr_roam_info *roam_info) +{ + return roam_info->isESEAssoc; +} +#endif +/** + * sme_set_5g_band_pref(): If 5G preference is enabled,set boost/drop + * params from ini. + * @hal_handle: Handle returned by mac_open + * @5g_pref_params: pref params from ini. + * + * Returns: None + */ +void sme_set_5g_band_pref(tHalHandle hal_handle, + struct sme_5g_band_pref_params *pref_params) +{ + + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + struct roam_ext_params *roam_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pref_params) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Invalid 5G pref params!"); + return; + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + roam_params = &mac_ctx->roam.configParam.roam_params; + roam_params->raise_rssi_thresh_5g = + pref_params->rssi_boost_threshold_5g; + roam_params->raise_factor_5g = + pref_params->rssi_boost_factor_5g; + roam_params->max_raise_rssi_5g = + pref_params->max_rssi_boost_5g; + roam_params->drop_rssi_thresh_5g = + pref_params->rssi_penalize_threshold_5g; + roam_params->drop_factor_5g = + pref_params->rssi_penalize_factor_5g; + roam_params->max_drop_rssi_5g = + pref_params->max_rssi_penalize_5g; + + sme_release_global_lock(&mac_ctx->sme); + } else + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Unable to acquire global sme lock"); +} + + +bool sme_neighbor_roam_is11r_assoc(tHalHandle hal_ctx, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + return csr_neighbor_roam_is11r_assoc(mac_ctx, session_id); +} + +#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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: invalid wow_pulse_set_info pointer", __func__); + return QDF_STATUS_E_FAILURE; + } + + wow_pulse_set_cmd = qdf_mem_malloc(sizeof(*wow_pulse_set_cmd)); + if (NULL == wow_pulse_set_cmd) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc wow_pulse_set_cmd", __func__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + qdf_mem_free(wow_pulse_set_cmd); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} +#endif + +/** + * sme_prepare_beacon_from_bss_descp() - prepares beacon frame by populating + * different fields and IEs from bss descriptor. + * @frame_buf: frame buffer to populate + * @bss_descp: bss descriptor + * @bssid: bssid of the beacon frame to populate + * @ie_len: length of IE fields + * + * Return: None + */ +static void sme_prepare_beacon_from_bss_descp(uint8_t *frame_buf, + tSirBssDescription *bss_descp, + const tSirMacAddr bssid, + uint32_t ie_len) +{ + tDot11fBeacon1 *bcn_fixed; + tpSirMacMgmtHdr mac_hdr = (tpSirMacMgmtHdr)frame_buf; + + /* populate mac header first to indicate beacon */ + mac_hdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + mac_hdr->fc.type = SIR_MAC_MGMT_FRAME; + mac_hdr->fc.subType = SIR_MAC_MGMT_BEACON; + qdf_mem_copy((uint8_t *) mac_hdr->da, + (uint8_t *) "\xFF\xFF\xFF\xFF\xFF\xFF", + sizeof(struct qdf_mac_addr)); + qdf_mem_copy((uint8_t *) mac_hdr->sa, bssid, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy((uint8_t *) mac_hdr->bssId, bssid, + sizeof(struct qdf_mac_addr)); + + /* now populate fixed params */ + bcn_fixed = (tDot11fBeacon1 *)(frame_buf + SIR_MAC_HDR_LEN_3A); + /* populate timestamp */ + qdf_mem_copy(&bcn_fixed->TimeStamp.timestamp, &bss_descp->timeStamp, + sizeof(bss_descp->timeStamp)); + /* populate beacon interval */ + bcn_fixed->BeaconInterval.interval = bss_descp->beaconInterval; + /* populate capability */ + qdf_mem_copy(&bcn_fixed->Capabilities, &bss_descp->capabilityInfo, + sizeof(bss_descp->capabilityInfo)); + + /* copy IEs now */ + qdf_mem_copy(frame_buf + SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET, + &bss_descp->ieFields, ie_len); +} + +QDF_STATUS sme_get_rssi_snr_by_bssid(tHalHandle hal, + struct csr_roam_profile *profile, + const uint8_t *bssid, + int8_t *rssi, int8_t *snr) +{ + tSirBssDescription *bss_descp; + tCsrScanResultFilter *scan_filter; + struct scan_result_list *bss_list; + tScanResultHandle result_handle = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) { + sme_err("memory allocation failed"); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + + status = csr_roam_prepare_filter_from_profile(mac_ctx, + profile, scan_filter); + if (QDF_STATUS_SUCCESS != status) { + sme_err("prepare_filter failed"); + goto free_scan_flter; + } + + /* update filter to get scan result with just target BSSID */ + if (NULL == scan_filter->BSSIDs.bssid) { + scan_filter->BSSIDs.bssid = + qdf_mem_malloc(sizeof(struct qdf_mac_addr)); + if (scan_filter->BSSIDs.bssid == NULL) { + sme_err("malloc failed"); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + } + + scan_filter->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy(scan_filter->BSSIDs.bssid[0].bytes, + bssid, sizeof(struct qdf_mac_addr)); + + status = csr_scan_get_result(mac_ctx, scan_filter, &result_handle); + if (QDF_STATUS_SUCCESS != status) { + sme_err("parse_scan_result failed"); + goto free_scan_flter; + } + + bss_list = (struct scan_result_list *)result_handle; + bss_descp = csr_get_fst_bssdescr_ptr(bss_list); + if (!bss_descp) { + sme_err("unable to fetch bss descriptor"); + status = QDF_STATUS_E_FAULT; + goto free_scan_flter; + } + + sme_debug("snr: %d, rssi: %d, raw_rssi: %d", + bss_descp->sinr, bss_descp->rssi, bss_descp->rssi_raw); + + if (rssi) + *rssi = bss_descp->rssi; + if (snr) + *snr = bss_descp->sinr; + +free_scan_flter: + /* free scan filter and exit */ + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + } + + if (result_handle) + csr_scan_result_purge(mac_ctx, result_handle); + + return status; +} + +QDF_STATUS sme_get_beacon_frm(tHalHandle hal, struct csr_roam_profile *profile, + const tSirMacAddr bssid, + uint8_t **frame_buf, uint32_t *frame_len, + int *channel) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tScanResultHandle result_handle = NULL; + tCsrScanResultFilter *scan_filter; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tSirBssDescription *bss_descp; + struct scan_result_list *bss_list; + uint32_t ie_len; + + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) { + sme_err("memory allocation failed"); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + status = csr_roam_prepare_filter_from_profile(mac_ctx, + profile, scan_filter); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("prepare_filter failed"); + status = QDF_STATUS_E_FAULT; + goto free_scan_flter; + } + + /* update filter to get scan result with just target BSSID */ + if (NULL == scan_filter->BSSIDs.bssid) { + scan_filter->BSSIDs.bssid = + qdf_mem_malloc(sizeof(struct qdf_mac_addr)); + if (scan_filter->BSSIDs.bssid == NULL) { + sme_err("malloc failed"); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + } + scan_filter->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy(scan_filter->BSSIDs.bssid[0].bytes, + bssid, sizeof(struct qdf_mac_addr)); + + status = csr_scan_get_result(mac_ctx, scan_filter, &result_handle); + if (QDF_STATUS_SUCCESS != status) { + sme_err("parse_scan_result failed"); + status = QDF_STATUS_E_FAULT; + goto free_scan_flter; + } + + bss_list = (struct scan_result_list *)result_handle; + bss_descp = csr_get_fst_bssdescr_ptr(bss_list); + if (!bss_descp) { + sme_err("unable to fetch bss descriptor"); + status = QDF_STATUS_E_FAULT; + goto free_scan_flter; + } + + /** + * Length of BSS descriptor is without length of + * length itself and length of pointer that holds ieFields. + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + ie_len = bss_descp->length + sizeof(bss_descp->length) + - (uint16_t)(offsetof(tSirBssDescription, ieFields[0])); + sme_debug("found bss_descriptor ie_len: %d channel %d", + ie_len, bss_descp->channelId); + + /* include mac header and fixed params along with IEs in frame */ + *frame_len = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET + ie_len; + *frame_buf = qdf_mem_malloc(*frame_len); + if (NULL == *frame_buf) { + sme_err("memory allocation failed"); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + + sme_prepare_beacon_from_bss_descp(*frame_buf, bss_descp, bssid, ie_len); + + if (!*channel) + *channel = bss_descp->channelId; +free_scan_flter: + /* free scan filter and exit */ + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + } + if (result_handle) + csr_scan_result_purge(mac_ctx, result_handle); + + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_fast_reassoc(tHalHandle hal, struct csr_roam_profile *profile, + const tSirMacAddr bssid, int channel, + uint8_t vdev_id, const tSirMacAddr connected_bssid) +{ + QDF_STATUS status; + struct wma_roam_invoke_cmd *fastreassoc; + struct scheduler_msg msg = {0}; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct csr_roam_session *session; + struct csr_roam_profile *roam_profile; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session || !session->pCurRoamProfile) { + sme_err("session %d not found", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + roam_profile = session->pCurRoamProfile; + if (roam_profile->driver_disabled_roaming) { + sme_debug("roaming status in driver %d", + roam_profile->driver_disabled_roaming); + return QDF_STATUS_E_FAILURE; + } + fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc)); + if (NULL == fastreassoc) { + sme_err("qdf_mem_malloc failed for fastreassoc"); + return QDF_STATUS_E_NOMEM; + } + /* if both are same then set the flag */ + if (!qdf_mem_cmp(connected_bssid, bssid, ETH_ALEN)) { + fastreassoc->is_same_bssid = true; + sme_debug("bssid same, bssid[%pM]", bssid); + } + fastreassoc->vdev_id = vdev_id; + fastreassoc->bssid[0] = bssid[0]; + fastreassoc->bssid[1] = bssid[1]; + fastreassoc->bssid[2] = bssid[2]; + fastreassoc->bssid[3] = bssid[3]; + fastreassoc->bssid[4] = bssid[4]; + fastreassoc->bssid[5] = bssid[5]; + + status = sme_get_beacon_frm(hal, profile, bssid, + &fastreassoc->frame_buf, + &fastreassoc->frame_len, + &channel); + + if (!channel) { + sme_err("channel retrieval from BSS desc fails!"); + qdf_mem_free(fastreassoc); + return QDF_STATUS_E_FAULT; + } + + fastreassoc->channel = channel; + if (QDF_STATUS_SUCCESS != status) { + sme_warn("sme_get_beacon_frm failed"); + fastreassoc->frame_buf = NULL; + fastreassoc->frame_len = 0; + } + + if (csr_is_auth_type_ese(mac_ctx->roam.roamSession[vdev_id]. + connectedProfile.AuthType)) { + sme_debug("Beacon is not required for ESE"); + if (fastreassoc->frame_len) { + qdf_mem_free(fastreassoc->frame_buf); + fastreassoc->frame_buf = NULL; + fastreassoc->frame_len = 0; + } + } + + msg.type = eWNI_SME_ROAM_INVOKE; + msg.reserved = 0; + msg.bodyptr = fastreassoc; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Not able to post ROAM_INVOKE_CMD message to PE"); + qdf_mem_free(fastreassoc); + } + + return status; +} +#endif + +QDF_STATUS sme_set_del_pmkid_cache(tHalHandle hal, uint8_t session_id, + tPmkidCacheInfo *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) { + sme_err("Memory allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(pmk_cache, sizeof(*pmk_cache)); + + pmk_cache->session_id = session_id; + + if (!pmk_cache_info) + 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.mac_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 = CSR_RSN_PMKID_SIZE; + qdf_mem_copy(pmk_cache->pmkid, pmk_cache_info->PMKID, + CSR_RSN_PMKID_SIZE); + + 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 + * @hal: handle to hal + * @set_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_set_nud_debug_stats(tHalHandle hal, + 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 == NULL) { + sme_err("Memory allocation failure"); + 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 + * @hal: handle to hal + * @get_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_get_nud_debug_stats(tHalHandle hal, + 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 == NULL) { + sme_err("Memory allocation failure"); + 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) { + sme_err("wma handle is NULL"); + 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(tHalHandle hHal, + 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; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.set_connection_info_cb = set_connection_info_cb; + pMac->sme.get_connection_info_cb = get_connection_info_cb; + sme_release_global_lock(&pMac->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; + tpAniSirGlobal 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(tHalHandle hal, + 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) { + sme_err("fail to alloc 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(tHalHandle hal, struct sme_rcpi_req *rcpi) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + struct scheduler_msg msg = {0}; + struct sme_rcpi_req *rcpi_req; + + rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req)); + if (rcpi_req == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for rcpi req", + __func__); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(rcpi_req, rcpi, sizeof(*rcpi_req)); + + status = sme_acquire_global_lock(&pMac->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(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("post get rcpi req failed")); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(rcpi_req); + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + qdf_mem_free(rcpi_req); + } + + return status; +} + +void sme_store_pdev(tHalHandle hal, struct wlan_objmgr_pdev *pdev) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("wma handle is NULL")); + return; + } + wma_store_pdev(wma_handle, pdev); +} + +QDF_STATUS sme_congestion_register_callback(tHalHandle hal, + congestion_cb congestion_cb) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.congestion_cb = congestion_cb; + sme_release_global_lock(&mac->sme); + sme_debug("congestion callback set"); + } else { + sme_err("Aquiring lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_register_tx_queue_cb(tHalHandle hal, + void (*tx_queue_cb)(void *, + uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + 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"); + } else { + sme_err("Aquiring lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_deregister_tx_queue_cb(tHalHandle hal) +{ + return sme_register_tx_queue_cb(hal, NULL); +} + +#ifdef WLAN_SUPPORT_TWT +QDF_STATUS sme_register_twt_enable_complete_cb(tHalHandle hal, + void (*twt_enable_cb)(void *hdd_ctx, + struct wmi_twt_enable_complete_event_param *params)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.twt_enable_cb = twt_enable_cb; + sme_release_global_lock(&mac->sme); + sme_debug("TWT: enable callback set"); + } else { + sme_err("Aquiring lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_register_twt_disable_complete_cb(tHalHandle hal, + void (*twt_disable_cb)(void *hdd_ctx)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.twt_disable_cb = twt_disable_cb; + sme_release_global_lock(&mac->sme); + sme_debug("TWT: disable callback set"); + } else { + sme_err("Aquiring lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_deregister_twt_enable_complete_cb(tHalHandle hal) +{ + return sme_register_twt_enable_complete_cb(hal, NULL); +} + +QDF_STATUS sme_deregister_twt_disable_complete_cb(tHalHandle hal) +{ + return sme_register_twt_disable_complete_cb(hal, NULL); +} +#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_ipa_uc_stat_request(tHalHandle hal, uint32_t vdev_id, + uint32_t param_id, uint32_t param_val, uint32_t req_cat) +{ + wma_cli_set_cmd_t *iwcmd; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + sme_err("Failed alloc memory for iwcmd"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(iwcmd, sizeof(*iwcmd)); + iwcmd->param_sec_value = 0; + iwcmd->param_vdev_id = vdev_id; + iwcmd->param_id = param_id; + iwcmd->param_vp_dev = req_cat; + iwcmd->param_value = param_val; + wma_ipa_uc_stat_request(iwcmd); + qdf_mem_free(iwcmd); + + return status; +} + +QDF_STATUS sme_set_reorder_timeout(tHalHandle hal, + 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(tHalHandle hal, + 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); +} + +QDF_STATUS sme_set_bt_activity_info_cb(mac_handle_t mac_handle, + bt_activity_info_cb cb) +{ + QDF_STATUS status; + tpAniSirGlobal 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"); + } else { + sme_debug("sme_acquire_global_lock failed %d", status); + } + + return status; +} + +QDF_STATUS sme_get_chain_rssi(tHalHandle hal, + struct get_chain_rssi_req_params *input, + get_chain_rssi_callback callback, + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tp_wma_handle wma_handle; + + SME_ENTER(); + + if (NULL == 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(tpAniSirGlobal mac, + struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (msg == NULL) { + sme_err("Empty message for SME Msg callback"); + return status; + } + status = sme_process_msg(mac, msg); + return status; +} + +void sme_display_disconnect_stats(tHalHandle hal, uint8_t session_id) +{ + struct csr_roam_session *session; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + 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_debug("Total No. of Disconnections: %d", + session->disconnect_stats.disconnection_cnt); + + sme_debug("No. of Diconnects Triggered by Application: %d", + session->disconnect_stats.disconnection_by_app); + + sme_debug("No. of Disassoc Sent by Peer: %d", + session->disconnect_stats.disassoc_by_peer); + + sme_debug("No. of Deauth Sent by Peer: %d", + session->disconnect_stats.deauth_by_peer); + + sme_debug("No. of Disconnections due to Beacon Miss: %d", + session->disconnect_stats.bmiss); + + sme_debug("No. of Disconnections due to Peer Kickout: %d", + session->disconnect_stats.peer_kickout); +} + + /** + * sme_set_vc_mode_config() - Set voltage corner config to FW + * @bitmap: Bitmap that referes 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_STATUS_SUCCESS != + wma_set_vc_mode_config(wma_handle, vc_bitmap)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to set Voltage Control config to FW", + __func__); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * 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(tHalHandle hal, 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) { + sme_err("qdf_mem_malloc failed for limit off channel"); + 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; +} + +/** + * sme_get_status_for_candidate() - Get bss transition status for candidate + * @hal: Handle for HAL + * @conn_bss_desc: connected bss descriptor + * @bss_desc: candidate bss descriptor + * @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(tHalHandle hal, + tSirBssDescription *conn_bss_desc, + tSirBssDescription *bss_desc, + struct bss_candidate_info *info, + uint8_t trans_reason, + bool is_bt_in_progress) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + /* + * 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 ((bss_desc->rssi < mac_ctx->roam.configParam.mbo_thresholds. + mbo_candidate_rssi_thres) && + (conn_bss_desc->rssi > mac_ctx->roam.configParam.mbo_thresholds. + mbo_current_rssi_thres)) { + sme_err("Candidate BSS "MAC_ADDRESS_STR" has LOW RSSI(%d), hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId), bss_desc->rssi); + 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) { + /* + * 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. + */ + if ((conn_bss_desc->rssi > + mac_ctx->roam.configParam.mbo_thresholds. + mbo_current_rssi_mcc_thres) && + csr_is_mcc_channel(mac_ctx, bss_desc->channelId)) { + sme_err("Candidate BSS "MAC_ADDRESS_STR" causes MCC, hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId)); + 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(conn_bss_desc->channelId) && + WLAN_REG_IS_24GHZ_CH(bss_desc->channelId) && + is_bt_in_progress && + (bss_desc->rssi < + mac_ctx->roam.configParam.mbo_thresholds. + mbo_candidate_rssi_btc_thres)) { + sme_err("Candidate BSS "MAC_ADDRESS_STR" causes BT coex, hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId)); + 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. + */ + if (policy_mgr_is_safe_channel(mac_ctx->psoc, + conn_bss_desc->channelId) && + !(policy_mgr_is_safe_channel(mac_ctx->psoc, + bss_desc->channelId))) { + sme_err("High interference expected if transitioned to BSS " + MAC_ADDRESS_STR" hence reject", + MAC_ADDR_ARRAY(bss_desc->bssId)); + info->status = + QCA_STATUS_REJECT_HIGH_INTERFERENCE; + return true; + } + } + + return false; +} + +uint32_t sme_unpack_rsn_ie(tHalHandle hal, uint8_t *buf, + uint8_t buf_len, tDot11fIERSN *rsn_ie, + bool append_ie) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + return dot11f_unpack_ie_rsn(mac_ctx, buf, buf_len, rsn_ie, append_ie); +} + +/** + * wlan_hdd_get_bss_transition_status() - get bss transition status all cadidates + * @adapter : Pointer to adapter + * @transition_reason : Transition reason + * @info : bss candidate information + * @n_candidates : number of candidates + * + * Return : 0 on success otherwise errno + */ +int sme_get_bss_transition_status(tHalHandle hal, + uint8_t transition_reason, + struct qdf_mac_addr *bssid, + struct bss_candidate_info *info, + uint16_t n_candidates, + bool is_bt_in_progress) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirBssDescription *bss_desc, *conn_bss_desc; + tCsrScanResultInfo *res, *conn_res; + uint16_t i; + + if (!n_candidates || !info) { + sme_err("No candidate info available"); + return QDF_STATUS_E_INVAL; + } + + conn_res = qdf_mem_malloc(sizeof(tCsrScanResultInfo)); + if (!conn_res) { + sme_err("Failed to allocate memory for conn_res"); + return QDF_STATUS_E_NOMEM; + } + + res = qdf_mem_malloc(sizeof(tCsrScanResultInfo)); + if (!res) { + sme_err("Failed to allocate memory for conn_res"); + status = QDF_STATUS_E_NOMEM; + goto free; + } + + /* Get the connected BSS descriptor */ + status = sme_scan_get_result_for_bssid(hal, bssid, conn_res); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to find connected BSS in scan list"); + goto free; + } + conn_bss_desc = &conn_res->BssDescriptor; + + for (i = 0; i < n_candidates; i++) { + /* Get candidate BSS descriptors */ + status = sme_scan_get_result_for_bssid(hal, &info[i].bssid, + res); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("BSS "MAC_ADDRESS_STR" not present in scan list", + MAC_ADDR_ARRAY(info[i].bssid.bytes)); + info[i].status = QCA_STATUS_REJECT_UNKNOWN; + continue; + } + + bss_desc = &res->BssDescriptor; + if (!sme_get_status_for_candidate(hal, conn_bss_desc, bss_desc, + &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; + } + } + + /* success */ + status = QDF_STATUS_SUCCESS; + +free: + /* free allocated memory */ + if (conn_res) + qdf_mem_free(conn_res); + if (res) + qdf_mem_free(res); + + return status; +} + +bool sme_is_conn_state_connected(mac_handle_t hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + return csr_is_conn_state_connected(mac_ctx, session_id); +} + +void sme_enable_roaming_on_connected_sta(tHalHandle hal) +{ + uint8_t session_id; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + QDF_STATUS status; + + session_id = csr_get_roam_enabled_sta_sessionid(mac_ctx); + if (session_id != CSR_SESSION_ID_INVALID) + return; + + session_id = csr_get_connected_infra(mac_ctx); + if (session_id == CSR_SESSION_ID_INVALID) { + sme_debug("No STA in conencted state"); + return; + } + + sme_debug("Roaming not enabled on any STA, enable roaming on session %d", + session_id); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_START, + REASON_CTX_INIT); + sme_release_global_lock(&mac_ctx->sme); + } +} + +int16_t sme_get_oper_chan_freq(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id, chan; + struct csr_roam_session *session; + tpAniSirGlobal mac_ctx; + tHalHandle h_hal; + int16_t freq = 0; + + if (vdev == NULL) { + sme_err("Invalid vdev id is passed"); + return 0; + } + + h_hal = cds_get_context(QDF_MODULE_ID_SME); + if (!h_hal) { + sme_err("h_hal is null"); + return 0; + } + mac_ctx = PMAC_STRUCT(h_hal); + 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); + chan = csr_get_infra_operation_channel(mac_ctx, vdev_id); + if (chan) + freq = cds_chan_to_freq(chan); + + return freq; +} + +enum phy_ch_width sme_get_oper_ch_width(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id; + struct csr_roam_session *session; + tpAniSirGlobal mac_ctx; + tHalHandle h_hal; + enum phy_ch_width ch_width = CH_WIDTH_20MHZ; + + if (vdev == NULL) { + sme_err("Invalid vdev id is passed"); + return CH_WIDTH_INVALID; + } + + h_hal = cds_get_context(QDF_MODULE_ID_SME); + if (!h_hal) { + sme_err("h_hal is null"); + return CH_WIDTH_INVALID; + } + mac_ctx = PMAC_STRUCT(h_hal); + vdev_id = wlan_vdev_get_id(vdev); + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("Invalid vdev id is passed"); + return CH_WIDTH_INVALID; + } + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (csr_is_conn_state_connected(mac_ctx, vdev_id)) + ch_width = session->connectedProfile.vht_channel_width; + + return 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(tHalHandle hal, uint8_t session_id, + uint8_t sae_status) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sir_sae_msg *sae_msg; + struct scheduler_msg sch_msg = {0}; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + sae_msg = qdf_mem_malloc(sizeof(*sae_msg)); + if (!sae_msg) { + qdf_status = QDF_STATUS_E_NOMEM; + sme_err("SAE: memory allocation failed"); + } else { + sae_msg->message_type = eWNI_SME_SEND_SAE_MSG; + sae_msg->length = sizeof(*sae_msg); + sae_msg->session_id = session_id; + sae_msg->sae_status = sae_status; + sme_debug("SAE: sae_status %d session_id %d", + sae_msg->sae_status, + sae_msg->session_id); + + 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); + } + sme_release_global_lock(&mac->sme); + } + + return qdf_status; +} +#endif + +bool sme_is_sta_key_exchange_in_progress(tHalHandle hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + 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(tHalHandle hal, + uint8_t *chan_list, + uint8_t num_channels) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint8_t i = 0; + uint8_t j; + bool found; + struct csr_channel *ch_lst_info = &mac_ctx->scan.base_channels; + + if (!chan_list || !num_channels) { + sme_err("Chan list empty %pK or num_channels is 0", chan_list); + return false; + } + + while (i < num_channels) { + found = false; + for (j = 0; j < ch_lst_info->numChannels; j++) { + if (ch_lst_info->channelList[j] == chan_list[i]) { + found = true; + break; + } + } + + if (!found) { + sme_debug("Invalid channel %d", chan_list[i]); + return false; + } + + i++; + } + + return true; +} + +void sme_set_amsdu(tHalHandle hal, bool enable) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + mac_ctx->is_usr_cfg_amsdu_enabled = enable; +} + +uint8_t sme_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags, + uint8_t *nss, uint8_t *mcs_rate_flags) +{ + return wma_get_mcs_idx(max_rate, rate_flags, nss, mcs_rate_flags); +} + +QDF_STATUS +sme_get_roam_scan_stats(tHalHandle hal, roam_scan_stats_cb cb, void *context, + uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct scheduler_msg msg = {0}; + struct sir_roam_scan_stats *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_err("Failed allocate memory for roam scan stats 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("post roam scan stats 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; +} + +QDF_STATUS sme_update_hidden_ssid_status_cb(mac_handle_t mac_handle, + hidden_ssid_cb cb) +{ + QDF_STATUS status; + tpAniSirGlobal 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; +} + +#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; + tpAniSirGlobal 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) { + sme_err("Failed allocate memory for MWS coex info 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 */ diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_ft_api.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_ft_api.c new file mode 100644 index 0000000000000000000000000000000000000000..c6c8af42a4674f07845632cd4f8f5bca6c3d4b55 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_ft_api.c @@ -0,0 +1,544 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include + +/* Initialize the FT context. */ +void sme_ft_open(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL != pSession) { + /* Clean up the context */ + qdf_mem_zero(&pSession->ftSmeContext, sizeof(tftSMEContext)); + + pSession->ftSmeContext.pUsrCtx = + qdf_mem_malloc(sizeof(tFTRoamCallbackUsrCtx)); + + if (NULL == pSession->ftSmeContext.pUsrCtx) { + sme_err("Memory allocation failure"); + return; + } + pSession->ftSmeContext.pUsrCtx->pMac = pMac; + pSession->ftSmeContext.pUsrCtx->sessionId = sessionId; + + status = + qdf_mc_timer_init(&pSession->ftSmeContext. + preAuthReassocIntvlTimer, + QDF_TIMER_TYPE_SW, + sme_preauth_reassoc_intvl_timer_callback, + (void *)pSession->ftSmeContext.pUsrCtx); + + if (QDF_STATUS_SUCCESS != status) { + sme_err("Preauth Reassoc interval Timer allocation failed"); + qdf_mem_free(pSession->ftSmeContext.pUsrCtx); + pSession->ftSmeContext.pUsrCtx = NULL; + return; + } + } +} + +/* Cleanup the SME FT Global context. */ +void sme_ft_close(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = NULL; + + /* Clear the FT Context */ + sme_ft_reset(hHal, sessionId); + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession) { + /* check if the timer is running */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&pSession->ftSmeContext. + preAuthReassocIntvlTimer)) { + qdf_mc_timer_stop(&pSession->ftSmeContext. + preAuthReassocIntvlTimer); + } + + qdf_mc_timer_destroy(&pSession->ftSmeContext. + preAuthReassocIntvlTimer); + + if (pSession->ftSmeContext.pUsrCtx != NULL) { + qdf_mem_free(pSession->ftSmeContext.pUsrCtx); + pSession->ftSmeContext.pUsrCtx = NULL; + } + } +} + +void sme_set_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId, bool state) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (pSession) + pSession->ftSmeContext.setFTPreAuthState = state; +} + +bool sme_get_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (pSession) + return pSession->ftSmeContext.setFTPreAuthState; + + return false; +} + +/** + * sme_set_ft_ies() - to set FT IEs + * @hal_ptr: pointer to HAL + * @session_id: sme session id + * @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 sme_set_ft_ies(tHalHandle hal_ptr, uint32_t session_id, + const uint8_t *ft_ies, uint16_t ft_ies_length) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ptr); + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (NULL == session || NULL == ft_ies) { + sme_err("ft ies or session is NULL"); + return; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) + return; + + sme_debug("FT IEs Req is received in state %d", + session->ftSmeContext.FTState); + + /* Global Station FT State */ + switch (session->ftSmeContext.FTState) { + case eFT_START_READY: + case eFT_AUTH_REQ_READY: + sme_debug("ft_ies_length: %d", ft_ies_length); + if ((session->ftSmeContext.auth_ft_ies) && + (session->ftSmeContext.auth_ft_ies_length)) { + /* Free the one we recvd last from supplicant */ + qdf_mem_free(session->ftSmeContext.auth_ft_ies); + session->ftSmeContext.auth_ft_ies_length = 0; + session->ftSmeContext.auth_ft_ies = NULL; + } + ft_ies_length = QDF_MIN(ft_ies_length, MAX_FTIE_SIZE); + /* Save the FT IEs */ + session->ftSmeContext.auth_ft_ies = + qdf_mem_malloc(ft_ies_length); + if (NULL == session->ftSmeContext.auth_ft_ies) { + sme_err("Mem alloc failed for auth_ft_ies"); + sme_release_global_lock(&mac_ctx->sme); + return; + } + session->ftSmeContext.auth_ft_ies_length = ft_ies_length; + qdf_mem_copy((uint8_t *)session->ftSmeContext.auth_ft_ies, + ft_ies, ft_ies_length); + session->ftSmeContext.FTState = eFT_AUTH_REQ_READY; + break; + + case eFT_AUTH_COMPLETE: + /* + * We will need to re-start preauth. If we received FT + * IEs in eFT_PRE_AUTH_DONE state, it implies there was + * a rekey in our pre-auth state. Hence this implies we + * need Pre-auth again. OK now inform SME we have no + * pre-auth list. Delete the pre-auth node locally. Set + * your self back to restart pre-auth + */ + sme_debug("Preauth done & rcving AUTHREQ in state %d", + session->ftSmeContext.FTState); + sme_debug("Unhandled reception of FT IES in state %d", + session->ftSmeContext.FTState); + break; + + case eFT_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); + + sme_debug("New Reassoc Req: %pK in state %d", + ft_ies, session->ftSmeContext.FTState); + if ((session->ftSmeContext.reassoc_ft_ies) && + (session->ftSmeContext.reassoc_ft_ies_length)) { + /* Free the one we recvd last from supplicant */ + qdf_mem_free(session->ftSmeContext.reassoc_ft_ies); + session->ftSmeContext.reassoc_ft_ies_length = 0; + } + /* Save the FT IEs */ + session->ftSmeContext.reassoc_ft_ies = + qdf_mem_malloc(ft_ies_length); + if (NULL == session->ftSmeContext.reassoc_ft_ies) { + sme_err("Mem alloc fail for reassoc_ft_ie"); + sme_release_global_lock(&mac_ctx->sme); + return; + } + session->ftSmeContext.reassoc_ft_ies_length = + ft_ies_length; + qdf_mem_copy((uint8_t *)session->ftSmeContext.reassoc_ft_ies, + ft_ies, ft_ies_length); + + session->ftSmeContext.FTState = eFT_SET_KEY_WAIT; + sme_debug("ft_ies_length: %d state: %d", ft_ies_length, + session->ftSmeContext.FTState); + + break; + + default: + sme_warn("Unhandled state: %d", session->ftSmeContext.FTState); + break; + } + sme_release_global_lock(&mac_ctx->sme); +} + +/** + * sme_ft_send_update_key_ind() - To send key update indication for FT session + * @mac: pointer to MAC context + * @session_id: sme session id + * @ftkey_info: FT key information + * + * To send key update indication for FT session + * + * Return: QDF_STATUS + */ +static +QDF_STATUS sme_ft_send_update_key_ind(tpAniSirGlobal mac, uint32_t session_id, + tCsrRoamSetKey *ftkey_info) +{ + tSirFTUpdateKeyInfo *msg; + uint16_t msglen; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirKeyMaterial *keymaterial = NULL; + tAniEdType ed_type; + + sme_debug("keyLength: %d", ftkey_info->keyLength); + + if (ftkey_info->keyLength > CSR_MAX_KEY_LEN) { + sme_err("invalid keyLength: %d", ftkey_info->keyLength); + return QDF_STATUS_E_FAILURE; + } + msglen = sizeof(tSirFTUpdateKeyInfo); + + msg = qdf_mem_malloc(msglen); + if (NULL == msg) + return QDF_STATUS_E_NOMEM; + + msg->messageType = eWNI_SME_FT_UPDATE_KEY; + msg->length = msglen; + + keymaterial = &msg->keyMaterial; + keymaterial->length = ftkey_info->keyLength; + ed_type = csr_translate_encrypt_type_to_ed_type(ftkey_info->encType); + keymaterial->edType = ed_type; + keymaterial->numKeys = 1; + keymaterial->key[0].keyId = ftkey_info->keyId; + keymaterial->key[0].unicast = (uint8_t) true; + keymaterial->key[0].keyDirection = ftkey_info->keyDirection; + + qdf_mem_copy(&keymaterial->key[0].keyRsc, + ftkey_info->keyRsc, CSR_MAX_RSC_LEN); + keymaterial->key[0].paeRole = ftkey_info->paeRole; + keymaterial->key[0].keyLength = ftkey_info->keyLength; + + if (ftkey_info->keyLength) + qdf_mem_copy(&keymaterial->key[0].key, ftkey_info->Key, + ftkey_info->keyLength); + + qdf_copy_macaddr(&msg->bssid, &ftkey_info->peerMac); + msg->smeSessionId = session_id; + sme_debug("BSSID = " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(msg->bssid.bytes)); + status = umac_send_mb_message_to_mac(msg); + + return status; +} + +bool sme_get_ftptk_state(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("pSession is NULL"); + return false; + } + return pSession->ftSmeContext.setFTPTKState; +} + +void sme_set_ftptk_state(tHalHandle hHal, uint32_t sessionId, bool state) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("pSession is NULL"); + return; + } + pSession->ftSmeContext.setFTPTKState = state; +} + +QDF_STATUS sme_ft_update_key(tHalHandle hHal, uint32_t sessionId, + tCsrRoamSetKey *pFTKeyInfo) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!pSession) { + sme_err("pSession is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (pFTKeyInfo == NULL) { + sme_err("pFTKeyInfo is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) + return QDF_STATUS_E_FAILURE; + + sme_debug("sme_ft_update_key is received in state %d", + pSession->ftSmeContext.FTState); + + /* Global Station FT State */ + switch (pSession->ftSmeContext.FTState) { + case eFT_SET_KEY_WAIT: + if (sme_get_ft_pre_auth_state(hHal, sessionId) == true) { + status = sme_ft_send_update_key_ind(pMac, sessionId, + pFTKeyInfo); + if (status != 0) { + sme_err("Key set failure: %d", status); + pSession->ftSmeContext.setFTPTKState = false; + status = QDF_STATUS_FT_PREAUTH_KEY_FAILED; + } else { + pSession->ftSmeContext.setFTPTKState = true; + status = QDF_STATUS_FT_PREAUTH_KEY_SUCCESS; + sme_debug("Key set success"); + } + sme_set_ft_pre_auth_state(hHal, sessionId, false); + } + + pSession->ftSmeContext.FTState = eFT_START_READY; + sme_debug("state changed to %d status %d", + pSession->ftSmeContext.FTState, status); + break; + + default: + sme_debug("Unhandled state:%d", pSession->ftSmeContext.FTState); + status = QDF_STATUS_E_FAILURE; + break; + } + sme_release_global_lock(&pMac->sme); + + return status; +} + +/* + * HDD Interface to SME. SME now sends the Auth 2 and RIC IEs up to the + * supplicant. The supplicant will then proceed to send down the + * Reassoc Req. + */ +void sme_get_ft_pre_auth_response(tHalHandle hHal, uint32_t sessionId, + uint8_t *ft_ies, uint32_t ft_ies_ip_len, + uint16_t *ft_ies_length) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!pSession) { + sme_err("pSession is NULL"); + return; + } + + *ft_ies_length = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) + return; + + /* All or nothing - proceed only if both BSSID and FT IE fit */ + if ((QDF_MAC_ADDR_SIZE + + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length) > + ft_ies_ip_len) { + sme_release_global_lock(&pMac->sme); + return; + } + /* hdd needs to pack the bssid also along with the */ + /* auth response to supplicant */ + qdf_mem_copy(ft_ies, pSession->ftSmeContext.preAuthbssId, + QDF_MAC_ADDR_SIZE); + + /* Copy the auth resp FTIEs */ + qdf_mem_copy(&(ft_ies[QDF_MAC_ADDR_SIZE]), + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length); + + *ft_ies_length = QDF_MAC_ADDR_SIZE + + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length; + + pSession->ftSmeContext.FTState = eFT_REASSOC_REQ_WAIT; + + sme_debug("Filled auth resp: %d", *ft_ies_length); + sme_release_global_lock(&pMac->sme); +} + +/* + * SME now sends the RIC IEs up to the supplicant. + * The supplicant will then proceed to send down the + * Reassoc Req. + */ +void sme_get_rici_es(tHalHandle hHal, uint32_t sessionId, uint8_t *ric_ies, + uint32_t ric_ies_ip_len, uint32_t *ric_ies_length) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!pSession) { + sme_err("pSession is NULL"); + return; + } + + *ric_ies_length = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) + return; + + /* All or nothing */ + if (pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length > + ric_ies_ip_len) { + sme_release_global_lock(&pMac->sme); + return; + } + + qdf_mem_copy(ric_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length); + + *ric_ies_length = + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length; + + sme_debug("Filled ric ies: %d", *ric_ies_length); + + sme_release_global_lock(&pMac->sme); +} + +/* + * Timer callback for the timer that is started between the preauth completion + * and reassoc request to the PE. 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 + */ +void sme_preauth_reassoc_intvl_timer_callback(void *context) +{ + tFTRoamCallbackUsrCtx *pUsrCtx = (tFTRoamCallbackUsrCtx *) context; + + if (pUsrCtx) + csr_neighbor_roam_request_handoff(pUsrCtx->pMac, + pUsrCtx->sessionId); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef FEATURE_WLAN_ESE +static void sme_reset_esecckm_info(struct csr_roam_session *session) +{ + qdf_mem_zero(&session->eseCckmInfo, sizeof(session->eseCckmInfo)); +} +#else +static void sme_reset_esecckm_info(struct csr_roam_session *session) +{ +} +#endif +void sme_reset_key(mac_handle_t mac_handle, uint32_t vdev_id) +{ + tpAniSirGlobal mac = PMAC_STRUCT(mac_handle); + struct csr_roam_session *session = NULL; + + if (!mac) { + sme_err("mac is NULL"); + return; + } + + session = CSR_GET_SESSION(mac, vdev_id); + if (!session) + return; + qdf_mem_zero(&session->psk_pmk, sizeof(session->psk_pmk)); + session->pmk_len = 0; + sme_reset_esecckm_info(session); +} +#endif +/* Reset the FT context. */ +void sme_ft_reset(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct csr_roam_session *pSession = NULL; + + if (pMac == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("pMac is NULL")); + return; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession) { + if (pSession->ftSmeContext.auth_ft_ies != NULL) { + qdf_mem_free(pSession->ftSmeContext.auth_ft_ies); + pSession->ftSmeContext.auth_ft_ies = NULL; + } + pSession->ftSmeContext.auth_ft_ies_length = 0; + + if (pSession->ftSmeContext.reassoc_ft_ies != NULL) { + qdf_mem_free(pSession->ftSmeContext.reassoc_ft_ies); + pSession->ftSmeContext.reassoc_ft_ies = NULL; + } + pSession->ftSmeContext.reassoc_ft_ies_length = 0; + + if (pSession->ftSmeContext.psavedFTPreAuthRsp != NULL) { + qdf_mem_free(pSession->ftSmeContext.psavedFTPreAuthRsp); + pSession->ftSmeContext.psavedFTPreAuthRsp = NULL; + } + pSession->ftSmeContext.setFTPreAuthState = false; + pSession->ftSmeContext.setFTPTKState = false; + + qdf_mem_zero(pSession->ftSmeContext.preAuthbssId, + QDF_MAC_ADDR_SIZE); + pSession->ftSmeContext.FTState = eFT_START_READY; + } +} + +/* End of File */ diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_power_save.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_power_save.c new file mode 100644 index 0000000000000000000000000000000000000000..51ca317fda61a2240bbd9143499080ce5d449572 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_power_save.c @@ -0,0 +1,915 @@ +/* + * 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. + */ + +#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 "cfg_api.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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Posting message %d failed", + __func__, 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(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sEnablePsParams *enable_ps_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + 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]; + enum ps_state ps_state; + + enable_ps_req_params = qdf_mem_malloc(sizeof(*enable_ps_req_params)); + if (NULL == enable_ps_req_params) { + sme_err("Memory allocation failed for 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, + session_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 = session_id; + + status = sme_post_ps_msg_to_wma(WMA_ENTER_PS_REQ, enable_ps_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Message WMA_ENTER_PS_REQ Successfully sent to WMA")); + 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(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sDisablePsParams *disable_ps_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + disable_ps_req_params = qdf_mem_malloc(sizeof(*disable_ps_req_params)); + if (NULL == disable_ps_req_params) { + sme_err("Memory allocation failed for sDisablePsParams"); + return QDF_STATUS_E_NOMEM; + } + + disable_ps_req_params->psSetting = eSIR_ADDON_NOTHING; + disable_ps_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_EXIT_PS_REQ, disable_ps_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Message WMA_EXIT_PS_REQ Successfully sent to WMA")); + sme_set_ps_state(mac_ctx, session_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(tpAniSirGlobal 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 (NULL == enable_uapsd_req_params) { + sme_err("Memory allocation failed for 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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(tpAniSirGlobal 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 (NULL == disable_uapsd_req_params) { + sme_err("Mem alloc failed for 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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(tpAniSirGlobal 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; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Power Save command %d"), 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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: power save cmd of type enum 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(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + QDF_BUG(session_id < CSR_ROAM_SESSION_MAX); + if (session_id >= CSR_ROAM_SESSION_MAX) + return QDF_STATUS_E_INVAL; + + /* Check if Sta Ps is enabled. */ + if (!ps_global_info->ps_enabled) { + sme_debug("Cannot initiate PS. PS is disabled in ini"); + return QDF_STATUS_E_FAILURE; + } + + /* Check whether the given session is Infra and in Connected State + * also if command is power save disable there is not need to check + * for connected state as firmware can handle this + */ + if (!csr_is_conn_state_connected_infra(mac_ctx, session_id)) { + sme_debug("STA not infra/connected state Session_id: %d", + session_id); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_disable(): function to enable/disable PS. + * @hal_ctx: global hal_handle + * @session_id: session id + * sme_ps_cmd: power save message + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_enable_disable(tHalHandle hal_ctx, uint32_t session_id, + enum sme_ps_cmd command) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (status != QDF_STATUS_SUCCESS) { + /* + * In non associated state driver wont handle the power save + * But kernel expects return status success even + * in the disconnected state. + * TODO: If driver to remember the ps state to further use + * after connection. + */ + if (!csr_is_conn_state_connected_infra(mac_ctx, session_id)) + status = QDF_STATUS_SUCCESS; + return status; + } + status = sme_ps_process_command(mac_ctx, session_id, command); + return status; +} + +QDF_STATUS sme_ps_timer_flush_sync(tHalHandle hal, uint8_t session_id) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct ps_params *ps_parm; + enum ps_state ps_state; + QDF_TIMER_STATE tstate; + struct sEnablePsParams *req; + t_wma_handle *wma; + + QDF_BUG(session_id < CSR_ROAM_SESSION_MAX); + if (session_id >= CSR_ROAM_SESSION_MAX) + return QDF_STATUS_E_INVAL; + + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (QDF_IS_STATUS_ERROR(status)) { + sme_debug("Power save not allowed for vdev id %d", session_id); + return QDF_STATUS_SUCCESS; + } + + 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) + return QDF_STATUS_SUCCESS; + + sme_debug("flushing powersave enable for vdev %u", session_id); + + qdf_mc_timer_stop(&ps_parm->auto_ps_enable_timer); + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + sme_err("wma is null"); + return QDF_STATUS_E_INVAL; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_err("out of memory"); + return QDF_STATUS_E_NOMEM; + } + + 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(wma, req); + qdf_mem_free(req); + + ps_parm->ps_state = ps_state; + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_uapsd_enable(): function to enable UAPSD. + * @hal_ctx: global hal_handle + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_uapsd_enable(tHalHandle hal_ctx, uint32_t session_id) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + status = sme_enable_sta_ps_check(mac_ctx, session_id); + 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. + * @hal_ctx: global hal_handle + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_uapsd_disable(tHalHandle hal_ctx, uint32_t session_id) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + status = sme_enable_sta_ps_check(mac_ctx, session_id); + 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(tpAniSirGlobal mac_ctx, + tSirMacTSInfo *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_err("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. + * @hal_ctx: global hal_handle + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_start_uapsd(tHalHandle hal_ctx, uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_ps_uapsd_enable(hal_ctx, session_id); + return status; +} + +/** + * sme_set_ps_host_offload(): Set the host offload feature. + * @hal_ctx - 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(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id) +{ + tpSirHostOffloadReq request_buf; + struct scheduler_msg msg = {0}; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: IP address = %d.%d.%d.%d", __func__, + request->params.hostIpv4Addr[0], + request->params.hostIpv4Addr[1], + request->params.hostIpv4Addr[2], + request->params.hostIpv4Addr[3]); + + if (NULL == session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: SESSION not Found", __func__); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirHostOffloadReq)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for host offload request")); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&request->bssid, &session->connectedProfile.bssid); + + qdf_mem_copy(request_buf, request, sizeof(tSirHostOffloadReq)); + + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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. + * @hal_ctx - 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(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + tpSirHostOffloadReq request_buf; + struct scheduler_msg msg = {0}; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (NULL == session) { + sme_err("Session not found"); + return QDF_STATUS_E_FAILURE; + } + + qdf_copy_macaddr(&request->bssid, &session->connectedProfile.bssid); + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Not able to allocate memory for NS offload request"); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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(tpAniSirGlobal 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; +} + +QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t session_id, uint32_t timeout) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + 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; + + if (!timeout) { + sme_debug("auto_ps_timer called with timeout 0; ignore"); + return QDF_STATUS_SUCCESS; + } + + 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(tHalHandle hal_ctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + 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]; + /* + * Stop the auto ps entry timer if runnin + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + sme_info("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(tHalHandle hal_ctx) +{ + + uint32_t i; + + for (i = 0; i < MAX_SME_SESSIONS; i++) { + if (QDF_STATUS_SUCCESS != sme_ps_open_per_session(hal_ctx, 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(tHalHandle hal_ctx, uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + 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; + tpAniSirGlobal mac_ctx; + uint32_t session_id; + QDF_STATUS status; + + if (!ps_params) { + sme_err("ps_params is NULL"); + return; + } + mac_ctx = (tpAniSirGlobal)ps_params->mac_ctx; + if (!mac_ctx) { + sme_err("mac_ctx is NULL"); + 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); + if (QDF_STATUS_SUCCESS == status) + sme_ps_enable_disable((tHalHandle)mac_ctx, session_id, + SME_PS_ENABLE); +} + +QDF_STATUS sme_ps_close(tHalHandle hal_ctx) +{ + uint32_t i; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + sme_ps_close_per_session(hal_ctx, i); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_ps_close_per_session(tHalHandle hal_ctx, uint32_t session_id) +{ + + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + 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; +} + +bool sme_is_auto_ps_timer_running(tHalHandle hal_ctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + 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]; + bool status = false; + /* + * Check if the auto ps entry timer if running + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) + status = true; + + return status; +} + diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_trace.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..b5200a64d6d226ba987fa0d950678f021c355e90 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_trace.c @@ -0,0 +1,216 @@ +/* + * 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: smeTrace.c + * Implementation for trace related APIs + * + * Author Kiran Kumar Reddy CH L V + */ +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "mac_trace.h" +#include "sme_trace.h" +#include "sme_internal.h" +#ifndef SME_TRACE_RECORD +void sme_trace_init(tpAniSirGlobal pMac) +{ + +} +#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_STATS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_RSSI); + 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_GET_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(e_sme_command_del_sta_session); + 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); + 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_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_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_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_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(tpAniSirGlobal pMac) +{ + qdf_trace_register(QDF_MODULE_ID_SME, &sme_trace_dump); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..7c4b3bda5eae4de3e86f13f92f34f9abc3f69109 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c @@ -0,0 +1,22798 @@ +/* + * 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: csr_api_roam.c + * + * Implementation for the Common Roaming interfaces. + */ +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "wma_types.h" +#include "wma_if.h" /* for STA_INVALID_IDX. */ +#include "csr_inside_api.h" +#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 "csr_neighbor_roam.h" +#include "cds_regdomain.h" +#include "cds_utils.h" +#include "sir_types.h" +#include "cfg_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_main.h" + +#define MAX_PWR_FCC_CHAN_12 8 +#define MAX_PWR_FCC_CHAN_13 2 + +#define CSR_NUM_IBSS_START_CHAN_50 5 +#define CSR_NUM_IBSS_START_CHANNELS_24 3 +/* 70 seconds, for WPA, WPA2, CCKM */ +#define CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD \ + (SIR_INSTALL_KEY_TIMEOUT_SEC * QDF_MC_TIMER_TO_SEC_UNIT) +/* 120 seconds, for WPS */ +#define CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD (120 * QDF_MC_TIMER_TO_SEC_UNIT) + +/* OBIWAN recommends [8 10]% : pick 9% */ +#define CSR_VCC_UL_MAC_LOSS_THRESHOLD 9 +/* OBIWAN recommends -85dBm */ +#define CSR_VCC_RSSI_THRESHOLD 80 +#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD 500 /* ms */ +#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS 2000 /* ms */ +#define CSR_MIN_TL_STAT_QUERY_PERIOD 500 /* ms */ +/* Flag to send/do not send disassoc frame over the air */ +#define CSR_DONT_SEND_DISASSOC_OVER_THE_AIR 1 +#define RSSI_HACK_BMPS (-40) +#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 + +/* Choose the largest possible value that can be accommodated in 8 bit signed */ +/* variable. */ +#define SNR_HACK_BMPS (127) + +/* + * ROAMING_OFFLOAD_TIMER_START - Indicates the action to start the timer + * ROAMING_OFFLOAD_TIMER_STOP - Indicates the action to stop the timer + * CSR_ROAMING_OFFLOAD_TIMEOUT_PERIOD - Timeout value for roaming offload timer + */ +#define ROAMING_OFFLOAD_TIMER_START 1 +#define ROAMING_OFFLOAD_TIMER_STOP 2 +#define CSR_ROAMING_OFFLOAD_TIMEOUT_PERIOD (5 * QDF_MC_TIMER_TO_SEC_UNIT) + +/* + * MAWC_ROAM_TRAFFIC_THRESHOLD_DEFAULT - Indicates the traffic thresold in kBps + * MAWC_ROAM_AP_RSSI_THRESHOLD_DEFAULT - indicates the AP RSSI threshold + * MAWC_ROAM_RSSI_HIGH_ADJUST_DEFAULT - Adjustable high value to suppress scan + * MAWC_ROAM_RSSI_LOW_ADJUST_DEFAULT - Adjustable low value to suppress scan + */ +#define MAWC_ROAM_TRAFFIC_THRESHOLD_DEFAULT 300 +#define MAWC_ROAM_AP_RSSI_THRESHOLD_DEFAULT (-66) +#define MAWC_ROAM_RSSI_HIGH_ADJUST_DEFAULT 5 +#define MAWC_ROAM_RSSI_LOW_ADJUST_DEFAULT 5 + +/* + * Neighbor report offload needs to send 0xFFFFFFFF if a particular + * parameter is disabled from the ini + */ +#define NEIGHBOR_REPORT_PARAM_INVALID (0xFFFFFFFFU) + +/* Static Type declarations */ +static struct csr_roam_session csr_roam_roam_session[CSR_ROAM_SESSION_MAX]; + +/* + * To get roam reason from 0 to 3rd bit of roam_synch_data + * received from firmware + */ +#define ROAM_REASON_MASK 0x0F +/** + * csr_get_ielen_from_bss_description() - to get IE length + * from tSirBssDescription structure + * @pBssDescr: pBssDescr + * + * This function is called in various places to get IE length + * from tSirBssDescription structure + * + * @Return: total IE length + */ +static inline uint16_t +csr_get_ielen_from_bss_description(tpSirBssDescription pBssDescr) +{ + uint16_t ielen; + + if (!pBssDescr) + return 0; + + /* + * Length of BSS desription is without length of + * length itself and length of pointer + * that holds ieFields + * + * <------------sizeof(tSirBssDescription)--------------------> + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + + ielen = (uint16_t)(pBssDescr->length + sizeof(pBssDescr->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + return ielen; +} + +#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(tpAniSirGlobal 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 "MAC_ADDRESS_STR"", + sae_info->vdev_id, + MAC_ADDR_ARRAY(sae_info->peer_mac_addr.bytes)); + + session_id = sae_info->vdev_id; + if (session_id == CSR_SESSION_ID_INVALID) + return QDF_STATUS_E_INVAL; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) { + sme_err("qdf_mem_malloc failed for SAE"); + return QDF_STATUS_E_FAILURE; + } + + roam_info->sae_info = sae_info; + + csr_roam_call_callback(mac_ctx, session_id, roam_info, + 0, 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(tpAniSirGlobal mac_ctx, + tSirSmeRsp *msg_ptr) +{ + return QDF_STATUS_SUCCESS; +} +#endif + + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +enum mgmt_auth_type diag_auth_type_from_csr_type(eCsrAuthType authtype) +{ + int n = AUTH_OPEN; + + switch (authtype) { + case eCSR_AUTH_TYPE_SHARED_KEY: + n = AUTH_SHARED; + break; + case eCSR_AUTH_TYPE_WPA: + n = AUTH_WPA_EAP; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + n = AUTH_WPA_PSK; + break; + case eCSR_AUTH_TYPE_RSN: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + n = AUTH_WPA2_EAP; + break; + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: +#endif + n = AUTH_WPA2_PSK; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + n = AUTH_WAPI_CERT; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + n = AUTH_WAPI_PSK; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: + break; + } + return n; +} + +enum mgmt_encrypt_type diag_enc_type_from_csr_type(eCsrEncryptionType enctype) +{ + int n = ENC_MODE_OPEN; + + switch (enctype) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + n = ENC_MODE_WEP40; + break; + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + n = ENC_MODE_WEP104; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + n = ENC_MODE_TKIP; + break; + case eCSR_ENCRYPT_TYPE_AES: + n = ENC_MODE_AES; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP: + n = ENC_MODE_AES_GCMP; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + n = ENC_MODE_AES_GCMP_256; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + n = ENC_MODE_SMS4; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: + break; + } + return n; +} + +enum mgmt_dot11_mode +diag_dot11_mode_from_csr_type(enum csr_cfgdot11mode dot11mode) +{ + switch (dot11mode) { + case eCSR_CFG_DOT11_MODE_ABG: + return DOT11_MODE_ABG; + 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_11G_ONLY: + return DOT11_MODE_11G_ONLY; + case eCSR_CFG_DOT11_MODE_11N_ONLY: + return DOT11_MODE_11N_ONLY; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + return DOT11_MODE_11AC_ONLY; + case eCSR_CFG_DOT11_MODE_AUTO: + return DOT11_MODE_AUTO; + case eCSR_CFG_DOT11_MODE_11AX: + return DOT11_MODE_11AX; + case eCSR_CFG_DOT11_MODE_11AX_ONLY: + return DOT11_MODE_11AX_ONLY; + default: + return DOT11_MODE_MAX; + } +} + +enum mgmt_ch_width diag_ch_width_from_csr_type(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 BW_MAX; + } +} + +enum mgmt_bss_type diag_persona_from_csr_type(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_IBSS_MODE: + return IBSS_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; + } +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static const uint8_t +csr_start_ibss_channels50[CSR_NUM_IBSS_START_CHAN_50] = { 36, 44, 52, 56, 140 }; +static const uint8_t +csr_start_ibss_channels24[CSR_NUM_IBSS_START_CHANNELS_24] = { 1, 6, 11 }; + +static const uint8_t +social_channel[MAX_SOCIAL_CHANNELS] = { 1, 6, 11 }; + +static void init_config_param(tpAniSirGlobal pMac); +static bool csr_roam_process_results(tpAniSirGlobal pMac, tSmeCmd *pCommand, + enum csr_roamcomplete_result Result, + void *Context); +static QDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + bool *pfSameIbss); +static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirSmeNewBssInfo * + pNewBss); +static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac, + uint8_t primaryChn, + tDot11fBeaconIEs *pIes); + +static void csr_roaming_state_config_cnf_processor(tpAniSirGlobal pMac, + tSmeCmd *pCommand, uint32_t result, uint8_t session_id); +static QDF_STATUS csr_roam_open(tpAniSirGlobal pMac); +static QDF_STATUS csr_roam_close(tpAniSirGlobal pMac); +static bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile, + struct csr_roam_profile *pProfile2); + +static QDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac, + uint32_t sessionId, + uint32_t interval); +static QDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac, + uint32_t sessionId); +static void csr_roam_roaming_timer_handler(void *pv); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void csr_roam_roaming_offload_timer_action(tpAniSirGlobal mac_ctx, + uint32_t interval, uint8_t session_id, uint8_t action); +#endif +static void csr_roam_roaming_offload_timeout_handler(void *timer_data); +static QDF_STATUS csr_roam_start_wait_for_key_timer(tpAniSirGlobal pMac, + uint32_t interval); +static void csr_roam_wait_for_key_time_out_handler(void *pv); +static QDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo); +static QDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac, + tCsr11dinfo *ps11dinfo); +static QDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac, + struct csr_roam_connectedinfo * + pConnectedInfo); +static QDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr peer_macaddr, + uint8_t numKeys, + tAniEdType edType, bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint8_t keyLength, + uint8_t *pKey, uint8_t paeRole, + uint8_t *pKeyRsc); +static void csr_roam_link_up(tpAniSirGlobal pMac, struct qdf_mac_addr bssid); +static void csr_roam_link_down(tpAniSirGlobal pMac, uint32_t sessionId); +#ifndef QCA_SUPPORT_CP_STATS +static QDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, + uint32_t statsMask, uint8_t staId, + uint8_t sessionId); +/* pStaEntry is no longer invalid upon the return of this function. */ +static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, + tListElem *pEntry); +struct csr_statsclient_reqinfo *csr_roam_insert_entry_into_list( + tpAniSirGlobal pMac, tDblLinkList *pStaList, + struct csr_statsclient_reqinfo * + pStaEntry); +static void csr_roam_report_statistics(tpAniSirGlobal pMac, + uint32_t statsMask, tCsrStatsCallback callback, uint8_t staId, + void *pContext); +tListElem *csr_roam_check_client_req_list( + tpAniSirGlobal pMac, uint32_t statsMask); +static void csr_roam_remove_entry_from_pe_stats_req_list( + tpAniSirGlobal pMac, struct csr_pestats_reqinfo *pPeStaEntry); +tListElem *csr_roam_find_in_pe_stats_req_list( + tpAniSirGlobal pMac, + uint32_t statsMask); +static QDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac); +#else +static QDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac) +{ + return QDF_STATUS_SUCCESS; +} +#endif +static enum csr_cfgdot11mode +csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + uint8_t operationChn, + enum band_info *pBand); +static QDF_STATUS csr_roam_get_qos_info_from_bss( +tpAniSirGlobal pMac, tSirBssDescription *pBssDesc); +static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac); +static uint32_t csr_find_session_by_type(tpAniSirGlobal, + enum QDF_OPMODE); +static bool csr_is_conn_allow_2g_band(tpAniSirGlobal pMac, + uint32_t chnl); +static bool csr_is_conn_allow_5g_band(tpAniSirGlobal pMac, + uint32_t chnl); +static QDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc); +static void csr_init_session(tpAniSirGlobal pMac, uint32_t sessionId); +static QDF_STATUS csr_roam_issue_set_key_command(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamSetKey *pSetKey, + uint32_t roamId); +static QDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf, + tSirSmeDisassocRsp *pRsp); +static void csr_init_operating_classes(tHalHandle hHal); + +static void csr_add_len_of_social_channels(tpAniSirGlobal mac, + uint8_t *num_chan); +static void csr_add_social_channels(tpAniSirGlobal mac, + tSirUpdateChanList *chan_list, struct csr_scanstruct *pScan, + uint8_t *num_chan); + +/* Initialize global variables */ +static void csr_roam_init_globals(tpAniSirGlobal pMac) +{ + if (pMac) { + qdf_mem_zero(&csr_roam_roam_session, + sizeof(csr_roam_roam_session)); + pMac->roam.roamSession = csr_roam_roam_session; + } +} + +static void csr_roam_de_init_globals(tpAniSirGlobal pMac) +{ + uint8_t i; + + if (pMac) { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (pMac->roam.roamSession[i].pCurRoamProfile) + csr_release_profile(pMac, + pMac->roam.roamSession[i]. + pCurRoamProfile); + csr_release_profile(pMac, + &pMac->roam.roamSession[i]. + stored_roam_profile.profile); + } + pMac->roam.roamSession = NULL; + } +} + +#ifdef QCA_SUPPORT_CP_STATS +static QDF_STATUS csr_open_stats_ll(struct sAniSirGlobal *mac_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static void csr_close_stats_ll(struct sAniSirGlobal *mac_ctx) {} +#else +static QDF_STATUS csr_open_stats_ll(struct sAniSirGlobal *mac_ctx) +{ + QDF_STATUS status; + + status = csr_ll_open(&mac_ctx->roam.statsClientReqList); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return csr_ll_open(&mac_ctx->roam.peStatsReqList); +} + +static void csr_close_stats_ll(struct sAniSirGlobal *mac_ctx) +{ + csr_ll_close(&mac_ctx->roam.statsClientReqList); + csr_ll_close(&mac_ctx->roam.peStatsReqList); +} +#endif + +/** + * csr_assoc_rej_free_rssi_disallow_list() - Free the rssi disallowed + * BSSID entries and destroy the list + * @mac_ctx: MAC context + * + * Return: void + */ +static void csr_assoc_rej_free_rssi_disallow_list(struct sAniSirGlobal *mac) +{ + QDF_STATUS status; + struct sir_rssi_disallow_lst *cur_node; + qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; + qdf_list_t *list = &mac->roam.rssi_disallow_bssid; + + qdf_mutex_acquire(&mac->roam.rssi_disallow_bssid_lock); + qdf_list_peek_front(list, &cur_lst); + while (cur_lst) { + qdf_list_peek_next(list, cur_lst, &next_lst); + cur_node = qdf_container_of(cur_lst, + struct sir_rssi_disallow_lst, node); + status = qdf_list_remove_node(list, cur_lst); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(cur_node); + cur_lst = next_lst; + next_lst = NULL; + } + qdf_list_destroy(list); + qdf_mutex_release(&mac->roam.rssi_disallow_bssid_lock); +} + +/** + * csr_roam_rssi_disallow_bssid_init() - Init the rssi disallowed + * list and mutex + * @mac_ctx: MAC context + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS csr_roam_rssi_disallow_bssid_init( + struct sAniSirGlobal *mac_ctx) +{ + qdf_list_create(&mac_ctx->roam.rssi_disallow_bssid, + MAX_RSSI_AVOID_BSSID_LIST); + qdf_mutex_create(&mac_ctx->roam.rssi_disallow_bssid_lock); + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_roam_rssi_disallow_bssid_deinit() - Free the rssi diallowed + * BSSID entries and destroy the list&mutex + * @mac_ctx: MAC context + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS csr_roam_rssi_disallow_bssid_deinit( + struct sAniSirGlobal *mac_ctx) +{ + csr_assoc_rej_free_rssi_disallow_list(mac_ctx); + qdf_mutex_destroy(&mac_ctx->roam.rssi_disallow_bssid_lock); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_open(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + + do { + /* Initialize CSR Roam Globals */ + csr_roam_init_globals(pMac); + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, i); + + init_config_param(pMac); + status = csr_scan_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + status = csr_roam_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + pMac->roam.nextRoamId = 1; /* Must not be 0 */ + status = csr_open_stats_ll(pMac); + if (QDF_IS_STATUS_ERROR(status)) + break; + + csr_roam_rssi_disallow_bssid_init(pMac); + } while (0); + + return status; +} + +QDF_STATUS csr_init_chan_list(tpAniSirGlobal mac, uint8_t *alpha2) +{ + QDF_STATUS status; + + mac->scan.countryCodeDefault[0] = alpha2[0]; + mac->scan.countryCodeDefault[1] = alpha2[1]; + mac->scan.countryCodeDefault[2] = alpha2[2]; + + sme_debug("init time country code %.2s", mac->scan.countryCodeDefault); + + mac->scan.domainIdDefault = 0; + mac->scan.domainIdCurrent = 0; + + qdf_mem_copy(mac->scan.countryCodeCurrent, + mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + qdf_mem_copy(mac->scan.countryCodeElected, + mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + status = csr_get_channel_and_power_list(mac); + csr_clear_votes_for_country_info(mac); + return status; +} + +QDF_STATUS csr_set_channels(tpAniSirGlobal pMac, tCsrConfigParam *pParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t index = 0; + + qdf_mem_copy(pParam->Csr11dinfo.countryCode, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + for (index = 0; index < pMac->scan.base_channels.numChannels; + index++) { + pParam->Csr11dinfo.Channels.channelList[index] = + pMac->scan.base_channels.channelList[index]; + pParam->Csr11dinfo.ChnPower[index].firstChannel = + pMac->scan.base_channels.channelList[index]; + pParam->Csr11dinfo.ChnPower[index].numChannels = 1; + pParam->Csr11dinfo.ChnPower[index].maxtxPower = + pMac->scan.defaultPowerTable[index].tx_power; + } + pParam->Csr11dinfo.Channels.numChannels = + pMac->scan.base_channels.numChannels; + + return status; +} + +QDF_STATUS csr_close(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_roam_close(pMac); + csr_roam_rssi_disallow_bssid_deinit(pMac); + csr_scan_close(pMac); + csr_close_stats_ll(pMac); + /* DeInit Globals */ + csr_roam_de_init_globals(pMac); + return status; +} + +static int8_t csr_find_channel_pwr(struct channel_power * + pdefaultPowerTable, + uint8_t ChannelNum) +{ + 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 < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (pdefaultPowerTable[i].chan_num == ChannelNum) + 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(tpAniSirGlobal 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 = (tSirUpdateChanParam *) + qdf_mem_malloc(sizeof(tSirUpdateChanParam) * num_channel); + if (tmp_list == NULL) { + sme_err("Memory allocation failed"); + return; + } + + /* Fist copy Non-DFS 5g channels */ + for (i = 0; i < num_channel; i++) { + if (WLAN_REG_IS_5GHZ_CH(chan_list[i].chanId) && + !wlan_reg_is_dfs_ch(mac_ctx->pdev, + chan_list[i].chanId)) { + qdf_mem_copy(&tmp_list[j++], + &chan_list[i], sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + if (prefer_dfs) { + /* next copy DFS channels (remaining channels in 5G) */ + for (i = 0; i < num_channel; i++) { + if (WLAN_REG_IS_5GHZ_CH(chan_list[i].chanId)) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + } else { + /* next copy 2G channels */ + for (i = 0; i < num_channel; i++) { + if (WLAN_REG_IS_24GHZ_CH(chan_list[i].chanId)) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + } + /* copy rest of the channels in same order to tmp list */ + for (i = 0; i < num_channel; i++) { + if (chan_list[i].chanId != INVALID_CHANNEL_ID) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + /* 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(tpAniSirGlobal mac_ctx, + tSirUpdateChanList *chan_list, uint8_t num_channel) +{ + tSirUpdateChanList *chan_list_greedy, *chan_list_non_greedy; + uint8_t i, j; + static const uint8_t fixed_greedy_chan_list[] = {1, 6, 11, 36, 48, 40, + 44, 10, 2, 9, 149, 157, 161, 3, 4, 8, 153, 165, 7, 5, 136, 140, + 52, 116, 56, 104, 64, 60, 100, 120, 13, 14, 112, 132, 151, 155}; + 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) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Failed to allocate memory for tSirUpdateChanList"); + goto scan_list_sort_error; + } + /* + * fixed_greedy_chan_list is an evaluated channel 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_chan_list)/sizeof(uint8_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].chanId == + fixed_greedy_chan_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_chan_list[i] == + chan_list->chanParam[j].chanId) { + qdf_mem_copy( + &chan_list_greedy->chanParam[num_greedy_chan], + &chan_list->chanParam[j], + sizeof(tSirUpdateChanParam)); + num_greedy_chan++; + break; + } + } + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_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) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "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_NAPIER_EMULATION +#define SCAN_CHAN_LIST_5G_LEN 6 +#define SCAN_CHAN_LIST_2G_LEN 3 +static const uint8_t +csr_scan_chan_list_5g[SCAN_CHAN_LIST_5G_LEN] = { 36, 44, 52, 56, 140, 149 }; +static const uint8_t +csr_scan_chan_list_2g[SCAN_CHAN_LIST_2G_LEN] = { 1, 6, 11 }; +static QDF_STATUS csr_emu_chan_req(uint32_t channel) +{ + int i; + + if (WLAN_REG_IS_24GHZ_CH(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(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; + } + } + 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(tpAniSirGlobal 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( + mac->pdev, social_channel[i]) == + CHANNEL_STATE_ENABLE) + no_chan++; + } + } + *num_chan = no_chan; + sme_debug("after adding - num_chan:%hu", *num_chan); +} + +static void csr_add_social_channels(tpAniSirGlobal 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(mac->pdev, + social_channel[i]) != CHANNEL_STATE_ENABLE) + continue; + chan_list->chanParam[no_chan].chanId = + social_channel[i]; + chan_list->chanParam[no_chan].pwr = + csr_find_channel_pwr(pScan->defaultPowerTable, + social_channel[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(tpAniSirGlobal mac, + uint8_t *num_chan) +{ + sme_debug("skip adding len of social channels"); +} +static void csr_add_social_channels(tpAniSirGlobal mac, + tSirUpdateChanList *chan_list, struct csr_scanstruct *pScan, + uint8_t *num_chan) +{ + sme_debug("skip social channels"); +} +#endif + +QDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac) +{ + tSirUpdateChanList *pChanList; + struct csr_scanstruct *pScan = &pMac->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; + uint8_t channel; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + sme_err("qdf_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + csr_add_len_of_social_channels(pMac, &numChan); + + bufLen = sizeof(tSirUpdateChanList) + + (sizeof(tSirUpdateChanParam) * (numChan)); + + csr_init_operating_classes((tHalHandle) pMac); + pChanList = (tSirUpdateChanList *) qdf_mem_malloc(bufLen); + if (!pChanList) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Failed to allocate memory for tSirUpdateChanList"); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < pScan->base_channels.numChannels; i++) { + struct csr_sta_roam_policy_params *roam_policy = + &pMac->roam.configParam.sta_roam_policy; + if (QDF_STATUS_SUCCESS != + csr_emu_chan_req(pScan->base_channels.channelList[i])) + continue; + + /* Scan is not performed on DSRC channels*/ + if (wlan_reg_is_dsrc_chan(pMac->pdev, + pScan->base_channels.channelList[i])) + continue; + + channel = pScan->base_channels.channelList[i]; + + channel_state = wlan_reg_get_channel_state(pMac->pdev, + pScan->base_channels.channelList[i]); + if ((CHANNEL_STATE_ENABLE == channel_state) || + pMac->scan.fEnableDFSChnlScan) { + if ((pMac->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED) && + (channel_state == CHANNEL_STATE_DFS)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("skip dfs channel %d"), + channel); + continue; + } + if (pMac->roam.configParam.sta_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) { + is_unsafe_chan = true; + break; + } + } + if ((is_unsafe_chan) && + ((WLAN_REG_IS_24GHZ_CH(channel) && + roam_policy->sap_operating_band == + BAND_2G) || + (WLAN_REG_IS_5GHZ_CH(channel) && + roam_policy->sap_operating_band == + BAND_5G))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("ignoring unsafe channel %d"), + channel); + continue; + } + } + pChanList->chanParam[num_channel].chanId = + pScan->base_channels.channelList[i]; + pChanList->chanParam[num_channel].pwr = + csr_find_channel_pwr(pScan->defaultPowerTable, + pChanList->chanParam[num_channel].chanId); + + if (pScan->fcc_constraint) { + if (12 == pChanList->chanParam[num_channel]. + chanId) { + pChanList->chanParam[num_channel].pwr = + MAX_PWR_FCC_CHAN_12; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "txpow for channel 12 is %d", + MAX_PWR_FCC_CHAN_12); + } + if (13 == pChanList->chanParam[num_channel]. + chanId) { + pChanList->chanParam[num_channel].pwr = + MAX_PWR_FCC_CHAN_13; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "txpow for channel 13 is %d", + MAX_PWR_FCC_CHAN_13); + } + } + + + if (CHANNEL_STATE_ENABLE == channel_state) + pChanList->chanParam[num_channel].dfsSet = + false; + else + pChanList->chanParam[num_channel].dfsSet = + true; + if (cds_is_5_mhz_enabled()) + pChanList->chanParam[num_channel].quarter_rate + = 1; + else if (cds_is_10_mhz_enabled()) + pChanList->chanParam[num_channel].half_rate = 1; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "channel:%d, pwr=%d, DFS=%d qrate %d hrate %d ", + pChanList->chanParam[num_channel].chanId, + pChanList->chanParam[num_channel].pwr, + pChanList->chanParam[num_channel].dfsSet, + pChanList->chanParam[num_channel].quarter_rate, + pChanList->chanParam[num_channel].half_rate); + num_channel++; + } + } + + csr_add_social_channels(pMac, pChanList, pScan, &num_channel); + + if (pMac->roam.configParam.early_stop_scan_enable) + csr_roam_sort_channel_for_early_stop(pMac, pChanList, + num_channel); + else + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Early Stop Scan Feature not supported")); + + if ((pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC_ONLY)) { + pChanList->vht_en = true; + if (pMac->roam.configParam.enableVhtFor24GHz) + pChanList->vht_24_en = true; + } + if ((pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N_ONLY)) { + pChanList->ht_en = true; + } + msg.type = WMA_UPDATE_CHAN_LIST_REQ; + msg.reserved = 0; + msg.bodyptr = pChanList; + pChanList->numChan = num_channel; + 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_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to post msg to WMA", __func__); + qdf_mem_free(pChanList); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef QCA_SUPPORT_CP_STATS +static void csr_init_tl_stats(struct sAniSirGlobal *mac_ctx) {} +#else +static void csr_init_tl_stats(struct sAniSirGlobal *mac_ctx) +{ + mac_ctx->roam.tlStatsReqInfo.numClient = 0; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +QDF_STATUS csr_start(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + + do { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_IDLE, i); + + status = csr_roam_start(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + pMac->roam.sPendingCommands = 0; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + status = csr_neighbor_roam_init(pMac, i); + csr_init_tl_stats(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_warn("csr_start: Couldn't Init HO control blk "); + break; + } + /* Register with scan component */ + pMac->scan.requester_id = ucfg_scan_register_requester( + pMac->psoc, + "CSR", csr_scan_callback, pMac); + ucfg_scan_set_enable(pMac->psoc, true); + } while (0); + return status; +} + +QDF_STATUS csr_stop(tpAniSirGlobal pMac) +{ + uint32_t sessionId; + + ucfg_scan_set_enable(pMac->psoc, false); + ucfg_scan_unregister_requester(pMac->psoc, pMac->scan.requester_id); + + /* + * purge all serialization commnad if there are any pending to make + * sure memory and vdev ref are freed. + */ + csr_purge_pdev_all_ser_cmd_list(pMac); + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + csr_roam_close_session(pMac, sessionId, true); + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + csr_neighbor_roam_close(pMac, sessionId); + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + csr_scan_flush_result(pMac); + + /* Reset the domain back to the deault */ + pMac->scan.domainIdCurrent = pMac->scan.domainIdDefault; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, sessionId); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_ready(tpAniSirGlobal pMac) +{ + 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(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("csr_apply_channel_and_power_list failed during csr_ready with status: %d", + status); + + return status; +} + +void csr_set_default_dot11_mode(tpAniSirGlobal pMac) +{ + uint32_t wniDot11mode = 0; + + wniDot11mode = csr_translate_to_wni_cfg_dot11_mode(pMac, + pMac->roam.configParam.uCfgDot11Mode); + cfg_set_int(pMac, WNI_CFG_DOT11_MODE, wniDot11mode); +} + +void csr_set_global_cfgs(tpAniSirGlobal pMac) +{ + + cfg_set_int(pMac, WNI_CFG_FRAGMENTATION_THRESHOLD, + csr_get_frag_thresh(pMac)); + cfg_set_int(pMac, WNI_CFG_RTS_THRESHOLD, csr_get_rts_thresh(pMac)); + cfg_set_int(pMac, WNI_CFG_11D_ENABLED, + ((pMac->roam.configParam.Is11hSupportEnabled) ? + pMac->roam.configParam.Is11dSupportEnabled : + pMac->roam.configParam.Is11dSupportEnabled)); + cfg_set_int(pMac, WNI_CFG_11H_ENABLED, + pMac->roam.configParam.Is11hSupportEnabled); + /* 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 + */ + cfg_set_int(pMac, WNI_CFG_CHANNEL_BONDING_MODE, + !!(pMac->roam.configParam.channelBondingMode5GHz)); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + + /* 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(pMac); +} + +/** + * 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) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s Invoking packetdump deregistration API", __func__); + wlan_deregister_txrx_packetdump(); +} + +/** + * 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) +{ + QDF_STATUS status; + tHalHandle hal; + tpAniSirGlobal mac; + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + 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_roam_open(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + struct csr_roam_session *pSession; + + do { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + pSession = CSR_GET_SESSION(pMac, i); + pSession->roamingTimerInfo.pMac = pMac; + pSession->roamingTimerInfo.sessionId = + CSR_SESSION_ID_INVALID; + } + pMac->roam.WaitForKeyTimerInfo.pMac = pMac; + pMac->roam.WaitForKeyTimerInfo.sessionId = + CSR_SESSION_ID_INVALID; + status = qdf_mc_timer_init(&pMac->roam.hTimerWaitForKey, + QDF_TIMER_TYPE_SW, + csr_roam_wait_for_key_time_out_handler, + &pMac->roam.WaitForKeyTimerInfo); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("cannot allocate memory for WaitForKey time out timer"); + break; + } + status = qdf_mc_timer_init(&pMac->roam.packetdump_timer, + QDF_TIMER_TYPE_SW, csr_packetdump_timer_handler, + pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("cannot allocate memory for packetdump timer"); + break; + } + spin_lock_init(&pMac->roam.roam_state_lock); + } while (0); + return status; +} + +static QDF_STATUS csr_roam_close(tpAniSirGlobal pMac) +{ + uint32_t sessionId; + + /* + * purge all serialization commnad if there are any pending to make + * sure memory and vdev ref are freed. + */ + csr_purge_pdev_all_ser_cmd_list(pMac); + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + csr_roam_close_session(pMac, sessionId, true); + + qdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey); + qdf_mc_timer_destroy(&pMac->roam.hTimerWaitForKey); + qdf_mc_timer_stop(&pMac->roam.packetdump_timer); + qdf_mc_timer_destroy(&pMac->roam.packetdump_timer); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_start(tpAniSirGlobal pMac) +{ + (void)pMac; + return QDF_STATUS_SUCCESS; +} + +void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId) +{ + csr_roam_stop_roaming_timer(pMac, sessionId); + /* deregister the clients requesting stats from PE/TL & also stop + * the corresponding timers + */ + csr_roam_dereg_statistics_req(pMac); +} + +QDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrConnectState *pState) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (CSR_IS_SESSION_VALID(pMac, sessionId) && (NULL != pState)) { + status = QDF_STATUS_SUCCESS; + *pState = pMac->roam.roamSession[sessionId].connectState; + } + return status; +} + +QDF_STATUS csr_roam_copy_connect_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamConnectedProfile *pProfile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t size = 0; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrRoamConnectedProfile *connected_prof; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + if (!pProfile) { + sme_err("profile not found"); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->pConnectBssDesc) { + size = pSession->pConnectBssDesc->length + + sizeof(pSession->pConnectBssDesc->length); + if (size) { + pProfile->pBssDesc = qdf_mem_malloc(size); + if (NULL != pProfile->pBssDesc) { + qdf_mem_copy(pProfile->pBssDesc, + pSession->pConnectBssDesc, + size); + status = QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_E_FAILURE; + } + } else { + pProfile->pBssDesc = NULL; + } + connected_prof = &(pSession->connectedProfile); + pProfile->AuthType = connected_prof->AuthType; + pProfile->EncryptionType = connected_prof->EncryptionType; + pProfile->mcEncryptionType = connected_prof->mcEncryptionType; + pProfile->BSSType = connected_prof->BSSType; + pProfile->operationChannel = connected_prof->operationChannel; + qdf_mem_copy(&pProfile->bssid, &connected_prof->bssid, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(&pProfile->SSID, &connected_prof->SSID, + sizeof(tSirMacSSid)); + if (connected_prof->MDID.mdiePresent) { + pProfile->MDID.mdiePresent = 1; + pProfile->MDID.mobilityDomain = + connected_prof->MDID.mobilityDomain; + } else { + pProfile->MDID.mdiePresent = 0; + pProfile->MDID.mobilityDomain = 0; + } +#ifdef FEATURE_WLAN_ESE + pProfile->isESEAssoc = connected_prof->isESEAssoc; + if (csr_is_auth_type_ese(connected_prof->AuthType)) { + qdf_mem_copy(pProfile->eseCckmInfo.krk, + connected_prof->eseCckmInfo.krk, + SIR_KRK_KEY_LEN); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + qdf_mem_copy(pProfile->eseCckmInfo.btk, + connected_prof->eseCckmInfo.btk, + SIR_BTK_KEY_LEN); +#endif + pProfile->eseCckmInfo.reassoc_req_num = + connected_prof->eseCckmInfo.reassoc_req_num; + pProfile->eseCckmInfo.krk_plumbed = + connected_prof->eseCckmInfo.krk_plumbed; + } +#endif +#ifdef WLAN_FEATURE_11W + pProfile->MFPEnabled = connected_prof->MFPEnabled; + pProfile->MFPRequired = connected_prof->MFPRequired; + pProfile->MFPCapable = connected_prof->MFPCapable; +#endif + } + return status; +} + +QDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamConnectedProfile *pProfile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if ((csr_is_conn_state_connected(pMac, sessionId)) || + (csr_is_conn_state_ibss(pMac, sessionId))) { + if (pProfile) { + status = + csr_roam_copy_connect_profile(pMac, sessionId, + pProfile); + } + } + return status; +} + +void csr_roam_free_connect_profile(tCsrRoamConnectedProfile *profile) +{ + if (profile->pBssDesc) + qdf_mem_free(profile->pBssDesc); + if (profile->pAddIEAssoc) + qdf_mem_free(profile->pAddIEAssoc); + qdf_mem_zero(profile, sizeof(tCsrRoamConnectedProfile)); + profile->AuthType = eCSR_AUTH_TYPE_UNKNOWN; +} + +static QDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac, + 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->staId = 0; + pConnectedInfo->nRICRspLength = 0; +#ifdef FEATURE_WLAN_ESE + pConnectedInfo->nTspecIeLength = 0; +#endif + return status; +} + +void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_roam_cmd(pMac, pCommand); +} + +void csr_release_command_wm_status_change(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + csr_reinit_wm_status_change_cmd(pMac, pCommand); +} + +static void csr_release_command_set_hw_mode(tpAniSirGlobal mac, + tSmeCmd *cmd) +{ + struct csr_roam_session *session; + uint32_t session_id; + + if (cmd->u.set_hw_mode_cmd.reason == + POLICY_MGR_UPDATE_REASON_HIDDEN_STA) { + session_id = cmd->u.set_hw_mode_cmd.session_id; + session = CSR_GET_SESSION(mac, session_id); + if (session) + csr_saved_scan_cmd_free_fields(mac, session); + } +} + +void csr_roam_substate_change(tpAniSirGlobal pMac, + enum csr_roam_substate NewSubstate, uint32_t sessionId) +{ + if (sessionId >= CSR_ROAM_SESSION_MAX) { + sme_err("Invalid no of concurrent sessions %d", + sessionId); + return; + } + sme_debug("CSR RoamSubstate: [ %s <== %s ]", + mac_trace_getcsr_roam_sub_state(NewSubstate), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[sessionId])); + if (pMac->roam.curSubState[sessionId] == NewSubstate) + return; + spin_lock(&pMac->roam.roam_state_lock); + pMac->roam.curSubState[sessionId] = NewSubstate; + spin_unlock(&pMac->roam.roam_state_lock); +} + +enum csr_roam_state csr_roam_state_change(tpAniSirGlobal pMac, + enum csr_roam_state NewRoamState, + uint8_t sessionId) +{ + enum csr_roam_state PreviousState; + + sme_debug("CSR RoamState[%hu]: [ %s <== %s ]", sessionId, + mac_trace_getcsr_roam_state(NewRoamState), + mac_trace_getcsr_roam_state(pMac->roam.curState[sessionId])); + PreviousState = pMac->roam.curState[sessionId]; + + if (NewRoamState != pMac->roam.curState[sessionId]) { + /* Whenever we transition OUT of the Roaming state, + * clear the Roaming substate. + */ + if (CSR_IS_ROAM_JOINING(pMac, sessionId)) { + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + + pMac->roam.curState[sessionId] = NewRoamState; + } + return PreviousState; +} + +void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi, + uint8_t catOffset) +{ + int i; + + sme_debug("best AP RSSI: %d cat offset: %d", bestApRssi, catOffset); + if (catOffset) { + pMac->roam.configParam.bCatRssiOffset = catOffset; + for (i = 0; i < CSR_NUM_RSSI_CAT; i++) { + pMac->roam.configParam.RSSICat[CSR_NUM_RSSI_CAT - i - + 1] = + (int)bestApRssi - + pMac->roam.configParam.nSelect5GHzMargin - + (int)(i * catOffset); + } + } +} + +static void init_config_param(tpAniSirGlobal pMac) +{ + int i; + + pMac->roam.configParam.agingCount = CSR_AGING_COUNT; + pMac->roam.configParam.channelBondingMode24GHz = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + pMac->roam.configParam.channelBondingMode5GHz = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + + pMac->roam.configParam.phyMode = eCSR_DOT11_MODE_AUTO; + pMac->roam.configParam.eBand = BAND_ALL; + pMac->roam.configParam.uCfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + pMac->roam.configParam.FragmentationThreshold = + eCSR_DOT11_FRAG_THRESH_DEFAULT; + pMac->roam.configParam.HeartbeatThresh24 = 40; + pMac->roam.configParam.HeartbeatThresh50 = 40; + pMac->roam.configParam.Is11dSupportEnabled = false; + pMac->roam.configParam.Is11eSupportEnabled = true; + pMac->roam.configParam.Is11hSupportEnabled = true; + pMac->roam.configParam.RTSThreshold = 2346; + pMac->roam.configParam.shortSlotTime = true; + pMac->roam.configParam.WMMSupportMode = eCsrRoamWmmAuto; + pMac->roam.configParam.ProprietaryRatesEnabled = true; + for (i = 0; i < CSR_NUM_RSSI_CAT; i++) + pMac->roam.configParam.BssPreferValue[i] = i; + csr_assign_rssi_for_category(pMac, CSR_BEST_RSSI_VALUE, + CSR_DEFAULT_RSSI_DB_GAP); + pMac->roam.configParam.fSupplicantCountryCodeHasPriority = false; + pMac->roam.configParam.nActiveMaxChnTime = CSR_ACTIVE_MAX_CHANNEL_TIME; + pMac->roam.configParam.nActiveMinChnTime = CSR_ACTIVE_MIN_CHANNEL_TIME; + pMac->roam.configParam.nPassiveMaxChnTime = + CSR_PASSIVE_MAX_CHANNEL_TIME; + pMac->roam.configParam.nPassiveMinChnTime = + CSR_PASSIVE_MIN_CHANNEL_TIME; + pMac->roam.configParam.nActiveMaxChnTimeConc = + CSR_ACTIVE_MAX_CHANNEL_TIME_CONC; + pMac->roam.configParam.nActiveMinChnTimeConc = + CSR_ACTIVE_MIN_CHANNEL_TIME_CONC; + pMac->roam.configParam.nPassiveMaxChnTimeConc = + CSR_PASSIVE_MAX_CHANNEL_TIME_CONC; + pMac->roam.configParam.nPassiveMinChnTimeConc = + CSR_PASSIVE_MIN_CHANNEL_TIME_CONC; + pMac->roam.configParam.nRestTimeConc = CSR_REST_TIME_CONC; + pMac->roam.configParam.min_rest_time_conc = CSR_MIN_REST_TIME_CONC; + pMac->roam.configParam.idle_time_conc = CSR_IDLE_TIME_CONC; + pMac->roam.configParam.nTxPowerCap = CSR_MAX_TX_POWER; + pMac->roam.configParam.allow_tpc_from_ap = true; + pMac->roam.configParam.statsReqPeriodicity = + CSR_MIN_GLOBAL_STAT_QUERY_PERIOD; + pMac->roam.configParam.statsReqPeriodicityInPS = + CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS; + pMac->roam.configParam.neighborRoamConfig.nMaxNeighborRetries = 3; + pMac->roam.configParam.neighborRoamConfig.nNeighborLookupRssiThreshold = + 120; + pMac->roam.configParam.neighborRoamConfig.rssi_thresh_offset_5g = 0; + pMac->roam.configParam.neighborRoamConfig.nOpportunisticThresholdDiff = + 30; + pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff = 5; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime = 20; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime = 40; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod = + 200; + pMac->roam.configParam.neighborRoamConfig. + neighbor_scan_min_timer_period = 200; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + numChannels = 3; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[0] = 1; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[1] = 6; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[2] = 11; + pMac->roam.configParam.neighborRoamConfig.nNeighborResultsRefreshPeriod + = 20000; /* 20 seconds */ + pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod = 0; + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt = 10; + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt = 10; + pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight = 14; + pMac->roam.configParam.nVhtChannelWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1; + + pMac->roam.configParam.addTSWhenACMIsOff = 0; + pMac->roam.configParam.fScanTwice = false; + + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + pMac->roam.configParam.doBMPSWorkaround = 0; + + pMac->roam.configParam.nInitialDwellTime = 0; + pMac->roam.configParam.initial_scan_no_dfs_chnl = 0; + pMac->roam.configParam.csr_mawc_config.mawc_enabled = true; + pMac->roam.configParam.csr_mawc_config.mawc_roam_enabled = true; + pMac->roam.configParam.csr_mawc_config.mawc_roam_traffic_threshold = + MAWC_ROAM_TRAFFIC_THRESHOLD_DEFAULT; + pMac->roam.configParam.csr_mawc_config.mawc_roam_ap_rssi_threshold = + MAWC_ROAM_AP_RSSI_THRESHOLD_DEFAULT; + pMac->roam.configParam.csr_mawc_config.mawc_roam_rssi_high_adjust = + MAWC_ROAM_RSSI_HIGH_ADJUST_DEFAULT; + pMac->roam.configParam.csr_mawc_config.mawc_roam_rssi_low_adjust = + MAWC_ROAM_RSSI_LOW_ADJUST_DEFAULT; + + qdf_mem_zero(&pMac->roam.configParam.bss_score_params, + sizeof(struct sir_score_config)); + pMac->roam.configParam.bss_score_params.weight_cfg.rssi_weightage = + RSSI_WEIGHTAGE; + pMac->roam.configParam.bss_score_params.weight_cfg.ht_caps_weightage = + HT_CAPABILITY_WEIGHTAGE; + pMac->roam.configParam.bss_score_params.weight_cfg.vht_caps_weightage = + VHT_CAP_WEIGHTAGE; + pMac->roam.configParam.bss_score_params. + weight_cfg.chan_width_weightage = CHAN_WIDTH_WEIGHTAGE; + pMac->roam.configParam.bss_score_params. + weight_cfg.chan_band_weightage = CHAN_BAND_WEIGHTAGE; + pMac->roam.configParam.bss_score_params.weight_cfg.nss_weightage = + NSS_WEIGHTAGE; + pMac->roam.configParam.bss_score_params.weight_cfg. + beamforming_cap_weightage = BEAMFORMING_CAP_WEIGHTAGE; + pMac->roam.configParam.bss_score_params.weight_cfg.pcl_weightage = + PCL_WEIGHT; + pMac->roam.configParam.bss_score_params.weight_cfg. + channel_congestion_weightage = CHANNEL_CONGESTION_WEIGHTAGE; +} + +enum band_info csr_get_current_band(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.bandCapability; +} + +/* This function flushes the roam scan cache */ +QDF_STATUS csr_flush_cfg_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + /* Free up the memory first (if required) */ + if (NULL != pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0; + } + return status; +} + +/* + * This function flushes the roam scan cache and creates fresh cache + * based on the input channel list + */ +QDF_STATUS csr_create_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + const uint8_t *pChannelList, + const uint8_t numChannels) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = numChannels; + + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = + qdf_mem_malloc(pNeighborRoamInfo->cfgParams.channelInfo. + numOfChannels); + + if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + sme_err("Memory Allocation for CFG Channel List failed"); + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0; + return QDF_STATUS_E_NOMEM; + } + + /* Update the roam global structure */ + qdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList, + pChannelList, + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels); + return status; +} + + +#ifdef FEATURE_WLAN_ESE +/** + * csr_create_roam_scan_channel_list() - create roam scan channel list + * @pMac: Global mac pointer + * @sessionId: session id + * @pChannelList: pointer to channel list + * @numChannels: number of channels + * @eBand: 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 csr_create_roam_scan_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels, + const enum band_info eBand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + tpCsrNeighborRoamControlInfo pNeighborRoamInfo + = &pMac->roam.neighborRoamInfo[sessionId]; + uint8_t outNumChannels = 0; + uint8_t inNumChannels = numChannels; + uint8_t *inPtr = pChannelList; + uint8_t i = 0; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t tmpChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t mergedOutputNumOfChannels = 0; + + tpCsrChannelInfo currChannelListInfo + = &pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo; + /* + * 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 (pMac->scan.occupiedChannels[sessionId].numChannels) { + csr_neighbor_roam_merge_channel_lists(pMac, &pMac->scan. + occupiedChannels[sessionId]. + channelList[0], pMac->scan. + occupiedChannels[sessionId]. + numChannels, inPtr, + inNumChannels, + &mergedOutputNumOfChannels); + inNumChannels = mergedOutputNumOfChannels; + } + if (BAND_2G == eBand) { + for (i = 0; i < inNumChannels; i++) { + if (WLAN_REG_IS_24GHZ_CH(inPtr[i]) + && csr_roam_is_channel_valid(pMac, inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else if (BAND_5G == eBand) { + for (i = 0; i < inNumChannels; i++) { + /* Add 5G Non-DFS channel */ + if (WLAN_REG_IS_5GHZ_CH(inPtr[i]) && + csr_roam_is_channel_valid(pMac, inPtr[i]) && + !wlan_reg_is_dfs_ch(pMac->pdev, inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else if (BAND_ALL == eBand) { + for (i = 0; i < inNumChannels; i++) { + if (csr_roam_is_channel_valid(pMac, inPtr[i]) && + !wlan_reg_is_dfs_ch(pMac->pdev, inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "Invalid band, No operation carried out (Band %d)", + eBand); + return QDF_STATUS_E_INVAL; + } + /* + * 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_ALL == eBand) && CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac)) { + csr_neighbor_roam_channels_filter_by_current_band(pMac, + sessionId, + ChannelList, + outNumChannels, + tmpChannelList, + &outNumChannels); + qdf_mem_copy(ChannelList, tmpChannelList, outNumChannels); + } + /* Prepare final roam scan channel list */ + if (outNumChannels) { + /* Clear the channel list first */ + if (NULL != currChannelListInfo->ChannelList) { + qdf_mem_free(currChannelListInfo->ChannelList); + currChannelListInfo->ChannelList = NULL; + currChannelListInfo->numOfChannels = 0; + } + currChannelListInfo->ChannelList + = qdf_mem_malloc(outNumChannels * sizeof(uint8_t)); + if (NULL == currChannelListInfo->ChannelList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "Failed to allocate memory for roam scan channel list"); + currChannelListInfo->numOfChannels = 0; + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(currChannelListInfo->ChannelList, + ChannelList, outNumChannels); + } + return status; +} + +/** + * 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(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + return mac_ctx->roam.neighborRoamInfo[session_id].isESEAssoc; +} + + +/** + * csr_roam_is_ese_ini_feature_enabled() - is ese feature enabled + * @mac_ctx: Global MAC context + * + * Return: true if ese feature is enabled; false otherwise + */ +bool csr_roam_is_ese_ini_feature_enabled(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.isEseIniFeatureEnabled; +} + +/** + * csr_tsm_stats_rsp_processor() - tsm stats response processor + * @pMac: Global MAC context + * @pMsg: Message pointer + * + * Return: None + */ +static void csr_tsm_stats_rsp_processor(tpAniSirGlobal pMac, void *pMsg) +{ + tAniGetTsmStatsRsp *pTsmStatsRsp = (tAniGetTsmStatsRsp *) pMsg; + + if (NULL != 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 (NULL != reqBkp) { + if (NULL != reqBkp->tsmStatsCallback) { + ((tCsrTsmStatsCallback) + (reqBkp->tsmStatsCallback))(pTsmStatsRsp-> + tsmMetrics, + pTsmStatsRsp-> + staId, + reqBkp-> + pDevContext); + reqBkp->tsmStatsCallback = NULL; + } + qdf_mem_free(reqBkp); + pTsmStatsRsp->tsmStatsReq = NULL; + } else { + if (NULL != 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 + * @pMac: Global MAC context + * @pSession: Session pointer + * + * Return: None + */ +static void csr_send_ese_adjacent_ap_rep_ind(tpAniSirGlobal pMac, + struct csr_roam_session *pSession) +{ + uint32_t roamTS2 = 0; + struct csr_roam_info roamInfo; + tpPESession pSessionEntry = NULL; + uint8_t sessionId = CSR_SESSION_ID_INVALID; + + if (NULL == pSession) { + sme_err("pSession is NULL"); + return; + } + + roamTS2 = qdf_mc_timer_get_system_time(); + roamInfo.tsmRoamDelay = roamTS2 - pSession->roamTS1; + sme_debug("Bssid(" MAC_ADDRESS_STR ") Roaming Delay(%u ms)", + MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes), + roamInfo.tsmRoamDelay); + + pSessionEntry = pe_find_session_by_bssid(pMac, + pSession->connectedProfile.bssid.bytes, + &sessionId); + if (NULL == pSessionEntry) { + sme_err("session %d not found", sessionId); + return; + } + + pSessionEntry->eseContext.tsm.tsmMetrics.RoamingDly + = roamInfo.tsmRoamDelay; + + csr_roam_call_callback(pMac, pSession->sessionId, &roamInfo, + 0, eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, 0); +} + +/** + * csr_get_tsm_stats() - get tsm stats + * @pMac: 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(tpAniSirGlobal pMac, + tCsrTsmStatsCallback callback, + uint8_t staId, + 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) { + sme_err( + "csr_get_tsm_stats: failed to allocate mem for req"); + 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->staId = staId; + 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("csr_get_tsm_stats: failed to send down the rssi req"); + /* pMsg is freed by cds_send_mb_message_to_mac */ + status = QDF_STATUS_E_FAILURE; + } + return status; +} + + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * csr_fetch_ch_lst_from_received_list() - fetch channel list from received list + * and update req msg + * parameters + * @mac_ctx: global mac ctx + * @roam_info: roam info struct + * @curr_ch_lst_info: current channel list info + * @req_buf: out param, roam offload scan request packet + * + * Return: void + */ +static void +csr_fetch_ch_lst_from_received_list(tpAniSirGlobal mac_ctx, + tpCsrNeighborRoamControlInfo roam_info, + tpCsrChannelInfo curr_ch_lst_info, + tSirRoamOffloadScanReq *req_buf) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = NULL; + 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); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return; + } + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + if (curr_ch_lst_info->numOfChannels == 0) + return; + + ch_lst = curr_ch_lst_info->ChannelList; + for (i = 0; i < curr_ch_lst_info->numOfChannels; i++) { + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (wlan_reg_is_dfs_ch(mac_ctx->pdev, *ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam.sta_roam_policy. + skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + ("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + ch_lst++; + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC; +} +#endif + +/** + * csr_set_cckm_ie() - set CCKM IE + * @pMac: Global MAC context + * @sessionId: session identifier + * @pCckmIe: Pointer to input CCKM IE data + * @ccKmIeLen: Length of @pCckmIe + * + * This function stores the CCKM IE passed by the supplicant + * in a place holder data structure and this IE will be packed inside + * reassociation request + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS csr_set_cckm_ie(tpAniSirGlobal pMac, const uint8_t sessionId, + const uint8_t *pCckmIe, const uint8_t ccKmIeLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(pSession->suppCckmIeInfo.cckmIe, pCckmIe, ccKmIeLen); + pSession->suppCckmIeInfo.cckmIeLen = ccKmIeLen; + return status; +} + +/** + * csr_roam_read_tsf() - read TSF + * @pMac: Global MAC context + * @sessionId: session identifier + * @pTimestamp: output TSF timestamp + * + * 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: QDF_STATUS enumeration + */ +QDF_STATUS csr_roam_read_tsf(tpAniSirGlobal pMac, uint8_t *pTimestamp, + uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrNeighborRoamBSSInfo handoffNode = {{0} }; + uint64_t timer_diff = 0; + uint32_t timeStamp[2]; + tpSirBssDescription pBssDescription = NULL; + + csr_neighbor_roam_get_handoff_ap_info(pMac, &handoffNode, sessionId); + if (!handoffNode.pBssDescription) { + sme_err("Invalid BSS Description"); + return QDF_STATUS_E_INVAL; + } + pBssDescription = handoffNode.pBssDescription; + /* Get the time diff in nano seconds */ + timer_diff = (qdf_get_monotonic_boottime_ns() - + pBssDescription->scansystimensec); + /* Convert msec to micro sec timer */ + timer_diff = do_div(timer_diff, SYSTEM_TIME_NSEC_TO_USEC); + timeStamp[0] = pBssDescription->timeStamp[0]; + timeStamp[1] = pBssDescription->timeStamp[1]; + update_cckmtsf(&(timeStamp[0]), &(timeStamp[1]), &timer_diff); + qdf_mem_copy(pTimestamp, (void *)&timeStamp[0], sizeof(uint32_t) * 2); + return status; +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * csr_roam_is_roam_offload_scan_enabled() - is roam offload enabled + * @mac_ctx: Global MAC context + * + * Returns whether firmware based background scan is currently enabled or not. + * + * Return: true if roam offload scan enabled; false otherwise + */ +bool csr_roam_is_roam_offload_scan_enabled(tpAniSirGlobal mac_ctx) +{ + return mac_ctx->roam.configParam.isRoamOffloadScanEnabled; +} + +QDF_STATUS csr_set_band(tHalHandle hHal, uint8_t sessionId, + enum band_info eBand) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (CSR_IS_PHY_MODE_A_ONLY(pMac) && (eBand == BAND_2G)) { + /* DOT11 mode configured to 11a only and received + * request to change the band to 2.4 GHz + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "failed to set band cfg80211 = %u, band = %u", + pMac->roam.configParam.uCfgDot11Mode, eBand); + return QDF_STATUS_E_INVAL; + } + if ((CSR_IS_PHY_MODE_B_ONLY(pMac) || + CSR_IS_PHY_MODE_G_ONLY(pMac)) && (eBand == BAND_5G)) { + /* DOT11 mode configured to 11b/11g only and received + * request to change the band to 5 GHz + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "failed to set band dot11mode = %u, band = %u", + pMac->roam.configParam.uCfgDot11Mode, eBand); + return QDF_STATUS_E_INVAL; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Band changed to %u (0 - ALL, 1 - 2.4 GHZ, 2 - 5GHZ)", eBand); + pMac->roam.configParam.eBand = eBand; + pMac->roam.configParam.bandCapability = eBand; + + status = csr_get_channel_and_power_list(pMac); + if (QDF_STATUS_SUCCESS == status) + csr_apply_channel_and_power_list(pMac); + return status; +} + +/* 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_11AX +/** + * csr_update_he_config_param() - Update MAC context with HE config param + * @mac_ctx: pointer to MAC context + * @param: pointer to CSR config params + * + * Return: None + */ +static void csr_update_he_config_param(tpAniSirGlobal mac_ctx, + tCsrConfigParam *param) +{ + mac_ctx->roam.configParam.enable_ul_ofdma = param->enable_ul_ofdma; + mac_ctx->roam.configParam.enable_ul_mimo = param->enable_ul_mimo; +} + +/** + * csr_get_he_config_param() - Get HE config param from MAC context + * @param: pointer to CSR config params + * @mac_ctx: pointer to MAC context + * + * Return: None + */ +static void csr_get_he_config_param(tCsrConfigParam *param, + tpAniSirGlobal mac_ctx) +{ + param->enable_ul_ofdma = mac_ctx->roam.configParam.enable_ul_ofdma; + param->enable_ul_mimo = mac_ctx->roam.configParam.enable_ul_mimo; +} + + +/** + * csr_join_req_copy_he_cap() - Copy HE cap into CSR Join Req + * @csr_join_req: pointer to CSR Join Req + * @session: pointer to CSR session + * + * Return: None + */ +static void csr_join_req_copy_he_cap(tSirSmeJoinReq *csr_join_req, + struct csr_roam_session *session) +{ + qdf_mem_copy(&csr_join_req->he_config, &session->he_config, + sizeof(session->he_config)); +} + +/** + * csr_start_bss_copy_he_cap() - Copy HE cap into CSR Join Req + * @req: pointer to START BSS Req + * @session: pointer to CSR session + * + * Return: None + */ +static void csr_start_bss_copy_he_cap(tSirSmeStartBssReq *req, + struct csr_roam_session *session) +{ + qdf_mem_copy(&req->he_config, &session->he_config, + sizeof(session->he_config)); +} + +void csr_update_session_he_cap(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session) +{ + mac_handle_t mac_hdl = MAC_HANDLE(mac_ctx); + uint32_t value = 0; + tDot11fIEhe_cap *he_cap = &session->he_config; + he_cap->present = true; + + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_CONTROL, &value); + he_cap->htc_he = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TWT_REQUESTOR, &value); + he_cap->twt_request = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TWT_RESPONDER, &value); + he_cap->twt_responder = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_FRAGMENTATION, &value); + he_cap->fragmentation = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MAX_FRAG_MSDU, &value); + he_cap->max_num_frag_msdu = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MIN_FRAG_SIZE, &value); + he_cap->min_frag_size = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TRIG_PAD, &value); + he_cap->trigger_frm_mac_pad = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MTID_AGGR, &value); + he_cap->multi_tid_aggr = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_LINK_ADAPTATION, &value); + he_cap->he_link_adaptation = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_ALL_ACK, &value); + he_cap->all_ack = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_UL_MU_RSP_SCHEDULING, &value); + he_cap->ul_mu_rsp_sched = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_BUFFER_STATUS_RPT, &value); + he_cap->a_bsr = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_BCAST_TWT, &value); + he_cap->broadcast_twt = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_BA_32BIT, &value); + he_cap->ba_32bit_bitmap = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MU_CASCADING, &value); + he_cap->mu_cascade = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MULTI_TID, &value); + he_cap->ack_enabled_multitid = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_DL_MU_BA, &value); + he_cap->dl_mu_ba = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_OMI, &value); + he_cap->omi_a_ctrl = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_OFDMA_RA, &value); + he_cap->ofdma_ra = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MAX_AMPDU_LEN, &value); + he_cap->max_ampdu_len = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_AMSDU_FRAG, &value); + he_cap->amsdu_frag = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_FLEX_TWT_SCHED, &value); + he_cap->flex_twt_sched = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_RX_CTRL, &value); + he_cap->rx_ctrl_frame = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_BSRP_AMPDU_AGGR, &value); + he_cap->bsrp_ampdu_aggr = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_QTP, &value); + he_cap->qtp = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_A_BQR, &value); + he_cap->a_bqr = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_SR_RESPONDER, &value); + he_cap->sr_responder = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_NDP_FEEDBACK_SUPP, &value); + he_cap->ndp_feedback_supp = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_OPS_SUPP, &value); + he_cap->ops_supp = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_AMSDU_IN_AMPDU, &value); + he_cap->amsdu_in_ampdu = value; + + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_DUAL_BAND, &value); + he_cap->dual_band = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_CHAN_WIDTH, &value); + he_cap->chan_width_0 = HE_CH_WIDTH_GET_BIT(value, 0); + he_cap->chan_width_1 = HE_CH_WIDTH_GET_BIT(value, 1); + he_cap->chan_width_2 = HE_CH_WIDTH_GET_BIT(value, 2); + he_cap->chan_width_3 = HE_CH_WIDTH_GET_BIT(value, 3); + he_cap->chan_width_4 = HE_CH_WIDTH_GET_BIT(value, 4); + he_cap->chan_width_5 = HE_CH_WIDTH_GET_BIT(value, 5); + he_cap->chan_width_6 = HE_CH_WIDTH_GET_BIT(value, 6); + + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_RX_PREAM_PUNC, &value); + he_cap->rx_pream_puncturing = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_CLASS_OF_DEVICE, &value); + he_cap->device_class = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_LDPC, &value); + he_cap->ldpc_coding = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_LTF_PPDU, &value); + he_cap->he_1x_ltf_800_gi_ppdu = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MIDAMBLE_RX_MAX_NSTS, &value); + he_cap->midamble_rx_max_nsts = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_LTF_NDP, &value); + he_cap->he_4x_ltf_3200_gi_ndp = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TX_STBC_LT80, &value); + he_cap->tx_stbc_lt_80mhz = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_RX_STBC_LT80, &value); + he_cap->rx_stbc_lt_80mhz = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_DOPPLER, &value); + he_cap->doppler = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_UL_MUMIMO, &value); + he_cap->ul_mu = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_DCM_TX, &value); + he_cap->dcm_enc_tx = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_DCM_RX, &value); + he_cap->dcm_enc_rx = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MU_PPDU, &value); + he_cap->ul_he_mu = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_SU_BEAMFORMEE, &value); + he_cap->su_beamformee = value; + if (he_cap->su_beamformee) { + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_BFEE_STS_LT80, &value); + he_cap->bfee_sts_lt_80 = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_BFEE_STS_GT80, &value); + he_cap->bfee_sts_gt_80 = value; + } else { + he_cap->bfee_sts_lt_80 = 0; + he_cap->bfee_sts_gt_80 = 0; + } + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_SU_BEAMFORMER, &value); + he_cap->su_beamformer = value; + if (he_cap->su_beamformer) { + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MU_BEAMFORMER, &value); + he_cap->mu_beamformer = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_NUM_SOUND_LT80, &value); + he_cap->num_sounding_lt_80 = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_NUM_SOUND_GT80, &value); + he_cap->num_sounding_gt_80 = value; + } else { + he_cap->mu_beamformer = 0; + he_cap->num_sounding_lt_80 = 0; + he_cap->num_sounding_gt_80 = 0; + } + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_SU_FEED_TONE16, &value); + he_cap->su_feedback_tone16 = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MU_FEED_TONE16, &value); + he_cap->mu_feedback_tone16 = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_CODEBOOK_SU, &value); + he_cap->codebook_su = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_CODEBOOK_MU, &value); + he_cap->codebook_mu = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_BFRM_FEED, &value); + he_cap->beamforming_feedback = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_ER_SU_PPDU, &value); + he_cap->he_er_su_ppdu = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_DL_PART_BW, &value); + he_cap->dl_mu_mimo_part_bw = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_PPET_PRESENT, &value); + he_cap->ppet_present = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_SRP, &value); + he_cap->srp = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_POWER_BOOST, &value); + he_cap->power_boost = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_4x_LTF_GI, &value); + he_cap->he_ltf_800_gi_4x = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MAX_NC, &value); + he_cap->max_nc = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TX_STBC_GT80, &value); + he_cap->tx_stbc_gt_80mhz = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_RX_STBC_GT80, &value); + he_cap->rx_stbc_gt_80mhz = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_ER_4x_LTF_GI, &value); + he_cap->er_he_ltf_800_gi_4x = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_PPDU_20_IN_40MHZ_2G, &value); + he_cap->he_ppdu_20_in_40Mhz_2G = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_PPDU_20_IN_160_80P80MHZ, &value); + he_cap->he_ppdu_20_in_160_80p80Mhz = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_PPDU_80_IN_160_80P80MHZ, &value); + he_cap->he_ppdu_80_in_160_80p80Mhz = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_ER_1X_HE_LTF_GI, &value); + he_cap->er_1x_he_ltf_gi = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_MIDAMBLE_RX_1X_HE_LTF, &value); + he_cap->midamble_rx_1x_he_ltf = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_RX_MCS_MAP_LT_80, &value); + he_cap->rx_he_mcs_map_lt_80 = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TX_MCS_MAP_LT_80, &value); + he_cap->tx_he_mcs_map_lt_80 = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_RX_MCS_MAP_160, &value); + *((uint16_t *)he_cap->rx_he_mcs_map_160) = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TX_MCS_MAP_160, &value); + *((uint16_t *)he_cap->tx_he_mcs_map_160) = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_RX_MCS_MAP_80_80, &value); + *((uint16_t *)he_cap->rx_he_mcs_map_80_80) = value; + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_TX_MCS_MAP_80_80, &value); + *((uint16_t *)he_cap->tx_he_mcs_map_80_80) = value; + + if (he_cap->ppet_present) { + value = WNI_CFG_HE_PPET_LEN; + /* till now operating channel is not decided yet, use 5g cap */ + sme_cfg_get_str(mac_hdl, WNI_CFG_HE_PPET_5G, + he_cap->ppet.ppe_threshold.ppe_th, &value); + he_cap->ppet.ppe_threshold.num_ppe_th = + lim_truncate_ppet(he_cap->ppet.ppe_threshold.ppe_th, + value); + } else { + he_cap->ppet.ppe_threshold.num_ppe_th = 0; + } + sme_cfg_get_int(mac_hdl, WNI_CFG_HE_STA_OBSSPD, &value); + session->he_sta_obsspd = value; +} + +#else +static inline void csr_update_he_config_param(tpAniSirGlobal mac_ctx, + tCsrConfigParam *param) +{ +} + +static inline void csr_get_he_config_param(tCsrConfigParam *param, + tpAniSirGlobal mac_ctx) +{ +} + +static inline void csr_join_req_copy_he_cap(tSirSmeJoinReq *csr_join_req, + struct csr_roam_session *session) +{ +} + +static inline void csr_start_bss_copy_he_cap(tSirSmeStartBssReq *req, + struct csr_roam_session *session) +{ +} + +#endif + +/** + * csr_set_11k_offload_config_param() - Update 11k neighbor report config + * + * @csr_config: pointer to csr_config in MAC context + * @pParam: pointer to config params from HDD + * + * Return: none + */ +static +void csr_set_11k_offload_config_param(struct csr_config *csr_config, + tCsrConfigParam *param) +{ + csr_config->offload_11k_enable_bitmask = + param->offload_11k_enable_bitmask; + csr_config->neighbor_report_offload.params_bitmask = + param->neighbor_report_offload.params_bitmask; + csr_config->neighbor_report_offload.time_offset = + param->neighbor_report_offload.time_offset; + csr_config->neighbor_report_offload.low_rssi_offset = + param->neighbor_report_offload.low_rssi_offset; + csr_config->neighbor_report_offload.bmiss_count_trigger = + param->neighbor_report_offload.bmiss_count_trigger; + csr_config->neighbor_report_offload.per_threshold_offset = + param->neighbor_report_offload.per_threshold_offset; + csr_config->neighbor_report_offload. + neighbor_report_cache_timeout = + param->neighbor_report_offload. + neighbor_report_cache_timeout; + csr_config->neighbor_report_offload. + max_neighbor_report_req_cap = + param->neighbor_report_offload. + max_neighbor_report_req_cap; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + +/** + * csr_get_roam_preauth_config_param() - Get the roam preauth params + * + * @csr_config: pointer to csr_config in MAC context + * @pParam: pointer to config params from HDD + * + * Return: none + */ + +static void csr_get_roam_preauth_config_param(tCsrConfigParam *pparam, + struct csr_config *cfg_params) +{ + pparam->roam_preauth_no_ack_timeout = + cfg_params->roam_preauth_no_ack_timeout; + pparam->roam_preauth_retry_count = cfg_params->roam_preauth_retry_count; +} + +/** + * csr_change_default_roam_preauth_params() - Update roam preauth params + * + * @pmac: pointer to MAC context + * @pParam: pointer to config params from HDD + * + * Return: none + */ +static void csr_change_default_roam_preauth_params(tpAniSirGlobal pmac, + tCsrConfigParam *pparam) +{ + pmac->roam.configParam.roam_preauth_retry_count = + pparam->roam_preauth_retry_count; + pmac->roam.configParam.roam_preauth_no_ack_timeout = + pparam->roam_preauth_no_ack_timeout; +} +#else +static void csr_change_default_roam_preauth_params(tpAniSirGlobal pmac, + tCsrConfigParam *pparam) +{ +} + +static void csr_get_roam_preauth_config_param(tCsrConfigParam *pparam, + struct csr_config *cfg_params) +{ +} +#endif + +QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, + tCsrConfigParam *pParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i; + + if (pParam) { + pMac->roam.configParam.pkt_err_disconn_th = + pParam->pkt_err_disconn_th; + pMac->roam.configParam.is_force_1x1_enable = + pParam->is_force_1x1_enable; + pMac->roam.configParam.WMMSupportMode = pParam->WMMSupportMode; + cfg_set_int(pMac, WNI_CFG_WME_ENABLED, + (pParam->WMMSupportMode == eCsrRoamWmmNoQos) ? 0 : 1); + pMac->roam.configParam.Is11eSupportEnabled = + pParam->Is11eSupportEnabled; + pMac->roam.configParam.FragmentationThreshold = + pParam->FragmentationThreshold; + pMac->roam.configParam.Is11dSupportEnabled = + pParam->Is11dSupportEnabled; + pMac->roam.configParam.Is11hSupportEnabled = + pParam->Is11hSupportEnabled; + + pMac->roam.configParam.fenableMCCMode = pParam->fEnableMCCMode; + pMac->roam.configParam.mcc_rts_cts_prot_enable = + pParam->mcc_rts_cts_prot_enable; + pMac->roam.configParam.mcc_bcast_prob_resp_enable = + pParam->mcc_bcast_prob_resp_enable; + pMac->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); + pMac->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); + pMac->roam.configParam.channelBondingMode5GHz = + csr_convert_cb_ini_value_to_phy_cb_state(pParam-> + channelBondingMode5GHz); + pMac->roam.configParam.RTSThreshold = pParam->RTSThreshold; + pMac->roam.configParam.phyMode = pParam->phyMode; + pMac->roam.configParam.shortSlotTime = pParam->shortSlotTime; + pMac->roam.configParam.HeartbeatThresh24 = + pParam->HeartbeatThresh24; + pMac->roam.configParam.HeartbeatThresh50 = + pParam->HeartbeatThresh50; + pMac->roam.configParam.ProprietaryRatesEnabled = + pParam->ProprietaryRatesEnabled; + pMac->roam.configParam.AdHocChannel24 = pParam->AdHocChannel24; + pMac->roam.configParam.AdHocChannel5G = pParam->AdHocChannel5G; + pMac->roam.configParam.bandCapability = pParam->bandCapability; + pMac->roam.configParam.wep_tkip_in_he = pParam->wep_tkip_in_he; + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop = + pParam->neighborRoamConfig.delay_before_vdev_stop; + + /* if HDD passed down non zero values then only update, */ + /* otherwise keep using the defaults */ + if (pParam->initial_scan_no_dfs_chnl) { + pMac->roam.configParam.initial_scan_no_dfs_chnl = + pParam->initial_scan_no_dfs_chnl; + } + if (pParam->nInitialDwellTime) { + pMac->roam.configParam.nInitialDwellTime = + pParam->nInitialDwellTime; + } + if (pParam->nActiveMaxChnTime) { + pMac->roam.configParam.nActiveMaxChnTime = + pParam->nActiveMaxChnTime; + cfg_set_int(pMac, WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + pParam->nActiveMaxChnTime); + } + if (pParam->nActiveMinChnTime) { + pMac->roam.configParam.nActiveMinChnTime = + pParam->nActiveMinChnTime; + cfg_set_int(pMac, WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + pParam->nActiveMinChnTime); + } + if (pParam->nPassiveMaxChnTime) { + pMac->roam.configParam.nPassiveMaxChnTime = + pParam->nPassiveMaxChnTime; + cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pParam->nPassiveMaxChnTime); + } + if (pParam->nPassiveMinChnTime) { + pMac->roam.configParam.nPassiveMinChnTime = + pParam->nPassiveMinChnTime; + cfg_set_int(pMac, WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + pParam->nPassiveMinChnTime); + } + if (pParam->nActiveMaxChnTimeConc) { + pMac->roam.configParam.nActiveMaxChnTimeConc = + pParam->nActiveMaxChnTimeConc; + } + if (pParam->nActiveMinChnTimeConc) { + pMac->roam.configParam.nActiveMinChnTimeConc = + pParam->nActiveMinChnTimeConc; + } + if (pParam->nPassiveMaxChnTimeConc) { + pMac->roam.configParam.nPassiveMaxChnTimeConc = + pParam->nPassiveMaxChnTimeConc; + } + if (pParam->nPassiveMinChnTimeConc) { + pMac->roam.configParam.nPassiveMinChnTimeConc = + pParam->nPassiveMinChnTimeConc; + } + pMac->roam.configParam.nRestTimeConc = pParam->nRestTimeConc; + pMac->roam.configParam.min_rest_time_conc = + pParam->min_rest_time_conc; + pMac->roam.configParam.idle_time_conc = pParam->idle_time_conc; + + pMac->roam.configParam.eBand = pParam->eBand; + pMac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(NULL, + pMac->roam.configParam. + phyMode, + pMac->roam.configParam. + ProprietaryRatesEnabled); + /* if HDD passed down non zero values for age params, + * then only update, otherwise keep using the defaults + */ + if (pParam->nScanResultAgeCount) { + pMac->roam.configParam.agingCount = + pParam->nScanResultAgeCount; + } + if (pParam->obss_width_interval) { + pMac->roam.configParam.obss_width_interval = + pParam->obss_width_interval; + cfg_set_int(pMac, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + pParam->obss_width_interval); + } + if (pParam->obss_active_dwelltime) { + pMac->roam.configParam.obss_active_dwelltime = + pParam->obss_active_dwelltime; + cfg_set_int(pMac, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + pParam->obss_active_dwelltime); + } + if (pParam->obss_passive_dwelltime) { + pMac->roam.configParam.obss_passive_dwelltime = + pParam->obss_passive_dwelltime; + cfg_set_int(pMac, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + pParam->obss_passive_dwelltime); + } + + pMac->first_scan_bucket_threshold = + pParam->first_scan_bucket_threshold; + csr_assign_rssi_for_category(pMac, + pMac->first_scan_bucket_threshold, + pParam->bCatRssiOffset); + pMac->roam.configParam.fSupplicantCountryCodeHasPriority = + pParam->fSupplicantCountryCodeHasPriority; + pMac->roam.configParam.vccRssiThreshold = + pParam->vccRssiThreshold; + pMac->roam.configParam.vccUlMacLossThreshold = + pParam->vccUlMacLossThreshold; + pMac->roam.configParam.statsReqPeriodicity = + pParam->statsReqPeriodicity; + pMac->roam.configParam.statsReqPeriodicityInPS = + pParam->statsReqPeriodicityInPS; + /* Assign this before calling csr_init11d_info */ + pMac->roam.configParam.nTxPowerCap = pParam->nTxPowerCap; + pMac->roam.configParam.allow_tpc_from_ap = + pParam->allow_tpc_from_ap; + if (wlan_reg_11d_enabled_on_host(pMac->psoc)) + status = csr_init11d_info(pMac, &pParam->Csr11dinfo); + else + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; + + /* Initialize the power + channel information if 11h is + * enabled. If 11d is enabled this information has already + * been initialized + */ + if (csr_is11h_supported(pMac) && + !wlan_reg_11d_enabled_on_host(pMac->psoc)) + csr_init_channel_power_list(pMac, &pParam->Csr11dinfo); + + pMac->roam.configParam.isFastTransitionEnabled = + pParam->isFastTransitionEnabled; + pMac->roam.configParam.RoamRssiDiff = pParam->RoamRssiDiff; + pMac->roam.configParam.rssi_abs_thresh = + pParam->rssi_abs_thresh; + pMac->roam.configParam.nRoamPrefer5GHz = + pParam->nRoamPrefer5GHz; + pMac->roam.configParam.nRoamIntraBand = pParam->nRoamIntraBand; + pMac->roam.configParam.isWESModeEnabled = + pParam->isWESModeEnabled; + pMac->roam.configParam.nProbes = pParam->nProbes; + pMac->roam.configParam.nRoamScanHomeAwayTime = + pParam->nRoamScanHomeAwayTime; + pMac->roam.configParam.isRoamOffloadScanEnabled = + pParam->isRoamOffloadScanEnabled; + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + pParam->bFastRoamInConIniFeatureEnabled; + pMac->roam.configParam.isFastRoamIniFeatureEnabled = + pParam->isFastRoamIniFeatureEnabled; + qdf_mem_copy(&pMac->roam.configParam.csr_mawc_config, + &pParam->csr_mawc_config, + sizeof(pParam->csr_mawc_config)); +#ifdef FEATURE_WLAN_ESE + pMac->roam.configParam.isEseIniFeatureEnabled = + pParam->isEseIniFeatureEnabled; +#endif + qdf_mem_copy(&pMac->roam.configParam.neighborRoamConfig, + &pParam->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + sme_debug("nNeighborScanTimerPerioid: %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanTimerPeriod); + sme_debug("neighbor_scan_min_timer_period: %d", + pMac->roam.configParam.neighborRoamConfig. + neighbor_scan_min_timer_period); + sme_debug("nNeighborLookupRssiThreshold: %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold); + sme_debug("rssi_thresh_offset_5g: %d", + pMac->roam.configParam.neighborRoamConfig.rssi_thresh_offset_5g); + sme_debug("nOpportunisticThresholdDiff: %d", + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff); + sme_debug("nRoamRescanRssiDiff: %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamRescanRssiDiff); + sme_debug("nNeighborScanMinChanTime: %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime); + sme_debug("nNeighborScanMaxChanTime: %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMaxChanTime); + sme_debug("nMaxNeighborRetries: %d", + pMac->roam.configParam.neighborRoamConfig. + nMaxNeighborRetries); + sme_debug("nNeighborResultsRefreshPeriod: %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod); + sme_debug("nEmptyScanRefreshPeriod: %d", + pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod); + { + int i; + + sme_debug("Num of Channels in CFG Channel List: %d", + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + for (i = 0; + i < + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels; i++) { + sme_debug("%d ", + pMac->roam.configParam. + neighborRoamConfig.neighborScanChanList. + channelList[i]); + } + } + sme_debug("nRoamBmissFirstBcnt: %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFirstBcnt); + sme_debug("nRoamBmissFinalBcnt: %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFinalBcnt); + sme_debug("nRoamBeaconRssiWeight: %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBeaconRssiWeight); + pMac->roam.configParam.addTSWhenACMIsOff = + pParam->addTSWhenACMIsOff; + pMac->scan.fEnableBypass11d = pParam->fEnableBypass11d; + pMac->scan.fEnableDFSChnlScan = pParam->fEnableDFSChnlScan; + pMac->scan.scanResultCfgAgingTime = pParam->scanCfgAgingTime; + pMac->roam.configParam.fScanTwice = pParam->fScanTwice; + pMac->scan.fFirstScanOnly2GChnl = pParam->fFirstScanOnly2GChnl; + pMac->scan.max_scan_count = pParam->max_scan_count; + /* This parameter is not available in cfg and not passed from + * upper layers. Instead it is initialized here This parametere + * is used in concurrency to determine if there are concurrent + * active sessions. Is used as a temporary fix to disconnect + * all active sessions when BMPS enabled so the active session + * if Infra STA will automatically connect back and resume BMPS + * since resume BMPS is not working when moving from concurrent + * to single session + */ + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + pMac->roam.configParam.doBMPSWorkaround = 0; + + pMac->roam.configParam.nVhtChannelWidth = + pParam->nVhtChannelWidth; + pMac->roam.configParam.enable_subfee_vendor_vhtie = + pParam->enable_subfee_vendor_vhtie; + pMac->roam.configParam.enable_txbf_sap_mode = + pParam->enable_txbf_sap_mode; + pMac->roam.configParam.enable_vht20_mcs9 = + pParam->enable_vht20_mcs9; + pMac->roam.configParam.enable2x2 = pParam->enable2x2; + pMac->roam.configParam.enableVhtFor24GHz = + pParam->enableVhtFor24GHz; + pMac->roam.configParam.enableVhtpAid = pParam->enableVhtpAid; + pMac->roam.configParam.enableVhtGid = pParam->enableVhtGid; + pMac->roam.configParam.enableAmpduPs = pParam->enableAmpduPs; + pMac->roam.configParam.enableHtSmps = pParam->enableHtSmps; + pMac->roam.configParam.htSmps = pParam->htSmps; + pMac->roam.configParam.send_smps_action = + pParam->send_smps_action; + pMac->roam.configParam.tx_ldpc_enable = pParam->enable_tx_ldpc; + pMac->roam.configParam.rx_ldpc_enable = pParam->enable_rx_ldpc; + pMac->roam.configParam.disable_high_ht_mcs_2x2 = + pParam->disable_high_ht_mcs_2x2; + pMac->roam.configParam.ignore_peer_erp_info = + pParam->ignore_peer_erp_info; + pMac->roam.configParam.max_amsdu_num = + pParam->max_amsdu_num; + pMac->roam.configParam.nSelect5GHzMargin = + pParam->nSelect5GHzMargin; + pMac->roam.configParam.ho_delay_for_rx = + pParam->ho_delay_for_rx; + csr_change_default_roam_preauth_params(pMac, pParam); + pMac->roam.configParam.min_delay_btw_roam_scans = + pParam->min_delay_btw_roam_scans; + pMac->roam.configParam.roam_trigger_reason_bitmask = + pParam->roam_trigger_reason_bitmask; + pMac->roam.configParam.roaming_scan_policy = + pParam->roaming_scan_policy; + pMac->roam.configParam.isCoalesingInIBSSAllowed = + pParam->isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pMac->roam.configParam.cc_switch_mode = pParam->cc_switch_mode; +#endif + pMac->roam.configParam.allowDFSChannelRoam = + pParam->allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pMac->roam.configParam.isRoamOffloadEnabled = + pParam->isRoamOffloadEnabled; +#endif + pMac->roam.configParam.obssEnabled = pParam->obssEnabled; + pMac->roam.configParam.vendor_vht_sap = + pParam->vendor_vht_sap; + pMac->roam.configParam.conc_custom_rule1 = + pParam->conc_custom_rule1; + pMac->roam.configParam.conc_custom_rule2 = + pParam->conc_custom_rule2; + pMac->roam.configParam.is_sta_connection_in_5gz_enabled = + pParam->is_sta_connection_in_5gz_enabled; + pMac->roam.configParam.send_deauth_before_con = + pParam->send_deauth_before_con; + + pMac->enable_dot11p = pParam->enable_dot11p; + pMac->roam.configParam.early_stop_scan_enable = + pParam->early_stop_scan_enable; + pMac->roam.configParam.early_stop_scan_min_threshold = + pParam->early_stop_scan_min_threshold; + pMac->roam.configParam.early_stop_scan_max_threshold = + pParam->early_stop_scan_max_threshold; + pMac->isCoalesingInIBSSAllowed = + pParam->isCoalesingInIBSSAllowed; + + pMac->roam.configParam.roam_params.dense_rssi_thresh_offset = + pParam->roam_dense_rssi_thresh_offset; + pMac->roam.configParam.roam_params.dense_min_aps_cnt = + pParam->roam_dense_min_aps; + pMac->roam.configParam.roam_params.traffic_threshold = + pParam->roam_dense_traffic_thresh; + + pMac->roam.configParam.roam_params.bg_scan_bad_rssi_thresh = + pParam->roam_bg_scan_bad_rssi_thresh; + pMac->roam.configParam.roam_params.bg_scan_client_bitmap = + pParam->roam_bg_scan_client_bitmap; + pMac->roam.configParam.roam_params. + roam_bad_rssi_thresh_offset_2g = + pParam->roam_bad_rssi_thresh_offset_2g; + + pMac->roam.configParam.enable_ftopen = + pParam->enable_ftopen; + pMac->roam.configParam.scan_adaptive_dwell_mode = + pParam->scan_adaptive_dwell_mode; + pMac->roam.configParam.scan_adaptive_dwell_mode_nc = + pParam->scan_adaptive_dwell_mode_nc; + pMac->roam.configParam.roamscan_adaptive_dwell_mode = + pParam->roamscan_adaptive_dwell_mode; + + pMac->roam.configParam.per_roam_config.enable = + pParam->per_roam_config.enable; + pMac->roam.configParam.per_roam_config.tx_high_rate_thresh = + pParam->per_roam_config.tx_high_rate_thresh; + pMac->roam.configParam.per_roam_config.rx_high_rate_thresh = + pParam->per_roam_config.rx_high_rate_thresh; + pMac->roam.configParam.per_roam_config.tx_low_rate_thresh = + pParam->per_roam_config.tx_low_rate_thresh; + pMac->roam.configParam.per_roam_config.rx_low_rate_thresh = + pParam->per_roam_config.rx_low_rate_thresh; + pMac->roam.configParam.per_roam_config.tx_rate_thresh_percnt = + pParam->per_roam_config.tx_rate_thresh_percnt; + pMac->roam.configParam.per_roam_config.rx_rate_thresh_percnt = + pParam->per_roam_config.rx_rate_thresh_percnt; + pMac->roam.configParam.per_roam_config.per_rest_time = + pParam->per_roam_config.per_rest_time; + pMac->roam.configParam.per_roam_config.tx_per_mon_time = + pParam->per_roam_config.tx_per_mon_time; + pMac->roam.configParam.per_roam_config.rx_per_mon_time = + pParam->per_roam_config.rx_per_mon_time; + pMac->roam.configParam.per_roam_config.min_candidate_rssi = + pParam->per_roam_config.min_candidate_rssi; + + pMac->fEnableDebugLog = pParam->fEnableDebugLog; + + /* update interface configuration */ + pMac->sme.max_intf_count = pParam->max_intf_count; + + pMac->enable5gEBT = pParam->enable5gEBT; + pMac->sme.enableSelfRecovery = pParam->enableSelfRecovery; + + pMac->f_sta_miracast_mcc_rest_time_val = + pParam->f_sta_miracast_mcc_rest_time_val; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + pMac->sap.sap_channel_avoidance = + pParam->sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + pMac->sap.acs_with_more_param = + pParam->acs_with_more_param; + + pMac->f_prefer_non_dfs_on_radar = + pParam->f_prefer_non_dfs_on_radar; + + pMac->sme.ps_global_info.ps_enabled = + pParam->is_ps_enabled; + pMac->sme.ps_global_info.auto_bmps_timer_val = + pParam->auto_bmps_timer_val; + pMac->roam.configParam.ignore_peer_ht_opmode = + pParam->ignore_peer_ht_opmode; + pMac->dual_mac_feature_disable = + pParam->dual_mac_feature_disable; + pMac->sta_sap_scc_on_dfs_chan = + pParam->sta_sap_scc_on_dfs_chan; + pMac->roam.configParam.early_stop_scan_enable = + pParam->early_stop_scan_enable; + pMac->roam.configParam.early_stop_scan_min_threshold = + pParam->early_stop_scan_min_threshold; + pMac->roam.configParam.early_stop_scan_max_threshold = + pParam->early_stop_scan_max_threshold; + pMac->roam.configParam.enable_edca_params = + pParam->enable_edca_params; + pMac->roam.configParam.edca_vo_cwmin = pParam->edca_vo_cwmin; + pMac->roam.configParam.edca_vi_cwmin = pParam->edca_vi_cwmin; + pMac->roam.configParam.edca_bk_cwmin = pParam->edca_bk_cwmin; + pMac->roam.configParam.edca_be_cwmin = pParam->edca_be_cwmin; + + pMac->roam.configParam.edca_vo_cwmax = pParam->edca_vo_cwmax; + pMac->roam.configParam.edca_vi_cwmax = pParam->edca_vi_cwmax; + pMac->roam.configParam.edca_bk_cwmax = pParam->edca_bk_cwmax; + pMac->roam.configParam.edca_be_cwmax = pParam->edca_be_cwmax; + + pMac->roam.configParam.edca_vo_aifs = pParam->edca_vo_aifs; + pMac->roam.configParam.edca_vi_aifs = pParam->edca_vi_aifs; + pMac->roam.configParam.edca_bk_aifs = pParam->edca_bk_aifs; + pMac->roam.configParam.edca_be_aifs = pParam->edca_be_aifs; + + pMac->roam.configParam.enable_fatal_event = + pParam->enable_fatal_event; + pMac->roam.configParam.sta_roam_policy.dfs_mode = + pParam->sta_roam_policy_params.dfs_mode; + pMac->roam.configParam.sta_roam_policy.skip_unsafe_channels = + pParam->sta_roam_policy_params.skip_unsafe_channels; + pMac->roam.configParam.sta_roam_policy.sap_operating_band = + pParam->sta_roam_policy_params.sap_operating_band; + + pMac->roam.configParam.tx_aggregation_size = + pParam->tx_aggregation_size; + pMac->roam.configParam.tx_aggregation_size_be = + pParam->tx_aggregation_size_be; + pMac->roam.configParam.tx_aggregation_size_bk = + pParam->tx_aggregation_size_bk; + pMac->roam.configParam.tx_aggregation_size_vi = + pParam->tx_aggregation_size_vi; + pMac->roam.configParam.tx_aggregation_size_vo = + pParam->tx_aggregation_size_vo; + pMac->roam.configParam.rx_aggregation_size = + pParam->rx_aggregation_size; + pMac->roam.configParam.tx_aggr_sw_retry_threshold_be = + pParam->tx_aggr_sw_retry_threshold_be; + pMac->roam.configParam.tx_aggr_sw_retry_threshold_bk = + pParam->tx_aggr_sw_retry_threshold_bk; + pMac->roam.configParam.tx_aggr_sw_retry_threshold_vi = + pParam->tx_aggr_sw_retry_threshold_vi; + pMac->roam.configParam.tx_aggr_sw_retry_threshold_vo = + pParam->tx_aggr_sw_retry_threshold_vo; + pMac->roam.configParam.tx_aggr_sw_retry_threshold = + pParam->tx_aggr_sw_retry_threshold; + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_be = + pParam->tx_non_aggr_sw_retry_threshold_be; + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_bk = + pParam->tx_non_aggr_sw_retry_threshold_bk; + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_vi = + pParam->tx_non_aggr_sw_retry_threshold_vi; + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_vo = + pParam->tx_non_aggr_sw_retry_threshold_vo; + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold = + pParam->tx_non_aggr_sw_retry_threshold; + pMac->roam.configParam.enable_bcast_probe_rsp = + pParam->enable_bcast_probe_rsp; + pMac->roam.configParam.is_fils_enabled = + pParam->is_fils_enabled; + pMac->roam.configParam.qcn_ie_support = + pParam->qcn_ie_support; + pMac->roam.configParam.fils_max_chan_guard_time = + pParam->fils_max_chan_guard_time; + pMac->roam.configParam.disallow_duration = + pParam->disallow_duration; + pMac->roam.configParam.rssi_channel_penalization = + pParam->rssi_channel_penalization; + pMac->roam.configParam.num_disallowed_aps = + pParam->num_disallowed_aps; + pMac->roam.configParam.wlm_latency_enable = + pParam->wlm_latency_enable; + pMac->roam.configParam.wlm_latency_level = + pParam->wlm_latency_level; + for (i = 0; i < CSR_NUM_WLM_LATENCY_LEVEL; i++) { + pMac->roam.configParam.wlm_latency_flags[i] = + pParam->wlm_latency_flags[i]; + } + pMac->roam.configParam.oce_feature_bitmap = + pParam->oce_feature_bitmap; + pMac->roam.configParam.roam_force_rssi_trigger = + pParam->roam_force_rssi_trigger; + + pMac->roam.configParam.mbo_thresholds. + mbo_candidate_rssi_thres = + pParam->mbo_thresholds.mbo_candidate_rssi_thres; + pMac->roam.configParam.mbo_thresholds. + mbo_current_rssi_thres = + pParam->mbo_thresholds.mbo_current_rssi_thres; + pMac->roam.configParam.mbo_thresholds. + mbo_current_rssi_mcc_thres = + pParam->mbo_thresholds.mbo_current_rssi_mcc_thres; + pMac->roam.configParam.mbo_thresholds. + mbo_candidate_rssi_btc_thres = + pParam->mbo_thresholds.mbo_candidate_rssi_btc_thres; + + qdf_mem_copy(&pMac->roam.configParam.bss_score_params, + &pParam->bss_score_params, + sizeof(struct sir_score_config)); + pMac->roam.configParam.btm_offload_config = + pParam->btm_offload_config; + pMac->roam.configParam.btm_solicited_timeout = + pParam->btm_solicited_timeout; + pMac->roam.configParam.btm_max_attempt_cnt = + pParam->btm_max_attempt_cnt; + pMac->roam.configParam.btm_sticky_time = + pParam->btm_sticky_time; + + pMac->roam.configParam.btm_validity_timer = + pParam->btm_validity_timer; + pMac->roam.configParam.btm_disassoc_timer_threshold = + pParam->btm_disassoc_timer_threshold; + pMac->roam.configParam.enable_bss_load_roam_trigger = + pParam->enable_bss_load_roam_trigger; + pMac->roam.configParam.bss_load_threshold = + pParam->bss_load_threshold; + pMac->roam.configParam.bss_load_sample_time = + pParam->bss_load_sample_time; + + csr_update_he_config_param(pMac, pParam); + csr_set_11k_offload_config_param(&pMac->roam.configParam, + pParam); + } + return status; +} + +/** + * csr_get_11k_offload_config_param() - Get 11k neighbor report config + * + * @csr_config: pointer to csr_config in MAC context + * @pParam: pointer to config params from HDD + * + * Return: none + */ +static +void csr_get_11k_offload_config_param(struct csr_config *csr_config, + tCsrConfigParam *param) +{ + param->offload_11k_enable_bitmask = + csr_config->offload_11k_enable_bitmask; + param->neighbor_report_offload.params_bitmask = + csr_config->neighbor_report_offload.params_bitmask; + param->neighbor_report_offload.time_offset = + csr_config->neighbor_report_offload.time_offset; + param->neighbor_report_offload.low_rssi_offset = + csr_config->neighbor_report_offload.low_rssi_offset; + param->neighbor_report_offload.bmiss_count_trigger = + csr_config->neighbor_report_offload.bmiss_count_trigger; + param->neighbor_report_offload.per_threshold_offset = + csr_config->neighbor_report_offload.per_threshold_offset; + param->neighbor_report_offload.neighbor_report_cache_timeout = + csr_config->neighbor_report_offload. + neighbor_report_cache_timeout; + param->neighbor_report_offload.max_neighbor_report_req_cap = + csr_config->neighbor_report_offload. + max_neighbor_report_req_cap; +} + +QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam) +{ + int i; + struct csr_config *cfg_params = &pMac->roam.configParam; + + if (!pParam) + return QDF_STATUS_E_INVAL; + + pParam->pkt_err_disconn_th = cfg_params->pkt_err_disconn_th; + pParam->is_force_1x1_enable = cfg_params->is_force_1x1_enable; + pParam->WMMSupportMode = cfg_params->WMMSupportMode; + pParam->Is11eSupportEnabled = cfg_params->Is11eSupportEnabled; + pParam->FragmentationThreshold = cfg_params->FragmentationThreshold; + pParam->Is11dSupportEnabled = cfg_params->Is11dSupportEnabled; + pParam->Is11hSupportEnabled = cfg_params->Is11hSupportEnabled; + 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->RTSThreshold = cfg_params->RTSThreshold; + pParam->phyMode = cfg_params->phyMode; + pParam->shortSlotTime = cfg_params->shortSlotTime; + pParam->HeartbeatThresh24 = cfg_params->HeartbeatThresh24; + pParam->HeartbeatThresh50 = cfg_params->HeartbeatThresh50; + pParam->ProprietaryRatesEnabled = cfg_params->ProprietaryRatesEnabled; + pParam->AdHocChannel24 = cfg_params->AdHocChannel24; + pParam->AdHocChannel5G = cfg_params->AdHocChannel5G; + pParam->bandCapability = cfg_params->bandCapability; + pParam->nActiveMaxChnTime = cfg_params->nActiveMaxChnTime; + pParam->nActiveMinChnTime = cfg_params->nActiveMinChnTime; + pParam->nPassiveMaxChnTime = cfg_params->nPassiveMaxChnTime; + pParam->nPassiveMinChnTime = cfg_params->nPassiveMinChnTime; + pParam->nActiveMaxChnTimeConc = cfg_params->nActiveMaxChnTimeConc; + pParam->nActiveMinChnTimeConc = cfg_params->nActiveMinChnTimeConc; + pParam->nPassiveMaxChnTimeConc = cfg_params->nPassiveMaxChnTimeConc; + pParam->nPassiveMinChnTimeConc = cfg_params->nPassiveMinChnTimeConc; + pParam->nRestTimeConc = cfg_params->nRestTimeConc; + pParam->min_rest_time_conc = cfg_params->min_rest_time_conc; + pParam->idle_time_conc = cfg_params->idle_time_conc; + pParam->eBand = cfg_params->eBand; + pParam->nScanResultAgeCount = cfg_params->agingCount; + pParam->bCatRssiOffset = cfg_params->bCatRssiOffset; + pParam->fSupplicantCountryCodeHasPriority = + cfg_params->fSupplicantCountryCodeHasPriority; + pParam->vccRssiThreshold = cfg_params->vccRssiThreshold; + pParam->vccUlMacLossThreshold = cfg_params->vccUlMacLossThreshold; + pParam->nTxPowerCap = cfg_params->nTxPowerCap; + pParam->allow_tpc_from_ap = cfg_params->allow_tpc_from_ap; + pParam->statsReqPeriodicity = cfg_params->statsReqPeriodicity; + pParam->statsReqPeriodicityInPS = cfg_params->statsReqPeriodicityInPS; + pParam->addTSWhenACMIsOff = cfg_params->addTSWhenACMIsOff; + pParam->fEnableBypass11d = pMac->scan.fEnableBypass11d; + pParam->fEnableDFSChnlScan = pMac->scan.fEnableDFSChnlScan; + pParam->fScanTwice = cfg_params->fScanTwice; + pParam->fFirstScanOnly2GChnl = pMac->scan.fFirstScanOnly2GChnl; + pParam->fEnableMCCMode = cfg_params->fenableMCCMode; + pParam->fAllowMCCGODiffBI = cfg_params->fAllowMCCGODiffBI; + pParam->scanCfgAgingTime = pMac->scan.scanResultCfgAgingTime; + qdf_mem_copy(&pParam->neighborRoamConfig, + &cfg_params->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + pParam->nVhtChannelWidth = cfg_params->nVhtChannelWidth; + pParam->enable_subfee_vendor_vhtie = + cfg_params->enable_subfee_vendor_vhtie; + pParam->enable_txbf_sap_mode = + cfg_params->enable_txbf_sap_mode; + pParam->enable_vht20_mcs9 = cfg_params->enable_vht20_mcs9; + pParam->enableVhtFor24GHz = cfg_params->enableVhtFor24GHz; + pParam->ignore_peer_erp_info = cfg_params->ignore_peer_erp_info; + pParam->enable2x2 = cfg_params->enable2x2; + pParam->isFastTransitionEnabled = cfg_params->isFastTransitionEnabled; + pParam->RoamRssiDiff = cfg_params->RoamRssiDiff; + pParam->rssi_abs_thresh = cfg_params->rssi_abs_thresh; + pParam->nRoamPrefer5GHz = cfg_params->nRoamPrefer5GHz; + pParam->nRoamIntraBand = cfg_params->nRoamIntraBand; + pParam->isWESModeEnabled = cfg_params->isWESModeEnabled; + pParam->nProbes = cfg_params->nProbes; + pParam->nRoamScanHomeAwayTime = cfg_params->nRoamScanHomeAwayTime; + pParam->isRoamOffloadScanEnabled = cfg_params->isRoamOffloadScanEnabled; + pParam->bFastRoamInConIniFeatureEnabled = + cfg_params->bFastRoamInConIniFeatureEnabled; + pParam->isFastRoamIniFeatureEnabled = + cfg_params->isFastRoamIniFeatureEnabled; +#ifdef FEATURE_WLAN_ESE + pParam->isEseIniFeatureEnabled = cfg_params->isEseIniFeatureEnabled; +#endif + qdf_mem_copy(&pParam->neighborRoamConfig, + &cfg_params->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + sme_debug("Num of Channels in CFG Channel List: %d", + cfg_params->neighborRoamConfig. + neighborScanChanList.numChannels); + for (i = 0; i < cfg_params->neighborRoamConfig. + neighborScanChanList.numChannels; i++) { + sme_debug("%d ", + cfg_params->neighborRoamConfig. + neighborScanChanList.channelList[i]); + } + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pParam->cc_switch_mode = cfg_params->cc_switch_mode; +#endif + pParam->enable_tx_ldpc = cfg_params->tx_ldpc_enable; + pParam->enable_rx_ldpc = cfg_params->rx_ldpc_enable; + pParam->wep_tkip_in_he = cfg_params->wep_tkip_in_he; + pParam->disable_high_ht_mcs_2x2 = cfg_params->disable_high_ht_mcs_2x2; + pParam->max_amsdu_num = cfg_params->max_amsdu_num; + pParam->nSelect5GHzMargin = cfg_params->nSelect5GHzMargin; + pParam->ho_delay_for_rx = cfg_params->ho_delay_for_rx; + + csr_get_roam_preauth_config_param(pParam, cfg_params); + + pParam->min_delay_btw_roam_scans = cfg_params->min_delay_btw_roam_scans; + pParam->roam_trigger_reason_bitmask = + cfg_params->roam_trigger_reason_bitmask; + pParam->roaming_scan_policy = + cfg_params->roaming_scan_policy; + pParam->isCoalesingInIBSSAllowed = cfg_params->isCoalesingInIBSSAllowed; + pParam->allowDFSChannelRoam = cfg_params->allowDFSChannelRoam; + pParam->nInitialDwellTime = cfg_params->nInitialDwellTime; + pParam->initial_scan_no_dfs_chnl = cfg_params->initial_scan_no_dfs_chnl; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pParam->isRoamOffloadEnabled = cfg_params->isRoamOffloadEnabled; +#endif + pParam->enable_dot11p = pMac->enable_dot11p; + csr_set_channels(pMac, pParam); + pParam->obssEnabled = cfg_params->obssEnabled; + pParam->vendor_vht_sap = + pMac->roam.configParam.vendor_vht_sap; + pParam->roam_dense_rssi_thresh_offset = + cfg_params->roam_params.dense_rssi_thresh_offset; + pParam->roam_dense_min_aps = + cfg_params->roam_params.dense_min_aps_cnt; + pParam->roam_dense_traffic_thresh = + cfg_params->roam_params.traffic_threshold; + + pParam->roam_bg_scan_bad_rssi_thresh = + cfg_params->roam_params.bg_scan_bad_rssi_thresh; + pParam->roam_bg_scan_client_bitmap = + cfg_params->roam_params.bg_scan_client_bitmap; + pParam->roam_bad_rssi_thresh_offset_2g = + cfg_params->roam_params.roam_bad_rssi_thresh_offset_2g; + + pParam->enable_ftopen = cfg_params->enable_ftopen; + pParam->scan_adaptive_dwell_mode = + cfg_params->scan_adaptive_dwell_mode; + pParam->scan_adaptive_dwell_mode_nc = + cfg_params->scan_adaptive_dwell_mode_nc; + pParam->roamscan_adaptive_dwell_mode = + cfg_params->roamscan_adaptive_dwell_mode; + + pParam->per_roam_config.enable = cfg_params->per_roam_config.enable; + pParam->per_roam_config.tx_high_rate_thresh = + cfg_params->per_roam_config.tx_high_rate_thresh; + pParam->per_roam_config.rx_high_rate_thresh = + cfg_params->per_roam_config.rx_high_rate_thresh; + pParam->per_roam_config.tx_low_rate_thresh = + cfg_params->per_roam_config.tx_low_rate_thresh; + pParam->per_roam_config.rx_low_rate_thresh = + cfg_params->per_roam_config.rx_low_rate_thresh; + pParam->per_roam_config.tx_rate_thresh_percnt = + cfg_params->per_roam_config.tx_rate_thresh_percnt; + pParam->per_roam_config.rx_rate_thresh_percnt = + cfg_params->per_roam_config.rx_rate_thresh_percnt; + pParam->per_roam_config.per_rest_time = + cfg_params->per_roam_config.per_rest_time; + pParam->per_roam_config.tx_per_mon_time = + cfg_params->per_roam_config.tx_per_mon_time; + pParam->per_roam_config.rx_per_mon_time = + cfg_params->per_roam_config.rx_per_mon_time; + pParam->per_roam_config.min_candidate_rssi = + cfg_params->per_roam_config.min_candidate_rssi; + + 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; + pParam->send_deauth_before_con = + cfg_params->send_deauth_before_con; + pParam->max_scan_count = pMac->scan.max_scan_count; + pParam->first_scan_bucket_threshold = + pMac->first_scan_bucket_threshold; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + pParam->sap_channel_avoidance = pMac->sap.sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + pParam->acs_with_more_param = pMac->sap.acs_with_more_param; + pParam->max_intf_count = pMac->sme.max_intf_count; + pParam->enableSelfRecovery = pMac->sme.enableSelfRecovery; + pParam->f_prefer_non_dfs_on_radar = + pMac->f_prefer_non_dfs_on_radar; + pParam->dual_mac_feature_disable = + pMac->dual_mac_feature_disable; + pParam->sta_sap_scc_on_dfs_chan = + pMac->sta_sap_scc_on_dfs_chan; + pParam->is_ps_enabled = pMac->sme.ps_global_info.ps_enabled; + pParam->auto_bmps_timer_val = + pMac->sme.ps_global_info.auto_bmps_timer_val; + pParam->fEnableDebugLog = pMac->fEnableDebugLog; + pParam->enable5gEBT = pMac->enable5gEBT; + pParam->f_sta_miracast_mcc_rest_time_val = + pMac->f_sta_miracast_mcc_rest_time_val; + pParam->early_stop_scan_enable = + pMac->roam.configParam.early_stop_scan_enable; + pParam->early_stop_scan_min_threshold = + pMac->roam.configParam.early_stop_scan_min_threshold; + pParam->early_stop_scan_max_threshold = + pMac->roam.configParam.early_stop_scan_max_threshold; + pParam->obss_width_interval = + pMac->roam.configParam.obss_width_interval; + pParam->obss_active_dwelltime = + pMac->roam.configParam.obss_active_dwelltime; + pParam->obss_passive_dwelltime = + pMac->roam.configParam.obss_passive_dwelltime; + pParam->ignore_peer_ht_opmode = + pMac->roam.configParam.ignore_peer_ht_opmode; + pParam->enableHtSmps = pMac->roam.configParam.enableHtSmps; + pParam->htSmps = pMac->roam.configParam.htSmps; + pParam->send_smps_action = pMac->roam.configParam.send_smps_action; + + pParam->enable_edca_params = + pMac->roam.configParam.enable_edca_params; + pParam->edca_vo_cwmin = pMac->roam.configParam.edca_vo_cwmin; + pParam->edca_vi_cwmin = pMac->roam.configParam.edca_vi_cwmin; + pParam->edca_bk_cwmin = pMac->roam.configParam.edca_bk_cwmin; + pParam->edca_be_cwmin = pMac->roam.configParam.edca_be_cwmin; + + pParam->edca_vo_cwmax = pMac->roam.configParam.edca_vo_cwmax; + pParam->edca_vi_cwmax = pMac->roam.configParam.edca_vi_cwmax; + pParam->edca_bk_cwmax = pMac->roam.configParam.edca_bk_cwmax; + pParam->edca_be_cwmax = pMac->roam.configParam.edca_be_cwmax; + + pParam->edca_vo_aifs = pMac->roam.configParam.edca_vo_aifs; + pParam->edca_vi_aifs = pMac->roam.configParam.edca_vi_aifs; + pParam->edca_bk_aifs = pMac->roam.configParam.edca_bk_aifs; + pParam->edca_be_aifs = pMac->roam.configParam.edca_be_aifs; + pParam->enable_fatal_event = + pMac->roam.configParam.enable_fatal_event; + pParam->sta_roam_policy_params.dfs_mode = + pMac->roam.configParam.sta_roam_policy.dfs_mode; + pParam->sta_roam_policy_params.skip_unsafe_channels = + pMac->roam.configParam.sta_roam_policy.skip_unsafe_channels; + pParam->tx_aggregation_size = + pMac->roam.configParam.tx_aggregation_size; + pParam->tx_aggregation_size_be = + pMac->roam.configParam.tx_aggregation_size_be; + pParam->tx_aggregation_size_bk = + pMac->roam.configParam.tx_aggregation_size_bk; + pParam->tx_aggregation_size_vi = + pMac->roam.configParam.tx_aggregation_size_vi; + pParam->tx_aggregation_size_vo = + pMac->roam.configParam.tx_aggregation_size_vo; + pParam->rx_aggregation_size = + pMac->roam.configParam.rx_aggregation_size; + pParam->enable_bcast_probe_rsp = + pMac->roam.configParam.enable_bcast_probe_rsp; + pParam->is_fils_enabled = + pMac->roam.configParam.is_fils_enabled; + pParam->qcn_ie_support = + pMac->roam.configParam.qcn_ie_support; + pParam->fils_max_chan_guard_time = + pMac->roam.configParam.fils_max_chan_guard_time; + pParam->disallow_duration = + pMac->roam.configParam.disallow_duration; + pParam->rssi_channel_penalization = + pMac->roam.configParam.rssi_channel_penalization; + pParam->num_disallowed_aps = + pMac->roam.configParam.num_disallowed_aps; + pParam->oce_feature_bitmap = + pMac->roam.configParam.oce_feature_bitmap; + pParam->roam_force_rssi_trigger = cfg_params->roam_force_rssi_trigger; + qdf_mem_copy(&pParam->csr_mawc_config, + &pMac->roam.configParam.csr_mawc_config, + sizeof(pParam->csr_mawc_config)); + + qdf_mem_copy(&pParam->bss_score_params, + &pMac->roam.configParam.bss_score_params, + sizeof(struct sir_score_config)); + pParam->btm_offload_config = pMac->roam.configParam.btm_offload_config; + pParam->btm_solicited_timeout = + pMac->roam.configParam.btm_solicited_timeout; + pParam->btm_max_attempt_cnt = + pMac->roam.configParam.btm_max_attempt_cnt; + pParam->btm_sticky_time = pMac->roam.configParam.btm_sticky_time; + + pParam->mbo_thresholds.mbo_candidate_rssi_thres = + pMac->roam.configParam.mbo_thresholds. + mbo_candidate_rssi_thres; + pParam->mbo_thresholds.mbo_current_rssi_thres = + pMac->roam.configParam.mbo_thresholds. + mbo_current_rssi_thres; + pParam->mbo_thresholds.mbo_current_rssi_mcc_thres = + pMac->roam.configParam.mbo_thresholds. + mbo_current_rssi_mcc_thres; + pParam->mbo_thresholds.mbo_candidate_rssi_btc_thres = + pMac->roam.configParam.mbo_thresholds. + mbo_candidate_rssi_btc_thres; + + pParam->btm_validity_timer = + pMac->roam.configParam.btm_validity_timer; + pParam->btm_disassoc_timer_threshold = + pMac->roam.configParam.btm_disassoc_timer_threshold; + pParam->enable_bss_load_roam_trigger = + pMac->roam.configParam.enable_bss_load_roam_trigger; + pParam->bss_load_threshold = + pMac->roam.configParam.bss_load_threshold; + pParam->bss_load_sample_time = + pMac->roam.configParam.bss_load_sample_time; + csr_get_he_config_param(pParam, pMac); + + csr_get_11k_offload_config_param(&pMac->roam.configParam, pParam); + + pParam->wlm_latency_enable = pMac->roam.configParam.wlm_latency_enable; + pParam->wlm_latency_level = pMac->roam.configParam.wlm_latency_level; + for (i = 0; i < CSR_NUM_WLM_LATENCY_LEVEL; i++) { + pParam->wlm_latency_flags[i] = + pMac->roam.configParam.wlm_latency_flags[i]; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_set_phy_mode(tHalHandle hHal, uint32_t phyMode, + enum band_info eBand, bool *pfRestartNeeded) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fRestartNeeded = false; + eCsrPhyMode newPhyMode = eCSR_DOT11_MODE_AUTO; + + if (BAND_2G == eBand) { + if (CSR_IS_RADIO_A_ONLY(pMac)) + goto end; + if (eCSR_DOT11_MODE_11a & phyMode) + goto end; + } + if (BAND_5G == eBand) { + if (CSR_IS_RADIO_BG_ONLY(pMac)) + goto end; + if ((eCSR_DOT11_MODE_11b & phyMode) + || (eCSR_DOT11_MODE_11b_ONLY & phyMode) + || (eCSR_DOT11_MODE_11g & phyMode) + || (eCSR_DOT11_MODE_11g_ONLY & phyMode)) + goto end; + } + if (eCSR_DOT11_MODE_AUTO & phyMode) + newPhyMode = eCSR_DOT11_MODE_AUTO; + else { + /* Check for dual band and higher capability first */ + if (eCSR_DOT11_MODE_11n_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11n_ONLY != phyMode) + goto end; + newPhyMode = eCSR_DOT11_MODE_11n_ONLY; + } else if (eCSR_DOT11_MODE_11g_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11g_ONLY != phyMode) + goto end; + if (BAND_5G == eBand) + goto end; + newPhyMode = eCSR_DOT11_MODE_11g_ONLY; + eBand = BAND_2G; + } else if (eCSR_DOT11_MODE_11b_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11b_ONLY != phyMode) + goto end; + if (BAND_5G == eBand) + goto end; + newPhyMode = eCSR_DOT11_MODE_11b_ONLY; + eBand = BAND_2G; + } else if (eCSR_DOT11_MODE_11n & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11n; + } else if (eCSR_DOT11_MODE_abg & phyMode) { + newPhyMode = eCSR_DOT11_MODE_abg; + } else if (eCSR_DOT11_MODE_11a & phyMode) { + if ((eCSR_DOT11_MODE_11g & phyMode) + || (eCSR_DOT11_MODE_11b & phyMode)) { + if (BAND_ALL == eBand) + newPhyMode = eCSR_DOT11_MODE_abg; + else + goto end; + } else { + newPhyMode = eCSR_DOT11_MODE_11a; + eBand = BAND_5G; + } + } else if (eCSR_DOT11_MODE_11g & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11g; + eBand = BAND_2G; + } else if (eCSR_DOT11_MODE_11b & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11b; + eBand = BAND_2G; + } else { + sme_err("can't recognize phymode 0x%08X", phyMode); + newPhyMode = eCSR_DOT11_MODE_AUTO; + } + } + /* Done validating */ + status = QDF_STATUS_SUCCESS; + /* Now we need to check whether a restart is needed. */ + if (eBand != pMac->roam.configParam.eBand) { + fRestartNeeded = true; + goto end; + } + if (newPhyMode != pMac->roam.configParam.phyMode) { + fRestartNeeded = true; + goto end; + } +end: + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.eBand = eBand; + pMac->roam.configParam.phyMode = newPhyMode; + if (pfRestartNeeded) + *pfRestartNeeded = fRestartNeeded; + } + return status; +} + +/** + * 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(ch_lst->channelList[idx])) { + ch_lst->channelList[num_channels] = + ch_lst->channelList[idx]; + num_channels++; + } + } else { + if (WLAN_REG_IS_5GHZ_CH(ch_lst->channelList[idx])) { + ch_lst->channelList[num_channels] = + ch_lst->channelList[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_zero() + * 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->channelList[num_channels], + sizeof(ch_lst->channelList[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(tpAniSirGlobal 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_CHANNEL 6 +QDF_STATUS csr_is_valid_channel(tpAniSirGlobal pMac, uint8_t chnNum) +{ + uint8_t index = 0; + QDF_STATUS status = QDF_STATUS_E_NOSUPPORT; + + /* regulatory check */ + for (index = 0; index < pMac->scan.base_channels.numChannels; + index++) { + if (pMac->scan.base_channels.channelList[index] == chnNum) { + status = QDF_STATUS_SUCCESS; + break; + } + } + + if (status == QDF_STATUS_SUCCESS) { + /* dfs nol */ + for (index = 0; + index < + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + index++) { + tSapDfsNolInfo *dfsChan = &pMac->sap.SapDfsInfo. + sapDfsChannelNolList[index]; + if ((dfsChan->dfs_channel_number == chnNum) + && (dfsChan->radar_status_flag == + eSAP_DFS_CHANNEL_UNAVAILABLE)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("channel %d is in dfs nol"), + chnNum); + status = QDF_STATUS_E_FAILURE; + break; + } + } + } + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("channel %d is not available"), chnNum); + } + + return status; +} + +QDF_STATUS csr_get_channel_and_power_list(tpAniSirGlobal pMac) +{ + 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(pMac->pdev, + pMac->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 > WNI_CFG_VALID_CHANNEL_LIST_LEN) + num20MHzChannelsFound = WNI_CFG_VALID_CHANNEL_LIST_LEN; + pMac->scan.numChannelsDefault = num20MHzChannelsFound; + /* Move the channel list to the global data */ + /* structure -- this will be used as the scan list */ + for (Index = 0; Index < num20MHzChannelsFound; Index++) + pMac->scan.base_channels.channelList[Index] = + pMac->scan.defaultPowerTable[Index].chan_num; + pMac->scan.base_channels.numChannels = + num20MHzChannelsFound; + } + return status; +} + +QDF_STATUS csr_apply_channel_and_power_list(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_prune_channel_list_for_mode(pMac, &pMac->scan.base_channels); + csr_save_channel_power_for_band(pMac, false); + csr_save_channel_power_for_band(pMac, true); + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan.base_channels, + pMac->scan.countryCodeCurrent); + + csr_init_operating_classes((tHalHandle) pMac); + return status; +} + +static QDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t index; + uint32_t count = 0; + tSirMacChanInfo *pChanInfo; + tSirMacChanInfo *pChanInfoStart; + bool applyConfig = true; + + if (!ps11dinfo) + return status; + + if (ps11dinfo->Channels.numChannels + && (WNI_CFG_VALID_CHANNEL_LIST_LEN >= + ps11dinfo->Channels.numChannels)) { + pMac->scan.base_channels.numChannels = + ps11dinfo->Channels.numChannels; + qdf_mem_copy(pMac->scan.base_channels.channelList, + ps11dinfo->Channels.channelList, + ps11dinfo->Channels.numChannels); + } else { + /* No change */ + return QDF_STATUS_SUCCESS; + } + /* legacy maintenance */ + + qdf_mem_copy(pMac->scan.countryCodeDefault, ps11dinfo->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + + /* Tush: at csropen get this initialized with default, + * during csr reset if this already set with some value + * no need initilaize with default again + */ + if (0 == pMac->scan.countryCodeCurrent[0]) { + qdf_mem_copy(pMac->scan.countryCodeCurrent, + ps11dinfo->countryCode, WNI_CFG_COUNTRY_CODE_LEN); + } + /* need to add the max power channel list */ + pChanInfo = + qdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo != NULL) { + pChanInfoStart = pChanInfo; + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->firstChanNum = + ps11dinfo->ChnPower[index].firstChannel; + pChanInfo->numChannels = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->maxTxPower = + QDF_MIN(ps11dinfo->ChnPower[index].maxtxPower, + pMac->roam.configParam.nTxPowerCap); + pChanInfo++; + count++; + } + if (count) { + status = csr_save_to_channel_power2_g_5_g(pMac, + count * + sizeof(tSirMacChanInfo), + 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 < CSR_ROAM_SESSION_MAX; index++) { + if ((CSR_IS_SESSION_VALID(pMac, index)) + && CSR_IS_ROAM_STOP(pMac, 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(pMac, + &pMac->scan. + base_channels, + pMac->scan. + countryCodeCurrent); + } + } + return status; +} + +/* Initialize the Channel + Power List in the local cache and in the CFG */ +QDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac, + tCsr11dinfo *ps11dinfo) +{ + uint8_t index; + uint32_t count = 0; + tSirMacChanInfo *pChanInfo; + tSirMacChanInfo *pChanInfoStart; + + if (!ps11dinfo || !pMac) + return QDF_STATUS_E_FAILURE; + + pChanInfo = + qdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo != NULL) { + pChanInfoStart = pChanInfo; + + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->firstChanNum = + ps11dinfo->ChnPower[index].firstChannel; + pChanInfo->numChannels = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->maxTxPower = + QDF_MIN(ps11dinfo->ChnPower[index].maxtxPower, + pMac->roam.configParam.nTxPowerCap); + pChanInfo++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(pMac, + count * + sizeof(tSirMacChanInfo), + pChanInfoStart); + } + qdf_mem_free(pChanInfoStart); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_roam_remove_duplicate_cmd_from_list()- Remove duplicate roam cmd from + * list + * + * @mac_ctx: pointer to global mac + * @session_id: session id for the cmd + * @list: pending list from which cmd needs to be removed + * @command: cmd to be removed, can be NULL + * @roam_reason: cmd with reason to be removed + * + * Remove duplicate command from the pending list. + * + * Return: void + */ +static void csr_roam_remove_duplicate_pending_cmd_from_list( + tpAniSirGlobal mac_ctx, + uint32_t session_id, + tSmeCmd *command, enum csr_roam_reason roam_reason) +{ + tListElem *entry, *next_entry; + tSmeCmd *dup_cmd; + tDblLinkList local_list; + + qdf_mem_zero(&local_list, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(&local_list))) { + sme_err("failed to open list"); + return; + } + csr_nonscan_pending_ll_lock(mac_ctx); + entry = csr_nonscan_pending_ll_peek_head(mac_ctx, LL_ACCESS_NOLOCK); + while (entry) { + next_entry = csr_nonscan_pending_ll_next(mac_ctx, entry, + LL_ACCESS_NOLOCK); + dup_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* + * If command is not NULL remove the similar duplicate cmd for + * same reason as command. If command is NULL then check if + * roam_reason is eCsrForcedDisassoc (disconnect) and remove + * all roam command for the sessionId, else if roam_reason is + * eCsrHddIssued (connect) remove all connect (non disconenct) + * commands. + */ + if ((command && (command->sessionId == dup_cmd->sessionId) && + ((command->command == dup_cmd->command) && + /* + * This peermac check is required for Softap/GO + * scenarios. for STA scenario below OR check will + * suffice as command will always be NULL for + * STA scenarios + */ + (!qdf_mem_cmp(dup_cmd->u.roamCmd.peerMac, + command->u.roamCmd.peerMac, + sizeof(QDF_MAC_ADDR_SIZE))) && + ((command->u.roamCmd.roamReason == + dup_cmd->u.roamCmd.roamReason) || + (eCsrForcedDisassoc == + command->u.roamCmd.roamReason) || + (eCsrHddIssued == + command->u.roamCmd.roamReason)))) || + /* OR if pCommand is NULL */ + ((session_id == dup_cmd->sessionId) && + (eSmeCommandRoam == dup_cmd->command) && + ((eCsrForcedDisassoc == roam_reason) || + (eCsrHddIssued == roam_reason && + !CSR_IS_DISCONNECT_COMMAND(dup_cmd))))) { + sme_debug("RoamReason: %d", + dup_cmd->u.roamCmd.roamReason); + /* Insert to local_list and remove later */ + csr_ll_insert_tail(&local_list, entry, + LL_ACCESS_NOLOCK); + } + entry = next_entry; + } + csr_nonscan_pending_ll_unlock(mac_ctx); + + while ((entry = csr_ll_remove_head(&local_list, LL_ACCESS_NOLOCK))) { + dup_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* Tell caller that the command is cancelled */ + csr_roam_call_callback(mac_ctx, dup_cmd->sessionId, NULL, + dup_cmd->u.roamCmd.roamId, + eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE); + csr_release_command(mac_ctx, dup_cmd); + } + csr_ll_close(&local_list); +} + +/** + * csr_roam_remove_duplicate_command()- Remove duplicate roam cmd + * from pending lists. + * + * @mac_ctx: pointer to global mac + * @session_id: session id for the cmd + * @command: cmd to be removed, can be null + * @roam_reason: cmd with reason to be removed + * + * Remove duplicate command from the sme and roam pending list. + * + * Return: void + */ +void csr_roam_remove_duplicate_command(tpAniSirGlobal mac_ctx, + uint32_t session_id, tSmeCmd *command, + enum csr_roam_reason roam_reason) +{ + /* Always lock active list before locking pending lists */ + csr_nonscan_active_ll_lock(mac_ctx); + csr_roam_remove_duplicate_pending_cmd_from_list(mac_ctx, + session_id, command, roam_reason); + csr_nonscan_active_ll_unlock(mac_ctx); +} + +/** + * csr_roam_populate_channels() - Helper function to populate channels + * @beacon_ies: pointer to beacon ie + * @roam_info: Roaming related information + * @chan1: center freq 1 + * @chan2: center freq2 + * + * This function will issue populate chan1 and chan2 based on beacon ie + * + * Return: none. + */ +static void csr_roam_populate_channels(tDot11fBeaconIEs *beacon_ies, + struct csr_roam_info *roam_info, + uint8_t *chan1, uint8_t *chan2) +{ + ePhyChanBondState phy_state; + + if (beacon_ies->VHTOperation.present) { + *chan1 = beacon_ies->VHTOperation.chanCenterFreqSeg1; + *chan2 = beacon_ies->VHTOperation.chanCenterFreqSeg2; + roam_info->chan_info.info = MODE_11AC_VHT80; + } else if (beacon_ies->HTInfo.present) { + if (beacon_ies->HTInfo.recommendedTxWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) { + phy_state = beacon_ies->HTInfo.secondaryChannelOffset; + if (phy_state == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + *chan1 = beacon_ies->HTInfo.primaryChannel + + CSR_CB_CENTER_CHANNEL_OFFSET; + else if (phy_state == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + *chan1 = beacon_ies->HTInfo.primaryChannel - + CSR_CB_CENTER_CHANNEL_OFFSET; + else + *chan1 = beacon_ies->HTInfo.primaryChannel; + + roam_info->chan_info.info = MODE_11NA_HT40; + } else { + *chan1 = beacon_ies->HTInfo.primaryChannel; + roam_info->chan_info.info = MODE_11NA_HT20; + } + *chan2 = 0; + } else { + *chan1 = 0; + *chan2 = 0; + roam_info->chan_info.info = MODE_11A; + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +#ifdef WLAN_DEBUG +static const char *csr_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 "Unknown"; + } +} + +static const char *csr_get_dot11_mode_str(enum csr_cfgdot11mode 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 "Unknown"; + } +} + +static const char *csr_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"; + } +} + +static const char *csr_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"; + } +} +#endif + +static void csr_dump_connection_stats(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, + struct csr_roam_info *roam_info, + eRoamCmdStatus u1, eCsrRoamResult u2) +{ + struct tagCsrRoamConnectedProfile *conn_profile; + struct csr_roam_profile *profile; + WLAN_HOST_DIAG_EVENT_DEF(conn_stats, + struct host_event_wlan_connection_stats); + + if (!session || !session->pCurRoamProfile || !roam_info) + return; + + conn_profile = roam_info->u.pConnectedProfile; + if (!conn_profile) + return; + profile = session->pCurRoamProfile; + qdf_mem_zero(&conn_stats, + sizeof(struct host_event_wlan_connection_stats)); + qdf_mem_copy(conn_stats.bssid, conn_profile->bssid.bytes, + QDF_MAC_ADDR_SIZE); + conn_stats.ssid_len = conn_profile->SSID.length; + if (conn_stats.ssid_len > SIR_MAC_MAX_SSID_LENGTH) + conn_stats.ssid_len = SIR_MAC_MAX_SSID_LENGTH; + qdf_mem_copy(conn_stats.ssid, conn_profile->SSID.ssId, + conn_stats.ssid_len); + sme_get_rssi_snr_by_bssid(MAC_HANDLE(mac_ctx), + session->pCurRoamProfile, + &conn_stats.bssid[0], + &conn_stats.rssi, NULL); + conn_stats.est_link_speed = 0; + conn_stats.chnl_bw = + diag_ch_width_from_csr_type(conn_profile->vht_channel_width); + conn_stats.dot11mode = + diag_dot11_mode_from_csr_type(conn_profile->dot11Mode); + conn_stats.bss_type = + diag_persona_from_csr_type(session->pCurRoamProfile->csrPersona); + conn_stats.operating_channel = conn_profile->operationChannel; + conn_stats.qos_capability = conn_profile->qosConnection; + conn_stats.auth_type = + diag_auth_type_from_csr_type(conn_profile->AuthType); + conn_stats.encryption_type = + diag_enc_type_from_csr_type(conn_profile->EncryptionType); + conn_stats.result_code = (u2 == eCSR_ROAM_RESULT_ASSOCIATED) ? 1 : 0; + conn_stats.reason_code = 0; + sme_debug("+---------CONNECTION INFO START------------+"); + sme_debug("connection stats for session-id: %d", session->sessionId); + sme_debug("ssid: %.*s", conn_stats.ssid_len, conn_stats.ssid); + sme_debug("bssid: %pM", conn_stats.bssid); + sme_debug("rssi: %d dBm", conn_stats.rssi); + sme_debug("channel: %d", conn_stats.operating_channel); + sme_debug("dot11Mode: %s", + csr_get_dot11_mode_str(conn_stats.dot11mode)); + sme_debug("channel bw: %s", + csr_get_ch_width_str(conn_stats.chnl_bw)); + sme_debug("Qos enable: %d", conn_stats.qos_capability); + sme_debug("Auth-type: %s", + csr_get_auth_type_str(conn_stats.auth_type)); + sme_debug("Encry-type: %s", + csr_get_encr_type_str(conn_stats.encryption_type)); + sme_debug("is associated?: %s", + (conn_stats.result_code ? "yes" : "no")); + sme_debug("+---------CONNECTION INFO END------------+"); + + WLAN_HOST_DIAG_EVENT_REPORT(&conn_stats, EVENT_WLAN_CONN_STATS_V2); +} +#else +static void csr_dump_connection_stats(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, + struct csr_roam_info *roam_info, + eRoamCmdStatus u1, eCsrRoamResult u2) +{} + +#endif + +QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus u1, eCsrRoamResult u2) +{ + QDF_STATUS ret, status = QDF_STATUS_SUCCESS; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + uint32_t rssi = 0; + + WLAN_HOST_DIAG_EVENT_DEF(connectionStatus, + host_event_wlan_status_payload_type); +#endif + struct csr_roam_session *pSession; + tDot11fBeaconIEs *beacon_ies = NULL; + uint8_t chan1, chan2; + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sme_err("Session ID: %d is not valid", sessionId); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (false == pSession->sessionActive) { + sme_debug("Session is not Active"); + return QDF_STATUS_E_FAILURE; + } + + if (eCSR_ROAM_ASSOCIATION_COMPLETION == u1 && + eCSR_ROAM_RESULT_ASSOCIATED == u2 && roam_info) { + sme_debug("Assoc complete result: %d status: %d reason: %d", + u2, roam_info->statusCode, roam_info->reasonCode); + beacon_ies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if ((NULL != beacon_ies) && (NULL != roam_info->pBssDesc)) { + status = csr_parse_bss_description_ies( + pMac, roam_info->pBssDesc, + beacon_ies); + csr_roam_populate_channels(beacon_ies, roam_info, + &chan1, &chan2); + if (0 != chan1) + roam_info->chan_info.band_center_freq1 = + cds_chan_to_freq(chan1); + else + roam_info->chan_info.band_center_freq1 = 0; + if (0 != chan2) + roam_info->chan_info.band_center_freq2 = + cds_chan_to_freq(chan2); + else + roam_info->chan_info.band_center_freq2 = 0; + } else { + roam_info->chan_info.band_center_freq1 = 0; + roam_info->chan_info.band_center_freq2 = 0; + roam_info->chan_info.info = 0; + } + roam_info->chan_info.chan_id = + roam_info->u.pConnectedProfile->operationChannel; + roam_info->chan_info.mhz = + cds_chan_to_freq(roam_info->chan_info.chan_id); + roam_info->chan_info.reg_info_1 = + (csr_get_cfg_max_tx_power(pMac, + roam_info->chan_info.chan_id) << 16); + roam_info->chan_info.reg_info_2 = + (csr_get_cfg_max_tx_power(pMac, + roam_info->chan_info.chan_id) << 8); + qdf_mem_free(beacon_ies); + } else if ((u1 == eCSR_ROAM_FT_REASSOC_FAILED) + && (pSession->bRefAssocStartCnt)) { + /* + * Decrement bRefAssocStartCnt for FT reassoc failure. + * Reason: For FT reassoc failures, we first call + * csr_roam_call_callback before notifying a failed roam + * completion through csr_roam_complete. The latter in + * turn calls csr_roam_process_results which tries to + * once again call csr_roam_call_callback if bRefAssocStartCnt + * is non-zero. Since this is redundant for FT reassoc + * failure, decrement bRefAssocStartCnt. + */ + pSession->bRefAssocStartCnt--; + } else if (roam_info && (u1 == eCSR_ROAM_SET_CHANNEL_RSP) + && (u2 == eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS)) { + pSession->connectedProfile.operationChannel = + roam_info->channelChangeRespEvent->newChannelNumber; + } else if (u1 == eCSR_ROAM_SESSION_OPENED) { + ret = (u2 == eCSR_ROAM_RESULT_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; + + if (pSession->session_open_cb) + pSession->session_open_cb(sessionId, ret); + else + sme_err("session_open_cb is not registered"); + } + if (eCSR_ROAM_ASSOCIATION_COMPLETION == u1) + csr_dump_connection_stats(pMac, pSession, roam_info, u1, u2); + + if (NULL != pSession->callback) { + if (roam_info) { + roam_info->sessionId = (uint8_t) sessionId; + /* + * the reasonCode will be passed to supplicant by + * cfg80211_disconnected. Based on the document, + * the reason code passed to supplicant needs to set + * to 0 if unknown. eSIR_BEACON_MISSED reason code is + * not recognizable so that we set to 0 instead. + */ + roam_info->reasonCode = + (roam_info->reasonCode == eSIR_BEACON_MISSED) ? + 0 : roam_info->reasonCode; + } + status = pSession->callback(pSession->pContext, roam_info, + roamId, u1, u2); + } + /* + * EVENT_WLAN_STATUS_V2: eCSR_ROAM_ASSOCIATION_COMPLETION, + * eCSR_ROAM_LOSTLINK, + * eCSR_ROAM_DISASSOCIATED, + */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + qdf_mem_zero(&connectionStatus, + sizeof(host_event_wlan_status_payload_type)); + + if ((eCSR_ROAM_ASSOCIATION_COMPLETION == u1) + && (eCSR_ROAM_RESULT_ASSOCIATED == u2) && roam_info) { + connectionStatus.eventId = eCSR_WLAN_STATUS_CONNECT; + connectionStatus.bssType = + roam_info->u.pConnectedProfile->BSSType; + + if (NULL != roam_info->pBssDesc) { + connectionStatus.rssi = + roam_info->pBssDesc->rssi * (-1); + connectionStatus.channel = + roam_info->pBssDesc->channelId; + } + if (cfg_set_int(pMac, WNI_CFG_CURRENT_RSSI, + connectionStatus.rssi) == QDF_STATUS_E_FAILURE) + sme_err("Can't pass WNI_CFG_CURRENT_RSSI to cfg"); + + connectionStatus.qosCapability = + roam_info->u.pConnectedProfile->qosConnection; + connectionStatus.authType = + (uint8_t) diag_auth_type_from_csr_type( + roam_info->u.pConnectedProfile->AuthType); + connectionStatus.encryptionType = + (uint8_t) diag_enc_type_from_csr_type( + roam_info->u.pConnectedProfile->EncryptionType); + qdf_mem_copy(connectionStatus.ssid, + roam_info->u.pConnectedProfile->SSID.ssId, + roam_info->u.pConnectedProfile->SSID.length); + + connectionStatus.reason = eCSR_REASON_UNSPECIFIED; + qdf_mem_copy(&pMac->sme.eventPayload, &connectionStatus, + sizeof(host_event_wlan_status_payload_type)); + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if ((eCSR_ROAM_MIC_ERROR_IND == u1) + || (eCSR_ROAM_RESULT_MIC_FAILURE == u2)) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (QDF_IS_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_MIC_ERROR; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if (eCSR_ROAM_RESULT_FORCED == u2) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (QDF_IS_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if (eCSR_ROAM_RESULT_DISASSOC_IND == u2) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (QDF_IS_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_DISASSOC; + if (roam_info) + connectionStatus.reasonDisconnect = + roam_info->reasonCode; + + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if (eCSR_ROAM_RESULT_DEAUTH_IND == u2) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (QDF_IS_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_DEAUTH; + if (roam_info) + connectionStatus.reasonDisconnect = + roam_info->reasonCode; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + return status; +} + +/* Returns whether handoff is currently in progress or not */ +static +bool csr_roam_is_handoff_in_progress(tpAniSirGlobal pMac, uint8_t sessionId) +{ + return csr_neighbor_roam_is_handoff_in_progress(pMac, sessionId); +} + +static +QDF_STATUS csr_roam_issue_disassociate(tpAniSirGlobal pMac, uint32_t sessionId, + enum csr_roam_substate NewSubstate, + bool fMICFailure) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BCAST_INIT; + uint16_t reasonCode; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (fMICFailure) { + reasonCode = eSIR_MAC_MIC_FAILURE_REASON; + } else if (NewSubstate == eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF) { + reasonCode = eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON; + } else if (eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT == NewSubstate) { + reasonCode = eSIR_MAC_DISASSOC_LEAVING_BSS_REASON; + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "set to reason code eSIR_MAC_DISASSOC_LEAVING_BSS_REASON and set back NewSubstate"); + } else { + reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON; + } + if ((csr_roam_is_handoff_in_progress(pMac, sessionId)) && + (NewSubstate != eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF)) { + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + qdf_copy_macaddr(&bssId, + pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs. + bssid); + } else if (pSession->pConnectBssDesc) { + qdf_mem_copy(&bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } + + sme_debug("CSR Attempting to Disassociate Bssid=" MAC_ADDRESS_STR + " subState: %s reason: %d", MAC_ADDR_ARRAY(bssId.bytes), + mac_trace_getcsr_roam_sub_state(NewSubstate), reasonCode); + + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + status = csr_send_mb_disassoc_req_msg(pMac, sessionId, bssId.bytes, + reasonCode); + + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_link_down(pMac, sessionId); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + /* no need to tell QoS that we are disassociating, it will be + * taken care off in assoc req for HO + */ + if (eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF != NewSubstate) { + /* notify QoS module that disassoc happening */ + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_REQ, NULL); + } +#endif + } else { + sme_warn("csr_send_mb_disassoc_req_msg failed status: %d", + status); + } + + return status; +} + +/** + * csr_roam_issue_disassociate_sta_cmd() - disassociate a associated station + * @sessionId: Session Id for Soft AP + * @p_del_sta_params: Pointer to parameters of the station to disassoc + * + * CSR function that HDD calls to delete a associated station + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_* on error + */ +QDF_STATUS csr_roam_issue_disassociate_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_del_sta_params + *p_del_sta_params) + +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sme_err("fail to get command buffer"); + status = QDF_STATUS_E_RESOURCES; + break; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrForcedDisassocSta; + qdf_mem_copy(pCommand->u.roamCmd.peerMac, + p_del_sta_params->peerMacAddr.bytes, + sizeof(pCommand->u.roamCmd.peerMac)); + pCommand->u.roamCmd.reason = + (tSirMacReasonCodes)p_del_sta_params->reason_code; + status = csr_queue_sme_command(pMac, pCommand, true); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to send message status: %d", status); + } while (0); + + return status; +} + +/** + * csr_roam_issue_deauthSta() - delete a associated station + * @sessionId: Session Id for Soft AP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * CSR function that HDD calls to delete a associated station + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_** on error + */ +QDF_STATUS csr_roam_issue_deauth_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_del_sta_params *pDelStaParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sme_err("fail to get command buffer"); + status = QDF_STATUS_E_RESOURCES; + break; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrForcedDeauthSta; + qdf_mem_copy(pCommand->u.roamCmd.peerMac, + pDelStaParams->peerMacAddr.bytes, + sizeof(tSirMacAddr)); + pCommand->u.roamCmd.reason = + (tSirMacReasonCodes)pDelStaParams->reason_code; + status = csr_queue_sme_command(pMac, pCommand, true); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to send message status: %d", status); + } while (0); + + return status; +} + +QDF_STATUS +csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, uint8_t *pAssocStasBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BCAST_INIT; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("csr_roam_get_associated_stas:CSR Session not found"); + return status; + } + if (pSession->pConnectBssDesc) { + qdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + sme_err("csr_roam_get_associated_stas:Connected BSS Description in CSR Session not found"); + return status; + } + sme_debug("CSR getting associated stations for Bssid: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + status = + csr_send_mb_get_associated_stas_req_msg(pMac, sessionId, modId, + bssId, + pUsrContext, + pfnSapEventCallback, + pAssocStasBuf); + return status; +} + +static +QDF_STATUS csr_roam_issue_deauth(tpAniSirGlobal pMac, uint32_t sessionId, + enum csr_roam_substate NewSubstate) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BCAST_INIT; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->pConnectBssDesc) { + qdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } + sme_debug("CSR Attempting to Deauth Bssid= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + status = + csr_send_mb_deauth_req_msg(pMac, sessionId, bssId.bytes, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON); + if (QDF_IS_STATUS_SUCCESS(status)) + csr_roam_link_down(pMac, sessionId); + else { + sme_err("csr_send_mb_deauth_req_msg failed with status %d Session ID: %d" + MAC_ADDRESS_STR, status, sessionId, + MAC_ADDR_ARRAY(bssId.bytes)); + } + + return status; +} + +QDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t size; + + if (!pSession) { + sme_err(" session %d not found ", sessionId); + return QDF_STATUS_E_FAILURE; + } + /* If no BSS description was found in this connection + * (happens with start IBSS), then nix the BSS description + * that we keep around for the connected BSS) and get out. + */ + if (NULL == pBssDesc) { + csr_free_connect_bss_desc(pMac, sessionId); + } else { + size = pBssDesc->length + sizeof(pBssDesc->length); + if (NULL != pSession->pConnectBssDesc) { + if (((pSession->pConnectBssDesc->length) + + sizeof(pSession->pConnectBssDesc->length)) < + size) { + /* not enough room for the new BSS, + * pMac->roam.pConnectBssDesc is freed inside + */ + csr_free_connect_bss_desc(pMac, sessionId); + } + } + if (NULL == pSession->pConnectBssDesc) + pSession->pConnectBssDesc = qdf_mem_malloc(size); + + if (NULL == pSession->pConnectBssDesc) + status = QDF_STATUS_E_NOMEM; + else + qdf_mem_copy(pSession->pConnectBssDesc, pBssDesc, size); + } + return status; +} + +static +QDF_STATUS csr_roam_prepare_bss_config(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc, + struct bss_config_param *pBssConfig, + tDot11fBeaconIEs *pIes) +{ + enum csr_cfgdot11mode cfgDot11Mode; + + QDF_ASSERT(pIes != NULL); + if (pIes == NULL) + return QDF_STATUS_E_FAILURE; + + qdf_mem_copy(&pBssConfig->BssCap, &pBssDesc->capabilityInfo, + sizeof(tSirMacCapabilityInfo)); + /* get qos */ + pBssConfig->qosType = csr_get_qos_from_bss_desc(pMac, pBssDesc, pIes); + /* Take SSID always from profile */ + qdf_mem_copy(&pBssConfig->SSID.ssId, + pProfile->SSIDs.SSIDList->SSID.ssId, + pProfile->SSIDs.SSIDList->SSID.length); + pBssConfig->SSID.length = pProfile->SSIDs.SSIDList->SSID.length; + + if (csr_is_nullssid(pBssConfig->SSID.ssId, pBssConfig->SSID.length)) { + sme_warn("BSS desc SSID is a wild card"); + /* Return failed if profile doesn't have an SSID either. */ + if (pProfile->SSIDs.numOfSSIDs == 0) { + sme_warn("BSS desc and profile doesn't have SSID"); + return QDF_STATUS_E_FAILURE; + } + } + if (WLAN_REG_IS_5GHZ_CH(pBssDesc->channelId)) + pBssConfig->eBand = BAND_5G; + else + pBssConfig->eBand = BAND_2G; + /* phymode */ + if (csr_is_phy_mode_match(pMac, pProfile->phyMode, pBssDesc, + pProfile, &cfgDot11Mode, pIes)) { + pBssConfig->uCfgDot11Mode = cfgDot11Mode; + } else { + /* + * No matching phy mode found, force to 11b/g based on INI for + * 2.4Ghz and to 11a mode for 5Ghz + */ + sme_warn("Can not find match phy mode"); + if (BAND_2G == pBssConfig->eBand) { + if (pMac->roam.configParam.phyMode & + (eCSR_DOT11_MODE_11b | eCSR_DOT11_MODE_11b_ONLY)) { + pBssConfig->uCfgDot11Mode = + eCSR_CFG_DOT11_MODE_11B; + } else { + pBssConfig->uCfgDot11Mode = + eCSR_CFG_DOT11_MODE_11G; + } + } else { + pBssConfig->uCfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + } + } + + sme_debug("phyMode=%d, uCfgDot11Mode=%d negotiatedAuthType %d", + pProfile->phyMode, pBssConfig->uCfgDot11Mode, + pProfile->negotiatedAuthType); + + /* Qos */ + if ((pBssConfig->uCfgDot11Mode != eCSR_CFG_DOT11_MODE_11N) && + (pMac->roam.configParam.WMMSupportMode == eCsrRoamWmmNoQos)) { + /* + * Joining BSS is not 11n capable and WMM is disabled on client. + * Disable QoS and WMM + */ + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF; + } + + if (((pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N) + || (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC)) + && ((pBssConfig->qosType != eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP) + || (pBssConfig->qosType != eCSR_MEDIUM_ACCESS_11e_HCF) + || (pBssConfig->qosType != eCSR_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 */ + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } + /* auth type */ + switch (pProfile->negotiatedAuthType) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pBssConfig->authType = eSIR_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + pBssConfig->authType = eSIR_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + pBssConfig->authType = eSIR_AUTO_SWITCH; + break; + case eCSR_AUTH_TYPE_SAE: + pBssConfig->authType = eSIR_AUTH_TYPE_SAE; + break; + } + /* short slot time */ + if (eCSR_CFG_DOT11_MODE_11B != cfgDot11Mode) + pBssConfig->uShortSlotTime = + pMac->roam.configParam.shortSlotTime; + else + pBssConfig->uShortSlotTime = 0; + + if (pBssConfig->BssCap.ibss) + /* We don't support 11h on IBSS */ + pBssConfig->f11hSupport = false; + else + pBssConfig->f11hSupport = + pMac->roam.configParam.Is11hSupportEnabled; + /* power constraint */ + pBssConfig->uPowerLimit = + csr_get11h_power_constraint(pMac, &pIes->PowerConstraints); + /* heartbeat */ + if (CSR_IS_11A_BSS(pBssDesc)) + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh50; + else + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh24; + + /* + * Join timeout: if we find a BeaconInterval in the BssDescription, + * then set the Join Timeout to be 10 x the BeaconInterval. + */ + if (pBssDesc->beaconInterval) { + /* Make sure it is bigger than the minimal */ + pBssConfig->uJoinTimeOut = + QDF_MAX(10 * pBssDesc->beaconInterval, + CSR_JOIN_FAILURE_TIMEOUT_MIN); + if (pBssConfig->uJoinTimeOut > CSR_JOIN_FAILURE_TIMEOUT_DEFAULT) + pBssConfig->uJoinTimeOut = + CSR_JOIN_FAILURE_TIMEOUT_DEFAULT; + } else { + pBssConfig->uJoinTimeOut = + CSR_JOIN_FAILURE_TIMEOUT_DEFAULT; + } + /* validate CB */ + if ((pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N) || + (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N_ONLY) || + (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC) || + (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC_ONLY) || + (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AX) || + (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AX_ONLY)) + pBssConfig->cbMode = csr_get_cb_mode_from_ies(pMac, + pBssDesc->channelId, pIes); + else + pBssConfig->cbMode = PHY_SINGLE_CHANNEL_CENTERED; + + if (WLAN_REG_IS_24GHZ_CH(pBssDesc->channelId) && + pProfile->force_24ghz_in_ht20) { + pBssConfig->cbMode = PHY_SINGLE_CHANNEL_CENTERED; + sme_debug("force_24ghz_in_ht20 is set so set cbmode to 0"); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_prepare_bss_config_from_profile( + tpAniSirGlobal pMac, struct csr_roam_profile *pProfile, + struct bss_config_param *pBssConfig, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t operationChannel = 0; + uint8_t qAPisEnabled = false; + /* SSID */ + pBssConfig->SSID.length = 0; + if (pProfile->SSIDs.numOfSSIDs) { + /* only use the first one */ + qdf_mem_copy(&pBssConfig->SSID, + &pProfile->SSIDs.SSIDList[0].SSID, + sizeof(tSirMacSSid)); + } else { + /* SSID must present */ + return QDF_STATUS_E_FAILURE; + } + /* Settomg up the capabilities */ + if (csr_is_bss_type_ibss(pProfile->BSSType)) + pBssConfig->BssCap.ibss = 1; + else + pBssConfig->BssCap.ess = 1; + + if (eCSR_ENCRYPT_TYPE_NONE != + pProfile->EncryptionType.encryptionType[0]) + pBssConfig->BssCap.privacy = 1; + + pBssConfig->eBand = pMac->roam.configParam.eBand; + /* phymode */ + if (pProfile->ChannelInfo.ChannelList) + operationChannel = pProfile->ChannelInfo.ChannelList[0]; + pBssConfig->uCfgDot11Mode = csr_roam_get_phy_mode_band_for_bss(pMac, + pProfile, operationChannel, + &pBssConfig->eBand); + /* QOS */ + /* Is this correct to always set to this // *** */ + if (pBssConfig->BssCap.ess == 1) { + /*For Softap case enable WMM */ + if (CSR_IS_INFRA_AP(pProfile) + && (eCsrRoamWmmNoQos != + pMac->roam.configParam.WMMSupportMode)) { + qAPisEnabled = true; + } else + if (csr_roam_get_qos_info_from_bss(pMac, pBssDesc) == + QDF_STATUS_SUCCESS) { + qAPisEnabled = true; + } else { + qAPisEnabled = false; + } + } else { + qAPisEnabled = true; + } + if ((eCsrRoamWmmNoQos != pMac->roam.configParam.WMMSupportMode && + qAPisEnabled) || + ((eCSR_CFG_DOT11_MODE_11N == pBssConfig->uCfgDot11Mode && + qAPisEnabled))) { + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } else { + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF; + } + + /* auth type */ + /* Take the preferred Auth type. */ + switch (pProfile->AuthType.authType[0]) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pBssConfig->authType = eSIR_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + pBssConfig->authType = eSIR_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + pBssConfig->authType = eSIR_AUTO_SWITCH; + break; + case eCSR_AUTH_TYPE_SAE: + pBssConfig->authType = eSIR_AUTH_TYPE_SAE; + break; + } + /* short slot time */ + if (WNI_CFG_PHY_MODE_11B != pBssConfig->uCfgDot11Mode) { + pBssConfig->uShortSlotTime = + pMac->roam.configParam.shortSlotTime; + } else { + pBssConfig->uShortSlotTime = 0; + } + /* power constraint. We don't support 11h on IBSS */ + pBssConfig->f11hSupport = false; + pBssConfig->uPowerLimit = 0; + /* heartbeat */ + if (BAND_5G == pBssConfig->eBand) { + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh50; + } else { + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh24; + } + /* Join timeout */ + pBssConfig->uJoinTimeOut = CSR_JOIN_FAILURE_TIMEOUT_DEFAULT; + + return status; +} + +static QDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tDot11fBeaconIEs *pIes = NULL; + + do { + if (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pBssDesc, &pIes))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "csr_roam_get_qos_info_from_bss() failed"); + break; + } + /* check if the AP is QAP & it supports APSD */ + if (CSR_IS_QOS_BSS(pIes)) + status = QDF_STATUS_SUCCESS; + } while (0); + + if (NULL != pIes) + qdf_mem_free(pIes); + + return status; +} + +static void csr_reset_cfg_privacy(tpAniSirGlobal mac) +{ + uint8_t Key0[WNI_CFG_WEP_DEFAULT_KEY_1_LEN] = {0}; + uint8_t Key1[WNI_CFG_WEP_DEFAULT_KEY_2_LEN] = {0}; + uint8_t Key2[WNI_CFG_WEP_DEFAULT_KEY_3_LEN] = {0}; + uint8_t Key3[WNI_CFG_WEP_DEFAULT_KEY_4_LEN] = {0}; + + cfg_set_int(mac, WNI_CFG_PRIVACY_ENABLED, 0); + cfg_set_int(mac, WNI_CFG_RSN_ENABLED, 0); + cfg_set_str(mac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, + WNI_CFG_WEP_DEFAULT_KEY_1_LEN); + cfg_set_str(mac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, + WNI_CFG_WEP_DEFAULT_KEY_2_LEN); + cfg_set_str(mac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, + WNI_CFG_WEP_DEFAULT_KEY_3_LEN); + cfg_set_str(mac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, + WNI_CFG_WEP_DEFAULT_KEY_4_LEN); + cfg_set_int(mac, WNI_CFG_WEP_DEFAULT_KEYID, 0); +} + +void csr_set_cfg_privacy(tpAniSirGlobal pMac, struct csr_roam_profile *pProfile, + bool fPrivacy) +{ + /* + * the only difference between this function and + * the csr_set_cfg_privacyFromProfile() is the setting of the privacy + * CFG based on the advertised privacy setting from the AP for WPA + * associations. See note below in this function... + */ + uint32_t PrivacyEnabled = 0, RsnEnabled = 0, WepDefaultKeyId = 0; + uint32_t WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5; + uint32_t Key0Length = 0, Key1Length = 0, Key2Length = 0, Key3Length = 0; + + /* Reserve for the biggest key */ + uint8_t Key0[WNI_CFG_WEP_DEFAULT_KEY_1_LEN]; + uint8_t Key1[WNI_CFG_WEP_DEFAULT_KEY_2_LEN]; + uint8_t Key2[WNI_CFG_WEP_DEFAULT_KEY_3_LEN]; + uint8_t Key3[WNI_CFG_WEP_DEFAULT_KEY_4_LEN]; + + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_NONE: + /* for NO encryption, turn off Privacy and Rsn. */ + PrivacyEnabled = 0; + RsnEnabled = 0; + /* clear out the WEP keys that may be hanging around. */ + Key0Length = 0; + Key1Length = 0; + Key2Length = 0; + Key3Length = 0; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + + /* Privacy is ON. NO RSN for Wep40 static key. */ + PrivacyEnabled = 1; + RsnEnabled = 0; + /* Set the Wep default key ID. */ + WepDefaultKeyId = pProfile->Keys.defaultIndex; + /* Wep key size if 5 bytes (40 bits). */ + WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5; + /* + * set encryption keys in the CFG database or + * clear those that are not present in this profile. + */ + if (pProfile->Keys.KeyLength[0]) { + qdf_mem_copy(Key0, + pProfile->Keys.KeyMaterial[0], + WNI_CFG_WEP_KEY_LENGTH_5); + Key0Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key0Length = 0; + } + + if (pProfile->Keys.KeyLength[1]) { + qdf_mem_copy(Key1, + pProfile->Keys.KeyMaterial[1], + WNI_CFG_WEP_KEY_LENGTH_5); + Key1Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key1Length = 0; + } + + if (pProfile->Keys.KeyLength[2]) { + qdf_mem_copy(Key2, + pProfile->Keys.KeyMaterial[2], + WNI_CFG_WEP_KEY_LENGTH_5); + Key2Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key2Length = 0; + } + + if (pProfile->Keys.KeyLength[3]) { + qdf_mem_copy(Key3, + pProfile->Keys.KeyMaterial[3], + WNI_CFG_WEP_KEY_LENGTH_5); + Key3Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key3Length = 0; + } + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + + /* Privacy is ON. NO RSN for Wep40 static key. */ + PrivacyEnabled = 1; + RsnEnabled = 0; + /* Set the Wep default key ID. */ + WepDefaultKeyId = pProfile->Keys.defaultIndex; + /* Wep key size if 13 bytes (104 bits). */ + WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_13; + /* + * set encryption keys in the CFG database or clear + * those that are not present in this profile. + */ + if (pProfile->Keys.KeyLength[0]) { + qdf_mem_copy(Key0, + pProfile->Keys.KeyMaterial[0], + WNI_CFG_WEP_KEY_LENGTH_13); + Key0Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key0Length = 0; + } + + if (pProfile->Keys.KeyLength[1]) { + qdf_mem_copy(Key1, + pProfile->Keys.KeyMaterial[1], + WNI_CFG_WEP_KEY_LENGTH_13); + Key1Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key1Length = 0; + } + + if (pProfile->Keys.KeyLength[2]) { + qdf_mem_copy(Key2, + pProfile->Keys.KeyMaterial[2], + WNI_CFG_WEP_KEY_LENGTH_13); + Key2Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key2Length = 0; + } + + if (pProfile->Keys.KeyLength[3]) { + qdf_mem_copy(Key3, + pProfile->Keys.KeyMaterial[3], + WNI_CFG_WEP_KEY_LENGTH_13); + Key3Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key3Length = 0; + } + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + case eCSR_ENCRYPT_TYPE_AES_GCMP: + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: +#endif /* FEATURE_WLAN_WAPI */ + /* + * this is the only difference between this function and + * the csr_set_cfg_privacyFromProfile(). + * (setting of the privacy CFG based on the advertised + * privacy setting from AP for WPA/WAPI associations). + */ + PrivacyEnabled = (0 != fPrivacy); + /* turn on RSN enabled for WPA associations */ + RsnEnabled = 1; + /* clear static WEP keys that may be hanging around. */ + Key0Length = 0; + Key1Length = 0; + Key2Length = 0; + Key3Length = 0; + break; + default: + PrivacyEnabled = 0; + RsnEnabled = 0; + break; + } + + cfg_set_int(pMac, WNI_CFG_PRIVACY_ENABLED, PrivacyEnabled); + cfg_set_int(pMac, WNI_CFG_RSN_ENABLED, RsnEnabled); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, Key0Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, Key1Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, Key2Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, Key3Length); + cfg_set_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, WepDefaultKeyId); +} + +static void csr_set_cfg_ssid(tpAniSirGlobal pMac, tSirMacSSid *pSSID) +{ + uint32_t len = 0; + + if (pSSID->length <= WNI_CFG_SSID_LEN) + len = pSSID->length; + cfg_set_str(pMac, WNI_CFG_SSID, (uint8_t *) pSSID->ssId, len); +} + +static QDF_STATUS csr_set_qos_to_cfg(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrMediaAccessType qosType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t QoSEnabled; + uint32_t WmeEnabled; + /* set the CFG enable/disable variables based on the + * qosType being configured. + */ + switch (qosType) { + case eCSR_MEDIUM_ACCESS_WMM_eDCF_802dot1p: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_WMM_eDCF_NoClassify: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_11e_eDCF: + QoSEnabled = true; + WmeEnabled = false; + break; + case eCSR_MEDIUM_ACCESS_11e_HCF: + QoSEnabled = true; + WmeEnabled = false; + break; + default: + case eCSR_MEDIUM_ACCESS_DCF: + QoSEnabled = false; + WmeEnabled = false; + break; + } + /* save the WMM setting for later use */ + pMac->roam.roamSession[sessionId].fWMMConnection = (bool) WmeEnabled; + pMac->roam.roamSession[sessionId].fQOSConnection = (bool) QoSEnabled; + return status; +} + +static QDF_STATUS csr_get_rate_set(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + eCsrPhyMode phyMode, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + tSirMacRateSet *pOpRateSet, + tSirMacRateSet *pExRateSet) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i; + enum csr_cfgdot11mode cfgDot11Mode; + uint8_t *pDstRate; + uint16_t rateBitmap = 0; + + qdf_mem_zero(pOpRateSet, sizeof(tSirMacRateSet)); + qdf_mem_zero(pExRateSet, sizeof(tSirMacRateSet)); + QDF_ASSERT(pIes != NULL); + + if (NULL == pIes) { + sme_err("failed to parse BssDesc"); + return status; + } + + csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile, + &cfgDot11Mode, pIes); + /* + * 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. + */ + pDstRate = pOpRateSet->rate; + if (pIes->SuppRates.present) { + for (i = 0; i < pIes->SuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported(pMac, + pIes->SuppRates.rates[i]) && + !csr_check_rate_bitmap( + pIes->SuppRates.rates[i], + rateBitmap)) { + csr_add_rate_bitmap(pIes->SuppRates. + rates[i], &rateBitmap); + *pDstRate++ = pIes->SuppRates.rates[i]; + pOpRateSet->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 (pIes->ExtSuppRates.present) { + pDstRate = pExRateSet->rate; + for (i = 0; i < pIes->ExtSuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported(pMac, + pIes->ExtSuppRates.rates[i]) && + !csr_check_rate_bitmap( + pIes->ExtSuppRates.rates[i], + rateBitmap)) { + *pDstRate++ = pIes->ExtSuppRates.rates[i]; + pExRateSet->numRates++; + } + } + } + if (pOpRateSet->numRates > 0 || pExRateSet->numRates > 0) + status = QDF_STATUS_SUCCESS; + return status; +} + +static void csr_set_cfg_rate_set(tpAniSirGlobal pMac, eCsrPhyMode phyMode, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + int i; + uint8_t *pDstRate; + enum csr_cfgdot11mode cfgDot11Mode; + /* leave enough room for the max number of rates */ + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint32_t OperationalRatesLength = 0; + /* leave enough room for the max number of rates */ + uint8_t ExtendedOperationalRates + [CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + uint32_t ExtendedOperationalRatesLength = 0; + uint8_t MCSRateIdxSet[SIZE_OF_SUPPORTED_MCS_SET]; + uint32_t MCSRateLength = 0; + + QDF_ASSERT(pIes != NULL); + if (NULL != pIes) { + csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile, + &cfgDot11Mode, pIes); + /* 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 have 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: + */ + pDstRate = OperationalRates; + if (pIes->SuppRates.present) { + for (i = 0; i < pIes->SuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported + (pMac, pIes->SuppRates.rates[i]) + && (OperationalRatesLength < + CSR_DOT11_SUPPORTED_RATES_MAX)) { + *pDstRate++ = pIes->SuppRates.rates[i]; + OperationalRatesLength++; + } + } + } + if (eCSR_CFG_DOT11_MODE_11G == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_11N == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_ABG == cfgDot11Mode) { + /* If there are Extended Rates in the beacon, we will + * reflect those extended rates that we support in out + * Extended Operational Rate set: + */ + pDstRate = ExtendedOperationalRates; + if (pIes->ExtSuppRates.present) { + for (i = 0; i < pIes->ExtSuppRates.num_rates; + i++) { + if (csr_rates_is_dot11_rate_supported + (pMac, pIes->ExtSuppRates. + rates[i]) + && (ExtendedOperationalRatesLength < + CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX)) { + *pDstRate++ = + pIes->ExtSuppRates. + rates[i]; + ExtendedOperationalRatesLength++; + } + } + } + } + /* Enable proprietary MAC features if peer node is Airgo node + * and STA user wants to use them For ANI network companions, + * we need to populate the proprietary rate set with any + * proprietary rates we found in the beacon, only if user allows + * them. + */ + /* No proprietary modes... */ + /* Get MCS Rate */ + pDstRate = MCSRateIdxSet; + if (pIes->HTCaps.present) { + for (i = 0; i < VALID_MAX_MCS_INDEX; i++) { + if ((unsigned int)pIes->HTCaps. + supportedMCSSet[0] & (1 << i)) { + MCSRateLength++; + *pDstRate++ = i; + } + } + } + /* Set the operational rate set CFG variables... */ + cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET, + OperationalRates, OperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedOperationalRates, + ExtendedOperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_CURRENT_MCS_SET, MCSRateIdxSet, + MCSRateLength); + } /* Parsing BSSDesc */ + else + sme_err("failed to parse BssDesc"); +} + +static void csr_set_cfg_rate_set_from_profile(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile) +{ + tSirMacRateSetIE DefaultSupportedRates11a = { SIR_MAC_RATESET_EID, + {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} } }; + tSirMacRateSetIE DefaultSupportedRates11b = { SIR_MAC_RATESET_EID, + {4, + {SIR_MAC_RATE_1, + SIR_MAC_RATE_2, + SIR_MAC_RATE_5_5, + SIR_MAC_RATE_11} } }; + enum csr_cfgdot11mode cfgDot11Mode; + enum band_info eBand; + /* leave enough room for the max number of rates */ + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint32_t OperationalRatesLength = 0; + /* leave enough room for the max number of rates */ + uint8_t ExtendedOperationalRates + [CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + uint32_t ExtendedOperationalRatesLength = 0; + uint8_t operationChannel = 0; + + if (pProfile->ChannelInfo.ChannelList) + operationChannel = pProfile->ChannelInfo.ChannelList[0]; + cfgDot11Mode = csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, + operationChannel, + &eBand); + /* For 11a networks, the 11a rates go into the Operational Rate set. + * For 11b and 11g networks, the 11b rates appear in the Operational + * Rate set. In either case, we can blindly put the rates we support + * into our Operational Rate set (including the basic rates, which we + * have already verified are supported earlier in the roaming decision). + */ + if (BAND_5G == eBand) { + /* 11a rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11a.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11a.supportedRateSet.rate); + qdf_mem_copy(OperationalRates, + DefaultSupportedRates11a.supportedRateSet.rate, + OperationalRatesLength); + + /* Nothing in the Extended rate set. */ + ExtendedOperationalRatesLength = 0; + } else if (eCSR_CFG_DOT11_MODE_11B == cfgDot11Mode) { + /* 11b rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11b.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11b.supportedRateSet.rate); + qdf_mem_copy(OperationalRates, + DefaultSupportedRates11b.supportedRateSet.rate, + OperationalRatesLength); + /* Nothing in the Extended rate set. */ + ExtendedOperationalRatesLength = 0; + } else { + /* 11G */ + + /* 11b rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11b.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11b.supportedRateSet.rate); + qdf_mem_copy(OperationalRates, + DefaultSupportedRates11b.supportedRateSet.rate, + OperationalRatesLength); + + /* 11a rates go in the Extended rate set. */ + ExtendedOperationalRatesLength = + DefaultSupportedRates11a.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11a.supportedRateSet.rate); + qdf_mem_copy(ExtendedOperationalRates, + DefaultSupportedRates11a.supportedRateSet.rate, + ExtendedOperationalRatesLength); + } + + /* Set the operational rate set CFG variables... */ + cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET, OperationalRates, + OperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedOperationalRates, + ExtendedOperationalRatesLength); +} + +void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result, + uint8_t session_id) +{ + tListElem *pEntry = + csr_nonscan_active_ll_peek_head(pMac, LL_ACCESS_LOCK); + uint32_t sessionId; + tSmeCmd *pCommand = NULL; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + struct csr_roam_session *pSession = NULL; +#endif + if (NULL == pEntry) { + sme_err("CFG_CNF with active list empty"); + return; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sessionId = pCommand->sessionId; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pSession = &pMac->roam.roamSession[sessionId]; + if (pSession->roam_synch_in_progress) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR3:csr_roam_cfg_set_callback"); + } +#endif + + if (CSR_IS_ROAM_JOINING(pMac, sessionId) + && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) { + csr_roaming_state_config_cnf_processor(pMac, pCommand, + (uint32_t) result, session_id); + } +} + +/* pIes may be NULL */ +QDF_STATUS csr_roam_set_bss_config_cfg(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc, + struct bss_config_param *pBssConfig, + struct sDot11fBeaconIEs *pIes, + bool resetCountry) +{ + QDF_STATUS status; + uint32_t cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + uint8_t channel = 0; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* Make sure we have the domain info for the BSS we try to connect to. + * Do we need to worry about sequence for OSs that are not Windows?? + */ + if (pBssDesc) { + if ((QDF_SAP_MODE != + csr_get_session_persona(pMac, sessionId)) && + csr_learn_11dcountry_information( + pMac, pBssDesc, pIes, true)) { + csr_apply_country_information(pMac); + } + if ((wlan_reg_11d_enabled_on_host(pMac->psoc)) && pIes) { + if (!pIes->Country.present) + csr_apply_channel_power_info_wrapper(pMac); + } + } + /* Qos */ + csr_set_qos_to_cfg(pMac, sessionId, pBssConfig->qosType); + /* SSID */ + csr_set_cfg_ssid(pMac, &pBssConfig->SSID); + + /* Auth type */ + cfg_set_int(pMac, WNI_CFG_AUTHENTICATION_TYPE, pBssConfig->authType); + /* encryption type */ + csr_set_cfg_privacy(pMac, pProfile, (bool) pBssConfig->BssCap.privacy); + /* short slot time */ + cfg_set_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + pBssConfig->uShortSlotTime); + /* 11d */ + cfg_set_int(pMac, WNI_CFG_11D_ENABLED, + ((pBssConfig->f11hSupport) ? pBssConfig->f11hSupport : + pProfile->ieee80211d)); + cfg_set_int(pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + pBssConfig->uPowerLimit); + /* CB */ + + if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_IBSS(pProfile)) + channel = pProfile->operationChannel; + else if (pBssDesc) + channel = pBssDesc->channelId; + if (0 != channel) { + /* for now if we are on 2.4 Ghz, CB will be always disabled */ + if (WLAN_REG_IS_24GHZ_CH(channel)) + cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + else + cfgCb = pBssConfig->cbMode; + } + /* Rate */ + /* Fixed Rate */ + if (pBssDesc) + csr_set_cfg_rate_set(pMac, (eCsrPhyMode) pProfile->phyMode, + pProfile, pBssDesc, pIes); + else + csr_set_cfg_rate_set_from_profile(pMac, pProfile); + status = cfg_set_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + pBssConfig->uJoinTimeOut); + /* Any roaming related changes should be above this line */ + if (pSession && pSession->roam_synch_in_progress) { + sme_debug("Roam synch is in progress Session_id: %d", + sessionId); + return QDF_STATUS_SUCCESS; + } + /* Make this the last CFG to set. The callback will trigger a + * join_req Join time out + */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_CONFIG, sessionId); + + csr_roam_ccm_cfg_set_callback(pMac, status, sessionId); + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS csr_roam_stop_network(tpAniSirGlobal mac, uint32_t sessionId, + struct csr_roam_profile *roam_profile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status; + struct bss_config_param *pBssConfig; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + pBssConfig = qdf_mem_malloc(sizeof(struct bss_config_param)); + if (NULL == pBssConfig) + return QDF_STATUS_E_NOMEM; + + sme_debug("session id: %d", sessionId); + + status = csr_roam_prepare_bss_config(mac, roam_profile, pBssDesc, + pBssConfig, pIes); + if (QDF_IS_STATUS_SUCCESS(status)) { + enum csr_roam_substate substate; + + substate = eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING; + pSession->bssParams.uCfgDot11Mode = pBssConfig->uCfgDot11Mode; + /* This will allow to pass cbMode during join req */ + pSession->bssParams.cbMode = pBssConfig->cbMode; + /* For IBSS, we need to prepare some more information */ + if (csr_is_bss_type_ibss(roam_profile->BSSType) || + CSR_IS_INFRA_AP(roam_profile)) + csr_roam_prepare_bss_params(mac, sessionId, + roam_profile, pBssDesc, + pBssConfig, pIes); + /* + * If we are in an IBSS, then stop the IBSS... + * Not worry about WDS connection for now + */ + if (csr_is_conn_state_ibss(mac, sessionId)) { + status = csr_roam_issue_stop_bss(mac, sessionId, + substate); + } else if (csr_is_conn_state_infra(mac, sessionId)) { + /* + * the new Bss is an Ibss OR we are roaming from + * Infra to Infra across SSIDs + * (roaming to a new SSID)... + * Not worry about WDS connection for now + */ + if (pBssDesc && + (csr_is_ibss_bss_desc(pBssDesc) || + !csr_is_ssid_equal(mac, pSession->pConnectBssDesc, + pBssDesc, pIes))) + status = csr_roam_issue_disassociate(mac, + sessionId, substate, false); + else if (pBssDesc) + /* + * In an infra & going to an infra network with + * the same SSID. This calls for a reassoc seq. + * So issue the CFG sets for this new AP. Set + * parameters for this Bss. + */ + status = csr_roam_set_bss_config_cfg( + mac, sessionId, roam_profile, + pBssDesc, pBssConfig, pIes, + false); + } else if (pBssDesc || CSR_IS_INFRA_AP(roam_profile)) { + /* + * Neither in IBSS nor in Infra. We can go ahead and set + * the cfg for tne new network... nothing to stop. + */ + bool is_11r_roaming = false; + + is_11r_roaming = csr_roam_is11r_assoc(mac, sessionId); + /* Set parameters for this Bss. */ + status = csr_roam_set_bss_config_cfg(mac, sessionId, + roam_profile, + pBssDesc, + pBssConfig, pIes, + is_11r_roaming); + } + } /* Success getting BSS config info */ + qdf_mem_free(pBssConfig); + return status; +} + +/** + * csr_roam_state_for_same_profile() - Determine roam state for same profile + * @mac_ctx: pointer to mac context + * @profile: Roam profile + * @session: Roam session + * @session_id: session id + * @ies_local: local ies + * @bss_descr: bss description + * + * This function will determine the roam state for same profile + * + * Return: Roaming state. + */ +static enum csr_join_state csr_roam_state_for_same_profile( + tpAniSirGlobal mac_ctx, struct csr_roam_profile *profile, + struct csr_roam_session *session, + uint32_t session_id, tDot11fBeaconIEs *ies_local, + tSirBssDescription *bss_descr) +{ + QDF_STATUS status; + struct bss_config_param bssConfig; + + if (csr_roam_is_same_profile_keys(mac_ctx, &session->connectedProfile, + profile)) + return eCsrReassocToSelfNoCapChange; + /* The key changes */ + qdf_mem_zero(&bssConfig, sizeof(bssConfig)); + status = csr_roam_prepare_bss_config(mac_ctx, profile, bss_descr, + &bssConfig, ies_local); + if (QDF_IS_STATUS_SUCCESS(status)) { + session->bssParams.uCfgDot11Mode = + bssConfig.uCfgDot11Mode; + session->bssParams.cbMode = + bssConfig.cbMode; + /* reapply the cfg including keys so reassoc happens. */ + status = csr_roam_set_bss_config_cfg(mac_ctx, session_id, + profile, bss_descr, &bssConfig, + ies_local, false); + if (QDF_IS_STATUS_SUCCESS(status)) + return eCsrContinueRoaming; + } + + return eCsrStopRoaming; + +} + +static enum csr_join_state csr_roam_join(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrScanResultInfo *pScanResult, + struct csr_roam_profile *pProfile) +{ + enum csr_join_state eRoamState = eCsrContinueRoaming; + tSirBssDescription *pBssDesc = &pScanResult->BssDescriptor; + tDot11fBeaconIEs *pIesLocal = (tDot11fBeaconIEs *) (pScanResult->pvIes); + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return eCsrStopRoaming; + } + + if (!pIesLocal && + !QDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies(pMac, + pBssDesc, &pIesLocal))) { + sme_err("fail to parse IEs"); + return eCsrStopRoaming; + } + if (csr_is_infra_bss_desc(pBssDesc)) { + /* + * If we are connected in infra mode and the join bss descr is + * for the same BssID, then we are attempting to join the AP we + * are already connected with. In that case, see if the Bss or + * sta capabilities have changed and handle the changes + * without disturbing the current association + */ + + if (csr_is_conn_state_connected_infra(pMac, sessionId) && + csr_is_bss_id_equal(pBssDesc, + pSession->pConnectBssDesc) && + csr_is_ssid_equal(pMac, pSession->pConnectBssDesc, + pBssDesc, pIesLocal)) { + /* + * Check to see if the Auth type has changed in the + * profile. If so, we don't want to reassociate with + * authenticating first. To force this, stop the + * current association (Disassociate) and then re 'Join' + * the AP, wihch will force an Authentication (with the + * new Auth type) followed by a new Association. + */ + if (csr_is_same_profile(pMac, + &pSession->connectedProfile, pProfile)) { + sme_warn("detect same profile"); + eRoamState = + csr_roam_state_for_same_profile(pMac, + pProfile, pSession, sessionId, + pIesLocal, pBssDesc); + } else if (!QDF_IS_STATUS_SUCCESS( + csr_roam_issue_disassociate( + pMac, + sessionId, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + false))) { + sme_err("fail disassoc session %d", + sessionId); + eRoamState = eCsrStopRoaming; + } + } else if (!QDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac, + sessionId, pProfile, pBssDesc, pIesLocal))) + /* we used to pre-auth here with open auth + * networks but that wasn't working so well. + * stop the existing network before attempting + * to join the new network. + */ + eRoamState = eCsrStopRoaming; + } else if (!QDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac, sessionId, + pProfile, pBssDesc, + pIesLocal))) + eRoamState = eCsrStopRoaming; + + if (pIesLocal && !pScanResult->pvIes) + qdf_mem_free(pIesLocal); + return eRoamState; +} + +static +QDF_STATUS csr_roam_should_roam(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc, uint32_t roamId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info roamInfo; + + qdf_mem_zero(&roamInfo, sizeof(struct csr_roam_info)); + roamInfo.pBssDesc = pBssDesc; + status = csr_roam_call_callback(pMac, sessionId, &roamInfo, roamId, + eCSR_ROAM_SHOULD_ROAM, eCSR_ROAM_RESULT_NONE); + return status; +} + +/* In case no matching BSS is found, use whatever default we can find */ +static void csr_roam_assign_default_param(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + /* Need to get all negotiated types in place first */ + /* auth type */ + /* Take the preferred Auth type. */ + switch (pCommand->u.roamCmd.roamProfile.AuthType.authType[0]) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + + case eCSR_AUTH_TYPE_SHARED_KEY: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_SHARED_KEY; + break; + + case eCSR_AUTH_TYPE_AUTOSWITCH: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_AUTOSWITCH; + break; + + case eCSR_AUTH_TYPE_SAE: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_SAE; + break; + } + pCommand->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + pCommand->u.roamCmd.roamProfile.EncryptionType. + encryptionType[0]; + /* In this case, the multicast encryption needs to follow the + * uncast ones. + */ + pCommand->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + pCommand->u.roamCmd.roamProfile.EncryptionType. + encryptionType[0]; +} + +/** + * csr_roam_select_bss() - Handle join scenario based on profile + * @mac_ctx: Global MAC Context + * @roam_bss_entry: The next BSS to join + * @csr_result_info: Result of join + * @csr_scan_result: Global scan result + * @session_id: SME Session ID + * @roam_id: Roaming ID + * @roam_state: Current roaming state + * @bss_list: BSS List + * + * Return: true if the entire BSS list is done, false otherwise. + */ +static bool csr_roam_select_bss(tpAniSirGlobal mac_ctx, + tListElem **roam_bss_entry, tCsrScanResultInfo **csr_result_info, + struct tag_csrscan_result **csr_scan_result, + uint32_t session_id, uint32_t roam_id, + enum csr_join_state *roam_state, + struct scan_result_list *bss_list) +{ + uint8_t conc_channel = 0; + bool status = false; + struct tag_csrscan_result *scan_result = NULL; + tCsrScanResultInfo *result = NULL; + + while (*roam_bss_entry) { + scan_result = GET_BASE_ADDR(*roam_bss_entry, struct + tag_csrscan_result, Link); + /* + * If concurrency enabled take the + * concurrent connected channel first. + * Valid multichannel concurrent + * sessions exempted + */ + result = &scan_result->Result; + + /* + * check if channel is allowed for current hw mode, if not fetch + * next BSS. + */ + if (!policy_mgr_is_hwmode_set_for_given_chnl(mac_ctx->psoc, + result->BssDescriptor.channelId)) { + sme_err("HW mode is not properly set for channel %d BSSID %pM", + result->BssDescriptor.channelId, + result->BssDescriptor.bssId); + *roam_state = eCsrStopRoamingDueToConcurrency; + status = true; + *roam_bss_entry = csr_ll_next(&bss_list->List, + *roam_bss_entry, + LL_ACCESS_LOCK); + continue; + } + if (policy_mgr_concurrent_open_sessions_running(mac_ctx->psoc) + && !csr_is_valid_mc_concurrent_session(mac_ctx, + session_id, &result->BssDescriptor)) { + conc_channel = csr_get_concurrent_operation_channel( + mac_ctx); + sme_debug("csr Conc Channel: %d", conc_channel); + if ((conc_channel) && (conc_channel == + result->BssDescriptor.channelId)) { + /* + * make this 0 because we do not want the below + * check to pass as we don't want to connect on + * other channel + */ + sme_debug("Conc chnl match: %d", conc_channel); + conc_channel = 0; + } + } + + /* Ok to roam this */ + if (!conc_channel && + QDF_IS_STATUS_SUCCESS(csr_roam_should_roam(mac_ctx, + session_id, &result->BssDescriptor, roam_id))) { + status = false; + break; + } + *roam_state = eCsrStopRoamingDueToConcurrency; + status = true; + *roam_bss_entry = csr_ll_next(&bss_list->List, *roam_bss_entry, + LL_ACCESS_LOCK); + } + *csr_result_info = result; + *csr_scan_result = scan_result; + return status; +} + +/** + * csr_roam_join_handle_profile() - Handle join scenario based on profile + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * @cmd: Command + * @roam_info_ptr: Pointed to the roaming info for join + * @roam_state: Current roaming state + * @result: Result of join + * @scan_result: Global scan result + * + * Return: None + */ +static void csr_roam_join_handle_profile(tpAniSirGlobal mac_ctx, + uint32_t session_id, tSmeCmd *cmd, + struct csr_roam_info *roam_info_ptr, + enum csr_join_state *roam_state, tCsrScanResultInfo *result, + struct tag_csrscan_result *scan_result) +{ +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + uint8_t acm_mask = 0; +#endif + QDF_STATUS status; + struct csr_roam_session *session; + struct csr_roam_profile *profile = &cmd->u.roamCmd.roamProfile; + tDot11fBeaconIEs *ies_local = NULL; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("Invalid session id %d", session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + /* + * We have something to roam, tell HDD when it is infra. + * For IBSS, the indication goes back to HDD via eCSR_ROAM_IBSS_IND + */ + if (CSR_IS_INFRASTRUCTURE(profile) && roam_info_ptr) { + if (session->bRefAssocStartCnt) { + session->bRefAssocStartCnt--; + roam_info_ptr->pProfile = profile; + /* + * Complete the last assoc attempt as a + * new one is about to be tried + */ + csr_roam_call_callback(mac_ctx, session_id, + roam_info_ptr, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + } + + qdf_mem_zero(roam_info_ptr, sizeof(struct csr_roam_info)); + if (!scan_result) + cmd->u.roamCmd.roamProfile.uapsd_mask = 0; + else + ies_local = scan_result->Result.pvIes; + + if (!result) { + sme_err(" cannot parse IEs"); + *roam_state = eCsrStopRoaming; + return; + } else if (scan_result && !ies_local && + (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + mac_ctx, &result->BssDescriptor, + &ies_local)))) { + sme_err(" cannot parse IEs"); + *roam_state = eCsrStopRoaming; + return; + } + roam_info_ptr->pBssDesc = &result->BssDescriptor; + cmd->u.roamCmd.pLastRoamBss = roam_info_ptr->pBssDesc; + /* dont put uapsd_mask if BSS doesn't support uAPSD */ + if (scan_result && cmd->u.roamCmd.roamProfile.uapsd_mask + && CSR_IS_QOS_BSS(ies_local) + && CSR_IS_UAPSD_BSS(ies_local)) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = sme_qos_get_acm_mask(mac_ctx, + &result->BssDescriptor, ies_local); +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + } else { + cmd->u.roamCmd.roamProfile.uapsd_mask = 0; + } + if (ies_local && !scan_result->Result.pvIes) + qdf_mem_free(ies_local); + roam_info_ptr->pProfile = profile; + session->bRefAssocStartCnt++; + csr_roam_call_callback(mac_ctx, session_id, roam_info_ptr, + cmd->u.roamCmd.roamId, eCSR_ROAM_ASSOCIATION_START, + eCSR_ROAM_RESULT_NONE); + } + if (NULL != cmd->u.roamCmd.pRoamBssEntry) { + /* + * We have BSS + * Need to assign these value because + * they are used in csr_is_same_profile + */ + scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + struct tag_csrscan_result, Link); + /* + * The OSEN IE doesn't provide the cipher suite.Therefore set + * to constant value of AES + */ + if (cmd->u.roamCmd.roamProfile.bOSENAssociation) { + cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_AES; + cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + eCSR_ENCRYPT_TYPE_AES; + } else { + /* Negotiated while building scan result. */ + cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + scan_result->ucEncryptionType; + cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + scan_result->mcEncryptionType; + } + cmd->u.roamCmd.roamProfile.negotiatedAuthType = + scan_result->authType; + if (CSR_IS_START_IBSS(&cmd->u.roamCmd.roamProfile)) { + if (csr_is_same_profile(mac_ctx, + &session->connectedProfile, profile)) { + *roam_state = eCsrStartIbssSameIbss; + return; + } + } + if (cmd->u.roamCmd.fReassocToSelfNoCapChange) { + /* trying to connect to the one already connected */ + cmd->u.roamCmd.fReassocToSelfNoCapChange = false; + *roam_state = eCsrReassocToSelfNoCapChange; + return; + } + /* Attempt to Join this Bss... */ + *roam_state = csr_roam_join(mac_ctx, session_id, + &scan_result->Result, profile); + return; + } + + /* For an IBSS profile, then we need to start the IBSS. */ + if (CSR_IS_START_IBSS(profile)) { + bool same_ibss = false; + /* Attempt to start this IBSS... */ + csr_roam_assign_default_param(mac_ctx, cmd); + status = csr_roam_start_ibss(mac_ctx, session_id, + profile, &same_ibss); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (same_ibss) + *roam_state = eCsrStartIbssSameIbss; + else + *roam_state = eCsrContinueRoaming; + } else { + /* it somehow fail need to stop */ + *roam_state = eCsrStopRoaming; + } + return; + } else if (CSR_IS_INFRA_AP(profile)) { + /* Attempt to start this WDS... */ + csr_roam_assign_default_param(mac_ctx, cmd); + /* For AP WDS, we dont have any BSSDescription */ + status = csr_roam_start_wds(mac_ctx, session_id, profile, NULL); + if (QDF_IS_STATUS_SUCCESS(status)) + *roam_state = eCsrContinueRoaming; + else + *roam_state = eCsrStopRoaming; + } else if (CSR_IS_NDI(profile)) { + csr_roam_assign_default_param(mac_ctx, cmd); + status = csr_roam_start_ndi(mac_ctx, session_id, profile); + if (QDF_IS_STATUS_SUCCESS(status)) + *roam_state = eCsrContinueRoaming; + else + *roam_state = eCsrStopRoaming; + } else { + /* Nothing we can do */ + sme_warn("cannot continue without BSS list"); + *roam_state = eCsrStopRoaming; + return; + } + +} +/** + * csr_roam_join_next_bss() - Pick the next BSS for join + * @mac_ctx: Global MAC Context + * @cmd: Command + * @use_same_bss: Use Same BSS to Join + * + * Return: The Join State + */ +static enum csr_join_state csr_roam_join_next_bss(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, bool use_same_bss) +{ + struct tag_csrscan_result *scan_result = NULL; + enum csr_join_state roam_state = eCsrStopRoaming; + struct scan_result_list *bss_list = + (struct scan_result_list *) cmd->u.roamCmd.hBSSList; + bool done = false; + struct csr_roam_info *roam_info = NULL; + uint32_t session_id = cmd->sessionId; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + struct csr_roam_profile *profile = &cmd->u.roamCmd.roamProfile; + struct csr_roam_joinstatus *join_status; + tCsrScanResultInfo *result = NULL; + + if (!session) { + sme_err("session %d not found", session_id); + return eCsrStopRoaming; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) { + sme_err("failed to allocate memory"); + return eCsrStopRoaming; + } + qdf_mem_copy(&roam_info->bssid, &session->joinFailStatusCode.bssId, + sizeof(tSirMacAddr)); + /* + * When handling AP's capability change, continue to associate + * to same BSS and make sure pRoamBssEntry is not Null. + */ + if ((NULL != bss_list) && + ((false == use_same_bss) || + (cmd->u.roamCmd.pRoamBssEntry == NULL))) { + if (cmd->u.roamCmd.pRoamBssEntry == NULL) { + /* Try the first BSS */ + cmd->u.roamCmd.pLastRoamBss = NULL; + cmd->u.roamCmd.pRoamBssEntry = + csr_ll_peek_head(&bss_list->List, + LL_ACCESS_LOCK); + } else { + cmd->u.roamCmd.pRoamBssEntry = + csr_ll_next(&bss_list->List, + cmd->u.roamCmd.pRoamBssEntry, + LL_ACCESS_LOCK); + /* + * Done with all the BSSs. + * In this case, will tell HDD the + * completion + */ + if (NULL == cmd->u.roamCmd.pRoamBssEntry) + goto end; + /* + * We need to indicate to HDD that we + * are done with this one. + */ + roam_info->pBssDesc = cmd->u.roamCmd.pLastRoamBss; + join_status = &session->joinFailStatusCode; + roam_info->statusCode = join_status->statusCode; + roam_info->reasonCode = join_status->reasonCode; + } + done = csr_roam_select_bss(mac_ctx, + &cmd->u.roamCmd.pRoamBssEntry, &result, + &scan_result, session_id, cmd->u.roamCmd.roamId, + &roam_state, bss_list); + if (done) + goto end; + } + roam_info->u.pConnectedProfile = &session->connectedProfile; + + csr_roam_join_handle_profile(mac_ctx, session_id, cmd, roam_info, + &roam_state, result, scan_result); +end: + if ((eCsrStopRoaming == roam_state) && CSR_IS_INFRASTRUCTURE(profile) && + (session->bRefAssocStartCnt > 0)) { + /* + * Need to indicate association_completion if association_start + * has been done + */ + session->bRefAssocStartCnt--; + /* + * Complete the last assoc attempte as a + * new one is about to be tried + */ + roam_info->pProfile = profile; + csr_roam_call_callback(mac_ctx, session_id, + roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + } + qdf_mem_free(roam_info); + + return roam_state; +} + +static QDF_STATUS csr_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum csr_join_state RoamState; + enum csr_roam_substate substate; + uint32_t sessionId = pCommand->sessionId; + + /* Attept to join a Bss... */ + RoamState = csr_roam_join_next_bss(pMac, pCommand, false); + + /* if nothing to join.. */ + if ((eCsrStopRoaming == RoamState) || + (eCsrStopRoamingDueToConcurrency == RoamState)) { + bool fComplete = false; + /* and if connected in Infrastructure mode... */ + if (csr_is_conn_state_infra(pMac, sessionId)) { + /* ... then we need to issue a disassociation */ + substate = eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN; + status = csr_roam_issue_disassociate(pMac, sessionId, + substate, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_warn("fail issuing disassoc status = %d", + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_warn("fail issuing stop bss status = %d", + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else if (csr_is_conn_state_connected_infra_ap(pMac, + sessionId)) { + substate = eCSR_ROAM_SUBSTATE_STOP_BSS_REQ; + status = csr_roam_issue_stop_bss(pMac, sessionId, + substate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_warn("fail issuing stop bss status = %d", + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else { + fComplete = true; + } + + if (fComplete) { + /* otherwise, we can complete the Roam command here. */ + if (eCsrStopRoamingDueToConcurrency == RoamState) + csr_roam_complete(pMac, + eCsrJoinFailureDueToConcurrency, NULL, + sessionId); + else + csr_roam_complete(pMac, + eCsrNothingToJoin, NULL, sessionId); + } + } else if (eCsrReassocToSelfNoCapChange == RoamState) { + csr_roam_complete(pMac, eCsrSilentlyStopRoamingSaveState, + NULL, sessionId); + } else if (eCsrStartIbssSameIbss == RoamState) { + csr_roam_complete(pMac, eCsrSilentlyStopRoaming, NULL, + sessionId); + } + + return status; +} + +static +QDF_STATUS csr_process_ft_reassoc_roam_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + uint32_t sessionId; + struct csr_roam_session *pSession; + struct tag_csrscan_result *pScanResult = NULL; + tSirBssDescription *pBssDesc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sessionId = pCommand->sessionId; + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (CSR_IS_ROAMING(pSession) && pSession->fCancelRoaming) { + /* the roaming is cancelled. Simply complete the command */ + sme_debug("Roam command canceled"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, sessionId); + return QDF_STATUS_E_FAILURE; + } + if (pCommand->u.roamCmd.pRoamBssEntry) { + pScanResult = + GET_BASE_ADDR(pCommand->u.roamCmd.pRoamBssEntry, + struct tag_csrscan_result, Link); + pBssDesc = &pScanResult->Result.BssDescriptor; + } else { + /* the roaming is cancelled. Simply complete the command */ + sme_debug("Roam command canceled"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, sessionId); + return QDF_STATUS_E_FAILURE; + } + status = csr_roam_issue_reassociate(pMac, sessionId, pBssDesc, + (tDot11fBeaconIEs *) (pScanResult-> + Result.pvIes), + &pCommand->u.roamCmd.roamProfile); + return status; +} + +/** + * csr_roam_trigger_reassociate() - Helper function to trigger reassociate + * @mac_ctx: pointer to mac context + * @cmd: sme command + * @roam_info: Roaming infor structure + * @session_ptr: session pointer + * @session_id: session id + * + * This function will trigger reassociate. + * + * Return: QDF_STATUS for success or failure. + */ +static QDF_STATUS csr_roam_trigger_reassociate( +tpAniSirGlobal mac_ctx, tSmeCmd *cmd, struct csr_roam_info *roam_info, + struct csr_roam_session *session_ptr, + uint32_t session_id) +{ + tDot11fBeaconIEs *pIes = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (session_ptr->pConnectBssDesc) { + status = csr_get_parsed_bss_description_ies(mac_ctx, + session_ptr->pConnectBssDesc, &pIes); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("fail to parse IEs"); + } else { + roam_info->reasonCode = + eCsrRoamReasonStaCapabilityChanged; + csr_roam_call_callback(mac_ctx, session_ptr->sessionId, + roam_info, 0, eCSR_ROAM_ROAMING_START, + eCSR_ROAM_RESULT_NONE); + session_ptr->roamingReason = eCsrReassocRoaming; + roam_info->pBssDesc = session_ptr->pConnectBssDesc; + roam_info->pProfile = &cmd->u.roamCmd.roamProfile; + session_ptr->bRefAssocStartCnt++; + csr_roam_call_callback(mac_ctx, session_id, roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_START, + eCSR_ROAM_RESULT_NONE); + + sme_debug("calling csr_roam_issue_reassociate"); + status = csr_roam_issue_reassociate(mac_ctx, session_id, + session_ptr->pConnectBssDesc, pIes, + &cmd->u.roamCmd.roamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("failed status %d", status); + csr_release_command(mac_ctx, cmd); + } else { + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, + session_id); + } + + + qdf_mem_free(pIes); + pIes = NULL; + } + } else { + sme_err("reassoc to same AP failed as connected BSS is NULL"); + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +/** + * csr_allow_concurrent_sta_connections() - Wrapper for policy_mgr api + * @mac: mac context + * @vdev_id: vdev id + * + * This function invokes policy mgr api to check for support of + * simultaneous connections on concurrent STA interfaces. + * + * Return: If supports return true else false. + */ +static +bool csr_allow_concurrent_sta_connections(tpAniSirGlobal mac, + uint32_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE vdev_mode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + sme_err("vdev object not found for vdev_id %u", vdev_id); + return false; + } + vdev_mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + /* If vdev mode is STA then proceed further */ + if (vdev_mode != QDF_STA_MODE) + return true; + + if (policy_mgr_allow_concurrency(mac->psoc, PM_STA_MODE, 0, + HW_MODE_20_MHZ)) + return true; + + return false; +} + + +QDF_STATUS csr_roam_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + struct csr_roam_info roamInfo; + QDF_STATUS lock_status, status = QDF_STATUS_SUCCESS; + uint32_t sessionId = pCommand->sessionId; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + 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); + + pSession->disconnect_reason = pCommand->u.roamCmd.disconnect_reason; + + switch (pCommand->u.roamCmd.roamReason) { + case eCsrForcedDisassoc: + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, false); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + sessionId); + return lock_status; + } + csr_free_roam_profile(pMac, sessionId); + sme_release_global_lock(&pMac->sme); + break; + case eCsrSmeIssuedDisassocForHandoff: + /* Not to free pMac->roam.pCurRoamProfile (via + * csr_free_roam_profile) because its needed after disconnect + */ + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, false); + + break; + case eCsrForcedDisassocMICFailure: + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, true); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + sessionId); + return lock_status; + } + csr_free_roam_profile(pMac, sessionId); + sme_release_global_lock(&pMac->sme); + break; + case eCsrForcedDeauth: + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + false, false); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + sessionId); + return lock_status; + } + csr_free_roam_profile(pMac, sessionId); + sme_release_global_lock(&pMac->sme); + break; + case eCsrHddIssuedReassocToSameAP: + case eCsrSmeIssuedReassocToSameAP: + status = csr_roam_trigger_reassociate(pMac, pCommand, &roamInfo, + pSession, sessionId); + break; + case eCsrCapsChange: + sme_err("received eCsrCapsChange "); + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + status = csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + break; + case eCsrSmeIssuedFTReassoc: + sme_debug("received FT Reassoc Req"); + status = csr_process_ft_reassoc_roam_command(pMac, pCommand); + break; + + case eCsrStopBss: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + break; + + case eCsrForcedDisassocSta: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + sessionId); + sme_debug("Disassociate issued with reason: %d", + pCommand->u.roamCmd.reason); + status = csr_send_mb_disassoc_req_msg(pMac, sessionId, + pCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.reason); + break; + + case eCsrForcedDeauthSta: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + sessionId); + status = csr_send_mb_deauth_req_msg(pMac, sessionId, + pCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.reason); + break; + + case eCsrPerformPreauth: + sme_debug("Attempting FT PreAuth Req"); + status = csr_roam_issue_ft_preauth_req(pMac, sessionId, + pCommand->u.roamCmd.pLastRoamBss); + break; + + case eCsrHddIssued: + /* + * Check for simultaneous connection support on + * multiple STA interfaces. + */ + if (!csr_allow_concurrent_sta_connections(pMac, sessionId)) { + sme_err("No support of conc STA con"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + sessionId); + status = QDF_STATUS_E_FAILURE; + break; + } + /* Fall through for success case */ + + default: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + + if (pCommand->u.roamCmd.fUpdateCurRoamProfile) { + /* Remember the roaming profile */ + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + sessionId); + return lock_status; + } + csr_free_roam_profile(pMac, sessionId); + pSession->pCurRoamProfile = + qdf_mem_malloc(sizeof(struct csr_roam_profile)); + if (NULL != pSession->pCurRoamProfile) { + csr_roam_copy_profile(pMac, + pSession->pCurRoamProfile, + &pCommand->u.roamCmd.roamProfile); + } + sme_release_global_lock(&pMac->sme); + } + /* + * At this point original uapsd_mask is saved in + * pCurRoamProfile. uapsd_mask in the pCommand may change from + * this point on. Attempt to roam with the new scan results + * (if we need to..) + */ + status = csr_roam(pMac, pCommand); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_warn("csr_roam() failed with status = 0x%08X", + status); + break; + } + return status; +} + +void csr_reinit_roam_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + if (pCommand->u.roamCmd.fReleaseBssList) { + csr_scan_result_purge(pMac, pCommand->u.roamCmd.hBSSList); + pCommand->u.roamCmd.fReleaseBssList = false; + pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + } + if (pCommand->u.roamCmd.fReleaseProfile) { + csr_release_profile(pMac, &pCommand->u.roamCmd.roamProfile); + pCommand->u.roamCmd.fReleaseProfile = false; + } + pCommand->u.roamCmd.pLastRoamBss = NULL; + pCommand->u.roamCmd.pRoamBssEntry = NULL; + /* 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(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + qdf_mem_zero(&pCommand->u.wmStatusChangeCmd, + sizeof(struct wmstatus_changecmd)); +} + +void csr_roam_complete(tpAniSirGlobal mac_ctx, + enum csr_roamcomplete_result Result, + void *Context, 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(mac_ctx, sme_cmd, Result, Context); + csr_release_command(mac_ctx, sme_cmd); + } +} + + +void csr_reset_pmkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session: %d not found", sessionId); + return; + } + qdf_mem_zero(&(pSession->PmkidCandidateInfo[0]), + sizeof(tPmkidCandidateInfo) * CSR_MAX_PMKID_ALLOWED); + pSession->NumPmkidCandidate = 0; +} + +#ifdef FEATURE_WLAN_WAPI +void csr_reset_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session: %d not found", sessionId); + return; + } + qdf_mem_zero(&(pSession->BkidCandidateInfo[0]), + sizeof(tBkidCandidateInfo) * CSR_MAX_BKID_ALLOWED); + pSession->NumBkidCandidate = 0; +} +#endif /* FEATURE_WLAN_WAPI */ + +/** + * csr_roam_save_params() - Helper function to save params + * @mac_ctx: pointer to mac context + * @session_ptr: Session pointer + * @auth_type: auth type + * @ie_ptr: pointer to ie + * @ie_local: pointr to local ie + * + * This function will save params to session + * + * Return: none. + */ +static QDF_STATUS csr_roam_save_params(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session_ptr, + eCsrAuthType auth_type, + tDot11fBeaconIEs *ie_ptr, + tDot11fBeaconIEs *ie_local) +{ + uint32_t nIeLen; + uint8_t *pIeBuf; + + if ((eCSR_AUTH_TYPE_RSN == auth_type) || + (eCSR_AUTH_TYPE_FT_RSN == auth_type) || + (eCSR_AUTH_TYPE_FT_RSN_PSK == auth_type) || +#if defined WLAN_FEATURE_11W + (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == auth_type) || + (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == auth_type) || +#endif + (eCSR_AUTH_TYPE_RSN_PSK == auth_type)) { + if (ie_local->RSN.present) { + tDot11fIERSN *rsnie = &ie_local->RSN; + /* + * Calculate the actual length + * version + gp_cipher_suite + pwise_cipher_suite_count + * + akm_suite_cnt + reserved + pwise_cipher_suites + */ + nIeLen = 8 + 2 + 2 + + (rsnie->pwise_cipher_suite_count * 4) + + (rsnie->akm_suite_cnt * 4); + if (rsnie->pmkid_count) + /* pmkid */ + nIeLen += 2 + rsnie->pmkid_count * 4; + + /* nIeLen doesn't count EID and length fields */ + session_ptr->pWpaRsnRspIE = qdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWpaRsnRspIE) + return QDF_STATUS_E_NOMEM; + + session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_RSN; + session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen; + /* copy upto akm_suite */ + pIeBuf = session_ptr->pWpaRsnRspIE + 2; + qdf_mem_copy(pIeBuf, &rsnie->version, + sizeof(rsnie->version)); + pIeBuf += sizeof(rsnie->version); + qdf_mem_copy(pIeBuf, &rsnie->gp_cipher_suite, + sizeof(rsnie->gp_cipher_suite)); + pIeBuf += sizeof(rsnie->gp_cipher_suite); + qdf_mem_copy(pIeBuf, &rsnie->pwise_cipher_suite_count, + sizeof(rsnie->pwise_cipher_suite_count)); + pIeBuf += sizeof(rsnie->pwise_cipher_suite_count); + if (rsnie->pwise_cipher_suite_count) { + /* copy pwise_cipher_suites */ + qdf_mem_copy(pIeBuf, rsnie->pwise_cipher_suites, + rsnie->pwise_cipher_suite_count * 4); + pIeBuf += rsnie->pwise_cipher_suite_count * 4; + } + qdf_mem_copy(pIeBuf, &rsnie->akm_suite_cnt, 2); + pIeBuf += 2; + if (rsnie->akm_suite_cnt) { + /* copy akm_suite */ + qdf_mem_copy(pIeBuf, rsnie->akm_suite, + rsnie->akm_suite_cnt * 4); + pIeBuf += rsnie->akm_suite_cnt * 4; + } + /* copy the rest */ + qdf_mem_copy(pIeBuf, rsnie->akm_suite + + rsnie->akm_suite_cnt * 4, + 2 + rsnie->pmkid_count * 4); + session_ptr->nWpaRsnRspIeLength = nIeLen + 2; + } + } else if ((eCSR_AUTH_TYPE_WPA == auth_type) || + (eCSR_AUTH_TYPE_WPA_PSK == auth_type)) { + if (ie_local->WPA.present) { + tDot11fIEWPA *wpaie = &ie_local->WPA; + /* Calculate the actual length wpaie */ + nIeLen = 12 + 2 /* auth_suite_count */ + + wpaie->unicast_cipher_count * 4 + + wpaie->auth_suite_count * 4; + + /* The WPA capabilities follows the Auth Suite + * (two octects)-- this field is optional, and + * we always "send" zero, so just remove it. This is + * consistent with our assumptions in the frames + * compiler; nIeLen doesn't count EID & length fields + */ + session_ptr->pWpaRsnRspIE = qdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWpaRsnRspIE) + return QDF_STATUS_E_NOMEM; + session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_WPA; + session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen; + pIeBuf = session_ptr->pWpaRsnRspIE + 2; + /* Copy WPA OUI */ + qdf_mem_copy(pIeBuf, &csr_wpa_oui[1], 4); + pIeBuf += 4; + qdf_mem_copy(pIeBuf, &wpaie->version, + 8 + wpaie->unicast_cipher_count * 4); + pIeBuf += 8 + wpaie->unicast_cipher_count * 4; + qdf_mem_copy(pIeBuf, &wpaie->auth_suite_count, + 2 + wpaie->auth_suite_count * 4); + pIeBuf += wpaie->auth_suite_count * 4; + session_ptr->nWpaRsnRspIeLength = nIeLen + 2; + } + } +#ifdef FEATURE_WLAN_WAPI + else if ((eCSR_AUTH_TYPE_WAPI_WAI_PSK == auth_type) || + (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == + auth_type)) { + if (ie_local->WAPI.present) { + tDot11fIEWAPI *wapi_ie = &ie_local->WAPI; + /* Calculate the actual length of wapi ie*/ + nIeLen = 4 + 2 /* pwise_cipher_suite_count */ + + wapi_ie->akm_suite_count * 4 + + wapi_ie->unicast_cipher_suite_count * 4 + + 6; /* gp_cipher_suite + preauth + reserved */ + + if (wapi_ie->bkid_count) + nIeLen += 2 + wapi_ie->bkid_count * 4; + + /* nIeLen doesn't count EID and length fields */ + session_ptr->pWapiRspIE = + qdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWapiRspIE) + return QDF_STATUS_E_NOMEM; + session_ptr->pWapiRspIE[0] = DOT11F_EID_WAPI; + session_ptr->pWapiRspIE[1] = (uint8_t) nIeLen; + pIeBuf = session_ptr->pWapiRspIE + 2; + /* copy upto akm_suite_count */ + qdf_mem_copy(pIeBuf, &wapi_ie->version, 2); + pIeBuf += 4; + if (wapi_ie->akm_suite_count) { + /* copy akm_suites */ + qdf_mem_copy(pIeBuf, + wapi_ie->akm_suites, + wapi_ie->akm_suite_count * 4); + pIeBuf += wapi_ie->akm_suite_count * 4; + } + qdf_mem_copy(pIeBuf, + &wapi_ie->unicast_cipher_suite_count, 2); + pIeBuf += 2; + if (wapi_ie->unicast_cipher_suite_count) { + uint16_t suite_size = + wapi_ie->unicast_cipher_suite_count * 4; + /* copy pwise_cipher_suites */ + qdf_mem_copy(pIeBuf, + wapi_ie->unicast_cipher_suites, + suite_size); + pIeBuf += suite_size; + } + /* gp_cipher_suite */ + qdf_mem_copy(pIeBuf, + wapi_ie->multicast_cipher_suite, 4); + pIeBuf += 4; + /* preauth + reserved */ + qdf_mem_copy(pIeBuf, + wapi_ie->multicast_cipher_suite + 4, 2); + pIeBuf += 2; + if (wapi_ie->bkid_count) { + /* bkid_count */ + qdf_mem_copy(pIeBuf, &wapi_ie->bkid_count, 2); + pIeBuf += 2; + /* copy akm_suites */ + qdf_mem_copy(pIeBuf, wapi_ie->bkid, + wapi_ie->bkid_count * 4); + pIeBuf += wapi_ie->bkid_count * 4; + } + session_ptr->nWapiRspIeLength = nIeLen + 2; + } + } +#endif /* FEATURE_WLAN_WAPI */ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS csr_roam_save_security_rsp_ie(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrAuthType authType, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + tDot11fBeaconIEs *pIesLocal = pIes; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("authType %d session %d", authType, sessionId); + if ((eCSR_AUTH_TYPE_WPA == authType) || + (eCSR_AUTH_TYPE_WPA_PSK == authType) || + (eCSR_AUTH_TYPE_RSN == authType) || + (eCSR_AUTH_TYPE_RSN_PSK == authType) + || (eCSR_AUTH_TYPE_FT_RSN == authType) || + (eCSR_AUTH_TYPE_FT_RSN_PSK == authType) +#ifdef FEATURE_WLAN_WAPI + || (eCSR_AUTH_TYPE_WAPI_WAI_PSK == authType) || + (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == authType) +#endif /* FEATURE_WLAN_WAPI */ +#ifdef WLAN_FEATURE_11W + || (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == authType) || + (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == authType) +#endif /* FEATURE_WLAN_WAPI */ + || (eCSR_AUTH_TYPE_SAE == authType)) { + if (!pIesLocal && !QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc, &pIesLocal))) + sme_err(" cannot parse IEs"); + if (pIesLocal) { + status = csr_roam_save_params(pMac, pSession, authType, + pIes, pIesLocal); + if (!pIes) + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + } + return status; +} + +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId) +{ + return csr_neighbor_roam_is11r_assoc(pMac, sessionId); +} + +/* Returns whether "Legacy Fast Roaming" is currently enabled...or not */ +bool csr_roam_is_fast_roam_enabled(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = NULL; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession->pCurRoamProfile) { + if (pSession->pCurRoamProfile->csrPersona != + QDF_STA_MODE) { + return false; + } + } + } + if (true == CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) { + return pMac->roam.configParam.isFastRoamIniFeatureEnabled; + } else { + return pMac->roam.configParam.isFastRoamIniFeatureEnabled && + (!csr_is_concurrent_session_running(pMac)); + } +} + +static void csr_update_scan_entry_associnfo(tpAniSirGlobal mac_ctx, + struct bss_info *bss, enum scan_entry_connection_state state) +{ + QDF_STATUS status; + struct mlme_info mlme; + + sme_debug("Update MLME info in scan database. bssid %pM state: %d", + bss->bssid.bytes, state); + mlme.assoc_state = state; + status = ucfg_scan_update_mlme_by_bssinfo(mac_ctx->pdev, bss, &mlme); + if (QDF_IS_STATUS_ERROR(status)) + sme_debug("Failed to update the MLME info in scan entry"); +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +static eCsrPhyMode csr_roamdot11mode_to_phymode(uint8_t dot11mode) +{ + eCsrPhyMode phymode = eCSR_DOT11_MODE_abg; + + switch (dot11mode) { + case WNI_CFG_DOT11_MODE_ALL: + phymode = eCSR_DOT11_MODE_abg; + break; + case WNI_CFG_DOT11_MODE_11A: + phymode = eCSR_DOT11_MODE_11a; + break; + case WNI_CFG_DOT11_MODE_11B: + phymode = eCSR_DOT11_MODE_11b; + break; + case WNI_CFG_DOT11_MODE_11G: + phymode = eCSR_DOT11_MODE_11g; + break; + case WNI_CFG_DOT11_MODE_11N: + phymode = eCSR_DOT11_MODE_11n; + break; + case WNI_CFG_DOT11_MODE_11G_ONLY: + phymode = eCSR_DOT11_MODE_11g_ONLY; + break; + case WNI_CFG_DOT11_MODE_11N_ONLY: + phymode = eCSR_DOT11_MODE_11n_ONLY; + break; + case WNI_CFG_DOT11_MODE_11AC: + phymode = eCSR_DOT11_MODE_11ac; + break; + case WNI_CFG_DOT11_MODE_11AC_ONLY: + phymode = eCSR_DOT11_MODE_11ac_ONLY; + break; + case WNI_CFG_DOT11_MODE_11AX: + phymode = eCSR_DOT11_MODE_11ax; + break; + case WNI_CFG_DOT11_MODE_11AX_ONLY: + phymode = eCSR_DOT11_MODE_11ax_ONLY; + break; + default: + break; + } + + return phymode; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void csr_roam_synch_clean_up(tpAniSirGlobal mac, uint8_t session_id) +{ + struct scheduler_msg msg = {0}; + struct roam_offload_synch_fail *roam_offload_failed = NULL; + struct csr_roam_session *session = &mac->roam.roamSession[session_id]; + + /* Clean up the roam synch in progress for LFR3 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Roam Synch Failed, Clean Up", __func__); + session->roam_synch_in_progress = false; + + roam_offload_failed = qdf_mem_malloc( + sizeof(struct roam_offload_synch_fail)); + if (NULL == roam_offload_failed) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: unable to allocate memory for roam synch fail", + __func__); + return; + } + + roam_offload_failed->session_id = session_id; + msg.type = WMA_ROAM_OFFLOAD_SYNCH_FAIL; + msg.reserved = 0; + msg.bodyptr = roam_offload_failed; + if (!QDF_IS_STATUS_SUCCESS(scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Unable to post WMA_ROAM_OFFLOAD_SYNCH_FAIL to WMA", + __func__); + qdf_mem_free(roam_offload_failed); + } +} +#endif + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * csr_roam_copy_ht_profile() - Copy from src to dst + * @dst_profile: Destination HT profile + * @src_profile: Source HT profile + * + * Copy the HT profile from the given source to destination + * + * Return: None + */ +static void csr_roam_copy_ht_profile(tCsrRoamHTProfile *dst_profile, + tSirSmeHTProfile *src_profile) +{ + dst_profile->phymode = + csr_roamdot11mode_to_phymode(src_profile->dot11mode); + dst_profile->htCapability = src_profile->htCapability; + dst_profile->htSupportedChannelWidthSet = + src_profile->htSupportedChannelWidthSet; + dst_profile->htRecommendedTxWidthSet = + src_profile->htRecommendedTxWidthSet; + dst_profile->htSecondaryChannelOffset = + src_profile->htSecondaryChannelOffset; + dst_profile->vhtCapability = src_profile->vhtCapability; + dst_profile->apCenterChan = src_profile->apCenterChan; + dst_profile->apChanWidth = src_profile->apChanWidth; +} +#endif + +#if defined(WLAN_FEATURE_FILS_SK) +/** + * csr_update_fils_seq_number() - Copy FILS sequence number to roam info + * @session: CSR Roam Session + * @roam_info: Roam info + * + * Return: None + */ +static void csr_update_fils_seq_number(struct csr_roam_session *session, + struct csr_roam_info *roam_info) +{ + roam_info->is_fils_connection = true; + roam_info->fils_seq_num = session->fils_seq_num; + pe_debug("FILS sequence number %x", session->fils_seq_num); +} +#else +static inline void csr_update_fils_seq_number(struct csr_roam_session *session, + struct csr_roam_info *roam_info) +{} +#endif + +/** + * csr_roam_process_results_default() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Return: None + */ +static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, void *context, enum csr_roamcomplete_result + res) +{ + uint32_t session_id = cmd->sessionId; + struct csr_roam_session *session; + struct csr_roam_info roam_info; + QDF_STATUS status; + struct bss_info bss_info; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("Invalid session id %d", session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + sme_debug("receives no association indication; FILS %d", + session->is_fils_connection); + sme_debug("Assoc ref count: %d", session->bRefAssocStartCnt); + + if (CSR_IS_INFRASTRUCTURE(&session->connectedProfile)) { + qdf_copy_macaddr(&bss_info.bssid, + &session->connectedProfile.bssid); + bss_info.chan = session->connectedProfile.operationChannel; + bss_info.ssid.length = session->connectedProfile.SSID.length; + qdf_mem_copy(&bss_info.ssid.ssid, + &session->connectedProfile.SSID.ssId, + bss_info.ssid.length); + } + if (CSR_IS_INFRASTRUCTURE(&session->connectedProfile) + || 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_free_connect_bss_desc(mac_ctx, session_id); + csr_roam_free_connect_profile(&session->connectedProfile); + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + csr_set_default_dot11_mode(mac_ctx); + } + + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + /* Copy FILS sequence number used to be updated to userspace */ + if (session->is_fils_connection) + csr_update_fils_seq_number(session, &roam_info); + + switch (cmd->u.roamCmd.roamReason) { + /* + * If this transition is because of an 802.11 OID, then we + * transition back to INIT state so we sit waiting for more + * OIDs to be issued and we don't start the IDLE timer. + */ + case eCsrSmeIssuedFTReassoc: + case eCsrSmeIssuedAssocToSimilarAP: + case eCsrHddIssued: + case eCsrSmeIssuedDisassocForHandoff: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss; + roam_info.pProfile = &cmd->u.roamCmd.roamProfile; + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + qdf_mem_copy(&roam_info.bssid, + &session->joinFailStatusCode.bssId, + sizeof(struct qdf_mac_addr)); + + /* + * If Join fails while Handoff is in progress, indicate + * disassociated event to supplicant to reconnect + */ + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id)) { + csr_neighbor_roam_indicate_connect(mac_ctx, + (uint8_t)session_id, QDF_STATUS_E_FAILURE); + } + if (session->bRefAssocStartCnt > 0) { + session->bRefAssocStartCnt--; + if (eCsrJoinFailureDueToConcurrency == res) + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL); + else + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_FAILURE); + } else { + /* + * bRefAssocStartCnt is not incremented when + * eRoamState == eCsrStopRoamingDueToConcurrency + * in csr_roam_join_next_bss API. so handle this in + * else case by sending assoc failure + */ + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_FAILURE); + } + sme_debug("roam(reason %d) failed", cmd->u.roamCmd.roamReason); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_update_hand_off((uint8_t) session_id, false); + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_FAILURE, false); + break; + case eCsrHddIssuedReassocToSameAP: + case eCsrSmeIssuedReassocToSameAP: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_FAILURE, false); + break; + case eCsrForcedDisassoc: + case eCsrForcedDeauth: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + csr_roam_call_callback( + mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, + NULL); +#endif + csr_update_scan_entry_associnfo(mac_ctx, &bss_info, + SCAN_ENTRY_CON_STATE_NONE); + csr_roam_link_down(mac_ctx, session_id); + + if (mac_ctx->roam.deauthRspStatus == eSIR_SME_DEAUTH_STATUS) { + sme_warn("FW still in connected state"); + break; + } + break; + case eCsrForcedIbssLeave: + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_LEAVE, + eCSR_ROAM_RESULT_IBSS_STOP); + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + break; + case eCsrForcedDisassocMICFailure: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_MIC_FAILURE); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_REQ, NULL); +#endif + break; + case eCsrStopBss: + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_STOPPED); + break; + 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; + + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + session = CSR_GET_SESSION(mac_ctx, session_id); + if (CSR_IS_SESSION_VALID(mac_ctx, session_id) && + CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info.u.pConnectedProfile = + &session->connectedProfile; + 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.statusCode = eSIR_SME_SUCCESS; + status = csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } + break; + default: + csr_roam_state_change(mac_ctx, + eCSR_ROAMING_STATE_IDLE, session_id); + break; + } +} + +/** + * csr_roam_process_start_bss_success() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Return: None + */ +static void csr_roam_process_start_bss_success(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, void *context) +{ + uint32_t session_id = cmd->sessionId; + struct csr_roam_profile *profile = &cmd->u.roamCmd.roamProfile; + struct csr_roam_session *session; + tSirBssDescription *bss_desc = NULL; + struct csr_roam_info roam_info; + tSirSmeStartBssRsp *start_bss_rsp = NULL; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + tDot11fBeaconIEs *ies_ptr = NULL; + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + QDF_STATUS status; + host_log_ibss_pkt_type *ibss_log; + uint32_t bi; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("Invalid session id %d", session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + /* + * on the StartBss Response, LIM is returning the Bss Description that + * we are beaconing. Add this Bss Description to our scan results and + * chain the Profile to this Bss Description. On a Start BSS, there was + * no detected Bss description (no partner) so we issued the Start Bss + * to start the Ibss without any Bss description. Lim was kind enough + * to return the Bss Description that we start beaconing for the newly + * started Ibss. + */ + sme_debug("receives start BSS ok indication"); + status = QDF_STATUS_E_FAILURE; + start_bss_rsp = (tSirSmeStartBssRsp *) context; + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + if (CSR_IS_IBSS(profile)) + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + else if (CSR_IS_INFRA_AP(profile)) + session->connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED; + else if (CSR_IS_NDI(profile)) + session->connectState = eCSR_CONNECT_STATE_TYPE_NDI_STARTED; + else + session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED; + + bss_desc = &start_bss_rsp->bssDescription; + if (CSR_IS_NDI(profile)) { + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + csr_roam_save_ndi_connected_info(mac_ctx, session_id, profile, + bss_desc); + roam_info.u.pConnectedProfile = &session->connectedProfile; + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ies_ptr))) { + sme_warn("cannot parse IBSS IEs"); + roam_info.pBssDesc = bss_desc; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_IND, + eCSR_ROAM_RESULT_IBSS_START_FAILED); + return; + } + } + if (!CSR_IS_INFRA_AP(profile) && !CSR_IS_NDI(profile)) { + csr_scan_append_bss_description(mac_ctx, bss_desc); + } + csr_roam_save_connected_bss_desc(mac_ctx, session_id, bss_desc); + csr_roam_free_connect_profile(&session->connectedProfile); + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + csr_roam_save_connected_information(mac_ctx, session_id, + profile, bss_desc, ies_ptr); + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + /* We are done with the IEs so free it */ + qdf_mem_free(ies_ptr); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_LOG_ALLOC(ibss_log, + host_log_ibss_pkt_type, LOG_WLAN_IBSS_C); + if (ibss_log) { + if (CSR_INVALID_SCANRESULT_HANDLE == + cmd->u.roamCmd.hBSSList) { + /* + * We start the IBSS (didn't find any + * matched IBSS out there) + */ + ibss_log->eventId = + WLAN_IBSS_EVENT_START_IBSS_RSP; + } else { + ibss_log->eventId = + WLAN_IBSS_EVENT_JOIN_IBSS_RSP; + } + if (bss_desc) { + qdf_mem_copy(ibss_log->bssid.bytes, + bss_desc->bssId, QDF_MAC_ADDR_SIZE); + ibss_log->operatingChannel = + bss_desc->channelId; + } + if (QDF_IS_STATUS_SUCCESS(wlan_cfg_get_int( + mac_ctx, + WNI_CFG_BEACON_INTERVAL, + &bi))) + /* U8 is not enough for BI */ + ibss_log->beaconInterval = (uint8_t) bi; + WLAN_HOST_DIAG_LOG_REPORT(ibss_log); + } +#endif + /* + * 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 (session->pCurRoamProfile && + !CSR_IS_INFRA_AP(session->pCurRoamProfile)) { + if (CSR_IS_ENC_TYPE_STATIC( + profile->negotiatedUCEncryptionType)) { + /* + * Issue the set Context request to LIM to establish + * the Broadcast STA context for the Ibss. In Rome IBSS + * case, dummy key installation will break proper BSS + * key installation, so skip it. + */ + if (!CSR_IS_IBSS(session->pCurRoamProfile)) { + /* NO keys. these key parameters don't matter */ + csr_roam_issue_set_context_req(mac_ctx, + session_id, + profile->negotiatedMCEncryptionType, + bss_desc, &bcast_mac, false, + false, eSIR_TX_RX, 0, 0, NULL, 0); + } + } + if (CSR_IS_IBSS(session->pCurRoamProfile) && + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + profile->negotiatedUCEncryptionType || + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + profile->negotiatedUCEncryptionType || + eCSR_ENCRYPT_TYPE_TKIP == + profile->negotiatedUCEncryptionType || + eCSR_ENCRYPT_TYPE_AES == + profile->negotiatedUCEncryptionType)) { + roam_info.fAuthRequired = true; + } + } + /* + * 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 + */ + if (!CSR_IS_JOIN_TO_IBSS(profile)) { + roam_status = eCSR_ROAM_IBSS_IND; + roam_result = eCSR_ROAM_RESULT_IBSS_STARTED; + if (CSR_IS_INFRA_AP(profile)) { + roam_status = eCSR_ROAM_INFRA_IND; + roam_result = eCSR_ROAM_RESULT_INFRA_STARTED; + } + roam_info.staId = (uint8_t) start_bss_rsp->staId; + if (CSR_IS_NDI(profile)) { + csr_roam_update_ndp_return_params(mac_ctx, + eCsrStartBssSuccess, + &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.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + /* We start the IBSS (didn't find any matched IBSS out there) */ + roam_info.pBssDesc = bss_desc; + if (bss_desc) + qdf_mem_copy(roam_info.bssid.bytes, bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + dst_profile = &session->connectedProfile.HTProfile; + src_profile = &start_bss_rsp->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, src_profile); +#endif + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + roam_status, roam_result); + } + +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * populate_fils_params_join_rsp() - Copy FILS params from JOIN rsp + * @mac_ctx: Global MAC Context + * @roam_info: CSR Roam Info + * @join_rsp: SME Join response + * + * Copy the FILS params from the join results + * + * Return: QDF_STATUS + */ +static QDF_STATUS populate_fils_params_join_rsp(tpAniSirGlobal mac_ctx, + struct csr_roam_info *roam_info, + tSirSmeJoinRsp *join_rsp) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct fils_join_rsp_params *roam_fils_info, + *fils_join_rsp = join_rsp->fils_join_rsp; + + if (!fils_join_rsp->fils_pmk_len || + !fils_join_rsp->fils_pmk || !fils_join_rsp->tk_len || + !fils_join_rsp->kek_len || !fils_join_rsp->gtk_len) { + sme_err("fils join rsp err: pmk len %d tk len %d kek len %d gtk len %d", + fils_join_rsp->fils_pmk_len, + fils_join_rsp->tk_len, + fils_join_rsp->kek_len, + fils_join_rsp->gtk_len); + status = QDF_STATUS_E_FAILURE; + goto free_fils_join_rsp; + } + + roam_info->fils_join_rsp = qdf_mem_malloc(sizeof(*fils_join_rsp)); + if (!roam_info->fils_join_rsp) { + sme_err("fils_join_rsp malloc fails!"); + status = QDF_STATUS_E_FAILURE; + goto free_fils_join_rsp; + } + + roam_fils_info = roam_info->fils_join_rsp; + roam_fils_info->fils_pmk = qdf_mem_malloc(fils_join_rsp->fils_pmk_len); + if (!roam_fils_info->fils_pmk) { + qdf_mem_free(roam_info->fils_join_rsp); + roam_info->fils_join_rsp = NULL; + sme_err("fils_pmk malloc fails!"); + status = QDF_STATUS_E_FAILURE; + goto free_fils_join_rsp; + } + + roam_info->fils_seq_num = join_rsp->fils_seq_num; + roam_fils_info->fils_pmk_len = fils_join_rsp->fils_pmk_len; + qdf_mem_copy(roam_fils_info->fils_pmk, + fils_join_rsp->fils_pmk, roam_fils_info->fils_pmk_len); + + qdf_mem_copy(roam_fils_info->fils_pmkid, + fils_join_rsp->fils_pmkid, PMKID_LEN); + + roam_fils_info->kek_len = fils_join_rsp->kek_len; + qdf_mem_copy(roam_fils_info->kek, + fils_join_rsp->kek, roam_fils_info->kek_len); + + roam_fils_info->tk_len = fils_join_rsp->tk_len; + qdf_mem_copy(roam_fils_info->tk, + fils_join_rsp->tk, fils_join_rsp->tk_len); + + roam_fils_info->gtk_len = fils_join_rsp->gtk_len; + qdf_mem_copy(roam_fils_info->gtk, + fils_join_rsp->gtk, roam_fils_info->gtk_len); + + cds_copy_hlp_info(&fils_join_rsp->dst_mac, &fils_join_rsp->src_mac, + fils_join_rsp->hlp_data_len, fils_join_rsp->hlp_data, + &roam_fils_info->dst_mac, &roam_fils_info->src_mac, + &roam_fils_info->hlp_data_len, + roam_fils_info->hlp_data); + sme_debug("FILS connect params copied to CSR!"); + +free_fils_join_rsp: + qdf_mem_free(fils_join_rsp->fils_pmk); + qdf_mem_free(fils_join_rsp); + return status; +} + +/** + * csr_process_fils_join_rsp() - Process join rsp for FILS connection + * @mac_ctx: Global MAC Context + * @profile: CSR Roam Profile + * @session_id: Session ID + * @roam_info: CSR Roam Info + * @bss_desc: BSS description + * @join_rsp: SME Join rsp + * + * Process SME join response for FILS connection + * + * Return: None + */ +static void csr_process_fils_join_rsp(tpAniSirGlobal mac_ctx, + struct csr_roam_profile *profile, + uint32_t session_id, + struct csr_roam_info *roam_info, + tSirBssDescription *bss_desc, + tSirSmeJoinRsp *join_rsp) +{ + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + QDF_STATUS status; + + if (!join_rsp || !join_rsp->fils_join_rsp) { + sme_err("Join rsp doesn't have FILS info"); + goto process_fils_join_rsp_fail; + } + + /* Copy FILS params */ + status = populate_fils_params_join_rsp(mac_ctx, roam_info, join_rsp); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Copy FILS params join rsp fails"); + goto process_fils_join_rsp_fail; + } + + status = csr_roam_issue_set_context_req(mac_ctx, session_id, + profile->negotiatedMCEncryptionType, + bss_desc, &bcast_mac, true, false, + eSIR_RX_ONLY, 2, + roam_info->fils_join_rsp->gtk_len, + roam_info->fils_join_rsp->gtk, 0); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Set context for bcast fail"); + goto process_fils_join_rsp_fail; + } + + status = csr_roam_issue_set_context_req(mac_ctx, session_id, + profile->negotiatedUCEncryptionType, + bss_desc, &(bss_desc->bssId), true, + true, eSIR_TX_RX, 0, + roam_info->fils_join_rsp->tk_len, + roam_info->fils_join_rsp->tk, 0); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Set context for unicast fail"); + goto process_fils_join_rsp_fail; + } + return; + +process_fils_join_rsp_fail: + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, session_id); +} +#else + +static inline void csr_process_fils_join_rsp(tpAniSirGlobal mac_ctx, + struct csr_roam_profile *profile, + uint32_t session_id, + struct csr_roam_info *roam_info, + tSirBssDescription *bss_desc, + tSirSmeJoinRsp *join_rsp) +{} +#endif + +/** + * csr_roam_process_join_res() - Process the Join results + * @mac_ctx: Global MAC Context + * @result: Result after the command was processed + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Process the join results which are obtained in a successful join + * + * Return: None + */ +static void csr_roam_process_join_res(tpAniSirGlobal mac_ctx, + enum csr_roamcomplete_result res, tSmeCmd *cmd, void *context) +{ + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + sme_QosAssocInfo assoc_info; + uint32_t key_timeout_interval = 0; + uint8_t acm_mask = 0; /* HDD needs ACM mask in assoc rsp callback */ + uint32_t session_id = cmd->sessionId; + struct csr_roam_profile *profile = &cmd->u.roamCmd.roamProfile; + struct csr_roam_session *session; + tSirBssDescription *bss_desc = NULL; + struct tag_csrscan_result *scan_res = NULL; + sme_qos_csr_event_indType ind_qos; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + tCsrRoamConnectedProfile *conn_profile = NULL; + tDot11fBeaconIEs *ies_ptr = NULL; + struct csr_roam_info roam_info; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + tSirSmeJoinRsp *join_rsp = (tSirSmeJoinRsp *) context; + uint32_t len; + struct bss_info bss_info; + + if (!join_rsp) { + sme_err("join_rsp is NULL"); + return; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("Invalid session id %d", session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + conn_profile = &session->connectedProfile; + if (eCsrReassocSuccess == res) { + roam_info.reassoc = true; + ind_qos = SME_QOS_CSR_REASSOC_COMPLETE; + } else { + roam_info.reassoc = false; + ind_qos = SME_QOS_CSR_ASSOC_COMPLETE; + } + sme_debug("receives association indication"); + /* always free the memory here */ + if (session->pWpaRsnRspIE) { + session->nWpaRsnRspIeLength = 0; + qdf_mem_free(session->pWpaRsnRspIE); + session->pWpaRsnRspIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + if (session->pWapiRspIE) { + session->nWapiRspIeLength = 0; + qdf_mem_free(session->pWapiRspIE); + session->pWapiRspIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_BTAMP_UT_RF + session->maxRetryCount = 0; + csr_roam_stop_join_retry_timer(mac_ctx, session_id); +#endif + /* + * Reset remain_in_power_active_till_dhcp as + * it might have been set by last failed secured connection. + * It should be set only for secured connection. + */ + ps_global_info->remain_in_power_active_till_dhcp = false; + if (CSR_IS_INFRASTRUCTURE(profile)) + session->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; + else + session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED; + /* + * Use the last connected bssdesc for reassoc-ing to the same AP. + * NOTE: What to do when reassoc to a different AP??? + */ + if ((eCsrHddIssuedReassocToSameAP == cmd->u.roamCmd.roamReason) + || (eCsrSmeIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason)) { + bss_desc = session->pConnectBssDesc; + if (bss_desc) + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + if (cmd->u.roamCmd.pRoamBssEntry) { + scan_res = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + struct tag_csrscan_result, Link); + if (scan_res != NULL) { + bss_desc = &scan_res->Result.BssDescriptor; + ies_ptr = (tDot11fBeaconIEs *) + (scan_res->Result.pvIes); + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + } + } + } + if (bss_desc) { + roam_info.staId = STA_INVALID_IDX; + csr_roam_save_connected_information(mac_ctx, session_id, + profile, bss_desc, ies_ptr); + /* Save WPA/RSN IE */ + csr_roam_save_security_rsp_ie(mac_ctx, session_id, + profile->negotiatedAuthType, bss_desc, ies_ptr); +#ifdef FEATURE_WLAN_ESE + roam_info.isESEAssoc = conn_profile->isESEAssoc; +#endif + + /* + * csr_roam_state_change also affects sub-state. + * Hence, csr_roam_state_change happens first and then + * substate change. + * Moving even save profile above so that below + * mentioned conditon is also met. + * JEZ100225: Moved to after saving the profile. + * Fix needed in main/latest + */ + csr_roam_state_change(mac_ctx, + eCSR_ROAMING_STATE_JOINED, session_id); + + /* + * Make sure the Set Context is issued before link + * indication to NDIS. After link indication is + * made to NDIS, frames could start flowing. + * If we have not set context with LIM, the frames + * will be dropped for the security context may not + * be set properly. + * + * this was causing issues in the 2c_wlan_wep WHQL test + * when the SetContext was issued after the link + * indication. (Link Indication happens in the + * profFSMSetConnectedInfra call). + * + * this reordering was done on titan_prod_usb branch + * and is being replicated here. + */ + + if (CSR_IS_ENC_TYPE_STATIC + (profile->negotiatedUCEncryptionType) && + !profile->bWPSAssociation) { + /* + * Issue the set Context request to LIM to establish + * the Unicast STA context + */ + if (!QDF_IS_STATUS_SUCCESS( + csr_roam_issue_set_context_req(mac_ctx, + session_id, + profile->negotiatedUCEncryptionType, + bss_desc, &(bss_desc->bssId), + false, true, + eSIR_TX_RX, 0, 0, NULL, 0))) { + /* NO keys. these key parameters don't matter */ + sme_err("Set context for unicast fail"); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, session_id); + } + /* + * Issue the set Context request to LIM + * to establish the Broadcast STA context + * NO keys. these key parameters don't matter + */ + csr_roam_issue_set_context_req(mac_ctx, session_id, + profile->negotiatedMCEncryptionType, + bss_desc, &bcast_mac, false, false, + eSIR_TX_RX, 0, 0, NULL, 0); + } else if (CSR_IS_AUTH_TYPE_FILS(profile->negotiatedAuthType) + && join_rsp->is_fils_connection) { + roam_info.is_fils_connection = true; + csr_process_fils_join_rsp(mac_ctx, profile, session_id, + &roam_info, bss_desc, join_rsp); + } else { + /* Need to wait for supplicant authtication */ + roam_info.fAuthRequired = true; + /* + * Set the substate to WaitForKey in case + * authentiation is needed + */ + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + session_id); + + /* + * Set remain_in_power_active_till_dhcp to make + * sure we wait for until keys are set before + * going into BMPS. + */ + ps_global_info->remain_in_power_active_till_dhcp + = true; + + if (profile->bWPSAssociation) + key_timeout_interval = + CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD; + else + key_timeout_interval = + CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD; + + /* Save session_id in case of timeout */ + mac_ctx->roam.WaitForKeyTimerInfo.sessionId = + (uint8_t) session_id; + /* + * This time should be long enough for the rest + * of the process plus setting key + */ + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_start_wait_for_key_timer( + mac_ctx, key_timeout_interval)) + ) { + /* Reset state so nothing is blocked. */ + sme_err("Failed preauth timer start"); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, + session_id); + } + } + + assoc_info.pBssDesc = bss_desc; /* could be NULL */ + assoc_info.pProfile = profile; + if (context) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Clear Connected info")); +#endif + csr_roam_free_connected_info(mac_ctx, + &session->connectedInfo); + len = join_rsp->assocReqLength + + join_rsp->assocRspLength + + join_rsp->beaconLength; + len += join_rsp->parsedRicRspLen; +#ifdef FEATURE_WLAN_ESE + len += join_rsp->tspecIeLen; +#endif + if (len) { + session->connectedInfo.pbFrames = + qdf_mem_malloc(len); + if (session->connectedInfo.pbFrames != + NULL) { + qdf_mem_copy( + session->connectedInfo.pbFrames, + join_rsp->frames, len); + session->connectedInfo.nAssocReqLength = + join_rsp->assocReqLength; + session->connectedInfo.nAssocRspLength = + join_rsp->assocRspLength; + session->connectedInfo.nBeaconLength = + join_rsp->beaconLength; + session->connectedInfo.nRICRspLength = + join_rsp->parsedRicRspLen; +#ifdef FEATURE_WLAN_ESE + session->connectedInfo.nTspecIeLength = + join_rsp->tspecIeLen; +#endif + roam_info.nAssocReqLength = + join_rsp->assocReqLength; + roam_info.nAssocRspLength = + join_rsp->assocRspLength; + roam_info.nBeaconLength = + join_rsp->beaconLength; + roam_info.pbFrames = + session->connectedInfo.pbFrames; + } + } + if (cmd->u.roamCmd.fReassoc) + roam_info.fReassocReq = + roam_info.fReassocRsp = true; + conn_profile->vht_channel_width = + join_rsp->vht_channel_width; + session->connectedInfo.staId = + (uint8_t) join_rsp->staId; + roam_info.staId = (uint8_t) join_rsp->staId; + roam_info.timingMeasCap = join_rsp->timingMeasCap; + roam_info.chan_info.nss = join_rsp->nss; + roam_info.chan_info.rate_flags = + join_rsp->max_rate_flags; + roam_info.chan_info.ch_width = + join_rsp->vht_channel_width; +#ifdef FEATURE_WLAN_TDLS + roam_info.tdls_prohibited = join_rsp->tdls_prohibited; + roam_info.tdls_chan_swit_prohibited = + join_rsp->tdls_chan_swit_prohibited; + sme_debug("tdls:prohibit: %d chan_swit_prohibit: %d", + roam_info.tdls_prohibited, + roam_info.tdls_chan_swit_prohibited); +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + src_profile = &join_rsp->HTProfile; + dst_profile = &conn_profile->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, + src_profile); +#endif + roam_info.vht_caps = join_rsp->vht_caps; + roam_info.ht_caps = join_rsp->ht_caps; + roam_info.hs20vendor_ie = join_rsp->hs20vendor_ie; + roam_info.ht_operation = join_rsp->ht_operation; + roam_info.vht_operation = join_rsp->vht_operation; + } else { + if (cmd->u.roamCmd.fReassoc) { + roam_info.fReassocReq = + roam_info.fReassocRsp = true; + roam_info.nAssocReqLength = + session->connectedInfo.nAssocReqLength; + roam_info.nAssocRspLength = + session->connectedInfo.nAssocRspLength; + roam_info.nBeaconLength = + session->connectedInfo.nBeaconLength; + roam_info.pbFrames = + session->connectedInfo.pbFrames; + } + } + /* + * Update the staId from the previous connected profile info + * as the reassociation is triggred at SME/HDD + */ + + if ((eCsrHddIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason) || + (eCsrSmeIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason)) + roam_info.staId = session->connectedInfo.staId; + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + /* + * Indicate SME-QOS with reassoc success event, + * only after copying the frames + */ + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, ind_qos, + &assoc_info); +#endif + roam_info.pBssDesc = bss_desc; + roam_info.statusCode = + session->joinFailStatusCode.statusCode; + roam_info.reasonCode = + session->joinFailStatusCode.reasonCode; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = sme_qos_get_acm_mask(mac_ctx, bss_desc, NULL); +#endif + conn_profile->acm_mask = acm_mask; + conn_profile->modifyProfileFields.uapsd_mask = + join_rsp->uapsd_mask; + /* + * start UAPSD if uapsd_mask is not 0 because HDD will + * configure for trigger frame It may be better to let QoS do + * this???? + */ + if (conn_profile->modifyProfileFields.uapsd_mask) { + sme_err( + " uapsd_mask (0x%X) set, request UAPSD now", + conn_profile->modifyProfileFields.uapsd_mask); + sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), session_id); + } + conn_profile->dot11Mode = session->bssParams.uCfgDot11Mode; + roam_info.u.pConnectedProfile = conn_profile; + + if (session->bRefAssocStartCnt > 0) { + session->bRefAssocStartCnt--; + if (!IS_FEATURE_SUPPORTED_BY_FW + (SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOCIATED); + } + + qdf_copy_macaddr(&bss_info.bssid, &conn_profile->bssid); + bss_info.chan = conn_profile->operationChannel; + bss_info.ssid.length = + conn_profile->SSID.length; + qdf_mem_copy(&bss_info.ssid.ssid, + &conn_profile->SSID.ssId, + bss_info.ssid.length); + csr_update_scan_entry_associnfo(mac_ctx, + &bss_info, SCAN_ENTRY_CON_STATE_ASSOC); + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_NONE, true); + csr_reset_pmkid_candidate_list(mac_ctx, session_id); +#ifdef FEATURE_WLAN_WAPI + csr_reset_bkid_candidate_list(mac_ctx, session_id); +#endif + } else { + sme_warn("Roam command doesn't have a BSS desc"); + } + /* Not to signal link up because keys are yet to be set. + * The linkup function will overwrite the sub-state that + * we need to keep at this point. + */ + if (!CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id)) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL + ("NO CSR_IS_WAIT_FOR_KEY -> csr_roam_link_up")); + } +#endif + csr_roam_link_up(mac_ctx, conn_profile->bssid); + } + sme_free_join_rsp_fils_params(&roam_info); +} + +/** + * csr_roam_process_results() - Process the Roam Results + * @mac_ctx: Global MAC Context + * @cmd: Command that has been processed + * @res: Results available after processing the command + * @context: Context + * + * Process the available results and make an appropriate decision + * + * Return: true if the command can be released, else not. + */ +static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, + enum csr_roamcomplete_result res, + void *context) +{ + bool release_cmd = true; + tSirBssDescription *bss_desc = NULL; + struct csr_roam_info roam_info; + uint32_t session_id = cmd->sessionId; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + struct csr_roam_profile *profile = &cmd->u.roamCmd.roamProfile; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + host_log_ibss_pkt_type *ibss_log; + tSirSmeStartBssRsp *start_bss_rsp = NULL; + + if (!session) { + sme_err("session %d not found ", session_id); + return false; + } + + sme_debug("Processing ROAM results..."); + switch (res) { + case eCsrJoinSuccess: + case eCsrReassocSuccess: + csr_roam_process_join_res(mac_ctx, res, cmd, context); + break; + case eCsrStartBssSuccess: + csr_roam_process_start_bss_success(mac_ctx, cmd, context); + break; + case eCsrStartBssFailure: +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_LOG_ALLOC(ibss_log, + host_log_ibss_pkt_type, LOG_WLAN_IBSS_C); + if (ibss_log) { + ibss_log->status = WLAN_IBSS_STATUS_FAILURE; + WLAN_HOST_DIAG_LOG_REPORT(ibss_log); + } +#endif + start_bss_rsp = (tSirSmeStartBssRsp *)context; + qdf_mem_zero(&roam_info, sizeof(roam_info)); + roam_status = eCSR_ROAM_IBSS_IND; + roam_result = eCSR_ROAM_RESULT_IBSS_STARTED; + if (CSR_IS_INFRA_AP(profile)) { + roam_status = eCSR_ROAM_INFRA_IND; + roam_result = eCSR_ROAM_RESULT_INFRA_START_FAILED; + } + if (CSR_IS_NDI(profile)) { + csr_roam_update_ndp_return_params(mac_ctx, + eCsrStartBssFailure, + &roam_status, &roam_result, &roam_info); + } + + if (context) + bss_desc = (tSirBssDescription *) context; + else + bss_desc = NULL; + roam_info.pBssDesc = bss_desc; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, roam_status, + roam_result); + csr_set_default_dot11_mode(mac_ctx); + break; + case eCsrSilentlyStopRoaming: + /* + * We are here because we try to start the same IBSS. + * No message to PE. return the roaming state to Joined. + */ + sme_debug("receives silently stop roam ind"); + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + session_id); + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + roam_info.pBssDesc = session->pConnectBssDesc; + if (roam_info.pBssDesc) + qdf_mem_copy(&roam_info.bssid, + &roam_info.pBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + /* + * Since there is no change in the current state, simply pass + * back no result otherwise HDD may be mistakenly mark to + * disconnected state. + */ + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_IBSS_IND, eCSR_ROAM_RESULT_NONE); + break; + case eCsrSilentlyStopRoamingSaveState: + /* We are here because we try to connect to the same AP */ + /* No message to PE */ + sme_debug("receives silently stop roaming indication"); + qdf_mem_zero(&roam_info, sizeof(roam_info)); + + /* to aviod resetting the substate to NONE */ + mac_ctx->roam.curState[session_id] = eCSR_ROAMING_STATE_JOINED; + /* + * No need to change substate to wai_for_key because there + * is no state change + */ + roam_info.pBssDesc = session->pConnectBssDesc; + if (roam_info.pBssDesc) + qdf_mem_copy(&roam_info.bssid, + &roam_info.pBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + roam_info.nBeaconLength = session->connectedInfo.nBeaconLength; + roam_info.nAssocReqLength = + session->connectedInfo.nAssocReqLength; + roam_info.nAssocRspLength = + session->connectedInfo.nAssocRspLength; + roam_info.pbFrames = session->connectedInfo.pbFrames; + roam_info.staId = session->connectedInfo.staId; + roam_info.u.pConnectedProfile = &session->connectedProfile; + if (0 == roam_info.staId) + QDF_ASSERT(0); + + session->bRefAssocStartCnt--; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOCIATED); + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_ASSOCIATED, true); + break; + case eCsrReassocFailure: + /* + * Currently Reassoc failure is handled through eCsrJoinFailure + * Need to revisit for eCsrReassocFailure handling + */ +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_REASSOC_FAILURE, NULL); +#endif + break; + case eCsrStopBssSuccess: + if (CSR_IS_NDI(profile)) { + qdf_mem_zero(&roam_info, sizeof(roam_info)); + csr_roam_update_ndp_return_params(mac_ctx, res, + &roam_status, &roam_result, &roam_info); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + roam_status, roam_result); + } + break; + case eCsrStopBssFailure: + if (CSR_IS_NDI(profile)) { + qdf_mem_zero(&roam_info, sizeof(roam_info)); + csr_roam_update_ndp_return_params(mac_ctx, res, + &roam_status, &roam_result, &roam_info); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + roam_status, roam_result); + } + break; + case eCsrJoinFailure: + case eCsrNothingToJoin: + case eCsrJoinFailureDueToConcurrency: + default: + csr_roam_process_results_default(mac_ctx, cmd, context, res); + break; + } + return release_cmd; +} + +#ifdef WLAN_FEATURE_FILS_SK +/* + * update_profile_fils_info: API to update FILS info from + * source profile to destination profile. + * @des_profile: pointer to destination profile + * @src_profile: pointer to souce profile + * + * Return: None + */ +static void update_profile_fils_info(struct csr_roam_profile *des_profile, + struct csr_roam_profile *src_profile) +{ + if (!src_profile || !src_profile->fils_con_info) + return; + + sme_debug("is fils %d", src_profile->fils_con_info->is_fils_connection); + + if (!src_profile->fils_con_info->is_fils_connection) + return; + + des_profile->fils_con_info = + qdf_mem_malloc(sizeof(struct cds_fils_connection_info)); + if (!des_profile->fils_con_info) { + sme_err("failed to allocate memory"); + return; + } + + qdf_mem_copy(des_profile->fils_con_info, + src_profile->fils_con_info, + sizeof(struct cds_fils_connection_info)); + + des_profile->hlp_ie = + qdf_mem_malloc(src_profile->hlp_ie_len); + if (!des_profile->hlp_ie) { + sme_err("failed to allocate memory for hlp ie"); + return; + } + + qdf_mem_copy(des_profile->hlp_ie, src_profile->hlp_ie, + src_profile->hlp_ie_len); + des_profile->hlp_ie_len = src_profile->hlp_ie_len; +} +#else +static inline +void update_profile_fils_info(struct csr_roam_profile *des_profile, + struct csr_roam_profile *src_profile) +{ } +#endif +QDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, + struct csr_roam_profile *pDstProfile, + struct csr_roam_profile *pSrcProfile) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t size = 0; + + qdf_mem_zero(pDstProfile, sizeof(struct csr_roam_profile)); + if (pSrcProfile->BSSIDs.numOfBSSIDs) { + size = sizeof(struct qdf_mac_addr) * pSrcProfile->BSSIDs. + numOfBSSIDs; + pDstProfile->BSSIDs.bssid = qdf_mem_malloc(size); + if (NULL == pDstProfile->BSSIDs.bssid) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->BSSIDs.numOfBSSIDs = + pSrcProfile->BSSIDs.numOfBSSIDs; + qdf_mem_copy(pDstProfile->BSSIDs.bssid, + pSrcProfile->BSSIDs.bssid, size); + } + if (pSrcProfile->SSIDs.numOfSSIDs) { + size = sizeof(tCsrSSIDInfo) * pSrcProfile->SSIDs.numOfSSIDs; + pDstProfile->SSIDs.SSIDList = qdf_mem_malloc(size); + if (NULL == pDstProfile->SSIDs.SSIDList) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->SSIDs.numOfSSIDs = + pSrcProfile->SSIDs.numOfSSIDs; + qdf_mem_copy(pDstProfile->SSIDs.SSIDList, + pSrcProfile->SSIDs.SSIDList, size); + } + if (pSrcProfile->nWPAReqIELength) { + pDstProfile->pWPAReqIE = + qdf_mem_malloc(pSrcProfile->nWPAReqIELength); + if (NULL == pDstProfile->pWPAReqIE) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nWPAReqIELength = + pSrcProfile->nWPAReqIELength; + qdf_mem_copy(pDstProfile->pWPAReqIE, pSrcProfile->pWPAReqIE, + pSrcProfile->nWPAReqIELength); + } + if (pSrcProfile->nRSNReqIELength) { + pDstProfile->pRSNReqIE = + qdf_mem_malloc(pSrcProfile->nRSNReqIELength); + if (NULL == pDstProfile->pRSNReqIE) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nRSNReqIELength = + pSrcProfile->nRSNReqIELength; + qdf_mem_copy(pDstProfile->pRSNReqIE, pSrcProfile->pRSNReqIE, + pSrcProfile->nRSNReqIELength); + } +#ifdef FEATURE_WLAN_WAPI + if (pSrcProfile->nWAPIReqIELength) { + pDstProfile->pWAPIReqIE = + qdf_mem_malloc(pSrcProfile->nWAPIReqIELength); + if (NULL == pDstProfile->pWAPIReqIE) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nWAPIReqIELength = + pSrcProfile->nWAPIReqIELength; + qdf_mem_copy(pDstProfile->pWAPIReqIE, pSrcProfile->pWAPIReqIE, + pSrcProfile->nWAPIReqIELength); + } +#endif /* FEATURE_WLAN_WAPI */ + if (pSrcProfile->nAddIEScanLength) { + pDstProfile->pAddIEScan = + qdf_mem_malloc(pSrcProfile->nAddIEScanLength); + if (NULL == pDstProfile->pAddIEScan) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nAddIEScanLength = + pSrcProfile->nAddIEScanLength; + qdf_mem_copy(pDstProfile->pAddIEScan, pSrcProfile->pAddIEScan, + pSrcProfile->nAddIEScanLength); + } + if (pSrcProfile->nAddIEAssocLength) { + pDstProfile->pAddIEAssoc = + qdf_mem_malloc(pSrcProfile->nAddIEAssocLength); + if (NULL == pDstProfile->pAddIEAssoc) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nAddIEAssocLength = + pSrcProfile->nAddIEAssocLength; + qdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc, + pSrcProfile->nAddIEAssocLength); + } + if (pSrcProfile->ChannelInfo.ChannelList) { + pDstProfile->ChannelInfo.ChannelList = + qdf_mem_malloc(pSrcProfile->ChannelInfo. + numOfChannels); + if (NULL == pDstProfile->ChannelInfo.ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->ChannelInfo.numOfChannels = + pSrcProfile->ChannelInfo.numOfChannels; + qdf_mem_copy(pDstProfile->ChannelInfo.ChannelList, + pSrcProfile->ChannelInfo.ChannelList, + pSrcProfile->ChannelInfo.numOfChannels); + } + pDstProfile->AuthType = pSrcProfile->AuthType; + pDstProfile->EncryptionType = pSrcProfile->EncryptionType; + pDstProfile->mcEncryptionType = pSrcProfile->mcEncryptionType; + pDstProfile->negotiatedUCEncryptionType = + pSrcProfile->negotiatedUCEncryptionType; + pDstProfile->negotiatedMCEncryptionType = + pSrcProfile->negotiatedMCEncryptionType; + pDstProfile->negotiatedAuthType = pSrcProfile->negotiatedAuthType; +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif + pDstProfile->BSSType = pSrcProfile->BSSType; + pDstProfile->phyMode = pSrcProfile->phyMode; + pDstProfile->csrPersona = pSrcProfile->csrPersona; + +#ifdef FEATURE_WLAN_WAPI + if (csr_is_profile_wapi(pSrcProfile)) + if (pDstProfile->phyMode & eCSR_DOT11_MODE_11n) + pDstProfile->phyMode &= ~eCSR_DOT11_MODE_11n; +#endif /* FEATURE_WLAN_WAPI */ + pDstProfile->ch_params.ch_width = pSrcProfile->ch_params.ch_width; + pDstProfile->ch_params.center_freq_seg0 = + pSrcProfile->ch_params.center_freq_seg0; + pDstProfile->ch_params.center_freq_seg1 = + pSrcProfile->ch_params.center_freq_seg1; + pDstProfile->ch_params.sec_ch_offset = + pSrcProfile->ch_params.sec_ch_offset; + /*Save the WPS info */ + pDstProfile->bWPSAssociation = pSrcProfile->bWPSAssociation; + pDstProfile->bOSENAssociation = pSrcProfile->bOSENAssociation; + pDstProfile->force_24ghz_in_ht20 = pSrcProfile->force_24ghz_in_ht20; + pDstProfile->uapsd_mask = pSrcProfile->uapsd_mask; + pDstProfile->beaconInterval = pSrcProfile->beaconInterval; + pDstProfile->privacy = pSrcProfile->privacy; + pDstProfile->fwdWPSPBCProbeReq = pSrcProfile->fwdWPSPBCProbeReq; + pDstProfile->csr80211AuthType = pSrcProfile->csr80211AuthType; + pDstProfile->dtimPeriod = pSrcProfile->dtimPeriod; + pDstProfile->ApUapsdEnable = pSrcProfile->ApUapsdEnable; + pDstProfile->SSIDs.SSIDList[0].ssidHidden = + pSrcProfile->SSIDs.SSIDList[0].ssidHidden; + pDstProfile->protEnabled = pSrcProfile->protEnabled; + pDstProfile->obssProtEnabled = pSrcProfile->obssProtEnabled; + pDstProfile->cfg_protection = pSrcProfile->cfg_protection; + pDstProfile->wps_state = pSrcProfile->wps_state; + pDstProfile->ieee80211d = pSrcProfile->ieee80211d; + pDstProfile->sap_dot11mc = pSrcProfile->sap_dot11mc; + pDstProfile->supplicant_disabled_roaming = + pSrcProfile->supplicant_disabled_roaming; + qdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys, + sizeof(pDstProfile->Keys)); +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif + if (pSrcProfile->MDID.mdiePresent) { + pDstProfile->MDID.mdiePresent = 1; + pDstProfile->MDID.mobilityDomain = + pSrcProfile->MDID.mobilityDomain; + } + qdf_mem_copy(&pDstProfile->addIeParams, &pSrcProfile->addIeParams, + sizeof(tSirAddIeParams)); + + update_profile_fils_info(pDstProfile, pSrcProfile); + + pDstProfile->beacon_tx_rate = pSrcProfile->beacon_tx_rate; + + if (pSrcProfile->supported_rates.numRates) { + qdf_mem_copy(pDstProfile->supported_rates.rate, + pSrcProfile->supported_rates.rate, + pSrcProfile->supported_rates.numRates); + pDstProfile->supported_rates.numRates = + pSrcProfile->supported_rates.numRates; + } + if (pSrcProfile->extended_rates.numRates) { + qdf_mem_copy(pDstProfile->extended_rates.rate, + pSrcProfile->extended_rates.rate, + pSrcProfile->extended_rates.numRates); + pDstProfile->extended_rates.numRates = + pSrcProfile->extended_rates.numRates; + } + pDstProfile->cac_duration_ms = pSrcProfile->cac_duration_ms; + pDstProfile->dfs_regdomain = pSrcProfile->dfs_regdomain; + pDstProfile->chan_switch_hostapd_rate_enabled = + pSrcProfile->chan_switch_hostapd_rate_enabled; + pDstProfile->force_rsne_override = pSrcProfile->force_rsne_override; +end: + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_release_profile(pMac, pDstProfile); + pDstProfile = NULL; + } + + return status; +} + +QDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_roam_profile *pDstProfile) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamConnectedProfile *pSrcProfile = + &pMac->roam.roamSession[sessionId].connectedProfile; + + qdf_mem_zero(pDstProfile, sizeof(struct csr_roam_profile)); + + pDstProfile->BSSIDs.bssid = qdf_mem_malloc(sizeof(struct qdf_mac_addr)); + if (NULL == pDstProfile->BSSIDs.bssid) { + status = QDF_STATUS_E_NOMEM; + sme_err("failed to allocate memory for BSSID " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes)); + goto end; + } + pDstProfile->BSSIDs.numOfBSSIDs = 1; + qdf_copy_macaddr(pDstProfile->BSSIDs.bssid, &pSrcProfile->bssid); + + if (pSrcProfile->SSID.length > 0) { + pDstProfile->SSIDs.SSIDList = + qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (NULL == pDstProfile->SSIDs.SSIDList) { + status = QDF_STATUS_E_NOMEM; + sme_err("failed to allocate memory for SSID " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes)); + goto end; + } + pDstProfile->SSIDs.numOfSSIDs = 1; + pDstProfile->SSIDs.SSIDList[0].handoffPermitted = + pSrcProfile->handoffPermitted; + pDstProfile->SSIDs.SSIDList[0].ssidHidden = + pSrcProfile->ssidHidden; + qdf_mem_copy(&pDstProfile->SSIDs.SSIDList[0].SSID, + &pSrcProfile->SSID, sizeof(tSirMacSSid)); + } + if (pSrcProfile->nAddIEAssocLength) { + pDstProfile->pAddIEAssoc = + qdf_mem_malloc(pSrcProfile->nAddIEAssocLength); + if (NULL == pDstProfile->pAddIEAssoc) { + status = QDF_STATUS_E_NOMEM; + sme_err("failed to allocate mem for additional ie"); + goto end; + } + pDstProfile->nAddIEAssocLength = pSrcProfile->nAddIEAssocLength; + qdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc, + pSrcProfile->nAddIEAssocLength); + } + pDstProfile->ChannelInfo.ChannelList = qdf_mem_malloc(1); + if (NULL == pDstProfile->ChannelInfo.ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->ChannelInfo.numOfChannels = 1; + pDstProfile->ChannelInfo.ChannelList[0] = pSrcProfile->operationChannel; + pDstProfile->AuthType.numEntries = 1; + pDstProfile->AuthType.authType[0] = pSrcProfile->AuthType; + pDstProfile->negotiatedAuthType = pSrcProfile->AuthType; + pDstProfile->EncryptionType.numEntries = 1; + pDstProfile->EncryptionType.encryptionType[0] = + pSrcProfile->EncryptionType; + pDstProfile->negotiatedUCEncryptionType = + pSrcProfile->EncryptionType; + pDstProfile->mcEncryptionType.numEntries = 1; + pDstProfile->mcEncryptionType.encryptionType[0] = + pSrcProfile->mcEncryptionType; + pDstProfile->negotiatedMCEncryptionType = + pSrcProfile->mcEncryptionType; + pDstProfile->BSSType = pSrcProfile->BSSType; + qdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys, + sizeof(pDstProfile->Keys)); + if (pSrcProfile->MDID.mdiePresent) { + pDstProfile->MDID.mdiePresent = 1; + pDstProfile->MDID.mobilityDomain = + pSrcProfile->MDID.mobilityDomain; + } +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif + +end: + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_release_profile(pMac, pDstProfile); + pDstProfile = NULL; + } + + return status; +} + +QDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tScanResultHandle hBSSList, + enum csr_roam_reason reason, uint32_t roamId, + bool fImediate, bool fClearScan) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + csr_scan_result_purge(pMac, hBSSList); + sme_err(" fail to get command buffer"); + status = QDF_STATUS_E_RESOURCES; + } else { + if (fClearScan) + csr_scan_abort_mac_scan(pMac, sessionId, INVAL_SCAN_ID); + + pCommand->u.roamCmd.fReleaseProfile = false; + if (NULL == pProfile) { + /* We can roam now + * Since pProfile is NULL, we need to build our own + * profile, set everything to default We can only + * support open and no encryption + */ + pCommand->u.roamCmd.roamProfile.AuthType.numEntries = 1; + pCommand->u.roamCmd.roamProfile.AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + pCommand->u.roamCmd.roamProfile.EncryptionType. + numEntries = 1; + pCommand->u.roamCmd.roamProfile.EncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE; + pCommand->u.roamCmd.roamProfile.csrPersona = + QDF_STA_MODE; + } else { + /* make a copy of the profile */ + status = csr_roam_copy_profile(pMac, &pCommand->u. + roamCmd.roamProfile, + pProfile); + if (QDF_IS_STATUS_SUCCESS(status)) + pCommand->u.roamCmd.fReleaseProfile = true; + } + + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.hBSSList = hBSSList; + pCommand->u.roamCmd.roamId = roamId; + pCommand->u.roamCmd.roamReason = reason; + /* We need to free the BssList when the command is done */ + pCommand->u.roamCmd.fReleaseBssList = true; + pCommand->u.roamCmd.fUpdateCurRoamProfile = true; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("CSR PERSONA=%d"), + pCommand->u.roamCmd.roamProfile.csrPersona); + status = csr_queue_sme_command(pMac, pCommand, fImediate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("fail to send message status: %d", status); + } + } + + return status; +} + +QDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tCsrRoamModifyProfileFields + *pMmodProfileFields, + enum csr_roam_reason reason, uint32_t roamId, + bool fImediate) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sme_err("fail to get command buffer"); + status = QDF_STATUS_E_RESOURCES; + } else { + csr_scan_abort_mac_scan(pMac, sessionId, INVAL_SCAN_ID); + if (pProfile) { + /* This is likely trying to reassoc to + * different profile + */ + pCommand->u.roamCmd.fReleaseProfile = false; + /* make a copy of the profile */ + status = csr_roam_copy_profile(pMac, &pCommand->u. + roamCmd.roamProfile, + pProfile); + pCommand->u.roamCmd.fUpdateCurRoamProfile = true; + } else { + status = csr_roam_copy_connected_profile(pMac, + sessionId, + &pCommand->u.roamCmd. + roamProfile); + /* how to update WPA/WPA2 info in roamProfile?? */ + pCommand->u.roamCmd.roamProfile.uapsd_mask = + pMmodProfileFields->uapsd_mask; + } + if (QDF_IS_STATUS_SUCCESS(status)) + pCommand->u.roamCmd.fReleaseProfile = true; + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamId = roamId; + pCommand->u.roamCmd.roamReason = reason; + /* We need to free the BssList when the command is done */ + /* For reassoc there is no BSS list, so the bool set to false */ + pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + pCommand->u.roamCmd.fReleaseBssList = false; + pCommand->u.roamCmd.fReassoc = true; + csr_roam_remove_duplicate_command(pMac, sessionId, pCommand, + reason); + status = csr_queue_sme_command(pMac, pCommand, fImediate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("fail to send message status = %d", status); + csr_roam_completion(pMac, sessionId, NULL, NULL, + eCSR_ROAM_RESULT_FAILURE, false); + } + } + return status; +} + +QDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, + enum csr_roam_reason reason, + uint8_t session_id) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + + pEntry = csr_nonscan_active_ll_peek_head(pMac, LL_ACCESS_LOCK); + + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) && + (eCsrPerformPreauth == reason)) { + sme_debug("DQ-Command = %d, Reason = %d", + pCommand->command, + pCommand->u.roamCmd.roamReason); + if (csr_nonscan_active_ll_remove_entry(pMac, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command(pMac, pCommand); + } + } else if ((eSmeCommandRoam == pCommand->command) && + (eCsrSmeIssuedFTReassoc == reason)) { + sme_debug("DQ-Command = %d, Reason = %d", + pCommand->command, + pCommand->u.roamCmd.roamReason); + if (csr_nonscan_active_ll_remove_entry(pMac, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command(pMac, pCommand); + } + } else { + sme_err("Command = %d, Reason = %d ", + pCommand->command, + pCommand->u.roamCmd.roamReason); + } + } else { + sme_err("pEntry NULL for eWNI_SME_FT_PRE_AUTH_RSP"); + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * csr_is_fils_connection() - API to check if FILS connection + * @profile: CSR Roam Profile + * + * Return: true, if fils connection, false otherwise + */ +static bool csr_is_fils_connection(struct csr_roam_profile *profile) +{ + if (!profile->fils_con_info) + return false; + + return profile->fils_con_info->is_fils_connection; +} +#else +static bool csr_is_fils_connection(struct csr_roam_profile *pProfile) +{ + return false; +} +#endif + +/** + * csr_roam_print_candidate_aps() - print all candidate AP in sorted + * score. + * @results: scan result + * + * Return : void + */ +static void csr_roam_print_candidate_aps(tScanResultHandle results) +{ + tListElem *entry; + struct tag_csrscan_result *bss_desc = NULL; + struct scan_result_list *bss_list = NULL; + + if (!results) + return; + bss_list = (struct scan_result_list *)results; + entry = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + while (entry) { + bss_desc = GET_BASE_ADDR(entry, + struct tag_csrscan_result, Link); + sme_debug("BSSID" MAC_ADDRESS_STR "score is %d", + MAC_ADDR_ARRAY(bss_desc->Result.BssDescriptor.bssId), + bss_desc->bss_score); + + entry = csr_ll_next(&bss_list->List, entry, + LL_ACCESS_NOLOCK); + } +} + +QDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + uint32_t *pRoamId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tScanResultHandle hBSSList; + tCsrScanResultFilter *pScanFilter; + uint32_t roamId = 0; + bool fCallCallback = false; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + tSirBssDescription *first_ap_profile; + uint8_t channel_id = 0; + + if (NULL == pSession) { + sme_err("session does not exist for given sessionId: %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == pProfile) { + sme_err("No profile specified"); + return QDF_STATUS_E_FAILURE; + } + + first_ap_profile = qdf_mem_malloc(sizeof(*first_ap_profile)); + if (NULL == first_ap_profile) { + sme_err("malloc fails for first_ap_profile"); + return QDF_STATUS_E_NOMEM; + } + + /* Initialize the count before proceeding with the Join requests */ + pSession->join_bssid_count = 0; + pSession->discon_in_progress = false; + pSession->is_fils_connection = csr_is_fils_connection(pProfile); + sme_debug( + "called BSSType = %s (%d) authtype = %d encryType = %d", + sme_bss_type_to_string(pProfile->BSSType), + pProfile->BSSType, pProfile->AuthType.authType[0], + pProfile->EncryptionType.encryptionType[0]); + csr_roam_cancel_roaming(pMac, sessionId); + csr_scan_abort_mac_scan(pMac, sessionId, INVAL_SCAN_ID); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued); + /* Check whether ssid changes */ + if (csr_is_conn_state_connected(pMac, sessionId) && + pProfile->SSIDs.numOfSSIDs && + !csr_is_ssid_in_list(&pSession->connectedProfile.SSID, + &pProfile->SSIDs)) + csr_roam_issue_disassociate_cmd(pMac, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + /* + * If roamSession.connectState is disconnecting that mean + * disconnect was received with scan for ssid in progress + * and dropped. This state will ensure that connect will + * not be issued from scan for ssid completion. Thus + * if this fresh connect also issue scan for ssid the connect + * command will be dropped assuming disconnect is in progress. + * Thus reset connectState here + */ + if (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING == + pMac->roam.roamSession[sessionId].connectState) + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifdef FEATURE_WLAN_BTAMP_UT_RF + pSession->maxRetryCount = CSR_JOIN_MAX_RETRY_COUNT; +#endif + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + /* Try to connect to any BSS */ + if (NULL == pProfile) { + /* No encryption */ + pScanFilter->EncryptionType.numEntries = 1; + pScanFilter->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + } else { + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(pMac, + pProfile, pScanFilter); + } + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (pRoamId) + *pRoamId = roamId; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pScanFilter); + goto end; + } + + /*Save the WPS info */ + if (NULL != pProfile) { + pScanFilter->bWPSAssociation = + pProfile->bWPSAssociation; + pScanFilter->bOSENAssociation = + pProfile->bOSENAssociation; + } else { + pScanFilter->bWPSAssociation = 0; + pScanFilter->bOSENAssociation = 0; + } + if (pProfile && CSR_IS_INFRA_AP(pProfile)) { + /* This can be started right away */ + status = csr_roam_issue_connect(pMac, sessionId, pProfile, NULL, + eCsrHddIssued, roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("CSR failed to issue start BSS cmd with status: 0x%08X", + status); + fCallCallback = true; + } else + sme_debug("Connect request to proceed for sap mode"); + + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + goto end; + } + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + sme_debug("csr_scan_get_result Status: %d", status); + csr_roam_print_candidate_aps(hBSSList); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* check if set hw mode needs to be done */ + if ((pScanFilter->csrPersona == QDF_STA_MODE) || + (pScanFilter->csrPersona == QDF_P2P_CLIENT_MODE)) { + bool ok; + + csr_get_bssdescr_from_scan_handle(hBSSList, + first_ap_profile); + status = policy_mgr_is_chan_ok_for_dnbs(pMac->psoc, + first_ap_profile->channelId, &ok); + if (QDF_IS_STATUS_ERROR(status)) { + sme_debug("policy_mgr_is_chan_ok_for_dnbs():error:%d", + status); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + goto error; + } + if (!ok) { + sme_debug("chan:%d not ok for DNBS", + first_ap_profile->channelId); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + status = QDF_STATUS_E_INVAL; + goto error; + } + + channel_id = csr_get_channel_for_hw_mode_change + (pMac, hBSSList, sessionId); + if (!channel_id) + channel_id = first_ap_profile->channelId; + + status = policy_mgr_handle_conc_multiport(pMac->psoc, + sessionId, channel_id); + if ((QDF_IS_STATUS_SUCCESS(status)) && + (!csr_wait_for_connection_update(pMac, true))) { + sme_debug("conn update error"); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + status = QDF_STATUS_E_TIMEOUT; + goto error; + } else if (status == QDF_STATUS_E_FAILURE) { + sme_debug("conn update error"); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + goto error; + } + } + + status = csr_roam_issue_connect(pMac, sessionId, pProfile, + hBSSList, eCsrHddIssued, roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("CSR failed to issue connect cmd with status: 0x%08X", + status); + fCallCallback = true; + } + } else if (NULL != pProfile) { + /* Check whether it is for start ibss */ + if (CSR_IS_START_IBSS(pProfile) || + CSR_IS_NDI(pProfile)) { + status = csr_roam_issue_connect(pMac, sessionId, + pProfile, NULL, eCsrHddIssued, + roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed with status = 0x%08X", + status); + fCallCallback = true; + } + } else { + /* scan for this SSID */ + status = csr_scan_for_ssid(pMac, sessionId, pProfile, + roamId, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("CSR failed to issue SSID scan cmd with status: 0x%08X", + status); + fCallCallback = true; + } else { + sme_debug("SSID scan requested"); + } + } + } else { + fCallCallback = true; + } + +error: + if (NULL != pProfile) + /* + * we need to free memory for filter + * if profile exists + */ + csr_free_scan_filter(pMac, pScanFilter); + + qdf_mem_free(pScanFilter); +end: + /* tell the caller if we fail to trigger a join request */ + if (fCallCallback) { + csr_roam_call_callback(pMac, sessionId, NULL, roamId, + eCSR_ROAM_FAILED, eCSR_ROAM_RESULT_FAILURE); + } + qdf_mem_free(first_ap_profile); + + return status; +} + +/** + * csr_roam_reassoc() - process reassoc command + * @mac_ctx: mac global context + * @session_id: session id + * @profile: roam profile + * @mod_fields: AC info being modified in reassoc + * @roam_id: roam id to be populated + * + * Return: status of operation + */ +QDF_STATUS +csr_roam_reassoc(tpAniSirGlobal mac_ctx, uint32_t session_id, + struct csr_roam_profile *profile, + tCsrRoamModifyProfileFields mod_fields, + uint32_t *roam_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fCallCallback = true; + uint32_t roamId = 0; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (NULL == profile) { + sme_err("No profile specified"); + return QDF_STATUS_E_FAILURE; + } + sme_debug( + "called BSSType = %s (%d) authtype = %d encryType = %d", + sme_bss_type_to_string(profile->BSSType), + profile->BSSType, profile->AuthType.authType[0], + profile->EncryptionType.encryptionType[0]); + csr_roam_cancel_roaming(mac_ctx, session_id); + csr_scan_abort_mac_scan(mac_ctx, session_id, INVAL_SCAN_ID); + csr_roam_remove_duplicate_command(mac_ctx, session_id, NULL, + eCsrHddIssuedReassocToSameAP); + if (csr_is_conn_state_connected(mac_ctx, session_id)) { + if (profile) { + if (profile->SSIDs.numOfSSIDs && + csr_is_ssid_in_list(&session->connectedProfile.SSID, + &profile->SSIDs)) { + fCallCallback = false; + } else { + /* + * Connected SSID did not match with what is + * asked in profile + */ + sme_debug("SSID mismatch"); + } + } else if (qdf_mem_cmp(&mod_fields, + &session->connectedProfile.modifyProfileFields, + sizeof(tCsrRoamModifyProfileFields))) { + fCallCallback = false; + } else { + sme_debug( + /* + * Either the profile is NULL or none of the + * fields in tCsrRoamModifyProfileFields got + * modified + */ + "Profile NULL or nothing to modify"); + } + } else { + sme_debug("Not connected! No need to reassoc"); + } + if (!fCallCallback) { + roamId = GET_NEXT_ROAM_ID(&mac_ctx->roam); + if (roam_id) + *roam_id = roamId; + status = csr_roam_issue_reassoc(mac_ctx, session_id, profile, + &mod_fields, eCsrHddIssuedReassocToSameAP, + roamId, false); + } else { + status = csr_roam_call_callback(mac_ctx, session_id, NULL, + roamId, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; +} + +static QDF_STATUS csr_roam_join_last_profile(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = NULL; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId; + struct csr_roam_profile *pProfile = NULL; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found ", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->pCurRoamProfile) { + csr_scan_abort_mac_scan(pMac, sessionId, INVAL_SCAN_ID); + /* We have to make a copy of pCurRoamProfile because it + * will be free inside csr_roam_issue_connect + */ + pProfile = qdf_mem_malloc(sizeof(struct csr_roam_profile)); + if (NULL == pProfile) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + status = csr_roam_copy_profile(pMac, pProfile, + pSession->pCurRoamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + status = csr_roam_prepare_filter_from_profile(pMac, pProfile, + pScanFilter); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* we want to put the last connected BSS to the + * very beginning, if possible + */ + csr_move_bss_to_head_from_bssid(pMac, + &pSession->connectedProfile.bssid, hBSSList); + status = csr_roam_issue_connect(pMac, sessionId, + pProfile, hBSSList, eCsrHddIssued, + roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + goto end; + } + } else { + /* scan for this SSID only incase AP suppresses SSID */ + status = csr_scan_for_ssid(pMac, sessionId, pProfile, + roamId, true); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + } + } /* We have a profile */ + else { + sme_warn("cannot find a roaming profile"); + goto end; + } +end: + if (pScanFilter) { + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + } + if (NULL != pProfile) { + csr_release_profile(pMac, pProfile); + qdf_mem_free(pProfile); + } + return status; +} + +QDF_STATUS csr_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (csr_is_conn_state_connected(pMac, sessionId)) { + status = csr_roam_issue_disassociate_cmd(pMac, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + if (QDF_IS_STATUS_SUCCESS(status)) + status = csr_roam_join_last_profile(pMac, sessionId); + } + return status; +} + +QDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + csr_roam_cancel_roaming(pMac, sessionId); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued); + if (csr_is_conn_state_disconnected(pMac, sessionId)) + status = csr_roam_join_last_profile(pMac, sessionId); + + return status; +} + +QDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, + tSmeCmd *pCommand, + bool fDisassoc, bool fMICFailure) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fComplete = false; + enum csr_roam_substate NewSubstate; + uint32_t sessionId = pCommand->sessionId; + + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + sme_debug("Stop Wait for key timer and change substate to eCSR_ROAM_SUBSTATE_NONE"); + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + /* change state to 'Roaming'... */ + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId); + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + /* If we are in an IBSS, then stop the IBSS... */ + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + fComplete = (!QDF_IS_STATUS_SUCCESS(status)); + } else if (csr_is_conn_state_infra(pMac, sessionId)) { + /* + * in Infrastructure, we need to disassociate from the + * Infrastructure network... + */ + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED; + if (eCsrSmeIssuedDisassocForHandoff == + pCommand->u.roamCmd.roamReason) { + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF; + } else + if ((eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason) + && (eSIR_MAC_DISASSOC_LEAVING_BSS_REASON == + pCommand->u.roamCmd.reason)) { + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "set to substate eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT"); + } + if (eCsrSmeIssuedDisassocForHandoff != + pCommand->u.roamCmd.roamReason) { + /* + * If we are in neighbor preauth done state then + * on receiving disassoc or deauth we dont roam + * instead we just disassoc from current ap and + * then go to disconnected state. + * This happens for ESE and 11r FT connections ONLY. + */ + if (csr_roam_is11r_assoc(pMac, sessionId) && + (csr_neighbor_roam_state_preauth_done(pMac, + sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + pMac, sessionId); +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(pMac, sessionId) && + (csr_neighbor_roam_state_preauth_done(pMac, + sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + pMac, sessionId); +#endif + if (csr_roam_is_fast_roam_enabled(pMac, sessionId) && + (csr_neighbor_roam_state_preauth_done(pMac, + sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + pMac, sessionId); + } + if (fDisassoc) + status = csr_roam_issue_disassociate(pMac, sessionId, + NewSubstate, + fMICFailure); + else + status = csr_roam_issue_deauth(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ); + fComplete = (!QDF_IS_STATUS_SUCCESS(status)); + } else { + /* we got a dis-assoc request while not connected to any peer */ + /* just complete the command */ + fComplete = true; + status = QDF_STATUS_E_FAILURE; + } + if (fComplete) + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, sessionId); + + if (QDF_IS_STATUS_SUCCESS(status)) { + if (csr_is_conn_state_infra(pMac, sessionId)) { + /* Set the state to disconnect here */ + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + } + } else + sme_warn(" failed with status %d", status); + return status; +} + +/** + * csr_prepare_disconnect_command() - function to prepare disconnect command + * @mac: pointer to global mac structure + * @session_id: sme session index + * @sme_cmd: pointer to sme command being prepared + * + * Function to prepare internal sme disconnect command + * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS_E_RESOURCES on failure + */ + +QDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac, + uint32_t session_id, tSmeCmd **sme_cmd) +{ + tSmeCmd *command; + + command = csr_get_command_buffer(mac); + if (!command) { + sme_err("fail to get command buffer"); + return QDF_STATUS_E_RESOURCES; + } + + command->command = eSmeCommandRoam; + command->sessionId = (uint8_t)session_id; + command->u.roamCmd.roamReason = eCsrForcedDisassoc; + + *sme_cmd = command; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sme_err(" fail to get command buffer"); + status = QDF_STATUS_E_RESOURCES; + break; + } + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + sme_debug( + "Disassociate reason: %d, sessionId: %d", + reason, sessionId); + switch (reason) { + case eCSR_DISCONNECT_REASON_MIC_ERROR: + pCommand->u.roamCmd.roamReason = + eCsrForcedDisassocMICFailure; + break; + case eCSR_DISCONNECT_REASON_DEAUTH: + pCommand->u.roamCmd.roamReason = eCsrForcedDeauth; + break; + case eCSR_DISCONNECT_REASON_HANDOFF: + pCommand->u.roamCmd.roamReason = + eCsrSmeIssuedDisassocForHandoff; + break; + case eCSR_DISCONNECT_REASON_UNSPECIFIED: + case eCSR_DISCONNECT_REASON_DISASSOC: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + break; + case eCSR_DISCONNECT_REASON_ROAM_HO_FAIL: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + break; + case eCSR_DISCONNECT_REASON_IBSS_LEAVE: + pCommand->u.roamCmd.roamReason = eCsrForcedIbssLeave; + break; + case eCSR_DISCONNECT_REASON_STA_HAS_LEFT: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + pCommand->u.roamCmd.reason = + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "SME convert to internal reason code eCsrStaHasLeft"); + break; + case eCSR_DISCONNECT_REASON_NDI_DELETE: + pCommand->u.roamCmd.roamReason = eCsrStopBss; + pCommand->u.roamCmd.roamProfile.BSSType = + eCSR_BSS_TYPE_NDI; + default: + break; + } + pCommand->u.roamCmd.disconnect_reason = reason; + status = csr_queue_sme_command(pMac, pCommand, true); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to send message status: %d", status); + } while (0); + return status; +} + +QDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + bool fHighPriority) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL != pCommand) { + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrStopBss; + status = csr_queue_sme_command(pMac, pCommand, fHighPriority); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to send message status: %d", status); + } else { + sme_err("fail to get command buffer"); + status = QDF_STATUS_E_RESOURCES; + } + return status; +} + +QDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session: %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_BTAMP_UT_RF + /* Stop the retry */ + pSession->maxRetryCount = 0; + csr_roam_stop_join_retry_timer(pMac, sessionId); +#endif + /* Not to call cancel roaming here */ + /* Only issue disconnect when necessary */ + if (csr_is_conn_state_connected(pMac, sessionId) + || csr_is_bss_type_ibss(pSession->connectedProfile.BSSType) + || csr_is_roam_command_waiting_for_session(pMac, sessionId) + || CSR_IS_CONN_NDI(&pSession->connectedProfile)) { + sme_debug("called"); + status = csr_roam_issue_disassociate_cmd(pMac, sessionId, + reason); + } else { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING; + csr_scan_abort_mac_scan(pMac, sessionId, INVAL_SCAN_ID); + status = QDF_STATUS_CMD_NOT_QUEUED; + sme_debug("Disconnect cmd not queued, Roam command is not present return with status: %d", + status); + } + return status; +} + +QDF_STATUS csr_roam_disconnect(tpAniSirGlobal mac_ctx, uint32_t session_id, + eCsrRoamDisconnectReason reason) +{ + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("session: %d not found ", session_id); + return QDF_STATUS_E_FAILURE; + } + + session->discon_in_progress = true; + csr_roam_cancel_roaming(mac_ctx, session_id); + csr_roam_remove_duplicate_command(mac_ctx, session_id, NULL, + eCsrForcedDisassoc); + + return csr_roam_disconnect_internal(mac_ctx, session_id, reason); +} + +QDF_STATUS csr_roam_save_connected_information(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tDot11fBeaconIEs *pIesTemp = pIes; + uint8_t index; + struct csr_roam_session *pSession = NULL; + tCsrRoamConnectedProfile *pConnectProfile = NULL; + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "session: %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("session id: %d", sessionId); + pConnectProfile = &pSession->connectedProfile; + if (pConnectProfile->pAddIEAssoc) { + qdf_mem_free(pConnectProfile->pAddIEAssoc); + pConnectProfile->pAddIEAssoc = NULL; + } + /* + * In case of LFR2.0, the connected profile is copied into a temporary + * profile and cleared and then is copied back. This is not needed for + * LFR3.0, since the profile is not cleared. + */ + if (!pSession->roam_synch_in_progress) { + qdf_mem_zero(&pSession->connectedProfile, + sizeof(tCsrRoamConnectedProfile)); + pConnectProfile->AuthType = pProfile->negotiatedAuthType; + pConnectProfile->AuthInfo = pProfile->AuthType; + pConnectProfile->EncryptionType = + pProfile->negotiatedUCEncryptionType; + pConnectProfile->EncryptionInfo = pProfile->EncryptionType; + pConnectProfile->mcEncryptionType = + pProfile->negotiatedMCEncryptionType; + pConnectProfile->mcEncryptionInfo = pProfile->mcEncryptionType; + pConnectProfile->BSSType = pProfile->BSSType; + pConnectProfile->modifyProfileFields.uapsd_mask = + pProfile->uapsd_mask; + qdf_mem_copy(&pConnectProfile->Keys, &pProfile->Keys, + sizeof(tCsrKeys)); + if (pProfile->nAddIEAssocLength) { + pConnectProfile->pAddIEAssoc = + qdf_mem_malloc(pProfile->nAddIEAssocLength); + if (NULL == pConnectProfile->pAddIEAssoc) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to allocate memory for IE"); + return QDF_STATUS_E_FAILURE; + } + pConnectProfile->nAddIEAssocLength = + pProfile->nAddIEAssocLength; + qdf_mem_copy(pConnectProfile->pAddIEAssoc, + pProfile->pAddIEAssoc, + pProfile->nAddIEAssocLength); + } +#ifdef WLAN_FEATURE_11W + pConnectProfile->MFPEnabled = pProfile->MFPEnabled; + pConnectProfile->MFPRequired = pProfile->MFPRequired; + pConnectProfile->MFPCapable = pProfile->MFPCapable; +#endif + } + /* Save bssid */ + pConnectProfile->operationChannel = pSirBssDesc->channelId; + pConnectProfile->beaconInterval = pSirBssDesc->beaconInterval; + if (!pConnectProfile->beaconInterval) + sme_err("ERROR: Beacon interval is ZERO"); + csr_get_bss_id_bss_desc(pSirBssDesc, &pConnectProfile->bssid); + if (pSirBssDesc->mdiePresent) { + pConnectProfile->MDID.mdiePresent = 1; + pConnectProfile->MDID.mobilityDomain = + (pSirBssDesc->mdie[1] << 8) | (pSirBssDesc->mdie[0]); + } + if (NULL == pIesTemp) + status = csr_get_parsed_bss_description_ies(pMac, pSirBssDesc, + &pIesTemp); +#ifdef FEATURE_WLAN_ESE + if ((csr_is_profile_ese(pProfile) || + (QDF_IS_STATUS_SUCCESS(status) && (pIesTemp->ESEVersion.present) + && (pProfile->negotiatedAuthType == eCSR_AUTH_TYPE_OPEN_SYSTEM))) + && (pMac->roam.configParam.isEseIniFeatureEnabled)) { + pConnectProfile->isESEAssoc = 1; + } +#endif + /* save ssid */ + if (QDF_IS_STATUS_SUCCESS(status)) { + if (pIesTemp->SSID.present && + !csr_is_nullssid(pIesTemp->SSID.ssid, + pIesTemp->SSID.num_ssid)) { + pConnectProfile->SSID.length = pIesTemp->SSID.num_ssid; + qdf_mem_copy(pConnectProfile->SSID.ssId, + pIesTemp->SSID.ssid, + pIesTemp->SSID.num_ssid); + } else if (pProfile->SSIDs.numOfSSIDs) { + pConnectProfile->SSID.length = + pProfile->SSIDs.SSIDList[0].SSID.length; + qdf_mem_copy(pConnectProfile->SSID.ssId, + pProfile->SSIDs.SSIDList[0].SSID.ssId, + pConnectProfile->SSID.length); + } + /* Save the bss desc */ + status = csr_roam_save_connected_bss_desc(pMac, sessionId, + pSirBssDesc); + + if (CSR_IS_QOS_BSS(pIesTemp) || pIesTemp->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 + */ + pConnectProfile->qap = true; + else + pConnectProfile->qap = false; + + if (pIesTemp->ExtCap.present) { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + pIesTemp->ExtCap.bytes; + pConnectProfile->proxyARPService = p_ext_cap-> + proxy_arp_service; + } + + if (NULL == pIes) + /* Free memory if it allocated locally */ + qdf_mem_free(pIesTemp); + } + /* Save Qos connection */ + pConnectProfile->qosConnection = + pMac->roam.roamSession[sessionId].fWMMConnection; + + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_free_connect_bss_desc(pMac, sessionId); + + for (index = 0; index < pProfile->SSIDs.numOfSSIDs; index++) { + if ((pProfile->SSIDs.SSIDList[index].SSID.length == + pConnectProfile->SSID.length) + && (!qdf_mem_cmp(pProfile->SSIDs.SSIDList[index].SSID. + ssId, pConnectProfile->SSID.ssId, + pConnectProfile->SSID.length))) { + pConnectProfile->handoffPermitted = pProfile->SSIDs. + SSIDList[index].handoffPermitted; + break; + } + pConnectProfile->handoffPermitted = false; + } + + return status; +} + + +bool is_disconnect_pending(tpAniSirGlobal pmac, + uint8_t sessionid) +{ + tListElem *entry = NULL; + tListElem *next_entry = NULL; + tSmeCmd *command = NULL; + bool disconnect_cmd_exist = false; + + csr_nonscan_pending_ll_lock(pmac); + entry = csr_nonscan_pending_ll_peek_head(pmac, LL_ACCESS_NOLOCK); + while (entry) { + next_entry = csr_nonscan_pending_ll_next(pmac, + entry, LL_ACCESS_NOLOCK); + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (command && CSR_IS_DISCONNECT_COMMAND(command) && + command->sessionId == sessionid){ + disconnect_cmd_exist = true; + break; + } + entry = next_entry; + } + csr_nonscan_pending_ll_unlock(pmac); + return disconnect_cmd_exist; +} + +static void csr_roam_join_rsp_processor(tpAniSirGlobal pMac, + tSirSmeJoinRsp *pSmeJoinRsp) +{ + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + struct csr_roam_session *session_ptr; + + if (pSmeJoinRsp) { + session_ptr = CSR_GET_SESSION(pMac, pSmeJoinRsp->sessionId); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Sme Join Response is NULL")); + return; + } + if (!session_ptr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + ("session %d not found"), pSmeJoinRsp->sessionId); + return; + } + /* The head of the active list is the request we sent */ + pEntry = csr_nonscan_active_ll_peek_head(pMac, LL_ACCESS_LOCK); + if (pEntry) + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + + sme_debug("is_fils_connection %d", pSmeJoinRsp->is_fils_connection); + /* Copy Sequence Number last used for FILS assoc failure case */ + if (session_ptr->is_fils_connection) + session_ptr->fils_seq_num = pSmeJoinRsp->fils_seq_num; + + if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) { + if (pCommand + && eCsrSmeIssuedAssocToSimilarAP == + pCommand->u.roamCmd.roamReason) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); +#endif + } + + session_ptr->supported_nss_1x1 = + pSmeJoinRsp->supported_nss_1x1; + sme_debug("SME session supported nss: %d", + session_ptr->supported_nss_1x1); + + /* + * The join bssid count can be reset as soon as + * we are done with the join requests and returning + * the response to upper layers + */ + session_ptr->join_bssid_count = 0; + csr_roam_complete(pMac, eCsrJoinSuccess, (void *)pSmeJoinRsp, + pSmeJoinRsp->sessionId); + } else { + uint32_t roamId = 0; + bool is_dis_pending; + + /* The head of the active list is the request we sent + * Try to get back the same profile and roam again + */ + if (pCommand) + roamId = pCommand->u.roamCmd.roamId; + session_ptr->joinFailStatusCode.statusCode = + pSmeJoinRsp->statusCode; + session_ptr->joinFailStatusCode.reasonCode = + pSmeJoinRsp->protStatusCode; + sme_warn("SmeJoinReq failed with statusCode= 0x%08X [%d]", + pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode); + /* If Join fails while Handoff is in progress, indicate + * disassociated event to supplicant to reconnect + */ + if (csr_roam_is_handoff_in_progress(pMac, + pSmeJoinRsp->sessionId)) { + csr_roam_call_callback(pMac, pSmeJoinRsp->sessionId, + NULL, roamId, + eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); + /* Should indicate neighbor roam algorithm about the + * connect failure here + */ + csr_neighbor_roam_indicate_connect(pMac, + pSmeJoinRsp->sessionId, + QDF_STATUS_E_FAILURE); + } + /* + * if userspace has issued disconnection, + * driver should not continue connecting + */ + is_dis_pending = is_disconnect_pending(pMac, + session_ptr->sessionId); + if (pCommand && (session_ptr->join_bssid_count < + CSR_MAX_BSSID_COUNT) && !is_dis_pending) + csr_roam(pMac, pCommand); + else { + /* + * When the upper layers issue a connect command, there + * is a roam command with reason eCsrHddIssued that + * gets enqueued and an associated timer for the SME + * command timeout is started which is currently 120 + * seconds. This command would be dequeued only upon + * successful connections. In case of join failures, if + * there are too many BSS in the cache, and if we fail + * Join requests with all of them, there is a chance of + * timing out the above timer. + */ + if (session_ptr->join_bssid_count >= + CSR_MAX_BSSID_COUNT) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "Excessive Join Req Failures"); + + if (is_dis_pending) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "disconnect is pending, complete roam"); + + if (session_ptr->bRefAssocStartCnt) + session_ptr->bRefAssocStartCnt--; + + session_ptr->join_bssid_count = 0; + + csr_roam_call_callback(pMac, session_ptr->sessionId, + NULL, roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + pSmeJoinRsp->sessionId); + } + } /*else: ( eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode ) */ +} + +static QDF_STATUS csr_roam_issue_join(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, + struct csr_roam_profile *pProfile, + uint32_t roamId) +{ + QDF_STATUS status; + + sme_debug("Attempting to Join Bssid= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pSirBssDesc->bssId)); + + /* Set the roaming substate to 'join attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_JOIN_REQ, sessionId); + /* attempt to Join this BSS... */ + status = csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, + pIes, eWNI_SME_JOIN_REQ); + return status; +} + +static void +csr_roam_reissue_roam_command(tpAniSirGlobal pMac, uint8_t session_id) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + struct csr_roam_info roamInfo; + uint32_t sessionId; + struct csr_roam_session *pSession; + + pEntry = csr_nonscan_active_ll_peek_head(pMac, LL_ACCESS_LOCK); + if (NULL == pEntry) { + sme_err("Disassoc rsp can't continue, no active CMD"); + return; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandRoam != pCommand->command) { + sme_err("Active cmd, is not a roaming CMD"); + return; + } + sessionId = pCommand->sessionId; + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return; + } + + if (!pCommand->u.roamCmd.fStopWds) { + if (pSession->bRefAssocStartCnt > 0) { + /* + * bRefAssocStartCnt was incremented in + * csr_roam_join_next_bss when the roam command issued + * previously. As part of reissuing the roam command + * again csr_roam_join_next_bss is going increment + * RefAssocStartCnt. So make sure to decrement the + * bRefAssocStartCnt + */ + pSession->bRefAssocStartCnt--; + } + if (eCsrStopRoaming == csr_roam_join_next_bss(pMac, pCommand, + true)) { + sme_warn("Failed to reissue join command"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + session_id); + } + return; + } + qdf_mem_zero(&roamInfo, sizeof(struct csr_roam_info)); + roamInfo.pBssDesc = pCommand->u.roamCmd.pLastRoamBss; + roamInfo.statusCode = pSession->joinFailStatusCode.statusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + pSession->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED; + csr_roam_call_callback(pMac, sessionId, &roamInfo, + pCommand->u.roamCmd.roamId, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_DISASSOCIATED); + + if (!QDF_IS_STATUS_SUCCESS(csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ))) { + sme_err("Failed to reissue stop_bss command for WDS"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, session_id); + } +} + +bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + bool fRet = false; + tListElem *pEntry; + tSmeCmd *pCommand = NULL; + + /* alwasy lock active list before locking pending list */ + csr_nonscan_active_ll_lock(pMac); + pEntry = csr_nonscan_active_ll_peek_head(pMac, LL_ACCESS_NOLOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + } + } + if (false == fRet) { + csr_nonscan_pending_ll_lock(pMac); + pEntry = csr_nonscan_pending_ll_peek_head(pMac, + LL_ACCESS_NOLOCK); + while (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + break; + } + pEntry = csr_nonscan_pending_ll_next(pMac, pEntry, + LL_ACCESS_NOLOCK); + } + csr_nonscan_pending_ll_unlock(pMac); + } + csr_nonscan_active_ll_unlock(pMac); + + return fRet; +} + +static void +csr_roaming_state_config_cnf_processor(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, uint32_t result, uint8_t sme_session_id) +{ + struct tag_csrscan_result *scan_result = NULL; + tSirBssDescription *bss_desc = NULL; + uint32_t session_id; + struct csr_roam_session *session; + tDot11fBeaconIEs *local_ies = NULL; + bool is_ies_malloced = false; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (NULL == cmd) { + sme_err("given sme cmd is null"); + return; + } + session_id = cmd->sessionId; + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("session %d not found", session_id); + return; + } + + if (CSR_IS_ROAMING(session) && session->fCancelRoaming) { + /* the roaming is cancelled. Simply complete the command */ + sme_warn("Roam command canceled"); + csr_roam_complete(mac_ctx, eCsrNothingToJoin, NULL, + sme_session_id); + return; + } + + if (!QDF_IS_STATUS_SUCCESS(result)) { + /* + * In the event the configuration failed, for infra let the roam + * processor attempt to join something else... + */ + if (cmd->u.roamCmd.pRoamBssEntry + && CSR_IS_INFRASTRUCTURE(&cmd->u.roamCmd.roamProfile)) { + csr_roam(mac_ctx, cmd); + } else { + /* We need to complete the command */ + if (csr_is_bss_type_ibss + (cmd->u.roamCmd.roamProfile.BSSType)) { + csr_roam_complete(mac_ctx, eCsrStartBssFailure, + NULL, sme_session_id); + } else { + csr_roam_complete(mac_ctx, eCsrNothingToJoin, + NULL, sme_session_id); + } + } + return; + } + + /* we have active entry */ + sme_debug("Cfg sequence complete"); + /* + * Successfully set the configuration parameters for the new Bss. + * Attempt to join the roaming Bss + */ + if (cmd->u.roamCmd.pRoamBssEntry) { + scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + struct tag_csrscan_result, + Link); + bss_desc = &scan_result->Result.BssDescriptor; + } + if (csr_is_bss_type_ibss(cmd->u.roamCmd.roamProfile.BSSType) + || CSR_IS_INFRA_AP(&cmd->u.roamCmd.roamProfile) + || CSR_IS_NDI(&cmd->u.roamCmd.roamProfile)) { + if (!QDF_IS_STATUS_SUCCESS(csr_roam_issue_start_bss(mac_ctx, + session_id, &session->bssParams, + &cmd->u.roamCmd.roamProfile, + bss_desc, + cmd->u.roamCmd.roamId))) { + sme_err("CSR start BSS failed"); + /* We need to complete the command */ + csr_roam_complete(mac_ctx, eCsrStartBssFailure, NULL, + sme_session_id); + } + return; + } + + if (!cmd->u.roamCmd.pRoamBssEntry) { + sme_err("pRoamBssEntry is NULL"); + /* We need to complete the command */ + csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL, + sme_session_id); + return; + } + + if (NULL == scan_result) { + /* If we are roaming TO an Infrastructure BSS... */ + QDF_ASSERT(scan_result != NULL); + return; + } + + if (!csr_is_infra_bss_desc(bss_desc)) { + sme_warn("found BSSType mismatching the one in BSS descp"); + return; + } + + local_ies = (tDot11fBeaconIEs *) scan_result->Result.pvIes; + if (!local_ies) { + status = csr_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &local_ies); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + is_ies_malloced = true; + } + + if (csr_is_conn_state_connected_infra(mac_ctx, session_id)) { + if (csr_is_ssid_equal(mac_ctx, session->pConnectBssDesc, + bss_desc, local_ies)) { + cmd->u.roamCmd.fReassoc = true; + csr_roam_issue_reassociate(mac_ctx, session_id, + bss_desc, local_ies, + &cmd->u.roamCmd.roamProfile); + } else { + /* + * otherwise, we have to issue a new Join request to LIM + * because we disassociated from the previously + * associated AP. + */ + status = csr_roam_issue_join(mac_ctx, session_id, + bss_desc, local_ies, + &cmd->u.roamCmd.roamProfile, + cmd->u.roamCmd.roamId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* try something else */ + csr_roam(mac_ctx, cmd); + } + } + } else { + status = QDF_STATUS_SUCCESS; + /* + * We need to come with other way to figure out that this is + * because of HO in BMP The below API will be only available for + * Android as it uses a different HO algorithm. Reassoc request + * will be used only for ESE and 11r handoff whereas other + * legacy roaming should use join request + */ + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is11r_assoc(mac_ctx, session_id)) { + status = csr_roam_issue_reassociate(mac_ctx, + session_id, bss_desc, + local_ies, + &cmd->u.roamCmd.roamProfile); + } else +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is_ese_assoc(mac_ctx, session_id)) { + /* Now serialize the reassoc command. */ + status = csr_roam_issue_reassociate_cmd(mac_ctx, + session_id); + } else +#endif + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is_fast_roam_enabled(mac_ctx, session_id)) { + /* Now serialize the reassoc command. */ + status = csr_roam_issue_reassociate_cmd(mac_ctx, + session_id); + } else { + /* + * else we are not connected and attempting to Join. + * Issue the Join request. + */ + status = csr_roam_issue_join(mac_ctx, session_id, + bss_desc, + local_ies, + &cmd->u.roamCmd.roamProfile, + cmd->u.roamCmd.roamId); + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* try something else */ + csr_roam(mac_ctx, cmd); + } + } + if (is_ies_malloced) { + /* Locally allocated */ + qdf_mem_free(local_ies); + } +} + +static void csr_roam_roaming_state_reassoc_rsp_processor(tpAniSirGlobal pMac, + tpSirSmeJoinRsp pSmeJoinRsp) +{ + enum csr_roamcomplete_result result; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + struct csr_roam_info roamInfo; + uint32_t roamId = 0; + struct csr_roam_session *csr_session; + + if (pSmeJoinRsp->sessionId >= CSR_ROAM_SESSION_MAX) { + sme_err("Invalid session ID received %d", pSmeJoinRsp->sessionId); + return; + } + + pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pSmeJoinRsp->sessionId]; + if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "CSR SmeReassocReq Successful"); + result = eCsrReassocSuccess; + csr_session = CSR_GET_SESSION(pMac, pSmeJoinRsp->sessionId); + if (NULL != csr_session) { + csr_session->supported_nss_1x1 = + pSmeJoinRsp->supported_nss_1x1; + sme_debug("SME session supported nss: %d", + csr_session->supported_nss_1x1); + } + /* + * Since the neighbor roam algorithm uses reassoc req for + * handoff instead of join, we need the response contents while + * processing the result in csr_roam_process_results() + */ + if (csr_roam_is_handoff_in_progress(pMac, + pSmeJoinRsp->sessionId)) { + /* Need to dig more on indicating events to + * SME QoS module + */ + sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); + csr_roam_complete(pMac, result, pSmeJoinRsp, + pSmeJoinRsp->sessionId); + } else { + csr_roam_complete(pMac, result, NULL, + pSmeJoinRsp->sessionId); + } + } + /* Should we handle this similar to handling the join failure? Is it ok + * to call csr_roam_complete() with state as CsrJoinFailure + */ + else { + sme_warn( + "CSR SmeReassocReq failed with statusCode= 0x%08X [%d]", + pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode); + result = eCsrReassocFailure; + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ROAM_FAIL, + true, false); + if ((eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE == + pSmeJoinRsp->statusCode) + || (eSIR_SME_FT_REASSOC_FAILURE == + pSmeJoinRsp->statusCode) + || (eSIR_SME_INVALID_PARAMETERS == + pSmeJoinRsp->statusCode)) { + /* Inform HDD to turn off FT flag in HDD */ + if (pNeighborRoamInfo) { + qdf_mem_zero(&roamInfo, sizeof(roamInfo)); + csr_roam_call_callback(pMac, + pSmeJoinRsp->sessionId, + &roamInfo, roamId, + eCSR_ROAM_FT_REASSOC_FAILED, + eCSR_ROAM_RESULT_SUCCESS); + /* + * Since the above callback sends a disconnect + * to HDD, we should clean-up our state + * machine as well to be in sync with the upper + * layers. There is no need to send a disassoc + * since: 1) we will never reassoc to the + * current AP in LFR, and 2) there is no need + * to issue a disassoc to the AP with which we + * were trying to reassoc. + */ + csr_roam_complete(pMac, eCsrJoinFailure, NULL, + pSmeJoinRsp->sessionId); + return; + } + } + /* In the event that the Reassociation fails, then we need to + * Disassociate the current association and keep roaming. Note + * that we will attempt to Join the AP instead of a Reassoc + * since we may have attempted a 'Reassoc to self', which AP's + * that don't support Reassoc will force a Disassoc. The + * isassoc rsp message will remove the command from active list + */ + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_issue_disassociate + (pMac, pSmeJoinRsp->sessionId, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, + false))) { + csr_roam_complete(pMac, eCsrJoinFailure, NULL, + pSmeJoinRsp->sessionId); + } + } +} + +static void csr_roam_roaming_state_stop_bss_rsp_processor(tpAniSirGlobal pMac, + tSirSmeRsp *pSmeRsp) +{ + enum csr_roamcomplete_result result_code = eCsrNothingToJoin; + struct csr_roam_profile *profile; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + { + host_log_ibss_pkt_type *pIbssLog; + + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_RSP; + if (eSIR_SME_SUCCESS != pSmeRsp->statusCode) + pIbssLog->status = WLAN_IBSS_STATUS_FAILURE; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + pMac->roam.roamSession[pSmeRsp->sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + if (CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(pMac, pSmeRsp->sessionId)) { + profile = + pMac->roam.roamSession[pSmeRsp->sessionId].pCurRoamProfile; + if (profile && CSR_IS_CONN_NDI(profile)) { + result_code = eCsrStopBssSuccess; + if (pSmeRsp->statusCode != eSIR_SME_SUCCESS) + result_code = eCsrStopBssFailure; + } + csr_roam_complete(pMac, result_code, NULL, pSmeRsp->sessionId); + } else if (CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, + pSmeRsp->sessionId)) { + csr_roam_reissue_roam_command(pMac, pSmeRsp->sessionId); + } +} + +/** + * csr_dequeue_command() - removes a command from active cmd list + * @pMac: mac global context + * + * Return: void + */ +static void +csr_dequeue_command(tpAniSirGlobal mac_ctx) +{ + bool fRemoveCmd; + tSmeCmd *cmd = NULL; + tListElem *entry = csr_nonscan_active_ll_peek_head(mac_ctx, + LL_ACCESS_LOCK); + if (!entry) { + sme_err("NO commands are active"); + return; + } + + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* + * If the head of the queue is Active and it is a given cmd type, remove + * and put this on the Free queue. + */ + if (eSmeCommandRoam != cmd->command) { + sme_err("Roam command not active"); + return; + } + /* + * we need to process the result first before removing it from active + * list because state changes still happening insides + * roamQProcessRoamResults so no other roam command should be issued. + */ + fRemoveCmd = csr_nonscan_active_ll_remove_entry(mac_ctx, entry, + LL_ACCESS_LOCK); + if (cmd->u.roamCmd.fReleaseProfile) { + csr_release_profile(mac_ctx, &cmd->u.roamCmd.roamProfile); + cmd->u.roamCmd.fReleaseProfile = false; + } + if (fRemoveCmd) + csr_release_command(mac_ctx, cmd); + else + sme_err("fail to remove cmd reason %d", + cmd->u.roamCmd.roamReason); +} + +/** + * csr_post_roam_failure() - post roam failure back to csr and issues a disassoc + * @pMac: mac global context + * @session_id: session id + * @roam_info: roam info struct + * @scan_filter: scan filter to free + * @cur_roam_profile: current csr roam profile + * + * Return: void + */ +static void +csr_post_roam_failure(tpAniSirGlobal mac_ctx, + uint32_t session_id, + struct csr_roam_info *roam_info, + tCsrScanResultFilter *scan_filter, + struct csr_roam_profile *cur_roam_profile) +{ + QDF_STATUS status; + + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + } + if (cur_roam_profile) + qdf_mem_free(cur_roam_profile); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + csr_roam_synch_clean_up(mac_ctx, session_id); +#endif + /* Inform the upper layers that the reassoc failed */ + qdf_mem_zero(roam_info, sizeof(struct csr_roam_info)); + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + eCSR_ROAM_FT_REASSOC_FAILED, + eCSR_ROAM_RESULT_SUCCESS); + /* + * Issue a disassoc request so that PE/LIM uses this to clean-up the FT + * session. Upon success, we would re-enter this routine after receiving + * the disassoc response and will fall into the reassoc fail sub-state. + * And, eventually call csr_roam_complete which would remove the roam + * command from SME active queue. + */ + status = csr_roam_issue_disassociate(mac_ctx, session_id, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err( + "csr_roam_issue_disassociate failed, status %d", + status); + csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL, session_id); + } +} + +/** + * csr_check_profile_in_scan_cache() - finds if roam profile is present in scan + * cache or not + * @pMac: mac global context + * @scan_filter: out param, scan filter + * @neighbor_roam_info: roam info struct + * @hBSSList: scan result + * + * Return: true if found else false. + */ +static bool +csr_check_profile_in_scan_cache(tpAniSirGlobal mac_ctx, + tCsrScanResultFilter **scan_filter, + tpCsrNeighborRoamControlInfo neighbor_roam_info, + tScanResultHandle *hBSSList) +{ + QDF_STATUS status; + *scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == *scan_filter) { + sme_err("alloc for ScanFilter failed"); + return false; + } + (*scan_filter)->scan_filter_for_roam = 1; + status = csr_roam_prepare_filter_from_profile(mac_ctx, + &neighbor_roam_info->csrNeighborRoamProfile, + *scan_filter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err( + "failed to prepare scan filter, status %d", + status); + return false; + } + status = csr_scan_get_result(mac_ctx, *scan_filter, hBSSList); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err( + "csr_scan_get_result failed, status %d", + status); + return false; + } + return true; +} + +static +void csr_roam_roaming_state_disassoc_rsp_processor(tpAniSirGlobal pMac, + tSirSmeDisassocRsp *pSmeRsp) +{ + tScanResultHandle hBSSList; + struct csr_roam_info *roamInfo; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId = 0; + struct csr_roam_profile *pCurRoamProfile = NULL; + QDF_STATUS status; + uint32_t sessionId; + struct csr_roam_session *pSession; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tSirSmeDisassocRsp SmeDisassocRsp; + + csr_ser_des_unpack_diassoc_rsp((uint8_t *) pSmeRsp, &SmeDisassocRsp); + sessionId = SmeDisassocRsp.sessionId; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, "sessionId %d", + sessionId); + + if (csr_is_conn_state_infra(pMac, sessionId)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sme_err("session %d not found", sessionId); + return; + } + + roamInfo = qdf_mem_malloc(sizeof(*roamInfo)); + + if (!roamInfo) { + sme_err("failed to allocate memory"); + return; + } + + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, sessionId)) { + sme_debug("***eCsrNothingToJoin***"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, sessionId); + } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, sessionId) || + CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, sessionId)) { + if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) { + sme_debug("CSR force disassociated successful"); + /* + * A callback to HDD will be issued from + * csr_roam_complete so no need to do anything here + */ + } + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, sessionId); + } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "CSR SmeDisassocReq due to HO on session %d", + sessionId); + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + /* + * First ensure if the roam profile is in the scan cache. + * If not, post a reassoc failure and disconnect. + */ + if (!csr_check_profile_in_scan_cache(pMac, &pScanFilter, + pNeighborRoamInfo, &hBSSList)) + goto POST_ROAM_FAILURE; + + /* notify HDD about handoff and provide the BSSID too */ + roamInfo->reasonCode = eCsrRoamReasonBetterAP; + + qdf_copy_macaddr(&roamInfo->bssid, + pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs.bssid); + + csr_roam_call_callback(pMac, sessionId, roamInfo, 0, + eCSR_ROAM_ROAMING_START, + eCSR_ROAM_RESULT_NONE); + + /* + * Copy the connected profile to apply the same for this + * connection as well + */ + pCurRoamProfile = qdf_mem_malloc(sizeof(*pCurRoamProfile)); + if (pCurRoamProfile != NULL) { + /* + * notify sub-modules like QoS etc. that handoff + * happening + */ + sme_qos_csr_event_ind(pMac, sessionId, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, + NULL); + csr_roam_copy_profile(pMac, pCurRoamProfile, + pSession->pCurRoamProfile); + /* + * After ensuring that the roam profile is in the scan + * result list, and pSession->pCurRoamProfile is saved, + * dequeue the command from the active list. + */ + csr_dequeue_command(pMac); + /* make sure to put it at the head of the cmd queue */ + status = csr_roam_issue_connect(pMac, sessionId, + pCurRoamProfile, hBSSList, + eCsrSmeIssuedAssocToSimilarAP, + roamId, true, false); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err( + "issue_connect failed. status %d", + status); + + csr_release_profile(pMac, pCurRoamProfile); + qdf_mem_free(pCurRoamProfile); + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + qdf_mem_free(roamInfo); + return; + } else { + sme_err("pCurRoamProfile memory alloc failed"); + QDF_ASSERT(0); + csr_dequeue_command(pMac); + } + csr_scan_result_purge(pMac, hBSSList); + +POST_ROAM_FAILURE: + csr_post_roam_failure(pMac, sessionId, roamInfo, + pScanFilter, pCurRoamProfile); + } /* else if ( CSR_IS_ROAM_SUBSTATE_DISASSOC_HO( pMac ) ) */ + else if (CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, sessionId)) { + /* Disassoc due to Reassoc failure falls into this codepath */ + csr_roam_complete(pMac, eCsrJoinFailure, NULL, sessionId); + } else { + if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) { + /* + * Successfully disassociated from the 'old' Bss. + * We get Disassociate response in three conditions. + * 1) The case where we are disasociating from an Infra + * Bss to start an IBSS. + * 2) When we are disassociating from an Infra Bss to + * join an IBSS or a new infra network. + * 3) Where we are doing an Infra to Infra roam between + * networks with different SSIDs. + * In all cases, we set the new Bss configuration here + * and attempt to join + */ + sme_debug("Disassociated successfully"); + } else { + sme_err( + "DisassocReq failed, statusCode= 0x%08X", + SmeDisassocRsp.statusCode); + } + /* We are not done yet. Get the data and continue roaming */ + csr_roam_reissue_roam_command(pMac, sessionId); + } + qdf_mem_free(roamInfo); +} + +static void csr_roam_roaming_state_deauth_rsp_processor(tpAniSirGlobal pMac, + tSirSmeDeauthRsp *pSmeRsp) +{ + tSirResultCodes statusCode; + /* No one is sending eWNI_SME_DEAUTH_REQ to PE. */ + sme_debug("is no-op"); + statusCode = csr_get_de_auth_rsp_status_code(pSmeRsp); + pMac->roam.deauthRspStatus = statusCode; + if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL, + pSmeRsp->sessionId); + } else { + if (eSIR_SME_SUCCESS == statusCode) { + /* Successfully deauth from the 'old' Bss... */ + /* */ + sme_debug( + "CSR SmeDeauthReq disassociated Successfully"); + } else { + sme_warn( + "SmeDeauthReq failed with statusCode= 0x%08X", + statusCode); + } + /* We are not done yet. Get the data and continue roaming */ + csr_roam_reissue_roam_command(pMac, pSmeRsp->sessionId); + } +} + +static void csr_roam_roaming_state_start_bss_rsp_processor(tpAniSirGlobal pMac, + tSirSmeStartBssRsp * + pSmeStartBssRsp) +{ + enum csr_roamcomplete_result result; + + if (eSIR_SME_SUCCESS == pSmeStartBssRsp->statusCode) { + sme_debug("SmeStartBssReq Successful"); + result = eCsrStartBssSuccess; + } else { + sme_warn("SmeStartBssReq failed with statusCode= 0x%08X", + pSmeStartBssRsp->statusCode); + /* Let csr_roam_complete decide what to do */ + result = eCsrStartBssFailure; + } + csr_roam_complete(pMac, result, pSmeStartBssRsp, + pSmeStartBssRsp->sessionId); +} + +/** + * 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(tpAniSirGlobal 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; + struct csr_roam_session *session; + + sme_debug("DISCONNECT_DONE_IND RC:%d", discon_ind->reason_code); + + if (CSR_IS_SESSION_VALID(mac_ctx, discon_ind->session_id)) { + roam_info.reasonCode = discon_ind->reason_code; + roam_info.statusCode = 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; + + csr_roam_call_callback(mac_ctx, discon_ind->session_id, + &roam_info, 0, eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_DISASSOC_IND); + session = CSR_GET_SESSION(mac_ctx, discon_ind->session_id); + if (session && + !CSR_IS_INFRA_AP(&session->connectedProfile)) + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + discon_ind->session_id); + + } else { + sme_err("Inactive session %d", discon_ind->session_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, discon_ind->session_id); +} + + +/** + * csr_roaming_state_msg_processor() - process roaming messages + * @pMac: mac global context + * @pMsgBuf: message buffer + * + * We need to be careful on whether to cast pMsgBuf (pSmeRsp) to other type of + * strucutres. It depends on how the message is constructed. If the message is + * sent by lim_send_sme_rsp, the pMsgBuf 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(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeRsp *pSmeRsp; + tSmeIbssPeerInd *pIbssPeerInd; + struct csr_roam_info *roam_info; + + pSmeRsp = (tSirSmeRsp *) pMsgBuf; + sme_debug("Message %d[0x%04X] received in substate %s", + pSmeRsp->messageType, pSmeRsp->messageType, + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + + switch (pSmeRsp->messageType) { + + case eWNI_SME_JOIN_RSP: + /* in Roaming state, process the Join response message... */ + if (CSR_IS_ROAM_SUBSTATE_JOIN_REQ(pMac, pSmeRsp->sessionId)) + /* We sent a JOIN_REQ */ + csr_roam_join_rsp_processor(pMac, + (tSirSmeJoinRsp *) pSmeRsp); + break; + case eWNI_SME_REASSOC_RSP: + /* or the Reassociation response message... */ + if (CSR_IS_ROAM_SUBSTATE_REASSOC_REQ(pMac, pSmeRsp->sessionId)) + csr_roam_roaming_state_reassoc_rsp_processor(pMac, + (tpSirSmeJoinRsp) pSmeRsp); + break; + case eWNI_SME_STOP_BSS_RSP: + /* or the Stop Bss response message... */ + csr_roam_roaming_state_stop_bss_rsp_processor(pMac, pSmeRsp); + break; + case eWNI_SME_DISASSOC_RSP: + /* or the Disassociate response message... */ + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, + pSmeRsp->sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "eWNI_SME_DISASSOC_RSP subState = %s", + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + csr_roam_roaming_state_disassoc_rsp_processor(pMac, + (tSirSmeDisassocRsp *) pSmeRsp); + } + break; + case eWNI_SME_DEAUTH_RSP: + /* or the Deauthentication response message... */ + if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId)) { + csr_remove_nonscan_cmd_from_pending_list(pMac, + pSmeRsp->sessionId, + eSmeCommandWmStatusChange); + csr_roam_roaming_state_deauth_rsp_processor(pMac, + (tSirSmeDeauthRsp *) pSmeRsp); + } + break; + case eWNI_SME_START_BSS_RSP: + /* or the Start BSS response message... */ + if (CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(pMac, + pSmeRsp->sessionId)) + csr_roam_roaming_state_start_bss_rsp_processor(pMac, + (tSirSmeStartBssRsp *) pSmeRsp); + break; + /* In case CSR issues STOP_BSS, we need to tell HDD about peer departed + * because PE is removing them + */ + case eWNI_SME_IBSS_PEER_DEPARTED_IND: + pIbssPeerInd = (tSmeIbssPeerInd *) pSmeRsp; + sme_err("Peer departed ntf from LIM in joining state"); + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) { + sme_err("failed to allocate memory for roam_info"); + break; + } + + roam_info->staId = (uint8_t) pIbssPeerInd->staId; + qdf_copy_macaddr(&roam_info->peerMac, &pIbssPeerInd->peer_addr); + csr_roam_call_callback(pMac, pSmeRsp->sessionId, roam_info, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + qdf_mem_free(roam_info); + roam_info = NULL; + break; + case eWNI_SME_GET_RSSI_REQ: + { + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsgBuf; + + if (NULL != pGetRssiReq->rssiCallback) + ((tCsrRssiCallback) pGetRssiReq->rssiCallback) + (pGetRssiReq->lastRSSI, pGetRssiReq->staId, + pGetRssiReq->pDevContext); + else + sme_err("pGetRssiReq->rssiCallback is NULL"); + } + break; + case eWNI_SME_TRIGGER_SAE: + sme_debug("Invoke SAE callback"); + csr_sae_callback(pMac, pSmeRsp); + break; + + case eWNI_SME_SETCONTEXT_RSP: + csr_roam_check_for_link_status_change(pMac, pSmeRsp); + break; + + case eWNI_SME_PURGE_ALL_PDEV_CMDS_REQ: + csr_purge_pdev_all_ser_cmd_list_sync(pMac, pMsgBuf); + break; + + case eWNI_SME_DISCONNECT_DONE_IND: + csr_roam_send_disconnect_done_indication(pMac, pSmeRsp); + break; + case eWNI_SME_UPPER_LAYER_ASSOC_CNF: + csr_roam_joined_state_msg_processor(pMac, 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( + pMac->roam.curSubState[pSmeRsp->sessionId])); + /* If we are connected, check the link status change */ + if (!csr_is_conn_state_disconnected(pMac, pSmeRsp->sessionId)) + csr_roam_check_for_link_status_change(pMac, pSmeRsp); + break; + } +} + +void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeRsp *pSirMsg = (tSirSmeRsp *) pMsgBuf; + + switch (pSirMsg->messageType) { + case eWNI_SME_GET_STATISTICS_RSP: + sme_debug("Stats rsp from PE"); + csr_roam_stats_rsp_processor(pMac, pSirMsg); + break; + case eWNI_SME_UPPER_LAYER_ASSOC_CNF: + { + struct csr_roam_session *pSession; + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; + struct csr_roam_info roamInfo; + struct csr_roam_info *roam_info = NULL; + uint32_t sessionId; + QDF_STATUS status; + + sme_debug("ASSOCIATION confirmation can be given to upper layer "); + qdf_mem_zero(&roamInfo, sizeof(struct csr_roam_info)); + roam_info = &roamInfo; + pUpperLayerAssocCnf = + (tSirSmeAssocIndToUpperLayerCnf *) pMsgBuf; + status = csr_roam_get_session_id_from_bssid(pMac, + (struct qdf_mac_addr *) + pUpperLayerAssocCnf-> + bssId, &sessionId); + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return; + } + /* send the status code as Success */ + roam_info->statusCode = eSIR_SME_SUCCESS; + roam_info->u.pConnectedProfile = + &pSession->connectedProfile; + 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)); + 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(tSirSmeChanInfo)); + 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->rx_mcs_map = pUpperLayerAssocCnf->rx_mcs_map; + roam_info->tx_mcs_map = pUpperLayerAssocCnf->tx_mcs_map; + roam_info->ecsa_capable = pUpperLayerAssocCnf->ecsa_capable; + 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; + + if (CSR_IS_INFRA_AP(roam_info->u.pConnectedProfile)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; + roam_info->fReassocReq = + pUpperLayerAssocCnf->reassocReq; + status = csr_roam_call_callback(pMac, sessionId, + roam_info, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + } + } + break; + default: + csr_roam_check_for_link_status_change(pMac, pSirMsg); + break; + } +} + +QDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrEncryptionType EncryptType, + tSirBssDescription *pBssDescription, + tSirMacAddr *bssId, bool addKey, + bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint16_t keyLength, + uint8_t *pKey, uint8_t paeRole) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tAniEdType edType; + + sme_debug("sessionId: %d EncryptType: %d", sessionId, EncryptType); + + if (eCSR_ENCRYPT_TYPE_UNKNOWN == EncryptType) + EncryptType = eCSR_ENCRYPT_TYPE_NONE; + + edType = csr_translate_encrypt_type_to_ed_type(EncryptType); + + /* + * Allow 0 keys to be set for the non-WPA encrypt types. For WPA encrypt + * types, the num keys must be non-zero or LIM will reject the set + * context (assumes the SET_CONTEXT does not occur until the keys are + * distrubuted). + */ + if (CSR_IS_ENC_TYPE_STATIC(EncryptType) || addKey) { + tCsrRoamSetKey setKey; + + setKey.encType = EncryptType; + setKey.keyDirection = aniKeyDirection; + qdf_mem_copy(&setKey.peerMac, bssId, sizeof(struct + qdf_mac_addr)); + /* 0 for supplicant */ + setKey.paeRole = paeRole; + /* Key index */ + setKey.keyId = keyId; + setKey.keyLength = keyLength; + if (keyLength) + qdf_mem_copy(setKey.Key, pKey, keyLength); + status = csr_roam_issue_set_key_command(pMac, sessionId, + &setKey, 0); + } + return status; +} + +/** + * csr_update_key_cmd() - update key info in set key command + * @mac_ctx: mac global context + * @session: roam session + * @set_key: input set key command + * @set_key_cmd: set key command to update + * @is_key_valid: indicates if key is valid + * + * This function will validate the key length, adjust if too long. It will + * update is_key_valid flag to false if some error has occurred key are local. + * + * Return: status of operation + */ +static QDF_STATUS +csr_update_key_cmd(tpAniSirGlobal mac_ctx, struct csr_roam_session *session, + tCsrRoamSetKey *set_key, struct setkey_cmd *set_key_cmd, + bool *is_key_valid) +{ + switch (set_key->encType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + /* KeyLength maybe 0 for static WEP */ + if (set_key->keyLength) { + if (set_key->keyLength < CSR_WEP40_KEY_LEN) { + sme_warn("Invalid WEP40 keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + + set_key_cmd->keyLength = CSR_WEP40_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_WEP40_KEY_LEN); + } + *is_key_valid = true; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + /* KeyLength maybe 0 for static WEP */ + if (set_key->keyLength) { + if (set_key->keyLength < CSR_WEP104_KEY_LEN) { + sme_warn("Invalid WEP104 keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + + set_key_cmd->keyLength = CSR_WEP104_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_WEP104_KEY_LEN); + } + *is_key_valid = true; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + if (set_key->keyLength < CSR_TKIP_KEY_LEN) { + sme_warn("Invalid TKIP keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_TKIP_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_TKIP_KEY_LEN); + *is_key_valid = true; + break; + case eCSR_ENCRYPT_TYPE_AES: + if (set_key->keyLength < CSR_AES_KEY_LEN) { + sme_warn("Invalid AES/CCMP keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_AES_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_AES_KEY_LEN); + *is_key_valid = true; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP: + if (set_key->keyLength < CSR_AES_GCMP_KEY_LEN) { + sme_warn( + "Invalid AES_GCMP keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_AES_GCMP_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_AES_GCMP_KEY_LEN); + *is_key_valid = true; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + if (set_key->keyLength < CSR_AES_GCMP_256_KEY_LEN) { + sme_warn( + "Invalid AES_GCMP_256 keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_AES_GCMP_256_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_AES_GCMP_256_KEY_LEN); + *is_key_valid = true; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + if (set_key->keyLength < CSR_WAPI_KEY_LEN) { + sme_warn("Invalid WAPI keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_WAPI_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_WAPI_KEY_LEN); + if (session->pCurRoamProfile) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WPI; + } else { + sme_err("pCurRoamProfile is NULL"); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + *is_key_valid = true; + break; +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + case eCSR_ENCRYPT_TYPE_KRK: + /* no need to enqueue KRK key request, since they are local */ + *is_key_valid = false; + if (set_key->keyLength < CSR_KRK_KEY_LEN) { + sme_warn("Invalid KRK keylength [= %d]", + set_key->keyLength); + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(session->eseCckmInfo.krk, set_key->Key, + CSR_KRK_KEY_LEN); + session->eseCckmInfo.reassoc_req_num = 1; + session->eseCckmInfo.krk_plumbed = true; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case eCSR_ENCRYPT_TYPE_BTK: + /* no need to enqueue KRK key request, since they are local */ + *is_key_valid = false; + if (set_key->keyLength < SIR_BTK_KEY_LEN) { + sme_warn("LFR3:Invalid BTK keylength [= %d]", + set_key->keyLength); + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(session->eseCckmInfo.btk, set_key->Key, + SIR_BTK_KEY_LEN); + /* + * KRK and BTK are updated by upper layer back to back. Send + * updated KRK and BTK together to FW here. + */ + csr_roam_offload_scan(mac_ctx, session->sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_PSK_PMK_CHANGED); + break; +#endif +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + /* Check for 11w BIP */ + case eCSR_ENCRYPT_TYPE_AES_CMAC: + if (set_key->keyLength < CSR_AES_KEY_LEN) { + sme_warn("Invalid AES/CCMP keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_AES_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_AES_KEY_LEN); + *is_key_valid = true; + break; + + case eCSR_ENCRYPT_TYPE_AES_GMAC_128: + if (set_key->keyLength < CSR_AES_GMAC_128_KEY_LEN) { + sme_warn("Invalid AES GMAC 128 keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_AES_GMAC_128_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_AES_GMAC_128_KEY_LEN); + *is_key_valid = true; + break; + + case eCSR_ENCRYPT_TYPE_AES_GMAC_256: + if (set_key->keyLength < CSR_AES_GMAC_256_KEY_LEN) { + sme_warn("Invalid AES GMAC 256 keylength [= %d]", + set_key->keyLength); + *is_key_valid = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->keyLength = CSR_AES_GMAC_256_KEY_LEN; + qdf_mem_copy(set_key_cmd->Key, set_key->Key, + CSR_AES_GMAC_256_KEY_LEN); + *is_key_valid = true; + break; + +#endif /* WLAN_FEATURE_11W */ + default: + /* for open security also we want to enqueue command */ + *is_key_valid = true; + return QDF_STATUS_SUCCESS; + } /* end of switch */ + return QDF_STATUS_SUCCESS; +} + + +static QDF_STATUS csr_roam_issue_set_key_command( +tpAniSirGlobal mac_ctx, uint32_t session_id, + tCsrRoamSetKey *set_key, + uint32_t roam_id) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + bool is_key_valid = true; + struct setkey_cmd set_key_cmd; +#if defined(FEATURE_WLAN_ESE) || defined(FEATURE_WLAN_WAPI) + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (NULL == session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "session %d not found", session_id); + return QDF_STATUS_E_FAILURE; + } +#endif /* FEATURE_WLAN_ESE */ + + qdf_mem_zero(&set_key_cmd, sizeof(struct setkey_cmd)); + /* + * following function will validate the key length, Adjust if too long. + * for static WEP the keys are not set thru' SetContextReq + * + * it will update bool is_key_valid, to false if some error has occurred + * key are local. enqueue sme command only if is_key_valid is true + * status is indication of success or failure and will be returned to + * called of current function if command is not enqueued due to key req + * being local + */ + status = csr_update_key_cmd(mac_ctx, session, set_key, + &set_key_cmd, &is_key_valid); + if (is_key_valid) { + set_key_cmd.roamId = roam_id; + set_key_cmd.encType = set_key->encType; + set_key_cmd.keyDirection = set_key->keyDirection; + qdf_copy_macaddr(&set_key_cmd.peermac, + &set_key->peerMac); + /* 0 for supplicant */ + set_key_cmd.paeRole = set_key->paeRole; + set_key_cmd.keyId = set_key->keyId; + qdf_mem_copy(set_key_cmd.keyRsc, set_key->keyRsc, + CSR_MAX_RSC_LEN); + /* + * Always put set key to the head of the Q because it is the + * only thing to get executed in case of WT_KEY state + */ + sme_debug("set key req for session-%d authtype-%d", + session_id, set_key->encType); + status = csr_roam_send_set_key_cmd(mac_ctx, session_id, + &set_key_cmd); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to send message status = %d", status); + } + return status; +} + +QDF_STATUS csr_roam_send_set_key_cmd(tpAniSirGlobal mac_ctx, + uint32_t session_id, + struct setkey_cmd *set_key_cmd) +{ + QDF_STATUS status; + uint8_t num_keys = (set_key_cmd->keyLength) ? 1 : 0; + tAniEdType ed_type = csr_translate_encrypt_type_to_ed_type( + set_key_cmd->encType); + bool unicast = (set_key_cmd->peermac.bytes[0] == 0xFF) ? false : true; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent, + host_event_wlan_security_payload_type); + + if (NULL == session) { + sme_err("session %d not found", session_id); + return QDF_STATUS_E_FAILURE; + } + + if (eSIR_ED_NONE != ed_type) { + qdf_mem_zero(&setKeyEvent, + sizeof(host_event_wlan_security_payload_type)); + if (qdf_is_macaddr_group(&set_key_cmd->peermac)) { + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_BCAST_REQ; + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + set_key_cmd->encType); + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type(session-> + connectedProfile. + EncryptionType); + } else { + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_REQ; + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + set_key_cmd->encType); + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type(session-> + connectedProfile. + mcEncryptionType); + } + qdf_mem_copy(setKeyEvent.bssid, + session->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + if (CSR_IS_ENC_TYPE_STATIC(set_key_cmd->encType)) { + uint32_t defKeyId; + /* It has to be static WEP here */ + if (QDF_IS_STATUS_SUCCESS(wlan_cfg_get_int(mac_ctx, + WNI_CFG_WEP_DEFAULT_KEYID, + &defKeyId))) { + setKeyEvent.keyId = (uint8_t) defKeyId; + } + } else { + setKeyEvent.keyId = set_key_cmd->keyId; + } + setKeyEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type(session-> + connectedProfile. + AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (csr_is_set_key_allowed(mac_ctx, session_id)) { + status = csr_send_mb_set_context_req_msg(mac_ctx, session_id, + set_key_cmd->peermac, + num_keys, ed_type, unicast, + set_key_cmd->keyDirection, + set_key_cmd->keyId, + set_key_cmd->keyLength, + set_key_cmd->Key, + set_key_cmd->paeRole, + set_key_cmd->keyRsc); + } else { + sme_warn(" cannot process not connected"); + /* Set this status so the error handling take + * care of the case. + */ + status = QDF_STATUS_CSR_WRONG_STATE; + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err(" error status %d", status); + csr_roam_call_callback(mac_ctx, session_id, NULL, + set_key_cmd->roamId, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_RESULT_FAILURE); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + if (eSIR_ED_NONE != ed_type) { + if (qdf_is_macaddr_group(&set_key_cmd->peermac)) + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_BCAST_RSP; + else + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_RSP; + setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, + EVENT_WLAN_SECURITY); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + } + return status; +} + +QDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t roamId) +{ + QDF_STATUS status; + + if (!csr_is_set_key_allowed(pMac, sessionId)) { + status = QDF_STATUS_CSR_WRONG_STATE; + } else { + status = csr_roam_issue_set_key_command(pMac, sessionId, + pSetKey, roamId); + } + return status; +} + +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_create_fils_realm_hash: API to create hash using realm + * @fils_con_info: fils connection info obtained from supplicant + * @tmp_hash: pointer to new hash + * + * Return: None + */ +static bool +csr_create_fils_realm_hash(struct cds_fils_connection_info *fils_con_info, + uint8_t *tmp_hash) +{ + uint8_t *hash; + uint8_t *data[1]; + + if (!fils_con_info->realm_len) + return false; + + hash = qdf_mem_malloc(SHA256_DIGEST_SIZE); + if (!hash) { + sme_err("malloc fails in fils realm"); + return false; + } + + data[0] = fils_con_info->realm; + qdf_get_hash(SHA256_CRYPTO_TYPE, 1, data, + &fils_con_info->realm_len, hash); + qdf_trace_hex_dump(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + hash, SHA256_DIGEST_SIZE); + qdf_mem_copy(tmp_hash, hash, 2); + qdf_mem_free(hash); + return true; +} + +/* + * csr_update_fils_scan_filter: update scan filter in case of fils session + * @scan_fltr: pointer to scan filer + * @profile: csr profile pointer + * + * Return: None + */ +static void csr_update_fils_scan_filter(tCsrScanResultFilter *scan_fltr, + struct csr_roam_profile *profile) +{ + if (profile->fils_con_info && + profile->fils_con_info->is_fils_connection) { + uint8_t realm_hash[2]; + + sme_debug("creating realm based on fils info %d", + profile->fils_con_info->is_fils_connection); + scan_fltr->realm_check = csr_create_fils_realm_hash( + profile->fils_con_info, realm_hash); + memcpy(scan_fltr->fils_realm, realm_hash, + sizeof(uint8_t) * 2); + } + +} +#else +static void csr_update_fils_scan_filter(tCsrScanResultFilter *scan_fltr, + struct csr_roam_profile *profile) +{ } +#endif + +/* + * Prepare a filter base on a profile for parsing the scan results. + * Upon successful return, caller MUST call csr_free_scan_filter on + *pScanFilter when it is done with the filter. + */ +QDF_STATUS +csr_roam_prepare_filter_from_profile(tpAniSirGlobal mac_ctx, + struct csr_roam_profile *profile, + tCsrScanResultFilter *scan_fltr) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t size = 0; + uint8_t idx = 0; + tCsrChannelInfo *fltr_ch_info = &scan_fltr->ChannelInfo; + tCsrChannelInfo *profile_ch_info = &profile->ChannelInfo; + struct roam_ext_params *roam_params; + uint8_t i; + + roam_params = &mac_ctx->roam.configParam.roam_params; + + if (profile->BSSIDs.numOfBSSIDs) { + size = sizeof(struct qdf_mac_addr) * profile->BSSIDs. + numOfBSSIDs; + scan_fltr->BSSIDs.bssid = qdf_mem_malloc(size); + if (NULL == scan_fltr->BSSIDs.bssid) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + scan_fltr->BSSIDs.numOfBSSIDs = profile->BSSIDs.numOfBSSIDs; + qdf_mem_copy(scan_fltr->BSSIDs.bssid, + profile->BSSIDs.bssid, size); + } + + if (profile->SSIDs.numOfSSIDs) { + scan_fltr->SSIDs.numOfSSIDs = profile->SSIDs.numOfSSIDs; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("No of Allowed List:%d"), + roam_params->num_ssid_allowed_list); + if (scan_fltr->scan_filter_for_roam + && roam_params->num_ssid_allowed_list) { + scan_fltr->SSIDs.numOfSSIDs = + roam_params->num_ssid_allowed_list; + size = sizeof(tCsrSSIDInfo) * + scan_fltr->SSIDs.numOfSSIDs; + scan_fltr->SSIDs.SSIDList = qdf_mem_malloc(size); + if (NULL == scan_fltr->SSIDs.SSIDList) + status = QDF_STATUS_E_FAILURE; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + for (i = 0; + i < roam_params->num_ssid_allowed_list; + i++) { + qdf_mem_copy((void *) + scan_fltr->SSIDs.SSIDList[i].SSID.ssId, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + scan_fltr->SSIDs.SSIDList[i].SSID.length = + roam_params->ssid_allowed_list[i].length; + scan_fltr->SSIDs.SSIDList[i].handoffPermitted = + 1; + scan_fltr->SSIDs.SSIDList[i].ssidHidden = 0; + } + } else { + size = sizeof(tCsrSSIDInfo) * + profile->SSIDs.numOfSSIDs; + scan_fltr->SSIDs.SSIDList = qdf_mem_malloc(size); + if (NULL == scan_fltr->SSIDs.SSIDList) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + qdf_mem_copy(scan_fltr->SSIDs.SSIDList, + profile->SSIDs.SSIDList, size); + } + } + + if (!profile_ch_info->ChannelList + || (profile_ch_info->ChannelList[0] == 0)) { + fltr_ch_info->numOfChannels = 0; + fltr_ch_info->ChannelList = NULL; + } else if (profile_ch_info->numOfChannels) { + fltr_ch_info->numOfChannels = 0; + fltr_ch_info->ChannelList = + qdf_mem_malloc(sizeof(*(fltr_ch_info->ChannelList)) * + profile_ch_info->numOfChannels); + if (NULL == fltr_ch_info->ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + + for (idx = 0; idx < profile_ch_info->numOfChannels; idx++) { + if (csr_roam_is_channel_valid(mac_ctx, + profile_ch_info->ChannelList[idx])) { + fltr_ch_info-> + ChannelList[fltr_ch_info->numOfChannels] + = profile_ch_info->ChannelList[idx]; + fltr_ch_info->numOfChannels++; + } else { + sme_debug( + "Channel (%d) is invalid", + profile_ch_info->ChannelList[idx]); + } + } + } else { + sme_err("Channel list empty"); + status = QDF_STATUS_E_FAILURE; + goto free_filter; + } + scan_fltr->uapsd_mask = profile->uapsd_mask; + scan_fltr->authType = profile->AuthType; + scan_fltr->EncryptionType = profile->EncryptionType; + scan_fltr->mcEncryptionType = profile->mcEncryptionType; + scan_fltr->BSSType = profile->BSSType; + scan_fltr->phyMode = profile->phyMode; +#ifdef FEATURE_WLAN_WAPI + /* + * check if user asked for WAPI with 11n or auto mode, in that + * case modify the phymode to 11g + */ + if (csr_is_profile_wapi(profile)) { + if (scan_fltr->phyMode & eCSR_DOT11_MODE_11n) + scan_fltr->phyMode &= ~eCSR_DOT11_MODE_11n; + if (scan_fltr->phyMode & eCSR_DOT11_MODE_AUTO) + scan_fltr->phyMode &= ~eCSR_DOT11_MODE_AUTO; + if (!scan_fltr->phyMode) + scan_fltr->phyMode = eCSR_DOT11_MODE_11g; + } +#endif /* FEATURE_WLAN_WAPI */ + /*Save the WPS info */ + scan_fltr->bWPSAssociation = profile->bWPSAssociation; + scan_fltr->bOSENAssociation = profile->bOSENAssociation; + if (profile->countryCode[0]) { + /* + * This causes the matching function to use countryCode as one + * of the criteria. + */ + qdf_mem_copy(scan_fltr->countryCode, profile->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } + if (profile->MDID.mdiePresent) { + scan_fltr->MDID.mdiePresent = 1; + scan_fltr->MDID.mobilityDomain = profile->MDID.mobilityDomain; + } + qdf_mem_copy(scan_fltr->bssid_hint.bytes, + profile->bssid_hint.bytes, QDF_MAC_ADDR_SIZE); + +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + scan_fltr->MFPEnabled = profile->MFPEnabled; + scan_fltr->MFPRequired = profile->MFPRequired; + scan_fltr->MFPCapable = profile->MFPCapable; +#endif + scan_fltr->csrPersona = profile->csrPersona; + csr_update_fils_scan_filter(scan_fltr, profile); + scan_fltr->force_rsne_override = profile->force_rsne_override; + +free_filter: + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_free_scan_filter(mac_ctx, scan_fltr); + + return status; +} + +static +bool csr_roam_issue_wm_status_change(tpAniSirGlobal pMac, 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(pMac); + if (!pCommand) { + sme_err(" fail to get command buffer"); + break; + } + /* Change the substate in case it is waiting for key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandWmStatusChange; + pCommand->sessionId = (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(pMac, pCommand, false))) + fCommandQueued = true; + else + sme_err("fail to send message"); + + /* AP has issued Dissac/Deauth, Set the operating mode + * value to configured value + */ + csr_set_default_dot11_mode(pMac); + } while (0); + return fCommandQueued; +} + +static QDF_STATUS csr_send_snr_request(void *pGetRssiReq) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != + wma_send_snr_request(wma_handle, pGetRssiReq)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to Trigger wma stats request"); + return QDF_STATUS_E_FAILURE; + } + + /* dont send success, otherwise call back + * will released with out values + */ + return QDF_STATUS_E_BUSY; +} + +static void csr_update_rssi(tpAniSirGlobal pMac, void *pMsg) +{ + int8_t rssi = 0; + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsg; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (pGetRssiReq) { + qdf_status = csr_send_snr_request(pGetRssiReq); + + if (NULL != pGetRssiReq->rssiCallback) { + if (qdf_status != QDF_STATUS_E_BUSY) + ((tCsrRssiCallback) (pGetRssiReq->rssiCallback)) + (rssi, pGetRssiReq->staId, + pGetRssiReq->pDevContext); + else + sme_debug("rssi request is posted. waiting for reply"); + } else { + sme_err("GetRssiReq->rssiCallback is NULL"); + return; + } + } else + sme_err("pGetRssiReq is NULL"); + +} + +static void csr_update_snr(tpAniSirGlobal pMac, 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"); +} + +static QDF_STATUS csr_send_reset_ap_caps_changed(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssId) +{ + tpSirResetAPCapsChange pMsg; + uint16_t len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* Create the message and send to lim */ + len = sizeof(tSirResetAPCapsChange); + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg->messageType = eWNI_SME_RESET_AP_CAPS_CHANGED; + pMsg->length = len; + qdf_copy_macaddr(&pMsg->bssId, bssId); + sme_debug( + "CSR reset caps change for Bssid= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pMsg->bssId.bytes)); + status = umac_send_mb_message_to_mac(pMsg); + } else { + sme_err("Memory allocation failed"); + } + return status; +} + +static void +csr_roam_chk_lnk_assoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info *roam_info_ptr = NULL; + tSirSmeAssocInd *pAssocInd; + struct csr_roam_info roam_info; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + sme_debug("Receive WNI_SME_ASSOC_IND from SME"); + pAssocInd = (tSirSmeAssocInd *) msg_ptr; + 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"); + return; + } + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + return; + } + roam_info_ptr = &roam_info; + /* Required for indicating the frames to upper layer */ + roam_info_ptr->assocReqLength = pAssocInd->assocReqLength; + roam_info_ptr->assocReqPtr = pAssocInd->assocReqPtr; + roam_info_ptr->beaconPtr = pAssocInd->beaconPtr; + roam_info_ptr->beaconLength = pAssocInd->beaconLength; + roam_info_ptr->statusCode = eSIR_SME_SUCCESS; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + roam_info_ptr->staId = (uint8_t) pAssocInd->staId; + roam_info_ptr->rsnIELen = (uint8_t) pAssocInd->rsnIE.length; + roam_info_ptr->prsnIE = pAssocInd->rsnIE.rsnIEdata; +#ifdef FEATURE_WLAN_WAPI + roam_info_ptr->wapiIELen = (uint8_t) pAssocInd->wapiIE.length; + roam_info_ptr->pwapiIE = pAssocInd->wapiIE.wapiIEdata; +#endif + roam_info_ptr->addIELen = (uint8_t) pAssocInd->addIE.length; + roam_info_ptr->paddIE = pAssocInd->addIE.addIEdata; + qdf_mem_copy(roam_info_ptr->peerMac.bytes, + pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(roam_info_ptr->bssid.bytes, + pAssocInd->bssId, + sizeof(struct qdf_mac_addr)); + roam_info_ptr->wmmEnabledSta = pAssocInd->wmmEnabledSta; + roam_info_ptr->timingMeasCap = pAssocInd->timingMeasCap; + roam_info_ptr->ecsa_capable = pAssocInd->ecsa_capable; + qdf_mem_copy(&roam_info_ptr->chan_info, + &pAssocInd->chan_info, + sizeof(tSirSmeChanInfo)); + + if (pAssocInd->HTCaps.present) + qdf_mem_copy(&roam_info_ptr->ht_caps, + &pAssocInd->HTCaps, + sizeof(tDot11fIEHTCaps)); + if (pAssocInd->VHTCaps.present) + qdf_mem_copy(&roam_info_ptr->vht_caps, + &pAssocInd->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + roam_info_ptr->capability_info = pAssocInd->capability_info; + roam_info_ptr->he_caps_present = pAssocInd->he_caps_present; + + if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile)) { + if (session->pCurRoamProfile && + CSR_IS_ENC_TYPE_STATIC( + session->pCurRoamProfile->negotiatedUCEncryptionType)) { + /* NO keys... these key parameters don't matter. */ + csr_roam_issue_set_context_req(mac_ctx, sessionId, + session->pCurRoamProfile->negotiatedUCEncryptionType, + session->pConnectBssDesc, + &(roam_info_ptr->peerMac.bytes), + false, true, eSIR_TX_RX, 0, 0, NULL, 0); + roam_info_ptr->fAuthRequired = false; + } else { + roam_info_ptr->fAuthRequired = true; + } + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND); + if (!QDF_IS_STATUS_SUCCESS(status)) + /* Refused due to Mac filtering */ + roam_info_ptr->statusCode = eSIR_SME_ASSOC_REFUSED; + } + + /* Send Association completion message to PE */ + status = csr_send_assoc_cnf_msg(mac_ctx, pAssocInd, status); + /* + * send a message to CSR itself just to avoid the EAPOL frames going + * OTA before association response + */ + if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile) + && (roam_info_ptr->statusCode != eSIR_SME_ASSOC_REFUSED)) { + roam_info_ptr->fReassocReq = pAssocInd->reassocReq; + status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac_ctx, + pAssocInd, status, sessionId); + } +} + +/* + * csr_is_deauth_disassoc_already_active() - Function to check if deauth or + * disassoc is already in progress. + * @mac_ctx: Global MAC context + * @session_id: session id + * @peer_macaddr: Peer MAC address + * + * Return: True if deauth/disassoc indication can be dropped + * else false + */ +static bool csr_is_deauth_disassoc_already_active(tpAniSirGlobal mac_ctx, + uint8_t session_id, + struct qdf_mac_addr peer_macaddr) +{ + bool ret = false; + tSmeCmd *sme_cmd; + + sme_cmd = wlan_serialization_get_active_cmd(mac_ctx->psoc, session_id, + WLAN_SER_CMD_FORCE_DEAUTH_STA); + if (!sme_cmd) { + sme_cmd = wlan_serialization_get_active_cmd(mac_ctx->psoc, + session_id, + WLAN_SER_CMD_FORCE_DISASSOC_STA); + if (!sme_cmd) + return ret; + } + + if ((mac_ctx->roam.curSubState[session_id] == + eCSR_ROAM_SUBSTATE_DEAUTH_REQ || + mac_ctx->roam.curSubState[session_id] == + eCSR_ROAM_SUBSTATE_DISASSOC_REQ) && + !qdf_mem_cmp(peer_macaddr.bytes, sme_cmd->u.roamCmd.peerMac, + QDF_MAC_ADDR_SIZE)) { + sme_debug("Ignore DEAUTH_IND/DIASSOC_IND as Deauth/Disassoc already in progress"); + ret = true; + } + + return ret; +} + +static void +csr_roam_chk_lnk_disassoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tSirSmeDisassocInd *pDisassocInd; + tSmeCmd *cmd; + + cmd = qdf_mem_malloc(sizeof(*cmd)); + if (NULL == cmd) { + sme_err("memory allocation failed for size: %zu", sizeof(*cmd)); + return; + } + + /* + * 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 + */ + pDisassocInd = (tSirSmeDisassocInd *) msg_ptr; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pDisassocInd->bssid, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Session Id not found for BSSID "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pDisassocInd->bssid.bytes)); + qdf_mem_free(cmd); + return; + } + + if (csr_is_deauth_disassoc_already_active(mac_ctx, sessionId, + pDisassocInd->peer_macaddr)) { + qdf_mem_free(cmd); + return; + } + + sme_err("DISASSOCIATION from peer =" MAC_ADDRESS_STR "reason: %d status: %d session: %d", + MAC_ADDR_ARRAY(pDisassocInd->peer_macaddr.bytes), + pDisassocInd->reasonCode, + pDisassocInd->statusCode, sessionId); + /* + * If we are in neighbor preauth done state then on receiving + * disassoc or deauth we dont roam instead we just disassoc + * from current ap and then go to disconnected state + * This happens for ESE and 11r FT connections ONLY. + */ + if (csr_roam_is11r_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session: %d not found", sessionId); + qdf_mem_free(cmd); + return; + } + + /* Update the disconnect stats */ + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.disassoc_by_peer++; + + if (csr_is_conn_state_infra(mac_ctx, sessionId)) + session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_link_down(mac_ctx, sessionId); + csr_roam_issue_wm_status_change(mac_ctx, sessionId, + eCsrDisassociated, msg_ptr); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + /* + * STA/P2P client got disassociated so remove any pending + * deauth commands in sme pending list + */ + cmd->command = eSmeCommandRoam; + cmd->sessionId = (uint8_t) sessionId; + cmd->u.roamCmd.roamReason = eCsrForcedDeauthSta; + qdf_mem_copy(cmd->u.roamCmd.peerMac, + pDisassocInd->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + csr_roam_remove_duplicate_command(mac_ctx, sessionId, cmd, + eCsrForcedDeauthSta); + } + qdf_mem_free(cmd); +} + +static void +csr_roam_chk_lnk_deauth_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tSirSmeDeauthInd *pDeauthInd; + struct csr_roam_info roam_info; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + sme_debug("DEAUTHENTICATION Indication from MAC"); + pDeauthInd = (tpSirSmeDeauthInd) msg_ptr; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pDeauthInd->bssid, + &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + + if (csr_is_deauth_disassoc_already_active(mac_ctx, sessionId, + pDeauthInd->peer_macaddr)) + return; + /* If we are in neighbor preauth done state then on receiving + * disassoc or deauth we dont roam instead we just disassoc + * from current ap and then go to disconnected state + * This happens for ESE and 11r FT connections ONLY. + */ + if (csr_roam_is11r_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + return; + } + + /* Update the disconnect stats */ + switch (pDeauthInd->reasonCode) { + case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON: + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.peer_kickout++; + break; + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON: + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + case eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON: + case eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON: + case eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON: + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.deauth_by_peer++; + break; + case eSIR_BEACON_MISSED: + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.bmiss++; + break; + default: + /* Unknown reason code */ + break; + } + + if (csr_is_conn_state_infra(mac_ctx, sessionId)) + session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_link_down(mac_ctx, sessionId); + csr_roam_issue_wm_status_change(mac_ctx, sessionId, + eCsrDeauthenticated, + msg_ptr); +} + +static void +csr_roam_chk_lnk_swt_ch_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + uint16_t ie_len; + QDF_STATUS status; + tpSirSmeSwitchChannelInd pSwitchChnInd; + struct csr_roam_info roamInfo; + tSirMacDsParamSetIE *ds_params_ie; + tDot11fIEHTInfo *ht_info_ie; + + /* in case of STA, the SWITCH_CHANNEL originates from its AP */ + sme_debug("eWNI_SME_SWITCH_CHL_IND from SME"); + pSwitchChnInd = (tpSirSmeSwitchChannelInd) msg_ptr; + /* Update with the new channel id. The channel id is hidden in the + * statusCode. + */ + 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; + } + session->connectedProfile.operationChannel = + (uint8_t) pSwitchChnInd->newChannelId; + if (session->pConnectBssDesc) { + session->pConnectBssDesc->channelId = + (uint8_t) pSwitchChnInd->newChannelId; + + ie_len = csr_get_ielen_from_bss_description( + session->pConnectBssDesc); + ds_params_ie = (tSirMacDsParamSetIE *)wlan_get_ie_ptr_from_eid( + DOT11F_EID_DSPARAMS, + (uint8_t *)session->pConnectBssDesc->ieFields, + ie_len); + if (ds_params_ie) + ds_params_ie->channelNumber = + (uint8_t)pSwitchChnInd->newChannelId; + + ht_info_ie = (tDot11fIEHTInfo *)wlan_get_ie_ptr_from_eid( + DOT11F_EID_HTINFO, + (uint8_t *)session->pConnectBssDesc->ieFields, + ie_len); + if (ht_info_ie) { + ht_info_ie->primaryChannel = + (uint8_t)pSwitchChnInd->newChannelId; + ht_info_ie->secondaryChannelOffset = + pSwitchChnInd->chan_params.sec_ch_offset; + } + } + + qdf_mem_zero(&roamInfo, sizeof(struct csr_roam_info)); + roamInfo.chan_info.chan_id = pSwitchChnInd->newChannelId; + roamInfo.chan_info.ch_width = pSwitchChnInd->chan_params.ch_width; + roamInfo.chan_info.sec_ch_offset = + pSwitchChnInd->chan_params.sec_ch_offset; + roamInfo.chan_info.band_center_freq1 = + pSwitchChnInd->chan_params.center_freq_seg0; + roamInfo.chan_info.band_center_freq2 = + pSwitchChnInd->chan_params.center_freq_seg1; + + if (CSR_IS_PHY_MODE_11ac(mac_ctx->roam.configParam.phyMode)) + roamInfo.mode = SIR_SME_PHY_MODE_VHT; + else if (CSR_IS_PHY_MODE_11n(mac_ctx->roam.configParam.phyMode)) + roamInfo.mode = SIR_SME_PHY_MODE_HT; + else + roamInfo.mode = SIR_SME_PHY_MODE_LEGACY; + + status = csr_roam_call_callback(mac_ctx, sessionId, &roamInfo, 0, + eCSR_ROAM_STA_CHANNEL_SWITCH, + eCSR_ROAM_RESULT_NONE); +} + +static void +csr_roam_chk_lnk_deauth_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info *roam_info_ptr = NULL; + tSirSmeDeauthRsp *pDeauthRsp = (tSirSmeDeauthRsp *) msg_ptr; + struct csr_roam_info roam_info; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + sme_debug("eWNI_SME_DEAUTH_RSP from SME"); + sessionId = pDeauthRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + qdf_copy_macaddr(&roam_info_ptr->peerMac, + &pDeauthRsp->peer_macaddr); + roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info_ptr->statusCode = pDeauthRsp->statusCode; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } +} + +static void +csr_roam_chk_lnk_disassoc_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info *roam_info_ptr = NULL; + struct csr_roam_info roam_info; + /* + * session id is invalid here so cant use it to access the array + * curSubstate as index + */ + tSirSmeDisassocRsp *pDisassocRsp = (tSirSmeDisassocRsp *) msg_ptr; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + sme_debug("eWNI_SME_DISASSOC_RSP from SME "); + sessionId = pDisassocRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + qdf_copy_macaddr(&roam_info_ptr->peerMac, + &pDisassocRsp->peer_macaddr); + roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info_ptr->statusCode = pDisassocRsp->statusCode; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_mic_fail(tpAniSirGlobal 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; + secEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.EncryptionType); + secEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type( + session->connectedProfile.AuthType); + qdf_mem_copy(secEvent.bssid, session->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_mic_fail_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info *roam_info_ptr = NULL; + struct csr_roam_info roam_info; + tpSirSmeMicFailureInd pMicInd = (tpSirSmeMicFailureInd) msg_ptr; + eCsrRoamResult result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pMicInd->bssId, &sessionId); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + roam_info.u.pMICFailureInfo = &pMicInd->info; + roam_info_ptr = &roam_info; + if (pMicInd->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_ptr, 0, + 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 */ +} + +static void +csr_roam_chk_lnk_pbs_probe_req_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info roam_info; + tpSirSmeProbeReqInd pProbeReqInd = (tpSirSmeProbeReqInd) msg_ptr; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + 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)) { + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + roam_info.u.pWPSPBCProbeReq = &pProbeReqInd->WPSPBCProbeReq; + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, + 0, eCSR_ROAM_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_joined_new_bss(tpAniSirGlobal mac_ctx, + tSirSmeNewBssInfo *pNewBss) +{ + host_log_ibss_pkt_type *pIbssLog; + uint32_t bi; + + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (!pIbssLog) + return; + pIbssLog->eventId = WLAN_IBSS_EVENT_COALESCING; + if (pNewBss) { + qdf_copy_macaddr(&pIbssLog->bssid, &pNewBss->bssId); + if (pNewBss->ssId.length > HOST_LOG_MAX_SSID_SIZE) + pNewBss->ssId.length = HOST_LOG_MAX_SSID_SIZE; + qdf_mem_copy(pIbssLog->ssid, pNewBss->ssId.ssId, + pNewBss->ssId.length); + pIbssLog->operatingChannel = pNewBss->channelNumber; + } + if (QDF_IS_STATUS_SUCCESS(wlan_cfg_get_int(mac_ctx, + WNI_CFG_BEACON_INTERVAL, + &bi))) + /* U8 is not enough for beacon interval */ + pIbssLog->beaconInterval = (uint8_t) bi; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_wm_status_change_ntf(tpAniSirGlobal mac_ctx, + tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info *roam_info_ptr = NULL; + tSirSmeWmStatusChangeNtf *pStatusChangeMsg; + struct csr_roam_info roam_info; + tSirSmeApNewCaps *pApNewCaps; + eCsrRoamResult result = eCSR_ROAM_RESULT_NONE; + tSirMacAddr Broadcastaddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + tSirSmeNewBssInfo *pNewBss; + eRoamCmdStatus roamStatus = eCSR_ROAM_FAILED; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + pStatusChangeMsg = (tSirSmeWmStatusChangeNtf *) msg_ptr; + switch (pStatusChangeMsg->statusChangeCode) { + case eSIR_SME_IBSS_ACTIVE: + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + break; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", + sessionId); + return; + } + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED; + if (session->pConnectBssDesc) { + qdf_mem_copy(&roam_info.bssid, + session->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + roam_info.u.pConnectedProfile = + &session->connectedProfile; + roam_info_ptr = &roam_info; + } else { + sme_err("CSR: connected BSS is empty"); + } + result = eCSR_ROAM_RESULT_IBSS_CONNECT; + roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE; + break; + + case eSIR_SME_IBSS_INACTIVE: + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID != sessionId) { + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + return; + } + session->connectState = + eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + result = eCSR_ROAM_RESULT_IBSS_INACTIVE; + roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE; + } + break; + + case eSIR_SME_JOINED_NEW_BSS: + /* IBSS coalescing. */ + sme_debug("CSR: eSIR_SME_JOINED_NEW_BSS received from PE"); + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + break; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", + sessionId); + return; + } + /* update the connection state information */ + pNewBss = &pStatusChangeMsg->statusChangeInfo.newBssInfo; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_joined_new_bss(mac_ctx, pNewBss); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + csr_roam_update_connected_profile_from_new_bss(mac_ctx, + sessionId, + pNewBss); + + if ((eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType)) { + csr_roam_issue_set_context_req(mac_ctx, + sessionId, + session->connectedProfile.EncryptionType, + session->pConnectBssDesc, + &Broadcastaddr, false, false, + eSIR_TX_RX, 0, 0, NULL, 0); + } + result = eCSR_ROAM_RESULT_IBSS_COALESCED; + roamStatus = eCSR_ROAM_IBSS_IND; + qdf_mem_copy(&roam_info.bssid, &pNewBss->bssId, + sizeof(struct qdf_mac_addr)); + roam_info_ptr = &roam_info; + /* This BSSID is the real BSSID, save it */ + if (session->pConnectBssDesc) + qdf_mem_copy(session->pConnectBssDesc->bssId, + &pNewBss->bssId, sizeof(struct qdf_mac_addr)); + break; + + /* + * detection by LIM that the capabilities of the associated + * AP have changed. + */ + case eSIR_SME_AP_CAPS_CHANGED: + pApNewCaps = &pStatusChangeMsg->statusChangeInfo.apNewCaps; + sme_debug("CSR handling eSIR_SME_AP_CAPS_CHANGED"); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pApNewCaps->bssId, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + if (eCSR_ROAMING_STATE_JOINED == + sme_get_current_roam_state(MAC_HANDLE(mac_ctx), sessionId) + && ((eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC + == mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_NONE == + mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC + == mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC == + mac_ctx->roam.curSubState[sessionId]))) { + sme_warn("Calling csr_roam_disconnect_internal"); + csr_roam_disconnect_internal(mac_ctx, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } else { + sme_warn("Skipping the new scan as CSR is in state: %s and sub-state: %s", + mac_trace_getcsr_roam_state( + mac_ctx->roam.curState[sessionId]), + mac_trace_getcsr_roam_sub_state( + mac_ctx->roam.curSubState[sessionId])); + /* We ignore the caps change event if CSR is not in full + * connected state. Send one event to PE to reset + * limSentCapsChangeNtf Once limSentCapsChangeNtf set + * 0, lim can send sub sequent CAPS change event + * otherwise lim cannot send any CAPS change events to + * SME + */ + csr_send_reset_ap_caps_changed(mac_ctx, + &pApNewCaps->bssId); + } + break; + + default: + roamStatus = eCSR_ROAM_FAILED; + result = eCSR_ROAM_RESULT_NONE; + break; + } /* end switch on statusChangeCode */ + if (eCSR_ROAM_RESULT_NONE != result) { + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + roamStatus, result); + } +} + +static void +csr_roam_chk_lnk_ibss_new_peer_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info *roam_info_ptr = NULL; + tSmeIbssPeerInd *pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr; + struct csr_roam_info roam_info; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_log_ibss_pkt_type *pIbssLog; + + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_JOIN; + qdf_copy_macaddr(&pIbssLog->peer_macaddr, + &pIbssPeerInd->peer_addr); + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + return; + } + /* + * Issue the set Context request to LIM to establish the Unicast STA + * context for the new peer... + */ + if (!session->pConnectBssDesc) { + sme_warn("CSR: connected BSS is empty"); + goto callback_and_free; + } + qdf_copy_macaddr(&roam_info.peerMac, &pIbssPeerInd->peer_addr); + qdf_mem_copy(&roam_info.bssid, session->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + if (pIbssPeerInd->mesgLen > sizeof(tSmeIbssPeerInd)) { + roam_info.pbFrames = qdf_mem_malloc((pIbssPeerInd->mesgLen - + sizeof(tSmeIbssPeerInd))); + if (NULL == roam_info.pbFrames) { + status = QDF_STATUS_E_NOMEM; + } else { + status = QDF_STATUS_SUCCESS; + roam_info.nBeaconLength = pIbssPeerInd->mesgLen - + sizeof(tSmeIbssPeerInd); + qdf_mem_copy(roam_info.pbFrames, + ((uint8_t *) pIbssPeerInd) + + sizeof(tSmeIbssPeerInd), + roam_info.nBeaconLength); + } + roam_info.staId = (uint8_t) pIbssPeerInd->staId; + roam_info.pBssDesc = qdf_mem_malloc( + session->pConnectBssDesc->length); + if (NULL == roam_info.pBssDesc) { + status = QDF_STATUS_E_NOMEM; + if (roam_info.pbFrames) + qdf_mem_free(roam_info.pbFrames); + if (roam_info.pBssDesc) + qdf_mem_free(roam_info.pBssDesc); + } else { + status = QDF_STATUS_SUCCESS; + qdf_mem_copy(roam_info.pBssDesc, + session->pConnectBssDesc, + session->pConnectBssDesc->length); + roam_info_ptr = &roam_info; + } + } else { + roam_info_ptr = &roam_info; + } + if ((eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType)) { + /* NO keys. these key parameters don't matter */ + csr_roam_issue_set_context_req(mac_ctx, sessionId, + session->connectedProfile.EncryptionType, + session->pConnectBssDesc, + &pIbssPeerInd->peer_addr.bytes, + false, true, eSIR_TX_RX, 0, 0, NULL, 0); + } + +callback_and_free: + /* send up the sec type for the new peer */ + if (roam_info_ptr) + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_NEW_PEER); + if (roam_info_ptr) { + if (roam_info.pbFrames) + qdf_mem_free(roam_info.pbFrames); + if (roam_info.pBssDesc) + qdf_mem_free(roam_info.pBssDesc); + } +} + +static void +csr_roam_chk_lnk_ibss_peer_departed_ind(tpAniSirGlobal mac_ctx, + tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + struct csr_roam_info roam_info; + tSmeIbssPeerInd *pIbssPeerInd; + + if (NULL == msg_ptr) { + sme_err("IBSS peer ind. message is NULL"); + return; + } + qdf_mem_zero(&roam_info, sizeof(roam_info)); + pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr; + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID != sessionId) { +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_log_ibss_pkt_type *pIbssLog; + + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_LEAVE; + if (pIbssPeerInd) { + qdf_copy_macaddr(&pIbssLog->peer_macaddr, + &pIbssPeerInd->peer_addr); + } + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + sme_debug("CSR: Peer departed notification from LIM"); + roam_info.staId = (uint8_t) pIbssPeerInd->staId; + qdf_copy_macaddr(&roam_info.peerMac, &pIbssPeerInd->peer_addr); + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_set_ctx_rsp(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, + tSirSmeSetContextRsp *pRsp) +{ + WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent, + host_event_wlan_security_payload_type); + if (eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType) + return; + 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; + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.mcEncryptionType); + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.EncryptionType); + qdf_mem_copy(setKeyEvent.bssid, session->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + setKeyEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type( + session->connectedProfile.AuthType); + if (eSIR_SME_SUCCESS != pRsp->statusCode) + setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_set_ctx_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + struct csr_roam_info *roam_info_ptr = NULL; + struct csr_roam_info roam_info; + eCsrRoamResult result = eCSR_ROAM_RESULT_NONE; + tSirSmeSetContextRsp *pRsp = (tSirSmeSetContextRsp *) msg_ptr; + + + if (!pRsp) { + sme_err("set key response is NULL"); + return; + } + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + sessionId = pRsp->sessionId; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_set_ctx_rsp(mac_ctx, session, pRsp); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (CSR_IS_WAIT_FOR_KEY(mac_ctx, sessionId)) { + csr_roam_stop_wait_for_key_timer(mac_ctx); + /* We are done with authentication, whethere succeed or not */ + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + /* We do it here because this linkup function is not called + * after association when a key needs to be set. + */ + if (csr_is_conn_state_connected_infra(mac_ctx, sessionId)) + csr_roam_link_up(mac_ctx, + session->connectedProfile.bssid); + } + if (eSIR_SME_SUCCESS == pRsp->statusCode) { + 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 (CSR_IS_CHANNEL_24GHZ( + session->connectedProfile.operationChannel) + && (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED) + && session->pCurRoamProfile + && ((QDF_P2P_CLIENT_MODE == + session->pCurRoamProfile->csrPersona) + || (QDF_STA_MODE == + session->pCurRoamProfile->csrPersona))) { + struct sme_obss_ht40_scanind_msg *msg; + + msg = qdf_mem_malloc(sizeof( + struct sme_obss_ht40_scanind_msg)); + if (NULL == msg) { + sme_err("Malloc failed"); + 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, + &session->connectedProfile.bssid); + status = umac_send_mb_message_to_mac(msg); + } + result = eCSR_ROAM_RESULT_AUTHENTICATED; + } else { + result = eCSR_ROAM_RESULT_NONE; + } + roam_info_ptr = &roam_info; + } else { + result = eCSR_ROAM_RESULT_FAILURE; + sme_err( + "CSR: setkey command failed(err=%d) PeerMac " + MAC_ADDRESS_STR, + pRsp->statusCode, + MAC_ADDR_ARRAY(pRsp->peer_macaddr.bytes)); + } + /* keeping roam_id = 0 as nobody is using roam_id for set_key */ + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, + 0, 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 + && session->connectedProfile.isESEAssoc) { + csr_send_ese_adjacent_ap_rep_ind(mac_ctx, session); + session->isPrevApInfoValid = false; + } +#endif + return; +} + + +static void +csr_roam_chk_lnk_max_assoc_exceeded(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + tSmeMaxAssocInd *pSmeMaxAssocInd; + struct csr_roam_info roam_info; + + qdf_mem_zero(&roam_info, sizeof(roam_info)); + pSmeMaxAssocInd = (tSmeMaxAssocInd *) msg_ptr; + sme_debug( + "max assoc have been reached, new peer cannot be accepted"); + sessionId = pSmeMaxAssocInd->sessionId; + roam_info.sessionId = sessionId; + qdf_copy_macaddr(&roam_info.peerMac, &pSmeMaxAssocInd->peer_mac); + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED); +} + +void csr_purge_pdev_all_ser_cmd_list_sync(tpAniSirGlobal mac_ctx, + struct sir_purge_pdev_cmd_req *req) +{ + csr_purge_pdev_all_ser_cmd_list(mac_ctx); + + if (req->purge_complete_cb) + req->purge_complete_cb(mac_ctx->hdd_handle); +} + +void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, + tSirSmeRsp *pSirMsg) +{ + if (NULL == pSirMsg) { + sme_err("pSirMsg is NULL"); + return; + } + switch (pSirMsg->messageType) { + case eWNI_SME_ASSOC_IND: + csr_roam_chk_lnk_assoc_ind(pMac, pSirMsg); + break; + case eWNI_SME_DISASSOC_IND: + csr_roam_chk_lnk_disassoc_ind(pMac, pSirMsg); + break; + case eWNI_SME_DISCONNECT_DONE_IND: + csr_roam_send_disconnect_done_indication(pMac, pSirMsg); + break; + case eWNI_SME_DEAUTH_IND: + csr_roam_chk_lnk_deauth_ind(pMac, pSirMsg); + break; + case eWNI_SME_SWITCH_CHL_IND: + csr_roam_chk_lnk_swt_ch_ind(pMac, pSirMsg); + break; + case eWNI_SME_DEAUTH_RSP: + csr_roam_chk_lnk_deauth_rsp(pMac, pSirMsg); + break; + case eWNI_SME_DISASSOC_RSP: + csr_roam_chk_lnk_disassoc_rsp(pMac, pSirMsg); + break; + case eWNI_SME_MIC_FAILURE_IND: + csr_roam_chk_lnk_mic_fail_ind(pMac, pSirMsg); + break; + case eWNI_SME_WPS_PBC_PROBE_REQ_IND: + csr_roam_chk_lnk_pbs_probe_req_ind(pMac, pSirMsg); + break; + case eWNI_SME_WM_STATUS_CHANGE_NTF: + csr_roam_chk_lnk_wm_status_change_ntf(pMac, pSirMsg); + break; + case eWNI_SME_IBSS_NEW_PEER_IND: + csr_roam_chk_lnk_ibss_new_peer_ind(pMac, pSirMsg); + break; + case eWNI_SME_IBSS_PEER_DEPARTED_IND: + csr_roam_chk_lnk_ibss_peer_departed_ind(pMac, pSirMsg); + break; + case eWNI_SME_SETCONTEXT_RSP: + csr_roam_chk_lnk_set_ctx_rsp(pMac, pSirMsg); + break; + case eWNI_SME_GET_STATISTICS_RSP: + sme_debug("Stats rsp from PE"); + csr_roam_stats_rsp_processor(pMac, 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(pMac, pSirMsg); + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_GET_RSSI_REQ: + sme_debug("GetRssiReq from self"); + csr_update_rssi(pMac, pSirMsg); + break; + case eWNI_SME_GET_SNR_REQ: + sme_debug("GetSnrReq from self"); + csr_update_snr(pMac, pSirMsg); + break; + case eWNI_SME_FT_PRE_AUTH_RSP: + csr_roam_ft_pre_auth_rsp_processor(pMac, + (tpSirFTPreAuthRsp) pSirMsg); + break; + case eWNI_SME_MAX_ASSOC_EXCEEDED: + csr_roam_chk_lnk_max_assoc_exceeded(pMac, pSirMsg); + break; + case eWNI_SME_CANDIDATE_FOUND_IND: + sme_debug("Candidate found indication from PE"); + csr_neighbor_roam_candidate_found_ind_hdlr(pMac, pSirMsg); + break; + case eWNI_SME_HANDOFF_REQ: + sme_debug("Handoff Req from self"); + csr_neighbor_roam_handoff_req_hdlr(pMac, pSirMsg); + break; + case eWNI_SME_PURGE_ALL_PDEV_CMDS_REQ: + csr_purge_pdev_all_ser_cmd_list_sync(pMac, + (struct sir_purge_pdev_cmd_req *)pSirMsg); + break; + default: + break; + } /* end switch on message type */ +} + +void csr_call_roaming_completion_callback(tpAniSirGlobal pMac, + struct csr_roam_session *pSession, + struct csr_roam_info *roam_info, + uint32_t roamId, + eCsrRoamResult roamResult) +{ + if (pSession) { + if (pSession->bRefAssocStartCnt) { + pSession->bRefAssocStartCnt--; + + if (0 != pSession->bRefAssocStartCnt) { + QDF_ASSERT(pSession->bRefAssocStartCnt == 0); + return; + } + /* Need to call association_completion because there + * is an assoc_start pending. + */ + csr_roam_call_callback(pMac, pSession->sessionId, NULL, + roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_FAILURE); + } + csr_roam_call_callback(pMac, pSession->sessionId, roam_info, + roamId, eCSR_ROAM_ROAMING_COMPLETION, + roamResult); + } else + sme_err("pSession is NULL"); +} + +/* return a bool to indicate whether roaming completed or continue. */ +bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + bool fForce, eCsrRoamResult roamResult) +{ + bool fCompleted = true; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found ", sessionId); + return false; + } + /* Check whether time is up */ + if (pSession->fCancelRoaming || fForce || + eCsrReassocRoaming == pSession->roamingReason || + eCsrDynamicRoaming == pSession->roamingReason) { + sme_debug("indicates roaming completion"); + if (pSession->fCancelRoaming + && CSR_IS_LOSTLINK_ROAMING(pSession->roamingReason)) { + /* roaming is cancelled, tell HDD to indicate disconnect + * Because LIM overload deauth_ind for both deauth frame + * and missed beacon we need to use this logic to + * detinguish it. For missed beacon, LIM set reason to + * be eSIR_BEACON_MISSED + */ + if (eSIR_BEACON_MISSED == pSession->roamingStatusCode) { + roamResult = eCSR_ROAM_RESULT_LOSTLINK; + } else if (eCsrLostlinkRoamingDisassoc == + pSession->roamingReason) { + roamResult = eCSR_ROAM_RESULT_DISASSOC_IND; + } else if (eCsrLostlinkRoamingDeauth == + pSession->roamingReason) { + roamResult = eCSR_ROAM_RESULT_DEAUTH_IND; + } else { + roamResult = eCSR_ROAM_RESULT_LOSTLINK; + } + } + csr_call_roaming_completion_callback(pMac, pSession, NULL, 0, + roamResult); + pSession->roamingReason = eCsrNotRoaming; + } else { + pSession->roamResult = roamResult; + if (!QDF_IS_STATUS_SUCCESS(csr_roam_start_roaming_timer(pMac, + sessionId, QDF_MC_TIMER_TO_SEC_UNIT))) { + csr_call_roaming_completion_callback(pMac, pSession, + NULL, 0, roamResult); + pSession->roamingReason = eCsrNotRoaming; + } else { + fCompleted = false; + } + } + return fCompleted; +} + +void csr_roam_cancel_roaming(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session: %d not found", sessionId); + return; + } + + if (CSR_IS_ROAMING(pSession)) { + sme_debug("Cancel roaming"); + pSession->fCancelRoaming = true; + if (CSR_IS_ROAM_JOINING(pMac, sessionId) + && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) { + /* No need to do anything in here because the handler + * takes care of it + */ + } else { + eCsrRoamResult roamResult = + CSR_IS_LOSTLINK_ROAMING(pSession-> + roamingReason) ? + eCSR_ROAM_RESULT_LOSTLINK : + eCSR_ROAM_RESULT_NONE; + /* Roaming is stopped after here */ + csr_roam_complete_roaming(pMac, sessionId, true, + roamResult); + /* Since CSR may be in lostlink roaming situation, + * abort all roaming related activities + */ + csr_scan_abort_mac_scan(pMac, sessionId, INVAL_SCAN_ID); + csr_roam_stop_roaming_timer(pMac, sessionId); + } + } +} + +void csr_roam_roaming_timer_handler(void *pv) +{ + tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv; + tpAniSirGlobal pMac = pInfo->pMac; + uint32_t sessionId = pInfo->sessionId; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err(" session %d not found ", sessionId); + return; + } + + if (false == pSession->fCancelRoaming) { + csr_call_roaming_completion_callback(pMac, pSession, + NULL, 0, + pSession->roamResult); + pSession->roamingReason = eCsrNotRoaming; + } +} + +/** + * csr_roam_roaming_offload_timeout_handler() - Handler for roaming failure + * @timer_data: Carries the mac_ctx and session info + * + * This function would be invoked when the roaming_offload_timer expires. + * The timer is waiting in anticipation of a related roaming event from + * the firmware after receiving the ROAM_START event. + * + * Return: None + */ +void csr_roam_roaming_offload_timeout_handler(void *timer_data) +{ + tCsrTimerInfo *timer_info = (tCsrTimerInfo *) timer_data; + + if (timer_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR3:roaming offload timer expired, session: %d", + timer_info->sessionId); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Invalid Session"); + return; + } + csr_roam_disconnect(timer_info->pMac, timer_info->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); +} + +QDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t interval) +{ + QDF_STATUS status; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("csrScanStartRoamingTimer"); + pSession->roamingTimerInfo.sessionId = (uint8_t) sessionId; + status = qdf_mc_timer_start(&pSession->hTimerRoaming, + interval / QDF_MC_TIMER_TO_MS_UNIT); + + return status; +} + +QDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + return qdf_mc_timer_stop + (&pMac->roam.roamSession[sessionId].hTimerRoaming); +} + +void csr_roam_wait_for_key_time_out_handler(void *pv) +{ + tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv; + tpAniSirGlobal pMac = pInfo->pMac; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, + pInfo->sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (pSession == NULL) { + sme_err("session not found"); + return; + } + + sme_debug("WaitForKey timer expired in state: %s sub-state: %s", + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo[pInfo->sessionId]. + neighborRoamState), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[pInfo->sessionId])); + spin_lock(&pMac->roam.roam_state_lock); + if (CSR_IS_WAIT_FOR_KEY(pMac, pInfo->sessionId)) { + /* Change the substate so command queue is unblocked. */ + if (CSR_ROAM_SESSION_MAX > pInfo->sessionId) + pMac->roam.curSubState[pInfo->sessionId] = + eCSR_ROAM_SUBSTATE_NONE; + spin_unlock(&pMac->roam.roam_state_lock); + + if (csr_neighbor_roam_is_handoff_in_progress(pMac, + pInfo->sessionId)) { + /* + * Enable heartbeat timer when hand-off is in progress + * and Key Wait timer expired. + */ + sme_debug("Enabling HB timer after WaitKey expiry nHBCount: %d)", + pMac->roam.configParam.HeartbeatThresh24); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + } + sme_debug("SME pre-auth state timeout"); + + if (csr_is_conn_state_connected_infra(pMac, pInfo->sessionId)) { + csr_roam_link_up(pMac, + pSession->connectedProfile.bssid); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_disconnect(pMac, pInfo->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + sme_release_global_lock(&pMac->sme); + } + } else { + sme_err("session not found"); + } + } else { + spin_unlock(&pMac->roam.roam_state_lock); + } + +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * csr_roam_roaming_offload_timer_action() - API to start/stop the timer + * @mac_ctx: MAC Context + * @interval: Value to be set for the timer + * @session_id: Session on which the timer should be operated + * @action: Start/Stop action for the timer + * + * API to start/stop the roaming offload timer + * + * Return: None + */ +void csr_roam_roaming_offload_timer_action( + tpAniSirGlobal mac_ctx, uint32_t interval, uint8_t session_id, + uint8_t action) +{ + struct csr_roam_session *csr_session = CSR_GET_SESSION(mac_ctx, + session_id); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("LFR3: timer action %d, session %d, intvl %d"), + action, session_id, interval); + if (mac_ctx) { + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + ("LFR3: Invalid MAC Context")); + return; + } + if (!csr_session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + ("LFR3: session %d not found"), session_id); + return; + } + csr_session->roamingTimerInfo.sessionId = (uint8_t) session_id; + if (action == ROAMING_OFFLOAD_TIMER_START) + qdf_mc_timer_start(&csr_session->roaming_offload_timer, + interval / QDF_MC_TIMER_TO_MS_UNIT); + if (action == ROAMING_OFFLOAD_TIMER_STOP) + qdf_mc_timer_stop(&csr_session->roaming_offload_timer); + +} +#endif + +static QDF_STATUS csr_roam_start_wait_for_key_timer( + tpAniSirGlobal pMac, uint32_t interval) +{ + QDF_STATUS status; +#ifdef WLAN_DEBUG + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo. + sessionId]; +#endif + if (csr_neighbor_roam_is_handoff_in_progress(pMac, + pMac->roam.WaitForKeyTimerInfo. + sessionId)) { + /* Disable heartbeat timer when hand-off is in progress */ + sme_debug("disabling HB timer in state: %s sub-state: %s", + mac_trace_get_neighbour_roam_state( + pNeighborRoamInfo->neighborRoamState), + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pMac->roam. + WaitForKeyTimerInfo.sessionId])); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, 0); + } + sme_debug("csrScanStartWaitForKeyTimer"); + status = qdf_mc_timer_start(&pMac->roam.hTimerWaitForKey, + interval / QDF_MC_TIMER_TO_MS_UNIT); + + return status; +} + +QDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac) +{ +#ifdef WLAN_DEBUG + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo. + sessionId]; +#endif + + sme_debug("WaitForKey timer stopped in state: %s sub-state: %s", + mac_trace_get_neighbour_roam_state(pNeighborRoamInfo-> + neighborRoamState), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[pMac->roam. + WaitForKeyTimerInfo. + sessionId])); + if (csr_neighbor_roam_is_handoff_in_progress(pMac, + pMac->roam.WaitForKeyTimerInfo. + sessionId)) { + /* + * Enable heartbeat timer when hand-off is in progress + * and Key Wait timer got stopped for some reason + */ + sme_debug("Enabling HB timer after WaitKey stop nHBCount: %d", + pMac->roam.configParam.HeartbeatThresh24); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + } + return qdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey); +} + +void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_info *roam_info, tSmeCmd *pCommand, + eCsrRoamResult roamResult, bool fSuccess) +{ + eRoamCmdStatus roamStatus = csr_get_roam_complete_status(pMac, + sessionId); + uint32_t roamId = 0; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session: %d not found ", sessionId); + return; + } + + if (pCommand) { + roamId = pCommand->u.roamCmd.roamId; + if (sessionId != pCommand->sessionId) { + QDF_ASSERT(sessionId == pCommand->sessionId); + return; + } + } + if (eCSR_ROAM_ROAMING_COMPLETION == roamStatus) + /* if success, force roaming completion */ + csr_roam_complete_roaming(pMac, sessionId, fSuccess, + roamResult); + else { + if (pSession->bRefAssocStartCnt != 0) { + QDF_ASSERT(pSession->bRefAssocStartCnt == 0); + return; + } + sme_debug("indicates association completion roamResult: %d", + roamResult); + csr_roam_call_callback(pMac, sessionId, roam_info, roamId, + roamStatus, roamResult); + } +} + +static +QDF_STATUS csr_roam_lost_link(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t type, tSirSmeRsp *pSirMsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeDeauthInd *pDeauthIndMsg = NULL; + tSirSmeDisassocInd *pDisassocIndMsg = NULL; + eCsrRoamResult result = eCSR_ROAM_RESULT_LOSTLINK; + struct csr_roam_info roamInfo; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session: %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&roamInfo, sizeof(struct csr_roam_info)); + if (eWNI_SME_DISASSOC_IND == type) { + result = eCSR_ROAM_RESULT_DISASSOC_IND; + pDisassocIndMsg = (tSirSmeDisassocInd *) pSirMsg; + pSession->roamingStatusCode = pDisassocIndMsg->statusCode; + pSession->joinFailStatusCode.reasonCode = + pDisassocIndMsg->reasonCode; + + qdf_copy_macaddr(&roamInfo.peerMac, + &pDisassocIndMsg->peer_macaddr); + } else if (eWNI_SME_DEAUTH_IND == type) { + result = eCSR_ROAM_RESULT_DEAUTH_IND; + pDeauthIndMsg = (tSirSmeDeauthInd *) pSirMsg; + pSession->roamingStatusCode = pDeauthIndMsg->statusCode; + pSession->joinFailStatusCode.reasonCode = + pDeauthIndMsg->reasonCode; + + qdf_copy_macaddr(&roamInfo.peerMac, + &pDeauthIndMsg->peer_macaddr); + + } else { + sme_warn("gets an unknown type (%d)", type); + result = eCSR_ROAM_RESULT_NONE; + pSession->joinFailStatusCode.reasonCode = 1; + } + + if (type == eWNI_SME_DISASSOC_IND || type == eWNI_SME_DEAUTH_IND) { + struct sir_peer_info_req req; + + req.sessionid = sessionId; + req.peer_macaddr = roamInfo.peerMac; + sme_get_peer_stats(pMac, req); + } + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_LOSTLINK_DETECTED, result); + + if (eWNI_SME_DISASSOC_IND == type) + status = csr_send_mb_disassoc_cnf_msg(pMac, pDisassocIndMsg); + else if (eWNI_SME_DEAUTH_IND == type) + status = csr_send_mb_deauth_cnf_msg(pMac, pDeauthIndMsg); + + /* prepare to tell HDD to disconnect */ + qdf_mem_zero(&roamInfo, sizeof(struct csr_roam_info)); + roamInfo.statusCode = (tSirResultCodes) pSession->roamingStatusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + if (eWNI_SME_DISASSOC_IND == type) { + /* staMacAddr */ + qdf_copy_macaddr(&roamInfo.peerMac, + &pDisassocIndMsg->peer_macaddr); + roamInfo.staId = (uint8_t) pDisassocIndMsg->staId; + roamInfo.reasonCode = pDisassocIndMsg->reasonCode; + } else if (eWNI_SME_DEAUTH_IND == type) { + /* staMacAddr */ + qdf_copy_macaddr(&roamInfo.peerMac, + &pDeauthIndMsg->peer_macaddr); + roamInfo.staId = (uint8_t) pDeauthIndMsg->staId; + roamInfo.reasonCode = pDeauthIndMsg->reasonCode; + roamInfo.rxRssi = pDeauthIndMsg->rssi; + } + sme_debug("roamInfo.staId: %d", roamInfo.staId); +/* Dont initiate internal driver based roaming after disconnection*/ + return status; +} + + +void csr_roam_wm_status_change_complete(tpAniSirGlobal pMac, + uint8_t session_id) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + + pEntry = csr_nonscan_active_ll_peek_head(pMac, 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(pMac, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command(pMac, pCommand); + } else { + sme_err( + " ******csr_roam_wm_status_change_complete fail to release command"); + } + + } else { + sme_warn( +"CSR: WmStatusChange Completion called but LOST LINK command is not ACTIVE ..."); + } + } else { + sme_warn( + "CSR: WmStatusChange Completion called but NO commands are ACTIVE ..."); + } +} + +void csr_roam_process_wm_status_change_command( + tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirSmeRsp *pSirSmeMsg; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, + pCommand->sessionId); + + if (!pSession) { + sme_err("session %d not found", pCommand->sessionId); + goto end; + } + sme_debug("session:%d, CmdType : %d", + pCommand->sessionId, pCommand->u.wmStatusChangeCmd.Type); + + switch (pCommand->u.wmStatusChangeCmd.Type) { + case eCsrDisassociated: + pSirSmeMsg = + (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg; + status = + csr_roam_lost_link(pMac, pCommand->sessionId, + eWNI_SME_DISASSOC_IND, pSirSmeMsg); + break; + case eCsrDeauthenticated: + pSirSmeMsg = + (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg; + status = + csr_roam_lost_link(pMac, pCommand->sessionId, + eWNI_SME_DEAUTH_IND, pSirSmeMsg); + break; + default: + sme_warn("gets an unknown command %d", + pCommand->u.wmStatusChangeCmd.Type); + break; + } + +end: + if (status != QDF_STATUS_SUCCESS) { + /* + * 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(pMac, pCommand->sessionId); + } +} + +QDF_STATUS csr_process_del_sta_session_command(tpAniSirGlobal mac_ctx, + tSmeCmd *sme_command) +{ + struct del_sta_self_params *del_sta_self_req; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + del_sta_self_req = qdf_mem_malloc(sizeof(struct del_sta_self_params)); + if (NULL == del_sta_self_req) { + sme_err(" mem alloc failed for tDelStaSelfParams"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(del_sta_self_req->self_mac_addr, + sme_command->u.delStaSessionCmd.selfMacAddr, + sizeof(tSirMacAddr)); + + del_sta_self_req->session_id = sme_command->sessionId; + del_sta_self_req->sme_callback = + sme_command->u.delStaSessionCmd.session_close_cb; + del_sta_self_req->sme_ctx = sme_command->u.delStaSessionCmd.context; + msg.type = WMA_DEL_STA_SELF_REQ; + msg.reserved = 0; + msg.bodyptr = del_sta_self_req; + msg.bodyval = 0; + + sme_debug("sending WMA_DEL_STA_SELF_REQ"); + status = wma_post_ctrl_msg(mac_ctx, &msg); + if (status != QDF_STATUS_SUCCESS) { + sme_err("wma_post_ctrl_msg failed"); + qdf_mem_free(del_sta_self_req); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * csr_compute_mode_and_band() - computes dot11mode + * @pMac: mac global context + * @dot11_mode: out param, do11 mode calculated + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. + * + * Return: void + */ +static void +csr_compute_mode_and_band(tpAniSirGlobal mac_ctx, + enum csr_cfgdot11mode *dot11_mode, + enum band_info *band, + uint8_t opr_ch) +{ + bool vht_24_ghz = mac_ctx->roam.configParam.enableVhtFor24GHz; + + switch (mac_ctx->roam.configParam.uCfgDot11Mode) { + case eCSR_CFG_DOT11_MODE_11A: + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = BAND_5G; + break; + case eCSR_CFG_DOT11_MODE_11B: + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = BAND_2G; + break; + case eCSR_CFG_DOT11_MODE_11G: + *dot11_mode = eCSR_CFG_DOT11_MODE_11G; + *band = BAND_2G; + break; + case eCSR_CFG_DOT11_MODE_11N: + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + *band = CSR_GET_BAND(opr_ch); + 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(opr_ch) && !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 = CSR_GET_BAND(opr_ch); + 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(opr_ch) && !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 = CSR_GET_BAND(opr_ch); + 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(opr_ch) && !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 = CSR_GET_BAND(opr_ch); + break; + case eCSR_CFG_DOT11_MODE_AUTO: + 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(opr_ch) + && !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 = CSR_GET_BAND(opr_ch); + 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) { + *band = mac_ctx->roam.configParam.eBand; + if (BAND_2G == *band) { + /* + * See reason in else if ( WLAN_REG_IS_24GHZ_CH + * (opr_ch) ) to pick 11B + */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } else { + /* prefer 5GHz */ + *band = BAND_5G; + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + } else if (WLAN_REG_IS_24GHZ_CH(opr_ch)) { + /* + * WiFi tests require IBSS networks to start in 11b mode + * without any change to the default parameter settings + * on the adapter. We use ACU to start an IBSS through + * creation of a startIBSS profile. This startIBSS + * profile has Auto MACProtocol and the adapter property + * setting for dot11Mode is also AUTO. So in this case, + * let's start the IBSS network in 11b mode instead of + * 11g mode. So this is for Auto=profile->MacProtocol && + * Auto=Global. dot11Mode && profile->channel is < 14, + * then start the IBSS in b mode. + * + * Note: we used to have this start as an 11g IBSS for + * best performance. now to specify that the user will + * have to set the do11Mode in the property page to 11g + * to force it. + */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = BAND_2G; + } else { + /* else, it's a 5.0GHz channel. Set mode to 11a. */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = BAND_5G; + } + break; + } /* switch */ +} + +/** + * csr_roam_get_phy_mode_band_for_bss() - This function returns band and mode + * information. + * @mac_ctx: mac global context + * @profile: bss profile + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * 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 + */ +static enum csr_cfgdot11mode +csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal mac_ctx, + struct csr_roam_profile *profile, + uint8_t opr_chn, + enum band_info *p_band) +{ + enum band_info band; +enum csr_cfgdot11mode curr_mode = mac_ctx->roam.configParam.uCfgDot11Mode; + enum csr_cfgdot11mode cfg_dot11_mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(profile, + (eCsrPhyMode) profile->phyMode, + mac_ctx->roam.configParam.ProprietaryRatesEnabled); + + /* + * If the global setting for dot11Mode is set to auto/abg, we overwrite + * the setting in the profile. + */ + if ((!CSR_IS_INFRA_AP(profile) + && ((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_chn); + } /* if( eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode ) */ + else { + /* dot11 mode is set, lets pick the band */ + if (eCSR_OPERATING_CHANNEL_AUTO == opr_chn) { + /* channel is Auto also. */ + band = mac_ctx->roam.configParam.eBand; + if (BAND_ALL == band) { + /* prefer 5GHz */ + band = BAND_5G; + } + } else{ + band = CSR_GET_BAND(opr_chn); + } + } + if (p_band) + *p_band = band; + + if (opr_chn == 14) { + sme_err("Switching to Dot11B mode"); + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } + + if (IS_24G_CH(opr_chn) && + (false == mac_ctx->roam.configParam.enableVhtFor24GHz) && + (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 + */ + if ((!CSR_IS_11n_ALLOWED(profile->EncryptionType.encryptionType[0]) + || ((profile->privacy == 1) + && (profile->EncryptionType.encryptionType[0] == + eCSR_ENCRYPT_TYPE_NONE))) + && ((eCSR_CFG_DOT11_MODE_11N == cfg_dot11_mode) || + (eCSR_CFG_DOT11_MODE_11AC == cfg_dot11_mode) || + (eCSR_CFG_DOT11_MODE_11AX == cfg_dot11_mode))) { + /* We cannot do 11n here */ + if (WLAN_REG_IS_24GHZ_CH(opr_chn)) + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11G; + else + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + sme_debug("dot11mode: %d", cfg_dot11_mode); + return cfg_dot11_mode; +} + +QDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, + uint32_t sessionId, enum csr_roam_substate NewSubstate) +{ + QDF_STATUS status; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + { + host_log_ibss_pkt_type *pIbssLog; + + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_REQ; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + /* Set the roaming substate to 'stop Bss request'... */ + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + /* attempt to stop the Bss (reason code is ignored...) */ + status = csr_send_mb_stop_bss_req_msg(pMac, sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_warn( + "csr_send_mb_stop_bss_req_msg failed with status %d", + status); + } + return status; +} + +/* pNumChan is a caller allocated space with the sizeof pChannels */ +QDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels, + uint32_t *pNumChan) +{ + uint8_t num_chan_temp = 0; + int i; + + if (!QDF_IS_STATUS_SUCCESS(wlan_cfg_get_str(pMac, + WNI_CFG_VALID_CHANNEL_LIST, + (uint8_t *) pChannels, pNumChan))) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < *pNumChan; i++) { + if (!wlan_reg_is_dsrc_chan(pMac->pdev, pChannels[i])) { + pChannels[num_chan_temp] = pChannels[i]; + num_chan_temp++; + } + } + + *pNumChan = num_chan_temp; + return QDF_STATUS_SUCCESS; +} + +int8_t csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel) +{ + uint32_t cfgLength = 0; + uint16_t cfgId = 0; + int8_t maxTxPwr = 0; + uint8_t *pCountryInfo = NULL; + QDF_STATUS status; + uint8_t count = 0; + uint8_t firstChannel; + uint8_t maxChannels; + + if (WLAN_REG_IS_5GHZ_CH(channel)) { + cfgId = WNI_CFG_MAX_TX_POWER_5; + cfgLength = WNI_CFG_MAX_TX_POWER_5_LEN; + } else if (WLAN_REG_IS_24GHZ_CH(channel)) { + cfgId = WNI_CFG_MAX_TX_POWER_2_4; + cfgLength = WNI_CFG_MAX_TX_POWER_2_4_LEN; + } else + return maxTxPwr; + + pCountryInfo = qdf_mem_malloc(cfgLength); + if (NULL == pCountryInfo) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to allocate memory, status = %d", + __func__, status); + goto error; + } + if (wlan_cfg_get_str(pMac, cfgId, (uint8_t *)pCountryInfo, + &cfgLength) != QDF_STATUS_SUCCESS) { + goto error; + } + /* Identify the channel and maxtxpower */ + while (count <= (cfgLength - (sizeof(tSirMacChanInfo)))) { + firstChannel = pCountryInfo[count++]; + maxChannels = pCountryInfo[count++]; + maxTxPwr = pCountryInfo[count++]; + + if ((channel >= firstChannel) && + (channel < (firstChannel + maxChannels))) { + break; + } + } + +error: + if (NULL != pCountryInfo) + qdf_mem_free(pCountryInfo); + + return maxTxPwr; +} + +bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel) +{ + bool fValid = false; + uint32_t idxValidChannels; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (QDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels(pMac, + pMac->roam.validChannelList, &len))) { + for (idxValidChannels = 0; (idxValidChannels < len); + idxValidChannels++) { + if (channel == + pMac->roam.validChannelList[idxValidChannels]) { + fValid = true; + break; + } + } + } + pMac->roam.numValidChannels = len; + return fValid; +} + +/* This function check and validate whether the NIC can do CB (40MHz) */ +static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac, + uint8_t chan, + tDot11fBeaconIEs *pIes) +{ + ePhyChanBondState eRet = PHY_SINGLE_CHANNEL_CENTERED; + uint8_t sec_ch = 0; + uint32_t ChannelBondingMode; + struct ch_params ch_params = {0}; + + if (WLAN_REG_IS_24GHZ_CH(chan)) { + ChannelBondingMode = + pMac->roam.configParam.channelBondingMode24GHz; + } else { + ChannelBondingMode = + pMac->roam.configParam.channelBondingMode5GHz; + } + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == ChannelBondingMode) + return PHY_SINGLE_CHANNEL_CENTERED; + + /* Figure what the other side's CB mode */ + if (!(pIes->HTCaps.present && (eHT_CHANNEL_WIDTH_40MHZ == + pIes->HTCaps.supportedChannelWidthSet))) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + + /* In Case WPA2 and TKIP is the only one cipher suite in Pairwise */ + if ((pIes->RSN.present && (pIes->RSN.pwise_cipher_suite_count == 1) && + !memcmp(&(pIes->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. + */ + || (!pIes->RSN.present && (pIes->WPA.present && + (pIes->WPA.unicast_cipher_count == 1) && + !memcmp(&(pIes->WPA.unicast_ciphers[0][0]), + "\x00\x50\xf2\x02", 4)))) { + sme_debug("No channel bonding in TKIP mode"); + return PHY_SINGLE_CHANNEL_CENTERED; + } + + if (!pIes->HTInfo.present) + return PHY_SINGLE_CHANNEL_CENTERED; + + /* + * This is called during INFRA STA/CLIENT and should use the merged + * value of supported channel width and recommended tx width as per + * standard + */ + sme_debug("chan %d scws %u rtws %u sco %u", chan, + pIes->HTCaps.supportedChannelWidthSet, + pIes->HTInfo.recommendedTxWidthSet, + pIes->HTInfo.secondaryChannelOffset); + + if (pIes->HTInfo.recommendedTxWidthSet == eHT_CHANNEL_WIDTH_40MHZ) + eRet = (ePhyChanBondState)pIes->HTInfo.secondaryChannelOffset; + else + eRet = PHY_SINGLE_CHANNEL_CENTERED; + + switch (eRet) { + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + sec_ch = chan + CSR_SEC_CHANNEL_OFFSET; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + sec_ch = chan - CSR_SEC_CHANNEL_OFFSET; + break; + default: + break; + } + + if (eRet != PHY_SINGLE_CHANNEL_CENTERED) { + ch_params.ch_width = CH_WIDTH_40MHZ; + wlan_reg_set_channel_params(pMac->pdev, chan, + sec_ch, &ch_params); + if (ch_params.ch_width == CH_WIDTH_20MHZ || + ch_params.sec_ch_offset != eRet) { + sme_err("chan %d :: Supported HT BW %d and cbmode %d, APs HT BW %d and cbmode %d, so switch to 20Mhz", + chan, ch_params.ch_width, + ch_params.sec_ch_offset, + pIes->HTInfo.recommendedTxWidthSet, eRet); + eRet = PHY_SINGLE_CHANNEL_CENTERED; + } + } + + return eRet; +} + +static bool csr_is_encryption_in_list(tpAniSirGlobal pMac, + tCsrEncryptionList *pCipherList, + eCsrEncryptionType encryptionType) +{ + bool fFound = false; + uint32_t idx; + + for (idx = 0; idx < pCipherList->numEntries; idx++) { + if (pCipherList->encryptionType[idx] == encryptionType) { + fFound = true; + break; + } + } + return fFound; +} + +static bool csr_is_auth_in_list(tpAniSirGlobal pMac, tCsrAuthList *pAuthList, + eCsrAuthType authType) +{ + bool fFound = false; + uint32_t idx; + + for (idx = 0; idx < pAuthList->numEntries; idx++) { + if (pAuthList->authType[idx] == authType) { + fFound = true; + break; + } + } + return fFound; +} + +bool csr_is_same_profile(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pProfile1, + struct csr_roam_profile *pProfile2) +{ + uint32_t i; + bool fCheck = false; + tCsrScanResultFilter *pScanFilter = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!(pProfile1 && pProfile2)) + return fCheck; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return fCheck; + + status = csr_roam_prepare_filter_from_profile(pMac, pProfile2, + pScanFilter); + if (!(QDF_IS_STATUS_SUCCESS(status))) + goto free_scan_filter; + + for (i = 0; i < pScanFilter->SSIDs.numOfSSIDs; i++) { + fCheck = csr_is_ssid_match(pMac, + pScanFilter->SSIDs.SSIDList[i].SSID.ssId, + pScanFilter->SSIDs.SSIDList[i].SSID.length, + pProfile1->SSID.ssId, + pProfile1->SSID.length, + false); + if (fCheck) + break; + } + if (!fCheck) + goto free_scan_filter; + + if (!csr_is_auth_in_list(pMac, &pProfile2->AuthType, + pProfile1->AuthType) + || (pProfile2->BSSType != pProfile1->BSSType) + || !csr_is_encryption_in_list(pMac, &pProfile2->EncryptionType, + pProfile1->EncryptionType)) { + fCheck = false; + goto free_scan_filter; + } + if (pProfile1->MDID.mdiePresent || pProfile2->MDID.mdiePresent) { + if (pProfile1->MDID.mobilityDomain + != pProfile2->MDID.mobilityDomain) { + fCheck = false; + goto free_scan_filter; + } + } + /* Match found */ + fCheck = true; +free_scan_filter: + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return fCheck; +} + +static bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile, + struct csr_roam_profile *pProfile2) +{ + bool fCheck = false; + int i; + + do { + /* Only check for static WEP */ + if (!csr_is_encryption_in_list + (pMac, &pProfile2->EncryptionType, + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY) + && !csr_is_encryption_in_list(pMac, + &pProfile2->EncryptionType, + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) { + fCheck = true; + break; + } + if (!csr_is_encryption_in_list + (pMac, &pProfile2->EncryptionType, + pConnProfile->EncryptionType)) + break; + if (pConnProfile->Keys.defaultIndex != + pProfile2->Keys.defaultIndex) + break; + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + if (pConnProfile->Keys.KeyLength[i] != + pProfile2->Keys.KeyLength[i]) + break; + if (qdf_mem_cmp(&pConnProfile->Keys.KeyMaterial[i], + &pProfile2->Keys.KeyMaterial[i], + pProfile2->Keys.KeyLength[i])) { + break; + } + } + if (i == CSR_MAX_NUM_KEY) + fCheck = true; + } while (0); + return fCheck; +} + +/* IBSS */ + +static uint8_t csr_roam_get_ibss_start_channel_number50(tpAniSirGlobal pMac) +{ + uint8_t channel = 0; + uint32_t idx; + uint32_t idxValidChannels; + bool fFound = false; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam. + AdHocChannel5G) { + channel = pMac->roam.configParam.AdHocChannel5G; + if (!csr_roam_is_channel_valid(pMac, channel)) + channel = 0; + } + if (0 == channel + && + QDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels + (pMac, (uint8_t *) pMac->roam. + validChannelList, &len))) { + for (idx = 0; (idx < CSR_NUM_IBSS_START_CHAN_50) && !fFound; + idx++) { + for (idxValidChannels = 0; + (idxValidChannels < len) && !fFound; + idxValidChannels++) { + if (csr_start_ibss_channels50[idx] == + pMac->roam. + validChannelList[idxValidChannels]) { + fFound = true; + channel = + csr_start_ibss_channels50[idx]; + } + } + } + /* + * this is rare, but if it does happen, + * we find anyone in 11a bandwidth and + * return the first 11a channel found! + */ + if (!fFound) { + for (idxValidChannels = 0; idxValidChannels < len; + idxValidChannels++) { + if (WLAN_REG_IS_5GHZ_CH(pMac->roam. + validChannelList[idxValidChannels])) { + /* the max channel# in 11g is 14 */ + if (idxValidChannels < + CSR_NUM_IBSS_START_CHAN_50) { + channel = + pMac->roam.validChannelList + [idxValidChannels]; + } + break; + } + } + } + } /* if */ + + return channel; +} + +static uint8_t csr_roam_get_ibss_start_channel_number24(tpAniSirGlobal pMac) +{ + uint8_t channel = 1; + uint32_t idx; + uint32_t idxValidChannels; + bool fFound = false; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam. + AdHocChannel24) { + channel = pMac->roam.configParam.AdHocChannel24; + if (!csr_roam_is_channel_valid(pMac, channel)) + channel = 0; + } + + if (0 == channel + && + QDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels(pMac, + (uint8_t *) pMac->roam.validChannelList, + &len))) { + for (idx = 0; (idx < CSR_NUM_IBSS_START_CHANNELS_24) && !fFound; + idx++) { + for (idxValidChannels = 0; + (idxValidChannels < len) && !fFound; + idxValidChannels++) { + if (csr_start_ibss_channels24[idx] == + pMac->roam. + validChannelList[idxValidChannels]) { + fFound = true; + channel = + csr_start_ibss_channels24[idx]; + } + } + } + } + + return channel; +} +/** + * csr_populate_basic_rates() - populates OFDM or CCK rates + * @rates: rate struct to populate + * @is_ofdm_rates: true: ofdm rates, false: cck rates + * @is_basic_rates: indicates if rates are to be masked with + * CSR_DOT11_BASIC_RATE_MASK + * + * This function will populate OFDM or CCK rates + * + * Return: void + */ +static void +csr_populate_basic_rates(tSirMacRateSet *rate_set, bool is_ofdm_rates, + bool is_basic_rates) +{ + int i = 0; + 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] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[4] |= CSR_DOT11_BASIC_RATE_MASK; + } + for (i = 0; i < rate_set->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("Default OFDM rate is %2x"), rate_set->rate[i]); + } else { + rate_set->numRates = 4; + qdf_mem_copy(rate_set->rate, cck_rates, sizeof(cck_rates)); + if (is_basic_rates) { + rate_set->rate[0] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[1] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[3] |= CSR_DOT11_BASIC_RATE_MASK; + } + for (i = 0; i < rate_set->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("Default CCK rate is %2x"), rate_set->rate[i]); + + } +} + +/** + * csr_convert_mode_to_nw_type() - convert mode into network type + * @dot11_mode: dot11_mode + * @band: 2.4 or 5 GHz + * + * Return: tSirNwType + */ +static tSirNwType +csr_convert_mode_to_nw_type(enum csr_cfgdot11mode dot11_mode, + enum band_info 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 (BAND_2G == band) + return eSIR_11G_NW_TYPE; + else + return eSIR_11A_NW_TYPE; + } + return eSIR_DONOT_USE_NW_TYPE; +} + +/** + * csr_populate_supported_rates_from_hostapd() - populates operational + * and extended rates. + * from hostapd.conf file + * @opr_rates: rate struct to populate operational rates + * @ext_rates: rate struct to populate extended rates + * @profile: bss profile + * + * Return: void + */ +static void csr_populate_supported_rates_from_hostapd(tSirMacRateSet *opr_rates, + tSirMacRateSet *ext_rates, + struct csr_roam_profile *profile) +{ + int i = 0; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("supported_rates: %d extended_rates: %d"), + profile->supported_rates.numRates, + profile->extended_rates.numRates); + + if (profile->supported_rates.numRates > SIR_MAC_RATESET_EID_MAX) + profile->supported_rates.numRates = SIR_MAC_RATESET_EID_MAX; + + if (profile->extended_rates.numRates > SIR_MAC_RATESET_EID_MAX) + profile->extended_rates.numRates = SIR_MAC_RATESET_EID_MAX; + + if (profile->supported_rates.numRates) { + opr_rates->numRates = profile->supported_rates.numRates; + qdf_mem_copy(opr_rates->rate, + profile->supported_rates.rate, + profile->supported_rates.numRates); + for (i = 0; i < opr_rates->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Supported Rate is %2x"), opr_rates->rate[i]); + } + if (profile->extended_rates.numRates) { + ext_rates->numRates = + profile->extended_rates.numRates; + qdf_mem_copy(ext_rates->rate, + profile->extended_rates.rate, + profile->extended_rates.numRates); + for (i = 0; i < ext_rates->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Extended Rate is %2x"), ext_rates->rate[i]); + } +} + +/** + * csr_roam_get_bss_start_parms() - get bss start param from profile + * @pMac: mac global context + * @pProfile: roam profile + * @pParam: out param, start bss params + * @skip_hostapd_rate: to skip given hostapd's rate + * + * This function populates start bss param from roam profile + * + * Return: void + */ +static QDF_STATUS +csr_roam_get_bss_start_parms(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + struct csr_roamstart_bssparams *pParam, + bool skip_hostapd_rate) +{ + enum band_info band; + uint8_t opr_ch = 0; + tSirNwType nw_type; + uint8_t tmp_opr_ch = 0; + tSirMacRateSet *opr_rates = &pParam->operationalRateSet; + tSirMacRateSet *ext_rates = &pParam->extendedRateSet; + + if (pProfile->ChannelInfo.numOfChannels + && pProfile->ChannelInfo.ChannelList) + tmp_opr_ch = pProfile->ChannelInfo.ChannelList[0]; + + pParam->uCfgDot11Mode = csr_roam_get_phy_mode_band_for_bss(pMac, + pProfile, tmp_opr_ch, &band); + + if (((pProfile->csrPersona == QDF_P2P_CLIENT_MODE) + || (pProfile->csrPersona == QDF_P2P_GO_MODE)) + && (pParam->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11B)) { + /* This should never happen */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "For P2P (persona %d) dot11_mode is 11B", + pProfile->csrPersona); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + nw_type = csr_convert_mode_to_nw_type(pParam->uCfgDot11Mode, band); + ext_rates->numRates = 0; + /* + * hostapd.conf will populate its basic and extended rates + * as per hw_mode, but if acs in ini is enabled driver should + * ignore basic and extended rates from hostapd.conf and should + * populate default rates. + */ + if (!cds_is_sub_20_mhz_enabled() && !skip_hostapd_rate && + (pProfile->supported_rates.numRates || + pProfile->extended_rates.numRates)) { + csr_populate_supported_rates_from_hostapd(opr_rates, + ext_rates, pProfile); + pParam->operationChn = tmp_opr_ch; + } else { + switch (nw_type) { + default: + sme_err( + "sees an unknown pSirNwType (%d)", + nw_type); + return QDF_STATUS_E_INVAL; + case eSIR_11A_NW_TYPE: + csr_populate_basic_rates(opr_rates, true, true); + if (eCSR_OPERATING_CHANNEL_ANY != tmp_opr_ch) { + opr_ch = tmp_opr_ch; + break; + } + opr_ch = csr_roam_get_ibss_start_channel_number50(pMac); + if (0 == opr_ch && + CSR_IS_PHY_MODE_DUAL_BAND(pProfile->phyMode) && + CSR_IS_PHY_MODE_DUAL_BAND( + pMac->roam.configParam.phyMode)) { + /* + * We could not find a 5G channel by auto pick, + * let's try 2.4G channels. We only do this here + * because csr_roam_get_phy_mode_band_for_bss + * always picks 11a for AUTO + */ + nw_type = eSIR_11B_NW_TYPE; + opr_ch = + csr_roam_get_ibss_start_channel_number24(pMac); + csr_populate_basic_rates(opr_rates, false, + true); + } + break; + case eSIR_11B_NW_TYPE: + csr_populate_basic_rates(opr_rates, false, true); + if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch) + opr_ch = + csr_roam_get_ibss_start_channel_number24(pMac); + else + opr_ch = tmp_opr_ch; + break; + case eSIR_11G_NW_TYPE: + /* For P2P Client and P2P GO, disable 11b rates */ + if ((pProfile->csrPersona == QDF_P2P_CLIENT_MODE) || + (pProfile->csrPersona == QDF_P2P_GO_MODE) || + (eCSR_CFG_DOT11_MODE_11G_ONLY == + pParam->uCfgDot11Mode)) { + csr_populate_basic_rates(opr_rates, true, true); + } else { + csr_populate_basic_rates(opr_rates, false, + true); + csr_populate_basic_rates(ext_rates, true, + false); + } + if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch) + opr_ch = + csr_roam_get_ibss_start_channel_number24(pMac); + else + opr_ch = tmp_opr_ch; + break; + } + pParam->operationChn = opr_ch; + } + + pParam->sirNwType = nw_type; + pParam->ch_params.ch_width = pProfile->ch_params.ch_width; + pParam->ch_params.center_freq_seg0 = + pProfile->ch_params.center_freq_seg0; + pParam->ch_params.center_freq_seg1 = + pProfile->ch_params.center_freq_seg1; + pParam->ch_params.sec_ch_offset = + pProfile->ch_params.sec_ch_offset; + return QDF_STATUS_SUCCESS; +} + +static void +csr_roam_get_bss_start_parms_from_bss_desc( + tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + struct csr_roamstart_bssparams *pParam) +{ + if (!pParam) { + sme_err("BSS param's pointer is NULL"); + return; + } + + pParam->sirNwType = pBssDesc->nwType; + pParam->cbMode = PHY_SINGLE_CHANNEL_CENTERED; + pParam->operationChn = pBssDesc->channelId; + qdf_mem_copy(&pParam->bssid, pBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + + if (!pIes) { + pParam->ssId.length = 0; + pParam->operationalRateSet.numRates = 0; + sme_err("IEs struct pointer is NULL"); + return; + } + + if (pIes->SuppRates.present) { + pParam->operationalRateSet.numRates = pIes->SuppRates.num_rates; + if (pIes->SuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) { + sme_err( + "num_rates: %d > max val, resetting", + pIes->SuppRates.num_rates); + pIes->SuppRates.num_rates = SIR_MAC_RATESET_EID_MAX; + } + qdf_mem_copy(pParam->operationalRateSet.rate, + pIes->SuppRates.rates, + sizeof(*pIes->SuppRates.rates) * + pIes->SuppRates.num_rates); + } + if (pIes->ExtSuppRates.present) { + pParam->extendedRateSet.numRates = pIes->ExtSuppRates.num_rates; + if (pIes->ExtSuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) { + sme_err( + "num_rates: %d > max val, resetting", + pIes->ExtSuppRates.num_rates); + pIes->ExtSuppRates.num_rates = SIR_MAC_RATESET_EID_MAX; + } + qdf_mem_copy(pParam->extendedRateSet.rate, + pIes->ExtSuppRates.rates, + sizeof(*pIes->ExtSuppRates.rates) * + pIes->ExtSuppRates.num_rates); + } + if (pIes->SSID.present) { + pParam->ssId.length = pIes->SSID.num_ssid; + qdf_mem_copy(pParam->ssId.ssId, pIes->SSID.ssid, + pParam->ssId.length); + } + pParam->cbMode = csr_get_cb_mode_from_ies(pMac, pParam->operationChn, + pIes); +} + +static void csr_roam_determine_max_rate_for_ad_hoc(tpAniSirGlobal pMac, + tSirMacRateSet *pSirRateSet) +{ + uint8_t MaxRate = 0; + uint32_t i; + uint8_t *pRate; + + pRate = pSirRateSet->rate; + for (i = 0; i < pSirRateSet->numRates; i++) { + MaxRate = CSR_MAX(MaxRate, (pRate[i] & + (~CSR_DOT11_BASIC_RATE_MASK))); + } + + /* Save the max rate in the connected state information. + * modify LastRates variable as well + */ + +} + +QDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roamstart_bssparams *pParam, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc, + uint32_t roamId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum band_info eBand; + /* Set the roaming substate to 'Start BSS attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_START_BSS_REQ, + sessionId); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + /* Need to figure out whether we need to log WDS??? */ + if (CSR_IS_IBSS(pProfile)) { + host_log_ibss_pkt_type *pIbssLog; + + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + if (pBssDesc) { + pIbssLog->eventId = + WLAN_IBSS_EVENT_JOIN_IBSS_REQ; + qdf_mem_copy(pIbssLog->bssid.bytes, + pBssDesc->bssId, QDF_MAC_ADDR_SIZE); + } else + pIbssLog->eventId = + WLAN_IBSS_EVENT_START_IBSS_REQ; + + qdf_mem_copy(pIbssLog->ssid, pParam->ssId.ssId, + pParam->ssId.length); + if (pProfile->ChannelInfo.numOfChannels == 0) + pIbssLog->channelSetting = AUTO_PICK; + else + pIbssLog->channelSetting = SPECIFIED; + + pIbssLog->operatingChannel = pParam->operationChn; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + /* Put RSN information in for Starting BSS */ + pParam->nRSNIELength = (uint16_t) pProfile->nRSNReqIELength; + pParam->pRSNIE = pProfile->pRSNReqIE; + + pParam->privacy = pProfile->privacy; + pParam->fwdWPSPBCProbeReq = pProfile->fwdWPSPBCProbeReq; + pParam->authType = pProfile->csr80211AuthType; + pParam->beaconInterval = pProfile->beaconInterval; + pParam->dtimPeriod = pProfile->dtimPeriod; + pParam->ApUapsdEnable = pProfile->ApUapsdEnable; + pParam->ssidHidden = pProfile->SSIDs.SSIDList[0].ssidHidden; + if (CSR_IS_INFRA_AP(pProfile) && (pParam->operationChn != 0)) { + if (csr_is_valid_channel(pMac, pParam->operationChn) != + QDF_STATUS_SUCCESS) { + pParam->operationChn = INFRA_AP_DEFAULT_CHANNEL; + pParam->ch_params.ch_width = CH_WIDTH_20MHZ; + } + } + pParam->protEnabled = pProfile->protEnabled; + pParam->obssProtEnabled = pProfile->obssProtEnabled; + pParam->ht_protection = pProfile->cfg_protection; + pParam->wps_state = pProfile->wps_state; + + pParam->uCfgDot11Mode = + csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, + pParam-> + operationChn, + &eBand); + pParam->bssPersona = pProfile->csrPersona; + +#ifdef WLAN_FEATURE_11W + pParam->mfpCapable = (0 != pProfile->MFPCapable); + pParam->mfpRequired = (0 != pProfile->MFPRequired); +#endif + + pParam->addIeParams.probeRespDataLen = + pProfile->addIeParams.probeRespDataLen; + pParam->addIeParams.probeRespData_buff = + pProfile->addIeParams.probeRespData_buff; + + pParam->addIeParams.assocRespDataLen = + pProfile->addIeParams.assocRespDataLen; + pParam->addIeParams.assocRespData_buff = + pProfile->addIeParams.assocRespData_buff; + + if (CSR_IS_IBSS(pProfile)) { + pParam->addIeParams.probeRespBCNDataLen = + pProfile->nWPAReqIELength; + pParam->addIeParams.probeRespBCNData_buff = pProfile->pWPAReqIE; + } else { + pParam->addIeParams.probeRespBCNDataLen = + pProfile->addIeParams.probeRespBCNDataLen; + pParam->addIeParams.probeRespBCNData_buff = + pProfile->addIeParams.probeRespBCNData_buff; + } + pParam->sap_dot11mc = pProfile->sap_dot11mc; + pParam->cac_duration_ms = pProfile->cac_duration_ms; + pParam->dfs_regdomain = pProfile->dfs_regdomain; + pParam->beacon_tx_rate = pProfile->beacon_tx_rate; + + /* When starting an IBSS, start on the channel from the Profile. */ + status = csr_send_mb_start_bss_req_msg(pMac, sessionId, + pProfile->BSSType, pParam, + pBssDesc); + return status; +} + +void csr_roam_prepare_bss_params(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc, + struct bss_config_param *pBssConfig, + tDot11fBeaconIEs *pIes) +{ + uint8_t Channel; + ePhyChanBondState cbMode = PHY_SINGLE_CHANNEL_CENTERED; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + bool skip_hostapd_rate = !pProfile->chan_switch_hostapd_rate_enabled; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return; + } + + if (pBssDesc) { + csr_roam_get_bss_start_parms_from_bss_desc(pMac, pBssDesc, pIes, + &pSession->bssParams); + if (CSR_IS_NDI(pProfile)) { + qdf_copy_macaddr(&pSession->bssParams.bssid, + &pSession->selfMacAddr); + } + } else { + csr_roam_get_bss_start_parms(pMac, pProfile, + &pSession->bssParams, + skip_hostapd_rate); + /* Use the first SSID */ + if (pProfile->SSIDs.numOfSSIDs) + qdf_mem_copy(&pSession->bssParams.ssId, + pProfile->SSIDs.SSIDList, + sizeof(tSirMacSSid)); + if (pProfile->BSSIDs.numOfBSSIDs) + /* Use the first BSSID */ + qdf_mem_copy(&pSession->bssParams.bssid, + pProfile->BSSIDs.bssid, + sizeof(struct qdf_mac_addr)); + else + qdf_mem_zero(&pSession->bssParams.bssid, + sizeof(struct qdf_mac_addr)); + } + Channel = pSession->bssParams.operationChn; + /* Set operating channel in pProfile which will be used */ + /* in csr_roam_set_bss_config_cfg() to determine channel bonding */ + /* mode and will be configured in CFG later */ + pProfile->operationChannel = Channel; + + if (Channel == 0) + sme_err("CSR cannot find a channel to start IBSS"); + else { + csr_roam_determine_max_rate_for_ad_hoc(pMac, + &pSession->bssParams. + operationalRateSet); + if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_START_IBSS(pProfile)) { + if (WLAN_REG_IS_24GHZ_CH(Channel)) { + cbMode = + pMac->roam.configParam. + channelBondingMode24GHz; + } else { + cbMode = + pMac->roam.configParam. + channelBondingMode5GHz; + } + sme_debug("## cbMode %d", cbMode); + pBssConfig->cbMode = cbMode; + pSession->bssParams.cbMode = cbMode; + } + } +} + +static QDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + bool *pfSameIbss) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fSameIbss = false; + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + /* Check if any profile parameter has changed ? If any profile + * parameter has changed then stop old BSS and start a new one + * with new parameters + */ + if (csr_is_same_profile(pMac, + &pMac->roam.roamSession[sessionId]. + connectedProfile, pProfile)) + fSameIbss = true; + else + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + + } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) + /* Disassociate from the connected Infrastructure network... */ + status = csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + else { + struct bss_config_param *pBssConfig; + + pBssConfig = qdf_mem_malloc(sizeof(struct bss_config_param)); + if (NULL == pBssConfig) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + /* there is no Bss description before we start an IBSS + * so we need to adopt all Bss configuration parameters + * from the Profile. + */ + status = csr_roam_prepare_bss_config_from_profile(pMac, + pProfile, + pBssConfig, + NULL); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* save dotMode */ + pMac->roam.roamSession[sessionId].bssParams. + uCfgDot11Mode = pBssConfig->uCfgDot11Mode; + /* Prepare some more parameters for this IBSS */ + csr_roam_prepare_bss_params(pMac, sessionId, + pProfile, NULL, + pBssConfig, NULL); + status = csr_roam_set_bss_config_cfg(pMac, + sessionId, + pProfile, NULL, + pBssConfig, + NULL, false); + } + + qdf_mem_free(pBssConfig); + } /* Allocate memory */ + } + + if (pfSameIbss) + *pfSameIbss = fSameIbss; + return status; +} + +static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirSmeNewBssInfo *pNewBss) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return; + } + + if (pNewBss) { + /* Set the operating channel. */ + pSession->connectedProfile.operationChannel = + pNewBss->channelNumber; + /* move the BSSId from the BSS description into the connected + * state information. + */ + qdf_mem_copy(&pSession->connectedProfile.bssid.bytes, + &(pNewBss->bssId), sizeof(struct qdf_mac_addr)); + } +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void csr_get_pmk_info(tpAniSirGlobal mac_ctx, uint8_t session_id, + tPmkidCacheInfo *pmk_cache) +{ + struct csr_roam_session *session = NULL; + + if (!mac_ctx) { + sme_err("Mac_ctx is NULL"); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("session %d not found", session_id); + return; + } + qdf_mem_copy(pmk_cache->pmk, session->psk_pmk, + sizeof(session->psk_pmk)); + pmk_cache->pmk_len = session->pmk_len; +} + +QDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(pSession->psk_pmk, pPSK_PMK, sizeof(pSession->psk_pmk)); + pSession->pmk_len = pmk_len; + + if (csr_is_auth_type_ese(pMac->roam.roamSession[sessionId]. + connectedProfile.AuthType)) { + sme_debug("PMK update is not required for ESE"); + return QDF_STATUS_SUCCESS; + } + + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_PSK_PMK_CHANGED); + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_set_pmkid(struct csr_roam_session *pSession) +{ + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); + qdf_mem_zero(&secEvent, + sizeof(host_event_wlan_security_payload_type)); + secEvent.eventId = WLAN_SECURITY_EVENT_PMKID_UPDATE; + secEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + pSession->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + pSession->connectedProfile.EncryptionType); + qdf_mem_copy(secEvent.bssid, + pSession->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + secEvent.authMode = (uint8_t) diag_auth_type_from_csr_type( + pSession->connectedProfile.AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_update_pmk_cache - API to update PMK cache + * @pSession: pointer to session + * @pmksa: pointer to PMKSA struct + * + * Return : None + */ +static void csr_update_pmk_cache(struct csr_roam_session *session, + tPmkidCacheInfo *pmksa) +{ + uint16_t cache_idx = session->curr_cache_idx; + + /* Add entry to the cache */ + if (!pmksa->ssid_len) { + qdf_copy_macaddr( + &session->PmkidCacheInfo[cache_idx].BSSID, + &pmksa->BSSID); + session->PmkidCacheInfo[cache_idx].ssid_len = 0; + } else { + qdf_mem_copy(session->PmkidCacheInfo[cache_idx].ssid, + pmksa->ssid, pmksa->ssid_len); + session->PmkidCacheInfo[cache_idx].ssid_len = + pmksa->ssid_len; + qdf_mem_copy(session->PmkidCacheInfo[cache_idx].cache_id, + pmksa->cache_id, CACHE_ID_LEN); + + } + qdf_mem_copy( + session->PmkidCacheInfo[cache_idx].PMKID, + pmksa->PMKID, CSR_RSN_PMKID_SIZE); + + if (pmksa->pmk_len) + qdf_mem_copy(session->PmkidCacheInfo[cache_idx].pmk, + pmksa->pmk, pmksa->pmk_len); + + session->PmkidCacheInfo[cache_idx].pmk_len = pmksa->pmk_len; + + /* Increment the CSR local cache index */ + if (cache_idx < (CSR_MAX_PMKID_ALLOWED - 1)) + session->curr_cache_idx++; + else { + sme_debug("max value reached, setting current index as 0"); + session->curr_cache_idx = 0; + } + + session->NumPmkidCache++; + if (session->NumPmkidCache > CSR_MAX_PMKID_ALLOWED) { + sme_debug("setting num pmkid cache to %d", + CSR_MAX_PMKID_ALLOWED); + session->NumPmkidCache = CSR_MAX_PMKID_ALLOWED; + } +} + +QDF_STATUS +csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCacheInfo *pPMKIDCache, uint32_t numItems, + bool update_entire_cache) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t i = 0; + tPmkidCacheInfo *pmksa; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("numItems = %d", numItems); + + if (numItems > CSR_MAX_PMKID_ALLOWED) + return QDF_STATUS_E_INVAL; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_set_pmkid(pSession); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + if (update_entire_cache) { + if (numItems && pPMKIDCache) { + pSession->NumPmkidCache = (uint16_t) numItems; + qdf_mem_copy(pSession->PmkidCacheInfo, pPMKIDCache, + sizeof(tPmkidCacheInfo) * numItems); + pSession->curr_cache_idx = (uint16_t)numItems; + } + return QDF_STATUS_SUCCESS; + } + + for (i = 0; i < numItems; i++) { + pmksa = &pPMKIDCache[i]; + + /* Delete the entry if present */ + csr_roam_del_pmkid_from_cache(pMac, sessionId, + pmksa, false); + /* Update new entry */ + csr_update_pmk_cache(pSession, pmksa); + + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void csr_mem_zero_psk_pmk(struct csr_roam_session *session) +{ + qdf_mem_zero(session->psk_pmk, sizeof(session->psk_pmk)); + session->pmk_len = 0; +} +#else +static void csr_mem_zero_psk_pmk(struct csr_roam_session *session) +{ +} +#endif + +QDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + tPmkidCacheInfo *pmksa, + bool flush_cache) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + bool fMatchFound = false; + uint32_t Index; + uint32_t curr_idx; + tPmkidCacheInfo *cached_pmksa; + uint32_t i; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* Check if there are no entries to delete */ + if (0 == pSession->NumPmkidCache) { + sme_debug("No entries to delete/Flush"); + return QDF_STATUS_SUCCESS; + } + + if (flush_cache) { + /* Flush the entire cache */ + qdf_mem_zero(pSession->PmkidCacheInfo, + sizeof(tPmkidCacheInfo) * CSR_MAX_PMKID_ALLOWED); + pSession->NumPmkidCache = 0; + pSession->curr_cache_idx = 0; + csr_mem_zero_psk_pmk(pSession); + return QDF_STATUS_SUCCESS; + } + + /* !flush_cache - so look up in the cache */ + for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) { + cached_pmksa = &pSession->PmkidCacheInfo[Index]; + if ((!cached_pmksa->ssid_len) && + qdf_is_macaddr_equal(&cached_pmksa->BSSID, + &pmksa->BSSID)) + fMatchFound = 1; + + else if (cached_pmksa->ssid_len && + (!qdf_mem_cmp(cached_pmksa->ssid, + pmksa->ssid, pmksa->ssid_len)) && + (!qdf_mem_cmp(cached_pmksa->cache_id, + pmksa->cache_id, CACHE_ID_LEN))) + fMatchFound = 1; + + if (fMatchFound) { + /* Clear this - matched entry */ + qdf_mem_zero(cached_pmksa, + sizeof(tPmkidCacheInfo)); + break; + } + } + + if (Index == CSR_MAX_PMKID_ALLOWED && !fMatchFound) { + sme_debug("No such PMKSA entry exists"); + return QDF_STATUS_SUCCESS; + } + + /* Match Found, Readjust the other entries */ + curr_idx = pSession->curr_cache_idx; + if (Index < curr_idx) { + for (i = Index; i < (curr_idx - 1); i++) { + qdf_mem_copy(&pSession->PmkidCacheInfo[i], + &pSession->PmkidCacheInfo[i + 1], + sizeof(tPmkidCacheInfo)); + } + + pSession->curr_cache_idx--; + qdf_mem_zero(&pSession->PmkidCacheInfo + [pSession->curr_cache_idx], + sizeof(tPmkidCacheInfo)); + } else if (Index > curr_idx) { + for (i = Index; i > (curr_idx); i--) { + qdf_mem_copy(&pSession->PmkidCacheInfo[i], + &pSession->PmkidCacheInfo[i - 1], + sizeof(tPmkidCacheInfo)); + } + + qdf_mem_zero(&pSession->PmkidCacheInfo + [pSession->curr_cache_idx], + sizeof(tPmkidCacheInfo)); + } + + /* Decrement the count since an entry has been deleted */ + pSession->NumPmkidCache--; + sme_debug("PMKID at index=%d deleted, current index=%d cache count=%d", + Index, pSession->curr_cache_idx, pSession->NumPmkidCache); + + return QDF_STATUS_SUCCESS; +} + +uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return pMac->roam.roamSession[sessionId].NumPmkidCache; +} + +QDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + tPmkidCacheInfo *pmksa; + uint16_t i, j; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (!pNum || !pPmkidCache) { + sme_err("Either pNum or pPmkidCache is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->NumPmkidCache == 0) { + *pNum = 0; + return QDF_STATUS_SUCCESS; + } + + if (*pNum < pSession->NumPmkidCache) + return QDF_STATUS_E_FAILURE; + + if (pSession->NumPmkidCache > CSR_MAX_PMKID_ALLOWED) { + sme_err("NumPmkidCache :%d is more than CSR_MAX_PMKID_ALLOWED, resetting to CSR_MAX_PMKID_ALLOWED", + pSession->NumPmkidCache); + pSession->NumPmkidCache = CSR_MAX_PMKID_ALLOWED; + } + + for (i = 0, j = 0; ((j < pSession->NumPmkidCache) && + (i < CSR_MAX_PMKID_ALLOWED)); i++) { + /* Fill the valid entries */ + pmksa = &pSession->PmkidCacheInfo[i]; + if (!qdf_is_macaddr_zero(&pmksa->BSSID)) { + qdf_mem_copy(pPmkidCache, pmksa, + sizeof(tPmkidCacheInfo)); + pPmkidCache++; + j++; + } + } + + *pNum = pSession->NumPmkidCache; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWpaRsnReqIeLength; + if (pBuf) { + if (len >= pSession->nWpaRsnReqIeLength) { + qdf_mem_copy(pBuf, pSession->pWpaRsnReqIE, + pSession->nWpaRsnReqIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} + +QDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWpaRsnRspIeLength; + if (pBuf) { + if (len >= pSession->nWpaRsnRspIeLength) { + qdf_mem_copy(pBuf, pSession->pWpaRsnRspIE, + pSession->nWpaRsnRspIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} + +#ifdef FEATURE_WLAN_WAPI +QDF_STATUS csr_roam_get_wapi_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWapiReqIeLength; + if (pBuf) { + if (len >= pSession->nWapiReqIeLength) { + qdf_mem_copy(pBuf, pSession->pWapiReqIE, + pSession->nWapiReqIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} + +QDF_STATUS csr_roam_get_wapi_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWapiRspIeLength; + if (pBuf) { + if (len >= pSession->nWapiRspIeLength) { + qdf_mem_copy(pBuf, pSession->pWapiRspIE, + pSession->nWapiRspIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} +#endif /* FEATURE_WLAN_WAPI */ +eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + eRoamCmdStatus retStatus = eCSR_ROAM_CONNECT_COMPLETION; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return retStatus; + } + + if (CSR_IS_ROAMING(pSession)) { + retStatus = eCSR_ROAM_ROAMING_COMPLETION; + pSession->fRoaming = false; + } + return retStatus; +} + +static QDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + struct bss_config_param bssConfig; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) { + /* Disassociate from the connected Infrastructure network.*/ + status = csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + } else { + /* We don't expect Bt-AMP HDD not to disconnect the last + * connection first at this time. Otherwise we need to add + * code to handle the situation just like IBSS. Though for + * WDS station, we need to send disassoc to PE first then + * send stop_bss to PE, before we can continue. + */ + + if (csr_is_conn_state_wds(pMac, sessionId)) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&bssConfig, sizeof(struct bss_config_param)); + /* Assume HDD provide bssid in profile */ + qdf_copy_macaddr(&pSession->bssParams.bssid, + pProfile->BSSIDs.bssid); + /* there is no Bss description before we start an WDS so we + * need to adopt all Bss configuration parameters from the + * Profile. + */ + status = csr_roam_prepare_bss_config_from_profile(pMac, + pProfile, + &bssConfig, + pBssDesc); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Save profile for late use */ + csr_free_roam_profile(pMac, sessionId); + pSession->pCurRoamProfile = + qdf_mem_malloc(sizeof(struct csr_roam_profile)); + if (pSession->pCurRoamProfile != NULL) { + csr_roam_copy_profile(pMac, + pSession->pCurRoamProfile, + pProfile); + } + /* Prepare some more parameters for this WDS */ + csr_roam_prepare_bss_params(pMac, sessionId, pProfile, + NULL, &bssConfig, NULL); + status = csr_roam_set_bss_config_cfg(pMac, sessionId, + pProfile, NULL, + &bssConfig, NULL, + false); + } + } + + return status; +} + +/** + * csr_add_supported_5Ghz_channels()- Add valid 5Ghz channels + * in Join req. + * @mac_ctx: pointer to global mac structure + * @chan_list: Pointer to channel list buffer to populate + * @num_chan: 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 + */ +static void csr_add_supported_5Ghz_channels(tpAniSirGlobal mac_ctx, + uint8_t *chan_list, + uint8_t *num_chnl, + bool supp_chan_ie) +{ + uint16_t i, j; + uint32_t size = 0; + + if (!chan_list) { + sme_err("chan_list buffer NULL"); + return; + } + + size = sizeof(mac_ctx->roam.validChannelList); + if (QDF_IS_STATUS_SUCCESS + (csr_get_cfg_valid_channels(mac_ctx, + (uint8_t *) mac_ctx->roam.validChannelList, + &size))) { + for (i = 0, j = 0; i < size; i++) { + /* Only add 5ghz channels.*/ + if (WLAN_REG_IS_5GHZ_CH + (mac_ctx->roam.validChannelList[i])) { + chan_list[j] + = mac_ctx->roam.validChannelList[i]; + j++; + + if (supp_chan_ie) { + chan_list[j] = 1; + j++; + } + } + } + *num_chnl = (uint8_t)j; + } else { + sme_err("can not find any valid channel"); + *num_chnl = 0; + } +} + +/** + * csr_set_ldpc_exception() - to set allow any LDPC exception permitted + * @mac_ctx: Pointer to mac context + * @session: Pointer to SME/CSR session + * @channel: Given channel number where connection will go + * @usr_cfg_rx_ldpc: User provided RX LDPC setting + * + * 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 csr_set_ldpc_exception(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, uint8_t channel, + bool usr_cfg_rx_ldpc) +{ + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "mac_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (!session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "session is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (usr_cfg_rx_ldpc && wma_is_rx_ldpc_supported_for_channel(channel)) { + session->htConfig.ht_rx_ldpc = 1; + session->vht_config.ldpc_coding = 1; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LDPC enable for chnl[%d]", channel); + } else { + session->htConfig.ht_rx_ldpc = 0; + session->vht_config.ldpc_coding = 0; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LDPC disable for chnl[%d]", channel); + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11W +/** + * csr_is_mfpc_capable() - is MFPC capable + * @ies: AP information element + * + * Return: true if MFPC capable, false otherwise + */ +bool csr_is_mfpc_capable(struct sDot11fIERSN *rsn) +{ + bool mfpc_capable = false; + + if (rsn && rsn->present && + ((rsn->RSN_Cap[0] >> 7) & 0x01)) + mfpc_capable = true; + + return mfpc_capable; +} + +/** + * csr_set_mgmt_enc_type() - set mgmt enc type for PMF + * @profile: roam profile + * @ies: AP ie + * @csr_join_req: csr join req + * + * Return: void + */ +static void csr_set_mgmt_enc_type(struct csr_roam_profile *profile, + tDot11fBeaconIEs *ies, + tSirSmeJoinReq *csr_join_req) +{ + sme_debug("mgmt encryption type %d MFPe %d MFPr %d", + profile->mgmt_encryption_type, + profile->MFPEnabled, profile->MFPRequired); + + if (profile->MFPEnabled) + csr_join_req->MgmtEncryptionType = + profile->mgmt_encryption_type; + else + csr_join_req->MgmtEncryptionType = eSIR_ED_NONE; + + if (profile->MFPEnabled && + !(profile->MFPRequired) && + !csr_is_mfpc_capable(&ies->RSN)) + csr_join_req->MgmtEncryptionType = eSIR_ED_NONE; +} +#else +static inline void csr_set_mgmt_enc_type(struct csr_roam_profile *profile, + tDot11fBeaconIEs *pIes, + tSirSmeJoinReq *csr_join_req) +{ +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_update_fils_connection_info: Copy fils connection info to join request + * @profile: pointer to profile + * @csr_join_req: csr join request + * + * Return: None + */ +static void csr_update_fils_connection_info(struct csr_roam_profile *profile, + tSirSmeJoinReq *csr_join_req) +{ + if (!profile->fils_con_info) + return; + + if (profile->fils_con_info->is_fils_connection) { + qdf_mem_copy(&csr_join_req->fils_con_info, + profile->fils_con_info, + sizeof(struct cds_fils_connection_info)); + } else { + qdf_mem_zero(&csr_join_req->fils_con_info, + sizeof(struct cds_fils_connection_info)); + } +} +#else +static void csr_update_fils_connection_info(struct csr_roam_profile *profile, + tSirSmeJoinReq *csr_join_req) +{ } +#endif + +#ifdef WLAN_FEATURE_SAE +/* + * csr_update_sae_config: Copy SAE info to join request + * @profile: pointer to profile + * @csr_join_req: csr join request + * + * Return: None + */ +static void csr_update_sae_config(tSirSmeJoinReq *csr_join_req, + tpAniSirGlobal mac, struct csr_roam_session *session) +{ + tPmkidCacheInfo pmkid_cache; + uint32_t index; + + qdf_mem_copy(pmkid_cache.BSSID.bytes, + csr_join_req->bssDescription.bssId, QDF_MAC_ADDR_SIZE); + + csr_join_req->sae_pmk_cached = + csr_lookup_pmkid_using_bssid(mac, session, &pmkid_cache, &index); + + sme_debug("pmk_cached %d for BSSID=" MAC_ADDRESS_STR, + csr_join_req->sae_pmk_cached, + MAC_ADDR_ARRAY(csr_join_req->bssDescription.bssId)); +} +#else +static void csr_update_sae_config(tSirSmeJoinReq *csr_join_req, + tpAniSirGlobal mac, struct csr_roam_session *session) +{ } +#endif + +/** + * csr_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 csr_get_nss_supported_by_sta_and_ap(tDot11fIEVHTCaps *vht_caps, + tDot11fIEHTCaps *ht_caps, + uint32_t dot11_mode) +{ + bool vht_capability, ht_capability; + + vht_capability = IS_DOT11_MODE_VHT(dot11_mode); + ht_capability = IS_DOT11_MODE_HT(dot11_mode); + + if (vht_capability && vht_caps->present) { + if ((vht_caps->rxMCSMap & 0xC0) != 0xC0) + return 4; + + if ((vht_caps->rxMCSMap & 0x30) != 0x30) + return 3; + + if ((vht_caps->rxMCSMap & 0x0C) != 0x0C) + return 2; + } else if (ht_capability && ht_caps->present) { + if (ht_caps->supportedMCSSet[3]) + return 4; + + if (ht_caps->supportedMCSSet[2]) + return 3; + + if (ht_caps->supportedMCSSet[1]) + return 2; + } + + return 1; +} + +/** + * csr_dump_vendor_ies() - Dumps all the vendor IEs + * @ie: ie buffer + * @ie_len: length of ie buffer + * + * This function dumps the vendor IEs present in the AP's IE buffer + * + * Return: none + */ +static +void csr_dump_vendor_ies(uint8_t *ie, uint16_t ie_len) +{ + int32_t left = ie_len; + uint8_t *ptr = ie; + uint8_t elem_id, elem_len; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + sme_err("Invalid IEs eid: %d elem_len: %d left: %d", + elem_id, elem_len, left); + return; + } + if (elem_id == SIR_MAC_EID_VENDOR) { + sme_debug("Dumping Vendor IE of len %d", elem_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + &ptr[2], elem_len); + } + left -= elem_len; + ptr += (elem_len + 2); + } +} + +/** + * csr_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 +csr_check_vendor_ap_3_present(tpAniSirGlobal 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))) { + sme_debug("Vendor OUI 3 and Vendor OUI 4 found"); + ret = false; + } + + return ret; +} + +/** + * csr_enable_twt() - Check if its allowed to enable twt for this session + * @ie: pointer to beacon/probe resp ie's + * + * TWT is allowed only if device is in 11ax mode and peer supports + * TWT responder or if QCN ie present. + * + * Return: true or flase + */ +static bool csr_enable_twt(tpAniSirGlobal mac_ctx, tDot11fBeaconIEs *ie) +{ + uint32_t value; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + CFG_GET_INT(status, mac_ctx, WNI_CFG_TWT_REQUESTOR, value); + if ((IS_FEATURE_SUPPORTED_BY_FW(DOT11AX) || value) && ie && + (ie->QCN_IE.present || ie->he_cap.twt_responder)) { + sme_debug("TWT is supported, hence disable UAPSD; twt_requestor: %d, twt respon supp: %d, QCN_IE: %d", + value, ie->he_cap.twt_responder, ie->QCN_IE.present); + return true; + } + + return false; +} + +/** + * The communication between HDD and LIM is thru mailbox (MB). + * Both sides will access the data structure "tSirSmeJoinReq". + * The rule is, while the components of "tSirSmeJoinReq" can be accessed in the + * regular way like tSirSmeJoinReq.assocType, this guideline stops at component + * tSirRSNie; + * any acces to the components after tSirRSNie is forbidden because the space + * from tSirRSNie is squeezed with the component "tSirBssDescription" and since + * the size of actual 'tSirBssDescription' varies, the receiving side should + * keep in mind not to access the components DIRECTLY after tSirRSNie. + */ +QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDescription, + struct csr_roam_profile *pProfile, + tDot11fBeaconIEs *pIes, uint16_t messageType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t acm_mask = 0, uapsd_mask; + uint16_t msgLen, ieLen; + tSirMacRateSet OpRateSet; + tSirMacRateSet ExRateSet; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t dwTmp, ucDot11Mode = 0; + uint8_t *wpaRsnIE = NULL; + uint8_t txBFCsnValue = 0; + tSirSmeJoinReq *csr_join_req; + tSirMacCapabilityInfo *pAP_capabilityInfo; + bool fTmp; + int8_t pwrLimit = 0; + struct ps_global_info *ps_global_info = &pMac->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[sessionId]; + uint8_t ese_config = 0; + tpCsrNeighborRoamControlInfo neigh_roam_info; + uint32_t value = 0, value1 = 0; + QDF_STATUS packetdump_timer_status; + bool is_vendor_ap_present; + struct vdev_type_nss *vdev_type_nss; + struct action_oui_search_attr vendor_ap_search_attr; + tDot11fIEVHTCaps *vht_caps = NULL; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + /* To satisfy klockworks */ + if (NULL == pBssDescription) { + sme_err(" pBssDescription is NULL"); + return QDF_STATUS_E_FAILURE; + } + neigh_roam_info = &pMac->roam.neighborRoamInfo[sessionId]; + if ((eWNI_SME_REASSOC_REQ == messageType) || + WLAN_REG_IS_5GHZ_CH(pBssDescription->channelId)) { + pSession->disable_hi_rssi = true; + sme_debug("Disabling HI_RSSI, AP channel=%d, rssi=%d", + pBssDescription->channelId, pBssDescription->rssi); + } else { + pSession->disable_hi_rssi = false; + } + + do { + pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS; + pSession->joinFailStatusCode.reasonCode = 0; + qdf_mem_copy(&pSession->joinFailStatusCode.bssId, + &pBssDescription->bssId, sizeof(tSirMacAddr)); + /* + * the tSirSmeJoinReq which includes a single + * bssDescription. it includes a single uint32_t for the + * IE fields, but the length field in the bssDescription + * needs to be interpreted to determine length of IE fields + * So, take the size of the tSirSmeJoinReq, subtract size of + * bssDescription, add the number of bytes indicated by the + * length field of the bssDescription, add the size of length + * field because it not included in the length field. + */ + msgLen = sizeof(tSirSmeJoinReq) - sizeof(*pBssDescription) + + pBssDescription->length + + sizeof(pBssDescription->length) + + /* + * add in the size of the WPA IE that + * we may build. + */ + sizeof(tCsrWpaIe) + sizeof(tCsrWpaAuthIe) + + sizeof(uint16_t); + csr_join_req = qdf_mem_malloc(msgLen); + if (NULL == csr_join_req) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + wpaRsnIE = qdf_mem_malloc(DOT11F_IE_RSN_MAX_LEN); + if (NULL == wpaRsnIE) + status = QDF_STATUS_E_NOMEM; + + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + csr_join_req->messageType = messageType; + csr_join_req->length = msgLen; + csr_join_req->sessionId = (uint8_t) sessionId; + csr_join_req->transactionId = 0; + if (pIes->SSID.present && + !csr_is_nullssid(pIes->SSID.ssid, + pIes->SSID.num_ssid)) { + csr_join_req->ssId.length = pIes->SSID.num_ssid; + qdf_mem_copy(&csr_join_req->ssId.ssId, pIes->SSID.ssid, + pIes->SSID.num_ssid); + } else if (pProfile->SSIDs.numOfSSIDs) { + csr_join_req->ssId.length = + pProfile->SSIDs.SSIDList[0].SSID.length; + qdf_mem_copy(&csr_join_req->ssId.ssId, + pProfile->SSIDs.SSIDList[0].SSID.ssId, + csr_join_req->ssId.length); + } else { + csr_join_req->ssId.length = 0; + } + qdf_mem_copy(&csr_join_req->selfMacAddr, &pSession->selfMacAddr, + sizeof(tSirMacAddr)); + sme_err("Connecting to ssid:%.*s bssid: "MAC_ADDRESS_STR" rssi: %d channel: %d country_code: %c%c", + csr_join_req->ssId.length, csr_join_req->ssId.ssId, + MAC_ADDR_ARRAY(pBssDescription->bssId), + pBssDescription->rssi, pBssDescription->channelId, + pMac->scan.countryCodeCurrent[0], + pMac->scan.countryCodeCurrent[1]); + /* bsstype */ + dwTmp = csr_translate_bsstype_to_mac_type + (pProfile->BSSType); + csr_join_req->bsstype = dwTmp; + /* dot11mode */ + ucDot11Mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pSession->bssParams. + uCfgDot11Mode); + if (pBssDescription->channelId <= 14 + && false == pMac->roam.configParam.enableVhtFor24GHz + && WNI_CFG_DOT11_MODE_11AC == ucDot11Mode) { + /* Need to disable VHT operation in 2.4 GHz band */ + ucDot11Mode = WNI_CFG_DOT11_MODE_11N; + } + + if (IS_5G_CH(pBssDescription->channelId)) + vdev_type_nss = &pMac->vdev_type_nss_5g; + else + vdev_type_nss = &pMac->vdev_type_nss_2g; + if (pSession->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE) + pSession->vdev_nss = vdev_type_nss->p2p_cli; + else + pSession->vdev_nss = vdev_type_nss->sta; + pSession->nss = pSession->vdev_nss; + + if (pSession->nss > csr_get_nss_supported_by_sta_and_ap( + &pIes->VHTCaps, + &pIes->HTCaps, ucDot11Mode)) { + pSession->nss = csr_get_nss_supported_by_sta_and_ap( + &pIes->VHTCaps, &pIes->HTCaps, + ucDot11Mode); + pSession->vdev_nss = pSession->nss; + } + + if (!pMac->roam.configParam.enable2x2) + pSession->nss = 1; + + if (pSession->nss == 1) + pSession->supported_nss_1x1 = true; + + ieLen = csr_get_ielen_from_bss_description(pBssDescription); + + /* Dump the Vendor Specific IEs*/ + csr_dump_vendor_ies((uint8_t *)&pBssDescription->ieFields[0], + ieLen); + + /* Fill the Vendor AP search params */ + vendor_ap_search_attr.ie_data = + (uint8_t *)&pBssDescription->ieFields[0]; + vendor_ap_search_attr.ie_length = ieLen; + vendor_ap_search_attr.mac_addr = &pBssDescription->bssId[0]; + vendor_ap_search_attr.nss = csr_get_nss_supported_by_sta_and_ap( + &pIes->VHTCaps, &pIes->HTCaps, + ucDot11Mode); + vendor_ap_search_attr.ht_cap = pIes->HTCaps.present; + vendor_ap_search_attr.vht_cap = pIes->VHTCaps.present; + vendor_ap_search_attr.enable_2g = + IS_24G_CH(pBssDescription->channelId); + vendor_ap_search_attr.enable_5g = + IS_5G_CH(pBssDescription->channelId); + + is_vendor_ap_present = + ucfg_action_oui_search(pMac->psoc, + &vendor_ap_search_attr, + ACTION_OUI_CONNECT_1X1); + + if (is_vendor_ap_present) { + is_vendor_ap_present = csr_check_vendor_ap_3_present( + pMac, + vendor_ap_search_attr.ie_data, + ieLen); + } + + /* + * 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 = + ucfg_action_oui_search(pMac->psoc, + &vendor_ap_search_attr, + ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN); + if (is_vendor_ap_present) + sme_debug("1x1 with 1 Chain AP"); + } + + if ((pMac->roam.configParam.is_force_1x1_enable == + FORCE_1X1_ENABLED_FORCED || + (pMac->roam.configParam.is_force_1x1_enable == + FORCE_1X1_ENABLED_FOR_AS && + pMac->lteCoexAntShare)) && is_vendor_ap_present) { + pSession->supported_nss_1x1 = true; + pSession->vdev_nss = 1; + pSession->nss = 1; + pSession->nss_forced_1x1 = true; + sme_debug("For special ap, NSS: %d force 1x1 %d", + pSession->nss, + pMac->roam.configParam.is_force_1x1_enable); + } + + /* + * If CCK WAR is set for current AP, update to firmware via + * WMI_VDEV_PARAM_ABG_MODE_TX_CHAIN_NUM + */ + is_vendor_ap_present = + ucfg_action_oui_search(pMac->psoc, + &vendor_ap_search_attr, + ACTION_OUI_CCKM_1X1); + if (is_vendor_ap_present) { + sme_debug("vdev: %d WMI_VDEV_PARAM_ABG_MODE_TX_CHAIN_NUM 1", + pSession->sessionId); + wma_cli_set_command( + pSession->sessionId, + (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 = + ucfg_action_oui_search(pMac->psoc, + &vendor_ap_search_attr, + ACTION_OUI_SWITCH_TO_11N_MODE); + if (pMac->roam.configParam.is_force_1x1_enable && + pMac->lteCoexAntShare && + is_vendor_ap_present && + (ucDot11Mode == WNI_CFG_DOT11_MODE_ALL || + ucDot11Mode == WNI_CFG_DOT11_MODE_11AC || + ucDot11Mode == WNI_CFG_DOT11_MODE_11AC_ONLY)) + ucDot11Mode = WNI_CFG_DOT11_MODE_11N; + + csr_join_req->supported_nss_1x1 = pSession->supported_nss_1x1; + csr_join_req->vdev_nss = pSession->vdev_nss; + csr_join_req->nss = pSession->nss; + csr_join_req->nss_forced_1x1 = pSession->nss_forced_1x1; + csr_join_req->dot11mode = (uint8_t) ucDot11Mode; + sme_debug("dot11mode=%d, uCfgDot11Mode=%d nss=%d", + csr_join_req->dot11mode, + pSession->bssParams.uCfgDot11Mode, + csr_join_req->nss); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + csr_join_req->cc_switch_mode = + pMac->roam.configParam.cc_switch_mode; +#endif + csr_join_req->staPersona = (uint8_t) pProfile->csrPersona; + csr_join_req->wps_registration = pProfile->bWPSAssociation; + csr_join_req->cbMode = (uint8_t) pSession->bssParams.cbMode; + csr_join_req->force_24ghz_in_ht20 = + pProfile->force_24ghz_in_ht20; + sme_debug("CSR PERSONA: %d CSR CbMode: %d force 24gh ht20 %d", + pProfile->csrPersona, pSession->bssParams.cbMode, + csr_join_req->force_24ghz_in_ht20); + pSession->uapsd_mask = pProfile->uapsd_mask; + status = + csr_get_rate_set(pMac, pProfile, + (eCsrPhyMode) pProfile->phyMode, + pBssDescription, pIes, &OpRateSet, + &ExRateSet); + if (!csr_enable_twt(pMac, pIes)) + ps_param->uapsd_per_ac_bit_mask = pProfile->uapsd_mask; + if (QDF_IS_STATUS_SUCCESS(status)) { + /* OperationalRateSet */ + if (OpRateSet.numRates) { + csr_join_req->operationalRateSet.numRates = + OpRateSet.numRates; + qdf_mem_copy(&csr_join_req->operationalRateSet. + rate, OpRateSet.rate, + OpRateSet.numRates); + } else + csr_join_req->operationalRateSet.numRates = 0; + + /* ExtendedRateSet */ + if (ExRateSet.numRates) { + csr_join_req->extendedRateSet.numRates = + ExRateSet.numRates; + qdf_mem_copy(&csr_join_req->extendedRateSet. + rate, ExRateSet.rate, + ExRateSet.numRates); + } else + csr_join_req->extendedRateSet.numRates = 0; + } else { + csr_join_req->operationalRateSet.numRates = 0; + csr_join_req->extendedRateSet.numRates = 0; + } + /* rsnIE */ + if (csr_is_profile_wpa(pProfile)) { + /* Insert the Wpa IE into the join request */ + ieLen = + csr_retrieve_wpa_ie(pMac, pProfile, + pBssDescription, pIes, + (tCsrWpaIe *) (wpaRsnIE)); + } else if (csr_is_profile_rsn(pProfile)) { + /* Insert the RSN IE into the join request */ + ieLen = + csr_retrieve_rsn_ie(pMac, sessionId, pProfile, + pBssDescription, pIes, + (tCsrRSNIe *) (wpaRsnIE)); + csr_join_req->force_rsne_override = + pProfile->force_rsne_override; + } +#ifdef FEATURE_WLAN_WAPI + else if (csr_is_profile_wapi(pProfile)) { + /* Insert the WAPI IE into the join request */ + ieLen = + csr_retrieve_wapi_ie(pMac, sessionId, pProfile, + pBssDescription, pIes, + (tCsrWapiIe *) (wpaRsnIE)); + } +#endif /* FEATURE_WLAN_WAPI */ + else + ieLen = 0; + /* remember the IE for future use */ + if (ieLen) { + if (ieLen > DOT11F_IE_RSN_MAX_LEN) { + sme_err("WPA RSN IE length :%d is more than DOT11F_IE_RSN_MAX_LEN, resetting to %d", + ieLen, DOT11F_IE_RSN_MAX_LEN); + ieLen = DOT11F_IE_RSN_MAX_LEN; + } +#ifdef FEATURE_WLAN_WAPI + if (csr_is_profile_wapi(pProfile)) { + /* Check whether we need to allocate more mem */ + if (ieLen > pSession->nWapiReqIeLength) { + if (pSession->pWapiReqIE + && pSession->nWapiReqIeLength) { + qdf_mem_free(pSession-> + pWapiReqIE); + } + pSession->pWapiReqIE = + qdf_mem_malloc(ieLen); + if (NULL == pSession->pWapiReqIE) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nWapiReqIeLength = ieLen; + qdf_mem_copy(pSession->pWapiReqIE, wpaRsnIE, + ieLen); + csr_join_req->rsnIE.length = ieLen; + qdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata, + wpaRsnIE, ieLen); + } else /* should be WPA/WPA2 otherwise */ +#endif /* FEATURE_WLAN_WAPI */ + { + /* Check whether we need to allocate more mem */ + if (ieLen > pSession->nWpaRsnReqIeLength) { + if (pSession->pWpaRsnReqIE + && pSession->nWpaRsnReqIeLength) { + qdf_mem_free(pSession-> + pWpaRsnReqIE); + } + pSession->pWpaRsnReqIE = + qdf_mem_malloc(ieLen); + if (NULL == pSession->pWpaRsnReqIE) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nWpaRsnReqIeLength = ieLen; + qdf_mem_copy(pSession->pWpaRsnReqIE, wpaRsnIE, + ieLen); + csr_join_req->rsnIE.length = ieLen; + qdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata, + wpaRsnIE, ieLen); + } + } else { + /* free whatever old info */ + pSession->nWpaRsnReqIeLength = 0; + if (pSession->pWpaRsnReqIE) { + qdf_mem_free(pSession->pWpaRsnReqIE); + pSession->pWpaRsnReqIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + pSession->nWapiReqIeLength = 0; + if (pSession->pWapiReqIE) { + qdf_mem_free(pSession->pWapiReqIE); + pSession->pWapiReqIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ + csr_join_req->rsnIE.length = 0; + } +#ifdef FEATURE_WLAN_ESE + if (eWNI_SME_JOIN_REQ == messageType) + csr_join_req->cckmIE.length = 0; + else if (eWNI_SME_REASSOC_REQ == messageType) { + /* cckmIE */ + if (csr_is_profile_ese(pProfile)) { + /* Insert the CCKM IE into the join request */ + ieLen = pSession->suppCckmIeInfo.cckmIeLen; + qdf_mem_copy((void *)(wpaRsnIE), + pSession->suppCckmIeInfo.cckmIe, + ieLen); + } else + ieLen = 0; + /* + * If present, copy the IE into the + * eWNI_SME_REASSOC_REQ message buffer + */ + if (ieLen) { + /* + * Copy the CCKM IE over from the temp + * buffer (wpaRsnIE) + */ + csr_join_req->cckmIE.length = ieLen; + qdf_mem_copy(&csr_join_req->cckmIE.cckmIEdata, + wpaRsnIE, ieLen); + } else + csr_join_req->cckmIE.length = 0; + } +#endif /* FEATURE_WLAN_ESE */ + /* addIEScan */ + if (pProfile->nAddIEScanLength && pProfile->pAddIEScan) { + ieLen = pProfile->nAddIEScanLength; + if (ieLen > pSession->nAddIEScanLength) { + if (pSession->pAddIEScan + && pSession->nAddIEScanLength) { + qdf_mem_free(pSession->pAddIEScan); + } + pSession->pAddIEScan = qdf_mem_malloc(ieLen); + if (NULL == pSession->pAddIEScan) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nAddIEScanLength = ieLen; + qdf_mem_copy(pSession->pAddIEScan, pProfile->pAddIEScan, + ieLen); + csr_join_req->addIEScan.length = ieLen; + qdf_mem_copy(&csr_join_req->addIEScan.addIEdata, + pProfile->pAddIEScan, ieLen); + } else { + pSession->nAddIEScanLength = 0; + if (pSession->pAddIEScan) { + qdf_mem_free(pSession->pAddIEScan); + pSession->pAddIEScan = NULL; + } + csr_join_req->addIEScan.length = 0; + } + /* addIEAssoc */ + if (pProfile->nAddIEAssocLength && pProfile->pAddIEAssoc) { + ieLen = pProfile->nAddIEAssocLength; + if (ieLen > pSession->nAddIEAssocLength) { + if (pSession->pAddIEAssoc + && pSession->nAddIEAssocLength) { + qdf_mem_free(pSession->pAddIEAssoc); + } + pSession->pAddIEAssoc = qdf_mem_malloc(ieLen); + if (NULL == pSession->pAddIEAssoc) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nAddIEAssocLength = ieLen; + qdf_mem_copy(pSession->pAddIEAssoc, + pProfile->pAddIEAssoc, ieLen); + csr_join_req->addIEAssoc.length = ieLen; + qdf_mem_copy(&csr_join_req->addIEAssoc.addIEdata, + pProfile->pAddIEAssoc, ieLen); + } else { + pSession->nAddIEAssocLength = 0; + if (pSession->pAddIEAssoc) { + qdf_mem_free(pSession->pAddIEAssoc); + pSession->pAddIEAssoc = NULL; + } + csr_join_req->addIEAssoc.length = 0; + } + + if (eWNI_SME_REASSOC_REQ == messageType) { + /* Unmask any AC in reassoc that is ACM-set */ + uapsd_mask = (uint8_t) pProfile->uapsd_mask; + if (uapsd_mask && (NULL != pBssDescription)) { + if (CSR_IS_QOS_BSS(pIes) + && CSR_IS_UAPSD_BSS(pIes)) +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = + sme_qos_get_acm_mask(pMac, + pBssDescription, + pIes); +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + else + uapsd_mask = 0; + } + } + + if (!CSR_IS_11n_ALLOWED(pProfile->negotiatedUCEncryptionType)) + csr_join_req->he_with_wep_tkip = + pMac->roam.configParam.wep_tkip_in_he; + + csr_join_req->UCEncryptionType = + csr_translate_encrypt_type_to_ed_type + (pProfile->negotiatedUCEncryptionType); + + csr_join_req->MCEncryptionType = + csr_translate_encrypt_type_to_ed_type + (pProfile->negotiatedMCEncryptionType); + csr_set_mgmt_enc_type(pProfile, pIes, csr_join_req); +#ifdef FEATURE_WLAN_ESE + ese_config = pMac->roam.configParam.isEseIniFeatureEnabled; +#endif + pProfile->MDID.mdiePresent = pBssDescription->mdiePresent; + if (csr_is_profile11r(pMac, pProfile) +#ifdef FEATURE_WLAN_ESE + && + !((pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM) && (pIes->ESEVersion.present) + && (ese_config)) +#endif + ) + csr_join_req->is11Rconnection = true; + else + csr_join_req->is11Rconnection = false; +#ifdef FEATURE_WLAN_ESE + if (true == ese_config) + csr_join_req->isESEFeatureIniEnabled = true; + else + csr_join_req->isESEFeatureIniEnabled = false; + + /* 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. + */ + if ((csr_is_profile_ese(pProfile) || + ((pIes->ESEVersion.present) && + (pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM))) + && (ese_config)) + csr_join_req->isESEconnection = true; + else + csr_join_req->isESEconnection = false; + + if (eWNI_SME_JOIN_REQ == messageType) { + tESETspecInfo eseTspec; + /* + * ESE-Tspec IEs in the ASSOC request is presently not + * supported. so nullify the TSPEC parameters + */ + qdf_mem_zero(&eseTspec, sizeof(tESETspecInfo)); + qdf_mem_copy(&csr_join_req->eseTspecInfo, + &eseTspec, sizeof(tESETspecInfo)); + } else if (eWNI_SME_REASSOC_REQ == messageType) { + if ((csr_is_profile_ese(pProfile) || + ((pIes->ESEVersion.present) + && (pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM))) && + (ese_config)) { + tESETspecInfo eseTspec; + + qdf_mem_zero(&eseTspec, sizeof(tESETspecInfo)); + eseTspec.numTspecs = + sme_qos_ese_retrieve_tspec_info(pMac, + sessionId, + (tTspecInfo *) &eseTspec. + tspec[0]); + csr_join_req->eseTspecInfo.numTspecs = + eseTspec.numTspecs; + if (eseTspec.numTspecs) { + qdf_mem_copy(&csr_join_req->eseTspecInfo + .tspec[0], + &eseTspec.tspec[0], + (eseTspec.numTspecs * + sizeof(tTspecInfo))); + } + } else { + tESETspecInfo eseTspec; + /* + * ESE-Tspec IEs in the ASSOC request is + * presently not supported. so nullify the TSPEC + * parameters + */ + qdf_mem_zero(&eseTspec, sizeof(tESETspecInfo)); + qdf_mem_copy(&csr_join_req->eseTspecInfo, + &eseTspec, + sizeof(tESETspecInfo)); + } + } +#endif /* FEATURE_WLAN_ESE */ + if (ese_config + || csr_roam_is_fast_roam_enabled(pMac, sessionId)) + csr_join_req->isFastTransitionEnabled = true; + else + csr_join_req->isFastTransitionEnabled = false; + + if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) + csr_join_req->isFastRoamIniFeatureEnabled = true; + else + csr_join_req->isFastRoamIniFeatureEnabled = false; + + csr_join_req->txLdpcIniFeatureEnabled = + (uint8_t) pMac->roam.configParam.tx_ldpc_enable; + + if ((csr_is11h_supported(pMac)) && + (WLAN_REG_IS_5GHZ_CH(pBssDescription->channelId)) && + (pIes->Country.present) && + (!pMac->roam.configParam. + fSupplicantCountryCodeHasPriority)) { + csr_save_to_channel_power2_g_5_g(pMac, + pIes->Country.num_triplets * + sizeof(tSirMacChanInfo), + (tSirMacChanInfo *) + (&pIes->Country.triplets[0])); + csr_apply_power2_current(pMac); + } + /* + * If RX LDPC has been disabled for 2.4GHz channels and enabled + * for 5Ghz for STA like persona then here is how to handle + * those cases (by now channel has been decided). + */ + if (eSIR_INFRASTRUCTURE_MODE == csr_join_req->bsstype || + !policy_mgr_is_dbs_enable(pMac->psoc)) + csr_set_ldpc_exception(pMac, pSession, + pBssDescription->channelId, + pMac->roam.configParam.rx_ldpc_enable); + qdf_mem_copy(&csr_join_req->htConfig, + &pSession->htConfig, sizeof(tSirHTConfig)); + qdf_mem_copy(&csr_join_req->vht_config, &pSession->vht_config, + sizeof(pSession->vht_config)); + sme_debug("ht capability 0x%x VHT capability 0x%x", + (unsigned int)(*(uint32_t *) &csr_join_req->htConfig), + (unsigned int)(*(uint32_t *) &csr_join_req-> + vht_config)); + + if (IS_DOT11_MODE_HE(csr_join_req->dot11mode)) + csr_join_req_copy_he_cap(csr_join_req, pSession); + + if (wlan_cfg_get_int(pMac, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + &value) != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + ("Failed to get SU beamformee capability")); + if (wlan_cfg_get_int(pMac, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + &value1) != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + ("Failed to get CSN beamformee capability")); + + csr_join_req->vht_config.su_beam_formee = value; + + if (pIes->VHTCaps.present) + vht_caps = &pIes->VHTCaps; + else if (pIes->vendor_vht_ie.VHTCaps.present) + vht_caps = &pIes->vendor_vht_ie.VHTCaps; + /* Set BF CSN value only if SU Bformee is enabled */ + if (vht_caps && csr_join_req->vht_config.su_beam_formee) { + txBFCsnValue = (uint8_t)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 (pIes->Vendor1IE.present && + vht_caps->csnofBeamformerAntSup < 4) { + if (vht_caps->csnofBeamformerAntSup) + txBFCsnValue = QDF_MIN(txBFCsnValue, + vht_caps->csnofBeamformerAntSup); + } + } + csr_join_req->vht_config.csnof_beamformer_antSup = txBFCsnValue; + + if (wlan_cfg_get_int(pMac, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, &value) + != QDF_STATUS_SUCCESS) + sme_err("Failed to get SU beamformer capability"); + + /* + * Set SU Bformer only if SU Bformer is enabled in INI + * and AP is SU Bformee capable + */ + if (value && !((IS_BSS_VHT_CAPABLE(pIes->VHTCaps) && + pIes->VHTCaps.suBeamformeeCap) || + (IS_BSS_VHT_CAPABLE( + pIes->vendor_vht_ie.VHTCaps) + && pIes->vendor_vht_ie.VHTCaps. + suBeamformeeCap))) + value = 0; + + csr_join_req->vht_config.su_beam_former = value; + + /* Set num soundingdim value to 0 if SU Bformer is disabled */ + if (!csr_join_req->vht_config.su_beam_former) + csr_join_req->vht_config.num_soundingdim = 0; + + if (wlan_cfg_get_int(pMac, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &value) + != QDF_STATUS_SUCCESS) + sme_err("Failed to get CSN beamformee capability"); + /* + * Set MU Bformee only if SU Bformee is enabled and + * MU Bformee is enabled in INI + */ + if (value && csr_join_req->vht_config.su_beam_formee && + pIes->VHTCaps.muBeamformerCap) + csr_join_req->vht_config.mu_beam_formee = 1; + else + csr_join_req->vht_config.mu_beam_formee = 0; + + csr_join_req->enableVhtpAid = + (uint8_t) pMac->roam.configParam.enableVhtpAid; + + csr_join_req->enableVhtGid = + (uint8_t) pMac->roam.configParam.enableVhtGid; + + csr_join_req->enableAmpduPs = + (uint8_t) pMac->roam.configParam.enableAmpduPs; + + csr_join_req->enableHtSmps = + (uint8_t) pMac->roam.configParam.enableHtSmps; + + csr_join_req->htSmps = (uint8_t) pMac->roam.configParam.htSmps; + csr_join_req->send_smps_action = + pMac->roam.configParam.send_smps_action; + + csr_join_req->max_amsdu_num = + (uint8_t) pMac->roam.configParam.max_amsdu_num; + + if (pMac->roam.roamSession[sessionId].fWMMConnection) + csr_join_req->isWMEenabled = true; + else + csr_join_req->isWMEenabled = false; + + if (pMac->roam.roamSession[sessionId].fQOSConnection) + csr_join_req->isQosEnabled = true; + else + csr_join_req->isQosEnabled = false; + + if (pProfile->bOSENAssociation) + csr_join_req->isOSENConnection = true; + else + csr_join_req->isOSENConnection = false; + + /* Fill rrm config parameters */ + qdf_mem_copy(&csr_join_req->rrm_config, + &pMac->rrm.rrmSmeContext.rrmConfig, + sizeof(struct rrm_config_param)); + + pAP_capabilityInfo = + (tSirMacCapabilityInfo *) + &pBssDescription->capabilityInfo; + /* + * tell the target AP my 11H capability only if both AP and STA + * support + * 11H and the channel being used is 11a + */ + if (csr_is11h_supported(pMac) && pAP_capabilityInfo->spectrumMgt + && eSIR_11A_NW_TYPE == pBssDescription->nwType) { + fTmp = true; + } else + fTmp = false; + + csr_join_req->spectrumMgtIndicator = fTmp; + csr_join_req->powerCap.minTxPower = MIN_TX_PWR_CAP; + /* + * 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. + */ + pwrLimit = csr_get_cfg_max_tx_power(pMac, + pBssDescription->channelId); + if (0 != pwrLimit && pwrLimit < MAX_TX_PWR_CAP) + csr_join_req->powerCap.maxTxPower = pwrLimit; + else + csr_join_req->powerCap.maxTxPower = MAX_TX_PWR_CAP; + + csr_add_supported_5Ghz_channels(pMac, + csr_join_req->supportedChannels.channelList, + &csr_join_req->supportedChannels.numChnl, + false); + /* Enable UAPSD only if TWT is not supported */ + if (!csr_enable_twt(pMac, pIes)) + csr_join_req->uapsdPerAcBitmask = pProfile->uapsd_mask; + /* Move the entire BssDescription into the join request. */ + qdf_mem_copy(&csr_join_req->bssDescription, pBssDescription, + pBssDescription->length + + sizeof(pBssDescription->length)); + csr_update_fils_connection_info(pProfile, csr_join_req); + csr_update_sae_config(csr_join_req, pMac, pSession); + /* + * conc_custom_rule1: + * If SAP comes up first and STA comes up later then SAP + * need to follow STA's channel in 2.4Ghz. In following if + * condition we are adding sanity check, just to make sure that + * if this rule is enabled then don't allow STA to connect on + * 5gz channel and also by this time SAP's channel should be the + * same as STA's channel. + */ + if (pMac->roam.configParam.conc_custom_rule1) { + if ((0 == pMac->roam.configParam. + is_sta_connection_in_5gz_enabled) && + WLAN_REG_IS_5GHZ_CH(pBssDescription-> + channelId)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "STA-conn on 5G isn't allowed"); + status = QDF_STATUS_E_FAILURE; + break; + } + if (!WLAN_REG_IS_5GHZ_CH(pBssDescription->channelId) && + (false == csr_is_conn_allow_2g_band(pMac, + pBssDescription->channelId))) { + status = QDF_STATUS_E_FAILURE; + break; + } + } + + /* + * conc_custom_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. + */ + if (pMac->roam.configParam.conc_custom_rule2 && + !WLAN_REG_IS_24GHZ_CH(pBssDescription->channelId) && + (!csr_is_conn_allow_5g_band(pMac, + pBssDescription->channelId))) { + status = QDF_STATUS_E_FAILURE; + break; + } + + if (pSession->pCurRoamProfile->csrPersona == QDF_STA_MODE) + csr_join_req->enable_bcast_probe_rsp = + pMac->roam.configParam.enable_bcast_probe_rsp; + + csr_join_req->enable_session_twt_support = csr_enable_twt(pMac, + pIes); + status = umac_send_mb_message_to_mac(csr_join_req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* + * umac_send_mb_message_to_mac would've released the mem + * allocated by csr_join_req. Let's make it defensive by + * assigning NULL to the pointer. + */ + csr_join_req = NULL; + break; + } + + if (pProfile->csrPersona == QDF_STA_MODE) { + sme_debug("Invoking packetdump register API"); + wlan_register_txrx_packetdump(); + packetdump_timer_status = qdf_mc_timer_start( + &pMac->roam.packetdump_timer, + (PKT_DUMP_TIMER_DURATION * + QDF_MC_TIMER_TO_SEC_UNIT)/ + QDF_MC_TIMER_TO_MS_UNIT); + if (!QDF_IS_STATUS_SUCCESS(packetdump_timer_status)) + sme_err("cannot start packetdump timer status: %d", + packetdump_timer_status); + } +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + if (eWNI_SME_JOIN_REQ == messageType) { + /* Notify QoS module that join happening */ + pSession->join_bssid_count++; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "BSSID Count: %d", pSession->join_bssid_count); + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_JOIN_REQ, NULL); + } else if (eWNI_SME_REASSOC_REQ == messageType) + /* Notify QoS module that reassoc happening */ + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_REASSOC_REQ, + NULL); +#endif + } while (0); + + /* Clean up the memory in case of any failure */ + if (!QDF_IS_STATUS_SUCCESS(status) && (NULL != csr_join_req)) + qdf_mem_free(csr_join_req); + + if (wpaRsnIE) + qdf_mem_free(wpaRsnIE); + + return status; +} + +/* */ +QDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode) +{ + tSirSmeDisassocReq *pMsg; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + return QDF_STATUS_E_FAILURE; + + pMsg = qdf_mem_malloc(sizeof(tSirSmeDisassocReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_DISASSOC_REQ; + pMsg->length = sizeof(tSirSmeDisassocReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + if ((pSession->pCurRoamProfile != NULL) + && (CSR_IS_INFRA_AP(pSession->pCurRoamProfile))) { + qdf_mem_copy(&pMsg->bssid.bytes, + &pSession->selfMacAddr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&pMsg->peer_macaddr.bytes, + bssId, + QDF_MAC_ADDR_SIZE); + } else { + qdf_mem_copy(&pMsg->bssid.bytes, + bssId, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&pMsg->peer_macaddr.bytes, + bssId, QDF_MAC_ADDR_SIZE); + } + pMsg->reasonCode = reasonCode; + pMsg->process_ho_fail = (pSession->disconnect_reason == + eCSR_DISCONNECT_REASON_ROAM_HO_FAIL) ? true : false; + + /* Update the disconnect stats */ + pSession->disconnect_stats.disconnection_cnt++; + pSession->disconnect_stats.disconnection_by_app++; + + /* + * The state will be DISASSOC_HANDOFF only when we are doing + * handoff. Here we should not send the disassoc over the air + * to the AP + */ + if ((CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) + && csr_roam_is11r_assoc(pMac, sessionId)) || + pMsg->process_ho_fail) { + /* Set DoNotSendOverTheAir flag to 1 only for handoff case */ + pMsg->doNotSendOverTheAir = CSR_DONT_SEND_DISASSOC_OVER_THE_AIR; + } + return umac_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS +csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + QDF_MODULE_ID modId, + struct qdf_mac_addr bssid, + void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeGetAssocSTAsReq *pMsg; + + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_GET_ASSOC_STAS_REQ; + qdf_copy_macaddr(&pMsg->bssid, &bssid); + pMsg->modId = modId; + qdf_mem_copy(pMsg->pUsrContext, pUsrContext, sizeof(void *)); + qdf_mem_copy(pMsg->pSapEventCallback, + pfnSapEventCallback, sizeof(void *)); + qdf_mem_copy(pMsg->pAssocStasArray, pAssocStasBuf, sizeof(void *)); + pMsg->length = sizeof(*pMsg); + status = umac_send_mb_message_to_mac(pMsg); + + return status; +} + +QDF_STATUS csr_send_chng_mcc_beacon_interval(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + tpSirChangeBIParams pMsg; + uint16_t len = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, 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 (!pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval) + return QDF_STATUS_SUCCESS; + + pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval = + false; + + /* Create the message and send to lim */ + len = sizeof(tSirChangeBIParams); + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg->messageType = eWNI_SME_CHNG_MCC_BEACON_INTERVAL; + pMsg->length = len; + + qdf_copy_macaddr(&pMsg->bssid, &pSession->selfMacAddr); + sme_debug( + "CSR Attempting to change BI for Bssid= " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pMsg->bssid.bytes)); + pMsg->sessionId = sessionId; + sme_debug("session %d BeaconInterval %d", + sessionId, + pMac->roam.roamSession[sessionId].bssParams. + beaconInterval); + pMsg->beaconInterval = + pMac->roam.roamSession[sessionId].bssParams.beaconInterval; + status = umac_send_mb_message_to_mac(pMsg); + } + return status; +} + +#ifdef QCA_HT_2040_COEX +QDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled) +{ + tpSirSetHT2040Mode pMsg; + uint16_t len = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* Create the message and send to lim */ + len = sizeof(tSirSetHT2040Mode); + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_zero(pMsg, sizeof(tSirSetHT2040Mode)); + pMsg->messageType = eWNI_SME_SET_HT_2040_MODE; + pMsg->length = len; + + qdf_copy_macaddr(&pMsg->bssid, &pSession->selfMacAddr); + sme_debug( + "CSR Attempting to set HT20/40 mode for Bssid= " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(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(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode) +{ + tSirSmeDeauthReq *pMsg; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + return QDF_STATUS_E_FAILURE; + + pMsg = qdf_mem_malloc(sizeof(tSirSmeDeauthReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + qdf_mem_zero(pMsg, sizeof(tSirSmeDeauthReq)); + pMsg->messageType = eWNI_SME_DEAUTH_REQ; + pMsg->length = sizeof(tSirSmeDeauthReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + + if ((pSession->pCurRoamProfile != NULL) + && (CSR_IS_INFRA_AP(pSession->pCurRoamProfile))) { + qdf_mem_copy(&pMsg->bssid, + &pSession->selfMacAddr, + QDF_MAC_ADDR_SIZE); + } else { + qdf_mem_copy(&pMsg->bssid, + bssId, QDF_MAC_ADDR_SIZE); + } + + /* 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(tpAniSirGlobal pMac, + tpSirSmeDisassocInd pDisassocInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeDisassocCnf *pMsg; + + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeDisassocCnf)); + if (NULL == 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->statusCode = eSIR_SME_SUCCESS; + pMsg->length = sizeof(tSirSmeDisassocCnf); + pMsg->sme_session_id = pDisassocInd->sessionId; + 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(tpAniSirGlobal pMac, + tpSirSmeDeauthInd pDeauthInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeDeauthCnf *pMsg; + + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeDeauthCnf)); + if (NULL == 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->statusCode = eSIR_SME_SUCCESS; + pMsg->length = sizeof(tSirSmeDeauthCnf); + pMsg->sme_session_id = pDeauthInd->sessionId; + 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(tpAniSirGlobal pMac, tpSirSmeAssocInd + pAssocInd, QDF_STATUS Halstatus) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeAssocCnf *pMsg; + struct scheduler_msg msg = { 0 }; + + sme_debug("Posting eWNI_SME_ASSOC_CNF to LIM.HalStatus: %d", Halstatus); + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeAssocCnf)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_ASSOC_CNF; + pMsg->length = sizeof(tSirSmeAssocCnf); + if (QDF_IS_STATUS_SUCCESS(Halstatus)) + pMsg->statusCode = eSIR_SME_SUCCESS; + else + pMsg->statusCode = eSIR_SME_ASSOC_REFUSED; + /* 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; + /* alternateBssId */ + qdf_mem_copy(pMsg->alternate_bssid.bytes, pAssocInd->bssId, + QDF_MAC_ADDR_SIZE); + /* alternateChannelId */ + pMsg->alternateChannelId = 11; + + 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; +} + +QDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeAssocInd pAssocInd, + QDF_STATUS Halstatus, + uint8_t sessionId) +{ + struct scheduler_msg msgQ = {0}; + tSirSmeAssocIndToUpperLayerCnf *pMsg; + uint8_t *pBuf; + tSirResultCodes statusCode; + uint16_t wTmp; + + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeAssocIndToUpperLayerCnf)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + pMsg->length = sizeof(tSirSmeAssocIndToUpperLayerCnf); + + pMsg->sessionId = sessionId; + + pBuf = (uint8_t *) &pMsg->statusCode; + if (QDF_IS_STATUS_SUCCESS(Halstatus)) + statusCode = eSIR_SME_SUCCESS; + else + statusCode = eSIR_SME_ASSOC_REFUSED; + qdf_mem_copy(pBuf, &statusCode, sizeof(tSirResultCodes)); + /* bssId */ + pBuf = (uint8_t *)&pMsg->bssId; + qdf_mem_copy((tSirMacAddr *)pBuf, pAssocInd->bssId, + sizeof(tSirMacAddr)); + /* peerMacAddr */ + pBuf = (uint8_t *)&pMsg->peerMacAddr; + qdf_mem_copy((tSirMacAddr *)pBuf, pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + /* StaId */ + pBuf = (uint8_t *)&pMsg->aid; + wTmp = pAssocInd->staId; + qdf_mem_copy(pBuf, &wTmp, sizeof(uint16_t)); + /* alternateBssId */ + pBuf = (uint8_t *)&pMsg->alternateBssId; + qdf_mem_copy((tSirMacAddr *)pBuf, pAssocInd->bssId, + sizeof(tSirMacAddr)); + /* alternateChannelId */ + pBuf = (uint8_t *)&pMsg->alternateChannelId; + *pBuf = 11; + /* + * Instead of copying roam Info,just copy WmmEnabled, + * RsnIE information. + * Wmm + */ + pBuf = (uint8_t *)&pMsg->wmmEnabledSta; + *pBuf = pAssocInd->wmmEnabledSta; + /* RSN IE */ + pBuf = (uint8_t *)&pMsg->rsnIE; + qdf_mem_copy((tSirRSNie *)pBuf, &pAssocInd->rsnIE, + sizeof(tSirRSNie)); +#ifdef FEATURE_WLAN_WAPI + /* WAPI IE */ + pBuf = (uint8_t *)&pMsg->wapiIE; + qdf_mem_copy((tSirWAPIie *)pBuf, &pAssocInd->wapiIE, + sizeof(tSirWAPIie)); +#endif + /* Additional IE */ + pBuf = (uint8_t *)&pMsg->addIE; + qdf_mem_copy((tSirAddie *)pBuf, &pAssocInd->addIE, + sizeof(tSirAddie)); + /* reassocReq */ + pBuf = (uint8_t *)&pMsg->reassocReq; + *pBuf = pAssocInd->reassocReq; + /* timingMeasCap */ + pBuf = (uint8_t *)&pMsg->timingMeasCap; + *pBuf = pAssocInd->timingMeasCap; + /* chan_info */ + pBuf = (uint8_t *)&pMsg->chan_info; + qdf_mem_copy((void *)pBuf, &pAssocInd->chan_info, + sizeof(tSirSmeChanInfo)); + /* ampdu */ + pBuf = (uint8_t *)&pMsg->ampdu; + *((bool *)pBuf) = pAssocInd->ampdu; + /* sgi_enable */ + pBuf = (uint8_t *)&pMsg->sgi_enable; + *((bool *)pBuf) = pAssocInd->sgi_enable; + /* tx stbc */ + pBuf = (uint8_t *)&pMsg->tx_stbc; + *((bool *)pBuf) = pAssocInd->tx_stbc; + /* ch_width */ + pBuf = (uint8_t *)&pMsg->ch_width; + *((tSirMacHTChannelWidth *)pBuf) = pAssocInd->ch_width; + /* mode */ + pBuf = (uint8_t *)&pMsg->mode; + *((enum sir_sme_phy_mode *)pBuf) = pAssocInd->mode; + /* rx stbc */ + pBuf = (uint8_t *)&pMsg->rx_stbc; + *((bool *)pBuf) = pAssocInd->rx_stbc; + /* max supported idx */ + pBuf = (uint8_t *)&pMsg->max_supp_idx; + *pBuf = pAssocInd->max_supp_idx; + /* max extended idx */ + pBuf = (uint8_t *)&pMsg->max_ext_idx; + *pBuf = pAssocInd->max_ext_idx; + /* max ht mcs idx */ + pBuf = (uint8_t *)&pMsg->max_mcs_idx; + *pBuf = pAssocInd->max_mcs_idx; + /* vht rx mcs map */ + pBuf = (uint8_t *)&pMsg->rx_mcs_map; + *pBuf = pAssocInd->rx_mcs_map; + /* vht tx mcs map */ + pBuf = (uint8_t *)&pMsg->tx_mcs_map; + *pBuf = pAssocInd->tx_mcs_map; + + pBuf = (uint8_t *)&pMsg->ecsa_capable; + *pBuf = pAssocInd->ecsa_capable; + + if (pAssocInd->HTCaps.present) + pMsg->ht_caps = pAssocInd->HTCaps; + if (pAssocInd->VHTCaps.present) + pMsg->vht_caps = pAssocInd->VHTCaps; + pMsg->capability_info = pAssocInd->capability_info; + pMsg->he_caps_present = pAssocInd->he_caps_present; + msgQ.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + msgQ.bodyptr = pMsg; + msgQ.bodyval = 0; + sys_process_mmh_msg(pMac, &msgQ); + } while (0); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr peer_macaddr, + uint8_t numKeys, + tAniEdType edType, bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint8_t keyLength, + uint8_t *pKey, uint8_t paeRole, + uint8_t *pKeyRsc) +{ + tSirSmeSetContextReq *pMsg; + struct scheduler_msg msg = {0}; + uint16_t msgLen; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + sme_debug("keylength: %d Encry type: %d", keyLength, edType); + do { + if ((1 != numKeys) && (0 != numKeys)) + break; + /* + * All of these fields appear in every SET_CONTEXT message. + * Below we'll add in the size for each key set. Since we only + * support up to one key, we always allocate memory for 1 key. + */ + msgLen = sizeof(struct sSirSmeSetContextReq); + + pMsg = qdf_mem_malloc(msgLen); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_SETCONTEXT_REQ; + pMsg->length = msgLen; + pMsg->sessionId = (uint8_t) sessionId; + pMsg->transactionId = 0; + qdf_copy_macaddr(&pMsg->peer_macaddr, &peer_macaddr); + qdf_copy_macaddr(&pMsg->bssid, + &pSession->connectedProfile.bssid); + + /** + * Set the pMsg->keyMaterial.length field + * (this length is defined as all data that follows the + * edType field in the tSirKeyMaterial keyMaterial; field). + * + * NOTE: This keyMaterial.length contains the length of a + * MAX size key, though the keyLength can be shorter than this + * max size. Is LIM interpreting this ok ? + */ + pMsg->keyMaterial.length = + sizeof(pMsg->keyMaterial.numKeys) + + (numKeys * sizeof(pMsg->keyMaterial.key)); + pMsg->keyMaterial.edType = edType; + pMsg->keyMaterial.numKeys = numKeys; + pMsg->keyMaterial.key[0].keyId = keyId; + pMsg->keyMaterial.key[0].unicast = fUnicast; + pMsg->keyMaterial.key[0].keyDirection = aniKeyDirection; + qdf_mem_copy(pMsg->keyMaterial.key[0].keyRsc, + pKeyRsc, CSR_MAX_RSC_LEN); + /* 0 is Supplicant */ + pMsg->keyMaterial.key[0].paeRole = paeRole; + pMsg->keyMaterial.key[0].keyLength = keyLength; + if (keyLength && pKey) + qdf_mem_copy(pMsg->keyMaterial.key[0].key, + pKey, keyLength); + + msg.type = eWNI_SME_SETCONTEXT_REQ; + msg.bodyptr = pMsg; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_zero(pMsg, msgLen); + qdf_mem_free(pMsg); + } + } while (0); + return status; +} + +QDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, uint32_t + sessionId, eCsrRoamBssType bssType, + struct csr_roamstart_bssparams *pParam, + tSirBssDescription *pBssDesc) +{ + tSirSmeStartBssReq *pMsg; + uint16_t wTmp; + uint32_t value = 0; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS; + pSession->joinFailStatusCode.reasonCode = 0; + pMsg = qdf_mem_malloc(sizeof(tSirSmeStartBssReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_START_BSS_REQ; + pMsg->sessionId = sessionId; + pMsg->length = sizeof(tSirSmeStartBssReq); + pMsg->transactionId = 0; + qdf_copy_macaddr(&pMsg->bssid, &pParam->bssid); + /* selfMacAddr */ + qdf_copy_macaddr(&pMsg->self_macaddr, &pSession->selfMacAddr); + /* beaconInterval */ + if (pBssDesc && pBssDesc->beaconInterval) + wTmp = pBssDesc->beaconInterval; + else if (pParam->beaconInterval) + wTmp = pParam->beaconInterval; + else + wTmp = WNI_CFG_BEACON_INTERVAL_STADEF; + + csr_validate_mcc_beacon_interval(pMac, pParam->operationChn, + &wTmp, sessionId, pParam->bssPersona); + /* Update the beacon Interval */ + pParam->beaconInterval = wTmp; + pMsg->beaconInterval = wTmp; + pMsg->dot11mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pParam->uCfgDot11Mode); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pMsg->cc_switch_mode = pMac->roam.configParam.cc_switch_mode; +#endif + pMsg->bssType = csr_translate_bsstype_to_mac_type(bssType); + qdf_mem_copy(&pMsg->ssId, &pParam->ssId, sizeof(pParam->ssId)); + pMsg->channelId = pParam->operationChn; + /* What should we really do for the cbmode. */ + pMsg->cbMode = (ePhyChanBondState) pParam->cbMode; + pMsg->vht_channel_width = pParam->ch_params.ch_width; + pMsg->center_freq_seg0 = pParam->ch_params.center_freq_seg0; + pMsg->center_freq_seg1 = pParam->ch_params.center_freq_seg1; + pMsg->sec_ch_offset = pParam->ch_params.sec_ch_offset; + pMsg->privacy = pParam->privacy; + pMsg->apUapsdEnable = pParam->ApUapsdEnable; + pMsg->ssidHidden = pParam->ssidHidden; + pMsg->fwdWPSPBCProbeReq = (uint8_t) pParam->fwdWPSPBCProbeReq; + pMsg->protEnabled = (uint8_t) pParam->protEnabled; + pMsg->obssProtEnabled = (uint8_t) pParam->obssProtEnabled; + /* set cfg related to protection */ + pMsg->ht_capab = pParam->ht_protection; + pMsg->authType = pParam->authType; + pMsg->dtimPeriod = pParam->dtimPeriod; + pMsg->wps_state = pParam->wps_state; + pMsg->isCoalesingInIBSSAllowed = pMac->isCoalesingInIBSSAllowed; + pMsg->bssPersona = pParam->bssPersona; + pMsg->txLdpcIniFeatureEnabled = pMac->roam.configParam.tx_ldpc_enable; + + /* + * If RX LDPC has been disabled for 2.4GHz channels and enabled + * for 5Ghz for STA like persona then here is how to handle + * those cases (by now channel has been decided). + */ + if (eSIR_IBSS_MODE == pMsg->bssType || + !policy_mgr_is_dbs_enable(pMac->psoc)) + csr_set_ldpc_exception(pMac, pSession, + pMsg->channelId, + pMac->roam.configParam.rx_ldpc_enable); + + qdf_mem_copy(&pMsg->vht_config, + &pSession->vht_config, + sizeof(pSession->vht_config)); + qdf_mem_copy(&pMsg->htConfig, + &pSession->htConfig, + sizeof(tSirHTConfig)); + + if (wlan_cfg_get_int(pMac, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, &value) + != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "could not get SU beam formee capability"); + pMsg->vht_config.su_beam_formee = + (uint8_t)value && + (uint8_t)pMac->roam.configParam.enable_txbf_sap_mode; + + value = WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF; + pMsg->vht_config.csnof_beamformer_antSup = (uint8_t)value; + pMsg->vht_config.mu_beam_formee = 0; + + sme_debug("ht capability 0x%x VHT capability 0x%x", + (uint32_t)(*(uint32_t *) &pMsg->htConfig), + (uint32_t)(*(uint32_t *) &pMsg->vht_config)); +#ifdef WLAN_FEATURE_11W + pMsg->pmfCapable = pParam->mfpCapable; + pMsg->pmfRequired = pParam->mfpRequired; +#endif + + if (pParam->nRSNIELength > sizeof(pMsg->rsnIE.rsnIEdata)) { + qdf_mem_free(pMsg); + return QDF_STATUS_E_INVAL; + } + pMsg->rsnIE.length = pParam->nRSNIELength; + qdf_mem_copy(pMsg->rsnIE.rsnIEdata, + pParam->pRSNIE, + pParam->nRSNIELength); + pMsg->nwType = (tSirNwType)pParam->sirNwType; + qdf_mem_copy(&pMsg->operationalRateSet, + &pParam->operationalRateSet, + sizeof(tSirMacRateSet)); + qdf_mem_copy(&pMsg->extendedRateSet, + &pParam->extendedRateSet, + sizeof(tSirMacRateSet)); + + if (IS_DOT11_MODE_HE(pMsg->dot11mode)) + csr_start_bss_copy_he_cap(pMsg, pSession); + + qdf_mem_copy(&pMsg->addIeParams, + &pParam->addIeParams, + sizeof(pParam->addIeParams)); + pMsg->obssEnabled = pMac->roam.configParam.obssEnabled; + pMsg->sap_dot11mc = pParam->sap_dot11mc; + pMsg->vendor_vht_sap = + pMac->roam.configParam.vendor_vht_sap; + pMsg->cac_duration_ms = pParam->cac_duration_ms; + pMsg->dfs_regdomain = pParam->dfs_regdomain; + pMsg->beacon_tx_rate = pParam->beacon_tx_rate; + + return umac_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tSirSmeStopBssReq *pMsg; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + pMsg = qdf_mem_malloc(sizeof(tSirSmeStopBssReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_STOP_BSS_REQ; + pMsg->sessionId = sessionId; + pMsg->length = sizeof(tSirSmeStopBssReq); + pMsg->transactionId = 0; + pMsg->reasonCode = 0; + qdf_copy_macaddr(&pMsg->bssid, &pSession->connectedProfile.bssid); + return umac_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields *pModProfileFields, + uint32_t *pRoamId, bool fForce) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t roamId = 0; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if ((csr_is_conn_state_connected(pMac, sessionId)) && + (fForce || (qdf_mem_cmp(&pModProfileFields, + &pSession->connectedProfile. + modifyProfileFields, + sizeof(tCsrRoamModifyProfileFields))))) { + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (pRoamId) + *pRoamId = roamId; + + status = + csr_roam_issue_reassoc(pMac, sessionId, NULL, + pModProfileFields, + eCsrSmeIssuedReassocToSameAP, + roamId, false); + } + return status; +} + +static QDF_STATUS csr_roam_session_opened(tpAniSirGlobal pMac, + QDF_STATUS qdf_status, + uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info roam_info; + + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + status = csr_roam_call_callback(pMac, sessionId, &roam_info, 0, + eCSR_ROAM_SESSION_OPENED, + eCSR_ROAM_RESULT_FAILURE); + } else { + status = csr_roam_call_callback(pMac, sessionId, &roam_info, 0, + eCSR_ROAM_SESSION_OPENED, + eCSR_ROAM_RESULT_SUCCESS); + } + 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(tpAniSirGlobal pMac, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev = + wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, WLAN_LEGACY_MAC_ID); + struct vdev_mlme_priv_obj *vdev_mlme; + + if (!vdev) { + sme_err("vdev is NULL"); + return; + } + + vdev_mlme = wlan_vdev_mlme_get_priv_obj(vdev); + if (!vdev_mlme) { + sme_err("vdev_mlme is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return; + } + + vdev_mlme->sta_dynamic_oce_value = + pMac->roam.configParam.oce_feature_bitmap; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +QDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) +{ + struct add_sta_self_params *rsp; + struct send_extcap_ie *msg; + QDF_STATUS status; + + if (pMsg == NULL) { + sme_err("in %s msg ptr is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + rsp = (struct add_sta_self_params *) pMsg; + sme_debug("Add Sta self rsp status = %d", rsp->status); + + if (QDF_IS_STATUS_SUCCESS(rsp->status)) { + if ((WMI_VDEV_TYPE_STA == rsp->type || + (WMI_VDEV_TYPE_AP == rsp->type && + WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE == rsp->sub_type))) { + sme_debug("send SET IE msg to PE"); + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) { + sme_err("Memory allocation failed"); + return QDF_STATUS_E_NOMEM; + } + + msg->msg_type = eWNI_SME_SET_IE_REQ; + msg->session_id = rsp->session_id; + msg->length = sizeof(*msg); + status = umac_send_mb_message_to_mac(msg); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("Failed to send down the set IE req "); + } + } + + csr_roam_session_opened(pMac, rsp->status, rsp->session_id); + + if (QDF_IS_STATUS_SUCCESS(rsp->status) && + rsp->type == WMI_VDEV_TYPE_STA) { + csr_store_oce_cfg_flags_in_vdev(pMac, pMac->pdev, + rsp->session_id); + + wlan_mlme_update_oce_flags(pMac->pdev, + pMac->roam.configParam.oce_feature_bitmap); + } + if (QDF_IS_STATUS_ERROR(rsp->status)) + csr_cleanup_session(pMac, rsp->session_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_get_vdev_type_nss() - gets the nss value based on vdev type + * @mac_ctx: Pointer to Global MAC structure + * @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(tpAniSirGlobal mac_ctx, + enum QDF_OPMODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g) +{ + 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; + default: + *nss_2g = 1; + *nss_5g = 1; + sme_err("Unknown device mode"); + break; + } + sme_debug("mode - %d: nss_2g - %d, 5g - %d", + dev_mode, *nss_2g, *nss_5g); +} + +static +QDF_STATUS csr_issue_add_sta_for_session_req(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirMacAddr sessionMacAddr, + uint32_t type, uint32_t subType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct add_sta_self_params *add_sta_self_req; + uint8_t nss_2g; + uint8_t nss_5g; + struct scheduler_msg msg = {0}; + + add_sta_self_req = qdf_mem_malloc(sizeof(struct add_sta_self_params)); + if (NULL == add_sta_self_req) { + sme_err("Unable to allocate memory for tAddSelfStaParams"); + return QDF_STATUS_E_NOMEM; + } + + csr_get_vdev_type_nss(pMac, pMac->sme.currDeviceMode, + &nss_2g, &nss_5g); + qdf_mem_copy(add_sta_self_req->self_mac_addr, sessionMacAddr, + sizeof(tSirMacAddr)); + add_sta_self_req->curr_device_mode = pMac->sme.currDeviceMode; + add_sta_self_req->session_id = sessionId; + add_sta_self_req->type = type; + add_sta_self_req->sub_type = subType; + add_sta_self_req->nss_2g = nss_2g; + add_sta_self_req->nss_5g = nss_5g; + add_sta_self_req->tx_aggregation_size = + pMac->roam.configParam.tx_aggregation_size; + add_sta_self_req->tx_aggregation_size_be = + pMac->roam.configParam.tx_aggregation_size_be; + add_sta_self_req->tx_aggregation_size_bk = + pMac->roam.configParam.tx_aggregation_size_bk; + add_sta_self_req->tx_aggregation_size_vi = + pMac->roam.configParam.tx_aggregation_size_vi; + add_sta_self_req->tx_aggregation_size_vo = + pMac->roam.configParam.tx_aggregation_size_vo; + add_sta_self_req->rx_aggregation_size = + pMac->roam.configParam.rx_aggregation_size; + add_sta_self_req->enable_bcast_probe_rsp = + pMac->roam.configParam.enable_bcast_probe_rsp; + add_sta_self_req->fils_max_chan_guard_time = + pMac->roam.configParam.fils_max_chan_guard_time; + add_sta_self_req->pkt_err_disconn_th = + pMac->roam.configParam.pkt_err_disconn_th; + add_sta_self_req->oce_feature_bitmap = + pMac->roam.configParam.oce_feature_bitmap; + add_sta_self_req->tx_aggr_sw_retry_threshold_be = + pMac->roam.configParam.tx_aggr_sw_retry_threshold_be; + add_sta_self_req->tx_aggr_sw_retry_threshold_bk = + pMac->roam.configParam.tx_aggr_sw_retry_threshold_bk; + add_sta_self_req->tx_aggr_sw_retry_threshold_vi = + pMac->roam.configParam.tx_aggr_sw_retry_threshold_vi; + add_sta_self_req->tx_aggr_sw_retry_threshold_vo = + pMac->roam.configParam.tx_aggr_sw_retry_threshold_vo; + add_sta_self_req->tx_aggr_sw_retry_threshold = + pMac->roam.configParam.tx_aggr_sw_retry_threshold; + add_sta_self_req->tx_non_aggr_sw_retry_threshold_be = + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_be; + add_sta_self_req->tx_non_aggr_sw_retry_threshold_bk = + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_bk; + add_sta_self_req->tx_non_aggr_sw_retry_threshold_vi = + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_vi; + add_sta_self_req->tx_non_aggr_sw_retry_threshold_vo = + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold_vo; + add_sta_self_req->tx_non_aggr_sw_retry_threshold = + pMac->roam.configParam.tx_non_aggr_sw_retry_threshold; + + msg.type = WMA_ADD_STA_SELF_REQ; + msg.reserved = 0; + msg.bodyptr = add_sta_self_req; + msg.bodyval = 0; + + sme_debug( + "Send WMA_ADD_STA_SELF_REQ for selfMac=" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(add_sta_self_req->self_mac_addr)); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + + if (status != QDF_STATUS_SUCCESS) { + sme_err("wma_post_ctrl_msg failed"); + qdf_mem_free(add_sta_self_req); + add_sta_self_req = NULL; + } + return status; +} + +QDF_STATUS csr_roam_open_session(tpAniSirGlobal mac_ctx, + struct sme_session_params *session_param) +{ + QDF_STATUS status; + uint32_t existing_session_id; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + } uHTCapabilityInfo; + uint32_t nCfgValue; + struct csr_roam_session *session; + + /* check to see if the mac address already belongs to a session */ + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct qdf_mac_addr *)session_param->self_mac_addr, + &existing_session_id); + if (QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Session %d exists with mac address " MAC_ADDRESS_STR, + existing_session_id, + MAC_ADDR_ARRAY(session_param->self_mac_addr)); + return QDF_STATUS_E_FAILURE; + } + + /* attempt to retrieve session for Id */ + session = CSR_GET_SESSION(mac_ctx, session_param->sme_session_id); + if (!session) { + sme_err("Session does not exist for interface %d", + session_param->sme_session_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", + session_param->sme_session_id); + return QDF_STATUS_E_FAILURE; + } + + session->sessionActive = true; + session->sessionId = session_param->sme_session_id; + + /* Initialize FT related data structures only in STA mode */ + sme_ft_open(MAC_HANDLE(mac_ctx), session->sessionId); + + session->session_open_cb = session_param->session_open_cb; + session->session_close_cb = session_param->session_close_cb; + session->callback = session_param->callback; + session->pContext = session_param->callback_ctx; + + qdf_mem_copy(&session->selfMacAddr, session_param->self_mac_addr, + sizeof(struct qdf_mac_addr)); + status = qdf_mc_timer_init(&session->hTimerRoaming, + QDF_TIMER_TYPE_SW, + csr_roam_roaming_timer_handler, + &session->roamingTimerInfo); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("cannot allocate memory for Roaming timer"); + return status; + } + + status = qdf_mc_timer_init(&session->roaming_offload_timer, + QDF_TIMER_TYPE_SW, + csr_roam_roaming_offload_timeout_handler, + &session->roamingTimerInfo); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("mem fail for roaming timer"); + return status; + } + + /* get the HT capability info */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_HT_CAP_INFO, &nCfgValue) != + QDF_STATUS_SUCCESS) { + sme_err("could not get HT capability info"); + return QDF_STATUS_SUCCESS; + } + + uHTCapabilityInfo.nCfgValue16 = 0xFFFF & nCfgValue; + session->htConfig.ht_rx_ldpc = uHTCapabilityInfo.htCapInfo.advCodingCap; + session->htConfig.ht_tx_stbc = uHTCapabilityInfo.htCapInfo.txSTBC; + session->htConfig.ht_rx_stbc = uHTCapabilityInfo.htCapInfo.rxSTBC; + session->htConfig.ht_sgi20 = uHTCapabilityInfo.htCapInfo.shortGI20MHz; + session->htConfig.ht_sgi40 = uHTCapabilityInfo.htCapInfo.shortGI40MHz; + +#ifdef FEATURE_WLAN_BTAMP_UT_RF + status = qdf_mc_timer_init(&session->hTimerJoinRetry, QDF_TIMER_TYPE_SW, + csr_roam_join_retry_timer_handler, + &session->joinRetryTimerInfo); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("cannot allocate memory for join retry timer"); + return status; + } +#endif /* FEATURE_WLAN_BTAMP_UT_RF */ + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_MAX_MPDU_LENGTH, &nCfgValue); + session->vht_config.max_mpdu_len = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + &nCfgValue); + session->vht_config.supported_channel_widthset = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_LDPC_CODING_CAP, &nCfgValue); + session->vht_config.ldpc_coding = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SHORT_GI_80MHZ, &nCfgValue); + session->vht_config.shortgi80 = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + &nCfgValue); + session->vht_config.shortgi160and80plus80 = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TXSTBC, &nCfgValue); + session->vht_config.tx_stbc = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RXSTBC, &nCfgValue); + session->vht_config.rx_stbc = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SU_BEAMFORMER_CAP, &nCfgValue); + session->vht_config.su_beam_former = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, &nCfgValue); + session->vht_config.su_beam_formee = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + &nCfgValue); + session->vht_config.csnof_beamformer_antSup = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + &nCfgValue); + session->vht_config.num_soundingdim = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_MU_BEAMFORMER_CAP, &nCfgValue); + session->vht_config.mu_beam_former = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &nCfgValue); + session->vht_config.mu_beam_formee = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TXOP_PS, &nCfgValue); + session->vht_config.vht_txops = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_HTC_VHTC_CAP, &nCfgValue); + session->vht_config.htc_vhtcap = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RX_ANT_PATTERN, &nCfgValue); + session->vht_config.rx_antpattern = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TX_ANT_PATTERN, &nCfgValue); + session->vht_config.tx_antpattern = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &nCfgValue); + session->vht_config.max_ampdu_lenexp = nCfgValue; + + csr_update_session_he_cap(mac_ctx, session); + + return csr_issue_add_sta_for_session_req(mac_ctx, + session_param->sme_session_id, + session_param->self_mac_addr, + session_param->type_of_persona, + session_param->subtype_of_persona); +} + +QDF_STATUS csr_process_del_sta_session_rsp(tpAniSirGlobal mac_ctx, + uint8_t *pMsg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct del_sta_self_params *rsp; + uint8_t sessionId; + tListElem *entry; + tSmeCmd *sme_command; + + if (pMsg == NULL) { + sme_err("msg ptr is NULL"); + return status; + } + + entry = csr_nonscan_active_ll_peek_head(mac_ctx, LL_ACCESS_LOCK); + if (!entry) { + sme_err("NO commands are ACTIVE"); + return status; + } + + sme_command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (e_sme_command_del_sta_session != sme_command->command) { + sme_err("No Del sta session command ACTIVE"); + return status; + } + + rsp = (struct del_sta_self_params *) pMsg; + sessionId = rsp->session_id; + sme_debug("Del Sta rsp status = %d", rsp->status); + + /* + * This session is done. This will also flush all the pending command + * for this vdev, as vdev is deleted and no command should be sent + * for this vdev. Active cmnd is e_sme_command_del_sta_session and will + * be removed anyway next. + */ + csr_cleanup_session(mac_ctx, sessionId); + + /* Remove this command out of the non scan active list */ + if (csr_nonscan_active_ll_remove_entry(mac_ctx, entry, + LL_ACCESS_LOCK)) { + csr_release_command(mac_ctx, sme_command); + } + + if (rsp->sme_callback) { + status = sme_release_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_debug("Failed to Release Lock"); + else { + rsp->sme_callback(rsp->session_id); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("Failed to get Lock"); + return status; + } + } + } + + return QDF_STATUS_SUCCESS; +} + + +static QDF_STATUS +csr_issue_del_sta_for_session_req(tpAniSirGlobal mac_ctx, uint32_t session_id, + tSirMacAddr session_mac_addr, + csr_session_close_cb callback, + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *sme_command; + + sme_command = csr_get_command_buffer(mac_ctx); + if (NULL == sme_command) { + status = QDF_STATUS_E_RESOURCES; + } else { + sme_command->command = e_sme_command_del_sta_session; + sme_command->sessionId = (uint8_t)session_id; + sme_command->u.delStaSessionCmd.session_close_cb = callback; + sme_command->u.delStaSessionCmd.context = context; + qdf_mem_copy(sme_command->u.delStaSessionCmd.selfMacAddr, + session_mac_addr, sizeof(tSirMacAddr)); + status = csr_queue_sme_command(mac_ctx, sme_command, false); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to send message status = %d", status); + } + return status; +} + +void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, + sessionId); + + csr_roam_stop(pMac, sessionId); + + /* Clean up FT related data structures */ + sme_ft_close(MAC_HANDLE(pMac), sessionId); + csr_free_connect_bss_desc(pMac, sessionId); + + sme_reset_key(MAC_HANDLE(pMac), sessionId); + csr_reset_cfg_privacy(pMac); + csr_roam_free_connect_profile(&pSession->connectedProfile); + csr_roam_free_connected_info(pMac, &pSession->connectedInfo); + qdf_mc_timer_destroy(&pSession->hTimerRoaming); + qdf_mc_timer_destroy(&pSession->roaming_offload_timer); +#ifdef FEATURE_WLAN_BTAMP_UT_RF + qdf_mc_timer_destroy(&pSession->hTimerJoinRetry); +#endif + csr_purge_vdev_pending_ser_cmd_list(pMac, sessionId); + csr_init_session(pMac, sessionId); + } +} + +QDF_STATUS csr_roam_close_session(tpAniSirGlobal mac_ctx, + uint32_t session_id, bool sync) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *session; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_debug("session %d not found", session_id); + return QDF_STATUS_E_INVAL; + } + + session = CSR_GET_SESSION(mac_ctx, session_id); + /* Vdev going down stop roaming */ + session->fCancelRoaming = true; + if (sync) { + csr_cleanup_session(mac_ctx, session_id); + return status; + } + + if (CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id)) { + sme_debug("Stop Wait for key timer and change substate to eCSR_ROAM_SUBSTATE_NONE"); + csr_roam_stop_wait_for_key_timer(mac_ctx); + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + session_id); + } + + if (!session->session_close_cb) { + sme_err("no close session callback registered"); + return QDF_STATUS_E_FAILURE; + } + status = csr_issue_del_sta_for_session_req(mac_ctx, + session_id, session->selfMacAddr.bytes, + session->session_close_cb, NULL); + return status; +} + +static void csr_init_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return; + } + + pSession->sessionActive = false; + pSession->sessionId = CSR_SESSION_ID_INVALID; + pSession->callback = NULL; + pSession->pContext = NULL; + pSession->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + csr_saved_scan_cmd_free_fields(pMac, pSession); + csr_free_roam_profile(pMac, sessionId); + csr_roam_free_connect_profile(&pSession->connectedProfile); + csr_roam_free_connected_info(pMac, &pSession->connectedInfo); + csr_free_connect_bss_desc(pMac, sessionId); + qdf_mem_zero(&pSession->selfMacAddr, sizeof(struct qdf_mac_addr)); + if (pSession->pWpaRsnReqIE) { + qdf_mem_free(pSession->pWpaRsnReqIE); + pSession->pWpaRsnReqIE = NULL; + } + pSession->nWpaRsnReqIeLength = 0; + if (pSession->pWpaRsnRspIE) { + qdf_mem_free(pSession->pWpaRsnRspIE); + pSession->pWpaRsnRspIE = NULL; + } + pSession->nWpaRsnRspIeLength = 0; +#ifdef FEATURE_WLAN_WAPI + if (pSession->pWapiReqIE) { + qdf_mem_free(pSession->pWapiReqIE); + pSession->pWapiReqIE = NULL; + } + pSession->nWapiReqIeLength = 0; + if (pSession->pWapiRspIE) { + qdf_mem_free(pSession->pWapiRspIE); + pSession->pWapiRspIE = NULL; + } + pSession->nWapiRspIeLength = 0; +#endif /* FEATURE_WLAN_WAPI */ + if (pSession->pAddIEScan) { + qdf_mem_free(pSession->pAddIEScan); + pSession->pAddIEScan = NULL; + } + pSession->nAddIEScanLength = 0; + if (pSession->pAddIEAssoc) { + qdf_mem_free(pSession->pAddIEAssoc); + pSession->pAddIEAssoc = NULL; + } + pSession->nAddIEAssocLength = 0; +} + +QDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssid, + uint32_t *pSessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t i; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + if (qdf_is_macaddr_equal(bssid, + &pMac->roam.roamSession[i].connectedProfile. + bssid)) { + /* Found it */ + status = QDF_STATUS_SUCCESS; + *pSessionId = i; + break; + } + } + } + return status; +} + +/* This function assumes that we only support one IBSS session. + * We cannot use BSSID to identify session because for IBSS, + * the bssid changes. + */ +static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac) +{ + uint32_t i, nRet = CSR_SESSION_ID_INVALID; + struct csr_roam_session *pSession; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + pSession = CSR_GET_SESSION(pMac, i); + if (pSession->pCurRoamProfile + && + (csr_is_bss_type_ibss + (pSession->connectedProfile.BSSType))) { + /* Found it */ + nRet = i; + break; + } + } + } + return nRet; +} + +static void csr_roam_link_up(tpAniSirGlobal pMac, struct qdf_mac_addr bssid) +{ + uint32_t sessionId = 0; + + /* + * Update the current BSS info in ho control block based on connected + * profile info from pmac global structure + */ + + sme_debug( + " csr_roam_link_up: WLAN link UP with AP= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssid.bytes)); + /* Check for user misconfig of RSSI trigger threshold */ + pMac->roam.configParam.vccRssiThreshold = + (0 == pMac->roam.configParam.vccRssiThreshold) ? + CSR_VCC_RSSI_THRESHOLD : + pMac->roam.configParam.vccRssiThreshold; + /* Check for user misconfig of UL MAC Loss trigger threshold */ + pMac->roam.configParam.vccUlMacLossThreshold = + (0 == pMac->roam.configParam.vccUlMacLossThreshold) ? + CSR_VCC_UL_MAC_LOSS_THRESHOLD : pMac->roam.configParam. + vccUlMacLossThreshold; + /* Indicate the neighbor roal algorithm about the connect indication */ + csr_roam_get_session_id_from_bssid(pMac, &bssid, + &sessionId); + csr_neighbor_roam_indicate_connect(pMac, sessionId, + QDF_STATUS_SUCCESS); +} + +static void csr_roam_link_down(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return; + } + /* Only to handle the case for Handover on infra link */ + if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) + return; + /* + * Incase of station mode, immediately stop data transmission whenever + * link down is detected. + */ + if (csr_roam_is_sta_mode(pMac, sessionId) + && !CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) + && !csr_roam_is11r_assoc(pMac, sessionId)) { + sme_debug("Inform Link lost for session %d", + sessionId); + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_LOSTLINK); + } + /* deregister the clients requesting stats from PE/TL & also stop the + * corresponding timers + */ + csr_roam_dereg_statistics_req(pMac); + /* Indicate the neighbor roal algorithm about the disconnect + * indication + */ + csr_neighbor_roam_indicate_disconnect(pMac, sessionId); + + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) && + csr_is_infra_ap_started(pMac) && + pMac->roam.configParam.doBMPSWorkaround) { + pMac->roam.configParam.doBMPSWorkaround = 0; + } + +} + +#ifndef QCA_SUPPORT_CP_STATS +QDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, uint32_t statsMask, + uint8_t staId, uint8_t sessionId) +{ + tAniGetPEStatsReq *pMsg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pMsg = qdf_mem_malloc(sizeof(tAniGetPEStatsReq)); + if (NULL == pMsg) { + sme_err("Failed to allocate mem for stats req "); + return QDF_STATUS_E_NOMEM; + } + /* need to initiate a stats request to PE */ + pMsg->msgType = eWNI_SME_GET_STATISTICS_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetPEStatsReq); + pMsg->staId = staId; + pMsg->statsMask = statsMask; + pMsg->sessionId = sessionId; + status = umac_send_mb_message_to_mac(pMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_debug("Failed to send down the stats req "); + + return status; +} + +/** + * csr_update_stats() - updates correct stats struct in mac_ctx + * @mac: mac global context + * @stats_type: stats type + * @sme_stats_rsp: stats rsp msg packet + * @stats: input stats data buffer to fill in mac_ctx struct + * @length: out param - stats length + * + * This function fills corresponding stats struct in mac_cts based on stats type + * passed + * + * Return: void + */ +static void +csr_update_stats(tpAniSirGlobal mac, uint8_t stats_type, + tAniGetPEStatsRsp *sme_stats_rsp, + uint8_t **stats, uint32_t *length) +{ + switch (stats_type) { + case eCsrSummaryStats: + sme_debug("summary stats"); + qdf_mem_copy((uint8_t *) &mac->roam.summaryStatsInfo, *stats, + sizeof(tCsrSummaryStatsInfo)); + *stats += sizeof(tCsrSummaryStatsInfo); + *length -= sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + sme_debug("ClassA stats"); + qdf_mem_copy((uint8_t *) &mac->roam.classAStatsInfo, *stats, + sizeof(tCsrGlobalClassAStatsInfo)); + *stats += sizeof(tCsrGlobalClassAStatsInfo); + *length -= sizeof(tCsrGlobalClassAStatsInfo); + break; + case csr_per_chain_rssi_stats: + sme_debug("csrRoamStatsRspProcessor:Per Chain RSSI stats"); + qdf_mem_copy((uint8_t *)&mac->roam.per_chain_rssi_stats, + *stats, sizeof(struct csr_per_chain_rssi_stats_info)); + *stats += sizeof(struct csr_per_chain_rssi_stats_info); + *length -= sizeof(struct csr_per_chain_rssi_stats_info); + break; + default: + sme_warn("unknown stats type"); + break; + } +} + +/** + * csr_roam_stats_rsp_processor() - processes stats rsp msg + * @pMac mac global context + * @pSirMsg: incoming message + * + * Return: void + */ +void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) +{ + tAniGetPEStatsRsp *pSmeStatsRsp; + tListElem *pEntry = NULL; + struct csr_statsclient_reqinfo *pTempStaEntry = NULL; + struct csr_pestats_reqinfo *pPeStaEntry = NULL; + uint32_t tempMask = 0; + uint8_t counter = 0; + uint8_t *pStats = NULL; + uint32_t length = 0; + int8_t rssi = 0, snr = 0; + uint32_t *pRssi = NULL, *pSnr = NULL; + uint32_t linkCapacity; + + pSmeStatsRsp = (tAniGetPEStatsRsp *) pSirMsg; + if (pSmeStatsRsp->rc) { + sme_warn("stats rsp from PE shows failure"); + goto post_update; + } + tempMask = pSmeStatsRsp->statsMask; + pStats = ((uint8_t *) &pSmeStatsRsp->statsMask) + + sizeof(pSmeStatsRsp->statsMask); + /* + * subtract all statistics from this length, and after processing the + * entire 'stat' part of the message, if the length is not zero, then + * rssi is piggy packed in this 'stats' message. + */ + length = pSmeStatsRsp->msgLen - sizeof(tAniGetPEStatsRsp); + /* new stats info from PE, fill up the stats strucutres in PMAC */ + while (tempMask) { + if (tempMask & 1) + csr_update_stats(pMac, counter, pSmeStatsRsp, + &pStats, &length); + tempMask >>= 1; + counter++; + } + if (length != 0) { + pRssi = (uint32_t *) pStats; + rssi = (int8_t) *pRssi; + pStats += sizeof(uint32_t); + length -= sizeof(uint32_t); + } else + /* If riva is not sending rssi, continue to use the hack */ + rssi = RSSI_HACK_BMPS; + + if (length != 0) { + linkCapacity = *(uint32_t *) pStats; + pStats += sizeof(uint32_t); + length -= sizeof(uint32_t); + } else + linkCapacity = 0; + + if (length != 0) { + pSnr = (uint32_t *) pStats; + snr = (int8_t) *pSnr; + } else + snr = SNR_HACK_BMPS; + +post_update: + /* make sure to update the pe stats req list */ + pEntry = csr_roam_find_in_pe_stats_req_list(pMac, + pSmeStatsRsp->statsMask); + if (pEntry) { + pPeStaEntry = GET_BASE_ADDR(pEntry, + struct csr_pestats_reqinfo, link); + pPeStaEntry->rspPending = false; + + } + /* check the one timer cases */ + pEntry = csr_roam_check_client_req_list(pMac, pSmeStatsRsp->statsMask); + if (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, + struct csr_statsclient_reqinfo, link); + if (pTempStaEntry->timerExpired) { + /* send up the stats report */ + csr_roam_report_statistics(pMac, + pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + /* also remove from the client list */ + csr_roam_remove_stat_list_entry(pMac, pEntry); + pTempStaEntry = NULL; + } + } +} + +tListElem *csr_roam_find_in_pe_stats_req_list( + tpAniSirGlobal pMac, uint32_t statsMask) +{ + tListElem *pEntry = NULL; + struct csr_pestats_reqinfo *pTempStaEntry = NULL; + + pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sme_debug("csr_roam_find_in_pe_stats_req_list: List empty, no request to PE"); + return NULL; + } + while (pEntry) { + pTempStaEntry = GET_BASE_ADDR(pEntry, struct csr_pestats_reqinfo, link); + if (pTempStaEntry->statsMask == statsMask) + break; + pEntry = + csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +static +tListElem *csr_roam_checkn_update_client_req_list( +tpAniSirGlobal pMac, struct csr_statsclient_reqinfo *pStaEntry, + bool update) +{ + tListElem *pEntry; + struct csr_statsclient_reqinfo *pTempStaEntry; + + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, + LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sme_debug("List empty, no request from upper layer client(s)"); + return NULL; + } + while (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, + struct csr_statsclient_reqinfo, link); + if ((pTempStaEntry->requesterId == pStaEntry->requesterId) + && (pTempStaEntry->statsMask == pStaEntry->statsMask)) { + if (update) { + pTempStaEntry->callback = pStaEntry->callback; + pTempStaEntry->pContext = pStaEntry->pContext; + } + break; + } + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +tListElem *csr_roam_check_client_req_list(tpAniSirGlobal pMac, + uint32_t statsMask) +{ + tListElem *pEntry; + struct csr_statsclient_reqinfo *pTempStaEntry; + + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, + LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sme_debug("List empty, no request from upper layer client(s)"); + return NULL; + } + while (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, + struct csr_statsclient_reqinfo, link); + if ((pTempStaEntry-> + statsMask & ~(1 << eCsrGlobalClassDStats)) == statsMask) { + break; + } + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +struct csr_statsclient_reqinfo *csr_roam_insert_entry_into_list( + tpAniSirGlobal pMac, tDblLinkList *pStaList, + struct csr_statsclient_reqinfo * + pStaEntry) +{ + struct csr_statsclient_reqinfo *pNewStaEntry = NULL; + /* + * if same entity requested for same set of stats with different + * callback update it + */ + if (NULL == csr_roam_checkn_update_client_req_list(pMac, pStaEntry, + true)) { + + pNewStaEntry = qdf_mem_malloc(sizeof(struct csr_statsclient_reqinfo)); + if (NULL == pNewStaEntry) { + sme_err("couldn't allocate memory for the entry"); + return NULL; + } + + pNewStaEntry->callback = pStaEntry->callback; + pNewStaEntry->pContext = pStaEntry->pContext; + pNewStaEntry->requesterId = pStaEntry->requesterId; + pNewStaEntry->statsMask = pStaEntry->statsMask; + pNewStaEntry->pPeStaEntry = pStaEntry->pPeStaEntry; + pNewStaEntry->pMac = pStaEntry->pMac; + pNewStaEntry->staId = pStaEntry->staId; + pNewStaEntry->timerExpired = pStaEntry->timerExpired; + + csr_ll_insert_tail(pStaList, &pNewStaEntry->link, + LL_ACCESS_LOCK); + } + return pNewStaEntry; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +QDF_STATUS csr_get_rssi(tpAniSirGlobal pMac, + tCsrRssiCallback callback, + uint8_t staId, + struct qdf_mac_addr bssId, + int8_t lastRSSI, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0}; + uint32_t sessionId; + tAniGetRssiReq *pMsg; + + status = csr_roam_get_session_id_from_bssid(pMac, &bssId, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + callback(lastRSSI, staId, pContext); + sme_err("Failed to get SessionId"); + return QDF_STATUS_E_FAILURE; + } + + pMsg = qdf_mem_malloc(sizeof(tAniGetRssiReq)); + if (NULL == pMsg) { + sme_err("csr_get_rssi: failed to allocate mem for req "); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_GET_RSSI_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetRssiReq); + pMsg->sessionId = sessionId; + pMsg->staId = staId; + pMsg->rssiCallback = callback; + pMsg->pDevContext = pContext; + /* + * store RSSI at time of calling, so that if RSSI request cannot + * be sent to firmware, this value can be used to return immediately + */ + pMsg->lastRSSI = lastRSSI; + msg.type = eWNI_SME_GET_RSSI_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)) { + sme_err("scheduler_post_msg failed to post msg to self"); + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +QDF_STATUS csr_get_snr(tpAniSirGlobal pMac, + tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0}; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + tAniGetSnrReq *pMsg; + + pMsg = (tAniGetSnrReq *) qdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (NULL == pMsg) { + sme_err("failed to allocate mem for req"); + return QDF_STATUS_E_NOMEM; + } + + status = csr_roam_get_session_id_from_bssid(pMac, &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->staId = staId; + 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)) { + sme_err("failed to post msg to self"); + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * csr_deregister_client_request() - deregisters a get stats request + * @mac_ctx: mac global context + * @sta_entry: stats request entry + * + * Return: status of operation + */ +static QDF_STATUS +csr_deregister_client_request(tpAniSirGlobal mac_ctx, + struct csr_statsclient_reqinfo *sta_entry) +{ + QDF_STATUS status; + tListElem *entry = NULL; + struct csr_statsclient_reqinfo *ptr_sta_entry = NULL; + + entry = csr_roam_checkn_update_client_req_list(mac_ctx, sta_entry, + false); + if (!entry) { + sme_err("callback is empty in the request & couldn't find any existing request in statsClientReqList"); + return QDF_STATUS_E_FAILURE; + } + /* clean up & return */ + ptr_sta_entry = GET_BASE_ADDR(entry, + struct csr_statsclient_reqinfo, link); + if (NULL != ptr_sta_entry->pPeStaEntry) { + ptr_sta_entry->pPeStaEntry->numClient--; + /* check if we need to delete the entry from peStatsReqList */ + if (!ptr_sta_entry->pPeStaEntry->numClient) + csr_roam_remove_entry_from_pe_stats_req_list(mac_ctx, + ptr_sta_entry->pPeStaEntry); + } + /* check if we need to stop the tl stats timer too */ + mac_ctx->roam.tlStatsReqInfo.numClient--; + qdf_mc_timer_stop(&ptr_sta_entry->timer); + /* Destroy the qdf timer... */ + status = qdf_mc_timer_destroy(&ptr_sta_entry->timer); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err( + "failed to destroy Client req timer"); + + csr_roam_remove_stat_list_entry(mac_ctx, entry); + return QDF_STATUS_SUCCESS; +} + +/** + * csr_insert_stats_request_to_list() - inserts request to existing list + * @mac_ctx: mac global context + * @sta_entry: stats request entry + * + * Return: status of operation + */ +static QDF_STATUS +csr_insert_stats_request_to_list(tpAniSirGlobal mac_ctx, + struct csr_statsclient_reqinfo *sta_entry) +{ +struct csr_statsclient_reqinfo *ptr_sta_entry = csr_roam_insert_entry_into_list( + mac_ctx, &mac_ctx->roam.statsClientReqList, + sta_entry); + if (!ptr_sta_entry) { + sme_err("Failed to insert req in statsClientReqList"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_get_statistics(tpAniSirGlobal pMac, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, + tCsrStatsCallback callback, + uint8_t staId, + void *pContext, + uint8_t sessionId) +{ + struct csr_statsclient_reqinfo staEntry; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool insertInClientList = false; + uint32_t temp_mask = 0; + + if (csr_is_all_session_disconnected(pMac)) + return QDF_STATUS_E_FAILURE; + + if (csr_neighbor_middle_of_roaming(pMac, sessionId)) { + sme_debug("in the middle of roaming states"); + return QDF_STATUS_E_FAILURE; + } + + if ((!statsMask) && (!callback)) { + sme_err("statsMask & callback empty in the request"); + return QDF_STATUS_E_FAILURE; + } + /* for the search list method for deregister */ + staEntry.requesterId = requesterId; + staEntry.statsMask = statsMask; + /* requester wants to deregister or just an error */ + if ((statsMask) && (!callback)) + return csr_deregister_client_request(pMac, &staEntry); + + /* add the request in the client req list */ + staEntry.callback = callback; + staEntry.pContext = pContext; + staEntry.pPeStaEntry = NULL; + staEntry.staId = staId; + staEntry.pMac = pMac; + staEntry.timerExpired = false; + staEntry.sessionId = sessionId; + + temp_mask = statsMask & ~(1 << eCsrGlobalClassDStats); + if (temp_mask) { + /* send down a req */ + status = csr_send_mb_stats_req_msg(pMac, + temp_mask, staId, sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("failed to send down stats req"); + /* + * so that when the stats rsp comes back from PE we + * respond to upper layer right away + */ + staEntry.timerExpired = true; + insertInClientList = true; + } + /* if looking for stats from TL only */ + if (!insertInClientList) { + /* return the stats */ + csr_roam_report_statistics(pMac, statsMask, callback, + staId, pContext); + return QDF_STATUS_SUCCESS; + } + if (insertInClientList) + return csr_insert_stats_request_to_list(pMac, &staEntry); + + return QDF_STATUS_SUCCESS; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * csr_roam_set_key_mgmt_offload() - enable/disable key mgmt offload + * @mac_ctx: mac context. + * @session_id: Session Identifier + * @roam_key_mgmt_offload_enabled: key mgmt enable/disable flag + * @pmkid_modes: PMKID modes of PMKSA caching and OKC + * + * Return: QDF_STATUS_SUCCESS - CSR updated config successfully. + * Other status means CSR is failed to update. + */ + +QDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal mac_ctx, + uint32_t session_id, + bool roam_key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes) +{ + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("session %d not found", session_id); + return QDF_STATUS_E_FAILURE; + } + session->RoamKeyMgmtOffloadEnabled = roam_key_mgmt_offload_enabled; + session->pmkid_modes.fw_okc = pmkid_modes->fw_okc; + session->pmkid_modes.fw_pmksa_cache = pmkid_modes->fw_pmksa_cache; + return QDF_STATUS_SUCCESS; +} + +/** + * csr_update_roam_scan_ese_params() - Update ESE related params in RSO request + * @req_buf: Roam Scan Offload Request buffer + * @session: Current Roam Session + * + * This API will set the KRK and BTK required in case of Auth Type is CCKM. + * It will also clear the PMK Len as CCKM PMK Caching is not supported + * + * Return: None + */ +#ifdef FEATURE_WLAN_ESE +static +void csr_update_roam_scan_ese_params(tSirRoamOffloadScanReq *req_buf, + struct csr_roam_session *session) +{ + if (csr_is_auth_type_ese(req_buf->ConnectedNetwork.authentication)) { + qdf_mem_copy(req_buf->KRK, session->eseCckmInfo.krk, + SIR_KRK_KEY_LEN); + qdf_mem_copy(req_buf->BTK, session->eseCckmInfo.btk, + SIR_BTK_KEY_LEN); + req_buf->pmkid_modes.fw_okc = 0; + req_buf->pmkid_modes.fw_pmksa_cache = 0; + req_buf->pmk_len = 0; + qdf_mem_zero(&req_buf->PSK_PMK[0], sizeof(req_buf->PSK_PMK)); + } +} +#else +static inline +void csr_update_roam_scan_ese_params(tSirRoamOffloadScanReq *req_buf, + struct csr_roam_session *session) +{ +} +#endif + +/** + * csr_update_roam_scan_offload_request() - updates req msg with roam offload + * parameters + * @pMac: mac global context + * @req_buf: out param, roam offload scan request packet + * @session: roam session + * + * Return: void + */ +static void +csr_update_roam_scan_offload_request(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf, + struct csr_roam_session *session) +{ + qdf_mem_copy(req_buf->PSK_PMK, session->psk_pmk, + sizeof(req_buf->PSK_PMK)); + req_buf->pmk_len = session->pmk_len; + req_buf->R0KH_ID_Length = session->ftSmeContext.r0kh_id_len; + qdf_mem_copy(req_buf->R0KH_ID, + session->ftSmeContext.r0kh_id, + req_buf->R0KH_ID_Length); + req_buf->Prefer5GHz = mac_ctx->roam.configParam.nRoamPrefer5GHz; + req_buf->RoamRssiCatGap = mac_ctx->roam.configParam.bCatRssiOffset; + req_buf->Select5GHzMargin = mac_ctx->roam.configParam.nSelect5GHzMargin; + req_buf->ho_delay_for_rx = mac_ctx->roam.configParam.ho_delay_for_rx; + req_buf->roam_preauth_retry_count = + mac_ctx->roam.configParam.roam_preauth_retry_count; + req_buf->roam_preauth_no_ack_timeout = + mac_ctx->roam.configParam.roam_preauth_no_ack_timeout; + req_buf->min_delay_btw_roam_scans = + mac_ctx->roam.configParam.min_delay_btw_roam_scans; + req_buf->roam_trigger_reason_bitmask = + mac_ctx->roam.configParam.roam_trigger_reason_bitmask; + req_buf->roaming_scan_policy = + mac_ctx->roam.configParam.roaming_scan_policy; + req_buf->roam_force_rssi_trigger = + mac_ctx->roam.configParam.roam_force_rssi_trigger; + + /* fill bss load triggered roam related configs */ + req_buf->bss_load_trig_enabled = + mac_ctx->roam.configParam.enable_bss_load_roam_trigger; + req_buf->bss_load_config.bss_load_threshold = + mac_ctx->roam.configParam.bss_load_threshold; + req_buf->bss_load_config.bss_load_sample_time = + mac_ctx->roam.configParam.bss_load_sample_time; + req_buf->bss_load_config.vdev_id = session->sessionId; + + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &req_buf->ReassocFailureTimeout) + != QDF_STATUS_SUCCESS) { + sme_err( + "could not retrieve ReassocFailureTimeout value"); + req_buf->ReassocFailureTimeout = + DEFAULT_REASSOC_FAILURE_TIMEOUT; + } + + csr_update_roam_scan_ese_params(req_buf, session); + + req_buf->AcUapsd.acbe_uapsd = SIR_UAPSD_GET(ACBE, session->uapsd_mask); + req_buf->AcUapsd.acbk_uapsd = SIR_UAPSD_GET(ACBK, session->uapsd_mask); + req_buf->AcUapsd.acvi_uapsd = SIR_UAPSD_GET(ACVI, session->uapsd_mask); + req_buf->AcUapsd.acvo_uapsd = SIR_UAPSD_GET(ACVO, session->uapsd_mask); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * csr_check_band_channel_match() - check if passed band and channel match + * parameters + * @band: band to match with channel + * @channel: channel to match with band + * + * Return: bool if match else false + */ +static bool +csr_check_band_channel_match(enum band_info band, uint8_t channel) +{ + if (BAND_ALL == band) + return true; + + if (BAND_2G == band && WLAN_REG_IS_24GHZ_CH(channel)) + return true; + + if (BAND_5G == band && WLAN_REG_IS_5GHZ_CH(channel)) + return true; + + return false; +} + +/** + * csr_fetch_ch_lst_from_ini() - fetch channel list from ini and update req msg + * parameters + * @mac_ctx: global mac ctx + * @roam_info: roam info struct + * @req_buf: out param, roam offload scan request packet + * + * Return: result of operation + */ +static QDF_STATUS +csr_fetch_ch_lst_from_ini(tpAniSirGlobal mac_ctx, + tpCsrNeighborRoamControlInfo roam_info, + tSirRoamOffloadScanReq *req_buf) +{ + enum band_info band; + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = roam_info->cfgParams.channelInfo.ChannelList; + 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); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + /* + * The INI channels need to be filtered with respect to the current band + * that is supported. + */ + band = mac_ctx->roam.configParam.bandCapability; + if ((BAND_2G != band) && (BAND_5G != band) + && (BAND_ALL != band)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Invalid band(%d), roam scan offload req aborted", + band); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < roam_info->cfgParams.channelInfo.numOfChannels; i++) { + if (!csr_check_band_channel_match(band, *ch_lst)) + continue; + /* Allow DFS channels only if the DFS roaming is enabled */ + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (wlan_reg_is_dfs_ch(mac_ctx->pdev, *ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam.sta_roam_policy. + skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + ("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + ch_lst++; + + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + req_buf->ChannelCacheType = CHANNEL_LIST_STATIC; + return QDF_STATUS_SUCCESS; +} + +/** + * csr_fetch_ch_lst_from_occupied_lst() - fetch channel list from occupied list + * and update req msg + * parameters + * @mac_ctx: global mac ctx + * @session_id: session id + * @reason: reason to roam + * @req_buf: out param, roam offload scan request packet + * @roam_info: roam info struct + * + * Return: void + */ +static void +csr_fetch_ch_lst_from_occupied_lst(tpAniSirGlobal mac_ctx, + uint8_t session_id, + uint8_t reason, + tSirRoamOffloadScanReq *req_buf, + tpCsrNeighborRoamControlInfo roam_info) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = + mac_ctx->scan.occupiedChannels[session_id].channelList; + 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); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Num of channels before filtering=%d", + mac_ctx->scan.occupiedChannels[session_id].numChannels); + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + for (i = 0; i < mac_ctx->scan.occupiedChannels[session_id].numChannels; + i++) { + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (wlan_reg_is_dfs_ch(mac_ctx->pdev, *ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam.sta_roam_policy. + skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + ("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + if (*ch_lst) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "DFSRoam=%d, ChnlState=%d, Chnl=%d, num_ch=%d", + mac_ctx->roam.configParam.allowDFSChannelRoam, + wlan_reg_get_channel_state(mac_ctx->pdev, + *ch_lst), + *ch_lst, + num_channels); + ch_lst++; + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC; +} + +/** + * csr_fetch_valid_ch_lst() - fetch channel list from valid channel list and + * update req msg + * parameters + * @mac_ctx: global mac ctx + * @req_buf: out param, roam offload scan request packet + * + * Return: void + */ +static QDF_STATUS +csr_fetch_valid_ch_lst(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf, + uint8_t session_id) +{ + QDF_STATUS status; + uint32_t host_channels = 0; + uint8_t *ch_lst = NULL; + uint8_t i = 0, num_channels = 0; + 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); + enum band_info band = BAND_ALL; + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + host_channels = sizeof(mac_ctx->roam.validChannelList); + status = csr_get_cfg_valid_channels(mac_ctx, + mac_ctx->roam.validChannelList, + &host_channels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to get the valid channel list"); + return status; + } + + if (CSR_IS_ROAM_INTRA_BAND_ENABLED(mac_ctx)) { + band = csr_get_rf_band(mac_ctx->roam.roamSession[session_id]. + connectedProfile.operationChannel); + sme_debug("updated band %d operational ch %d", band, + mac_ctx->roam.roamSession[session_id]. + connectedProfile.operationChannel); + } + + ch_lst = mac_ctx->roam.validChannelList; + mac_ctx->roam.numValidChannels = host_channels; + + for (i = 0; i < mac_ctx->roam.numValidChannels; i++) { + if (!csr_check_band_channel_match(band, *ch_lst)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("ignoring non-intra band channel %d"), + *ch_lst); + ch_lst++; + continue; + } + + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (wlan_reg_is_dfs_ch(mac_ctx->pdev, *ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam. + sta_roam_policy.skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + ("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + ch_lst++; + } + req_buf->ValidChannelCount = num_channels; + + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC; + req_buf->ConnectedNetwork.ChannelCount = num_channels; + return status; +} + +/** + * csr_create_roam_scan_offload_request() - init roam offload scan request + * + * parameters + * @mac_ctx: global mac ctx + * @command: roam scan offload command input + * @session_id: session id + * @reason: reason to roam + * @session: roam session + * @roam_info: roam info struct + * + * Return: roam offload scan request packet buffer + */ +static tSirRoamOffloadScanReq * +csr_create_roam_scan_offload_request(tpAniSirGlobal mac_ctx, + uint8_t command, + uint8_t session_id, + uint8_t reason, + struct csr_roam_session *session, + tpCsrNeighborRoamControlInfo roam_info) +{ + QDF_STATUS status; + uint8_t i, j, dot11_mode; + bool ese_neighbor_list_recvd = false; + uint8_t ch_cache_str[128] = { 0 }; + tSirRoamOffloadScanReq *req_buf = NULL; + tpCsrChannelInfo curr_ch_lst_info = + &roam_info->roamChannelInfo.currentChannelListInfo; +#ifdef FEATURE_WLAN_ESE + /* + * this flag will be true if connection is ESE and no neighbor + * list received or if the connection is not ESE + */ + ese_neighbor_list_recvd = ((roam_info->isESEAssoc) + && (roam_info->roamChannelInfo.IAPPNeighborListReceived + == false)) + || (roam_info->isESEAssoc == false); +#endif /* FEATURE_WLAN_ESE */ + + req_buf = qdf_mem_malloc(sizeof(tSirRoamOffloadScanReq)); + if (NULL == req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Mem alloc for roam scan offload req failed"); + return NULL; + } + req_buf->Command = command; + /* + * If command is STOP, then pass down ScanOffloadEnabled as Zero. This + * will handle the case of host driver reloads, but Riva still up and + * running + */ + if (command == ROAM_SCAN_OFFLOAD_STOP) { + /* + * clear the roaming parameters that are per connection. + * For a new connection, they have to be programmed again. + */ + if (csr_neighbor_middle_of_roaming(mac_ctx, + session_id)) + req_buf->middle_of_roaming = 1; + else + csr_roam_reset_roam_params(mac_ctx); + req_buf->RoamScanOffloadEnabled = 0; + } else if (command == ROAM_SCAN_OFFLOAD_UPDATE_CFG) { + req_buf->RoamScanOffloadEnabled = + roam_info->b_roam_scan_offload_started; + } else { + req_buf->RoamScanOffloadEnabled = + mac_ctx->roam.configParam.isRoamOffloadScanEnabled; + } + qdf_mem_copy(req_buf->ConnectedNetwork.currAPbssid, + roam_info->currAPbssid.bytes, sizeof(struct qdf_mac_addr)); + req_buf->ConnectedNetwork.ssId.length = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.SSID.length; + qdf_mem_copy(req_buf->ConnectedNetwork.ssId.ssId, + mac_ctx->roam.roamSession[session_id]. + connectedProfile.SSID.ssId, + req_buf->ConnectedNetwork.ssId.length); + req_buf->ConnectedNetwork.authentication = + mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType; + req_buf->ConnectedNetwork.encryption = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.EncryptionType; + req_buf->ConnectedNetwork.mcencryption = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.mcEncryptionType; + /* Copy the RSN capabilities in roam offload request from session*/ + req_buf->rsn_caps = session->rsn_caps; +#ifdef WLAN_FEATURE_11W + req_buf->ConnectedNetwork.mfp_enabled = + mac_ctx->roam.roamSession[session_id].connectedProfile.MFPEnabled; +#endif + req_buf->delay_before_vdev_stop = + roam_info->cfgParams.delay_before_vdev_stop; + req_buf->OpportunisticScanThresholdDiff = + roam_info->cfgParams.nOpportunisticThresholdDiff; + req_buf->RoamRescanRssiDiff = + roam_info->cfgParams.nRoamRescanRssiDiff; + req_buf->RoamRssiDiff = mac_ctx->roam.configParam.RoamRssiDiff; + req_buf->rssi_abs_thresh = mac_ctx->roam.configParam.rssi_abs_thresh; + req_buf->reason = reason; + req_buf->NeighborScanTimerPeriod = + roam_info->cfgParams.neighborScanPeriod; + req_buf->neighbor_scan_min_timer_period = + roam_info->cfgParams.neighbor_scan_min_period; + req_buf->NeighborRoamScanRefreshPeriod = + roam_info->cfgParams.neighborResultsRefreshPeriod; + req_buf->NeighborScanChannelMinTime = + roam_info->cfgParams.minChannelScanTime; + req_buf->NeighborScanChannelMaxTime = + roam_info->cfgParams.maxChannelScanTime; + req_buf->EmptyRefreshScanPeriod = + roam_info->cfgParams.emptyScanRefreshPeriod; + req_buf->RoamBmissFirstBcnt = + roam_info->cfgParams.nRoamBmissFirstBcnt; + req_buf->RoamBmissFinalBcnt = + roam_info->cfgParams.nRoamBmissFinalBcnt; + req_buf->RoamBeaconRssiWeight = + roam_info->cfgParams.nRoamBeaconRssiWeight; + qdf_mem_copy(&req_buf->mawc_roam_params, + &mac_ctx->roam.configParam.csr_mawc_config, + sizeof(req_buf->mawc_roam_params)); + sme_debug("MAWC:global=%d,roam=%d,traffic=%d,ap_rssi=%d,high=%d,low=%d", + req_buf->mawc_roam_params.mawc_enabled, + req_buf->mawc_roam_params.mawc_roam_enabled, + req_buf->mawc_roam_params.mawc_roam_traffic_threshold, + req_buf->mawc_roam_params.mawc_roam_ap_rssi_threshold, + req_buf->mawc_roam_params.mawc_roam_rssi_high_adjust, + req_buf->mawc_roam_params.mawc_roam_rssi_low_adjust); +#ifdef FEATURE_WLAN_ESE + req_buf->IsESEAssoc = + csr_roam_is_ese_assoc(mac_ctx, session_id) && + ((req_buf->ConnectedNetwork.authentication == + eCSR_AUTH_TYPE_OPEN_SYSTEM) || + (csr_is_auth_type_ese(req_buf-> + ConnectedNetwork.authentication))); + req_buf->is_11r_assoc = roam_info->is11rAssoc; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "IsEseAssoc: %d is_11r_assoc: %d middle of roaming: %d ese_neighbor_list_recvd: %d cur no of chan: %d", + req_buf->IsESEAssoc, req_buf->is_11r_assoc, + req_buf->middle_of_roaming, + ese_neighbor_list_recvd, + curr_ch_lst_info->numOfChannels); +#endif + + if (!CSR_IS_ROAM_INTRA_BAND_ENABLED(mac_ctx)) { + if (ese_neighbor_list_recvd || + curr_ch_lst_info->numOfChannels == 0) { + /* + * Retrieve the Channel Cache either from ini or from + * the occupied channels list. + * Give Preference to INI Channels + */ + if (roam_info->cfgParams.channelInfo.numOfChannels) { + status = csr_fetch_ch_lst_from_ini(mac_ctx, + roam_info, + req_buf); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "Fetch channel list from ini failed"); + qdf_mem_free(req_buf); + return NULL; + } + } else { + csr_fetch_ch_lst_from_occupied_lst(mac_ctx, + session_id, reason, req_buf, + roam_info); + } + } +#ifdef FEATURE_WLAN_ESE + 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 + */ + csr_fetch_ch_lst_from_received_list(mac_ctx, roam_info, + curr_ch_lst_info, req_buf); + } +#endif + } + if (req_buf->ConnectedNetwork.ChannelCount == 0) { + /* Maintain the Valid Channels List */ + status = csr_fetch_valid_ch_lst(mac_ctx, req_buf, session_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Fetch channel list fail"); + qdf_mem_free(req_buf); + return NULL; + } + } + + for (i = 0, j = 0; i < req_buf->ConnectedNetwork.ChannelCount; i++) { + if (j < sizeof(ch_cache_str)) { + j += snprintf(ch_cache_str + j, + sizeof(ch_cache_str) - j, " %d", + req_buf->ConnectedNetwork. + ChannelCache[i]); + } else + break; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("ChnlCacheType:%d, No of Chnls:%d,Channels: %s"), + req_buf->ChannelCacheType, + req_buf->ConnectedNetwork.ChannelCount, ch_cache_str); + + req_buf->MDID.mdiePresent = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.MDID.mdiePresent; + req_buf->MDID.mobilityDomain = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.MDID.mobilityDomain; + req_buf->sessionId = session_id; + req_buf->nProbes = mac_ctx->roam.configParam.nProbes; + req_buf->HomeAwayTime = mac_ctx->roam.configParam.nRoamScanHomeAwayTime; + + /* + * Home Away Time should be at least equal to (MaxDwell time + (2*RFS)), + * where RFS is the RF Switching time. It is twice RFS to consider the + * time to go off channel and return to the home channel. + */ + if (req_buf->HomeAwayTime < (req_buf->NeighborScanChannelMaxTime + + (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Invalid config, Home away time(%d) is less than (twice RF switching time + channel max time)(%d). Hence enforcing home away time to disable (0)", + req_buf->HomeAwayTime, + (req_buf->NeighborScanChannelMaxTime + + (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME))); + req_buf->HomeAwayTime = 0; + } + + /*Prepare a probe request for 2.4GHz band and one for 5GHz band */ + dot11_mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + csr_find_best_phy_mode(mac_ctx, + mac_ctx->roam.configParam.phyMode)); + req_buf->allowDFSChannelRoam = + mac_ctx->roam.configParam.allowDFSChannelRoam; + req_buf->early_stop_scan_enable = + mac_ctx->roam.configParam.early_stop_scan_enable; + req_buf->early_stop_scan_min_threshold = + mac_ctx->roam.configParam.early_stop_scan_min_threshold; + req_buf->early_stop_scan_max_threshold = + mac_ctx->roam.configParam.early_stop_scan_max_threshold; + req_buf->roamscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.roamscan_adaptive_dwell_mode; + req_buf->lca_config_params.disallow_duration = + mac_ctx->roam.configParam.disallow_duration; + req_buf->lca_config_params.rssi_channel_penalization = + mac_ctx->roam.configParam.rssi_channel_penalization; + req_buf->lca_config_params.num_disallowed_aps = + mac_ctx->roam.configParam.num_disallowed_aps; + + /* For RSO Stop, we need to notify FW to deinit BTM */ + if (command == ROAM_SCAN_OFFLOAD_STOP) + req_buf->btm_offload_config = 0; + else + req_buf->btm_offload_config = + mac_ctx->roam.configParam.btm_offload_config; + + req_buf->btm_solicited_timeout = + mac_ctx->roam.configParam.btm_solicited_timeout; + req_buf->btm_max_attempt_cnt = + mac_ctx->roam.configParam.btm_max_attempt_cnt; + req_buf->btm_sticky_time = + mac_ctx->roam.configParam.btm_sticky_time; + req_buf->rct_validity_timer = + mac_ctx->roam.configParam.btm_validity_timer; + req_buf->disassoc_timer_threshold = + mac_ctx->roam.configParam.btm_disassoc_timer_threshold; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("HomeAwayTime=%d EarlyStopFeature Enable=%d, MinThresh=%d, MaxThresh=%d PMK len=%d disallow_dur=%d rssi_chan_pen=%d num_disallowed_aps=%d"), + req_buf->HomeAwayTime, + req_buf->early_stop_scan_enable, + req_buf->early_stop_scan_min_threshold, + req_buf->early_stop_scan_max_threshold, + req_buf->pmk_len, + req_buf->lca_config_params.disallow_duration, + req_buf->lca_config_params.rssi_channel_penalization, + req_buf->lca_config_params.num_disallowed_aps); + req_buf->RoamOffloadEnabled = csr_roamIsRoamOffloadEnabled(mac_ctx); + req_buf->RoamKeyMgmtOffloadEnabled = session->RoamKeyMgmtOffloadEnabled; + req_buf->pmkid_modes = session->pmkid_modes; + /* Roam Offload piggybacks upon the Roam Scan offload command. */ + if (req_buf->RoamOffloadEnabled) + csr_update_roam_scan_offload_request(mac_ctx, req_buf, session); + qdf_mem_copy(&req_buf->roam_params, + &mac_ctx->roam.configParam.roam_params, + sizeof(req_buf->roam_params)); +#endif + return req_buf; +} + +/** + * csr_update_11k_offload_params - Update 11K offload params + * @mac_ctx: MAC context + * @session: Pointer to the CSR Roam Session + * @req_buffer: Pointer to the RSO Request buffer + * @enabled: 11k offload enabled/disabled. + * + * API to update 11k offload params to Roam Scan Offload request buffer + * + * Return: none + */ +static void csr_update_11k_offload_params(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, + tSirRoamOffloadScanReq *req_buffer, + bool enabled) +{ + struct wmi_11k_offload_params *params = &req_buffer->offload_11k_params; + struct csr_config *csr_config = &mac_ctx->roam.configParam; + struct csr_neighbor_report_offload_params *neighbor_report_offload = + &csr_config->neighbor_report_offload; + + params->vdev_id = session->sessionId; + + if (enabled) { + params->offload_11k_bitmask = + csr_config->offload_11k_enable_bitmask; + } else { + params->offload_11k_bitmask = 0; + sme_debug("11k offload disabled in RSO"); + 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) { + sme_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; + + params->neighbor_report_params.ssid.length = + session->connectedProfile.SSID.length; + qdf_mem_copy(params->neighbor_report_params.ssid.mac_ssid, + session->connectedProfile.SSID.ssId, + session->connectedProfile.SSID.length); + + sme_debug("Updated 11k offload params to RSO"); +} + +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) { + sme_err("Memory allocation failure"); + 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.mac_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; +} + +/** + * check_allowed_ssid_list() - Check the WhiteList + * @req_buffer: Buffer which contains the connected profile SSID. + * @roam_params: Buffer which contains the whitelist SSID's. + * + * Check if the connected profile SSID exists in the whitelist. + * It is assumed that the framework provides this also in the whitelist. + * If it exists there is no issue. Otherwise add it to the list. + * + * Return: None + */ +static void check_allowed_ssid_list(tSirRoamOffloadScanReq *req_buffer, + struct roam_ext_params *roam_params) +{ + int i = 0; + bool match = false; + + for (i = 0; i < roam_params->num_ssid_allowed_list; i++) { + if ((roam_params->ssid_allowed_list[i].length == + req_buffer->ConnectedNetwork.ssId.length) && + (!qdf_mem_cmp(roam_params->ssid_allowed_list[i].ssId, + req_buffer->ConnectedNetwork.ssId.ssId, + roam_params->ssid_allowed_list[i].length))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Whitelist contains connected profile SSID"); + match = true; + break; + } + } + if (!match) { + if (roam_params->num_ssid_allowed_list >= + MAX_SSID_ALLOWED_LIST) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Whitelist is FULL. Cannot Add another entry"); + return; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Adding Connected profile SSID to whitelist"); + /* i is the next available index to add the entry.*/ + i = roam_params->num_ssid_allowed_list; + qdf_mem_copy(roam_params->ssid_allowed_list[i].ssId, + req_buffer->ConnectedNetwork.ssId.ssId, + req_buffer->ConnectedNetwork.ssId.length); + roam_params->ssid_allowed_list[i].length = + req_buffer->ConnectedNetwork.ssId.length; + roam_params->num_ssid_allowed_list++; + } +} + +/** + * csr_add_rssi_reject_ap_list() - add rssi reject AP list to the + * roam params + * @mac_ctx: mac ctx. + * @roam_params: roam params in which reject AP list needs + * to be populated. + * + * Return: None + */ +static void csr_add_rssi_reject_ap_list(tpAniSirGlobal mac_ctx, + struct roam_ext_params *roam_params) +{ + int i = 0; + struct sir_rssi_disallow_lst *cur_node; + qdf_list_node_t *cur_list = NULL; + qdf_list_node_t *next_list = NULL; + struct rssi_disallow_bssid *rssi_rejection_ap; + qdf_list_t *list = &mac_ctx->roam.rssi_disallow_bssid; + qdf_time_t cur_time = + qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + + roam_params->num_rssi_rejection_ap = qdf_list_size(list); + + if (!qdf_list_size(list)) + return; + + if (roam_params->num_rssi_rejection_ap > MAX_RSSI_AVOID_BSSID_LIST) + roam_params->num_rssi_rejection_ap = MAX_RSSI_AVOID_BSSID_LIST; + + qdf_mutex_acquire(&mac_ctx->roam.rssi_disallow_bssid_lock); + qdf_list_peek_front(list, &cur_list); + while (cur_list) { + int32_t rem_time; + + rssi_rejection_ap = &roam_params->rssi_rejection_ap[i]; + cur_node = qdf_container_of(cur_list, + struct sir_rssi_disallow_lst, node); + rem_time = cur_node->retry_delay - + (cur_time - cur_node->time_during_rejection); + + if (rem_time > 0) { + qdf_copy_macaddr(&rssi_rejection_ap->bssid, + &cur_node->bssid); + rssi_rejection_ap->expected_rssi = + cur_node->expected_rssi; + rssi_rejection_ap->remaining_duration = rem_time; + i++; + } + qdf_list_peek_next(list, cur_list, &next_list); + cur_list = next_list; + next_list = NULL; + + if (i >= MAX_RSSI_AVOID_BSSID_LIST) + break; + } + qdf_mutex_release(&mac_ctx->roam.rssi_disallow_bssid_lock); + + for (i = 0; i < roam_params->num_rssi_rejection_ap; i++) { + sme_debug("BSSID %pM expected rssi %d remaining duration %d", + roam_params->rssi_rejection_ap[i].bssid.bytes, + roam_params->rssi_rejection_ap[i].expected_rssi, + roam_params->rssi_rejection_ap[i].remaining_duration); + } +} + +/* + * Below Table describe whether RSO command can be send down to fimrware or not. + * Host check it on the basis of previous RSO command sent down to firmware. + * ||=========================================================================|| + * || New cmd | LAST SENT COMMAND ---> || + * ||====|====================================================================|| + * || V | START | STOP | RESTART | UPDATE_CFG| ABORT_SCAN || + * || ------------------------------------------------------------------------|| + * || RSO_START | NO | YES | NO | YES | NO || + * || RSO_STOP | YES | YES | YES | YES | YES || + * || RSO_RESTART | YES | YES | NO | YES | YES || + * || RSO_UPDATE_CFG | YES | NO | YES | YES | YES || + * || RSO_ABORT_SCAN | YES | NO | YES | YES | YES || + * ||=========================================================================|| + **/ +#define RSO_START_BIT (1<roam.neighborRoamInfo[session_id]; + uint8_t desiredMask = 0; + bool ret_val; + + switch (command) { + case ROAM_SCAN_OFFLOAD_START: + desiredMask = RSO_START_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_STOP: + desiredMask = RSO_STOP_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_RESTART: + desiredMask = RSO_RESTART_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + desiredMask = RSO_UPDATE_CFG_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_ABORT_SCAN: + desiredMask = RSO_ABORT_SCAN_ALLOW_MASK; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + ("Wrong RSO command %d, not allowed"), command); + return 0;/*Cmd Not allowed*/ + } + ret_val = desiredMask & (1 << neigh_roam_info->last_sent_cmd); + return ret_val; +} + +/* + * csr_roam_send_rso_cmd() - API to send RSO command to PE + * @mac_ctx: Pointer to global MAC structure + * @session_id: Session ID + * @request_buf: Pointer to tSirRoamOffloadScanReq + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_roam_send_rso_cmd(tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirRoamOffloadScanReq *request_buf) +{ + QDF_STATUS status; + + request_buf->message_type = eWNI_SME_ROAM_SCAN_OFFLOAD_REQ; + request_buf->length = sizeof(*request_buf); + + status = umac_send_mb_message_to_mac(request_buf); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Send RSO from CSR failed"); + return status; + } + return QDF_STATUS_SUCCESS; +} + +/** + * csr_append_assoc_ies() - Append specific IE to assoc IE's buffer + * @mac_ctx: Pointer to global mac context + * @req_buf: 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 + */ +static void csr_append_assoc_ies(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf, uint8_t ie_id, + uint8_t ie_len, uint8_t *ie_data) +{ + tSirAddie *assoc_ie = &req_buf->assoc_ie; + + if ((SIR_MAC_MAX_ADD_IE_LENGTH - assoc_ie->length) < ie_len) { + sme_err("Appending IE id: %d fails", ie_id); + return; + } + assoc_ie->addIEdata[assoc_ie->length] = ie_id; + assoc_ie->addIEdata[assoc_ie->length + 1] = ie_len; + qdf_mem_copy(&assoc_ie->addIEdata[assoc_ie->length + 2], + ie_data, ie_len); + assoc_ie->length += (ie_len + 2); +} + +#ifdef FEATURE_WLAN_ESE +/** + * ese_populate_addtional_ies() - add IEs to reassoc frame + * @mac_ctx: Pointer to global mac structure + * @session: pointer to CSR session + * @req_buf: Pointer to Roam offload scan request + * + * This function populates the TSPEC ie and appends the info + * to assoc buffer. + * + * Return: None + */ +static void ese_populate_addtional_ies(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, + tSirRoamOffloadScanReq *req_buf) { + + 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; + + tspec_ie = (ese_wmm_tspec_ie *)(tspec_ie_buf + SIR_MAC_OUI_WME_HDR_MIN); + if (csr_is_wmm_supported(mac_ctx) && + mac_ctx->roam.configParam.isEseIniFeatureEnabled && + csr_roam_is_ese_assoc(mac_ctx, session->sessionId)) { + ese_tspec.numTspecs = sme_qos_ese_retrieve_tspec_info(mac_ctx, + session->sessionId, + (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); + csr_append_assoc_ies(mac_ctx, req_buf, + IEEE80211_ELEMID_VENDOR, + DOT11F_IE_WMMTSPEC_MAX_LEN, + tspec_ie_buf); + } + } + +} +#else +static inline void ese_populate_addtional_ies( + tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, tSirRoamOffloadScanReq *req_buf) { +} +#endif +/** + * csr_update_driver_assoc_ies() - Append driver built IE's to assoc IE's + * @mac_ctx: Pointer to global mac structure + * @session: pointer to CSR session + * @req_buf: Pointer to Roam offload scan request + * + * Return: None + */ +static void csr_update_driver_assoc_ies(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, + tSirRoamOffloadScanReq *req_buf) +{ + bool power_caps_populated = false; + uint32_t csr_11henable = WNI_CFG_11H_ENABLED_STADEF; + + uint8_t *rrm_cap_ie_data + = (uint8_t *) &mac_ctx->rrm.rrmPEContext.rrmEnabledCaps; + 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; + uint8_t supp_chan_ie[DOT11F_IE_SUPPCHANNELS_MAX_LEN], supp_chan_ie_len; + +#ifdef FEATURE_WLAN_ESE + uint8_t ese_ie[DOT11F_IE_ESEVERSION_MAX_LEN] + = { 0x0, 0x40, 0x96, 0x3, ESE_VERSION_SUPPORTED}; +#endif + uint8_t qcn_ie[DOT11F_IE_QCN_IE_MAX_LEN] + = {0x8C, 0xFD, 0xF0, 0x1, QCN_IE_VERSION_SUBATTR_ID, + QCN_IE_VERSION_SUBATTR_DATA_LEN, + QCN_IE_VERSION_SUPPORTED, + QCN_IE_SUBVERSION_SUPPORTED}; + + if (session->pConnectBssDesc) + max_tx_pwr_cap = csr_get_cfg_max_tx_power(mac_ctx, + session->pConnectBssDesc->channelId); + + 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; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &csr_11henable); + + if (csr_11henable && csr_is11h_supported(mac_ctx)) { + /* Append power cap IE */ + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_PWRCAP, + DOT11F_IE_POWERCAPS_MAX_LEN, + power_cap_ie_data); + power_caps_populated = true; + + /* Append Supported channels IE */ + csr_add_supported_5Ghz_channels(mac_ctx, supp_chan_ie, + &supp_chan_ie_len, true); + + csr_append_assoc_ies(mac_ctx, req_buf, + IEEE80211_ELEMID_SUPPCHAN, + supp_chan_ie_len, supp_chan_ie); + } + +#ifdef FEATURE_WLAN_ESE + /* Append ESE version IE if isEseIniFeatureEnabled INI is enabled */ + if (mac_ctx->roam.configParam.isEseIniFeatureEnabled) + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_VENDOR, + DOT11F_IE_ESEVERSION_MAX_LEN, + ese_ie); +#endif + + if (mac_ctx->rrm.rrmPEContext.rrmEnable) { + /* Append RRM IE */ + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_RRM, + DOT11F_IE_RRMENABLEDCAP_MAX_LEN, + rrm_cap_ie_data); + if (!power_caps_populated) + /* Append Power cap IE if not appended already */ + csr_append_assoc_ies(mac_ctx, req_buf, + IEEE80211_ELEMID_PWRCAP, + DOT11F_IE_POWERCAPS_MAX_LEN, + power_cap_ie_data); + } + ese_populate_addtional_ies(mac_ctx, session, req_buf); + + /* Append QCN IE if g_support_qcn_ie INI is enabled */ + if (mac_ctx->roam.configParam.qcn_ie_support) + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_VENDOR, + DOT11F_IE_QCN_IE_MAX_LEN, + qcn_ie); +} + +/** + * csr_create_per_roam_request() - create PER roam offload scan request + * + * parameters + * @mac_ctx: global mac ctx + * @session_id: session id + * + * Return: per roam config request packet buffer + */ +static struct wmi_per_roam_config_req * +csr_create_per_roam_request(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + struct wmi_per_roam_config_req *req_buf = NULL; + + req_buf = qdf_mem_malloc(sizeof(struct wmi_per_roam_config_req)); + if (!req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Mem alloc for per roam req failed"); + return NULL; + } + req_buf->vdev_id = session_id; + req_buf->per_config.enable = + mac_ctx->roam.configParam.per_roam_config.enable; + req_buf->per_config.tx_high_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.tx_high_rate_thresh; + req_buf->per_config.rx_high_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.rx_high_rate_thresh; + req_buf->per_config.tx_low_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.tx_low_rate_thresh; + req_buf->per_config.rx_low_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.rx_low_rate_thresh; + req_buf->per_config.per_rest_time = + mac_ctx->roam.configParam.per_roam_config.per_rest_time; + req_buf->per_config.tx_per_mon_time = + mac_ctx->roam.configParam.per_roam_config.tx_per_mon_time; + req_buf->per_config.rx_per_mon_time = + mac_ctx->roam.configParam.per_roam_config.rx_per_mon_time; + req_buf->per_config.tx_rate_thresh_percnt = + mac_ctx->roam.configParam.per_roam_config.tx_rate_thresh_percnt; + req_buf->per_config.rx_rate_thresh_percnt = + mac_ctx->roam.configParam.per_roam_config.rx_rate_thresh_percnt; + req_buf->per_config.min_candidate_rssi = + mac_ctx->roam.configParam.per_roam_config.min_candidate_rssi; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "PER based roaming configuaration 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_buf->per_config.enable, session_id, + req_buf->per_config.tx_high_rate_thresh, + req_buf->per_config.tx_low_rate_thresh, + req_buf->per_config.tx_rate_thresh_percnt, + req_buf->per_config.per_rest_time, + req_buf->per_config.tx_per_mon_time, + req_buf->per_config.min_candidate_rssi); + return req_buf; +} + +/** + * csr_roam_offload_per_scan() - populates roam offload scan request and sends + * to WMA + * + * parameters + * @mac_ctx: global mac ctx + * @session_id: session id + * + * Return: result of operation + */ +static QDF_STATUS +csr_roam_offload_per_scan(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + struct wmi_per_roam_config_req *req_buf; + struct scheduler_msg msg = {0}; + + /* + * No need to update in case of stop command, FW takes care of stopping + * this internally + */ + if (roam_info->last_sent_cmd == ROAM_SCAN_OFFLOAD_STOP) + return QDF_STATUS_SUCCESS; + + if (!mac_ctx->roam.configParam.per_roam_config.enable) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "PER based roaming is disabled in configuration"); + return QDF_STATUS_SUCCESS; + } + + req_buf = csr_create_per_roam_request(mac_ctx, session_id); + if (!req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to create req packet"); + return QDF_STATUS_E_FAILURE; + } + msg.type = WMA_SET_PER_ROAM_CONFIG_CMD; + msg.reserved = 0; + msg.bodyptr = req_buf; + if (!QDF_IS_STATUS_SUCCESS(scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Unable to post WMA_SET_PER_ROAM_CONFIG_CMD to WMA", + __func__); + qdf_mem_free(req_buf); + } + return QDF_STATUS_SUCCESS; +} + +#if defined(WLAN_FEATURE_FILS_SK) +QDF_STATUS csr_update_fils_config(tpAniSirGlobal mac, uint8_t session_id, + struct csr_roam_profile *src_profile) +{ + struct csr_roam_session *session = CSR_GET_SESSION(mac, session_id); + struct csr_roam_profile *dst_profile = NULL; + + if (!session) { + sme_err("session NULL"); + return QDF_STATUS_E_FAILURE; + } + + dst_profile = session->pCurRoamProfile; + + if (!dst_profile) { + sme_err("Current Roam profile of SME session NULL"); + return QDF_STATUS_E_FAILURE; + } + update_profile_fils_info(dst_profile, src_profile); + return QDF_STATUS_SUCCESS; +} + +/** + * copy_all_before_char() - API to copy all character before a particular char + * @str: Source string + * @str_len: Source string legnth + * @dst: Destination string + * @dst_len: Destination string legnth + * @c: Character before which all characters need to be copied + * + * Return: length of the copied string, if success. zero otherwise. + */ +static uint32_t copy_all_before_char(char *str, uint32_t str_len, + char *dst, uint32_t dst_len, char c) +{ + uint32_t len = 0; + + if (!str) + return len; + + while ((len < str_len) && (len < dst_len) && + (*str != '\0') && (*str != c)) { + *dst++ = *str++; + len++; + } + + return len; +} + +/** + * csr_update_fils_params_rso() - API to update FILS params in RSO + * @mac: Mac context + * @session: CSR Roam Session + * @req_buffer: RSO request buffer + * + * Return: None + */ +static void csr_update_fils_params_rso(tpAniSirGlobal mac, + struct csr_roam_session *session, + tSirRoamOffloadScanReq *req_buffer) +{ + struct roam_fils_params *roam_fils_params; + struct cds_fils_connection_info *fils_info; + uint32_t usr_name_len; + + if (!session->pCurRoamProfile) + return; + + fils_info = session->pCurRoamProfile->fils_con_info; + if (!fils_info || !req_buffer) + return; + + if (!fils_info->key_nai_length) { + sme_debug("key_nai_length is NULL"); + return; + } + + roam_fils_params = &req_buffer->roam_fils_params; + if ((fils_info->key_nai_length > FILS_MAX_KEYNAME_NAI_LENGTH) || + (fils_info->r_rk_length > FILS_MAX_RRK_LENGTH)) { + sme_err("Fils info len error: keyname nai len(%d) rrk len(%d)", + fils_info->key_nai_length, fils_info->r_rk_length); + return; + } + + usr_name_len = copy_all_before_char(fils_info->keyname_nai, + sizeof(fils_info->keyname_nai), + roam_fils_params->username, + sizeof(roam_fils_params->username), + '@'); + if (fils_info->key_nai_length <= usr_name_len) { + sme_err("Fils info len error: key nai len %d, user name len %d", + fils_info->key_nai_length, usr_name_len); + return; + } + + roam_fils_params->username_length = usr_name_len; + req_buffer->is_fils_connection = true; + + roam_fils_params->next_erp_seq_num = fils_info->sequence_number; + + roam_fils_params->rrk_length = fils_info->r_rk_length; + qdf_mem_copy(roam_fils_params->rrk, fils_info->r_rk, + roam_fils_params->rrk_length); + + /* REALM info */ + roam_fils_params->realm_len = fils_info->key_nai_length + - roam_fils_params->username_length - 1; + qdf_mem_copy(roam_fils_params->realm, fils_info->keyname_nai + + roam_fils_params->username_length + 1, + roam_fils_params->realm_len); + sme_debug("Fils: next_erp_seq_num %d rrk_len %d realm_len:%d", + roam_fils_params->next_erp_seq_num, + roam_fils_params->rrk_length, roam_fils_params->realm_len); +} +#else +static inline +void csr_update_fils_params_rso(tpAniSirGlobal mac, + struct csr_roam_session *session, + tSirRoamOffloadScanReq *req_buffer) +{} +#endif + +/** + * csr_update_score_params() - API to update Score params in RSO + * @mac_ctx: Mac context + * @req_buffer: RSO request buffer + * + * Return: None + */ +static void csr_update_score_params(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buffer) +{ + struct scoring_param *req_score_params; + struct rssi_scoring *req_rssi_score; + struct sir_score_config *bss_score_params; + struct sir_weight_config *weight_config; + struct sir_rssi_cfg_score *rssi_score; + + req_score_params = &req_buffer->score_params; + req_rssi_score = &req_score_params->rssi_scoring; + + bss_score_params = &mac_ctx->roam.configParam.bss_score_params; + weight_config = &bss_score_params->weight_cfg; + rssi_score = &bss_score_params->rssi_score; + + if (!bss_score_params->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->esp_qbss_weightage = + weight_config->channel_congestion_weightage; + req_score_params->beamforming_weightage = + weight_config->beamforming_cap_weightage; + req_score_params->pcl_weightage = + weight_config->pcl_weightage; + req_score_params->oce_wan_weightage = weight_config->oce_wan_weightage; + + req_score_params->bw_index_score = + bss_score_params->bandwidth_weight_per_index; + req_score_params->band_index_score = + bss_score_params->band_weight_per_index; + req_score_params->nss_index_score = + bss_score_params->nss_weight_per_index; + req_score_params->roam_score_delta = + bss_score_params->roam_score_delta; + req_score_params->roam_trigger_bitmap = + bss_score_params->roam_score_delta_bitmap; + + req_rssi_score->best_rssi_threshold = rssi_score->best_rssi_threshold; + req_rssi_score->good_rssi_threshold = rssi_score->good_rssi_threshold; + req_rssi_score->bad_rssi_threshold = rssi_score->bad_rssi_threshold; + req_rssi_score->good_rssi_pcnt = rssi_score->good_rssi_pcnt; + req_rssi_score->bad_rssi_pcnt = rssi_score->bad_rssi_pcnt; + req_rssi_score->good_bucket_size = rssi_score->good_rssi_bucket_size; + req_rssi_score->bad_bucket_size = rssi_score->bad_rssi_bucket_size; + req_rssi_score->rssi_pref_5g_rssi_thresh = + rssi_score->rssi_pref_5g_rssi_thresh; + + req_score_params->esp_qbss_scoring.num_slot = + bss_score_params->esp_qbss_scoring.num_slot; + req_score_params->esp_qbss_scoring.score_pcnt3_to_0 = + bss_score_params->esp_qbss_scoring.score_pcnt3_to_0; + req_score_params->esp_qbss_scoring.score_pcnt7_to_4 = + bss_score_params->esp_qbss_scoring.score_pcnt7_to_4; + req_score_params->esp_qbss_scoring.score_pcnt11_to_8 = + bss_score_params->esp_qbss_scoring.score_pcnt11_to_8; + req_score_params->esp_qbss_scoring.score_pcnt15_to_12 = + bss_score_params->esp_qbss_scoring.score_pcnt15_to_12; + + req_score_params->oce_wan_scoring.num_slot = + bss_score_params->oce_wan_scoring.num_slot; + req_score_params->oce_wan_scoring.score_pcnt3_to_0 = + bss_score_params->oce_wan_scoring.score_pcnt3_to_0; + req_score_params->oce_wan_scoring.score_pcnt7_to_4 = + bss_score_params->oce_wan_scoring.score_pcnt7_to_4; + req_score_params->oce_wan_scoring.score_pcnt11_to_8 = + bss_score_params->oce_wan_scoring.score_pcnt11_to_8; + req_score_params->oce_wan_scoring.score_pcnt15_to_12 = + bss_score_params->oce_wan_scoring.score_pcnt15_to_12; +} + +uint8_t csr_get_roam_enabled_sta_sessionid(tpAniSirGlobal mac_ctx) +{ + struct csr_roam_session *session; + tpCsrNeighborRoamControlInfo roam_info; + uint8_t i; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + session = CSR_GET_SESSION(mac_ctx, i); + if (!session || !CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + if (!session->pCurRoamProfile || + session->pCurRoamProfile->csrPersona != QDF_STA_MODE) + continue; + roam_info = &mac_ctx->roam.neighborRoamInfo[i]; + if (roam_info->b_roam_scan_offload_started) { + sme_debug("Roaming enabled on iface, session: %d", i); + return i; + } + } + + return CSR_SESSION_ID_INVALID; +} + +/** + * csr_roam_offload_scan() - populates roam offload scan request and sends to + * WMA + * + * parameters + * @mac_ctx: global mac ctx + * @session_id: session id + * @command: roam scan offload command input + * @reason: reason to roam + * + * Return: result of operation + */ +QDF_STATUS +csr_roam_offload_scan(tpAniSirGlobal mac_ctx, uint8_t session_id, + uint8_t command, uint8_t reason) +{ + uint8_t *state = NULL; + tSirRoamOffloadScanReq *req_buf; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + tpCsrNeighborRoamControlInfo roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + struct roam_ext_params *roam_params_dst; + struct roam_ext_params *roam_params_src; + uint8_t i, temp_session_id; + uint8_t op_channel; + bool prev_roaming_state; + + sme_debug("RSO Command %d, Session id %d, Reason %d", command, + session_id, reason); + if (NULL == session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "session is null"); + return QDF_STATUS_E_FAILURE; + } + + temp_session_id = csr_get_roam_enabled_sta_sessionid(mac_ctx); + if ((temp_session_id != CSR_SESSION_ID_INVALID) && + (session_id != temp_session_id)) { + sme_debug("Roam cmd not for session %d on which roaming is enabled", + temp_session_id); + return QDF_STATUS_E_FAILURE; + } + + if ((command == ROAM_SCAN_OFFLOAD_START || + command == ROAM_SCAN_OFFLOAD_UPDATE_CFG) && + (session->pCurRoamProfile && + session->pCurRoamProfile->driver_disabled_roaming)) { + if (reason == REASON_DRIVER_ENABLED) { + session->pCurRoamProfile->driver_disabled_roaming = + false; + sme_debug("driver_disabled_roaming reset for session %d", + session_id); + } else { + sme_debug("Roam start received for session %d on which driver has disabled roaming", + session_id); + return QDF_STATUS_E_FAILURE; + } + } + + if ((ROAM_SCAN_OFFLOAD_START == command && + REASON_CTX_INIT != reason) && + (session->pCurRoamProfile && + session->pCurRoamProfile->supplicant_disabled_roaming)) { + sme_debug("Supplicant disabled driver roaming"); + return QDF_STATUS_E_FAILURE; + } + + if (0 == csr_roam_is_roam_offload_scan_enabled(mac_ctx)) { + sme_err("isRoamOffloadScanEnabled not set"); + return QDF_STATUS_E_FAILURE; + } + if (!csr_is_RSO_cmd_allowed(mac_ctx, command, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + ("RSO out-of-sync command %d lastSentCmd %d"), + command, roam_info->last_sent_cmd); + return QDF_STATUS_E_FAILURE; + } + + if ((true == roam_info->b_roam_scan_offload_started) + && (ROAM_SCAN_OFFLOAD_START == command)) { + sme_err("Roam Scan Offload is already started"); + return QDF_STATUS_E_FAILURE; + } + + /* Roaming is not supported currently for FILS akm */ + if (session->pCurRoamProfile && CSR_IS_AUTH_TYPE_FILS( + session->pCurRoamProfile->AuthType.authType[0]) && + !mac_ctx->is_fils_roaming_supported) { + sme_info("FILS Roaming not suppprted by fw"); + return QDF_STATUS_SUCCESS; + } + + /* Roaming is not supported currently for OWE akm */ + if (session->pCurRoamProfile && + (session->pCurRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_OWE)) { + sme_info("OWE Roaming not suppprted by fw"); + return QDF_STATUS_SUCCESS; + } + + /* Roaming is not supported currently for SAE authentication */ + if (session->pCurRoamProfile && + CSR_IS_AUTH_TYPE_SAE( + session->pCurRoamProfile->AuthType.authType[0])) { + sme_info("Roaming not suppprted for SAE connection"); + return QDF_STATUS_SUCCESS; + } + + /* + * 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_BLACKLIST_BSSID, + * because we need to inform firmware of blacklisted AP for PNO in + * all states. + */ + + if ((roam_info->neighborRoamState == + eCSR_NEIGHBOR_ROAM_STATE_INIT) && + (command != ROAM_SCAN_OFFLOAD_STOP) && + (reason != REASON_ROAM_SET_BLACKLIST_BSSID)) { + state = mac_trace_get_neighbour_roam_state( + roam_info->neighborRoamState); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Scan Command not sent to FW state=%s and cmd=%d"), + state, command); + return QDF_STATUS_E_FAILURE; + } + + req_buf = csr_create_roam_scan_offload_request(mac_ctx, command, + session_id, reason, + session, roam_info); + if (!req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to create req packet"); + return QDF_STATUS_E_FAILURE; + } + roam_params_dst = &req_buf->roam_params; + roam_params_src = &mac_ctx->roam.configParam.roam_params; + if (reason == REASON_ROAM_SET_SSID_ALLOWED) + check_allowed_ssid_list(req_buf, roam_params_src); + + /* + * 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. + */ + csr_add_rssi_reject_ap_list(mac_ctx, roam_params_src); + + /* + * Configure the lookup threshold either from INI or from framework. + * If both are present, give higher priority to the one from framework. + */ + if (roam_params_src->alert_rssi_threshold) + req_buf->LookupThreshold = + roam_params_src->alert_rssi_threshold; + else + req_buf->LookupThreshold = + (int8_t)roam_info->cfgParams.neighborLookupThreshold * + (-1); + req_buf->rssi_thresh_offset_5g = + roam_info->cfgParams.rssi_thresh_offset_5g; + sme_debug("5g offset threshold: %d", req_buf->rssi_thresh_offset_5g); + qdf_mem_copy(roam_params_dst, roam_params_src, + sizeof(*roam_params_dst)); + /* + * rssi_diff which is updated via framework is equivalent to the + * INI RoamRssiDiff parameter and hence should be updated. + */ + if (roam_params_src->rssi_diff) + req_buf->RoamRssiDiff = roam_params_src->rssi_diff; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "num_bssid_avoid_list: %d num_ssid_allowed_list: %d num_bssid_favored: %d raise_rssi_thresh_5g: %d drop_rssi_thresh_5g: %d raise_rssi_type_5g: %d raise_factor_5g: %d drop_rssi_type_5g: %d drop_factor_5g: %d max_raise_rssi_5g: %d max_drop_rssi_5g: %d rssi_diff: %d alert_rssi_threshold: %d", + roam_params_dst->num_bssid_avoid_list, + roam_params_dst->num_ssid_allowed_list, + roam_params_dst->num_bssid_favored, + roam_params_dst->raise_rssi_thresh_5g, + roam_params_dst->drop_rssi_thresh_5g, + roam_params_dst->raise_rssi_type_5g, + roam_params_dst->raise_factor_5g, + roam_params_dst->drop_rssi_type_5g, + roam_params_dst->drop_factor_5g, + roam_params_dst->max_raise_rssi_5g, + roam_params_dst->max_drop_rssi_5g, + req_buf->RoamRssiDiff, roam_params_dst->alert_rssi_threshold); + + /* Set initial dense roam status */ + if (mac_ctx->scan.roam_candidate_count[session_id] > + roam_params_dst->dense_min_aps_cnt) + roam_params_dst->initial_dense_status = true; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "dense_rssi_thresh_offset: %d, dense_min_aps_cnt:%d, traffic_threshold:%d, " + "initial_dense_status:%d, candidate count:%d", + roam_params_dst->dense_rssi_thresh_offset, + roam_params_dst->dense_min_aps_cnt, + roam_params_dst->traffic_threshold, + roam_params_dst->initial_dense_status, + mac_ctx->scan.roam_candidate_count[session_id]); + sme_debug("BG Scan Bad RSSI:%d, bitmap:0x%x Offset for 2G to 5G Roam %d", + roam_params_dst->bg_scan_bad_rssi_thresh, + roam_params_dst->bg_scan_client_bitmap, + roam_params_dst->roam_bad_rssi_thresh_offset_2g); + + for (i = 0; i < roam_params_dst->num_bssid_avoid_list; i++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Blacklist Bssid:"MAC_ADDRESS_STR")", + MAC_ADDR_ARRAY(roam_params_dst->bssid_avoid_list[i]. + bytes)); + } + for (i = 0; i < roam_params_dst->num_ssid_allowed_list; i++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Whitelist: %.*s", + roam_params_dst->ssid_allowed_list[i].length, + roam_params_dst->ssid_allowed_list[i].ssId); + } + for (i = 0; i < roam_params_dst->num_bssid_favored; i++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Preferred Bssid:"MAC_ADDRESS_STR") score: %d", + MAC_ADDR_ARRAY(roam_params_dst->bssid_favored[i].bytes), + roam_params_dst->bssid_favored_factor[i]); + } + + op_channel = session->connectedProfile.operationChannel; + req_buf->hi_rssi_scan_max_count = + roam_info->cfgParams.hi_rssi_scan_max_count; + req_buf->hi_rssi_scan_delay = + roam_info->cfgParams.hi_rssi_scan_delay; + req_buf->hi_rssi_scan_rssi_ub = + roam_info->cfgParams.hi_rssi_scan_rssi_ub; + /* + * 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 (session->disable_hi_rssi) + req_buf->hi_rssi_scan_rssi_delta = 0; + else + req_buf->hi_rssi_scan_rssi_delta = + roam_info->cfgParams.hi_rssi_scan_rssi_delta; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "hi_rssi:delta=%d, max_count=%d, delay=%d, ub=%d", + req_buf->hi_rssi_scan_rssi_delta, + req_buf->hi_rssi_scan_max_count, + req_buf->hi_rssi_scan_delay, + req_buf->hi_rssi_scan_rssi_ub); + + if (command != ROAM_SCAN_OFFLOAD_STOP) { + req_buf->assoc_ie.length = session->nAddIEAssocLength; + qdf_mem_copy(req_buf->assoc_ie.addIEdata, + session->pAddIEAssoc, + session->nAddIEAssocLength); + csr_update_driver_assoc_ies(mac_ctx, session, req_buf); + csr_update_score_params(mac_ctx, req_buf); + csr_update_fils_params_rso(mac_ctx, session, req_buf); + } + + /* + * 11k offload is enabled during RSO Start after connect indication and + * 11k offload is disabled during RSO Stop after disconnect indication + */ + if (command == ROAM_SCAN_OFFLOAD_START) + csr_update_11k_offload_params(mac_ctx, session, req_buf, TRUE); + else if (command == ROAM_SCAN_OFFLOAD_STOP) + csr_update_11k_offload_params(mac_ctx, session, req_buf, FALSE); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Assoc IE buffer:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + req_buf->assoc_ie.addIEdata, req_buf->assoc_ie.length); + + prev_roaming_state = roam_info->b_roam_scan_offload_started; + if (ROAM_SCAN_OFFLOAD_START == command) + roam_info->b_roam_scan_offload_started = true; + else if (ROAM_SCAN_OFFLOAD_STOP == command) + roam_info->b_roam_scan_offload_started = false; + policy_mgr_set_pcl_for_existing_combo(mac_ctx->psoc, PM_STA_MODE); + + if (!QDF_IS_STATUS_SUCCESS( + csr_roam_send_rso_cmd(mac_ctx, session_id, req_buf))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post message to PE", + __func__); + roam_info->b_roam_scan_offload_started = prev_roaming_state; + policy_mgr_set_pcl_for_existing_combo(mac_ctx->psoc, + PM_STA_MODE); + return QDF_STATUS_E_FAILURE; + } + /* update the last sent cmd */ + roam_info->last_sent_cmd = command; + + /* Update PER config to FW after sending the command */ + csr_roam_offload_per_scan(mac_ctx, session_id); + return status; +} + +QDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp + scanOffloadRsp) +{ + switch (scanOffloadRsp->reason) { + case 0: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Rsp for Roam Scan Offload with failure status"); + break; + case REASON_OS_REQUESTED_ROAMING_NOW: + csr_neighbor_roam_proceed_with_handoff_req(pMac, + scanOffloadRsp->sessionId); + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Rsp for Roam Scan Offload with reason %d", + scanOffloadRsp->reason); + } + return QDF_STATUS_SUCCESS; +} +#endif + +#ifndef QCA_SUPPORT_CP_STATS +/* pStaEntry is no longer invalid upon the return of this function. */ +static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, + tListElem *pEntry) +{ + if (pEntry) { + if (csr_ll_remove_entry(&pMac->roam.statsClientReqList, + pEntry, LL_ACCESS_LOCK)) + qdf_mem_free(GET_BASE_ADDR(pEntry, + struct csr_statsclient_reqinfo, link)); + } +} + +static void csr_roam_remove_entry_from_pe_stats_req_list( +tpAniSirGlobal pMac, struct csr_pestats_reqinfo *pPeStaEntry) +{ + tListElem *pEntry; + struct csr_pestats_reqinfo *pTempStaEntry; + + pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK); + if (!pEntry) { + sme_err("List empty, no stats req for PE"); + return; + } + while (pEntry) { + pTempStaEntry = GET_BASE_ADDR(pEntry, + struct csr_pestats_reqinfo, link); + if (NULL == pTempStaEntry + || (pTempStaEntry->statsMask != + pPeStaEntry->statsMask)) { + pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + continue; + } + sme_debug("Match found"); + if (csr_ll_remove_entry(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_LOCK)) { + qdf_mem_free(pTempStaEntry); + pTempStaEntry = NULL; + break; + } + pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + } /* end of while loop */ +} + +static void csr_roam_report_statistics(tpAniSirGlobal pMac, + uint32_t statsMask, + tCsrStatsCallback callback, uint8_t staId, + void *pContext) +{ + uint8_t stats[500]; + uint8_t *pStats = NULL; + uint32_t tempMask = 0; + uint8_t counter = 0; + + if (!callback) { + sme_err("Cannot report callback NULL"); + return; + } + if (!statsMask) { + sme_err("Cannot report statsMask is 0"); + return; + } + pStats = stats; + tempMask = statsMask; + while (tempMask) { + if (tempMask & 1) { + /* new stats info from PE, fill up the stats + * strucutres in PMAC + */ + switch (counter) { + case eCsrSummaryStats: + sme_debug("Summary stats"); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + summaryStatsInfo, + sizeof(tCsrSummaryStatsInfo)); + pStats += sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + sme_debug("ClassA stats"); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classAStatsInfo, + sizeof(tCsrGlobalClassAStatsInfo)); + pStats += sizeof(tCsrGlobalClassAStatsInfo); + break; + case eCsrGlobalClassDStats: + sme_debug("ClassD stats"); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classDStatsInfo, + sizeof(tCsrGlobalClassDStatsInfo)); + pStats += sizeof(tCsrGlobalClassDStatsInfo); + break; + case csr_per_chain_rssi_stats: + sme_debug("Per Chain RSSI stats"); + qdf_mem_copy(pStats, + (uint8_t *)&pMac->roam.per_chain_rssi_stats, + sizeof(struct csr_per_chain_rssi_stats_info)); + pStats += sizeof( + struct csr_per_chain_rssi_stats_info); + break; + default: + sme_err( + "Unknown stats type and counter %d", + counter); + break; + } + } + tempMask >>= 1; + counter++; + } + callback(stats, pContext); +} + +static QDF_STATUS csr_roam_dereg_statistics_req( + tpAniSirGlobal pMac) +{ + tListElem *pEntry = NULL; + tListElem *pPrevEntry = NULL; + struct csr_statsclient_reqinfo *pTempStaEntry = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, + LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sme_debug("List empty, no request from upper layer client(s)"); + return status; + } + while (pEntry) { + if (pPrevEntry) { + pTempStaEntry = + GET_BASE_ADDR(pPrevEntry, + struct csr_statsclient_reqinfo, link); + /* send up the stats report */ + csr_roam_report_statistics(pMac, + pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + csr_roam_remove_stat_list_entry(pMac, pPrevEntry); + } + pTempStaEntry = + GET_BASE_ADDR(pEntry, struct csr_statsclient_reqinfo, link); + if (pTempStaEntry->pPeStaEntry) { + /* pPeStaEntry can be NULL */ + pTempStaEntry->pPeStaEntry->numClient--; + /* check if we need to delete the entry from + * peStatsReqList too + */ + if (!pTempStaEntry->pPeStaEntry->numClient) { + csr_roam_remove_entry_from_pe_stats_req_list( + pMac, + pTempStaEntry-> + pPeStaEntry); + } + } + /* check if we need to stop the tl stats timer too */ + pMac->roam.tlStatsReqInfo.numClient--; + pPrevEntry = pEntry; + pEntry = csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + /* the last one */ + if (pPrevEntry) { + pTempStaEntry = + GET_BASE_ADDR(pPrevEntry, struct csr_statsclient_reqinfo, link); + /* send up the stats report */ + csr_roam_report_statistics(pMac, pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + csr_roam_remove_stat_list_entry(pMac, pPrevEntry); + } + return status; + +} +#endif /* QCA_SUPPORT_CP_STATS */ + +tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac) +{ + tSmeCmd *pCmd = sme_get_command_buffer(pMac); + + if (pCmd) + pMac->roam.sPendingCommands++; + + return pCmd; +} + +static void csr_free_cmd_memory(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + if (!pCommand) { + sme_err("pCommand is NULL"); + return; + } + switch (pCommand->command) { + case eSmeCommandRoam: + csr_release_command_roam(pMac, pCommand); + break; + case eSmeCommandWmStatusChange: + csr_release_command_wm_status_change(pMac, pCommand); + break; + case e_sme_command_set_hw_mode: + csr_release_command_set_hw_mode(pMac, pCommand); + default: + break; + } +} + +void csr_release_command_buffer(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + if (pMac->roam.sPendingCommands > 0) { + /* + * All command allocated through csr_get_command_buffer + * need to decrement the pending count when releasing + */ + pMac->roam.sPendingCommands--; + csr_free_cmd_memory(pMac, pCommand); + sme_release_command(pMac, pCommand); + } else { + sme_err("no pending commands"); + QDF_ASSERT(0); + } +} + +void csr_release_command(tpAniSirGlobal 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->sessionId, WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("Invalid vdev"); + return; + } + qdf_mem_zero(&cmd_info, + sizeof(struct wlan_serialization_queued_cmd_info)); + + sme_debug("filled cmd_id = %d", sme_cmd->cmd_id); + 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)) { + sme_debug("Releasing active cmd_id[%d] cmd_type[%d]", + cmd_info.cmd_id, cmd_info.cmd_type); + wlan_serialization_remove_cmd(&cmd_info); + } else if (wlan_serialization_is_cmd_present_in_pending_queue( + mac_ctx->psoc, &cmd)) { + sme_debug("Releasing pending cmd_id[%d] cmd_type[%d]", + cmd_info.cmd_id, cmd_info.cmd_type); + 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 eCsrForcedDisassoc: + cmd_type = WLAN_SER_CMD_FORCE_DISASSOC; + break; + case eCsrHddIssued: + cmd_type = WLAN_SER_CMD_HDD_ISSUED; + break; + case eCsrForcedDisassocMICFailure: + cmd_type = WLAN_SER_CMD_FORCE_DISASSOC_MIC_FAIL; + break; + case eCsrHddIssuedReassocToSameAP: + cmd_type = WLAN_SER_CMD_HDD_ISSUE_REASSOC_SAME_AP; + break; + case eCsrSmeIssuedReassocToSameAP: + cmd_type = WLAN_SER_CMD_SME_ISSUE_REASSOC_SAME_AP; + break; + case eCsrForcedDeauth: + cmd_type = WLAN_SER_CMD_FORCE_DEAUTH; + break; + case eCsrSmeIssuedDisassocForHandoff: + cmd_type = + WLAN_SER_CMD_SME_ISSUE_DISASSOC_FOR_HANDOFF; + break; + case eCsrSmeIssuedAssocToSimilarAP: + cmd_type = + WLAN_SER_CMD_SME_ISSUE_ASSOC_TO_SIMILAR_AP; + break; + case eCsrForcedIbssLeave: + cmd_type = WLAN_SER_CMD_FORCE_IBSS_LEAVE; + break; + case eCsrStopBss: + cmd_type = WLAN_SER_CMD_STOP_BSS; + break; + case eCsrSmeIssuedFTReassoc: + cmd_type = WLAN_SER_CMD_SME_ISSUE_FT_REASSOC; + break; + case eCsrForcedDisassocSta: + cmd_type = WLAN_SER_CMD_FORCE_DISASSOC_STA; + break; + case eCsrForcedDeauthSta: + cmd_type = WLAN_SER_CMD_FORCE_DEAUTH_STA; + break; + case eCsrPerformPreauth: + cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH; + 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 e_sme_command_del_sta_session: + cmd_type = WLAN_SER_CMD_DEL_STA_SESSION; + 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; + default: + break; + } + + return cmd_type; +} + +static uint32_t csr_get_monotonous_number(tpAniSirGlobal 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; +} + +QDF_STATUS csr_set_serialization_params_to_cmd(tpAniSirGlobal 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; + sme_debug("cmd_id = %d", cmd->cmd_id); + + cmd->cmd_type = csr_get_cmd_type(sme_cmd); + sme_debug("filled cmd_type[%d] cmd_id[%d]", + cmd->cmd_type, cmd->cmd_id); + if (cmd->cmd_type == WLAN_SER_CMD_MAX) { + sme_err("serialization enum not found"); + return status; + } + cmd->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + sme_cmd->sessionId, WLAN_LEGACY_SME_ID); + if (!cmd->vdev) { + sme_err("vdev is NULL for sme_session:%d", sme_cmd->sessionId); + return status; + } + cmd->umac_cmd = sme_cmd; + + /* + * For START BSS and STOP BSS commands for SAP, the command timeout + * is set to 10 seconds. For all other commands its 30 seconds + */ + if ((cmd->vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE) && + ((cmd->cmd_type == WLAN_SER_CMD_HDD_ISSUED) || + (cmd->cmd_type == WLAN_SER_CMD_STOP_BSS))) + cmd->cmd_timeout_duration = SME_START_STOP_BSS_CMD_TIMEOUT; + else if (cmd->cmd_type == WLAN_SER_CMD_DEL_STA_SESSION) + cmd->cmd_timeout_duration = SME_VDEV_DELETE_CMD_TIMEOUT; + else + cmd->cmd_timeout_duration = SME_DEFAULT_CMD_TIMEOUT; + + cmd->cmd_cb = sme_ser_cmd_callback; + cmd->is_high_priority = high_priority; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_queue_sme_command(tpAniSirGlobal 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; + } + + if (CSR_IS_WAIT_FOR_KEY(mac_ctx, sme_cmd->sessionId)) { + if (!CSR_IS_DISCONNECT_COMMAND(sme_cmd)) { + sme_err("Can't process cmd(%d), waiting for key", + sme_cmd->command); + 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); + sme_debug("wlan_serialization_request status:%d", ser_cmd_status); + + 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; + 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; + default: + QDF_ASSERT(0); + 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(tpAniSirGlobal 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 (NULL == 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 (NULL == msg) { + sme_err("malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + msg->messageType = eWNI_SME_UPDATE_CONFIG; + msg->sme_session_id = session_id; + msg->capab = capab; + msg->value = value; + msg->length = sizeof(*msg); + status = umac_send_mb_message_to_mac(msg); + + return status; +} + +/* + * pBuf points to the beginning of the message + * LIM packs disassoc rsp as below, + * messageType - 2 bytes + * messageLength - 2 bytes + * sessionId - 1 byte + * transactionId - 2 bytes (uint16_t) + * reasonCode - 4 bytes (sizeof(tSirResultCodes)) + * peerMacAddr - 6 bytes + * The rest is conditionally defined of (WNI_POLARIS_FW_PRODUCT == AP) + * and not used + */ +static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf, tSirSmeDisassocRsp + *pRsp) +{ + if (pBuf && pRsp) { + pBuf += 4; /* skip type and length */ + pRsp->sessionId = *pBuf++; + qdf_get_u16(pBuf, (uint16_t *) &pRsp->transactionId); + pBuf += 2; + qdf_get_u32(pBuf, (uint32_t *) &pRsp->statusCode); + pBuf += 4; + qdf_mem_copy(pRsp->peer_macaddr.bytes, pBuf, QDF_MAC_ADDR_SIZE); + } +} + +/* Returns whether a session is in QDF_STA_MODE...or not */ +bool csr_roam_is_sta_mode(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = NULL; + + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return false; + } + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sme_err("Inactive session_id: %d", sessionId); + return false; + } + if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) + return false; + /* There is a possibility that the above check may fail,because + * P2P CLI also uses the same BSSType (eCSR_BSS_TYPE_INFRASTRUCTURE) + * when it is connected.So,we may sneak through the above check even + * if we are not a STA mode INFRA station. So, if we sneak through + * the above condition, we can use the following check if we are + * really in STA Mode. + */ + + if (NULL != pSession->pCurRoamProfile) { + if (pSession->pCurRoamProfile->csrPersona == QDF_STA_MODE) + return true; + else + return false; + } + + return false; +} + +QDF_STATUS csr_handoff_request(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0}; + + tAniHandoffReq *pMsg; + + pMsg = qdf_mem_malloc(sizeof(tAniHandoffReq)); + if (NULL == pMsg) { + sme_err("csr_handoff_request: failed to allocate mem for req "); + return QDF_STATUS_E_NOMEM; + } + pMsg->msgType = eWNI_SME_HANDOFF_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniHandoffReq); + pMsg->sessionId = sessionId; + pMsg->channel = pHandoffInfo->channel; + pMsg->handoff_src = pHandoffInfo->src; + qdf_mem_copy(pMsg->bssid, pHandoffInfo->bssid.bytes, QDF_MAC_ADDR_SIZE); + msg.type = eWNI_SME_HANDOFF_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)) { + sme_err("scheduler_post_msg failed to post msg to self"); + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +/** + * csr_roam_channel_change_req() - Post channel change request to LIM + * @pMac: mac context + * @bssid: SAP bssid + * @ch_params: channel information + * @profile: CSR profile + * + * This API is primarily used to post Channel Change Req for SAP + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_roam_channel_change_req(tpAniSirGlobal pMac, + struct qdf_mac_addr bssid, + struct ch_params *ch_params, + struct csr_roam_profile *profile) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirChanChangeRequest *pMsg; + struct csr_roamstart_bssparams param; + bool skip_hostapd_rate = !profile->chan_switch_hostapd_rate_enabled; + + /* + * while changing the channel, use basic rates given by driver + * and not by hostapd as there is a chance that hostapd might + * give us rates based on original channel which may not be + * suitable for new channel + */ + qdf_mem_zero(¶m, sizeof(struct csr_roamstart_bssparams)); + + status = csr_roam_get_bss_start_parms(pMac, profile, ¶m, + skip_hostapd_rate); + + if (status != QDF_STATUS_SUCCESS) { + sme_err("Failed to get bss parameters"); + return status; + } + + pMsg = qdf_mem_malloc(sizeof(tSirChanChangeRequest)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_CHANNEL_CHANGE_REQ; + pMsg->messageLen = sizeof(tSirChanChangeRequest); + pMsg->targetChannel = profile->ChannelInfo.ChannelList[0]; + pMsg->sec_ch_offset = ch_params->sec_ch_offset; + pMsg->ch_width = profile->ch_params.ch_width; + pMsg->dot11mode = csr_translate_to_wni_cfg_dot11_mode(pMac, + param.uCfgDot11Mode); + if (IS_24G_CH(pMsg->targetChannel) && + (false == pMac->roam.configParam.enableVhtFor24GHz) && + (WNI_CFG_DOT11_MODE_11AC == pMsg->dot11mode || + WNI_CFG_DOT11_MODE_11AC_ONLY == pMsg->dot11mode)) + pMsg->dot11mode = WNI_CFG_DOT11_MODE_11N; + pMsg->nw_type = param.sirNwType; + pMsg->center_freq_seg_0 = ch_params->center_freq_seg0; + pMsg->center_freq_seg_1 = ch_params->center_freq_seg1; + pMsg->cac_duration_ms = profile->cac_duration_ms; + pMsg->dfs_regdomain = profile->dfs_regdomain; + qdf_mem_copy(pMsg->bssid, bssid.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&pMsg->operational_rateset, + ¶m.operationalRateSet, sizeof(pMsg->operational_rateset)); + qdf_mem_copy(&pMsg->extended_rateset, + ¶m.extendedRateSet, sizeof(pMsg->extended_rateset)); + + sme_debug("target_chan %d ch_width %d dot11mode %d", + pMsg->targetChannel, pMsg->ch_width, pMsg->dot11mode); + status = umac_send_mb_message_to_mac(pMsg); + + 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(tpAniSirGlobal pMac, + 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 + * + * @pMac: pMac global structure + * @pModifyIE: pointer to tSirModifyIE structure + * @updateType: Type of buffer + * + * + * Return: QDF_STATUS - Success or failure + */ +QDF_STATUS +csr_roam_modify_add_ies(tpAniSirGlobal pMac, + 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 (NULL == pLocalBuffer) { + sme_err("Memory Allocation Failure!!!"); + return QDF_STATUS_E_NOMEM; + } + + pModifyAddIEInd = qdf_mem_malloc(sizeof(tSirModifyIEsInd)); + if (NULL == pModifyAddIEInd) { + sme_err("Memory Allocation Failure!!!"); + 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.smeSessionId = pModifyIE->smeSessionId; + 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 + * + * @pMac: pMac 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(tpAniSirGlobal pMac, + 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 (NULL == pLocalBuffer) { + sme_err("Memory Allocation Failure!!!"); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pLocalBuffer, pUpdateIE->pAdditionIEBuffer, + pUpdateIE->ieBufferlength); + } + + pUpdateAddIEs = qdf_mem_malloc(sizeof(tSirUpdateIEsInd)); + if (NULL == pUpdateAddIEs) { + sme_err("Memory Allocation Failure!!!"); + if (pLocalBuffer != NULL) + 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.smeSessionId = pUpdateIE->smeSessionId; + 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_channel()- function to post send ECSA + * action frame to lim. + * @mac_ctx: pointer to global mac structure + * @channel: new channel 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_channel(tpAniSirGlobal mac_ctx, uint32_t channel, + 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 (NULL == msg) + return QDF_STATUS_E_NOMEM; + + msg->message_type = eWNI_SME_EXT_CHANGE_CHANNEL; + msg->length = sizeof(*msg); + msg->new_channel = channel; + msg->session_id = session_id; + status = umac_send_mb_message_to_mac(msg); + return status; +} + +/** + * csr_roam_send_chan_sw_ie_request() - Request to transmit CSA IE + * @mac_ctx: Global MAC context + * @bssid: BSSID + * @target_channel: Channel on which to send the IE + * @csa_ie_reqd: Include/Exclude CSA IE. + * @ch_params: operating Channel related information + * + * 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(tpAniSirGlobal mac_ctx, + struct qdf_mac_addr bssid, + uint8_t target_channel, + uint8_t csa_ie_reqd, + struct ch_params *ch_params) +{ + 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->targetChannel = target_channel; + msg->csaIeRequired = csa_ie_reqd; + msg->ch_switch_beacon_cnt = + mac_ctx->sap.SapDfsInfo.sap_ch_switch_beacon_cnt; + 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; + 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; +} +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +/** + * csr_roaming_report_diag_event() - Diag events for LFR3 + * @mac_ctx: MAC context + * @roam_synch_ind_ptr: Roam Synch Indication Pointer + * @reason: Reason for this event to happen + * + * The major events in the host for LFR3 roaming such as + * roam synch indication, roam synch completion and + * roam synch handoff fail will be indicated to the + * diag framework using this API. + * + * Return: None + */ +void csr_roaming_report_diag_event(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_ind_ptr, + enum csr_diagwlan_status_eventreason reason) +{ + 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)); + switch (reason) { + case eCSR_REASON_ROAM_SYNCH_IND: + roam_connection.eventId = eCSR_WLAN_STATUS_CONNECT; + if (roam_synch_ind_ptr) { + roam_connection.rssi = roam_synch_ind_ptr->rssi; + roam_connection.channel = + cds_freq_to_chan(roam_synch_ind_ptr->chan_freq); + } + break; + case eCSR_REASON_ROAM_SYNCH_CNF: + roam_connection.eventId = eCSR_WLAN_STATUS_CONNECT; + break; + case eCSR_REASON_ROAM_HO_FAIL: + roam_connection.eventId = eCSR_WLAN_STATUS_DISCONNECT; + break; + default: + sme_err("LFR3: Unsupported reason %d", reason); + return; + } + roam_connection.reason = reason; + WLAN_HOST_DIAG_EVENT_REPORT(&roam_connection, EVENT_WLAN_STATUS_V2); +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * fn csr_process_ho_fail_ind + * brief This function will process the Hand Off Failure indication + * received from the firmware. It will trigger a disconnect on + * the session which the firmware reported a hand off failure + * param pMac global structure + * param pMsgBuf - Contains the session ID for which the handler should apply + */ +void csr_process_ho_fail_ind(tpAniSirGlobal mac_ctx, void *pMsgBuf) +{ + tSirSmeHOFailureInd *pSmeHOFailInd = (tSirSmeHOFailureInd *) pMsgBuf; + uint32_t sessionId; + + if (pSmeHOFailInd) + sessionId = pSmeHOFailInd->sessionId; + else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "LFR3: Hand-Off Failure Ind is NULL"); + return; + } + /* Roaming is supported only on Infra STA Mode. */ + if (!csr_roam_is_sta_mode(mac_ctx, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "LFR3:HO Fail cannot be handled for session %d", + sessionId); + return; + } + mac_ctx->sme.set_connection_info_cb(false); + csr_roam_roaming_offload_timer_action(mac_ctx, 0, sessionId, + ROAMING_OFFLOAD_TIMER_STOP); + csr_roam_call_callback(mac_ctx, sessionId, NULL, 0, + eCSR_ROAM_NAPI_OFF, eCSR_ROAM_RESULT_FAILURE); + csr_roam_synch_clean_up(mac_ctx, sessionId); + csr_roaming_report_diag_event(mac_ctx, NULL, + eCSR_REASON_ROAM_HO_FAIL); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "LFR3:Issue Disconnect on session %d", sessionId); + csr_roam_disconnect(mac_ctx, sessionId, + eCSR_DISCONNECT_REASON_ROAM_HO_FAIL); + if (mac_ctx->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ROAM_HO_FAILURE, + true, false); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * 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(tpAniSirGlobal 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_bandwidth; + + sme_debug("Num of %s channels, %d", + ch_name, num_channels); + + for (idx = 0; idx < num_channels && + *i < (REG_MAX_SUPP_OPER_CLASSES - 1); idx++) { + for (ch_bandwidth = BW20; ch_bandwidth < BWALL; + ch_bandwidth++) { + class = wlan_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel_info->channelList[idx], + ch_bandwidth); + sme_debug("for chan %d, op class: %d", + channel_info->channelList[idx], class); + + 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_update_op_class_array() - update op class for all bands + * @hHal: global hal context + * + * Return: void + */ +static void csr_init_operating_classes(tHalHandle hHal) +{ + 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,}; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sme_debug("Current Country = %c%c", + pMac->scan.countryCodeCurrent[0], + pMac->scan.countryCodeCurrent[1]); + + csr_update_op_class_array(pMac, opClasses, + &pMac->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; + } + } + } + + sme_debug("Number of unique supported op classes %d", + numClasses); + for (i = 0; i < numClasses; i++) + sme_debug("supported opClasses[%d] = %d", i, opClasses[i]); + + /* Set the ordered list of op classes in regdomain + * for use by other modules + */ + wlan_reg_dmn_set_curr_opclasses(numClasses, &opClasses[0]); +} + +/** + * csr_find_session_by_type() - This function will find given session type from + * all sessions. + * @mac_ctx: pointer to mac context. + * @type: session type + * + * Return: session id for give session type. + **/ +static uint32_t +csr_find_session_by_type(tpAniSirGlobal mac_ctx, enum QDF_OPMODE type) +{ + uint32_t i, session_id = CSR_SESSION_ID_INVALID; + struct csr_roam_session *session_ptr; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + + session_ptr = CSR_GET_SESSION(mac_ctx, i); + if (type == session_ptr->bssParams.bssPersona) { + session_id = i; + break; + } + } + return session_id; +} +/** + * csr_is_conn_allow_2g_band() - This function will check if station's conn + * is allowed in 2.4Ghz band. + * @mac_ctx: pointer to mac context. + * @chnl: station's channel. + * + * This function will check if station's connection is allowed in 5Ghz band + * after comparing it with SAP's operating channel. If SAP's operating + * channel and Station's channel is different than this function will return + * false else true. + * + * Return: true or false. + **/ +static bool csr_is_conn_allow_2g_band(tpAniSirGlobal mac_ctx, uint32_t chnl) +{ + uint32_t sap_session_id; + struct csr_roam_session *sap_session; + + if (0 == chnl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("channel is zero, connection not allowed")); + + return false; + } + + sap_session_id = csr_find_session_by_type(mac_ctx, QDF_SAP_MODE); + if (CSR_SESSION_ID_INVALID != sap_session_id) { + sap_session = CSR_GET_SESSION(mac_ctx, sap_session_id); + if ((0 != sap_session->bssParams.operationChn) && + (sap_session->bssParams.operationChn != chnl)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Can't allow STA to connect, chnls not same"); + return false; + } + } + return true; +} + +/** + * csr_is_conn_allow_5g_band() - This function will check if station's conn + * is allowed in 5Ghz band. + * @mac_ctx: pointer to mac context. + * @chnl: station's channel. + * + * This function will check if station's connection is allowed in 5Ghz band + * after comparing it with P2PGO's operating channel. If P2PGO's operating + * channel and Station's channel is different than this function will return + * false else true. + * + * Return: true or false. + **/ +static bool csr_is_conn_allow_5g_band(tpAniSirGlobal mac_ctx, uint32_t chnl) +{ + uint32_t p2pgo_session_id; + struct csr_roam_session *p2pgo_session; + + if (0 == chnl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("channel is zero, connection not allowed")); + return false; + } + + p2pgo_session_id = csr_find_session_by_type(mac_ctx, QDF_P2P_GO_MODE); + if (CSR_SESSION_ID_INVALID != p2pgo_session_id) { + p2pgo_session = CSR_GET_SESSION(mac_ctx, p2pgo_session_id); + if ((0 != p2pgo_session->bssParams.operationChn) && + (eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED != + p2pgo_session->connectState) && + (p2pgo_session->bssParams.operationChn != + chnl)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Can't allow STA to connect, chnls not same"); + return false; + } + } + return true; +} + +/** + * csr_clear_joinreq_param() - This function will clear station's params + * for stored join request to csr. + * @hal_handle: pointer to hal context. + * @session_id: station's session id. + * + * This function will clear station's allocated memory for cached join + * request. + * + * Return: true or false based on function's overall success. + **/ +bool csr_clear_joinreq_param(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct csr_roam_session *sta_session; + struct scan_result_list *bss_list; + + if (NULL == mac_ctx) + return false; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return false; + + /* Release the memory allocated by previous join request */ + bss_list = + (struct scan_result_list *)&sta_session->stored_roam_profile. + bsslist_handle; + if (NULL != bss_list) { + csr_scan_result_purge(mac_ctx, + sta_session->stored_roam_profile.bsslist_handle); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("bss list is released for session %d"), session_id); + sta_session->stored_roam_profile.bsslist_handle = NULL; + } + sta_session->stored_roam_profile.bsslist_handle = NULL; + csr_release_profile(mac_ctx, &sta_session->stored_roam_profile.profile); + sta_session->stored_roam_profile.reason = 0; + sta_session->stored_roam_profile.roam_id = 0; + sta_session->stored_roam_profile.imediate_flag = false; + sta_session->stored_roam_profile.clear_flag = false; + return true; +} + +/** + * csr_store_joinreq_param() - This function will store station's join + * request to that station's session. + * @mac_ctx: pointer to mac context. + * @profile: pointer to station's roam profile. + * @scan_cache: pointer to station's scan cache. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will store station's join request to one of the + * csr structure and add it to station's session. + * + * Return: true or false based on function's overall success. + **/ +bool csr_store_joinreq_param(tpAniSirGlobal mac_ctx, + struct csr_roam_profile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id) +{ + struct csr_roam_session *sta_session; + + if (NULL == mac_ctx) + return false; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return false; + + sta_session->stored_roam_profile.session_id = session_id; + csr_roam_copy_profile(mac_ctx, + &sta_session->stored_roam_profile.profile, profile); + /* new bsslist_handle's memory will be relased later */ + sta_session->stored_roam_profile.bsslist_handle = scan_cache; + sta_session->stored_roam_profile.reason = eCsrHddIssued; + sta_session->stored_roam_profile.roam_id = *roam_id; + sta_session->stored_roam_profile.imediate_flag = false; + sta_session->stored_roam_profile.clear_flag = false; + + return true; +} + +/** + * csr_issue_stored_joinreq() - This function will issues station's stored + * the join request. + * @mac_ctx: pointer to mac context. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will issue station's stored join request, from this point + * onwards the flow will be just like normal connect request. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + **/ +QDF_STATUS csr_issue_stored_joinreq(tpAniSirGlobal mac_ctx, + uint32_t *roam_id, + uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *sta_session; + uint32_t new_roam_id; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return QDF_STATUS_E_FAILURE; + new_roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + *roam_id = new_roam_id; + status = csr_roam_issue_connect(mac_ctx, + sta_session->stored_roam_profile.session_id, + &sta_session->stored_roam_profile.profile, + sta_session->stored_roam_profile.bsslist_handle, + sta_session->stored_roam_profile.reason, + new_roam_id, + sta_session->stored_roam_profile.imediate_flag, + sta_session->stored_roam_profile.clear_flag); + + sta_session->stored_roam_profile.bsslist_handle = + CSR_INVALID_SCANRESULT_HANDLE; + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("CSR failed issuing connect cmd with status = 0x%08X"), + status); + csr_clear_joinreq_param(mac_ctx, session_id); + } + return status; +} + +/** + * 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(tpAniSirGlobal 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; + + /* 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) { + sme_err("Memory allocation failed"); + /* Probably the fail response will also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + } + + /* For hidden SSID case, if there is any scan command pending + * it needs to be cleared before issuing set HW mode + */ + if (command->u.set_hw_mode_cmd.reason == + POLICY_MGR_UPDATE_REASON_HIDDEN_STA) { + sme_err("clear any pending scan command"); + status = csr_scan_abort_mac_scan(mac, + command->u.set_hw_mode_cmd.session_id, INVAL_SCAN_ID); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to clear scan cmd"); + goto fail; + } + } + + 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 fail; + } + + 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))) { + sme_err("Set HW mode to SMM not needed anymore"); + 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); + + 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) { + policy_mgr_set_hw_mode_change_in_progress(mac->psoc, + POLICY_MGR_HW_MODE_NOT_IN_PROGRESS); + sme_err("Posting to PE failed"); + cmd = NULL; + goto fail; + } + return; +fail: + if (cmd) + qdf_mem_free(cmd); + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + sme_err( + "Malloc fail: Fail to send response to SME"); + return; + } + sme_err("Sending set HW fail response to SME"); + param->status = SET_HW_MODE_STATUS_ECANCELED; + 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(tpAniSirGlobal 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) { + sme_err("Memory allocation failed"); + /* 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) { + sme_err( + "Malloc fail: Fail to send response to SME"); + 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(tpAniSirGlobal 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) { + sme_err("Memory allocation failed"); + 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) { + sme_err( + "Malloc fail: Fail to send response to SME"); + 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(tpAniSirGlobal 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->sessionId)) { + sme_err("Invalid session id %d", command->sessionId); + goto fail; + } + session = CSR_GET_SESSION(mac, command->sessionId); + + len = sizeof(*msg); + msg = qdf_mem_malloc(len); + if (!msg) { + sme_err("Memory allocation failed"); + /* 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->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) { + sme_err( + "Malloc fail: Fail to send response to SME"); + 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); +} +#ifdef FEATURE_WLAN_TDLS +/** + * csr_roam_fill_tdls_info() - Fill TDLS information + * @roam_info: Roaming information buffer + * @join_rsp: Join response which has TDLS info + * + * Return: None + */ +void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, + struct csr_roam_info *roam_info, + tpSirSmeJoinRsp join_rsp) +{ + roam_info->tdls_prohibited = join_rsp->tdls_prohibited; + roam_info->tdls_chan_swit_prohibited = + join_rsp->tdls_chan_swit_prohibited; + sme_debug( + "tdls:prohibit: %d, chan_swit_prohibit: %d", + roam_info->tdls_prohibited, + roam_info->tdls_chan_swit_prohibited); +} +#endif + +#if defined(WLAN_FEATURE_FILS_SK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +static void csr_copy_fils_join_rsp_roam_info(struct csr_roam_info *roam_info, + roam_offload_synch_ind *roam_synch_data) +{ + struct fils_join_rsp_params *roam_fils_info; + + roam_info->fils_join_rsp = qdf_mem_malloc(sizeof(*roam_fils_info)); + if (!roam_info->fils_join_rsp) { + sme_err("fils_join_rsp malloc fails!"); + return; + } + + roam_fils_info = roam_info->fils_join_rsp; + 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, + &roam_fils_info->dst_mac, + &roam_fils_info->src_mac, + &roam_fils_info->hlp_data_len, + roam_fils_info->hlp_data); +} + +static void +csr_update_fils_erp_seq_num(struct csr_roam_profile *roam_info, + uint16_t erp_next_seq_num) +{ + if (roam_info->fils_con_info) + roam_info->fils_con_info->sequence_number = erp_next_seq_num; +} +#else +static inline +void csr_copy_fils_join_rsp_roam_info(struct csr_roam_info *roam_info, + roam_offload_synch_ind *roam_synch_data) +{} + +static inline +void csr_update_fils_erp_seq_num(struct csr_roam_profile *roam_info, + uint16_t erp_next_seq_num) +{} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static QDF_STATUS csr_process_roam_sync_callback(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc, enum sir_roam_op_code reason) +{ + uint8_t session_id = roam_synch_data->roamedVdevId; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + tDot11fBeaconIEs *ies_local = NULL; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct csr_roam_info *roam_info; + tCsrRoamConnectedProfile *conn_profile = NULL; + sme_QosAssocInfo assoc_info; + tpAddBssParams add_bss_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tPmkidCacheInfo pmkid_cache; + uint32_t pmkid_index; + uint16_t len; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + + if (!session) { + sme_err("LFR3: Session not found"); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("LFR3: reason: %d", reason); + switch (reason) { + case SIR_ROAMING_DEREGISTER_STA: + /* + * The following is the first thing done in CSR + * after receiving RSI. Hence stopping the timer here. + */ + csr_roam_roaming_offload_timer_action(mac_ctx, + 0, session_id, ROAMING_OFFLOAD_TIMER_STOP); + if (session->discon_in_progress || + !CSR_IS_ROAM_JOINED(mac_ctx, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: Session not in connected state or disconnect is in progress %d"), + session->discon_in_progress); + return QDF_STATUS_E_FAILURE; + } + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_FT_START, eCSR_ROAM_RESULT_SUCCESS); + return status; + case SIR_ROAMING_START: + csr_roam_roaming_offload_timer_action(mac_ctx, + CSR_ROAMING_OFFLOAD_TIMEOUT_PERIOD, session_id, + ROAMING_OFFLOAD_TIMER_START); + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_START, eCSR_ROAM_RESULT_SUCCESS); + wlan_abort_scan(mac_ctx->pdev, INVAL_PDEV_ID, + session_id, INVAL_SCAN_ID, false); + return status; + case SIR_ROAMING_ABORT: + csr_roam_roaming_offload_timer_action(mac_ctx, + 0, session_id, ROAMING_OFFLOAD_TIMER_STOP); + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_ABORT, eCSR_ROAM_RESULT_SUCCESS); + return status; + case SIR_ROAM_SYNCH_NAPI_OFF: + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_NAPI_OFF, eCSR_ROAM_RESULT_SUCCESS); + return status; + case SIR_ROAMING_INVOKE_FAIL: + /* Userspace roam request failed, disconnect with current AP */ + sme_debug("LFR3: roam invoke from user-space fail, dis cur AP"); + csr_roam_disconnect(mac_ctx, session_id, + eCSR_DISCONNECT_REASON_DEAUTH); + return status; + case SIR_ROAM_SYNCH_PROPAGATION: + break; + case SIR_ROAM_SYNCH_COMPLETE: + /* + * 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 + * 3) Set connection in progress = false + */ + /* first update connection info from wma interface */ + policy_mgr_update_connection_info(mac_ctx->psoc, session_id); + /* then update remaining parameters from roam sync ctx */ + sme_debug("Update DBS hw mode"); + 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, + mac_ctx->psoc); + mac_ctx->sme.set_connection_info_cb(false); + session->roam_synch_in_progress = false; + + if (WLAN_REG_IS_5GHZ_CH(bss_desc->channelId)) { + session->disable_hi_rssi = true; + sme_debug("Disabling HI_RSSI, AP channel=%d, rssi=%d", + bss_desc->channelId, bss_desc->rssi); + } else { + session->disable_hi_rssi = false; + } + + policy_mgr_check_concurrent_intf_and_restart_sap(mac_ctx->psoc); + if (roam_synch_data->authStatus == + CSR_ROAM_AUTH_STATUS_AUTHENTICATED) + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CONNECT); + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_SYNCH_COMPLETE, + eCSR_ROAM_RESULT_SUCCESS); + return status; + default: + sme_debug("LFR3: callback reason %d", reason); + return QDF_STATUS_E_FAILURE; + } + session->roam_synch_in_progress = true; + session->roam_synch_data = roam_synch_data; + status = csr_get_parsed_bss_description_ies( + mac_ctx, bss_desc, &ies_local); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("LFR3: fail to parse IEs"); + session->roam_synch_in_progress = false; + return status; + } + + conn_profile = &session->connectedProfile; + csr_roam_stop_network(mac_ctx, session_id, session->pCurRoamProfile, + bss_desc, ies_local); + ps_global_info->remain_in_power_active_till_dhcp = false; + session->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; + roam_info = qdf_mem_malloc(sizeof(struct csr_roam_info)); + if (NULL == roam_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: Mem Alloc failed for roam info")); + session->roam_synch_in_progress = false; + qdf_mem_free(ies_local); + return QDF_STATUS_E_NOMEM; + } + csr_scan_save_roam_offload_ap_to_scan_cache(mac_ctx, roam_synch_data, + bss_desc); + roam_info->sessionId = session_id; + + qdf_mem_copy(&roam_info->bssid.bytes, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + csr_roam_save_connected_information(mac_ctx, session_id, + session->pCurRoamProfile, + bss_desc, + ies_local); + csr_roam_save_security_rsp_ie(mac_ctx, session_id, + session->pCurRoamProfile->negotiatedAuthType, + bss_desc, ies_local); + +#ifdef FEATURE_WLAN_ESE + roam_info->isESEAssoc = conn_profile->isESEAssoc; +#endif + + /* + * Encryption keys for new connection are obtained as follows: + * authStatus = 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. + * + * authStatus = 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. + */ + if (roam_synch_data->authStatus + == CSR_ROAM_AUTH_STATUS_AUTHENTICATED) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Don't start waitforkey timer")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, session_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. + */ + qdf_mem_zero(&pmkid_cache, sizeof(pmkid_cache)); + qdf_copy_macaddr(&pmkid_cache.BSSID, + &session->connectedProfile.bssid); + sme_debug("Trying to find PMKID for " QDF_MAC_ADDR_STR, + QDF_MAC_ADDR_ARRAY(pmkid_cache.BSSID.bytes)); + if (csr_lookup_pmkid_using_bssid(mac_ctx, session, + &pmkid_cache, + &pmkid_index)) { + session->pmk_len = + session->PmkidCacheInfo[pmkid_index].pmk_len; + qdf_mem_zero(session->psk_pmk, + sizeof(session->psk_pmk)); + qdf_mem_copy(session->psk_pmk, + session->PmkidCacheInfo[pmkid_index].pmk, + session->pmk_len); + sme_debug("pmkid found for " QDF_MAC_ADDR_STR " at %d len %d", + QDF_MAC_ADDR_ARRAY(pmkid_cache.BSSID.bytes), + pmkid_index, (uint32_t)session->pmk_len); + } else { + sme_debug("PMKID Not found in cache for " QDF_MAC_ADDR_STR, + QDF_MAC_ADDR_ARRAY(pmkid_cache.BSSID.bytes)); + } + } else { + roam_info->fAuthRequired = true; + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + session_id); + + ps_global_info->remain_in_power_active_till_dhcp = true; + mac_ctx->roam.WaitForKeyTimerInfo.sessionId = session_id; + if (!QDF_IS_STATUS_SUCCESS(csr_roam_start_wait_for_key_timer( + mac_ctx, CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD)) + ) { + sme_err("Failed wait for key timer start"); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, + session_id); + } + } + roam_info->nBeaconLength = 0; + roam_info->nAssocReqLength = roam_synch_data->reassoc_req_length - + SIR_MAC_HDR_LEN_3A - SIR_MAC_REASSOC_SSID_OFFSET; + roam_info->nAssocRspLength = roam_synch_data->reassocRespLength - + SIR_MAC_HDR_LEN_3A; + roam_info->pbFrames = qdf_mem_malloc(roam_info->nBeaconLength + + roam_info->nAssocReqLength + roam_info->nAssocRspLength); + if (NULL == roam_info->pbFrames) { + sme_err("no memory available"); + session->roam_synch_in_progress = false; + if (roam_info) + qdf_mem_free(roam_info); + qdf_mem_free(ies_local); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(roam_info->pbFrames, + (uint8_t *)roam_synch_data + + roam_synch_data->reassoc_req_offset + + SIR_MAC_HDR_LEN_3A + SIR_MAC_REASSOC_SSID_OFFSET, + roam_info->nAssocReqLength); + qdf_mem_copy(roam_info->pbFrames + roam_info->nAssocReqLength, + (uint8_t *)roam_synch_data + + roam_synch_data->reassocRespOffset + + SIR_MAC_HDR_LEN_3A, + roam_info->nAssocRspLength); + + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Clear Connected info")); + csr_roam_free_connected_info(mac_ctx, + &session->connectedInfo); + len = roam_synch_data->join_rsp->parsedRicRspLen; + +#ifdef FEATURE_WLAN_ESE + len += roam_synch_data->join_rsp->tspecIeLen; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: tspecLen %d"), + roam_synch_data->join_rsp->tspecIeLen); +#endif + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: RIC length - %d"), + roam_synch_data->join_rsp->parsedRicRspLen); + if (len) { + session->connectedInfo.pbFrames = + qdf_mem_malloc(len); + if (session->connectedInfo.pbFrames != NULL) { + qdf_mem_copy(session->connectedInfo.pbFrames, + roam_synch_data->join_rsp->frames, len); + session->connectedInfo.nRICRspLength = + roam_synch_data->join_rsp->parsedRicRspLen; + +#ifdef FEATURE_WLAN_ESE + session->connectedInfo.nTspecIeLength = + roam_synch_data->join_rsp->tspecIeLen; +#endif + } + } + conn_profile->vht_channel_width = + roam_synch_data->join_rsp->vht_channel_width; + add_bss_params = (tpAddBssParams)roam_synch_data->add_bss_params; + session->connectedInfo.staId = add_bss_params->staContext.staIdx; + roam_info->staId = session->connectedInfo.staId; + roam_info->timingMeasCap = + roam_synch_data->join_rsp->timingMeasCap; + roam_info->chan_info.nss = roam_synch_data->join_rsp->nss; + roam_info->chan_info.rate_flags = + roam_synch_data->join_rsp->max_rate_flags; + roam_info->chan_info.ch_width = + roam_synch_data->join_rsp->vht_channel_width; + csr_roam_fill_tdls_info(mac_ctx, roam_info, roam_synch_data->join_rsp); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + src_profile = &roam_synch_data->join_rsp->HTProfile; + dst_profile = &conn_profile->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, + src_profile); +#endif + assoc_info.pBssDesc = bss_desc; + roam_info->statusCode = eSIR_SME_SUCCESS; + roam_info->reasonCode = eSIR_SME_SUCCESS; + assoc_info.pProfile = session->pCurRoamProfile; + mac_ctx->roam.roamSession[session_id].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, NULL); + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_REASSOC_REQ, NULL); + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); + mac_ctx->roam.roamSession[session_id].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_REASSOC_COMPLETE, &assoc_info); + roam_info->pBssDesc = bss_desc; + conn_profile->acm_mask = sme_qos_get_acm_mask(mac_ctx, + bss_desc, NULL); + if (conn_profile->modifyProfileFields.uapsd_mask) { + sme_debug( + " uapsd_mask (0x%X) set, request UAPSD now", + conn_profile->modifyProfileFields.uapsd_mask); + sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), session_id); + } + conn_profile->dot11Mode = session->bssParams.uCfgDot11Mode; + roam_info->u.pConnectedProfile = conn_profile; + + sme_debug( + "vht ch width %d staId %d nss %d rate_flag %d dot11Mode %d", + conn_profile->vht_channel_width, + roam_info->staId, + roam_info->chan_info.nss, + roam_info->chan_info.rate_flags, + conn_profile->dot11Mode); + + if (!IS_FEATURE_SUPPORTED_BY_FW + (SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } + roam_info->roamSynchInProgress = true; + roam_info->synchAuthStatus = roam_synch_data->authStatus; + roam_info->kek_len = roam_synch_data->kek_len; + roam_info->pmk_len = roam_synch_data->pmk_len; + qdf_mem_copy(roam_info->kck, roam_synch_data->kck, SIR_KCK_KEY_LEN); + qdf_mem_copy(roam_info->kek, roam_synch_data->kek, roam_info->kek_len); + + if (roam_synch_data->pmk_len) + qdf_mem_copy(roam_info->pmk, roam_synch_data->pmk, + roam_synch_data->pmk_len); + + qdf_mem_copy(roam_info->pmkid, roam_synch_data->pmkid, SIR_PMKID_LEN); + roam_info->update_erp_next_seq_num = + roam_synch_data->update_erp_next_seq_num; + roam_info->next_erp_seq_num = roam_synch_data->next_erp_seq_num; + csr_update_fils_erp_seq_num(session->pCurRoamProfile, + roam_info->next_erp_seq_num); + sme_debug("Update ERP Seq Num : %d, Next ERP Seq Num : %d", + roam_info->update_erp_next_seq_num, + roam_info->next_erp_seq_num); + qdf_mem_copy(roam_info->replay_ctr, roam_synch_data->replay_ctr, + SIR_REPLAY_CTR_LEN); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: Copy KCK, KEK(len %d) and Replay Ctr"), + roam_info->kek_len); + /* bit-4 and bit-5 indicate the subnet status */ + roam_info->subnet_change_status = + CSR_GET_SUBNET_STATUS(roam_synch_data->roamReason); + + /* fetch 4 LSB to get roam reason */ + roam_info->roam_reason = roam_synch_data->roamReason & + ROAM_REASON_MASK; + sme_info("Update roam reason : %d", roam_info->roam_reason); + csr_copy_fils_join_rsp_roam_info(roam_info, roam_synch_data); + + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + eCSR_ROAM_ASSOCIATION_COMPLETION, eCSR_ROAM_RESULT_ASSOCIATED); + csr_reset_pmkid_candidate_list(mac_ctx, session_id); +#ifdef FEATURE_WLAN_WAPI + csr_reset_bkid_candidate_list(mac_ctx, session_id); +#endif + if (!CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL + ("NO CSR_IS_WAIT_FOR_KEY -> csr_roam_link_up")); + csr_roam_link_up(mac_ctx, conn_profile->bssid); + } + + session->fRoaming = false; + session->roam_synch_in_progress = false; + sme_free_join_rsp_fils_params(roam_info); + qdf_mem_free(roam_info->pbFrames); + qdf_mem_free(roam_info); + qdf_mem_free(ies_local); + + return status; +} + +/** + * csr_roam_synch_callback() - SME level callback for roam synch propagation + * @mac_ctx: MAC Context + * @roam_synch_data: Roam synch data buffer pointer + * @bss_desc: BSS descriptor pointer + * @reason: Reason for calling the callback + * + * This callback is registered with WMA and used after roaming happens in + * firmware and the call to this routine completes the roam synch + * propagation at both CSR and HDD levels. The HDD level propagation + * is achieved through the already defined callback for assoc completion + * handler. + * + * Return: Success or Failure. + */ +QDF_STATUS csr_roam_synch_callback(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc, enum sir_roam_op_code reason) +{ + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("LFR3: Locking failed, bailing out"); + return status; + } + + status = csr_process_roam_sync_callback(mac_ctx, roam_synch_data, + bss_desc, reason); + + sme_release_global_lock(&mac_ctx->sme); + + return status; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c new file mode 100644 index 0000000000000000000000000000000000000000..cc9ee4f40bec01ed4e4dee65bd8149688bfc084f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c @@ -0,0 +1,3274 @@ +/* + * 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. + */ + +/* + * 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 "cfg_api.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" + +/* Purpose of HIDDEN_TIMER + * When we remove hidden ssid from the profile i.e., forget the SSID via GUI + * that SSID shouldn't see in the profile For above requirement we used timer + * limit, logic is explained below Timer value is initialsed to current time + * when it receives corresponding probe response of hidden SSID (The probe + * request is received regularly till SSID in the profile. Once it is removed + * from profile probe request is not sent.) when we receive probe response for + * broadcast probe request, during update SSID with saved SSID we will diff + * current time with saved SSID time if it is greater than 1 min then we are + * not updating with old one + */ + +#define HIDDEN_TIMER (1*60*1000) +/* must be less than 100, represent the persentage of new RSSI */ +#define CSR_SCAN_RESULT_RSSI_WEIGHT 80 +#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL 140 +#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL 120 + +#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 30 +#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 20 + +#define PCL_ADVANTAGE 30 +#define PCL_RSSI_THRESHOLD -75 + +static void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, uint8_t + *pChannelList, uint8_t NumChannels); +static void csr_save_tx_power_to_cfg(tpAniSirGlobal pMac, tDblLinkList *pList, + uint32_t cfgId); +static void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode); +static void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList + *pChannelList); +static bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel); + +#define CSR_IS_SOCIAL_CHANNEL(channel) \ + (((channel) == 1) || ((channel) == 6) || ((channel) == 11)) + +/* pResult is invalid calling this function. */ +void csr_free_scan_result_entry(tpAniSirGlobal pMac, struct tag_csrscan_result + *pResult) +{ + if (NULL != pResult->Result.pvIes) + qdf_mem_free(pResult->Result.pvIes); + + qdf_mem_free(pResult); +} + +static QDF_STATUS csr_ll_scan_purge_result(tpAniSirGlobal pMac, + tDblLinkList *pList) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry; + struct tag_csrscan_result *pBssDesc; + + csr_ll_lock(pList); + + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) { + pBssDesc = GET_BASE_ADDR(pEntry, struct tag_csrscan_result, + Link); + csr_free_scan_result_entry(pMac, pBssDesc); + } + + csr_ll_unlock(pList); + + return status; +} + +QDF_STATUS csr_scan_open(tpAniSirGlobal 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(tpAniSirGlobal pMac) +{ + csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList24); + csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList5G); + csr_ll_close(&pMac->scan.channelPowerInfoList24); + csr_ll_close(&pMac->scan.channelPowerInfoList5G); + ucfg_scan_set_enable(pMac->psoc, false); + return QDF_STATUS_SUCCESS; +} +QDF_STATUS csr_scan_handle_search_for_ssid(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + tCsrScanResultFilter *pScanFilter = NULL; + struct csr_roam_profile *profile; + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("session %d not found", session_id); + return QDF_STATUS_E_FAILURE; + } + profile = session->scan_info.profile; + sme_debug("session %d", session_id); + do { + /* If this scan is for HDD reassociate */ + if (mac_ctx->roam.neighborRoamInfo[session_id]. + uOsRequestedHandoff) { + /* notify LFR state m/c */ + status = csr_neighbor_roam_sssid_scan_done + (mac_ctx, session_id, QDF_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_neighbor_roam_start_lfr_scan(mac_ctx, + session_id); + status = QDF_STATUS_SUCCESS; + break; + } + /* + * If there is roam command waiting, ignore this roam because + * the newer roam command is the one to execute + */ + if (csr_is_roam_command_waiting_for_session(mac_ctx, session_id)) { + sme_warn("aborts because roam command waiting"); + break; + } + if (profile == NULL) + break; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = QDF_STATUS_E_NOMEM; + break; + } + status = csr_roam_prepare_filter_from_profile(mac_ctx, profile, + pScanFilter); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + status = csr_scan_get_result(mac_ctx, pScanFilter, &hBSSList); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + if (mac_ctx->roam.roamSession[session_id].connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING) { + sme_err("upper layer issued disconnetion"); + status = QDF_STATUS_E_FAILURE; + break; + } + status = csr_roam_issue_connect(mac_ctx, session_id, profile, + hBSSList, eCsrHddIssued, + session->scan_info.roam_id, + true, true); + hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + } while (0); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_INVALID_SCANRESULT_HANDLE != hBSSList) { + csr_scan_result_purge(mac_ctx, hBSSList); + } + /* We haven't done anything to this profile */ + csr_roam_call_callback(mac_ctx, session_id, NULL, + session->scan_info.roam_id, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + } + if (pScanFilter) { + csr_free_scan_filter(mac_ctx, pScanFilter); + qdf_mem_free(pScanFilter); + } + return status; +} + +/** + * csr_handle_fils_scan_for_ssid_failure() - Checks and fills FILS seq number + * in roam_info structure to send to hdd + * + * @roam_profile: Pointer to current roam_profile structure + * @roam_info: Pointer to roam_info strucure to be filled + * + * Return: true for FILS connection else false + */ +#ifdef WLAN_FEATURE_FILS_SK +static bool +csr_handle_fils_scan_for_ssid_failure(struct csr_roam_profile *roam_profile, + struct csr_roam_info *roam_info) +{ + if (roam_profile && roam_profile->fils_con_info && + roam_profile->fils_con_info->is_fils_connection) { + sme_debug("send roam_info for FILS connection failure, seq %d", + roam_profile->fils_con_info->sequence_number); + roam_info->is_fils_connection = true; + roam_info->fils_seq_num = + roam_profile->fils_con_info->sequence_number; + return true; + } + + return false; +} +#else +static bool +csr_handle_fils_scan_for_ssid_failure(struct csr_roam_profile *roam_profile, + struct csr_roam_info *roam_info) +{ + return false; +} +#endif + +QDF_STATUS csr_scan_handle_search_for_ssid_failure(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_profile *profile; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + eCsrRoamResult roam_result; + struct csr_roam_info *roam_info = NULL; + struct tag_csrscan_result *scan_result; + + if (!session) { + sme_err("session %d not found", session_id); + return QDF_STATUS_E_FAILURE; + } + + /* If this scan is for HDD reassociate */ + if (mac_ctx->roam.neighborRoamInfo[session_id].uOsRequestedHandoff) { + /* notify LFR state m/c */ + status = csr_neighbor_roam_sssid_scan_done + (mac_ctx, session_id, QDF_STATUS_E_FAILURE); + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_neighbor_roam_start_lfr_scan(mac_ctx, session_id); + return QDF_STATUS_SUCCESS; + } + + profile = session->scan_info.profile; + + /* + * Check whether it is for start ibss. No need to do anything if it + * is a JOIN request + */ + if (profile && CSR_IS_START_IBSS(profile)) { + status = csr_roam_issue_connect(mac_ctx, session_id, profile, NULL, + eCsrHddIssued, session->scan_info.roam_id, + true, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("failed to issue startIBSS, session_id %d status: 0x%08X roam id %d", + session_id, status, session->scan_info.roam_id); + csr_roam_call_callback(mac_ctx, session_id, NULL, + session->scan_info.roam_id, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; + } + roam_result = eCSR_ROAM_RESULT_FAILURE; + if (NULL != profile && csr_is_bss_type_ibss(profile->BSSType)) { + roam_result = eCSR_ROAM_RESULT_IBSS_START_FAILED; + goto roam_completion; + } + + roam_info = qdf_mem_malloc(sizeof(struct csr_roam_info)); + if (!roam_info) { + sme_err("Failed to allocate memory for roam_info"); + goto roam_completion; + } + + if (session->scan_info.roambssentry) { + scan_result = GET_BASE_ADDR(session->scan_info.roambssentry, + struct tag_csrscan_result, Link); + roam_info->pBssDesc = &scan_result->Result.BssDescriptor; + } + roam_info->statusCode = session->joinFailStatusCode.statusCode; + roam_info->reasonCode = session->joinFailStatusCode.reasonCode; + + /* Only indicate assoc_completion if we indicate assoc_start. */ + if (session->bRefAssocStartCnt > 0) { + session->bRefAssocStartCnt--; + csr_roam_call_callback(mac_ctx, session_id, roam_info, + session->scan_info.roam_id, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + } else { + if (!csr_handle_fils_scan_for_ssid_failure( + profile, roam_info)) { + qdf_mem_free(roam_info); + roam_info = NULL; + } + csr_roam_call_callback(mac_ctx, session_id, roam_info, + session->scan_info.roam_id, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + } + + if (roam_info) + qdf_mem_free(roam_info); +roam_completion: + csr_roam_completion(mac_ctx, session_id, NULL, NULL, roam_result, + false); + return status; +} + +QDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac, + 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(pMac, &pScanList->List); + csr_ll_close(&pScanList->List); + qdf_mem_free(pScanList); + } + return status; +} + +/* Add the channel to the occupiedChannels array */ +static void csr_add_to_occupied_channels(tpAniSirGlobal pMac, + uint8_t ch, + uint8_t sessionId, + struct csr_channel *occupied_ch, + bool is_init_list) +{ + QDF_STATUS status; + uint8_t num_occupied_ch = occupied_ch->numChannels; + uint8_t *occupied_ch_lst = occupied_ch->channelList; + + if (is_init_list) + pMac->scan.roam_candidate_count[sessionId]++; + + if (csr_is_channel_present_in_list(occupied_ch_lst, + num_occupied_ch, ch)) + return; + + status = csr_add_to_channel_list_front(occupied_ch_lst, + num_occupied_ch, ch); + if (QDF_IS_STATUS_SUCCESS(status)) { + occupied_ch->numChannels++; + sme_debug("Added channel %d to the list (count=%d)", + ch, occupied_ch->numChannels); + if (occupied_ch->numChannels > + CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN) + occupied_ch->numChannels = + CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN; + } +} + +/* Put the BSS into the scan result list */ +/* pIes can not be NULL */ +static void csr_scan_add_result(tpAniSirGlobal mac_ctx, + struct tag_csrscan_result *pResult) +{ + qdf_nbuf_t buf; + uint8_t *data; + struct mgmt_rx_event_params rx_param = {0}; + struct wlan_frame_hdr *hdr; + struct wlan_bcn_frame *fixed_frame; + uint32_t buf_len, i; + tSirBssDescription *bss_desc; + enum mgmt_frame_type frm_type = MGMT_BEACON; + + if (!pResult) { + sme_err("pResult is null"); + return; + } + + bss_desc = &pResult->Result.BssDescriptor; + if (bss_desc->fProbeRsp) + frm_type = MGMT_PROBE_RESP; + + rx_param.pdev_id = 0; + rx_param.channel = bss_desc->channelId; + rx_param.rssi = bss_desc->rssi; + rx_param.tsf_delta = bss_desc->tsf_delta; + + /* 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_len = GET_IE_LEN_IN_BSS(bss_desc->length) + + + offsetof(struct wlan_bcn_frame, ie) + sizeof(*hdr); + + buf = qdf_nbuf_alloc(NULL, qdf_roundup(buf_len, 4), + 0, 4, false); + if (!buf) { + sme_err("Failed to allocate wbuf for mgmt rx len (%u)", + buf_len); + return; + } + qdf_nbuf_put_tail(buf, buf_len); + qdf_nbuf_set_protocol(buf, ETH_P_CONTROL); + + data = qdf_nbuf_data(buf); + hdr = (struct wlan_frame_hdr *) data; + qdf_mem_copy(hdr->i_addr3, bss_desc->bssId, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr->i_addr2, bss_desc->bssId, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr->i_seq, + &bss_desc->seq_ctrl, sizeof(uint16_t)); + + data += sizeof(*hdr); + fixed_frame = (struct wlan_bcn_frame *)data; + qdf_mem_copy(fixed_frame->timestamp, + bss_desc->timeStamp, 8); + fixed_frame->beacon_interval = bss_desc->beaconInterval; + fixed_frame->capability.value = bss_desc->capabilityInfo; + data += offsetof(struct wlan_bcn_frame, ie); + + qdf_mem_copy(data, bss_desc->ieFields, + GET_IE_LEN_IN_BSS(bss_desc->length)); + tgt_scan_bcn_probe_rx_callback(mac_ctx->psoc, NULL, buf, &rx_param, + frm_type); +} + +/* + * NOTE: This routine is being added to make + * sure that scan results are not being flushed + * while roaming. If the scan results are flushed, + * we are unable to recover from + * csr_roam_roaming_state_disassoc_rsp_processor. + * If it is needed to remove this routine, + * first ensure that we recover gracefully from + * csr_roam_roaming_state_disassoc_rsp_processor if + * csr_scan_get_result returns with a failure because + * of not being able to find the roaming BSS. + */ +static bool csr_scan_flush_denied(tpAniSirGlobal pMac) +{ + uint8_t sessionId; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + if (csr_neighbor_middle_of_roaming(pMac, sessionId)) + return 1; + } + } + return 0; +} + +static bool csr_scan_save_bss_description(tpAniSirGlobal pMac, + tSirBssDescription * + pBSSDescription) +{ + struct tag_csrscan_result *pCsrBssDescription = NULL; + uint32_t cbBSSDesc; + uint32_t cbAllocated; + + /* figure out how big the BSS description is (the BSSDesc->length does + * NOT include the size of the length field itself). + */ + cbBSSDesc = pBSSDescription->length + sizeof(pBSSDescription->length); + + cbAllocated = sizeof(struct tag_csrscan_result) + cbBSSDesc; + + pCsrBssDescription = qdf_mem_malloc(cbAllocated); + if (!pCsrBssDescription) { + sme_err(" Failed to allocate memory for pCsrBssDescription"); + return false; + } + + pCsrBssDescription->AgingCount = + (int32_t) pMac->roam.configParam.agingCount; + sme_debug( + "Set Aging Count = %d for BSS " MAC_ADDRESS_STR " ", + pCsrBssDescription->AgingCount, + MAC_ADDR_ARRAY(pCsrBssDescription->Result.BssDescriptor. + bssId)); + qdf_mem_copy(&pCsrBssDescription->Result.BssDescriptor, + pBSSDescription, cbBSSDesc); + csr_scan_add_result(pMac, pCsrBssDescription); + csr_free_scan_result_entry(pMac, pCsrBssDescription); + + return true; +} + +/* Append a Bss Description... */ +bool csr_scan_append_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDescription) +{ + return csr_scan_save_bss_description(pMac, + pSirBssDescription); +} + +static void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList + *pChannelList) +{ + struct csr_channel_powerinfo *pChannelSet; + tListElem *pEntry; + + csr_ll_lock(pChannelList); + /* + * Remove the channel sets from the learned list and put them + * in the free list + */ + 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); +} + +/* + * 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(tpAniSirGlobal pMac, + uint32_t tableSize, + tSirMacChanInfo *channelTable) +{ + uint32_t i = tableSize / sizeof(tSirMacChanInfo); + tSirMacChanInfo *pChannelInfo; + struct csr_channel_powerinfo *pChannelSet; + bool f2GHzInfoFound = false; + bool f2GListPurged = false, f5GListPurged = false; + + pChannelInfo = channelTable; + /* atleast 3 bytes have to be remaining -- from "countryString" */ + while (i--) { + pChannelSet = qdf_mem_malloc(sizeof(struct csr_channel_powerinfo)); + if (NULL == pChannelSet) { + pChannelInfo++; + continue; + } + pChannelSet->firstChannel = pChannelInfo->firstChanNum; + pChannelSet->numChannels = pChannelInfo->numChannels; + /* + * Now set the inter-channel offset based on the frequency band + * the channel set lies in + */ + if ((WLAN_REG_IS_24GHZ_CH(pChannelSet->firstChannel)) && + ((pChannelSet->firstChannel + + (pChannelSet->numChannels - 1)) <= + WLAN_REG_MAX_24GHZ_CH_NUM)) { + pChannelSet->interChannelOffset = 1; + f2GHzInfoFound = true; + } else if ((WLAN_REG_IS_5GHZ_CH(pChannelSet->firstChannel)) + && ((pChannelSet->firstChannel + + ((pChannelSet->numChannels - 1) * 4)) <= + WLAN_REG_MAX_5GHZ_CH_NUM)) { + pChannelSet->interChannelOffset = 4; + f2GHzInfoFound = false; + } else { + sme_warn("Invalid Channel %d Present in Country IE", + pChannelSet->firstChannel); + qdf_mem_free(pChannelSet); + return QDF_STATUS_E_FAILURE; + } + pChannelSet->txPower = QDF_MIN(pChannelInfo->maxTxPower, + pMac->roam.configParam.nTxPowerCap); + if (f2GHzInfoFound) { + if (!f2GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(pMac, + &pMac->scan. + channelPowerInfoList24); + f2GListPurged = true; + } + if (CSR_IS_OPERATING_BG_BAND(pMac)) { + /* add to the list of 2.4 GHz channel sets */ + csr_ll_insert_tail(&pMac->scan. + channelPowerInfoList24, + &pChannelSet->link, + LL_ACCESS_LOCK); + } else { + sme_debug( + "Adding 11B/G ch in 11A. 1st ch %d", + pChannelSet->firstChannel); + qdf_mem_free(pChannelSet); + } + } else { + /* 5GHz info found */ + if (!f5GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(pMac, + &pMac->scan. + channelPowerInfoList5G); + f5GListPurged = true; + } + if (CSR_IS_OPERATING_A_BAND(pMac)) { + /* add to the list of 5GHz channel sets */ + csr_ll_insert_tail(&pMac->scan. + channelPowerInfoList5G, + &pChannelSet->link, + LL_ACCESS_LOCK); + } else { + sme_debug( + "Adding 11A ch in B/G. 1st ch %d", + pChannelSet->firstChannel); + qdf_mem_free(pChannelSet); + } + } + pChannelInfo++; /* move to next entry */ + } + return QDF_STATUS_SUCCESS; +} + +void csr_apply_power2_current(tpAniSirGlobal pMac) +{ + sme_debug("Updating Cfg with power settings"); + csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList24, + WNI_CFG_MAX_TX_POWER_2_4); + csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList5G, + WNI_CFG_MAX_TX_POWER_5); +} + +void csr_apply_channel_power_info_to_fw(tpAniSirGlobal mac_ctx, + struct csr_channel *ch_lst, + uint8_t *countryCode) +{ + int i; + uint8_t num_ch = 0; + uint8_t tempNumChannels = 0; + struct csr_channel tmp_ch_lst; + + if (ch_lst->numChannels) { + tempNumChannels = CSR_MIN(ch_lst->numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + for (i = 0; i < tempNumChannels; i++) { + tmp_ch_lst.channelList[num_ch] = ch_lst->channelList[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.channelList, + tmp_ch_lst.numChannels); + } else { + sme_err("11D channel list is empty"); + } + csr_set_cfg_country_code(mac_ctx, countryCode); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_reset_country_information(tpAniSirGlobal pMac) +{ + + host_log_802_11d_pkt_type *p11dLog; + int Index; + + 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; + qdf_mem_copy(p11dLog->countryCode, pMac->scan.countryCodeCurrent, 3); + p11dLog->numChannel = pMac->scan.base_channels.numChannels; + if (p11dLog->numChannel <= HOST_LOG_MAX_NUM_CHANNEL) { + qdf_mem_copy(p11dLog->Channels, + pMac->scan.base_channels.channelList, + p11dLog->numChannel); + for (Index = 0; + Index < pMac->scan.base_channels.numChannels; + Index++) { + p11dLog->TxPwr[Index] = QDF_MIN( + pMac->scan.defaultPowerTable[Index].tx_power, + pMac->roam.configParam.nTxPowerCap); + } + } + if (!pMac->roam.configParam.Is11dSupportEnabled) + p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED; + else + p11dLog->supportMultipleDomain = + WLAN_80211D_SUPPORT_MULTI_DOMAIN; + WLAN_HOST_DIAG_LOG_REPORT(p11dLog); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_apply_channel_power_info_wrapper() - sends channel info to fw + * @pMac: main MAC data structure + * + * This function sends the channel power info to firmware + * + * Return: none + */ +void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac) +{ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_reset_country_information(pMac); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + csr_prune_channel_list_for_mode(pMac, &pMac->scan.base_channels); + csr_save_channel_power_for_band(pMac, false); + csr_save_channel_power_for_band(pMac, true); + /* apply the channel list, power settings, and the country code. */ + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan.base_channels, pMac->scan.countryCodeCurrent); + /* clear the 11d channel list */ + qdf_mem_zero(&pMac->scan.channels11d, sizeof(pMac->scan.channels11d)); +} + +void csr_clear_votes_for_country_info(tpAniSirGlobal pMac) +{ + pMac->scan.countryCodeCount = 0; + qdf_mem_zero(pMac->scan.votes11d, + sizeof(struct csr_votes11d) * CSR_MAX_NUM_COUNTRY_CODE); +} + +/* caller allocated memory for pNumChn and pChnPowerInfo */ +/* As input, *pNumChn has the size of the array of pChnPowerInfo */ +/* Upon return, *pNumChn has the number of channels assigned. */ +static void csr_get_channel_power_info(tpAniSirGlobal pMac, tDblLinkList *list, + uint32_t *num_ch, + struct channel_power *chn_pwr_info) +{ + tListElem *entry; + uint32_t chn_idx = 0, idx; + struct csr_channel_powerinfo *ch_set; + + /* Get 2.4Ghz first */ + entry = csr_ll_peek_head(list, LL_ACCESS_LOCK); + while (entry && (chn_idx < *num_ch)) { + ch_set = GET_BASE_ADDR(entry, + struct csr_channel_powerinfo, link); + for (idx = 0; (idx < ch_set->numChannels) + && (chn_idx < *num_ch); idx++) { + chn_pwr_info[chn_idx].chan_num = + (uint8_t) (ch_set->firstChannel + + (idx * ch_set->interChannelOffset)); + chn_pwr_info[chn_idx++].tx_power = ch_set->txPower; + } + entry = csr_ll_next(list, entry, LL_ACCESS_LOCK); + } + *num_ch = chn_idx; + +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_apply_country_info(tpAniSirGlobal mac_ctx) +{ + host_log_802_11d_pkt_type *p11dLog; + struct channel_power chnPwrInfo[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN, nTmp; + + WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type, + LOG_WLAN_80211D_C); + if (!p11dLog) + return; + + p11dLog->eventId = WLAN_80211D_EVENT_COUNTRY_SET; + qdf_mem_copy(p11dLog->countryCode, mac_ctx->scan.countryCode11d, 3); + p11dLog->numChannel = mac_ctx->scan.channels11d.numChannels; + if (p11dLog->numChannel > HOST_LOG_MAX_NUM_CHANNEL) + goto diag_end; + + qdf_mem_copy(p11dLog->Channels, + mac_ctx->scan.channels11d.channelList, + p11dLog->numChannel); + csr_get_channel_power_info(mac_ctx, + &mac_ctx->scan.channelPowerInfoList24, + &nChnInfo, chnPwrInfo); + nTmp = nChnInfo; + nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN - nTmp; + csr_get_channel_power_info(mac_ctx, + &mac_ctx->scan.channelPowerInfoList5G, + &nChnInfo, &chnPwrInfo[nTmp]); + for (nTmp = 0; nTmp < p11dLog->numChannel; nTmp++) { + for (nChnInfo = 0; + nChnInfo < WNI_CFG_VALID_CHANNEL_LIST_LEN; + nChnInfo++) { + if (p11dLog->Channels[nTmp] == + chnPwrInfo[nChnInfo].chan_num) { + p11dLog->TxPwr[nTmp] = + chnPwrInfo[nChnInfo].tx_power; + break; + } + } + } +diag_end: + if (!mac_ctx->roam.configParam.Is11dSupportEnabled) + p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED; + else + p11dLog->supportMultipleDomain = + WLAN_80211D_SUPPORT_MULTI_DOMAIN; + WLAN_HOST_DIAG_LOG_REPORT(p11dLog); +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_apply_country_information() - apply country code information + * @pMac: core MAC data structure + * + * This function programs the new country code + * + * Return: none + */ +void csr_apply_country_information(tpAniSirGlobal pMac) +{ + v_REGDOMAIN_t domainId; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!wlan_reg_11d_enabled_on_host(pMac->psoc)) + return; + status = csr_get_regulatory_domain_for_country(pMac, + pMac->scan.countryCode11d, &domainId, SOURCE_QUERY); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + /* Check whether we need to enforce default domain */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_apply_country_info(pMac); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + if (pMac->scan.domainIdCurrent != domainId) + return; + if (pMac->scan.domainIdCurrent != domainId) { + sme_debug("Domain Changed Old %d, new %d", + pMac->scan.domainIdCurrent, domainId); + if (domainId >= REGDOMAIN_COUNT) + sme_err("fail to set regId %d", domainId); + } + pMac->scan.domainIdCurrent = domainId; + /* switch to active scans using this new channel list */ + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; +} + +void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fill_5f) +{ + uint32_t idx, count = 0; + tSirMacChanInfo *chan_info; + tSirMacChanInfo *ch_info_start; + int32_t max_ch_idx; + bool tmp_bool; + uint8_t ch = 0; + + max_ch_idx = + (pMac->scan.base_channels.numChannels < + WNI_CFG_VALID_CHANNEL_LIST_LEN) ? + pMac->scan.base_channels.numChannels : + WNI_CFG_VALID_CHANNEL_LIST_LEN; + + chan_info = qdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (NULL == chan_info) + return; + + ch_info_start = chan_info; + for (idx = 0; idx < max_ch_idx; idx++) { + ch = pMac->scan.defaultPowerTable[idx].chan_num; + tmp_bool = (fill_5f && WLAN_REG_IS_5GHZ_CH(ch)) || + (!fill_5f && WLAN_REG_IS_24GHZ_CH(ch)); + if (!tmp_bool) + continue; + + if (count >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + sme_warn("count: %d exceeded", count); + break; + } + + chan_info->firstChanNum = + pMac->scan.defaultPowerTable[idx].chan_num; + chan_info->numChannels = 1; + chan_info->maxTxPower = + QDF_MIN(pMac->scan.defaultPowerTable[idx].tx_power, + pMac->roam.configParam.nTxPowerCap); + chan_info++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(pMac, + count * sizeof(tSirMacChanInfo), ch_info_start); + } + qdf_mem_free(ch_info_start); +} + +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId) +{ + bool fRet = false; + uint32_t i; + + for (i = 0; i < pMac->scan.base_channels.numChannels; i++) { + if (channelId == + pMac->scan.base_channels.channelList[i]) { + fRet = true; + break; + } + } + + return fRet; +} + +/* + * 802.11D only: Gather 11d IE via beacon or Probe response and store them in + * pAdapter->channels11d + */ +bool csr_learn_11dcountry_information(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, bool fForce) +{ + QDF_STATUS status; + uint8_t *pCountryCodeSelected; + bool fRet = false; + v_REGDOMAIN_t domainId; + tDot11fBeaconIEs *pIesLocal = pIes; + bool useVoting = false; + + if ((NULL == pSirBssDesc) && (NULL == pIes)) + useVoting = true; + + /* check if .11d support is enabled */ + if (!wlan_reg_11d_enabled_on_host(pMac->psoc)) + goto free_ie; + + if (false == useVoting) { + if (!pIesLocal && + (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pSirBssDesc, &pIesLocal)))) + goto free_ie; + /* check if country information element is present */ + if (!pIesLocal->Country.present) + /* No country info */ + goto free_ie; + status = csr_get_regulatory_domain_for_country(pMac, + pIesLocal->Country.country, &domainId, + SOURCE_QUERY); + if (QDF_IS_STATUS_SUCCESS(status) + && (domainId == REGDOMAIN_WORLD)) + goto free_ie; + } /* useVoting == false */ + + if (false == useVoting) + pCountryCodeSelected = pIesLocal->Country.country; + else + pCountryCodeSelected = pMac->scan.countryCodeElected; + + if (qdf_mem_cmp(pCountryCodeSelected, pMac->scan.countryCodeCurrent, + CDS_COUNTRY_CODE_LEN) == 0) { + qdf_mem_copy(pMac->scan.countryCode11d, + pMac->scan.countryCodeCurrent, + CDS_COUNTRY_CODE_LEN); + goto free_ie; + } + + pMac->reg_hint_src = SOURCE_11D; + status = csr_get_regulatory_domain_for_country(pMac, + pCountryCodeSelected, &domainId, SOURCE_11D); + if (status != QDF_STATUS_SUCCESS) { + sme_err("fail to get regId %d", domainId); + fRet = false; + goto free_ie; + } + + fRet = true; +free_ie: + if (!pIes && pIesLocal) { + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + return fRet; +} + +static enum csr_scancomplete_nextcommand csr_scan_get_next_command_state( + tpAniSirGlobal mac_ctx, + uint32_t session_id, + eCsrScanStatus scan_status, + uint8_t *chan) +{ + enum csr_scancomplete_nextcommand NextCommand = eCsrNextScanNothing; + int8_t channel; + struct csr_roam_session *session; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("session %d is invalid", session_id); + return NextCommand; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + switch (session->scan_info.scan_reason) { + case eCsrScanForSsid: + sme_debug("Resp for Scan For Ssid"); + channel = csr_scan_get_channel_for_hw_mode_change( + mac_ctx, + session_id, + session->scan_info.profile); + if ((!channel) || scan_status) { + NextCommand = eCsrNexteScanForSsidFailure; + sme_err("next Scan For Ssid Failure %d %d", + channel, scan_status); + } else { + NextCommand = eCsrNextCheckAllowConc; + *chan = channel; + sme_debug("next CheckAllowConc"); + } + break; + default: + NextCommand = eCsrNextScanNothing; + break; + } + sme_debug("Next Command %d", NextCommand); + return NextCommand; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_diag_scan_complete(tpAniSirGlobal mac_ctx, + eCsrScanStatus scan_status) +{ + host_log_scan_pkt_type *pScanLog = NULL; + qdf_list_t *list = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct scan_cache_node *cur_node = NULL; + struct scan_cache_node *next_node = NULL; + int n = 0, c = 0; + + WLAN_HOST_DIAG_LOG_ALLOC(pScanLog, + host_log_scan_pkt_type, + LOG_WLAN_SCAN_C); + if (!pScanLog) + return; + + pScanLog->eventId = WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP; + + if (eCSR_SCAN_SUCCESS != scan_status) { + pScanLog->status = WLAN_SCAN_STATUS_FAILURE; + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + return; + } + pdev = wlan_objmgr_get_pdev_by_id(mac_ctx->psoc, + 0, WLAN_LEGACY_MAC_ID); + + if (!pdev) { + sme_err("pdev is NULL"); + return; + } + + list = ucfg_scan_get_result(pdev, NULL); + if (list) + sme_debug("num_entries %d", qdf_list_size(list)); + if (!list || (list && !qdf_list_size(list))) { + sme_err("get scan result failed"); + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + if (list) + ucfg_scan_purge_results(list); + return; + } + + qdf_list_peek_front(list, + (qdf_list_node_t **) &cur_node); + while (cur_node) { + if (n < HOST_LOG_MAX_NUM_BSSID) { + qdf_mem_copy(pScanLog->bssid[n], + cur_node->entry->bssid.bytes, + QDF_MAC_ADDR_SIZE); + if (cur_node->entry->ssid.length > + WLAN_SSID_MAX_LEN) + cur_node->entry->ssid.length = + WLAN_SSID_MAX_LEN; + qdf_mem_copy(pScanLog->ssid[n], + cur_node->entry->ssid.ssid, + cur_node->entry->ssid.length); + n++; + } + c++; + qdf_list_peek_next( + list, + (qdf_list_node_t *) cur_node, + (qdf_list_node_t **) &next_node); + cur_node = next_node; + next_node = NULL; + } + pScanLog->numSsid = (uint8_t) n; + pScanLog->totalSsid = (uint8_t) c; + ucfg_scan_purge_results(list); + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_saved_scan_cmd_free_fields() - Free internal fields of scan command + * + * @mac_ctx: Global MAC context + * @session: sme session + * + * Frees data structures allocated inside saved_scan_cmd and releases + * the profile. + * Return: None + */ + +void csr_saved_scan_cmd_free_fields(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session) +{ + if (session->scan_info.profile) { + sme_debug("Free profile for session %d", session->sessionId); + csr_release_profile(mac_ctx, + session->scan_info.profile); + qdf_mem_free(session->scan_info.profile); + session->scan_info.profile = NULL; + } + + if (session->scan_info.roambssentry) { + qdf_mem_free(session->scan_info.roambssentry); + session->scan_info.roambssentry = NULL; + } +} +/** + * csr_save_profile() - Save the profile info from sme command + * @mac_ctx: Global MAC context + * @save_cmd: Pointer where the command will be saved + * @command: Command from which the profile will be saved + * + * Saves the profile information from the SME's scan command + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_save_profile(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct tag_csrscan_result *scan_result; + struct tag_csrscan_result *temp; + uint32_t bss_len; + struct csr_roam_session *session; + + /* + * check the session's validity first, if session itself + * is not valid then there is no point of releasing the memory + * for invalid session (i.e. "goto error" case) + */ + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("session %d is invalid", session_id); + return QDF_STATUS_E_FAILURE; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session->scan_info.roambssentry) + return QDF_STATUS_SUCCESS; + + scan_result = GET_BASE_ADDR(session->scan_info.roambssentry, + struct tag_csrscan_result, Link); + + bss_len = scan_result->Result.BssDescriptor.length + + sizeof(scan_result->Result.BssDescriptor.length); + + temp = qdf_mem_malloc(sizeof(struct tag_csrscan_result) + bss_len); + if (!temp) { + sme_err("bss mem fail"); + goto error; + } + + temp->AgingCount = scan_result->AgingCount; + temp->preferValue = scan_result->preferValue; + temp->capValue = scan_result->capValue; + temp->ucEncryptionType = scan_result->ucEncryptionType; + temp->mcEncryptionType = scan_result->mcEncryptionType; + temp->authType = scan_result->authType; + /* pvIes is unsued in success/failure */ + temp->Result.pvIes = NULL; + + qdf_mem_copy(temp->Result.pvIes, + scan_result->Result.pvIes, + sizeof(*scan_result->Result.pvIes)); + temp->Result.ssId.length = scan_result->Result.ssId.length; + qdf_mem_copy(temp->Result.ssId.ssId, + scan_result->Result.ssId.ssId, + sizeof(scan_result->Result.ssId.ssId)); + temp->Result.timer = scan_result->Result.timer; + qdf_mem_copy(&temp->Result.BssDescriptor, + &scan_result->Result.BssDescriptor, + sizeof(temp->Result.BssDescriptor)); + temp->Link.last = temp->Link.next = NULL; + session->scan_info.roambssentry = (tListElem *)temp; + + return QDF_STATUS_SUCCESS; +error: + csr_scan_handle_search_for_ssid_failure(mac_ctx, + session_id); + csr_saved_scan_cmd_free_fields(mac_ctx, session); + + return QDF_STATUS_E_FAILURE; +} + +static void csr_handle_nxt_cmd(tpAniSirGlobal mac_ctx, + enum csr_scancomplete_nextcommand nxt_cmd, + uint32_t session_id, + uint8_t chan) +{ + QDF_STATUS status, ret; + struct csr_roam_session *session; + + switch (nxt_cmd) { + + case eCsrNexteScanForSsidSuccess: + csr_scan_handle_search_for_ssid(mac_ctx, session_id); + break; + case eCsrNexteScanForSsidFailure: + csr_scan_handle_search_for_ssid_failure(mac_ctx, session_id); + break; + case eCsrNextCheckAllowConc: + ret = policy_mgr_current_connections_update(mac_ctx->psoc, + session_id, chan, + POLICY_MGR_UPDATE_REASON_HIDDEN_STA); + sme_debug("chan: %d session: %d status: %d", + chan, session_id, ret); + + status = csr_save_profile(mac_ctx, session_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* csr_save_profile should report error */ + sme_err("profile save failed %d", status); + break; + } + + if (QDF_STATUS_E_FAILURE == ret) { + sme_err("conn update fail %d", chan); + csr_scan_handle_search_for_ssid_failure(mac_ctx, + session_id); + } else if ((QDF_STATUS_E_NOSUPPORT == ret) || + (QDF_STATUS_E_ALREADY == ret)) { + sme_err("conn update ret %d", ret); + csr_scan_handle_search_for_ssid(mac_ctx, session_id); + } + /* Else: Set hw mode was issued and the saved connect would + * be issued after set hw mode response + */ + if (QDF_IS_STATUS_SUCCESS(ret)) + return; + default: + break; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + if (session) + csr_saved_scan_cmd_free_fields(mac_ctx, session); +} + +void csr_scan_callback(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + eCsrScanStatus scan_status = eCSR_SCAN_FAILURE; + enum csr_scancomplete_nextcommand NextCommand = eCsrNextScanNothing; + tpAniSirGlobal mac_ctx; + struct csr_roam_session *session; + uint32_t session_id = 0; + uint8_t chan = 0; + bool success = false; + + mac_ctx = (tpAniSirGlobal)arg; + + 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; + + session_id = wlan_vdev_get_id(vdev); + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("session %d is invalid", session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + sme_debug("Scan Completion: status %d session %d scan_id %d", + scan_status, session_id, event->scan_id); + + /* verify whether scan event is related to scan interested by CSR */ + if (session->scan_info.scan_id != event->scan_id) { + sme_debug("Scan Completion on wrong scan_id %d, expected %d", + session->scan_info.scan_id, event->scan_id); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_scan_complete(mac_ctx, scan_status); +#endif + NextCommand = csr_scan_get_next_command_state(mac_ctx, + session_id, scan_status, + &chan); + /* We reuse the command here instead reissue a new command */ + csr_handle_nxt_cmd(mac_ctx, NextCommand, + session_id, chan); +} + +tCsrScanResultInfo *csr_scan_result_get_first(tpAniSirGlobal pMac, + tScanResultHandle hScanResult) +{ + tListElem *pEntry; + struct tag_csrscan_result *pResult; + tCsrScanResultInfo *pRet = NULL; + struct scan_result_list *pResultList = + (struct scan_result_list *) hScanResult; + + if (pResultList) { + csr_ll_lock(&pResultList->List); + 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; + csr_ll_unlock(&pResultList->List); + } + + return pRet; +} + +tCsrScanResultInfo *csr_scan_result_get_next(tpAniSirGlobal pMac, + 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; + + csr_ll_lock(&pResultList->List); + if (NULL == 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; + csr_ll_unlock(&pResultList->List); + return pRet; +} + +/* + * This function moves the first BSS that matches the bssid to the + * head of the result + */ +QDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssid, + tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct scan_result_list *pResultList = + (struct scan_result_list *) hScanResult; + struct tag_csrscan_result *pResult = NULL; + tListElem *pEntry = NULL; + + if (!(pResultList && bssid)) + return status; + + csr_ll_lock(&pResultList->List); + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + while (pEntry) { + pResult = GET_BASE_ADDR(pEntry, struct tag_csrscan_result, + Link); + if (!qdf_mem_cmp(bssid, pResult->Result.BssDescriptor.bssId, + sizeof(struct qdf_mac_addr))) { + status = QDF_STATUS_SUCCESS; + csr_ll_remove_entry(&pResultList->List, pEntry, + LL_ACCESS_NOLOCK); + csr_ll_insert_head(&pResultList->List, pEntry, + LL_ACCESS_NOLOCK); + break; + } + pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pResultList->List); + + return status; +} + +/** + * csr_scan_for_ssid() - Function usually used for BSSs that suppresses SSID + * @mac_ctx: Pointer to Global Mac structure + * @profile: pointer to struct csr_roam_profile + * @roam_id: variable representing roam id + * @notify: boolean variable + * + * Function is usually used for BSSs that suppresses SSID so the profile + * shall have one and only one SSID. + * + * Return: Success - QDF_STATUS_SUCCESS, Failure - error number + */ +QDF_STATUS csr_scan_for_ssid(tpAniSirGlobal mac_ctx, uint32_t session_id, + struct csr_roam_profile *profile, uint32_t roam_id, + bool notify) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t num_ssid = profile->SSIDs.numOfSSIDs; + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev; + uint8_t i, chan, num_chan = 0; + uint8_t pdev_id; + wlan_scan_id scan_id; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("session %d is invalid", session_id); + return status; + } + + if (!ucfg_scan_get_enable(mac_ctx->psoc) && (num_ssid != 1)) { + sme_err( + "cannot scan because scanEnable (%d) or numSSID (%d) is invalid", + ucfg_scan_get_enable(mac_ctx->psoc), profile->SSIDs.numOfSSIDs); + return status; + } + + if (!mac_ctx->pdev) { + sme_err("pdev ctx is NULL"); + return status; + } + pdev_id = wlan_objmgr_pdev_get_pdev_id(mac_ctx->pdev); + + /* Free old memory if any before its overwritten */ + csr_saved_scan_cmd_free_fields(mac_ctx, session); + session->scan_info.profile = + qdf_mem_malloc(sizeof(struct csr_roam_profile)); + if (!session->scan_info.profile) + status = QDF_STATUS_E_NOMEM; + else + status = csr_roam_copy_profile(mac_ctx, + session->scan_info.profile, + profile); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + scan_id = ucfg_scan_get_scan_id(mac_ctx->psoc); + session->scan_info.scan_id = scan_id; + session->scan_info.scan_reason = eCsrScanForSsid; + session->scan_info.roam_id = roam_id; + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to allocate memory")); + status = QDF_STATUS_E_NOMEM; + goto error; + } + + vdev = wlan_objmgr_get_vdev_by_macaddr_from_psoc(mac_ctx->psoc, + pdev_id, + session->selfMacAddr.bytes, + WLAN_LEGACY_SME_ID); + ucfg_scan_init_default_params(vdev, req); + req->scan_req.scan_id = scan_id; + req->scan_req.vdev_id = session_id; + req->scan_req.scan_req_id = mac_ctx->scan.requester_id; + req->scan_req.scan_f_passive = false; + req->scan_req.scan_f_bcast_probe = false; + + if (QDF_P2P_CLIENT_MODE == profile->csrPersona) + req->scan_req.scan_priority = SCAN_PRIORITY_HIGH; + + /* Allocate memory for IE field */ + if (profile->pAddIEScan) { + req->scan_req.extraie.ptr = + qdf_mem_malloc(profile->nAddIEScanLength); + + if (NULL == req->scan_req.extraie.ptr) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_copy(req->scan_req.extraie.ptr, + profile->pAddIEScan, + profile->nAddIEScanLength); + req->scan_req.extraie.len = profile->nAddIEScanLength; + } else { + sme_err("No memory for scanning IE fields"); + } + } + + req->scan_req.num_bssid = 1; + if (profile->BSSIDs.numOfBSSIDs == 1) + qdf_copy_macaddr(&req->scan_req.bssid_list[0], + profile->BSSIDs.bssid); + else + qdf_set_macaddr_broadcast(&req->scan_req.bssid_list[0]); + + if (profile->ChannelInfo.numOfChannels) { + for (i = 0; i < profile->ChannelInfo.numOfChannels; i++) { + if (csr_roam_is_valid_channel(mac_ctx, + profile->ChannelInfo.ChannelList[i])) { + chan = profile->ChannelInfo.ChannelList[i]; + req->scan_req.chan_list.chan[num_chan].freq = + wlan_chan_to_freq(chan); + num_chan++; + } + } + req->scan_req.chan_list.num_chan = num_chan; + } + + /* Extend it for multiple SSID */ + if (profile->SSIDs.numOfSSIDs) { + if (profile->SSIDs.SSIDList[0].SSID.length > MAX_SSID_LEN) { + sme_debug("wrong ssid length = %d", + profile->SSIDs.SSIDList[0].SSID.length); + status = QDF_STATUS_E_INVAL; + goto error; + } + req->scan_req.num_ssids = 1; + qdf_mem_copy(&req->scan_req.ssid[0].ssid, + &profile->SSIDs.SSIDList[0].SSID.ssId, + profile->SSIDs.SSIDList[0].SSID.length); + req->scan_req.ssid[0].length = + profile->SSIDs.SSIDList[0].SSID.length; + sme_debug("scan for SSID = %.*s", req->scan_req.ssid[0].length, + req->scan_req.ssid[0].ssid); + } + status = ucfg_scan_start(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +error: + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to initiate scan with status: %d", status); + csr_release_profile(mac_ctx, session->scan_info.profile); + qdf_mem_free(session->scan_info.profile); + session->scan_info.profile = NULL; + if (notify) + csr_roam_call_callback(mac_ctx, session_id, NULL, + roam_id, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; +} + +static void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, + uint8_t *pChannelList, uint8_t NumChannels) +{ + uint32_t dataLen = sizeof(uint8_t) * NumChannels; + QDF_STATUS status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: dump valid channel list(NumChannels(%d))", + __func__, NumChannels); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + pChannelList, NumChannels); + cfg_set_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, pChannelList, + dataLen); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Scan offload is enabled, update default chan list"); + /* + * disable fcc constraint since new country code + * is being set + */ + pMac->scan.fcc_constraint = false; + status = csr_update_channel_list(pMac); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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(tpAniSirGlobal pMac, tDblLinkList *pList, + uint32_t cfgId) +{ + tListElem *pEntry; + uint32_t cbLen = 0, dataLen, tmp_len; + struct csr_channel_powerinfo *ch_set; + uint32_t idx; + tSirMacChanInfo *ch_pwr_set; + uint8_t *pBuf = NULL; + + /* allocate maximum space for all channels */ + dataLen = WNI_CFG_VALID_CHANNEL_LIST_LEN * sizeof(tSirMacChanInfo); + pBuf = qdf_mem_malloc(dataLen); + if (pBuf == NULL) + return; + + ch_pwr_set = (tSirMacChanInfo *) (pBuf); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_LOCK); + /* + * 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 (1 != ch_set->interChannelOffset) { + /* + * 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(tSirMacChanInfo)); + if (tmp_len >= dataLen) { + /* + * expanding this entry will overflow our + * allocation + */ + sme_err( + "Buffer overflow, start %d, num %d, offset %d", + ch_set->firstChannel, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + + for (idx = 0; idx < ch_set->numChannels; idx++) { + ch_pwr_set->firstChanNum = (tSirMacChanNum) + (ch_set->firstChannel + (idx * + ch_set->interChannelOffset)); + sme_debug( + "Setting Channel Number %d", + ch_pwr_set->firstChanNum); + ch_pwr_set->numChannels = 1; + ch_pwr_set->maxTxPower = + QDF_MIN(ch_set->txPower, + pMac->roam.configParam.nTxPowerCap); + sme_debug( + "Setting Max Transmit Power %d", + ch_pwr_set->maxTxPower); + cbLen += sizeof(tSirMacChanInfo); + ch_pwr_set++; + } + } else { + if (cbLen >= dataLen) { + /* this entry will overflow our allocation */ + sme_err( + "Buffer overflow, start %d, num %d, offset %d", + ch_set->firstChannel, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + ch_pwr_set->firstChanNum = ch_set->firstChannel; + sme_debug("Setting Channel Number %d", + ch_pwr_set->firstChanNum); + ch_pwr_set->numChannels = ch_set->numChannels; + ch_pwr_set->maxTxPower = QDF_MIN(ch_set->txPower, + pMac->roam.configParam.nTxPowerCap); + sme_debug( + "Setting Max Tx Power %d, nTxPower %d", + ch_pwr_set->maxTxPower, + pMac->roam.configParam.nTxPowerCap); + cbLen += sizeof(tSirMacChanInfo); + ch_pwr_set++; + } + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_LOCK); + } + if (cbLen) + cfg_set_str(pMac, cfgId, (uint8_t *) pBuf, cbLen); + + qdf_mem_free(pBuf); +} + +static void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode) +{ + uint8_t cc[WNI_CFG_COUNTRY_CODE_LEN]; + /* v_REGDOMAIN_t DomainId */ + + sme_debug("Setting Country Code in Cfg %s", countryCode); + qdf_mem_copy(cc, countryCode, WNI_CFG_COUNTRY_CODE_LEN); + + /* + * Don't program the bogus country codes that we created for Korea in + * the MAC. if we see the bogus country codes, program the MAC with + * the right country code. + */ + if (('K' == countryCode[0] && '1' == countryCode[1]) || + ('K' == countryCode[0] && '2' == countryCode[1]) || + ('K' == countryCode[0] && '3' == countryCode[1]) || + ('K' == countryCode[0] && '4' == countryCode[1])) { + /* + * replace the alternate Korea country codes, 'K1', 'K2', .. + * with 'KR' for Korea + */ + cc[1] = 'R'; + } + cfg_set_str(pMac, WNI_CFG_COUNTRY_CODE, cc, WNI_CFG_COUNTRY_CODE_LEN); + + /* + * Need to let HALPHY know about the current domain so it can apply some + * domain-specific settings (TX filter...) + */ +} + +QDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf, + uint8_t *pbLen) +{ + QDF_STATUS status; + uint32_t len; + + if (pBuf && pbLen && (*pbLen >= WNI_CFG_COUNTRY_CODE_LEN)) { + len = *pbLen; + status = wlan_cfg_get_str(pMac, WNI_CFG_COUNTRY_CODE, pBuf, + &len); + if (status == QDF_STATUS_SUCCESS) { + *pbLen = (uint8_t) len; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_INVAL; +} + +QDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal mac_ctx, uint32_t vdev_id, + uint32_t scan_id) +{ + struct scan_cancel_request *req; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_err("Failed to allocate memory"); + return QDF_STATUS_E_NOMEM; + } + + /* Get NL global context from objmgr*/ + if (vdev_id == INVAL_VDEV_ID) + vdev = wlan_objmgr_pdev_get_first_vdev(mac_ctx->pdev, + WLAN_LEGACY_SME_ID); + else + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, + vdev_id, WLAN_LEGACY_SME_ID); + + if (!vdev) { + sme_err("Failed get vdev"); + qdf_mem_free(req); + return QDF_STATUS_E_INVAL; + } + + req->vdev = vdev; + req->cancel_req.scan_id = scan_id; + req->cancel_req.pdev_id = wlan_objmgr_pdev_get_pdev_id(mac_ctx->pdev); + req->cancel_req.vdev_id = vdev_id; + if (scan_id != INVAL_SCAN_ID) + req->cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE; + if (vdev_id == INVAL_VDEV_ID) + req->cancel_req.req_type = WLAN_SCAN_CANCEL_PDEV_ALL; + else + req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL; + + status = ucfg_scan_cancel(req); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Cancel scan request failed"); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + return status; +} +QDF_STATUS csr_remove_nonscan_cmd_from_pending_list(tpAniSirGlobal pMac, + uint8_t sessionId, + eSmeCommandType commandType) +{ + tDblLinkList localList; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pEntryToRemove; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + qdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(&localList))) { + sme_err("failed to open list"); + return status; + } + + csr_nonscan_pending_ll_lock(pMac); + pEntry = csr_nonscan_pending_ll_peek_head(pMac, 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) { + pEntryToRemove = pEntry; + pEntry = csr_nonscan_pending_ll_next(pMac, + pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link); + + if ((pCommand->command == commandType) && + (pCommand->sessionId == sessionId)) { + /* Insert to localList and remove later */ + csr_ll_insert_tail(&localList, pEntryToRemove, + LL_ACCESS_NOLOCK); + status = QDF_STATUS_SUCCESS; + } + } + csr_nonscan_pending_ll_unlock(pMac); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_debug("Sending abort for command ID %d", + sessionId); + csr_release_command(pMac, pCommand); + } + + csr_ll_close(&localList); + return status; +} +bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel) +{ + bool fValid = false; + uint32_t idx_valid_ch; + uint32_t len = pMac->roam.numValidChannels; + + for (idx_valid_ch = 0; (idx_valid_ch < len); idx_valid_ch++) { + if (channel == pMac->roam.validChannelList[idx_valid_ch]) { + fValid = true; + break; + } + } + return fValid; +} + +QDF_STATUS csr_scan_create_entry_in_scan_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr bssid, + uint8_t channel) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + tSirBssDescription *pNewBssDescriptor = NULL; + uint32_t size = 0; + + if (NULL == pSession) { + return QDF_STATUS_E_FAILURE; + } + sme_debug("Current bssid::"MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pSession->pConnectBssDesc->bssId)); + sme_debug("My bssid::"MAC_ADDRESS_STR" channel %d", + MAC_ADDR_ARRAY(bssid.bytes), channel); + + size = pSession->pConnectBssDesc->length + + sizeof(pSession->pConnectBssDesc->length); + if (!size) { + sme_err("length of bss descriptor is 0"); + return QDF_STATUS_E_FAILURE; + } + pNewBssDescriptor = qdf_mem_malloc(size); + if (NULL == pNewBssDescriptor) { + sme_err("memory allocation failed"); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(pNewBssDescriptor, pSession->pConnectBssDesc, size); + /* change the BSSID & channel as passed */ + qdf_mem_copy(pNewBssDescriptor->bssId, bssid.bytes, + sizeof(tSirMacAddr)); + pNewBssDescriptor->channelId = channel; + if (!csr_scan_append_bss_description(pMac, pNewBssDescriptor)) { + sme_err("csr_scan_append_bss_description failed"); + status = QDF_STATUS_E_FAILURE; + goto free_mem; + } + sme_err("entry successfully added in scan cache"); + +free_mem: + if (pNewBssDescriptor) + qdf_mem_free(pNewBssDescriptor); + + return status; +} + +#ifdef FEATURE_WLAN_ESE +/* Update the TSF with the difference in system time */ +void 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); +} +#endif + +/** + * csr_scan_save_roam_offload_ap_to_scan_cache + * This function parses the received beacon/probe response + * from the firmware as part of the roam synch indication. + * The beacon or the probe response is parsed and is also + * saved into the scan cache + * + * @param pMac Pointer to Global Mac + * @param roam_sync_ind_ptr Roam Synch Indication from + * firmware which also contains the beacon/probe + * response + * @return Status + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_scan_save_roam_offload_ap_to_scan_cache(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_sync_ind_ptr, + tpSirBssDescription bss_desc_ptr) +{ + uint32_t length = 0; + struct tag_csrscan_result *scan_res_ptr = NULL; + + length = roam_sync_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + scan_res_ptr = qdf_mem_malloc(sizeof(struct tag_csrscan_result) + + length); + if (scan_res_ptr == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + " fail to allocate memory for frame"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(&scan_res_ptr->Result.BssDescriptor, + bss_desc_ptr, + (sizeof(tSirBssDescription) + length)); + + sme_debug("LFR3:Add BSSID to scan cache" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(scan_res_ptr->Result.BssDescriptor.bssId)); + csr_scan_add_result(pMac, scan_res_ptr); + csr_free_scan_result_entry(pMac, scan_res_ptr); + return QDF_STATUS_SUCCESS; +} +#endif +/** + * csr_get_fst_bssdescr_ptr() - This function returns the pointer to first bss + * description from scan handle + * @result_handle: an object for the result. + * + * Return: first bss descriptor from the scan handle. + */ +tpSirBssDescription csr_get_fst_bssdescr_ptr(tScanResultHandle result_handle) +{ + tListElem *first_element = NULL; + struct tag_csrscan_result *scan_result = NULL; + struct scan_result_list *bss_list = + (struct scan_result_list *)result_handle; + + if (NULL == bss_list) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Empty bss_list")); + return NULL; + } + if (csr_ll_is_list_empty(&bss_list->List, LL_ACCESS_NOLOCK)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("bss_list->List is empty")); + return NULL; + } + first_element = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + if (NULL == first_element) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("peer head return NULL")); + return NULL; + } + + scan_result = GET_BASE_ADDR(first_element, struct tag_csrscan_result, + Link); + + return &scan_result->Result.BssDescriptor; +} + +/** + * csr_get_bssdescr_from_scan_handle() - This function to extract + * first bss description from scan handle + * @result_handle: an object for the result. + * + * This function is written to extract first bss from scan handle. + * + * Return: first bss descriptor from the scan handle. + */ +tSirBssDescription* +csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle, + tSirBssDescription *bss_descr) +{ + tListElem *first_element = NULL; + struct tag_csrscan_result *scan_result = NULL; + struct scan_result_list *bss_list = + (struct scan_result_list *)result_handle; + + if (NULL == bss_list) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Empty bss_list")); + return NULL; + } + if (csr_ll_is_list_empty(&bss_list->List, LL_ACCESS_NOLOCK)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("bss_list->List is empty")); + qdf_mem_free(bss_list); + return NULL; + } + first_element = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + if (first_element) { + scan_result = GET_BASE_ADDR(first_element, + struct tag_csrscan_result, + Link); + qdf_mem_copy(bss_descr, + &scan_result->Result.BssDescriptor, + sizeof(tSirBssDescription)); + } + return bss_descr; +} + +uint8_t +csr_get_channel_for_hw_mode_change(tpAniSirGlobal mac_ctx, + tScanResultHandle result_handle, + uint32_t session_id) +{ + tListElem *next_element = NULL; + struct tag_csrscan_result *scan_result = NULL; + struct scan_result_list *bss_list = + (struct scan_result_list *)result_handle; + uint8_t channel_id = 0; + + if (NULL == bss_list) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Empty bss_list")); + goto end; + } + + if (policy_mgr_is_hw_dbs_capable(mac_ctx->psoc) == false) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("driver isn't dbs capable")); + goto end; + } + + if (policy_mgr_is_current_hwmode_dbs(mac_ctx->psoc)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("driver is already in DBS")); + goto end; + } + + if (!policy_mgr_is_dbs_allowed_for_concurrency(mac_ctx->psoc, + QDF_STA_MODE)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("DBS is not allowed for this concurrency combo")); + goto end; + } + + if (!policy_mgr_is_hw_dbs_2x2_capable(mac_ctx->psoc) && + !policy_mgr_get_connection_count(mac_ctx->psoc)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("1x1 DBS HW with no prior connection")); + goto end; + } + + if (csr_ll_is_list_empty(&bss_list->List, LL_ACCESS_NOLOCK)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("bss_list->List is empty")); + qdf_mem_free(bss_list); + goto end; + } + + next_element = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + while (next_element) { + scan_result = GET_BASE_ADDR(next_element, + struct tag_csrscan_result, + Link); + if (policy_mgr_is_hw_dbs_2x2_capable(mac_ctx->psoc)) { + if (WLAN_REG_IS_24GHZ_CH + (scan_result->Result.BssDescriptor.channelId)) { + channel_id = + scan_result-> + Result.BssDescriptor.channelId; + break; + } + } else { + if (WLAN_REG_IS_24GHZ_CH + (scan_result->Result.BssDescriptor.channelId) && + policy_mgr_is_any_mode_active_on_band_along_with_session + (mac_ctx->psoc, + session_id, POLICY_MGR_BAND_5)) { + channel_id = + scan_result-> + Result.BssDescriptor.channelId; + break; + } + if (WLAN_REG_IS_5GHZ_CH + (scan_result->Result.BssDescriptor.channelId) && + policy_mgr_is_any_mode_active_on_band_along_with_session + (mac_ctx->psoc, + session_id, POLICY_MGR_BAND_24)) { + channel_id = + scan_result-> + Result.BssDescriptor.channelId; + break; + } + } + next_element = csr_ll_next(&bss_list->List, next_element, + LL_ACCESS_NOLOCK); + } +end: + return channel_id; +} + +uint8_t +csr_scan_get_channel_for_hw_mode_change( + tpAniSirGlobal mac_ctx, uint32_t session_id, + struct csr_roam_profile *profile) +{ + tScanResultHandle result_handle = NULL; + QDF_STATUS status; + uint8_t first_ap_ch = 0; + uint8_t candidate_chan; + + status = sme_get_ap_channel_from_scan_cache(profile, &result_handle, + &first_ap_ch); + if (status != QDF_STATUS_SUCCESS || !result_handle || !first_ap_ch) { + if (result_handle) + sme_scan_result_purge(result_handle); + sme_err("fail get scan result: status %d first ap ch %d", + status, first_ap_ch); + return 0; + } + if (!policy_mgr_check_for_session_conc(mac_ctx->psoc, session_id, + first_ap_ch)) { + sme_scan_result_purge(result_handle); + sme_err("Conc not allowed for the session %d ch %d", + session_id, first_ap_ch); + return 0; + } + + candidate_chan = csr_get_channel_for_hw_mode_change(mac_ctx, + result_handle, + session_id); + sme_scan_result_purge(result_handle); + if (!candidate_chan) + candidate_chan = first_ap_ch; + sme_debug("session %d hw mode check candidate_chan %d", session_id, + candidate_chan); + + return candidate_chan; +} + +static enum wlan_auth_type csr_covert_auth_type_new(eCsrAuthType auth) +{ + switch (auth) { + case eCSR_AUTH_TYPE_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + return WLAN_AUTH_TYPE_OPEN_SYSTEM; + case eCSR_AUTH_TYPE_SHARED_KEY: + return WLAN_AUTH_TYPE_SHARED_KEY; + case eCSR_AUTH_TYPE_AUTOSWITCH: + return WLAN_AUTH_TYPE_AUTOSWITCH; + case eCSR_AUTH_TYPE_WPA: + return WLAN_AUTH_TYPE_WPA; + case eCSR_AUTH_TYPE_WPA_PSK: + return WLAN_AUTH_TYPE_WPA_PSK; + case eCSR_AUTH_TYPE_WPA_NONE: + return WLAN_AUTH_TYPE_WPA_NONE; + case eCSR_AUTH_TYPE_RSN: + return WLAN_AUTH_TYPE_RSN; + case eCSR_AUTH_TYPE_RSN_PSK: + return WLAN_AUTH_TYPE_RSN_PSK; + case eCSR_AUTH_TYPE_FT_RSN: + return WLAN_AUTH_TYPE_FT_RSN; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + return WLAN_AUTH_TYPE_FT_RSN_PSK; + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + return WLAN_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + return WLAN_AUTH_TYPE_WAPI_WAI_PSK; + case eCSR_AUTH_TYPE_CCKM_WPA: + return WLAN_AUTH_TYPE_CCKM_WPA; + case eCSR_AUTH_TYPE_CCKM_RSN: + return WLAN_AUTH_TYPE_CCKM_RSN; + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + return WLAN_AUTH_TYPE_RSN_PSK_SHA256; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + return WLAN_AUTH_TYPE_RSN_8021X_SHA256; + case eCSR_AUTH_TYPE_FILS_SHA256: + return WLAN_AUTH_TYPE_FILS_SHA256; + case eCSR_AUTH_TYPE_FILS_SHA384: + return WLAN_AUTH_TYPE_FILS_SHA384; + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return WLAN_AUTH_TYPE_FT_FILS_SHA256; + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return WLAN_AUTH_TYPE_FT_FILS_SHA384; + case eCSR_AUTH_TYPE_DPP_RSN: + return WLAN_AUTH_TYPE_DPP_RSN; + case eCSR_AUTH_TYPE_OWE: + return WLAN_AUTH_TYPE_OWE; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA256: + return WLAN_AUTH_TYPE_SUITEB_EAP_SHA256; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA384: + return WLAN_AUTH_TYPE_SUITEB_EAP_SHA384; + case eCSR_AUTH_TYPE_SAE: + return WLAN_AUTH_TYPE_SAE; + case eCSR_NUM_OF_SUPPORT_AUTH_TYPE: + default: + return WLAN_AUTH_TYPE_OPEN_SYSTEM; + } +} + +static eCsrAuthType csr_covert_auth_type_old(enum wlan_auth_type auth) +{ + switch (auth) { + case WLAN_AUTH_TYPE_OPEN_SYSTEM: + return eCSR_AUTH_TYPE_OPEN_SYSTEM; + case WLAN_AUTH_TYPE_SHARED_KEY: + return eCSR_AUTH_TYPE_SHARED_KEY; + case WLAN_AUTH_TYPE_AUTOSWITCH: + return eCSR_AUTH_TYPE_AUTOSWITCH; + case WLAN_AUTH_TYPE_WPA: + return eCSR_AUTH_TYPE_WPA; + case WLAN_AUTH_TYPE_WPA_PSK: + return eCSR_AUTH_TYPE_WPA_PSK; + case WLAN_AUTH_TYPE_WPA_NONE: + return eCSR_AUTH_TYPE_WPA_NONE; + case WLAN_AUTH_TYPE_RSN: + return eCSR_AUTH_TYPE_RSN; + case WLAN_AUTH_TYPE_RSN_PSK: + return eCSR_AUTH_TYPE_RSN_PSK; + case WLAN_AUTH_TYPE_FT_RSN: + return eCSR_AUTH_TYPE_FT_RSN; + case WLAN_AUTH_TYPE_FT_RSN_PSK: + return eCSR_AUTH_TYPE_FT_RSN_PSK; + case WLAN_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + return eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + case WLAN_AUTH_TYPE_WAPI_WAI_PSK: + return eCSR_AUTH_TYPE_WAPI_WAI_PSK; + case WLAN_AUTH_TYPE_CCKM_WPA: + return eCSR_AUTH_TYPE_CCKM_WPA; + case WLAN_AUTH_TYPE_CCKM_RSN: + return eCSR_AUTH_TYPE_CCKM_RSN; + case WLAN_AUTH_TYPE_RSN_PSK_SHA256: + return eCSR_AUTH_TYPE_RSN_PSK_SHA256; + case WLAN_AUTH_TYPE_RSN_8021X_SHA256: + return eCSR_AUTH_TYPE_RSN_8021X_SHA256; + case WLAN_AUTH_TYPE_FILS_SHA256: + return eCSR_AUTH_TYPE_FILS_SHA256; + case WLAN_AUTH_TYPE_FILS_SHA384: + return eCSR_AUTH_TYPE_FILS_SHA384; + case WLAN_AUTH_TYPE_FT_FILS_SHA256: + return eCSR_AUTH_TYPE_FT_FILS_SHA256; + case WLAN_AUTH_TYPE_FT_FILS_SHA384: + return eCSR_AUTH_TYPE_FT_FILS_SHA384; + case WLAN_AUTH_TYPE_DPP_RSN: + return eCSR_AUTH_TYPE_DPP_RSN; + case WLAN_AUTH_TYPE_OWE: + return eCSR_AUTH_TYPE_OWE; + case WLAN_AUTH_TYPE_SUITEB_EAP_SHA256: + return eCSR_AUTH_TYPE_SUITEB_EAP_SHA256; + case WLAN_AUTH_TYPE_SUITEB_EAP_SHA384: + return eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; + case WLAN_AUTH_TYPE_SAE: + return eCSR_AUTH_TYPE_SAE; + case WLAN_NUM_OF_SUPPORT_AUTH_TYPE: + default: + return eCSR_AUTH_TYPE_OPEN_SYSTEM; + } +} + +static enum wlan_enc_type csr_covert_enc_type_new(eCsrEncryptionType enc) +{ + switch (enc) { + case eCSR_ENCRYPT_TYPE_NONE: + return WLAN_ENCRYPT_TYPE_NONE; + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + return WLAN_ENCRYPT_TYPE_WEP40_STATICKEY; + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + return WLAN_ENCRYPT_TYPE_WEP104_STATICKEY; + case eCSR_ENCRYPT_TYPE_WEP40: + return WLAN_ENCRYPT_TYPE_WEP40; + case eCSR_ENCRYPT_TYPE_WEP104: + return WLAN_ENCRYPT_TYPE_WEP104; + case eCSR_ENCRYPT_TYPE_TKIP: + return WLAN_ENCRYPT_TYPE_TKIP; + case eCSR_ENCRYPT_TYPE_AES: + return WLAN_ENCRYPT_TYPE_AES; + case eCSR_ENCRYPT_TYPE_WPI: + return WLAN_ENCRYPT_TYPE_WPI; + case eCSR_ENCRYPT_TYPE_KRK: + return WLAN_ENCRYPT_TYPE_KRK; + case eCSR_ENCRYPT_TYPE_BTK: + return WLAN_ENCRYPT_TYPE_BTK; + case eCSR_ENCRYPT_TYPE_AES_CMAC: + return WLAN_ENCRYPT_TYPE_AES_CMAC; + case eCSR_ENCRYPT_TYPE_AES_GCMP: + return WLAN_ENCRYPT_TYPE_AES_GCMP; + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + return WLAN_ENCRYPT_TYPE_AES_GCMP_256; + case eCSR_ENCRYPT_TYPE_ANY: + default: + return WLAN_ENCRYPT_TYPE_NONE; + } +} + +static eCsrEncryptionType csr_covert_enc_type_old(enum wlan_enc_type enc) +{ + switch (enc) { + case WLAN_ENCRYPT_TYPE_NONE: + return eCSR_ENCRYPT_TYPE_NONE; + case WLAN_ENCRYPT_TYPE_WEP40_STATICKEY: + return eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + case WLAN_ENCRYPT_TYPE_WEP104_STATICKEY: + return eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + case WLAN_ENCRYPT_TYPE_WEP40: + return eCSR_ENCRYPT_TYPE_WEP40; + case WLAN_ENCRYPT_TYPE_WEP104: + return eCSR_ENCRYPT_TYPE_WEP104; + case WLAN_ENCRYPT_TYPE_TKIP: + return eCSR_ENCRYPT_TYPE_TKIP; + case WLAN_ENCRYPT_TYPE_AES: + return eCSR_ENCRYPT_TYPE_AES; + case WLAN_ENCRYPT_TYPE_WPI: + return eCSR_ENCRYPT_TYPE_WPI; + case WLAN_ENCRYPT_TYPE_KRK: + return eCSR_ENCRYPT_TYPE_KRK; + case WLAN_ENCRYPT_TYPE_BTK: + return eCSR_ENCRYPT_TYPE_BTK; + case WLAN_ENCRYPT_TYPE_AES_CMAC: + return eCSR_ENCRYPT_TYPE_AES_CMAC; + case WLAN_ENCRYPT_TYPE_AES_GCMP: + return eCSR_ENCRYPT_TYPE_AES_GCMP; + case WLAN_ENCRYPT_TYPE_AES_GCMP_256: + return eCSR_ENCRYPT_TYPE_AES_GCMP_256; + case WLAN_ENCRYPT_TYPE_ANY: + default: + return eCSR_ENCRYPT_TYPE_NONE; + } +} + +#ifdef WLAN_FEATURE_11W +/** + * csr_update_pmf_cap: Updates PMF cap + * @src_filter: Source filter + * @dst_filter: Destination filter + * + * Return: None + */ +static void csr_update_pmf_cap(tCsrScanResultFilter *src_filter, + struct scan_filter *dst_filter) { + + if (src_filter->MFPCapable || src_filter->MFPEnabled) + dst_filter->pmf_cap = WLAN_PMF_CAPABLE; + if (src_filter->MFPRequired) + dst_filter->pmf_cap = WLAN_PMF_REQUIRED; +} +#else +static inline void csr_update_pmf_cap(tCsrScanResultFilter *src_filter, + struct scan_filter *dst_filter) +{} +#endif + +/** + * csr_convert_dotllmod_phymode: Convert eCsrPhyMode to wlan_phymode + * @dotllmode: phy mode + * + * Return: returns enum wlan_phymode + */ +static enum wlan_phymode csr_convert_dotllmod_phymode(eCsrPhyMode dotllmode) +{ + + enum wlan_phymode con_phy_mode; + + switch (dotllmode) { + case eCSR_DOT11_MODE_abg: + con_phy_mode = WLAN_PHYMODE_AUTO; + break; + case eCSR_DOT11_MODE_11a: + con_phy_mode = WLAN_PHYMODE_11A; + break; + case eCSR_DOT11_MODE_11b: + con_phy_mode = WLAN_PHYMODE_11B; + break; + case eCSR_DOT11_MODE_11g: + con_phy_mode = WLAN_PHYMODE_11G; + break; + case eCSR_DOT11_MODE_11n: + con_phy_mode = WLAN_PHYMODE_11NA_HT20; + break; + case eCSR_DOT11_MODE_11g_ONLY: + con_phy_mode = WLAN_PHYMODE_11G; + break; + case eCSR_DOT11_MODE_11n_ONLY: + con_phy_mode = WLAN_PHYMODE_11NA_HT20; + break; + case eCSR_DOT11_MODE_11b_ONLY: + con_phy_mode = WLAN_PHYMODE_11B; + break; + case eCSR_DOT11_MODE_11ac: + con_phy_mode = WLAN_PHYMODE_11AC_VHT160; + break; + case eCSR_DOT11_MODE_11ac_ONLY: + con_phy_mode = WLAN_PHYMODE_11AC_VHT160; + break; + case eCSR_DOT11_MODE_AUTO: + con_phy_mode = WLAN_PHYMODE_AUTO; + break; + case eCSR_DOT11_MODE_11ax: + con_phy_mode = WLAN_PHYMODE_11AXA_HE160; + break; + case eCSR_DOT11_MODE_11ax_ONLY: + con_phy_mode = WLAN_PHYMODE_11AXA_HE160; + break; + default: + con_phy_mode = WLAN_PHYMODE_AUTO; + break; + } + + return con_phy_mode; +} + +static QDF_STATUS csr_prepare_scan_filter(tpAniSirGlobal mac_ctx, + tCsrScanResultFilter *pFilter, struct scan_filter *filter) +{ + int i; + uint32_t len = 0; + QDF_STATUS status; + enum policy_mgr_con_mode new_mode; + + filter->num_of_bssid = pFilter->BSSIDs.numOfBSSIDs; + if (filter->num_of_bssid > WLAN_SCAN_FILTER_NUM_BSSID) + filter->num_of_bssid = WLAN_SCAN_FILTER_NUM_BSSID; + for (i = 0; i < filter->num_of_bssid; i++) + qdf_mem_copy(filter->bssid_list[i].bytes, + pFilter->BSSIDs.bssid[i].bytes, + QDF_MAC_ADDR_SIZE); + + filter->num_of_ssid = pFilter->SSIDs.numOfSSIDs; + if (filter->num_of_ssid > WLAN_SCAN_FILTER_NUM_SSID) + filter->num_of_ssid = WLAN_SCAN_FILTER_NUM_SSID; + for (i = 0; i < filter->num_of_ssid; i++) { + filter->ssid_list[i].length = + pFilter->SSIDs.SSIDList[i].SSID.length; + qdf_mem_copy(filter->ssid_list[i].ssid, + pFilter->SSIDs.SSIDList[i].SSID.ssId, + filter->ssid_list[i].length); + } + + filter->num_of_channels = + pFilter->ChannelInfo.numOfChannels; + if (filter->num_of_channels > QDF_MAX_NUM_CHAN) + filter->num_of_channels = QDF_MAX_NUM_CHAN; + qdf_mem_copy(filter->channel_list, + pFilter->ChannelInfo.ChannelList, + filter->num_of_channels); + + if (pFilter->realm_check) { + filter->fils_scan_filter.realm_check = true; + qdf_mem_copy(filter->fils_scan_filter.fils_realm, + pFilter->fils_realm, REAM_HASH_LEN); + } + + if (pFilter->force_rsne_override) { + + sme_debug("force_rsne_override set auth type and enctype to any and ignore pmf cap"); + + filter->num_of_auth = 1; + filter->auth_type[0] = WLAN_AUTH_TYPE_ANY; + filter->num_of_enc_type = 1; + filter->enc_type[0] = WLAN_ENCRYPT_TYPE_ANY; + filter->num_of_mc_enc_type = 1; + filter->mc_enc_type[0] = WLAN_ENCRYPT_TYPE_ANY; + + filter->ignore_pmf_cap = true; + } else { + filter->num_of_auth = + pFilter->authType.numEntries; + if (filter->num_of_auth > WLAN_NUM_OF_SUPPORT_AUTH_TYPE) + filter->num_of_auth = WLAN_NUM_OF_SUPPORT_AUTH_TYPE; + for (i = 0; i < filter->num_of_auth; i++) + filter->auth_type[i] = + csr_covert_auth_type_new( + pFilter->authType.authType[i]); + filter->num_of_enc_type = + pFilter->EncryptionType.numEntries; + if (filter->num_of_enc_type > WLAN_NUM_OF_ENCRYPT_TYPE) + filter->num_of_enc_type = WLAN_NUM_OF_ENCRYPT_TYPE; + for (i = 0; i < filter->num_of_enc_type; i++) + filter->enc_type[i] = + csr_covert_enc_type_new( + pFilter->EncryptionType.encryptionType[i]); + filter->num_of_mc_enc_type = + pFilter->mcEncryptionType.numEntries; + if (filter->num_of_mc_enc_type > WLAN_NUM_OF_ENCRYPT_TYPE) + filter->num_of_mc_enc_type = WLAN_NUM_OF_ENCRYPT_TYPE; + for (i = 0; i < filter->num_of_mc_enc_type; i++) + filter->mc_enc_type[i] = + csr_covert_enc_type_new( + pFilter->mcEncryptionType.encryptionType[i]); + } + qdf_mem_copy(filter->country, + pFilter->countryCode, WNI_CFG_COUNTRY_CODE_LEN); + + if (pFilter->bWPSAssociation || pFilter->bOSENAssociation) + filter->ignore_auth_enc_type = true; + + filter->rrm_measurement_filter = pFilter->fMeasurement; + + filter->mobility_domain = pFilter->MDID.mobilityDomain; + + filter->p2p_results = pFilter->p2pResult; + + csr_update_pmf_cap(pFilter, filter); + + if (pFilter->BSSType == eCSR_BSS_TYPE_INFRASTRUCTURE) + filter->bss_type = WLAN_TYPE_BSS; + else if (pFilter->BSSType == eCSR_BSS_TYPE_IBSS || + pFilter->BSSType == eCSR_BSS_TYPE_START_IBSS) + filter->bss_type = WLAN_TYPE_IBSS; + else + filter->bss_type = WLAN_TYPE_ANY; + + filter->dot11_mode = csr_convert_dotllmod_phymode(pFilter->phyMode); + + // enable bss scoring for only STA mode + if (pFilter->csrPersona == QDF_STA_MODE) + filter->bss_scoring_required = true; + else + filter->bss_scoring_required = false; + if (!pFilter->BSSIDs.numOfBSSIDs) { + if (policy_mgr_map_concurrency_mode( + &pFilter->csrPersona, &new_mode)) { + status = policy_mgr_get_pcl(mac_ctx->psoc, new_mode, + filter->pcl_channel_list, &len, + filter->pcl_weight_list, QDF_MAX_NUM_CHAN); + filter->num_of_pcl_channels = (uint8_t)len; + } + } + qdf_mem_copy(filter->bssid_hint.bytes, + pFilter->bssid_hint.bytes, + QDF_MAC_ADDR_SIZE); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * csr_update_bss_with_fils_data: Fill FILS params in bss desc from scan entry + * @mac_ctx: mac context + * @scan_entry: scan entry + * @bss_descr: bss description + */ +static void csr_update_bss_with_fils_data(tpAniSirGlobal mac_ctx, + struct scan_cache_entry *scan_entry, + tSirBssDescription *bss_descr) +{ + int ret; + tDot11fIEfils_indication fils_indication = {0}; + struct sir_fils_indication fils_ind; + + if (!scan_entry->ie_list.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)) { + sme_err("unpack failed ret: 0x%x", ret); + 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); + 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; +} +#else +static void csr_update_bss_with_fils_data(tpAniSirGlobal mac_ctx, + struct scan_cache_entry *scan_entry, + tSirBssDescription *bss_descr) +{ } +#endif + +static QDF_STATUS csr_fill_bss_from_scan_entry(tpAniSirGlobal mac_ctx, + struct scan_cache_entry *scan_entry, + struct tag_csrscan_result **p_result) +{ + tDot11fBeaconIEs *bcn_ies; + tSirBssDescription *bss_desc; + tCsrScanResultInfo *result_info; + tpSirMacMgmtHdr hdr; + uint8_t *ie_ptr; + struct tag_csrscan_result *bss; + uint32_t bss_len, alloc_len, ie_len; + QDF_STATUS status; + + ie_len = util_scan_entry_ie_len(scan_entry); + ie_ptr = util_scan_entry_ie_data(scan_entry); + + hdr = (tpSirMacMgmtHdr)scan_entry->raw_frame.ptr; + + bss_len = (uint16_t)(offsetof(tSirBssDescription, + ieFields[0]) + ie_len); + alloc_len = sizeof(struct tag_csrscan_result) + bss_len; + bss = qdf_mem_malloc(alloc_len); + + if (!bss) { + sme_err("could not allocate bss"); + return QDF_STATUS_E_NOMEM; + } + + bss->AgingCount = + (int32_t) mac_ctx->roam.configParam.agingCount; + bss->ucEncryptionType = + csr_covert_enc_type_old(scan_entry->neg_sec_info.uc_enc); + bss->mcEncryptionType = + csr_covert_enc_type_old(scan_entry->neg_sec_info.mc_enc); + bss->authType = + csr_covert_auth_type_old(scan_entry->neg_sec_info.auth_type); + bss->bss_score = scan_entry->bss_score; + + 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; + + bss_desc->length = (uint16_t) (offsetof(tSirBssDescription, + ieFields[0]) - sizeof(bss_desc->length) + ie_len); + + qdf_mem_copy(bss_desc->bssId, + scan_entry->bssid.bytes, + QDF_MAC_ADDR_SIZE); + bss_desc->scansystimensec = scan_entry->scan_entry_time; + 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(scan_entry->channel.chan_idx)) + 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; + + /* channelId what peer sent in beacon/probersp. */ + bss_desc->channelId = + scan_entry->channel.chan_idx; + /* channelId on which we are parked at. */ + /* used only in scan case. */ + bss_desc->channelIdSelf = + scan_entry->channel.chan_idx; + bss_desc->rx_channel = bss_desc->channelIdSelf; + bss_desc->received_time = + scan_entry->scan_entry_time; + 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 == + IEEE80211_FC0_SUBTYPE_PROBE_RESP); + bss_desc->seq_ctrl = hdr->seqControl; + bss_desc->tsf_delta = scan_entry->tsf_delta; + + qdf_mem_copy((uint8_t *) &bss_desc->ieFields, + ie_ptr, ie_len); + + status = csr_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; + + 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)); + } +#ifdef FEATURE_WLAN_ESE + if (bcn_ies->QBSSLoad.present) { + bss_desc->QBSSLoad_present = true; + bss_desc->QBSSLoad_avail = + bcn_ies->QBSSLoad.avail; + } +#endif + csr_update_bss_with_fils_data(mac_ctx, scan_entry, bss_desc); + if (scan_entry->alt_wcn_ie.ptr) { + bss_desc->WscIeLen = scan_entry->alt_wcn_ie.len; + qdf_mem_copy(bss_desc->WscIeProbeRsp, + scan_entry->alt_wcn_ie.ptr, + scan_entry->alt_wcn_ie.len); + } + + *p_result = bss; + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS csr_parse_scan_list(tpAniSirGlobal mac_ctx, + struct scan_result_list *ret_list, + qdf_list_t *scan_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tag_csrscan_result *pResult = NULL; + struct scan_cache_node *cur_node = NULL; + struct scan_cache_node *next_node = NULL; + + status = + 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); + status = csr_fill_bss_from_scan_entry(mac_ctx, + cur_node->entry, &pResult); + if (QDF_IS_STATUS_ERROR(status)) + return status; + if (pResult) + csr_ll_insert_tail(&ret_list->List, &pResult->Link, + LL_ACCESS_NOLOCK); + cur_node = next_node; + next_node = NULL; + } + + return status; +} + +/** + * csr_remove_ap_due_to_rssi() - check if bss is present in + * list of BSSID which rejected Assoc due to RSSI + * @list: rssi based rejected BSS list + * @bss_descr: pointer to bss description + * + * Check if the time interval indicated in last Assoc reject + * has expired OR rssi has improved by margin indicated + * in last Assoc reject. If any of the condition match remove + * the AP from the avoid list, else do not try to conenct + * to the AP + * + * Return: true if connection cannot be tried with AP else false + */ +static bool csr_remove_ap_due_to_rssi(qdf_list_t *list, + tSirBssDescription *bss_descr) +{ + QDF_STATUS status; + struct sir_rssi_disallow_lst *cur_node = NULL; + qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; + qdf_time_t cur_time; + uint32_t time_diff; + + if (!qdf_list_size(list)) + return false; + + cur_time = qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + + qdf_list_peek_front(list, &cur_lst); + while (cur_lst) { + cur_node = qdf_container_of(cur_lst, + struct sir_rssi_disallow_lst, node); + + qdf_list_peek_next(list, cur_lst, &next_lst); + + time_diff = cur_time - cur_node->time_during_rejection; + if ((time_diff > cur_node->retry_delay)) { + sme_debug("Remove %pM as time diff %d is greater retry delay %d", + cur_node->bssid.bytes, time_diff, + cur_node->retry_delay); + status = qdf_list_remove_node(list, cur_lst); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(cur_node); + cur_lst = next_lst; + next_lst = NULL; + cur_node = NULL; + continue; + } + + if (!qdf_mem_cmp(cur_node->bssid.bytes, + bss_descr->bssId, QDF_MAC_ADDR_SIZE)) + break; + cur_lst = next_lst; + next_lst = NULL; + cur_node = NULL; + } + + if (cur_node) { + time_diff = cur_time - cur_node->time_during_rejection; + if (!(time_diff > cur_node->retry_delay || + bss_descr->rssi_raw >= cur_node->expected_rssi)) { + sme_err("Don't Attempt to connect %pM (time diff %d retry delay %d rssi %d expected rssi %d)", + cur_node->bssid.bytes, time_diff, + cur_node->retry_delay, bss_descr->rssi_raw, + cur_node->expected_rssi); + return true; + } + sme_debug("Remove %pM as time diff %d is greater retry delay %d or RSSI %d is greater than expected %d", + cur_node->bssid.bytes, time_diff, + cur_node->retry_delay, + bss_descr->rssi_raw, + cur_node->expected_rssi); + status = qdf_list_remove_node(list, cur_lst); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(cur_node); + } + + return false; +} + +/** + * csr_filter_ap_due_to_rssi_reject() - filter the AP who has sent + * assoc reject due to RSSI if condition has not improved + * @mac_ctx: mac context + * @scan_list: candidate list for the connection + * + * Return: void + */ +static void csr_filter_ap_due_to_rssi_reject(tpAniSirGlobal mac_ctx, + struct scan_result_list *scan_list) +{ + tListElem *cur_entry; + tListElem *next_entry; + struct tag_csrscan_result *scan_res; + bool remove; + + if (!scan_list || + !qdf_list_size(&mac_ctx->roam.rssi_disallow_bssid)) + return; + + csr_ll_lock(&scan_list->List); + + cur_entry = csr_ll_peek_head(&scan_list->List, LL_ACCESS_NOLOCK); + while (cur_entry) { + scan_res = GET_BASE_ADDR(cur_entry, struct tag_csrscan_result, + Link); + next_entry = csr_ll_next(&scan_list->List, + cur_entry, LL_ACCESS_NOLOCK); + + qdf_mutex_acquire(&mac_ctx->roam.rssi_disallow_bssid_lock); + remove = csr_remove_ap_due_to_rssi( + &mac_ctx->roam.rssi_disallow_bssid, + &scan_res->Result.BssDescriptor); + qdf_mutex_release(&mac_ctx->roam.rssi_disallow_bssid_lock); + + if (remove) { + csr_ll_remove_entry(&scan_list->List, + cur_entry, LL_ACCESS_NOLOCK); + csr_free_scan_result_entry(mac_ctx, scan_res); + } + cur_entry = next_entry; + next_entry = NULL; + } + csr_ll_unlock(&scan_list->List); + +} + +QDF_STATUS csr_scan_get_result(tpAniSirGlobal mac_ctx, + tCsrScanResultFilter *pFilter, + tScanResultHandle *results) +{ + QDF_STATUS status; + struct scan_result_list *ret_list = NULL; + qdf_list_t *list = NULL; + struct scan_filter *filter = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + + 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; + } + + if (pFilter) { + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) { + status = QDF_STATUS_E_NOMEM; + goto error; + } + + status = csr_prepare_scan_filter(mac_ctx, pFilter, filter); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Prepare filter failed"); + goto error; + } + } + + list = ucfg_scan_get_result(pdev, + pFilter ? filter : NULL); + if (list) + sme_debug("num_entries %d", qdf_list_size(list)); + + if (!list || (list && !qdf_list_size(list))) { + sme_err("get scan result failed"); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + ret_list = qdf_mem_malloc(sizeof(struct scan_result_list)); + if (!ret_list) { + sme_err("pRetList is NULL"); + 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); + sme_debug("status: %d No of BSS: %d", + status, csr_ll_count(&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 (pFilter) + csr_filter_ap_due_to_rssi_reject(mac_ctx, ret_list); + 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); + status = QDF_STATUS_E_NULL_VALUE; + } else if (results) { + *results = ret_list; + } + } + +error: + if (filter) + qdf_mem_free(filter); + if (list) + ucfg_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(tpAniSirGlobal mac_ctx, + struct qdf_mac_addr *bssid, + tCsrScanResultInfo *res) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tCsrScanResultFilter *scan_filter = NULL; + tScanResultHandle filtered_scan_result = NULL; + tCsrScanResultInfo *scan_result; + + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("mac_ctx is NULL")); + return QDF_STATUS_E_FAILURE; + } + + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (!scan_filter) { + sme_err("Failed to allocated memory for scan_filter"); + return QDF_STATUS_E_NOMEM; + } + + scan_filter->BSSIDs.bssid = qdf_mem_malloc(sizeof(*bssid)); + if (!scan_filter->BSSIDs.bssid) { + sme_err("Failed to allocate memory for BSSIDs"); + status = QDF_STATUS_E_FAILURE; + goto free_filter; + } + + scan_filter->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy(scan_filter->BSSIDs.bssid, bssid, sizeof(*bssid)); + + status = csr_scan_get_result(mac_ctx, scan_filter, + &filtered_scan_result); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to get scan result"); + goto free_filter; + } + + scan_result = csr_scan_result_get_first(mac_ctx, filtered_scan_result); + + if (scan_result) { + res->pvIes = NULL; + res->ssId.length = scan_result->ssId.length; + qdf_mem_copy(&res->ssId.ssId, &scan_result->ssId.ssId, + res->ssId.length); + res->timer = scan_result->timer; + qdf_mem_copy(&res->BssDescriptor, &scan_result->BssDescriptor, + sizeof(tSirBssDescription)); + status = QDF_STATUS_SUCCESS; + } else { + status = QDF_STATUS_E_FAILURE; + } + + csr_scan_result_purge(mac_ctx, filtered_scan_result); + +free_filter: + csr_free_scan_filter(mac_ctx, scan_filter); + if (scan_filter) + qdf_mem_free(scan_filter); + + return status; +} + +static inline QDF_STATUS +csr_flush_scan_results(tpAniSirGlobal mac_ctx, + struct scan_filter *filter) +{ + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status; + + 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; + } + status = ucfg_scan_flush_results(pdev, filter); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + return status; +} + +QDF_STATUS csr_scan_flush_result(tpAniSirGlobal mac_ctx) +{ + + if (csr_scan_flush_denied(mac_ctx)) { + sme_err("scan flush denied in roam state"); + return QDF_STATUS_E_FAILURE; + } + + return csr_flush_scan_results(mac_ctx, NULL); +} + +QDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal mac_ctx, + bool flush_p2p) +{ + struct scan_filter *filter; + QDF_STATUS status; + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + filter->p2p_results = flush_p2p; + status = csr_flush_scan_results(mac_ctx, filter); + if (filter) + qdf_mem_free(filter); +end: + return status; +} + +static inline void csr_flush_bssid(tpAniSirGlobal mac_ctx, + uint8_t *bssid) +{ + struct scan_filter *filter; + + 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); + + csr_flush_scan_results(mac_ctx, filter); + sme_debug("Removed BSS entry:%pM", bssid); + if (filter) + qdf_mem_free(filter); +} + +void csr_scan_flush_bss_entry(tpAniSirGlobal mac_ctx, + tpSmeCsaOffloadInd csa_off_ind) +{ + csr_flush_bssid(mac_ctx, + csa_off_ind->bssid.bytes); +} + +void csr_remove_bssid_from_scan_list(tpAniSirGlobal mac_ctx, + tSirMacAddr bssid) +{ + csr_flush_bssid(mac_ctx, bssid); +} + +void csr_init_occupied_channels_list(tpAniSirGlobal mac_ctx, + uint8_t sessionId) +{ + qdf_list_t *list = NULL; + struct wlan_objmgr_pdev *pdev = 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; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *profile = NULL; + uint8_t ch; + + if (!(mac_ctx && mac_ctx->roam.roamSession && + CSR_IS_SESSION_VALID(mac_ctx, sessionId))) { + sme_debug("Invalid session"); + return; + } + if (neighbor_roam_info->cfgParams.channelInfo.numOfChannels) { + /* + * Ini file contains neighbor scan channel list, hence NO need + * to build occupied channel list" + */ + sme_debug("Ini contains neighbor scan ch list"); + return; + } + + if (!csr_neighbor_roam_is_new_connected_profile(mac_ctx, sessionId)) { + /* + * Do not flush occupied list since current roam profile matches + * previous + */ + sme_debug("Current roam profile matches prev"); + return; + } + + profile = &mac_ctx->roam.roamSession[sessionId].connectedProfile; + if (!profile) + return; + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) { + sme_err("filter is NULL"); + return; + } + + filter->num_of_auth = 1; + filter->auth_type[0] = csr_covert_auth_type_new(profile->AuthType); + filter->num_of_enc_type = 1; + filter->enc_type[0] = csr_covert_enc_type_new(profile->EncryptionType); + filter->num_of_mc_enc_type = 1; + filter->mc_enc_type[0] = + csr_covert_enc_type_new(profile->mcEncryptionType); + filter->num_of_ssid = 1; + filter->ssid_list[0].length = profile->SSID.length; + qdf_mem_copy(filter->ssid_list[0].ssid, profile->SSID.ssId, + profile->SSID.length); + + pdev = wlan_objmgr_get_pdev_by_id(mac_ctx->psoc, 0, WLAN_LEGACY_MAC_ID); + + if (!pdev) { + sme_err("pdev is NULL"); + qdf_mem_free(filter); + return; + } + + /* Empty occupied channels here */ + mac_ctx->scan.occupiedChannels[sessionId].numChannels = 0; + mac_ctx->scan.roam_candidate_count[sessionId] = 0; + + csr_add_to_occupied_channels( + mac_ctx, profile->operationChannel, + sessionId, + &mac_ctx->scan.occupiedChannels[sessionId], + true); + list = ucfg_scan_get_result(pdev, filter); + if (list) + sme_debug("num_entries %d", qdf_list_size(list)); + if (!list || (list && !qdf_list_size(list))) { + sme_err("get scan result failed"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + qdf_mem_free(filter); + if (list) + ucfg_scan_purge_results(list); + return; + } + + qdf_list_peek_front(list, &cur_lst); + while (cur_lst) { + cur_node = qdf_container_of(cur_lst, struct scan_cache_node, + node); + ch = cur_node->entry->channel.chan_idx; + csr_add_to_occupied_channels( + mac_ctx, ch, + sessionId, + &mac_ctx->scan.occupiedChannels[sessionId], + true); + qdf_list_peek_next(list, cur_lst, &next_lst); + cur_lst = next_lst; + next_lst = NULL; + } + + qdf_mem_free(filter); + ucfg_scan_purge_results(list); + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); +} + +/** + * 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(tpAniSirGlobal mac_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t len = sizeof(mac_ctx->roam.validChannelList); + struct wlan_objmgr_pdev *pdev = NULL; + + 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; + } + status = csr_get_cfg_valid_channels(mac_ctx, + mac_ctx->roam.validChannelList, + &len); + + /* Get valid channels list from CFG */ + if (QDF_IS_STATUS_ERROR(status)) { + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + sme_err("Failed to get Channel list from CFG"); + return status; + } + sme_debug("No of valid channel %d", len); + + ucfg_scan_filter_valid_channel(pdev, + mac_ctx->roam.validChannelList, len); + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c new file mode 100644 index 0000000000000000000000000000000000000000..bca20c0c2ffe08cd00c8338e3d7446461cfb5155 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c @@ -0,0 +1,142 @@ +/* + * 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: 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(tpAniSirGlobal mac_ctx, void *msg_buf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeRsp *sme_rsp = (tSirSmeRsp *) msg_buf; + uint8_t session_id = sme_rsp->sessionId; + enum csr_roam_state cur_state; + + cur_state = sme_get_current_roam_state(MAC_HANDLE(mac_ctx), session_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[session_id]), + session_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_GET_STATISTICS_RSP) { + csr_roam_joined_state_msg_processor(mac_ctx, + msg_buf); + 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/IBSS 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 if (eWNI_SME_GET_RSSI_REQ == + sme_rsp->messageType) { + tAniGetRssiReq *pGetRssiReq = + (tAniGetRssiReq *) msg_buf; + if (NULL == pGetRssiReq->rssiCallback) { + sme_err("rssiCallback is NULL"); + return status; + } + ((tCsrRssiCallback)(pGetRssiReq->rssiCallback))( + pGetRssiReq->lastRSSI, + pGetRssiReq->staId, + pGetRssiReq->pDevContext); + } else if (sme_rsp->messageType == + eWNI_SME_PURGE_ALL_PDEV_CMDS_REQ) { + csr_purge_pdev_all_ser_cmd_list_sync(mac_ctx, msg_buf); + } else { + sme_err("Message 0x%04X is not handled by CSR state is %d session Id %d", + sme_rsp->messageType, cur_state, + session_id); + + if (eWNI_SME_FT_PRE_AUTH_RSP == + sme_rsp->messageType) { + sme_err("Dequeue eSmeCommandRoam command with reason eCsrPerformPreauth"); + csr_dequeue_roam_command(mac_ctx, + eCsrPerformPreauth, session_id); + } else if (eWNI_SME_REASSOC_RSP == + sme_rsp->messageType) { + sme_err("Dequeue eSmeCommandRoam command with reason eCsrSmeIssuedFTReassoc"); + csr_dequeue_roam_command(mac_ctx, + eCsrSmeIssuedFTReassoc, + session_id); + } + } + break; + } /* switch */ + return status; +} + +bool csr_check_ps_ready(void *pv) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + + if (pMac->roam.sPendingCommands < 0) { + QDF_ASSERT(pMac->roam.sPendingCommands >= 0); + return 0; + } + return pMac->roam.sPendingCommands == 0; +} + +bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + + QDF_ASSERT(pMac->roam.sPendingCommands >= 0); + return pMac->roam.sPendingCommands == 0; +} + diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_host_scan_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_host_scan_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..8c3cc20adfba469ef00071cd680fac79fdcf3dc6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_host_scan_roam.c @@ -0,0 +1,809 @@ +/* + * Copyright (c) 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. + */ + +/** + * DOC: csr_host_scan_roam.c + * + * Host based roaming processing scan results and initiating the roaming + */ + +#include "wma_types.h" +#include "csr_inside_api.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 "sme_api.h" +#include "csr_neighbor_roam.h" +#include "mac_trace.h" +#include "wlan_policy_mgr_api.h" + +/** + * csr_roam_issue_reassociate() - Issue Reassociate + * @pMac: Global MAC Context + * @sessionId: SME Session ID + * @pSirBssDesc: BSS Descriptor + * @pIes: Pointer to the IE's + * @pProfile: Roaming profile + * + * Return: Success or Failure + */ +QDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, struct csr_roam_profile *pProfile) +{ + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId); + /* Set the roaming substate to 'join attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_REASSOC_REQ, + sessionId); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL(" calling csr_send_join_req_msg (eWNI_SME_REASSOC_REQ)")); + /* attempt to Join this BSS... */ + return csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, + pIes, eWNI_SME_REASSOC_REQ); +} + +/** + * csr_roam_issue_reassociate_cmd() - Issue the reassociate command + * @pMac: Global MAC Context + * @sessionId: SME Session ID + * + * Return: Success or Failure status + */ +QDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand = NULL; + bool fHighPriority = true; + bool fRemoveCmd = false; + tListElem *pEntry; + tSmeCmd *tmp_command; + + pEntry = csr_nonscan_active_ll_peek_head(pMac, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (!pCommand) { + sme_err("fail to get command buffer"); + return QDF_STATUS_E_RESOURCES; + } + if (eSmeCommandRoam == pCommand->command) { + if (pCommand->u.roamCmd.roamReason == + eCsrSmeIssuedAssocToSimilarAP) + fRemoveCmd = + csr_nonscan_active_ll_remove_entry(pMac, + pEntry, + LL_ACCESS_LOCK); + else + sme_err("Unexpected roam cmd present"); + if (fRemoveCmd == false) + pCommand = NULL; + } + } + if (NULL == pCommand) { + sme_err("fail to get cmd buf based on prev roam command"); + return QDF_STATUS_E_RESOURCES; + } + do { + /* + * Get a new sme command to save the necessary info for + * the following roaming process, such as BSS list and + * roam profile. Or those info will be freed in function + * csr_reinit_roam_cmd when releasing the current command. + */ + tmp_command = csr_get_command_buffer(pMac); + if (tmp_command == NULL) { + sme_err("fail to get cmd buf!"); + csr_release_command(pMac, pCommand); + return QDF_STATUS_E_RESOURCES; + } + qdf_mem_copy(tmp_command, pCommand, sizeof(*pCommand)); + pCommand->u.roamCmd.fReleaseBssList = false; + pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + pCommand->u.roamCmd.fReleaseProfile = false; + /* + * Invoking csr_release_command to release the current command + * or the following command will be stuck in pending queue. + * Because the API csr_nonscan_active_ll_remove_entry does + * not remove the current command from active queue. + */ + csr_release_command(pMac, pCommand); + + pCommand = tmp_command; + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrSmeIssuedFTReassoc; + status = csr_queue_sme_command(pMac, pCommand, fHighPriority); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to send message status: %d", status); + } while (0); + + return status; +} + +/** + * csr_neighbor_roam_process_scan_results() - build roaming candidate list + * + * @mac_ctx: The handle returned by mac_open. + * @sessionid: Session information + * @scan_results_list: List obtained from csr_scan_get_result() + * + * This function applies various candidate checks like LFR, 11r, preauth, ESE + * and builds a roamable AP list. It applies age limit only if no suitable + * recent candidates are found. + * + * Output list is built in mac_ctx->roam.neighborRoamInfo[sessionid]. + * + * Return: void + */ + +void csr_neighbor_roam_process_scan_results(tpAniSirGlobal mac_ctx, + uint8_t sessionid, tScanResultHandle *scan_results_list) +{ + tCsrScanResultInfo *scan_result; + tpCsrNeighborRoamControlInfo n_roam_info = + &mac_ctx->roam.neighborRoamInfo[sessionid]; + tpCsrNeighborRoamBSSInfo bss_info; + uint64_t age = 0; + uint8_t num_candidates = 0; + uint8_t num_dropped = 0; + /* + * first iteration of scan list should consider + * age constraint for candidates + */ + bool age_constraint = true; +#ifdef FEATURE_WLAN_ESE + uint16_t qpresent; + uint16_t qavail; + bool voadmitted; +#endif + /* + * Expecting the scan result already to be in the sorted order based on + * RSSI. Based on the previous state we need to check whether the list + * should be sorted again taking neighbor score into consideration. If + * previous state is CFG_CHAN_LIST_SCAN, there should not be a neighbor + * score associated with any of the BSS. If the previous state is + * REPORT_QUERY, then there will be neighbor score for each of the APs. + * For now, let us take top of the list provided as it is by CSR Scan + * result API. Hence it is assumed that neighbor score and rssi score + * are in the same order. This will be taken care later. + */ + + do { + while (true) { + tSirBssDescription *descr; + + scan_result = csr_scan_result_get_next( + mac_ctx, *scan_results_list); + if (NULL == scan_result) + break; + descr = &scan_result->BssDescriptor; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Scan result: BSSID " MAC_ADDRESS_STR + " (Rssi %d, Ch:%d)"), + MAC_ADDR_ARRAY(descr->bssId), + (int)abs(descr->rssi), descr->channelId); + + if (!qdf_mem_cmp(descr->bssId, + n_roam_info->currAPbssid.bytes, + sizeof(tSirMacAddr))) { + /* + * currently associated AP. Do not have this + * in the roamable AP list + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "SKIP-currently associated AP"); + continue; + } + + /* + * Continue if MCC is disabled in INI and if AP + * will create MCC + */ + if (policy_mgr_concurrent_open_sessions_running( + mac_ctx->psoc) && + !mac_ctx->roam.configParam.fenableMCCMode) { + uint8_t conc_channel; + + conc_channel = + csr_get_concurrent_operation_channel(mac_ctx); + if (conc_channel && + (conc_channel != + scan_result->BssDescriptor.channelId)) { + sme_debug("MCC not supported so Ignore AP on channel %d", + scan_result->BssDescriptor.channelId); + continue; + } + } + /* + * In case of reassoc requested by upper layer, look + * for exact match of bssid & channel. csr cache might + * have duplicates + */ + if ((n_roam_info->uOsRequestedHandoff) && + ((qdf_mem_cmp(descr->bssId, + n_roam_info->handoffReqInfo.bssid.bytes, + sizeof(tSirMacAddr))) + || (descr->channelId != + n_roam_info->handoffReqInfo.channel))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "SKIP-not a candidate AP for OS requested roam"); + continue; + } + + if ((n_roam_info->is11rAssoc) && + (!csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId))) { + sme_err("BSSID in preauth fail list. Ignore"); + continue; + } + +#ifdef FEATURE_WLAN_ESE + if (!csr_roam_is_roam_offload_scan_enabled(mac_ctx) && + (n_roam_info->isESEAssoc) && + !csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId)) { + sme_err("BSSID in preauth faillist. Ignore"); + continue; + } + + qpresent = descr->QBSSLoad_present; + qavail = descr->QBSSLoad_avail; + voadmitted = n_roam_info->isVOAdmitted; + if (voadmitted) + sme_debug("New QBSS=%s,BWavail=0x%x,req=0x%x", + ((qpresent) ? "yes" : "no"), qavail, + n_roam_info->MinQBssLoadRequired); + if (voadmitted && qpresent && + (qavail < n_roam_info->MinQBssLoadRequired)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "BSSID:" MAC_ADDRESS_STR "has no BW", + MAC_ADDR_ARRAY(descr->bssId)); + continue; + } + if (voadmitted && !qpresent) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "BSSID:" MAC_ADDRESS_STR "no LOAD IE", + MAC_ADDR_ARRAY(descr->bssId)); + continue; + } +#endif /* FEATURE_WLAN_ESE */ + + /* + * If we are supporting legacy roaming, and + * if the candidate is on the "pre-auth failed" list, + * ignore it. + */ + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionid) && + !csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId)) { + sme_err("BSSID in preauth faillist Ignore"); + continue; + } + + /* check the age of the AP */ + age = (uint64_t) qdf_mc_timer_get_system_time() - + descr->received_time; + if (age_constraint == true && + age > ROAM_AP_AGE_LIMIT_MS) { + num_dropped++; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_WARN, + FL("Old AP (probe rsp/beacon) skipped.") + ); + continue; + } + + /* Finished all checks, now add it to candidate list */ + bss_info = + qdf_mem_malloc(sizeof(tCsrNeighborRoamBSSInfo)); + if (NULL == bss_info) { + sme_err("Memory alloc fail"); + continue; + } + bss_info->pBssDescription = + qdf_mem_malloc(descr->length + + sizeof(descr->length)); + if (bss_info->pBssDescription != NULL) { + qdf_mem_copy(bss_info->pBssDescription, descr, + descr->length + sizeof(descr->length)); + } else { + sme_err("Memory alloc fail"); + qdf_mem_free(bss_info); + continue; + } + /* + * Assign some preference value for now. Need to + * calculate theactual score based on RSSI and neighbor + * AP score + */ + bss_info->apPreferenceVal = 10; + num_candidates++; + csr_ll_insert_tail(&n_roam_info->roamableAPList, + &bss_info->List, LL_ACCESS_LOCK); + } /* end of while (csr_scan_result_get_next) */ + + /* if some candidates were found, then no need to repeat */ + if (num_candidates) + break; + /* + * if age_constraint is already false, we have done two + * iterations and no candidate were found + */ + if (age_constraint == false) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: No roam able candidates found", + __func__); + break; + } + /* + * if all candidates were dropped rescan the scan + * list but this time without age constraint. + */ + age_constraint = false; + /* if no candidates were dropped no need to repeat */ + } while (num_dropped); + + /* + * Now we have all the scan results in our local list. Good time to free + * up the the list we got as a part of csrGetScanResult + */ + csr_scan_result_purge(mac_ctx, *scan_results_list); +} + +/** + * csr_neighbor_roam_trigger_handoff() - Start roaming + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * + * Return: None + */ +void csr_neighbor_roam_trigger_handoff(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + if (csr_roam_is_fast_roam_enabled(mac_ctx, session_id)) + csr_neighbor_roam_issue_preauth_req(mac_ctx, session_id); + else + sme_err("Roaming is disabled"); +} + +/** + * csr_neighbor_roam_process_scan_complete() - Post process the scan results + * @pMac: Global MAC Context + * @sessionId: SME Session ID + * + * Return: Success or Failure + */ +QDF_STATUS csr_neighbor_roam_process_scan_complete(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrScanResultFilter scanFilter; + tScanResultHandle scanResult; + uint32_t tempVal = 0; + QDF_STATUS hstatus; + + hstatus = csr_neighbor_roam_prepare_scan_profile_filter(pMac, + &scanFilter, + sessionId); + sme_debug("Prepare scan to find neighbor AP filter status: %d", + hstatus); + if (QDF_STATUS_SUCCESS != hstatus) { + sme_err("Scan Filter prep fail for Assoc %d Bail out", + tempVal); + return QDF_STATUS_E_FAILURE; + } + hstatus = csr_scan_get_result(pMac, &scanFilter, &scanResult); + if (hstatus != QDF_STATUS_SUCCESS) + sme_err("Get Scan Result status code %d", hstatus); + /* Process the scan results and update roamable AP list */ + csr_neighbor_roam_process_scan_results(pMac, sessionId, &scanResult); + + /* Free the scan filter */ + csr_free_scan_filter(pMac, &scanFilter); + + tempVal = csr_ll_count(&pNeighborRoamInfo->roamableAPList); + + if (tempVal) { + csr_neighbor_roam_trigger_handoff(pMac, sessionId); + return QDF_STATUS_SUCCESS; + } + + if (csr_roam_is_roam_offload_scan_enabled(pMac)) { + if (pNeighborRoamInfo->uOsRequestedHandoff) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_START, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + pNeighborRoamInfo->uOsRequestedHandoff = 0; + } else { + /* There is no candidate or We are not roaming Now. + * Inform the FW to restart Roam Offload Scan + */ + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_RESTART, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + } + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, sessionId); + } + return QDF_STATUS_SUCCESS; + +} + +/** + * csr_neighbor_roam_candidate_found_ind_hdlr() + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to msg buff + * + * This function is called by CSR as soon as TL posts the candidate + * found indication to SME via MC thread + * + * Return: QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +QDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr(tpAniSirGlobal pMac, + void *pMsg) +{ + tSirSmeCandidateFoundInd *pSirSmeCandidateFoundInd = + (tSirSmeCandidateFoundInd *) pMsg; + uint32_t sessionId = pSirSmeCandidateFoundInd->sessionId; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sme_debug("Received indication from firmware"); + + /* we must be in connected state, if not ignore it */ + if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) + || (pNeighborRoamInfo->uOsRequestedHandoff)) { + sme_err("Recvd in NotCONNECTED or OsReqHandoff. Ignore"); + status = QDF_STATUS_E_FAILURE; + } else { + /* Future enhancements: + * If firmware tags candidate beacons, give them preference + * for roaming. + * Age out older entries so that new candidate beacons + * will get preference. + */ + status = csr_neighbor_roam_process_scan_complete(pMac, + sessionId); + if (QDF_STATUS_SUCCESS != status) { + sme_err("scan process complete failed, status %d", + status); + return QDF_STATUS_E_FAILURE; + } + } + + return status; +} + +/** + * csr_neighbor_roam_free_roamable_bss_list() - Frees roamable APs list + * @mac_ctx: The handle returned by mac_open. + * @llist: Neighbor Roam BSS List to be emptied + * + * Empties and frees all the nodes in the roamable AP list + * + * Return: none + */ +void csr_neighbor_roam_free_roamable_bss_list(tpAniSirGlobal mac_ctx, + tDblLinkList *llist) +{ + tpCsrNeighborRoamBSSInfo result = NULL; + + sme_debug("Emptying the BSS list. Current count: %d", + csr_ll_count(llist)); + + /* + * Pick up the head, remove and free the node till + * the list becomes empty + */ + while ((result = csr_neighbor_roam_next_roamable_ap(mac_ctx, llist, + NULL)) != NULL) { + csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx, + llist, result); + csr_neighbor_roam_free_neighbor_roam_bss_node(mac_ctx, result); + } +} + +/** + * csr_neighbor_roam_remove_roamable_ap_list_entry() + * + * @mac_ctx: Pointer to Global MAC structure + * @pList: The list from which the entry should be removed + * @pNeighborEntry: Neighbor Roam BSS Node to be removed + * + * This function removes a given entry from the given list + * + * Return: true if successfully removed, else false + */ +bool csr_neighbor_roam_remove_roamable_ap_list_entry(tpAniSirGlobal pMac, + tDblLinkList *pList, + tpCsrNeighborRoamBSSInfo + pNeighborEntry) +{ + if (pList) { + return csr_ll_remove_entry(pList, &pNeighborEntry->List, + LL_ACCESS_LOCK); + } + + sme_debug("Remove neigh BSS node from fail list. Current count: %d", + csr_ll_count(pList)); + + return false; +} + +/** + * csr_neighbor_roam_next_roamable_ap() - Get next AP from roamable AP list + * @mac_ctx - The handle returned by mac_open. + * @plist - The list from which the entry should be returned + * @neighbor_entry - Neighbor Roam BSS Node whose next entry should be returned + * + * Gets the entry next to passed entry. If NULL is passed, return the entry + * in the head of the list + * + * Return: Neighbor Roam BSS Node to be returned + */ +tpCsrNeighborRoamBSSInfo csr_neighbor_roam_next_roamable_ap( + tpAniSirGlobal mac_ctx, tDblLinkList *llist, + tpCsrNeighborRoamBSSInfo neighbor_entry) +{ + tListElem *entry = NULL; + tpCsrNeighborRoamBSSInfo result = NULL; + + if (llist) { + if (NULL == neighbor_entry) + entry = csr_ll_peek_head(llist, LL_ACCESS_LOCK); + else + entry = csr_ll_next(llist, &neighbor_entry->List, + LL_ACCESS_LOCK); + if (entry) + result = GET_BASE_ADDR(entry, tCsrNeighborRoamBSSInfo, + List); + } + + return result; +} + + +/** + * csr_neighbor_roam_request_handoff() - Handoff to a different AP + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function triggers actual switching from one AP to the new AP. + * It issues disassociate with reason code as Handoff and CSR as a part of + * handling disassoc rsp, issues reassociate to the new AP + * + * Return: none + */ +void csr_neighbor_roam_request_handoff(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + struct csr_roam_info roam_info; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tCsrNeighborRoamBSSInfo handoff_node; + uint32_t roamid = 0; + QDF_STATUS status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, "%s session_id=%d", + __func__, session_id); + + if (neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE) { + sme_err("Roam requested when Neighbor roam is in %s state", + mac_trace_get_neighbour_roam_state( + neighbor_roam_info->neighborRoamState)); + return; + } + + if (false == csr_neighbor_roam_get_handoff_ap_info(mac_ctx, + &handoff_node, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("failed to obtain handoff AP")); + return; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("HANDOFF CANDIDATE BSSID "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(handoff_node.pBssDescription->bssId)); + + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, roamid, + eCSR_ROAM_FT_START, eCSR_ROAM_RESULT_SUCCESS); + + qdf_mem_zero(&roam_info, sizeof(struct csr_roam_info)); + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, session_id); + + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + handoff_node.pBssDescription->bssId, + eCSR_ROAM_HANDOVER_SUCCESS); + /* Free the profile.. Just to make sure we dont leak memory here */ + csr_release_profile(mac_ctx, + &neighbor_roam_info->csrNeighborRoamProfile); + /* + * Create the Handoff AP profile. Copy the currently connected profile + * and update only the BSSID and channel number. This should happen + * before issuing disconnect + */ + status = csr_roam_copy_connected_profile(mac_ctx, session_id, + &neighbor_roam_info->csrNeighborRoamProfile); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("csr_roam_copy_connected_profile failed %d"), + status); + return; + } + qdf_mem_copy(neighbor_roam_info->csrNeighborRoamProfile.BSSIDs.bssid, + handoff_node.pBssDescription->bssId, sizeof(tSirMacAddr)); + neighbor_roam_info->csrNeighborRoamProfile.ChannelInfo.ChannelList[0] = + handoff_node.pBssDescription->channelId; + + sme_debug("csr_roamHandoffRequested: disassociating with current AP"); + + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_issue_disassociate_cmd + (mac_ctx, session_id, + eCSR_DISCONNECT_REASON_HANDOFF))) { + sme_warn("csr_roamHandoffRequested: fail to issue disassoc"); + return; + } + /* notify HDD for handoff, providing the BSSID too */ + roam_info.reasonCode = eCsrRoamReasonBetterAP; + + qdf_mem_copy(roam_info.bssid.bytes, + handoff_node.pBssDescription->bssId, + sizeof(struct qdf_mac_addr)); + + csr_roam_call_callback(mac_ctx, session_id, &roam_info, 0, + eCSR_ROAM_ROAMING_START, eCSR_ROAM_RESULT_NONE); + +} + + +/** + * csr_neighbor_roam_get_handoff_ap_info - Identifies the best AP for roaming + * + * @pMac: mac context + * @session_id: Session Id + * @hand_off_node: AP node that is the handoff candidate returned + * + * This function returns the best possible AP for handoff. For 11R case, it + * returns the 1st entry from pre-auth done list. For non-11r case, it returns + * the 1st entry from roamable AP list + * + * Return: true if able find handoff AP, false otherwise + */ + +bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo hand_off_node, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + tpCsrNeighborRoamBSSInfo bss_node = NULL; + + if (NULL == hand_off_node) { + QDF_ASSERT(NULL != hand_off_node); + return false; + } + if (ngbr_roam_info->is11rAssoc) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = csr_neighbor_roam_next_roamable_ap( + pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + sme_debug("Number of Handoff candidates: %d", + csr_ll_count(& + ngbr_roam_info->FTRoamInfo.preAuthDoneList)); + } else +#ifdef FEATURE_WLAN_ESE + if (ngbr_roam_info->isESEAssoc) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + sme_debug("Number of Handoff candidates: %d", + csr_ll_count(&ngbr_roam_info->FTRoamInfo. + preAuthDoneList)); + } else +#endif + if (csr_roam_is_fast_roam_enabled(pMac, session_id)) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + sme_debug("Number of Handoff candidates: %d", + csr_ll_count( + &ngbr_roam_info->FTRoamInfo.preAuthDoneList)); + } else { + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->roamableAPList, + NULL); + sme_debug("Number of Handoff candidates: %d", + csr_ll_count(&ngbr_roam_info->roamableAPList)); + } + if (NULL == bss_node) + return false; + qdf_mem_copy(hand_off_node, bss_node, sizeof(tCsrNeighborRoamBSSInfo)); + return true; +} + +/** + * csr_neighbor_roam_is_handoff_in_progress() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function returns whether handoff is in progress or not based on + * the current neighbor roam state + * + * Return: true if reassoc in progress, false otherwise + */ +bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + if (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING == + pMac->roam.neighborRoamInfo[sessionId].neighborRoamState) + return true; + + return false; +} + +/** + * csr_neighbor_roam_free_neighbor_roam_bss_node() + * + * @mac_ctx: Pointer to Global MAC structure + * @neighborRoamBSSNode: Neighbor Roam BSS Node to be freed + * + * This function frees all the internal pointers CSR NeighborRoam BSS Info + * and also frees the node itself + * + * Return: None + */ +void csr_neighbor_roam_free_neighbor_roam_bss_node(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo + neighborRoamBSSNode) +{ + if (neighborRoamBSSNode) { + if (neighborRoamBSSNode->pBssDescription) { + qdf_mem_free(neighborRoamBSSNode->pBssDescription); + neighborRoamBSSNode->pBssDescription = NULL; + } + qdf_mem_free(neighborRoamBSSNode); + neighborRoamBSSNode = NULL; + } +} + diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_inside_api.h b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_inside_api.h new file mode 100644 index 0000000000000000000000000000000000000000..e12f63c74817641d91d25cec3e788968820f9302 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_inside_api.h @@ -0,0 +1,1152 @@ +/* + * 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. + */ + +/* + * 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" + +#define CSR_PASSIVE_MAX_CHANNEL_TIME 110 +#define CSR_PASSIVE_MIN_CHANNEL_TIME 60 + +#define CSR_ACTIVE_MAX_CHANNEL_TIME 40 +#define CSR_ACTIVE_MIN_CHANNEL_TIME 20 + +#define CSR_PASSIVE_MAX_CHANNEL_TIME_CONC 110 +#define CSR_PASSIVE_MIN_CHANNEL_TIME_CONC 60 + +#define CSR_ACTIVE_MAX_CHANNEL_TIME_CONC 27 +#define CSR_ACTIVE_MIN_CHANNEL_TIME_CONC 20 + +#define CSR_REST_TIME_CONC 100 +#define CSR_MIN_REST_TIME_CONC 50 +#define CSR_IDLE_TIME_CONC 25 + +#define CSR_MAX_NUM_SUPPORTED_CHANNELS 55 + +#define CSR_MAX_2_4_GHZ_SUPPORTED_CHANNELS 14 + +#define CSR_MAX_BSS_SUPPORT 512 + +/* This number minus 1 means the number of times a channel is scanned before + * a BSS is remvoed from + */ +/* cache scan result */ +#define CSR_AGING_COUNT 3 +/* 5 seconds */ +#define CSR_SCAN_GET_RESULT_INTERVAL (5 * QDF_MC_TIMER_TO_SEC_UNIT) +/* 60 seconds */ +#define CSR_MIC_ERROR_TIMEOUT (60 * QDF_MC_TIMER_TO_SEC_UNIT) +/* 60 seconds */ +#define CSR_TKIP_COUNTER_MEASURE_TIMEOUT (60 * QDF_MC_TIMER_TO_SEC_UNIT) + +/* the following defines are NOT used by palTimer */ +#define CSR_JOIN_FAILURE_TIMEOUT_DEFAULT (3000) +#define CSR_JOIN_FAILURE_TIMEOUT_MIN (1000) /* minimal value */ +/* These are going against the signed RSSI (int8_t) so it is between -+127 */ +#define CSR_BEST_RSSI_VALUE (-30) /* RSSI >= this is in CAT4 */ +#define CSR_DEFAULT_RSSI_DB_GAP 30 /* every 30 dbm for one category */ +#define CSR_BSS_CAP_VALUE_NONE 0 /* not much value */ +#define CSR_BSS_CAP_VALUE_HT 1 +#define CSR_BSS_CAP_VALUE_VHT 2 +#define CSR_BSS_CAP_VALUE_WMM 1 +#define CSR_BSS_CAP_VALUE_UAPSD 1 +#define CSR_BSS_CAP_VALUE_5GHZ 2 + +#define CSR_ROAMING_DFS_CHANNEL_DISABLED (0) +#define CSR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL (1) +#define CSR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE (2) + +#ifdef QCA_WIFI_3_0_EMU +#define CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT (1000*30*20) +#else +#define CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT (1000*30) +#endif +/* *************************************************************************** + * The MAX BSSID Count should be lower than the command timeout value and it + * can be of a fraction of 1/3 to 1/2 of the total command timeout value. + * ***************************************************************************/ +#define CSR_MAX_BSSID_COUNT (SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE/3000) - 2 +#define CSR_CUSTOM_CONC_GO_BI 100 +extern uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE]; +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId); + +enum csr_scancomplete_nextcommand { + eCsrNextScanNothing, + eCsrNexteScanForSsidSuccess, + eCsrNexteScanForSsidFailure, + eCsrNextCheckAllowConc, +}; + +enum csr_roamcomplete_result { + eCsrJoinSuccess, + eCsrJoinFailure, + eCsrReassocSuccess, + eCsrReassocFailure, + eCsrNothingToJoin, + eCsrStartBssSuccess, + eCsrStartBssFailure, + eCsrSilentlyStopRoaming, + eCsrSilentlyStopRoamingSaveState, + eCsrJoinFailureDueToConcurrency, + eCsrStopBssSuccess, + eCsrStopBssFailure, +}; + +struct tag_scanreq_param { + uint8_t bReturnAfter1stMatch; + uint8_t fUniqueResult; + uint8_t freshScan; + uint8_t hiddenSsid; + uint8_t reserved; +}; + +struct tag_csrscan_result { + tListElem Link; + /* This BSS is removed when it reaches 0 or less */ + int32_t AgingCount; + /* The bigger the number, the better the BSS. + * This value override capValue + */ + uint32_t preferValue; + /* The biggger the better. This value is in use only if we have + * equal preferValue + */ + uint32_t capValue; + /* This member must be the last in the structure because the end of + * tSirBssDescription (inside) is an + * array with nonknown size at this time + */ + /* Preferred Encryption type that matched with profile. */ + eCsrEncryptionType ucEncryptionType; + eCsrEncryptionType mcEncryptionType; + /* Preferred auth type that matched with the profile. */ + eCsrAuthType authType; + int bss_score; + + tCsrScanResultInfo Result; + /* + * WARNING - Do not add any element here + * This member Result must be the last in the structure because the end + * of tSirBssDescription (inside) is an array with nonknown size at + * this time. + */ +}; + +struct scan_result_list { + tDblLinkList List; + tListElem *pCurEntry; +}; + +#define CSR_IS_ROAM_REASON(pCmd, reason) \ + ((reason) == (pCmd)->roamCmd.roamReason) +#define CSR_IS_BETTER_PREFER_VALUE(v1, v2) ((v1) > (v2)) +#define CSR_IS_EQUAL_PREFER_VALUE(v1, v2) ((v1) == (v2)) +#define CSR_IS_BETTER_CAP_VALUE(v1, v2) ((v1) > (v2)) +#define CSR_IS_EQUAL_CAP_VALUE(v1, v2) ((v1) == (v2)) +#define CSR_IS_BETTER_RSSI(v1, v2) ((v1) > (v2)) +#define CSR_IS_ENC_TYPE_STATIC(encType) ((eCSR_ENCRYPT_TYPE_NONE == (encType)) \ + || (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == (encType)) || \ + (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == (encType))) + +#define CSR_IS_AUTH_TYPE_FILS(auth_type) \ + ((eCSR_AUTH_TYPE_FILS_SHA256 == auth_type) || \ + (eCSR_AUTH_TYPE_FILS_SHA384 == auth_type) || \ + (eCSR_AUTH_TYPE_FT_FILS_SHA256 == auth_type) || \ + (eCSR_AUTH_TYPE_FT_FILS_SHA384 == auth_type)) +#define CSR_IS_WAIT_FOR_KEY(pMac, sessionId) \ + (CSR_IS_ROAM_JOINED(pMac, sessionId) && \ + CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId)) +/* WIFI has a test case for not using HT rates with TKIP as encryption */ +/* We may need to add WEP but for now, TKIP only. */ + +#define CSR_IS_11n_ALLOWED(encType) ((eCSR_ENCRYPT_TYPE_TKIP != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP40 != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP104 != (encType))) + +#define CSR_IS_DISCONNECT_COMMAND(pCommand) ((eSmeCommandRoam == \ + (pCommand)->command) && \ + ((eCsrForcedDisassoc == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrForcedDeauth == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrSmeIssuedDisassocForHandoff == \ + (pCommand)->u.roamCmd.roamReason) || \ + (eCsrForcedDisassocMICFailure == \ + (pCommand)->u.roamCmd.roamReason))) + +enum csr_roam_state csr_roam_state_change(tpAniSirGlobal pMac, + enum csr_roam_state NewRoamState, + uint8_t sessionId); +void csr_roaming_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +void csr_scan_callback(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg); +void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_release_command_wm_status_change(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx, + tSmeCmd *pCommand); + +QDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirBssDescription *pBssDesc); +bool csr_is_network_type_equal(tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2); +/* + * Prepare a filter base on a profile for parsing the scan results. + * Upon successful return, caller MUST call csr_free_scan_filter on + * pScanFilter when it is done with the filter. + */ +QDF_STATUS +csr_roam_prepare_filter_from_profile(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + tCsrScanResultFilter *pScanFilter); + +QDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, + struct csr_roam_profile *pDstProfile, + struct csr_roam_profile *pSrcProfile); +QDF_STATUS csr_roam_start(tpAniSirGlobal pMac); +void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_roam_startMICFailureTimer(tpAniSirGlobal pMac); +void csr_roam_stopMICFailureTimer(tpAniSirGlobal pMac); +void csr_roam_startTKIPCounterMeasureTimer(tpAniSirGlobal pMac); +void csr_roam_stopTKIPCounterMeasureTimer(tpAniSirGlobal pMac); + +QDF_STATUS csr_scan_open(tpAniSirGlobal pMac); +QDF_STATUS csr_scan_close(tpAniSirGlobal pMac); +bool csr_scan_append_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDescription); +QDF_STATUS csr_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, uint32_t roamId, + bool notify); +/** + * csr_scan_abort_mac_scan() - Generic API to abort scan request + * @pMac: pointer to pmac + * @vdev_id: pdev id + * @scan_id: scan id + * + * Generic API to abort scans + * + * Return: 0 for success, non zero for failure + */ +QDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal pMac, uint32_t vdev_id, + uint32_t scan_id); +QDF_STATUS csr_remove_nonscan_cmd_from_pending_list(tpAniSirGlobal pMac, + uint8_t sessionId, eSmeCommandType commandType); + +/* If fForce is true we will save the new String that is learn't. */ +/* Typically it will be true in case of Join or user initiated ioctl */ +bool csr_learn_11dcountry_information(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, bool fForce); +void csr_apply_country_information(tpAniSirGlobal pMac); +void csr_free_scan_result_entry(tpAniSirGlobal pMac, struct tag_csrscan_result + *pResult); + +QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_info *roam_info, + uint32_t roamId, + eRoamCmdStatus u1, eCsrRoamResult u2); +QDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tScanResultHandle hBSSList, + enum csr_roam_reason reason, uint32_t roamId, + bool fImediate, bool fClearScan); +QDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tCsrRoamModifyProfileFields *pModProfileFields, + enum csr_roam_reason reason, uint32_t roamId, + bool fImediate); +void csr_roam_complete(tpAniSirGlobal pMac, enum csr_roamcomplete_result Result, + void *Context, uint8_t session_id); +QDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrEncryptionType EncryptType, + tSirBssDescription *pBssDescription, + tSirMacAddr *bssId, bool addKey, + bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint16_t keyLength, + uint8_t *pKey, uint8_t paeRole); +QDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, + tSmeCmd *pCommand, + bool fDisassoc, bool fMICFailure); +QDF_STATUS csr_roam_save_connected_information(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes); +/** + * csr_purge_pdev_all_ser_cmd_list_sync() - purge pdev cmnds and call cb to HDD + * @mac_ctx: pointer to pmac + * @req: purge req + * + * Return: void + */ +void csr_purge_pdev_all_ser_cmd_list_sync(tpAniSirGlobal mac, + struct sir_purge_pdev_cmd_req *req); +void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, + tSirSmeRsp *pSirMsg); + +#ifndef QCA_SUPPORT_CP_STATS +void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg); +#else +static inline void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, + tSirSmeRsp *pSirMsg) {} +#endif /* QCA_SUPPORT_CP_STATS */ + +QDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roamstart_bssparams *pParam, + struct csr_roam_profile *pProfile, + tSirBssDescription *pBssDesc, + uint32_t roamId); +QDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, uint32_t sessionId, + enum csr_roam_substate NewSubstate); +bool csr_is_same_profile(tpAniSirGlobal pMac, tCsrRoamConnectedProfile + *pProfile1, struct csr_roam_profile *pProfile2); +bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, + uint32_t sessionId); +eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac, + uint32_t sessionId); +/* pBand can be NULL if caller doesn't need to get it */ +QDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrRoamDisconnectReason reason); +QDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); +/* pCommand may be NULL */ +void csr_roam_remove_duplicate_command(tpAniSirGlobal pMac, uint32_t sessionId, + tSmeCmd *pCommand, + enum csr_roam_reason eRoamReason); + +QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDescription, + struct csr_roam_profile *pProfile, + tDot11fBeaconIEs *pIes, uint16_t messageType); +QDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +QDF_STATUS csr_send_mb_deauth_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +QDF_STATUS csr_send_mb_disassoc_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDisassocInd pDisassocInd); +QDF_STATUS csr_send_mb_deauth_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDeauthInd pDeauthInd); +QDF_STATUS csr_send_assoc_cnf_msg(tpAniSirGlobal pMac, tpSirSmeAssocInd + pAssocInd, + QDF_STATUS status); +QDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeAssocInd pAssocInd, + QDF_STATUS Halstatus, + uint8_t sessionId); +QDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrRoamBssType bssType, + struct csr_roamstart_bssparams *pParam, + tSirBssDescription *pBssDesc); +QDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId); + +/* Caller should put the BSS' ssid to fiedl bssSsid when + * comparing SSID for a BSS. + */ +bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len, + uint8_t *bssSsid, uint8_t bssSsidLen, + bool fSsidRequired); +bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode, + tSirBssDescription *pSirBssDesc, + struct csr_roam_profile *pProfile, + enum csr_cfgdot11mode *pReturnCfgDot11Mode, + tDot11fBeaconIEs *pIes); +bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel); + +/* pNumChan is a caller allocated space with the sizeof pChannels */ +QDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels, + uint32_t *pNumChan); +void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result, + uint8_t session_id); + +int8_t csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel); + +/* To free the last roaming profile */ +void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId); +QDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssid, + tScanResultHandle hScanResult); +bool csr_check_ps_ready(void *pv); +bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId); + +/* to free memory allocated inside the profile structure */ +void csr_release_profile(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile); + +/* To free memory allocated inside scanFilter */ +void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter + *pScanFilter); + +enum csr_cfgdot11mode +csr_get_cfg_dot11_mode_from_csr_phy_mode(struct csr_roam_profile *pProfile, + eCsrPhyMode phyMode, + bool fProprietary); + +uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac, + enum csr_cfgdot11mode csrDot11Mode); +void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fPopulate5GBand); +void csr_apply_channel_power_info_to_fw(tpAniSirGlobal pMac, + struct csr_channel *pChannelList, + uint8_t *countryCode); +void csr_apply_power2_current(tpAniSirGlobal pMac); +void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi, + uint8_t catOffset); +QDF_STATUS csr_roam_start_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + enum csr_roaming_reason roamingReason); +/* return a bool to indicate whether roaming completed or continue. */ +bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + bool fForce, eCsrRoamResult roamResult); +void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_info *roam_info, tSmeCmd *pCommand, + eCsrRoamResult roamResult, bool fSuccess); +void csr_roam_cancel_roaming(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac); +void csr_reset_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId); +#ifdef FEATURE_WLAN_WAPI +void csr_reset_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId); +#endif /* FEATURE_WLAN_WAPI */ +QDF_STATUS csr_save_to_channel_power2_g_5_g(tpAniSirGlobal pMac, + uint32_t tableSize, tSirMacChanInfo + *channelTable); +QDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t roamId); +QDF_STATUS csr_roam_open_session(tpAniSirGlobal pMac, + struct sme_session_params *session_param); +QDF_STATUS csr_roam_close_session(tpAniSirGlobal mac_ctx, + uint32_t session_id, bool sync); +void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId); +QDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssid, + uint32_t *pSessionId); +enum csr_cfgdot11mode csr_find_best_phy_mode(tpAniSirGlobal pMac, + uint32_t phyMode); + +/* + * csr_scan_get_result() - + * Return scan results. + * + * pFilter - If pFilter is NULL, all cached results are returned + * phResult - an object for the result. + * Return QDF_STATUS + */ +QDF_STATUS csr_scan_get_result(tpAniSirGlobal pMac, tCsrScanResultFilter + *pFilter, 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 + * @res: pointer to tCsrScanResultInfo + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_scan_get_result_for_bssid(tpAniSirGlobal mac_ctx, + struct qdf_mac_addr *bssid, + tCsrScanResultInfo *res); + +/* + * csr_scan_flush_result() - + * Clear scan results. + * + * pMac - pMac global pointer + * sessionId - Session Identifier + * Return QDF_STATUS + */ +QDF_STATUS csr_scan_flush_result(tpAniSirGlobal mac_ctx); +/* + * csr_scan_filter_results() - + * Filter scan results based on valid channel list. + * + * pMac - Pointer to Global MAC structure + * Return QDF_STATUS + */ +QDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac); + +QDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal pMac, bool flushP2P); + +/* + * 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(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + tScanResultHandle hScanResult); + +/* + * csr_get_country_code() - + * This function is to get the country code current being used + * pBuf - Caller allocated buffer with at least 3 bytes, upon success return, + * this has the country code + * pbLen - Caller allocated, as input, it indicates the length of pBuf. Upon + * success return, this contains the length of the data in pBuf + * Return QDF_STATUS + */ +QDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf, + uint8_t *pbLen); + +/* + * csr_get_regulatory_domain_for_country() - + * This function is to get the regulatory domain for a country. + * This function must be called after CFG is downloaded and all the band/mode + * setting already passed into CSR. + * + * pCountry - Caller allocated buffer with at least 3 bytes specifying the + * country code + * pDomainId - Caller allocated buffer to get the return domain ID upon + * success return. Can be NULL. + * source - the source of country information. + * Return QDF_STATUS + */ +QDF_STATUS csr_get_regulatory_domain_for_country(tpAniSirGlobal pMac, + uint8_t *pCountry, + v_REGDOMAIN_t *pDomainId, + enum country_src source); + +/* some support functions */ +bool csr_is11d_supported(tpAniSirGlobal pMac); +bool csr_is11h_supported(tpAniSirGlobal pMac); +bool csr_is11e_supported(tpAniSirGlobal pMac); +bool csr_is_wmm_supported(tpAniSirGlobal pMac); +bool csr_is_mcc_supported(tpAniSirGlobal pMac); + +/* Return SUCCESS is the command is queued, failed */ +QDF_STATUS csr_queue_sme_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fHighPriority); +tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac); +void csr_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_release_command_buffer(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_scan_flush_bss_entry(tpAniSirGlobal pMac, + tpSmeCsaOffloadInd pCsaOffloadInd); + +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(struct csr_roam_profile *pProfile); +#endif /* FEATURE_WLAN_WAPI */ + +void csr_get_vdev_type_nss(tpAniSirGlobal mac_ctx, + enum QDF_OPMODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + +/* Security */ +#define WLAN_SECURITY_EVENT_REMOVE_KEY_REQ 5 +#define WLAN_SECURITY_EVENT_REMOVE_KEY_RSP 6 +#define WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND 7 +#define WLAN_SECURITY_EVENT_PMKID_UPDATE 8 +#define WLAN_SECURITY_EVENT_MIC_ERROR 9 +#define WLAN_SECURITY_EVENT_SET_UNICAST_REQ 10 +#define WLAN_SECURITY_EVENT_SET_UNICAST_RSP 11 +#define WLAN_SECURITY_EVENT_SET_BCAST_REQ 12 +#define WLAN_SECURITY_EVENT_SET_BCAST_RSP 13 + +#define NO_MATCH 0 +#define MATCH 1 + +#define WLAN_SECURITY_STATUS_SUCCESS 0 +#define WLAN_SECURITY_STATUS_FAILURE 1 + +/* Scan */ +#define WLAN_SCAN_EVENT_ACTIVE_SCAN_REQ 1 +#define WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP 2 +#define WLAN_SCAN_EVENT_PASSIVE_SCAN_REQ 3 +#define WLAN_SCAN_EVENT_PASSIVE_SCAN_RSP 4 +#define WLAN_SCAN_EVENT_HO_SCAN_REQ 5 +#define WLAN_SCAN_EVENT_HO_SCAN_RSP 6 + +#define WLAN_SCAN_STATUS_SUCCESS 0 +#define WLAN_SCAN_STATUS_FAILURE 1 +#define WLAN_SCAN_STATUS_ABORT 2 + +/* Ibss */ +#define WLAN_IBSS_EVENT_START_IBSS_REQ 0 +#define WLAN_IBSS_EVENT_START_IBSS_RSP 1 +#define WLAN_IBSS_EVENT_JOIN_IBSS_REQ 2 +#define WLAN_IBSS_EVENT_JOIN_IBSS_RSP 3 +#define WLAN_IBSS_EVENT_COALESCING 4 +#define WLAN_IBSS_EVENT_PEER_JOIN 5 +#define WLAN_IBSS_EVENT_PEER_LEAVE 6 +#define WLAN_IBSS_EVENT_STOP_REQ 7 +#define WLAN_IBSS_EVENT_STOP_RSP 8 + +#define AUTO_PICK 0 +#define SPECIFIED 1 + +#define WLAN_IBSS_STATUS_SUCCESS 0 +#define WLAN_IBSS_STATUS_FAILURE 1 + +/* 11d */ +#define WLAN_80211D_EVENT_COUNTRY_SET 0 +#define WLAN_80211D_EVENT_RESET 1 + +#define WLAN_80211D_DISABLED 0 +#define WLAN_80211D_SUPPORT_MULTI_DOMAIN 1 +#define WLAN_80211D_NOT_SUPPORT_MULTI_DOMAIN 2 + +/** + * diag_auth_type_from_csr_type() - to convert CSR auth type to DIAG auth type + * @authtype: CSR auth type + * + * DIAG tool understands its own ENUMs, so this API can be used to convert + * CSR defined auth type ENUMs to DIAG defined auth type ENUMs + * + * + * Return: DIAG auth type + */ +enum mgmt_auth_type diag_auth_type_from_csr_type(eCsrAuthType authtype); +/** + * diag_enc_type_from_csr_type() - to convert CSR encr type to DIAG encr type + * @enctype: CSR encryption type + * + * DIAG tool understands its own ENUMs, so this API can be used to convert + * CSR defined encr type ENUMs to DIAG defined encr type ENUMs + * + * Return: DIAG encryption type + */ +enum mgmt_encrypt_type diag_enc_type_from_csr_type(eCsrEncryptionType enctype); +/** + * diag_dot11_mode_from_csr_type() - to convert CSR .11 mode to DIAG .11 mode + * @dot11mode: CSR 80211 mode + * + * DIAG tool understands its own ENUMs, so this API can be used to convert + * CSR defined 80211 mode ENUMs to DIAG defined 80211 mode ENUMs + * + * Return: DIAG 80211mode + */ +enum mgmt_dot11_mode +diag_dot11_mode_from_csr_type(enum csr_cfgdot11mode dot11mode); +/** + * diag_ch_width_from_csr_type() - to convert CSR ch width to DIAG ch width + * @ch_width: CSR channel width + * + * DIAG tool understands its own ENUMs, so this API can be used to convert + * CSR defined ch width ENUMs to DIAG defined ch width ENUMs + * + * Return: DIAG channel width + */ +enum mgmt_ch_width diag_ch_width_from_csr_type(enum phy_ch_width ch_width); +/** + * diag_persona_from_csr_type() - to convert QDF persona to DIAG persona + * @persona: QDF persona + * + * DIAG tool understands its own ENUMs, so this API can be used to convert + * QDF defined persona type ENUMs to DIAG defined persona type ENUMs + * + * Return: DIAG persona + */ +enum mgmt_bss_type diag_persona_from_csr_type(enum QDF_OPMODE persona); +#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 reutrns. + * Return QDF_STATUS + */ +QDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac, + tScanResultHandle hScanResult); + +/* /////////////////////////////////////////Common Scan ends */ + +/* + * csr_roam_connect() - + * To inititiate an association + * pProfile - can be NULL to join to any open ones + * pRoamId - to get back the request ID + * Return QDF_STATUS + */ +QDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + uint32_t *pRoamId); + +/* + * csr_roam_reassoc() - + * To inititiate a re-association + * pProfile - can be NULL to join the currently connected AP. In that + * case modProfileFields should carry the modified field(s) which could trigger + * reassoc + * modProfileFields - fields which are part of tCsrRoamConnectedProfile + * that might need modification dynamically once STA is up & running and this + * could trigger a reassoc + * pRoamId - to get back the request ID + * Return QDF_STATUS + */ +QDF_STATUS csr_roam_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId); + +/* + * csr_roam_reconnect() - + * To disconnect and reconnect with the same profile + * + * Return QDF_STATUS. It returns fail if currently not connected + */ +QDF_STATUS csr_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId); + +/* + * csr_roam_set_pmkid_cache() - + * return the PMKID candidate list + * + * pPMKIDCache - caller allocated buffer point to an array of tPmkidCacheInfo + * numItems - a variable that has the number of tPmkidCacheInfo allocated + * when retruning, this is either the number needed or number of items put + * into pPMKIDCache + * Return QDF_STATUS - when fail, it usually means the buffer allocated is not + * big enough and pNumItems has the number of tPmkidCacheInfo. + * \Note: pNumItems is a number of tPmkidCacheInfo, not + * sizeof(tPmkidCacheInfo) * something + */ +QDF_STATUS csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, bool update_entire_cache); + +#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(tpAniSirGlobal mac_ctx, uint8_t session_id, + tPmkidCacheInfo *pmk_cache); + +/* + * csr_roam_set_psk_pmk() - + * store PSK/PMK + * pMac - pointer to global structure for MAC + * sessionId - Sme session id + * pPSK_PMK - pointer to an array of Psk/Pmk + * Return QDF_STATUS - usually it succeed unless sessionId is not found + * Note: + */ +QDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len); + +QDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal mac_ctx, + uint32_t session_id, + bool roam_key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes); +#endif +/* + * csr_roam_get_wpa_rsn_req_ie() - + * Return the WPA or RSN IE CSR passes to PE to JOIN request or START_BSS + * request + * pLen - caller allocated memory that has the length of pBuf as input. + * Upon returned, *pLen has the needed or IE length in pBuf. + * pBuf - Caller allocated memory that contain the IE field, if any, upon return + * Return QDF_STATUS - when fail, it usually means the buffer allocated is not + * big enough + */ +QDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); + +/* + * csr_roam_get_wpa_rsn_rsp_ie() - + * Return the WPA or RSN IE from the beacon or probe rsp if connected + * + * pLen - caller allocated memory that has the length of pBuf as input. + * Upon returned, *pLen has the needed or IE length in pBuf. + * pBuf - Caller allocated memory that contain the IE field, if any, upon return + * Return QDF_STATUS - when fail, it usually means the buffer allocated is not + * big enough + */ +QDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); + +/* + * csr_roam_get_num_pmkid_cache() - + * Return number of PMKID cache entries + * + * Return uint32_t - the number of PMKID cache entries + */ +uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId); + +/* + * csr_roam_get_pmkid_cache() - + * Return PMKID cache from CSR + * + * pNum - caller allocated memory that has the space of the number of pBuf + * tPmkidCacheInfo as input. Upon returned, *pNum has the needed or actually + * number in tPmkidCacheInfo. + * pPmkidCache - Caller allocated memory that contains PMKID cache, if any, + * upon return + * Return QDF_STATUS - when fail, it usually means the buffer allocated is + * not big enough + */ +QDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache); + +/** + * csr_roam_get_connect_profile() - To return the current connect profile, + * caller must call csr_roam_free_connect_profile after it is done and before + * reuse for another csr_roam_get_connect_profile call. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID + * @pProfile: pointer to a caller allocated structure + * tCsrRoamConnectedProfile + * + * Return: QDF_STATUS. Failure if not connected, success otherwise + */ +QDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamConnectedProfile *pProfile); + +/* + * csr_roam_get_connect_state() + * To return the current connect state of Roaming + * + * Return QDF_STATUS + */ +QDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrConnectState *pState); + +void csr_roam_free_connect_profile(tCsrRoamConnectedProfile *profile); + +/* + * csr_apply_channel_and_power_list() - + * HDD calls this function to set the WNI_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(tpAniSirGlobal pMac); + +/* + * csr_roam_connect_to_last_profile() - + * To disconnect and reconnect with the same profile + * + * Return QDF_STATUS. It returns fail if currently connected + */ +QDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, + uint32_t sessionId); + +/* + * csr_roam_disconnect() - + * To disconnect from a network + * + * Reason -- To indicate the reason for disconnecting. Currently, only + * eCSR_DISCONNECT_REASON_MIC_ERROR is meanful. + * Return QDF_STATUS + */ +QDF_STATUS csr_roam_disconnect(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); + +/* This function is used to stop a BSS. It is similar of csr_roamIssueDisconnect + * but this function doesn't have any logic other than blindly trying to stop + * BSS + */ +QDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + bool fHighPriority); + +void csr_call_roaming_completion_callback(tpAniSirGlobal pMac, + struct csr_roam_session *pSession, + struct csr_roam_info *roam_info, + uint32_t roamId, + eCsrRoamResult roamResult); +/** + * csr_roam_issue_disassociate_sta_cmd() - disassociate a associated station + * @pMac: Pointer to global structure for MAC + * @sessionId: Session Id for Soft AP + * @p_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(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_del_sta_params + *p_del_sta_params); +/** + * csr_roam_issue_deauth_sta_cmd() - issue deauthenticate station command + * @pMac: Pointer to global structure for MAC + * @sessionId: Session Id for Soft AP + * @pDelStaParams: 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(tpAniSirGlobal pMac, + uint32_t sessionId, + struct csr_del_sta_params *pDelStaParams); + +/* + * csr_roam_get_associated_stas + * csr function that HDD calls to get list of associated stations based on + * module ID + * sessionId - session Id for Soft AP + * modId - module ID - PE/HAL/TL + * pUsrContext - Opaque HDD context + * pfnSapEventCallback - Sap event callback in HDD + * pAssocStasBuf - Caller allocated memory to be filled with associatd + * stations info + * Return QDF_STATUS + */ +QDF_STATUS csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); + +QDF_STATUS csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, + QDF_MODULE_ID modId, + struct qdf_mac_addr bssId, + void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); + +/* + * 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(tpAniSirGlobal pMac, uint32_t sessionId); + +/** + * csr_roam_ft_pre_auth_rsp_processor() - Handle the preauth response + * @mac_ctx: Global MAC context + * @preauth_rsp: Received preauthentication response + * + * Return: None + */ +#ifdef WLAN_FEATURE_HOST_ROAM +void csr_roam_ft_pre_auth_rsp_processor(tpAniSirGlobal mac_ctx, + tpSirFTPreAuthRsp pFTPreAuthRsp); +#else +static inline +void csr_roam_ft_pre_auth_rsp_processor(tpAniSirGlobal mac_ctx, + tpSirFTPreAuthRsp pFTPreAuthRsp) +{} +#endif + +#if defined(FEATURE_WLAN_ESE) +void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1, + uint64_t *incr); +#endif + +QDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal pMac, uint32_t sessionId, + tpSirBssDescription pBssDescription, + enum csr_roam_reason reason, bool fImmediate); +QDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, + enum csr_roam_reason reason, + uint8_t session_id); +void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac, + uint8_t sessionId, + struct tag_csrscan_result + *pResult, + tDot11fBeaconIEs *pIes); + +QDF_STATUS csr_scan_create_entry_in_scan_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr bssid, + uint8_t channel); + +QDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac); +QDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + tPmkidCacheInfo *pmksa, + bool flush_cache); + +bool csr_elected_country_info(tpAniSirGlobal pMac); +void csr_add_vote_for_country_info(tpAniSirGlobal pMac, uint8_t *pCountryCode); +void csr_clear_votes_for_country_info(tpAniSirGlobal pMac); + +QDF_STATUS csr_send_ext_change_channel(tpAniSirGlobal mac_ctx, + uint32_t channel, uint8_t session_id); + +#ifdef QCA_HT_2040_COEX +QDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled); +#endif +QDF_STATUS csr_scan_handle_search_for_ssid(tpAniSirGlobal mac_ctx, + uint32_t session_id); +QDF_STATUS csr_scan_handle_search_for_ssid_failure(tpAniSirGlobal mac, + uint32_t session_id); +void csr_saved_scan_cmd_free_fields(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session); +tpSirBssDescription csr_get_fst_bssdescr_ptr(tScanResultHandle result_handle); + +tSirBssDescription* +csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle, + tSirBssDescription *bss_descr); +bool is_disconnect_pending(tpAniSirGlobal mac_ctx, + uint8_t sessionid); +void csr_scan_active_list_timeout_handle(void *userData); +QDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac, + uint32_t session_id, tSmeCmd **sme_cmd); + +QDF_STATUS +csr_roam_prepare_bss_config_from_profile(tpAniSirGlobal mac_ctx, + struct csr_roam_profile *profile, + struct bss_config_param *bss_cfg, + tSirBssDescription *bss_desc); + +void csr_roam_prepare_bss_params(tpAniSirGlobal mac_ctx, uint32_t session_id, + struct csr_roam_profile *profile, tSirBssDescription *bss_desc, + struct bss_config_param *bss_cfg, tDot11fBeaconIEs *ies); + +/** + * csr_remove_bssid_from_scan_list() - remove the bssid from + * scan list + * @mac_tx: mac context. + * @bssid: bssid to be removed + * + * This function remove the given bssid from scan list. + * + * Return: void. + */ +void csr_remove_bssid_from_scan_list(tpAniSirGlobal mac_ctx, + tSirMacAddr bssid); + +QDF_STATUS csr_roam_set_bss_config_cfg(tpAniSirGlobal mac_ctx, + uint32_t session_id, + struct csr_roam_profile *profile, tSirBssDescription *bss_desc, + struct bss_config_param *bss_cfg, tDot11fBeaconIEs *ies, + bool reset_country); +void csr_prune_channel_list_for_mode(tpAniSirGlobal pMac, + struct csr_channel *pChannelList); + +#ifdef WLAN_FEATURE_11W +bool csr_is_mfpc_capable(struct sDot11fIERSN *rsn); +#else +static inline bool csr_is_mfpc_capable(struct sDot11fIERSN *rsn) +{ + return false; +} +#endif + +/** + * csr_get_rf_band() + * + * @channel: channel number + * + * This function is used to translate channel number to band + * + * Return: BAND_2G - if 2.4GHZ channel + * BAND_5G - if 5GHZ channel + */ +enum band_info csr_get_rf_band(uint8_t channel); + +/** + * csr_lookup_pmkid_using_bssid() - lookup pmkid using bssid + * @mac: pointer to mac + * @session: sme session pointer + * @pmk_cache: pointer to pmk cache + * @index: index value needs to be seached + * + * Return: true if pmkid is found else false + */ +bool csr_lookup_pmkid_using_bssid(tpAniSirGlobal mac, + struct csr_roam_session *session, + tPmkidCacheInfo *pmk_cache, + uint32_t *index); +#ifdef WLAN_FEATURE_11AX +void csr_update_session_he_cap(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session); +#else +static inline void csr_update_session_he_cap(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session) +{ +} +#endif +/** + * csr_get_channel_for_hw_mode_change() - This function to find + * out if HW mode change + * is needed for any of + * the candidate AP which + * STA could join + * @mac_ctx: mac context + * @result_handle: an object for the result. + * @session_id: STA session ID + * + * This function is written to find out for any bss from scan + * handle a HW mode change to DBS will be needed or not. + * + * Return: AP channel for which DBS HW mode will be needed. 0 + * means no HW mode change is needed. + */ +uint8_t +csr_get_channel_for_hw_mode_change(tpAniSirGlobal mac_ctx, + tScanResultHandle result_handle, + uint32_t session_id); + +/** + * csr_scan_get_channel_for_hw_mode_change() - This function to find + * out if HW mode change + * is needed for any of + * the candidate AP which + * STA could join + * @mac_ctx: mac context + * @session_id: STA session ID + * @profile: profile + * + * This function is written to find out for any bss from scan + * handle a HW mode change to DBS will be needed or not. + * If there is no candidate AP which requires DBS, this function will return + * the first Candidate AP's chan. + * + * Return: AP channel for which HW mode change will be needed. 0 + * means no candidate AP to connect. + */ +uint8_t +csr_scan_get_channel_for_hw_mode_change( + tpAniSirGlobal mac_ctx, uint32_t session_id, + struct csr_roam_profile *profile); +#endif /* CSR_INSIDE_API_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_link_list.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_link_list.c new file mode 100644 index 0000000000000000000000000000000000000000..5d120dc3e8c26cf6d23d142d61fe07055affc08e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_link_list.c @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2011-2012, 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. + */ + +/* + * 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" + +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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pEntry is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + return c; + } + + if (pList && (LIST_FLAG_OPEN == pList->Flag)) + c = pList->Count; + + return c; +} + +void csr_ll_lock(tDblLinkList *pList) +{ + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) + qdf_mutex_acquire(&pList->Lock); +} + +void csr_ll_unlock(tDblLinkList *pList) +{ + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Error!! pList is Null", __func__); + 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/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..eca2c458e454a352a2038d2d232a0cad958ab944 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c @@ -0,0 +1,1768 @@ +/* + * 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: csr_neighbor_roam.c + * + * Implementation for the simple roaming algorithm for 802.11r Fast + * transitions and Legacy roaming for Android platform. + */ + +#include "wma_types.h" +#include "csr_inside_api.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 "sme_api.h" +#include "csr_neighbor_roam.h" +#include "mac_trace.h" +#include "wlan_policy_mgr_api.h" + +#ifdef WLAN_DEBUG +static const char *lfr_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); + CASE_RETURN_STRING(REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED); + default: + return "unknown"; + } +} +#endif + +static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo + rChInfo); + +void csr_neighbor_roam_state_transition(tpAniSirGlobal mac_ctx, + uint8_t newstate, uint8_t session) +{ + mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState = + mac_ctx->roam.neighborRoamInfo[session].neighborRoamState; + mac_ctx->roam.neighborRoamInfo[session].neighborRoamState = newstate; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Sessionid (%d) NeighborRoam transition from %s to %s"), + session, csr_neighbor_roam_state_to_string( + mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState), + csr_neighbor_roam_state_to_string(newstate)); +} + +uint8_t *csr_neighbor_roam_state_to_string(uint8_t state) +{ + switch (state) { + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE); + default: + return "eCSR_NEIGHBOR_ROAM_STATE_UNKNOWN"; + } + +} + +#ifdef FEATURE_WLAN_LFR_METRICS +/** + * csr_neighbor_roam_send_lfr_metric_event() - Send event of LFR metric + * @mac_ctx: Handle returned by mac_open. + * @session_id: Session information + * @bssid: BSSID of attempted AP + * @status: Result of LFR operation + * + * LFR metrics - pre-auth completion metric + * Send the event to supplicant indicating pre-auth result + * + * Return: void + */ + +void csr_neighbor_roam_send_lfr_metric_event( + tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirMacAddr bssid, + eRoamCmdStatus status) +{ + struct csr_roam_info *roam_info; + + roam_info = qdf_mem_malloc(sizeof(struct csr_roam_info)); + if (NULL == roam_info) { + sme_err("Memory allocation failed!"); + } else { + qdf_mem_copy((void *)roam_info->bssid.bytes, + (void *)bssid, sizeof(struct qdf_mac_addr)); + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + status, 0); + qdf_mem_free(roam_info); + } +} +#endif + +/** + * csr_neighbor_roam_update_fast_roaming_enabled() - update roaming capability + * + * @mac_ctx: Global MAC context + * @session_id: Session + * @fast_roam_enabled: Is fast roaming enabled on this device? + * This capability can be changed dynamically. + * + * Return: None + */ +QDF_STATUS csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal mac_ctx, + uint8_t session_id, + const bool fast_roam_enabled) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + + switch (neighbor_roam_info->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + qdf_status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + if (fast_roam_enabled) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_START, + REASON_CONNECT); + } else { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_STOP, + REASON_SUPPLICANT_DISABLED_ROAMING); + } + sme_release_global_lock(&mac_ctx->sme); + } else { + sme_err("Failed to acquire SME lock"); + } + break; + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + sme_debug("Currently in INIT state, Nothing to do"); + break; + default: + sme_err("Unexpected state %s, returning failure", + mac_trace_get_neighbour_roam_state + (neighbor_roam_info->neighborRoamState)); + qdf_status = QDF_STATUS_E_FAILURE; + break; + } + return qdf_status; +} +QDF_STATUS csr_neighbor_roam_update_config(tpAniSirGlobal mac_ctx, + uint8_t session_id, uint8_t value, uint8_t reason) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tpCsrNeighborRoamCfgParams cfg_params; + eCsrNeighborRoamState state; + uint8_t old_value; + + if (NULL == pNeighborRoamInfo) { + sme_err("Invalid Session ID %d", session_id); + return QDF_STATUS_E_FAILURE; + } + cfg_params = &pNeighborRoamInfo->cfgParams; + state = pNeighborRoamInfo->neighborRoamState; + if ((state == eCSR_NEIGHBOR_ROAM_STATE_CONNECTED) || + state == eCSR_NEIGHBOR_ROAM_STATE_INIT) { + switch (reason) { + case REASON_LOOKUP_THRESH_CHANGED: + old_value = cfg_params->neighborLookupThreshold; + cfg_params->neighborLookupThreshold = value; + pNeighborRoamInfo->currentNeighborLookupThreshold = + value; + break; + case REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED: + old_value = cfg_params->nOpportunisticThresholdDiff; + cfg_params->nOpportunisticThresholdDiff = value; + pNeighborRoamInfo->currentOpportunisticThresholdDiff = + value; + break; + case REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED: + old_value = cfg_params->nRoamRescanRssiDiff; + cfg_params->nRoamRescanRssiDiff = value; + pNeighborRoamInfo->currentRoamRescanRssiDiff = value; + break; + case REASON_ROAM_BMISS_FIRST_BCNT_CHANGED: + old_value = cfg_params->nRoamBmissFirstBcnt; + cfg_params->nRoamBmissFirstBcnt = value; + pNeighborRoamInfo->currentRoamBmissFirstBcnt = value; + break; + case REASON_ROAM_BMISS_FINAL_BCNT_CHANGED: + old_value = cfg_params->nRoamBmissFinalBcnt; + cfg_params->nRoamBmissFinalBcnt = value; + pNeighborRoamInfo->currentRoamBmissFinalBcnt = value; + break; + case REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED: + old_value = cfg_params->nRoamBeaconRssiWeight; + cfg_params->nRoamBeaconRssiWeight = value; + pNeighborRoamInfo->currentRoamBeaconRssiWeight = value; + break; + default: + sme_debug("Unknown update cfg reason"); + return QDF_STATUS_E_FAILURE; + } + } else { + sme_err("Unexpected state %s, return fail", + mac_trace_get_neighbour_roam_state(state)); + return QDF_STATUS_E_FAILURE; + } + if (state == eCSR_NEIGHBOR_ROAM_STATE_CONNECTED) { + sme_debug("CONNECTED, send update cfg cmd"); + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, reason); + } + sme_debug("LFR config for %s changed from %d to %d", + lfr_get_config_item_string(reason), old_value, value); + return QDF_STATUS_SUCCESS; +} + +/*CleanUP Routines*/ +static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo + rChInfo) +{ + if ((rChInfo->IAPPNeighborListReceived == false) && + (rChInfo->currentChannelListInfo.numOfChannels)) { + rChInfo->currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + rChInfo->currentChannelListInfo.numOfChannels = 0; + + if (rChInfo->currentChannelListInfo.ChannelList) + qdf_mem_free(rChInfo->currentChannelListInfo. + ChannelList); + + rChInfo->currentChannelListInfo.ChannelList = NULL; + } else { + rChInfo->currentChanIndex = 0; + } +} + +/** + * csr_neighbor_roam_reset_connected_state_control_info() + * + * @mac_ctx: Pointer to Global MAC structure + * @sessionId : session id + * + * This function will reset the neighbor roam control info data structures. + * This function should be invoked whenever we move to CONNECTED state from + * any state other than INIT state + * + * Return: None + */ +static void csr_neighbor_roam_reset_connected_state_control_info( + tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + csr_neighbor_roam_reset_channel_info(&pNeighborRoamInfo-> + roamChannelInfo); + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + + /* Do not free up the preauth done list here */ + pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0; + pNeighborRoamInfo->FTRoamInfo.neighborRptPending = false; + pNeighborRoamInfo->FTRoamInfo.numPreAuthRetries = 0; + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + pNeighborRoamInfo->FTRoamInfo.preauthRspPending = 0; + qdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + pNeighborRoamInfo->uOsRequestedHandoff = 0; + qdf_mem_zero(&pNeighborRoamInfo->handoffReqInfo, + sizeof(tCsrHandoffRequest)); +} + +static void csr_neighbor_roam_reset_report_scan_state_control_info( + tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + qdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid); +#ifdef FEATURE_WLAN_ESE + pNeighborRoamInfo->isESEAssoc = false; + pNeighborRoamInfo->isVOAdmitted = false; + pNeighborRoamInfo->MinQBssLoadRequired = 0; +#endif + + /* Purge roamable AP list */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); +} + +/** + * csr_neighbor_roam_reset_init_state_control_info() + * + * @mac_ctx: Pointer to Global MAC structure + * @sessionId : session id + * + * This function will reset the neighbor roam control info data structures. + * This function should be invoked whenever we move to CONNECTED state from + * INIT state + * + * Return: None + */ +static void csr_neighbor_roam_reset_init_state_control_info(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + csr_neighbor_roam_reset_connected_state_control_info(pMac, sessionId); + + /* In addition to the above resets, + * we should clear off the curAPBssId/Session ID in the timers + */ + csr_neighbor_roam_reset_report_scan_state_control_info(pMac, sessionId); +} + +/** + * csr_neighbor_roam_prepare_scan_profile_filter() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @scan_filter: Populated scan filter based on the connected profile + * + * This function creates a scan filter based on the currently + * connected profile. Based on this filter, scan results are obtained + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS +csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac, + tCsrScanResultFilter *pScanFilter, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo nbr_roam_info = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pCurProfile = + &pMac->roam.roamSession[sessionId].connectedProfile; + uint8_t i = 0; + struct roam_ext_params *roam_params; + uint8_t num_ch = 0; + + QDF_ASSERT(pScanFilter != NULL); + if (pScanFilter == NULL) + return QDF_STATUS_E_FAILURE; + + qdf_mem_zero(pScanFilter, sizeof(tCsrScanResultFilter)); + roam_params = &pMac->roam.configParam.roam_params; + /* We dont want to set BSSID based Filter */ + pScanFilter->BSSIDs.numOfBSSIDs = 0; + pScanFilter->scan_filter_for_roam = 1; + /* only for HDD requested handoff fill in the BSSID in the filter */ + if (nbr_roam_info->uOsRequestedHandoff) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("OS Requested Handoff")); + pScanFilter->BSSIDs.numOfBSSIDs = 1; + pScanFilter->BSSIDs.bssid = + qdf_mem_malloc(sizeof(tSirMacAddr) * + pScanFilter->BSSIDs.numOfBSSIDs); + if (NULL == pScanFilter->BSSIDs.bssid) { + sme_err("Scan Filter BSSID mem alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + /* Populate the BSSID from handoff info received from HDD */ + for (i = 0; i < pScanFilter->BSSIDs.numOfBSSIDs; i++) { + qdf_copy_macaddr(&pScanFilter->BSSIDs.bssid[i], + &nbr_roam_info->handoffReqInfo.bssid); + } + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("No of Allowed SSID List:%d"), + roam_params->num_ssid_allowed_list); + if (roam_params->num_ssid_allowed_list) { + pScanFilter->SSIDs.numOfSSIDs = + roam_params->num_ssid_allowed_list; + pScanFilter->SSIDs.SSIDList = + qdf_mem_malloc(sizeof(tCsrSSIDInfo) * + pScanFilter->SSIDs.numOfSSIDs); + if (!pScanFilter->SSIDs.SSIDList) { + qdf_mem_free(pScanFilter->BSSIDs.bssid); + pScanFilter->BSSIDs.bssid = NULL; + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < roam_params->num_ssid_allowed_list; i++) { + pScanFilter->SSIDs.SSIDList[i].handoffPermitted = 1; + pScanFilter->SSIDs.SSIDList[i].ssidHidden = 0; + qdf_mem_copy((void *) + pScanFilter->SSIDs.SSIDList[i].SSID.ssId, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + pScanFilter->SSIDs.SSIDList[i].SSID.length = + roam_params->ssid_allowed_list[i].length; + } + } else { + /* Populate all the information from the connected profile */ + pScanFilter->SSIDs.numOfSSIDs = 1; + pScanFilter->SSIDs.SSIDList = + qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (!pScanFilter->SSIDs.SSIDList) { + qdf_mem_free(pScanFilter->BSSIDs.bssid); + pScanFilter->BSSIDs.bssid = NULL; + return QDF_STATUS_E_NOMEM; + } + + pScanFilter->SSIDs.SSIDList->handoffPermitted = 1; + pScanFilter->SSIDs.SSIDList->ssidHidden = 0; + pScanFilter->SSIDs.SSIDList->SSID.length = + pCurProfile->SSID.length; + qdf_mem_copy((void *)pScanFilter->SSIDs.SSIDList->SSID.ssId, + (void *)pCurProfile->SSID.ssId, + pCurProfile->SSID.length); + + sme_debug("Filtering for SSID %.*s,length of SSID = %u", + pScanFilter->SSIDs.SSIDList->SSID.length, + pScanFilter->SSIDs.SSIDList->SSID.ssId, + pScanFilter->SSIDs.SSIDList->SSID.length); + } + pScanFilter->authType.numEntries = 1; + pScanFilter->authType.authType[0] = pCurProfile->AuthType; + + pScanFilter->EncryptionType.numEntries = 1; /* This must be 1 */ + pScanFilter->EncryptionType.encryptionType[0] = + pCurProfile->EncryptionType; + + pScanFilter->mcEncryptionType.numEntries = 1; + pScanFilter->mcEncryptionType.encryptionType[0] = + pCurProfile->mcEncryptionType; + + pScanFilter->BSSType = pCurProfile->BSSType; + + num_ch = + nbr_roam_info->roamChannelInfo.currentChannelListInfo.numOfChannels; + if (num_ch) { + /* + * We are intrested only in the scan results on channels we + * scanned + */ + pScanFilter->ChannelInfo.numOfChannels = num_ch; + pScanFilter->ChannelInfo.ChannelList = + qdf_mem_malloc(num_ch * sizeof(uint8_t)); + if (!pScanFilter->ChannelInfo.ChannelList) { + qdf_mem_free(pScanFilter->BSSIDs.bssid); + pScanFilter->BSSIDs.bssid = NULL; + qdf_mem_free(pScanFilter->SSIDs.SSIDList); + pScanFilter->SSIDs.SSIDList = NULL; + return QDF_STATUS_E_NOMEM; + } + for (i = 0; i < pScanFilter->ChannelInfo.numOfChannels; i++) { + pScanFilter->ChannelInfo.ChannelList[i] = + nbr_roam_info->roamChannelInfo.currentChannelListInfo. + ChannelList[i]; + } + } else { + pScanFilter->ChannelInfo.numOfChannels = 0; + pScanFilter->ChannelInfo.ChannelList = NULL; + } + + if (nbr_roam_info->is11rAssoc) { + /* + * MDIE should be added as a part of profile. This should be + * added as a part of filter as well + */ + pScanFilter->MDID.mdiePresent = pCurProfile->MDID.mdiePresent; + pScanFilter->MDID.mobilityDomain = + pCurProfile->MDID.mobilityDomain; + } + +#ifdef WLAN_FEATURE_11W + pScanFilter->MFPEnabled = pCurProfile->MFPEnabled; + pScanFilter->MFPRequired = pCurProfile->MFPRequired; + pScanFilter->MFPCapable = pCurProfile->MFPCapable; +#endif + return QDF_STATUS_SUCCESS; +} + +enum band_info csr_get_rf_band(uint8_t channel) +{ + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + return BAND_5G; + + if ((channel >= SIR_11B_CHANNEL_BEGIN) && + (channel <= SIR_11B_CHANNEL_END)) + return BAND_2G; + + return BAND_UNKNOWN; +} + +/** + * csr_neighbor_roam_channels_filter_by_current_band() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @input_ch_list: The input channel list + * @input_num_of_ch: The number of channels in input channel list + * @output_ch_list: The output channel list + * @output_num_of_ch: The number of channels in output channel list + * @merged_output_num_of_ch: The final number of channels in the + * output channel list. + * + * This function is used to filter out the channels based on the + * currently associated AP channel + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_channels_filter_by_current_band(tpAniSirGlobal + pMac, + uint8_t sessionId, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t * + pMergedOutputNumOfChannels) +{ + uint8_t i = 0; + uint8_t numChannels = 0; + uint8_t currAPoperationChannel = + pMac->roam.neighborRoamInfo[sessionId].currAPoperationChannel; + /* Check for NULL pointer */ + if (!pInputChannelList) + return QDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!pOutputChannelList) + return QDF_STATUS_E_INVAL; + + if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Input Channels %d", + __func__, inputNumOfChannels); + return QDF_STATUS_E_INVAL; + } + for (i = 0; i < inputNumOfChannels; i++) { + if (csr_get_rf_band(currAPoperationChannel) == + csr_get_rf_band(pInputChannelList[i])) { + pOutputChannelList[numChannels] = pInputChannelList[i]; + numChannels++; + } + } + + /* Return final number of channels */ + *pMergedOutputNumOfChannels = numChannels; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_channels_filter_by_current_band() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @input_ch_list: The additional channels to merge in to the + * "merged" channels list. + * @input_num_of_ch: The number of additional channels. + * @output_ch_list: The place to put the "merged" channel list. + * @output_num_of_ch: The original number of channels in the + * "merged" channels list. + * @merged_output_num_of_ch: The final number of channels in the + * "merged" channel list. + * + * This function is used to merge two channel list. + * NB: If called with outputNumOfChannels == 0, this routines simply + * copies the input channel list to the output channel list. if number + * of merged channels are more than 100, num of channels set to 100 + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t outputNumOfChannels, + uint8_t * + pMergedOutputNumOfChannels) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t numChannels = outputNumOfChannels; + + /* Check for NULL pointer */ + if (!pInputChannelList) + return QDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!pOutputChannelList) + return QDF_STATUS_E_INVAL; + + if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Input Channels %d", + __func__, inputNumOfChannels); + return QDF_STATUS_E_INVAL; + } + if (outputNumOfChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Output Channels %d", + __func__, outputNumOfChannels); + return QDF_STATUS_E_INVAL; + } + /* Add the "new" channels in the input list to the end of the + * output list. + */ + for (i = 0; i < inputNumOfChannels; i++) { + for (j = 0; j < outputNumOfChannels; j++) { + if (pInputChannelList[i] == pOutputChannelList[j]) + break; + } + if (j == outputNumOfChannels) { + if (pInputChannelList[i]) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: [INFOLOG] Adding extra %d to Neighbor channel list", + __func__, pInputChannelList[i]); + pOutputChannelList[numChannels] = + pInputChannelList[i]; + numChannels++; + } + } + if (numChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Merge Neighbor channel list reached Max limit %d", + __func__, numChannels); + break; + } + } + + /* Return final number of channels */ + *pMergedOutputNumOfChannels = numChannels; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_is_ssid_and_security_match() - to match ssid/security + * @pMac: Pointer to mac context + * @pCurProfile: pointer to current roam profile + * @pBssDesc: pointer to bss description + * @pIes: pointer to local ies + * + * This routine will be called to see if SSID and security parameters + * are matching. + * + * Return: bool + */ +static bool csr_neighbor_roam_is_ssid_and_security_match(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pCurProfile, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes) +{ + tCsrAuthList authType; + tCsrEncryptionList uCEncryptionType; + tCsrEncryptionList mCEncryptionType; + bool fMatch = false; + + authType.numEntries = 1; + authType.authType[0] = pCurProfile->AuthType; + uCEncryptionType.numEntries = 1; + uCEncryptionType.encryptionType[0] = pCurProfile->EncryptionType; + mCEncryptionType.numEntries = 1; + mCEncryptionType.encryptionType[0] = pCurProfile->mcEncryptionType; + + /* Again, treat missing pIes as a non-match. */ + if (!pIes) + return false; + + /* Treat a missing SSID as a non-match. */ + if (!pIes->SSID.present) + return false; + + fMatch = csr_is_ssid_match(pMac, + (void *)pCurProfile->SSID.ssId, + pCurProfile->SSID.length, + pIes->SSID.ssid, + pIes->SSID.num_ssid, true); + if (true == fMatch) { +#ifdef WLAN_FEATURE_11W + /* + * We are sending current connected APs profile setting + * if other AP doesn't have the same PMF setting as currently + * connected AP then we will have some issues in roaming. + * + * Make sure all the APs have same PMF settings to avoid + * any corner cases. + */ + fMatch = csr_is_security_match(pMac, &authType, + &uCEncryptionType, &mCEncryptionType, + &pCurProfile->MFPEnabled, + &pCurProfile->MFPRequired, + &pCurProfile->MFPCapable, + pBssDesc, pIes, NULL, NULL, NULL); +#else + fMatch = csr_is_security_match(pMac, &authType, + &uCEncryptionType, + &mCEncryptionType, NULL, + NULL, NULL, pBssDesc, + pIes, NULL, NULL, NULL); +#endif + return fMatch; + } else { + return fMatch; + } + +} + +bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pCurrProfile = NULL; + tCsrRoamConnectedProfile *pPrevProfile = NULL; + tDot11fBeaconIEs *pIes = NULL; + tSirBssDescription *pBssDesc = NULL; + bool fNew = true; + + if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) + return fNew; + + pCurrProfile = &pMac->roam.roamSession[sessionId].connectedProfile; + if (!pCurrProfile) + return fNew; + + pPrevProfile = &pNeighborRoamInfo->prevConnProfile; + if (!pPrevProfile) + return fNew; + + pBssDesc = pPrevProfile->pBssDesc; + if (pBssDesc) { + if (QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, pBssDesc, &pIes)) + && csr_neighbor_roam_is_ssid_and_security_match(pMac, + pCurrProfile, pBssDesc, pIes)) { + fNew = false; + } + if (pIes) + qdf_mem_free(pIes); + } + + sme_debug("roam profile match: %d", !fNew); + + return fNew; +} + +bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac, + uint8_t sessionId, + struct tag_csrscan_result + *pResult, + tDot11fBeaconIEs *pIes) +{ + tCsrRoamConnectedProfile *pCurProfile = NULL; + tSirBssDescription *pBssDesc = &pResult->Result.BssDescriptor; + + if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) + return false; + + pCurProfile = &pMac->roam.roamSession[sessionId].connectedProfile; + + if (!pCurProfile) + return false; + + return csr_neighbor_roam_is_ssid_and_security_match(pMac, pCurProfile, + pBssDesc, pIes); +} + +/** + * csr_roam_reset_roam_params - API to reset the roaming parameters + * @mac_ctx: Pointer to the global MAC structure + * + * The BSSID blacklist should not be cleared since it has to + * be used across connections. These parameters will be cleared + * and sent to firmware with with the roaming STOP command. + * + * Return: VOID + */ +void csr_roam_reset_roam_params(tpAniSirGlobal mac_ctx) +{ + struct roam_ext_params *roam_params = NULL; + + /* + * clear all the whitelist parameters and remaining + * needs to be retained across connections. + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Roaming parameters are reset")); + roam_params = &mac_ctx->roam.configParam.roam_params; + roam_params->num_ssid_allowed_list = 0; + qdf_mem_zero(&roam_params->ssid_allowed_list, + sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST); +} + +/** + * csr_neighbor_roam_indicate_disconnect() - To indicate disconnect + * @pMac: The handle returned by mac_open + * @sessionId: CSR session id that got disconnected + * + * This function is called by CSR as soon as the station disconnects + * from the AP. This function does the necessary cleanup of neighbor roam + * data structures. Neighbor roam state transitions to INIT state whenever + * this function is called except if the current state is REASSOCIATING + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pPrevProfile = + &pNeighborRoamInfo->prevConnProfile; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + struct csr_roam_session *roam_session = NULL; + + if (NULL == pSession) { + sme_err("pSession is NULL"); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Disconn ind on session %d in state %d from bss :" + MAC_ADDRESS_STR), sessionId, + pNeighborRoamInfo->neighborRoamState, + MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes)); + /* + * Free the current previous profile and move + * the current profile to prev profile. + */ + csr_roam_free_connect_profile(pPrevProfile); + csr_roam_copy_connect_profile(pMac, sessionId, pPrevProfile); + /* + * clear the roaming parameters that are per connection. + * For a new connection, they have to be programmed again. + */ + if (!csr_neighbor_middle_of_roaming(pMac, sessionId)) + csr_roam_reset_roam_params(pMac); + if (NULL != pSession) { + roam_session = &pMac->roam.roamSession[sessionId]; + if (NULL != pSession->pCurRoamProfile && (QDF_STA_MODE != + roam_session->pCurRoamProfile->csrPersona)) { + sme_err("Ignore disconn ind rcvd from nonSTA persona sessionId: %d csrPersonna %d", + sessionId, + (int)roam_session->pCurRoamProfile->csrPersona); + return QDF_STATUS_SUCCESS; + } +#ifdef FEATURE_WLAN_ESE + if (pSession->connectedProfile.isESEAssoc) { + qdf_mem_copy(&pSession->prevApSSID, + &pSession->connectedProfile.SSID, + sizeof(tSirMacSSid)); + qdf_copy_macaddr(&pSession->prevApBssid, + &pSession->connectedProfile.bssid); + pSession->prevOpChannel = + pSession->connectedProfile.operationChannel; + pSession->isPrevApInfoValid = true; + pSession->roamTS1 = qdf_mc_timer_get_system_time(); + } +#endif + } + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING: + /* + * Stop scan and neighbor refresh timers. + * These are indeed not required when we'r in reassoc state. + */ + if (!CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) { + /* + * Disconnect indication during Disassoc Handoff + * sub-state is received when we are trying to + * disconnect with the old AP during roam. + * BUT, if receive a disconnect indication outside of + * Disassoc Handoff sub-state, then it means that + * this is a genuine disconnect and we need to clean up. + * Otherwise, we will be stuck in reassoc state which'll + * in-turn block scans. + */ + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo. + IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + } + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + csr_neighbor_roam_reset_init_state_control_info(pMac, + sessionId); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = + false; + csr_neighbor_roam_reset_connected_state_control_info(pMac, + sessionId); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE: + /* Stop pre-auth to reassoc interval timer */ + qdf_mc_timer_stop(&pSession->ftSmeContext. + preAuthReassocIntvlTimer); + case eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING: + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = + false; + csr_neighbor_roam_reset_preauth_control_info(pMac, sessionId); + csr_neighbor_roam_reset_report_scan_state_control_info(pMac, + sessionId); + break; + default: + sme_debug("Received disconnect event in state %s", + mac_trace_get_neighbour_roam_state( + pNeighborRoamInfo->neighborRoamState)); + sme_debug("Transit to INIT state"); + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo. + IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + break; + } + /*Inform the Firmware to STOP Scanning as the host has a disconnect. */ + if (csr_roam_is_sta_mode(pMac, sessionId)) { + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_STOP, + REASON_DISCONNECTED); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_info_ctx_init() - Initialize neighbor roam struct + * @pMac: mac context + * @session_id: Session Id + * + * This initializes all the necessary data structures related to the + * associated AP. + * + * Return: QDF status + */ +static void csr_neighbor_roam_info_ctx_init( + tpAniSirGlobal pMac, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + struct csr_roam_session *session = &pMac->roam.roamSession[session_id]; + struct csr_roam_profile *roam_profile = session->pCurRoamProfile; + int init_ft_flag = false; + + /* + * Initialize the occupied list ONLY if we are + * transitioning from INIT state to CONNECTED state. + */ + if (eCSR_NEIGHBOR_ROAM_STATE_INIT == + ngbr_roam_info->neighborRoamState) + csr_init_occupied_channels_list(pMac, session_id); + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, session_id); + + qdf_copy_macaddr(&ngbr_roam_info->currAPbssid, + &session->connectedProfile.bssid); + ngbr_roam_info->currAPoperationChannel = + session->connectedProfile.operationChannel; + ngbr_roam_info->currentNeighborLookupThreshold = + ngbr_roam_info->cfgParams.neighborLookupThreshold; + ngbr_roam_info->currentOpportunisticThresholdDiff = + ngbr_roam_info->cfgParams.nOpportunisticThresholdDiff; + ngbr_roam_info->currentRoamRescanRssiDiff = + ngbr_roam_info->cfgParams.nRoamRescanRssiDiff; + ngbr_roam_info->currentRoamBmissFirstBcnt = + ngbr_roam_info->cfgParams.nRoamBmissFirstBcnt; + ngbr_roam_info->currentRoamBmissFinalBcnt = + ngbr_roam_info->cfgParams.nRoamBmissFinalBcnt; + ngbr_roam_info->currentRoamBeaconRssiWeight = + ngbr_roam_info->cfgParams.nRoamBeaconRssiWeight; + + /* + * Now we can clear the preauthDone that + * was saved as we are connected afresh + */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList); + + /* Based on the auth scheme tell if we are 11r */ + if (csr_is_auth_type11r + (pMac, session->connectedProfile.AuthType, + session->connectedProfile.MDID.mdiePresent)) { + if (pMac->roam.configParam.isFastTransitionEnabled) + init_ft_flag = true; + ngbr_roam_info->is11rAssoc = true; + } else + ngbr_roam_info->is11rAssoc = false; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("11rAssoc is = %d"), ngbr_roam_info->is11rAssoc); + +#ifdef FEATURE_WLAN_ESE + /* Based on the auth scheme tell if we are 11r */ + if (session->connectedProfile.isESEAssoc) { + if (pMac->roam.configParam.isFastTransitionEnabled) + init_ft_flag = true; + ngbr_roam_info->isESEAssoc = true; + } else + ngbr_roam_info->isESEAssoc = false; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("isESEAssoc is = %d ft = %d"), + ngbr_roam_info->isESEAssoc, init_ft_flag); +#endif + /* If "FastRoamEnabled" ini is enabled */ + if (csr_roam_is_fast_roam_enabled(pMac, session_id)) + init_ft_flag = true; + + if (init_ft_flag) { + /* Initialize all the data needed for the 11r FT Preauth */ + ngbr_roam_info->FTRoamInfo.currentNeighborRptRetryNum = 0; + csr_neighbor_roam_purge_preauth_failed_list(pMac); + } + + if (csr_roam_is_roam_offload_scan_enabled(pMac)) { + /* + * If this is not a INFRA type BSS, then do not send the command + * down to firmware.Do not send the START command for + * other session connections. + */ + if (!csr_roam_is_sta_mode(pMac, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Wrong Mode %d", + session->connectedProfile.BSSType); + return; + } + ngbr_roam_info->uOsRequestedHandoff = 0; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress) { + if (pMac->roam.pReassocResp != NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "Free Reassoc Rsp"); + qdf_mem_free(pMac->roam.pReassocResp); + pMac->roam.pReassocResp = NULL; + } + } else +#endif + { + csr_roam_offload_scan(pMac, session_id, + ROAM_SCAN_OFFLOAD_START, + REASON_CTX_INIT); + + if (roam_profile && + roam_profile->supplicant_disabled_roaming) { + sme_debug("Supplicant disabled driver roaming"); + csr_roam_offload_scan(pMac, session_id, + ROAM_SCAN_OFFLOAD_STOP, + REASON_SUPPLICANT_DISABLED_ROAMING); + } + } + } +} + +/** + * csr_neighbor_roam_indicate_connect() + * @pMac: mac context + * @session_id: Session Id + * @qdf_status: QDF status + * + * This function is called by CSR as soon as the station connects to an AP. + * This initializes all the necessary data structures related to the + * associated AP and transitions the state to CONNECTED state + * + * Return: QDF status + */ +QDF_STATUS csr_neighbor_roam_indicate_connect( + tpAniSirGlobal pMac, uint8_t session_id, + QDF_STATUS qdf_status) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + struct csr_roam_session *session = &pMac->roam.roamSession[session_id]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + struct csr_roam_info roamInfo; +#endif + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* if session id invalid then we need return failure */ + if (NULL == ngbr_roam_info || !CSR_IS_SESSION_VALID(pMac, session_id) + || (NULL == pMac->roam.roamSession[session_id].pCurRoamProfile)) { + return QDF_STATUS_E_FAILURE; + } + + sme_debug("Connect ind. received with session id %d in state %s", + session_id, mac_trace_get_neighbour_roam_state( + ngbr_roam_info->neighborRoamState)); + + /* Bail out if this is NOT a STA persona */ + if (pMac->roam.roamSession[session_id].pCurRoamProfile->csrPersona != + QDF_STA_MODE) { + sme_err("Ignoring Connect ind received from a non STA. session_id: %d, csrPersonna %d", + session_id, + (int)session->pCurRoamProfile->csrPersona); + return QDF_STATUS_SUCCESS; + } + /* if a concurrent session is running */ + if ((false == + CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) && + (csr_is_concurrent_session_running(pMac))) { + sme_err("Ignoring Connect ind. received in multisession %d", + csr_is_concurrent_session_running(pMac)); + return QDF_STATUS_SUCCESS; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress && + (eSIR_ROAM_AUTH_STATUS_AUTHENTICATED == + session->roam_synch_data->authStatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR3:csr_neighbor_roam_indicate_connect"); + qdf_copy_macaddr(&roamInfo.peerMac, + &session->connectedProfile.bssid); + roamInfo.roamSynchInProgress = + session->roam_synch_in_progress; + csr_roam_call_callback(pMac, session_id, &roamInfo, 0, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_RESULT_AUTHENTICATED); + csr_neighbor_roam_reset_init_state_control_info(pMac, + session_id); + csr_neighbor_roam_info_ctx_init(pMac, session_id); + return status; + } +#endif + + switch (ngbr_roam_info->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING: + if (QDF_STATUS_SUCCESS != qdf_status) { + /** + * Just transition the state to INIT state.Rest of the + * clean up happens when we get next connect indication + */ + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, session_id); + ngbr_roam_info->roamChannelInfo. + IAPPNeighborListReceived = false; + ngbr_roam_info->uOsRequestedHandoff = 0; + break; + } + /* Fall through if the status is SUCCESS */ + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + /* Reset all the data structures here */ + csr_neighbor_roam_reset_init_state_control_info(pMac, + session_id); + csr_neighbor_roam_info_ctx_init(pMac, session_id); + break; + default: + sme_err("Connect evt received in invalid state %s Ignoring", + mac_trace_get_neighbour_roam_state( + ngbr_roam_info->neighborRoamState)); + break; + } + return status; +} + +/* + * csr_neighbor_roam_init11r_assoc_info - + * This function initializes 11r related neighbor roam data structures + * + * @pMac: The handle returned by mac_open. + * + * return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +static QDF_STATUS csr_neighbor_roam_init11r_assoc_info(tpAniSirGlobal pMac) +{ + QDF_STATUS status; + uint8_t i; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tpCsr11rAssocNeighborInfo pFTRoamInfo = NULL; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[i]; + pFTRoamInfo = &pNeighborRoamInfo->FTRoamInfo; + + pNeighborRoamInfo->is11rAssoc = false; + pNeighborRoamInfo->cfgParams.maxNeighborRetries = + pMac->roam.configParam.neighborRoamConfig. + nMaxNeighborRetries; + + pFTRoamInfo->neighborReportTimeout = + CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT; + pFTRoamInfo->PEPreauthRespTimeout = + CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER * + pNeighborRoamInfo->cfgParams.neighborScanPeriod; + pFTRoamInfo->neighborRptPending = false; + pFTRoamInfo->preauthRspPending = false; + + pFTRoamInfo->currentNeighborRptRetryNum = 0; + pFTRoamInfo->numBssFromNeighborReport = 0; + + qdf_mem_zero(pFTRoamInfo->neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + + status = csr_ll_open(&pFTRoamInfo->preAuthDoneList); + if (QDF_STATUS_SUCCESS != status) { + sme_err("LL Open of preauth done AP List failed"); + return QDF_STATUS_E_RESOURCES; + } + } + return status; +} + +/* + * csr_neighbor_roam_init() - + * This function initializes neighbor roam data structures + * + * @pMac: The handle returned by mac_open. + * sessionId: Session identifier + * + * Return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +QDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId) +{ + QDF_STATUS status; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + pNeighborRoamInfo->neighborRoamState = eCSR_NEIGHBOR_ROAM_STATE_CLOSED; + pNeighborRoamInfo->prevNeighborRoamState = + eCSR_NEIGHBOR_ROAM_STATE_CLOSED; + pNeighborRoamInfo->cfgParams.maxChannelScanTime = + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMaxChanTime; + pNeighborRoamInfo->cfgParams.minChannelScanTime = + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime; + pNeighborRoamInfo->cfgParams.maxNeighborRetries = 0; + pNeighborRoamInfo->cfgParams.neighborLookupThreshold = + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold; + pNeighborRoamInfo->cfgParams.rssi_thresh_offset_5g = + pMac->roam.configParam.neighborRoamConfig.rssi_thresh_offset_5g; + pNeighborRoamInfo->cfgParams.delay_before_vdev_stop = + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop; + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff = + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff; + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff = + pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff; + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt = + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt; + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt = + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt; + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight = + pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight; + pNeighborRoamInfo->cfgParams.neighborScanPeriod = + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanTimerPeriod; + pNeighborRoamInfo->cfgParams.neighbor_scan_min_period = + pMac->roam.configParam.neighborRoamConfig. + neighbor_scan_min_timer_period; + pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod = + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod; + pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod = + pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod; + + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + numChannels; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("number of channels: %u"), + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels); + if (pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels != 0) { + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = + qdf_mem_malloc(pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + if (NULL == + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + sme_err("Memory Allocation for CFG Channel List failed"); + return QDF_STATUS_E_NOMEM; + } + } else { + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + } + + /* Update the roam global structure from CFG */ + qdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList, + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.channelList, + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + pNeighborRoamInfo->cfgParams.hi_rssi_scan_max_count = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_max_count; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_delta = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_rssi_delta; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_delay = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_delay; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_ub = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_rssi_ub; + + qdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid); + pNeighborRoamInfo->currentNeighborLookupThreshold = + pNeighborRoamInfo->cfgParams.neighborLookupThreshold; + pNeighborRoamInfo->currentOpportunisticThresholdDiff = + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff; + pNeighborRoamInfo->currentRoamRescanRssiDiff = + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff; + pNeighborRoamInfo->currentRoamBmissFirstBcnt = + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt; + pNeighborRoamInfo->currentRoamBmissFinalBcnt = + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt; + pNeighborRoamInfo->currentRoamBeaconRssiWeight = + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight; + qdf_mem_zero(&pNeighborRoamInfo->prevConnProfile, + sizeof(tCsrRoamConnectedProfile)); + + status = csr_ll_open(&pNeighborRoamInfo->roamableAPList); + if (QDF_STATUS_SUCCESS != status) { + sme_err("LL Open of roam able AP List failed"); + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + return QDF_STATUS_E_RESOURCES; + } + + pNeighborRoamInfo->roamChannelInfo.currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + + status = csr_neighbor_roam_init11r_assoc_info(pMac); + if (QDF_STATUS_SUCCESS != status) { + sme_err("LL Open of roam able AP List failed"); + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + csr_ll_close(&pNeighborRoamInfo->roamableAPList); + return QDF_STATUS_E_RESOURCES; + } + + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + /* Set the Last Sent Cmd as RSO_STOP */ + pNeighborRoamInfo->last_sent_cmd = ROAM_SCAN_OFFLOAD_STOP; + return QDF_STATUS_SUCCESS; +} + +/* + * csr_neighbor_roam_close() - + * This function closes/frees all the neighbor roam data structures + * + * @pMac: The handle returned by mac_open. + * @sessionId: Session identifier + * + * Return VOID + */ +void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (eCSR_NEIGHBOR_ROAM_STATE_CLOSED == + pNeighborRoamInfo->neighborRoamState) { + sme_warn("Neighbor Roam Algorithm Already Closed"); + return; + } + + if (pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + + /* Should free up the nodes in the list before closing the + * double Linked list + */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + csr_ll_close(&pNeighborRoamInfo->roamableAPList); + + if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList) { + qdf_mem_free(pNeighborRoamInfo->roamChannelInfo. + currentChannelListInfo.ChannelList); + } + + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + + /* Free the profile.. */ + csr_release_profile(pMac, &pNeighborRoamInfo->csrNeighborRoamProfile); + csr_roam_free_connect_profile(&pNeighborRoamInfo->prevConnProfile); + pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0; + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + qdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->FTRoamInfo. + preAuthDoneList); + csr_ll_close(&pNeighborRoamInfo->FTRoamInfo.preAuthDoneList); + pNeighborRoamInfo->b_roam_scan_offload_started = false; + + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_CLOSED, sessionId); + +} + +/** + * csr_neighbor_roam_is11r_assoc() - Check if association type is 11R + * @mac_ctx: MAC Global context + * @session_id: Session ID + * + * Return: true if 11r Association, false otherwise. + */ +bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + return mac_ctx->roam.neighborRoamInfo[session_id].is11rAssoc; +} + +/* + * csr_neighbor_middle_of_roaming() - + * This function returns true if STA is in the middle of roaming states + * + * @halHandle: The handle from HDD context. + * @sessionId: Session identifier + * + * Return bool + */ +bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + bool val = (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING == + pNeighborRoamInfo->neighborRoamState) || + (eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING == + pNeighborRoamInfo->neighborRoamState) || + (eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE == + pNeighborRoamInfo->neighborRoamState); + return val; +} + +/** + * csr_neighbor_roam_process_handoff_req - Processes handoff request + * + * @mac_ctx Pointer to mac context + * @session_id SME session id + * + * This function is called start with the handoff process. First do a + * SSID scan for the BSSID provided. + * + * Return: status + */ +static QDF_STATUS csr_neighbor_roam_process_handoff_req( + tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo roam_ctrl_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t roam_id; + struct csr_roam_profile *profile = NULL; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + uint8_t i = 0; + uint8_t roam_now = 0; + uint8_t roamable_ap_count = 0; + tCsrScanResultFilter scan_filter; + tScanResultHandle scan_result; + + if (NULL == session) { + sme_err("session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + profile = qdf_mem_malloc(sizeof(struct csr_roam_profile)); + if (NULL == profile) { + sme_err("Memory alloc failed"); + return QDF_STATUS_E_NOMEM; + } + status = + csr_roam_copy_profile(mac_ctx, profile, + session->pCurRoamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Profile copy failed"); + goto end; + } + /* Add the BSSID & Channel */ + profile->BSSIDs.numOfBSSIDs = 1; + if (NULL == profile->BSSIDs.bssid) { + profile->BSSIDs.bssid = + qdf_mem_malloc(sizeof(tSirMacAddr) * + profile->BSSIDs.numOfBSSIDs); + if (NULL == profile->BSSIDs.bssid) { + sme_err("mem alloc failed for BSSID"); + status = QDF_STATUS_E_NOMEM; + goto end; + } + } + + /* Populate the BSSID from handoff info received from HDD */ + for (i = 0; i < profile->BSSIDs.numOfBSSIDs; i++) { + qdf_copy_macaddr(&profile->BSSIDs.bssid[i], + &roam_ctrl_info->handoffReqInfo.bssid); + } + + profile->ChannelInfo.numOfChannels = 1; + if (NULL == profile->ChannelInfo.ChannelList) { + profile->ChannelInfo.ChannelList = + qdf_mem_malloc(sizeof(*profile-> + ChannelInfo.ChannelList) * + profile->ChannelInfo.numOfChannels); + if (NULL == profile->ChannelInfo.ChannelList) { + sme_err("mem alloc failed for ChannelList"); + status = QDF_STATUS_E_NOMEM; + goto end; + } + } + profile->ChannelInfo.ChannelList[0] = + roam_ctrl_info->handoffReqInfo.channel; + + /* + * For User space connect requests, the scan has already been done. + * So, check if the BSS descriptor exists in the scan cache and + * proceed with the handoff instead of a redundant scan again. + */ + if (roam_ctrl_info->handoffReqInfo.src == CONNECT_CMD_USERSPACE) { + sme_debug("Connect cmd with bssid within same ESS"); + status = csr_neighbor_roam_prepare_scan_profile_filter(mac_ctx, + &scan_filter, + session_id); + sme_debug("Filter creation status: %d", status); + status = csr_scan_get_result(mac_ctx, &scan_filter, + &scan_result); + csr_neighbor_roam_process_scan_results(mac_ctx, session_id, + &scan_result); + roamable_ap_count = csr_ll_count( + &roam_ctrl_info->roamableAPList); + csr_free_scan_filter(mac_ctx, &scan_filter); + sme_debug("roam_now=%d, roamable_ap_count=%d", + roam_now, roamable_ap_count); + } + if (roam_now && roamable_ap_count) { + csr_neighbor_roam_trigger_handoff(mac_ctx, session_id); + } else { + status = csr_scan_for_ssid(mac_ctx, session_id, profile, + roam_id, false); + if (status != QDF_STATUS_SUCCESS) + sme_err("SSID scan failed"); + } + +end: + if (NULL != profile) { + csr_release_profile(mac_ctx, profile); + qdf_mem_free(profile); + } + + return status; +} + +/* + * csr_neighbor_roam_sssid_scan_done() - + * This function is called once SSID scan is done. If SSID scan failed + * to find our candidate add an entry to csr scan cache ourself before starting + * the handoff process + + * @pMac: The handle returned by mac_open. + * @session_id SME session id + * + * Return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +QDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac, + uint8_t sessionId, QDF_STATUS status) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + QDF_STATUS hstatus; + + /* we must be in connected state, if not ignore it */ + if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) { + sme_err("Received in not CONNECTED state. Ignore it"); + return QDF_STATUS_E_FAILURE; + } + /* if SSID scan failed to find our candidate add an entry to + * csr scan cache ourself + */ + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Add an entry to csr scan cache"); + hstatus = csr_scan_create_entry_in_scan_cache(pMac, sessionId, + pNeighborRoamInfo-> + handoffReqInfo.bssid, + pNeighborRoamInfo-> + handoffReqInfo.channel); + if (QDF_STATUS_SUCCESS != hstatus) { + sme_err( + "csr_scan_create_entry_in_scan_cache failed with status %d", + hstatus); + return QDF_STATUS_E_FAILURE; + } + } + + /* Now we have completed scanning for the candidate provided by HDD. + * Let move on to HO + */ + hstatus = csr_neighbor_roam_process_scan_complete(pMac, sessionId); + + if (QDF_STATUS_SUCCESS != hstatus) { + sme_err("Neighbor scan process complete failed with status %d", + hstatus); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + + +/** + * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request + * @mac_ctx Pointer to mac context + * @msg message sent to HDD + * + * This function is called by CSR as soon as it gets a handoff request + * to SME via MC thread + * + * Return: status + */ +QDF_STATUS csr_neighbor_roam_handoff_req_hdlr( + tpAniSirGlobal mac_ctx, void *msg) +{ + tAniHandoffReq *handoff_req = (tAniHandoffReq *) msg; + uint32_t session_id = handoff_req->sessionId; + tpCsrNeighborRoamControlInfo roam_ctrl_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* we must be in connected state, if not ignore it */ + if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + roam_ctrl_info->neighborRoamState) { + sme_err("Received in not CONNECTED state. Ignore it"); + return QDF_STATUS_E_FAILURE; + } + + /* save the handoff info came from HDD as part of the reassoc req */ + handoff_req = (tAniHandoffReq *) msg; + if (NULL == handoff_req) { + sme_err("Received msg is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* sanity check */ + if (!qdf_mem_cmp(handoff_req->bssid, + roam_ctrl_info->currAPbssid.bytes, + sizeof(tSirMacAddr))) { + sme_err("Received req has same BSSID as current AP!!"); + return QDF_STATUS_E_FAILURE; + } + roam_ctrl_info->handoffReqInfo.channel = + handoff_req->channel; + roam_ctrl_info->handoffReqInfo.src = + handoff_req->handoff_src; + qdf_mem_copy(&roam_ctrl_info->handoffReqInfo.bssid.bytes, + &handoff_req->bssid, QDF_MAC_ADDR_SIZE); + roam_ctrl_info->uOsRequestedHandoff = 1; + status = csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_STOP, + REASON_OS_REQUESTED_ROAMING_NOW); + if (QDF_STATUS_SUCCESS != status) { + sme_err("csr_roam_offload_scan failed"); + roam_ctrl_info->uOsRequestedHandoff = 0; + } + return status; +} + +/** + * csr_neighbor_roam_proceed_with_handoff_req() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function is called by CSR as soon as it gets rsp back for + * ROAM_SCAN_OFFLOAD_STOP with reason REASON_OS_REQUESTED_ROAMING_NOW + * + * Return: QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +QDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + /* we must be in connected state, if not ignore it */ + if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) + || (!pNeighborRoamInfo->uOsRequestedHandoff)) { + sme_err( + "Received in not CONNECTED state(%d) or uOsRequestedHandoff(%d) is not set. Ignore it", + pNeighborRoamInfo->neighborRoamState, + pNeighborRoamInfo->uOsRequestedHandoff); + status = QDF_STATUS_E_FAILURE; + } else + /* Let's go ahead with handoff */ + status = csr_neighbor_roam_process_handoff_req(pMac, sessionId); + + if (!QDF_IS_STATUS_SUCCESS(status)) + pNeighborRoamInfo->uOsRequestedHandoff = 0; + + return status; +} + +/* + * csr_neighbor_roam_start_lfr_scan() - + * This function is called if HDD requested handoff failed for some + * reason. start the LFR logic at that point.By the time, this function is + * called, a STOP command has already been issued. + + * @pMac: The handle returned by mac_open. + * @session_id: Session ID + * + * Return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +QDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + /* There is no candidate or We are not roaming Now. + * Inform the FW to restart Roam Offload Scan + */ + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + + return QDF_STATUS_SUCCESS; + + + +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_roam_preauth.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_roam_preauth.c new file mode 100644 index 0000000000000000000000000000000000000000..de7798f626389342f142f7279422151128924a01 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_roam_preauth.c @@ -0,0 +1,777 @@ +/* + * 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: csr_roam_preauth.c + * + * Host based roaming preauthentication implementation + */ + +#include "wma_types.h" +#include "csr_inside_api.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 "sme_api.h" +#include "csr_neighbor_roam.h" +#include "mac_trace.h" +#include "wlan_policy_mgr_api.h" +#include "sir_api.h" + +static QDF_STATUS csr_neighbor_roam_add_preauth_fail(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirMacAddr bssid); + +/** + * csr_neighbor_roam_state_preauth_done() - Check if state is preauth done + * @mac_ctx: Global MAC context + * @session_id: SME session ID + * + * Return: True if the state id preauth done, false otherwise + */ +bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + return mac_ctx->roam.neighborRoamInfo[session_id].neighborRoamState == + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE; +} + +/** + * csr_neighbor_roam_tranistion_preauth_done_to_disconnected() - Transition + * the state from preauth done to disconnected + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * + * In the event that we are associated with AP1 and we have + * completed pre auth with AP2. Then we receive a deauth/disassoc from AP1. + * At this point neighbor roam is in pre auth done state, pre auth timer + * is running. We now handle this case by stopping timer and clearing + * the pre-auth state. We basically clear up and just go to disconnected + * state + * + * Return: None + */ +void csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &mac_ctx->roam.neighborRoamInfo[session_id]; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("session is NULL")); + return; + } + + if (pNeighborRoamInfo->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE) + return; + + qdf_mc_timer_stop(&session->ftSmeContext.preAuthReassocIntvlTimer); + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_INIT, session_id); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; +} + +/** + * csr_roam_enqueue_preauth() - Put the preauth command in the queue + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * @bss_desc: BSS descriptor + * @reason: roaming reason + * @immediate: High priority in the queue or not + * + * Return: Success if queued properly, false otherwise. + */ +QDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal mac_ctx, + uint32_t session_id, tpSirBssDescription bss_desc, + enum csr_roam_reason reason, bool immediate) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *command; + + command = csr_get_command_buffer(mac_ctx); + if (NULL == command) { + sme_err("fail to get command buffer"); + status = QDF_STATUS_E_RESOURCES; + } else { + if (bss_desc) { + command->command = eSmeCommandRoam; + command->sessionId = (uint8_t) session_id; + command->u.roamCmd.roamReason = reason; + command->u.roamCmd.pLastRoamBss = bss_desc; + status = csr_queue_sme_command(mac_ctx, command, + immediate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("fail to queue preauth,status: %d", + status); + } + } else { + status = QDF_STATUS_E_RESOURCES; + } + } + return status; +} + +/** + * csr_neighbor_roam_purge_preauth_failed_list() - Purge the preauth fail list + * @mac_ctx: Global MAC Context + * + * Return: None + */ +void csr_neighbor_roam_purge_preauth_failed_list(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + uint8_t j; + uint8_t num_mac_addr; + tpCsrNeighborRoamControlInfo neigh_roam_info = NULL; + tpCsrPreauthFailListInfo fail_list; + + for (j = 0; j < CSR_ROAM_SESSION_MAX; j++) { + neigh_roam_info = &mac_ctx->roam.neighborRoamInfo[j]; + fail_list = &neigh_roam_info->FTRoamInfo.preAuthFailList; + num_mac_addr = fail_list->numMACAddress; + for (i = 0; i < num_mac_addr; i++) + qdf_mem_zero(fail_list->macAddress[i], + sizeof(tSirMacAddr)); + fail_list->numMACAddress = 0; + } +} + +/** + * @csr_neighbor_roam_reset_preauth_control_info - Reset preauth info + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * + * Return: None + */ +void csr_neighbor_roam_reset_preauth_control_info(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo neigh_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + + neigh_roam_info->is11rAssoc = false; + csr_neighbor_roam_purge_preauth_failed_list(mac_ctx); + + neigh_roam_info->FTRoamInfo.preauthRspPending = false; + neigh_roam_info->FTRoamInfo.numPreAuthRetries = 0; + neigh_roam_info->FTRoamInfo.currentNeighborRptRetryNum = 0; + neigh_roam_info->FTRoamInfo.neighborRptPending = false; + neigh_roam_info->FTRoamInfo.numBssFromNeighborReport = 0; + qdf_mem_zero(neigh_roam_info->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + neigh_roam_info->uOsRequestedHandoff = 0; + qdf_mem_zero(&neigh_roam_info->handoffReqInfo, + sizeof(tCsrHandoffRequest)); +} + +/** + * csr_neighbor_roam_preauth_rsp_handler() - handle preauth response + * @mac_ctx: The handle returned by mac_open. + * @session_id: SME session + * @lim_status: QDF_STATUS_SUCCESS/QDF_STATUS_E_FAILURE/QDF_STATUS_E_NOSPC/ + * eSIT_LIM_AUTH_RSP_TIMEOUT status from PE + * + * This function handle the Preauth response from PE + * Every preauth is allowed max 3 tries if it fails. If a bssid failed + * for more than MAX_TRIES, we will remove it from the list and try + * with the next node in the roamable AP list and add the BSSID to + * pre-auth failed list. If no more entries present in roamable AP list, + * transition to REPORT_SCAN state. + * + * Return: QDF_STATUS_SUCCESS on success (i.e. pre-auth processed), + * QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_preauth_rsp_handler(tpAniSirGlobal mac_ctx, + uint8_t session_id, + QDF_STATUS lim_status) +{ + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS preauth_processed = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamBSSInfo preauth_rsp_node = NULL; + + if (false == neighbor_roam_info->FTRoamInfo.preauthRspPending) { + /* + * This can happen when we disconnect immediately + * after sending a pre-auth request. During processing + * of the disconnect command, we would have reset + * preauthRspPending and transitioned to INIT state. + */ + sme_warn("Unexpected pre-auth response in state %d", + neighbor_roam_info->neighborRoamState); + preauth_processed = QDF_STATUS_E_FAILURE; + goto DEQ_PREAUTH; + } + /* We can receive it in these 2 states. */ + if ((neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING)) { + sme_debug("Preauth response received in state %s", + mac_trace_get_neighbour_roam_state + (neighbor_roam_info->neighborRoamState)); + preauth_processed = QDF_STATUS_E_FAILURE; + goto DEQ_PREAUTH; + } + + neighbor_roam_info->FTRoamInfo.preauthRspPending = false; + + if (QDF_STATUS_SUCCESS == lim_status) + preauth_rsp_node = + csr_neighbor_roam_next_roamable_ap( + mac_ctx, &neighbor_roam_info->roamableAPList, + NULL); + if ((QDF_STATUS_SUCCESS == lim_status) && (NULL != preauth_rsp_node)) { + sme_debug("Preauth completed successfully after %d tries", + neighbor_roam_info->FTRoamInfo.numPreAuthRetries); + sme_debug("After Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d", + MAC_ADDR_ARRAY( + preauth_rsp_node->pBssDescription->bssId), + (int)preauth_rsp_node->pBssDescription->channelId); + + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + preauth_rsp_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_STATUS_SUCCESS); + /* + * Preauth completed successfully. Insert the preauthenticated + * node to tail of preAuthDoneList. + */ + csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx, + &neighbor_roam_info->roamableAPList, + preauth_rsp_node); + csr_ll_insert_tail( + &neighbor_roam_info->FTRoamInfo.preAuthDoneList, + &preauth_rsp_node->List, LL_ACCESS_LOCK); + + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, session_id); + neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0; + + /* + * The caller of this function would start a timer and by + * the time it expires, supplicant should have provided + * the updated FTIEs to SME. So, when it expires, handoff + * will be triggered then. + */ + } else { + tpCsrNeighborRoamBSSInfo neighbor_bss_node = NULL; + tListElem *entry; + bool is_dis_pending = false; + + sme_err("Preauth failed retry number %d, status: 0x%x", + neighbor_roam_info->FTRoamInfo.numPreAuthRetries, + lim_status); + + /* + * Preauth failed. Add the bssId to the preAuth failed list + * of MAC Address. Also remove the AP from roamable AP list. + */ + if ((neighbor_roam_info->FTRoamInfo.numPreAuthRetries >= + CSR_NEIGHBOR_ROAM_MAX_NUM_PREAUTH_RETRIES) || + (QDF_STATUS_E_NOSPC == lim_status)) { + /* + * We are going to remove the node as it fails for + * more than MAX tries. Reset this count to 0 + */ + neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0; + + /* + * The one in the head of the list should be one with + * which we issued pre-auth and failed + */ + entry = csr_ll_remove_head( + &neighbor_roam_info->roamableAPList, + LL_ACCESS_LOCK); + if (!entry) { + sme_err("Preauth list is empty"); + goto NEXT_PREAUTH; + } + neighbor_bss_node = GET_BASE_ADDR(entry, + tCsrNeighborRoamBSSInfo, + List); + /* + * Add the BSSID to pre-auth fail list if + * it is not requested by HDD + */ + if (!neighbor_roam_info->uOsRequestedHandoff) + status = + csr_neighbor_roam_add_preauth_fail( + mac_ctx, session_id, + neighbor_bss_node-> + pBssDescription->bssId); + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, + session_id, + neighbor_bss_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_STATUS_FAILURE); + /* Now we can free this node */ + csr_neighbor_roam_free_neighbor_roam_bss_node( + mac_ctx, neighbor_bss_node); + } +NEXT_PREAUTH: + is_dis_pending = is_disconnect_pending(mac_ctx, session_id); + if (is_dis_pending) { + sme_err("Disconnect in progress, Abort preauth"); + goto ABORT_PREAUTH; + } + /* Issue preauth request for the same/next entry */ + if (QDF_STATUS_SUCCESS == csr_neighbor_roam_issue_preauth_req( + mac_ctx, session_id)) + goto DEQ_PREAUTH; +ABORT_PREAUTH: + if (csr_roam_is_roam_offload_scan_enabled(mac_ctx)) { + if (neighbor_roam_info->uOsRequestedHandoff) { + neighbor_roam_info->uOsRequestedHandoff = 0; + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_START, + REASON_PREAUTH_FAILED_FOR_ALL); + } else { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_RESTART, + REASON_PREAUTH_FAILED_FOR_ALL); + } + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, session_id); + } + } + +DEQ_PREAUTH: + csr_dequeue_roam_command(mac_ctx, eCsrPerformPreauth, session_id); + return preauth_processed; +} + +/** + * csr_neighbor_roam_add_preauth_fail() - add bssid to preauth failed list + * @mac_ctx: The handle returned by mac_open. + * @bssid: BSSID to be added to the preauth fail list + * + * This function adds the given BSSID to the Preauth fail list + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +static QDF_STATUS csr_neighbor_roam_add_preauth_fail(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirMacAddr bssid) +{ + uint8_t i = 0; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + uint8_t num_mac_addr = neighbor_roam_info->FTRoamInfo.preAuthFailList. + numMACAddress; + + sme_warn("Added BSSID " MAC_ADDRESS_STR " to Preauth failed list", + MAC_ADDR_ARRAY(bssid)); + + for (i = 0; + i < neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress; + i++) { + if (!qdf_mem_cmp( + neighbor_roam_info->FTRoamInfo.preAuthFailList.macAddress[i], + bssid, sizeof(tSirMacAddr))) { + sme_warn("BSSID "MAC_ADDRESS_STR" already fail list", + MAC_ADDR_ARRAY(bssid)); + return QDF_STATUS_SUCCESS; + } + } + + if ((num_mac_addr + 1) > MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS) { + sme_err("Cannot add, preauth fail list is full"); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(neighbor_roam_info->FTRoamInfo.preAuthFailList. + macAddress[num_mac_addr], bssid, sizeof(tSirMacAddr)); + neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress++; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_is_preauth_candidate() + * + * @mac_ctx: Pointer to Global MAC structure + * @bssId : BSSID of the candidate + * + * This function checks whether the given MAC address is already present + * in the preauth fail list and returns true/false accordingly + * + * Return: true if preauth candidate, false otherwise + */ +bool csr_neighbor_roam_is_preauth_candidate(tpAniSirGlobal pMac, + uint8_t sessionId, tSirMacAddr bssId) +{ + uint8_t i = 0; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (csr_roam_is_roam_offload_scan_enabled(pMac)) + return true; + if (0 == pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress) + return true; + + for (i = 0; + i < pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress; + i++) { + if (!qdf_mem_cmp(pNeighborRoamInfo->FTRoamInfo. + preAuthFailList.macAddress[i], bssId, + sizeof(tSirMacAddr))) { + sme_err("BSSID exists in fail list" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId)); + return false; + } + } + + return true; +} + +/** + * csr_get_dot11_mode() - Derives dot11mode + * @mac_ctx: Global MAC context + * @session_id: SME Session ID + * @bss_desc: BSS descriptor + * + * Return: dot11mode + */ +static uint32_t csr_get_dot11_mode(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tpSirBssDescription bss_desc) +{ + struct csr_roam_session *csr_session = CSR_GET_SESSION(mac_ctx, + session_id); + enum csr_cfgdot11mode ucfg_dot11_mode, cfg_dot11_mode; + QDF_STATUS status; + tDot11fBeaconIEs *ies_local = NULL; + uint32_t dot11mode = 0; + + if (!csr_session) { + sme_err("Invalid session id %d", session_id); + return 0; + } + + sme_debug("phyMode %d", csr_session->pCurRoamProfile->phyMode); + + /* Get IE's */ + status = csr_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ies_local); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("csr_get_parsed_bss_description_ies failed"); + return 0; + } + if (ies_local == NULL) { + sme_err("ies_local is NULL"); + return 0; + } + + if (csr_is_phy_mode_match(mac_ctx, + csr_session->pCurRoamProfile->phyMode, + bss_desc, csr_session->pCurRoamProfile, + &cfg_dot11_mode, ies_local)) + ucfg_dot11_mode = cfg_dot11_mode; + else { + sme_err("Can not find match phy mode"); + if (WLAN_REG_IS_5GHZ_CH(bss_desc->channelId)) + ucfg_dot11_mode = eCSR_CFG_DOT11_MODE_11A; + else + ucfg_dot11_mode = eCSR_CFG_DOT11_MODE_11G; + } + + /* dot11mode */ + dot11mode = csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + ucfg_dot11_mode); + sme_debug("dot11mode %d ucfg_dot11_mode %d", + dot11mode, ucfg_dot11_mode); + + if (bss_desc->channelId <= 14 && + false == mac_ctx->roam.configParam.enableVhtFor24GHz && + WNI_CFG_DOT11_MODE_11AC == dot11mode) { + /* Need to disable VHT operation in 2.4 GHz band */ + dot11mode = WNI_CFG_DOT11_MODE_11N; + } + qdf_mem_free(ies_local); + return dot11mode; +} + +QDF_STATUS csr_roam_issue_ft_preauth_req(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tpSirBssDescription bss_desc) +{ + tpSirFTPreAuthReq preauth_req; + uint16_t auth_req_len = 0; + struct csr_roam_session *csr_session = CSR_GET_SESSION(mac_ctx, + session_id); + + if (NULL == csr_session) { + sme_err("Session does not exist for session id: %d", + session_id); + return QDF_STATUS_E_FAILURE; + } + + auth_req_len = sizeof(tSirFTPreAuthReq); + preauth_req = (tpSirFTPreAuthReq) qdf_mem_malloc(auth_req_len); + if (NULL == preauth_req) { + sme_err("Memory allocation for FT Preauth request failed"); + return QDF_STATUS_E_NOMEM; + } + /* Save the SME Session ID. We need it while processing preauth resp */ + csr_session->ftSmeContext.smeSessionId = session_id; + + preauth_req->pbssDescription = + (tpSirBssDescription) qdf_mem_malloc(sizeof(bss_desc->length) + + bss_desc->length); + if (NULL == preauth_req->pbssDescription) { + sme_err("Memory allocation for FT Preauth request failed"); + qdf_mem_free(preauth_req); + return QDF_STATUS_E_NOMEM; + } + + preauth_req->messageType = eWNI_SME_FT_PRE_AUTH_REQ; + + preauth_req->preAuthchannelNum = bss_desc->channelId; + preauth_req->dot11mode = csr_get_dot11_mode(mac_ctx, session_id, + bss_desc); + if (!preauth_req->dot11mode) { + sme_err("preauth_req->dot11mode is zero"); + qdf_mem_free(preauth_req); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy((void *)&preauth_req->currbssId, + (void *)csr_session->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + qdf_mem_copy((void *)&preauth_req->preAuthbssId, + (void *)bss_desc->bssId, sizeof(tSirMacAddr)); + qdf_mem_copy((void *)&preauth_req->self_mac_addr, + (void *)&csr_session->selfMacAddr.bytes, sizeof(tSirMacAddr)); + + if (csr_roam_is11r_assoc(mac_ctx, session_id) && + (mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType != + eCSR_AUTH_TYPE_OPEN_SYSTEM)) { + preauth_req->ft_ies_length = + (uint16_t) csr_session->ftSmeContext.auth_ft_ies_length; + qdf_mem_copy(preauth_req->ft_ies, + csr_session->ftSmeContext.auth_ft_ies, + csr_session->ftSmeContext.auth_ft_ies_length); + } else { + preauth_req->ft_ies_length = 0; + } + qdf_mem_copy(preauth_req->pbssDescription, bss_desc, + sizeof(bss_desc->length) + bss_desc->length); + preauth_req->length = auth_req_len; + return umac_send_mb_message_to_mac(preauth_req); +} + +void csr_roam_ft_pre_auth_rsp_processor(tpAniSirGlobal mac_ctx, + tpSirFTPreAuthRsp preauth_rsp) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info roam_info; + eCsrAuthType conn_Auth_type; + uint32_t session_id = preauth_rsp->smeSessionId; + struct csr_roam_session *csr_session = CSR_GET_SESSION(mac_ctx, + session_id); + tDot11fAuthentication *p_auth = NULL; + + if (NULL == csr_session) { + sme_err("CSR session is NULL"); + return; + } + status = csr_neighbor_roam_preauth_rsp_handler(mac_ctx, + preauth_rsp->smeSessionId, preauth_rsp->status); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Preauth was not processed: %d SessionID: %d", + status, session_id); + return; + } + + if (QDF_STATUS_SUCCESS != (QDF_STATUS) preauth_rsp->status) + return; + csr_session->ftSmeContext.FTState = eFT_AUTH_COMPLETE; + csr_session->ftSmeContext.psavedFTPreAuthRsp = preauth_rsp; + /* No need to notify qos module if this is a non 11r & ESE roam */ + if (csr_roam_is11r_assoc(mac_ctx, preauth_rsp->smeSessionId) +#ifdef FEATURE_WLAN_ESE + || csr_roam_is_ese_assoc(mac_ctx, preauth_rsp->smeSessionId) +#endif + ) { + sme_qos_csr_event_ind(mac_ctx, + csr_session->ftSmeContext.smeSessionId, + SME_QOS_CSR_PREAUTH_SUCCESS_IND, NULL); + } + status = + qdf_mc_timer_start( + &csr_session->ftSmeContext.preAuthReassocIntvlTimer, + 60); + if (QDF_STATUS_SUCCESS != status) { + sme_err("PreauthReassocInterval timer failed status %d", + status); + return; + } + qdf_mem_copy((void *)&csr_session->ftSmeContext.preAuthbssId, + (void *)preauth_rsp->preAuthbssId, + sizeof(struct qdf_mac_addr)); + if (csr_roam_is11r_assoc(mac_ctx, preauth_rsp->smeSessionId)) + csr_roam_call_callback(mac_ctx, preauth_rsp->smeSessionId, + NULL, 0, eCSR_ROAM_FT_RESPONSE, eCSR_ROAM_RESULT_NONE); + +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, preauth_rsp->smeSessionId)) { + csr_roam_read_tsf(mac_ctx, (uint8_t *) roam_info.timestamp, + preauth_rsp->smeSessionId); + qdf_mem_copy((void *)&roam_info.bssid, + (void *)preauth_rsp->preAuthbssId, + sizeof(struct qdf_mac_addr)); + csr_roam_call_callback(mac_ctx, preauth_rsp->smeSessionId, + &roam_info, 0, eCSR_ROAM_CCKM_PREAUTH_NOTIFY, + 0); + } +#endif + + if (csr_roam_is_fast_roam_enabled(mac_ctx, preauth_rsp->smeSessionId)) { + /* Save the bssid from the received response */ + qdf_mem_copy((void *)&roam_info.bssid, + (void *)preauth_rsp->preAuthbssId, + sizeof(struct qdf_mac_addr)); + csr_roam_call_callback(mac_ctx, preauth_rsp->smeSessionId, + &roam_info, 0, eCSR_ROAM_PMK_NOTIFY, 0); + } + + /* If its an Open Auth, FT IEs are not provided by supplicant */ + /* Hence populate them here */ + conn_Auth_type = + mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType; + + csr_session->ftSmeContext.addMDIE = false; + + /* Done with it, init it. */ + csr_session->ftSmeContext.psavedFTPreAuthRsp = NULL; + + if (csr_roam_is11r_assoc(mac_ctx, preauth_rsp->smeSessionId) && + (conn_Auth_type == eCSR_AUTH_TYPE_OPEN_SYSTEM)) { + uint16_t ft_ies_length; + + ft_ies_length = preauth_rsp->ric_ies_length; + + if ((csr_session->ftSmeContext.reassoc_ft_ies) && + (csr_session->ftSmeContext.reassoc_ft_ies_length)) { + qdf_mem_free(csr_session->ftSmeContext.reassoc_ft_ies); + csr_session->ftSmeContext.reassoc_ft_ies_length = 0; + csr_session->ftSmeContext.reassoc_ft_ies = NULL; + } + p_auth = (tDot11fAuthentication *) qdf_mem_malloc( + sizeof(tDot11fAuthentication)); + + if (p_auth == NULL) + return; + + status = dot11f_unpack_authentication(mac_ctx, + preauth_rsp->ft_ies, + preauth_rsp->ft_ies_length, p_auth, false); + if (DOT11F_FAILED(status)) + sme_err("Failed to parse an Authentication frame"); + else if (p_auth->MobilityDomain.present) + csr_session->ftSmeContext.addMDIE = true; + + qdf_mem_free(p_auth); + + if (!ft_ies_length) + return; + + csr_session->ftSmeContext.reassoc_ft_ies = + qdf_mem_malloc(ft_ies_length); + if (NULL == csr_session->ftSmeContext.reassoc_ft_ies) { + sme_err("Memory allocation failed for ft_ies"); + return; + } + /* Copy the RIC IEs to reassoc IEs */ + qdf_mem_copy(((uint8_t *) csr_session->ftSmeContext. + reassoc_ft_ies), + (uint8_t *) preauth_rsp->ric_ies, + preauth_rsp->ric_ies_length); + csr_session->ftSmeContext.reassoc_ft_ies_length = ft_ies_length; + csr_session->ftSmeContext.addMDIE = true; + } +} + +/** + * csr_neighbor_roam_issue_preauth_req() - Send preauth request to first AP + * @mac_ctx: The handle returned by mac_open. + * @session_id: Session information + * + * This function issues preauth request to PE with the 1st AP entry in the + * roamable AP list + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamBSSInfo neighbor_bss_node; + + + if (false != neighbor_roam_info->FTRoamInfo.preauthRspPending) { + /* This must not be true here */ + QDF_ASSERT(neighbor_roam_info->FTRoamInfo.preauthRspPending == + false); + return QDF_STATUS_E_FAILURE; + } + + /* + * Issue Preauth request to PE here. + * Need to issue the preauth request with the BSSID that is in the + * head of the roamable AP list. Parameters that should be passed are + * BSSID, Channel number and the neighborScanPeriod(probably). If + * roamableAPList gets empty, should transition to REPORT_SCAN state + */ + neighbor_bss_node = csr_neighbor_roam_next_roamable_ap(mac_ctx, + &neighbor_roam_info->roamableAPList, NULL); + + if (NULL == neighbor_bss_node) { + sme_err("Roamable AP list is empty"); + return QDF_STATUS_E_FAILURE; + } + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + neighbor_bss_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_INIT_NOTIFY); + status = csr_roam_enqueue_preauth(mac_ctx, session_id, + neighbor_bss_node->pBssDescription, + eCsrPerformPreauth, true); + + sme_debug("Before Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d", + MAC_ADDR_ARRAY( + neighbor_bss_node->pBssDescription->bssId), + (int)neighbor_bss_node->pBssDescription->channelId); + + if (QDF_STATUS_SUCCESS != status) { + sme_err("Return failed preauth request status %d", + status); + return status; + } + + neighbor_roam_info->FTRoamInfo.preauthRspPending = true; + neighbor_roam_info->FTRoamInfo.numPreAuthRetries++; + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING, session_id); + + return status; +} + diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_util.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_util.c new file mode 100644 index 0000000000000000000000000000000000000000..44a67c9045fce6243e34a206da23b590f175487a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_util.c @@ -0,0 +1,6444 @@ +/* + * 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: 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" + + +uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE] = { + {0x00, 0x50, 0xf2, 0x00} + , + {0x00, 0x50, 0xf2, 0x01} + , + {0x00, 0x50, 0xf2, 0x02} + , + {0x00, 0x50, 0xf2, 0x03} + , + {0x00, 0x50, 0xf2, 0x04} + , + {0x00, 0x50, 0xf2, 0x05} + , +#ifdef FEATURE_WLAN_ESE + {0x00, 0x40, 0x96, 0x00} + , /* CCKM */ +#endif /* FEATURE_WLAN_ESE */ +}; + +/* + * PLEASE DO NOT ADD THE #IFDEF IN BELOW TABLE, + * IF STILL REQUIRE THEN PLEASE ADD NULL ENTRIES + * OTHERWISE IT WILL BREAK OTHER LOWER + * SECUIRTY MODES. + */ + +uint8_t csr_rsn_oui[][CSR_RSN_OUI_SIZE] = { + {0x00, 0x0F, 0xAC, 0x00} + , /* group cipher */ + {0x00, 0x0F, 0xAC, 0x01} + , /* WEP-40 or RSN */ + {0x00, 0x0F, 0xAC, 0x02} + , /* TKIP or RSN-PSK */ + {0x00, 0x0F, 0xAC, 0x03} + , /* Reserved */ + {0x00, 0x0F, 0xAC, 0x04} + , /* AES-CCMP */ + {0x00, 0x0F, 0xAC, 0x05} + , /* WEP-104 */ + {0x00, 0x40, 0x96, 0x00} + , /* CCKM */ + {0x00, 0x0F, 0xAC, 0x06} + , /* BIP (encryption type) or + * RSN-PSK-SHA256 (authentication type) + */ + /* RSN-8021X-SHA256 (authentication type) */ + {0x00, 0x0F, 0xAC, 0x05}, +#ifdef WLAN_FEATURE_FILS_SK +#define ENUM_FILS_SHA256 9 + /* FILS SHA256 */ + {0x00, 0x0F, 0xAC, 0x0E}, +#define ENUM_FILS_SHA384 10 + /* FILS SHA384 */ + {0x00, 0x0F, 0xAC, 0x0F}, +#define ENUM_FT_FILS_SHA256 11 + /* FILS FT SHA256 */ + {0x00, 0x0F, 0xAC, 0x10}, +#define ENUM_FT_FILS_SHA384 12 + /* FILS FT SHA384 */ + {0x00, 0x0F, 0xAC, 0x11}, +#else + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, +#endif + /* AES GCMP */ + {0x00, 0x0F, 0xAC, 0x08}, + /* AES GCMP-256 */ + {0x00, 0x0F, 0xAC, 0x09}, +#define ENUM_DPP_RSN 15 + /* DPP RSN */ + {0x50, 0x6F, 0x9A, 0x02}, +#define ENUM_OWE 16 + /* OWE https://tools.ietf.org/html/rfc8110 */ + {0x00, 0x0F, 0xAC, 0x12}, +#define ENUM_SUITEB_EAP256 17 + {0x00, 0x0F, 0xAC, 0x0B}, +#define ENUM_SUITEB_EAP384 18 + {0x00, 0x0F, 0xAC, 0x0C}, + +#ifdef WLAN_FEATURE_SAE +#define ENUM_SAE 19 + /* SAE */ + {0x00, 0x0F, 0xAC, 0x08}, +#define ENUM_FT_SAE 20 + /* FT SAE */ + {0x00, 0x0F, 0xAC, 0x09}, +#else + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, +#endif + + /* define new oui here, update #define CSR_OUI_***_INDEX */ +}; + +#ifdef FEATURE_WLAN_WAPI +uint8_t csr_wapi_oui[][CSR_WAPI_OUI_SIZE] = { + {0x00, 0x14, 0x72, 0x00} + , /* Reserved */ + {0x00, 0x14, 0x72, 0x01} + , /* WAI certificate or SMS4 */ + {0x00, 0x14, 0x72, 0x02} /* WAI PSK */ +}; +#endif /* FEATURE_WLAN_WAPI */ +uint8_t csr_wme_info_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; +uint8_t csr_wme_parm_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; + +uint8_t csr_group_mgmt_oui[][CSR_RSN_OUI_SIZE] = { +#define ENUM_CMAC 0 + {0x00, 0x0F, 0xAC, 0x06}, +#define ENUM_GMAC_128 1 + {0x00, 0x0F, 0xAC, 0x0B}, +#define ENUM_GMAC_256 2 + {0x00, 0x0F, 0xAC, 0x0C}, +}; + + +/* ////////////////////////////////////////////////////////////////////// */ + +/** + * \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 */ + +}; + +#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_CANCELLED); + CASE_RETURN_STR(eCSR_ROAM_FAILED); + CASE_RETURN_STR(eCSR_ROAM_ROAMING_START); + CASE_RETURN_STR(eCSR_ROAM_ROAMING_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_CONNECT_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_START); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_DISASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_SHOULD_ROAM); + CASE_RETURN_STR(eCSR_ROAM_SCAN_FOUND_NEW_BSS); + CASE_RETURN_STR(eCSR_ROAM_LOSTLINK); + CASE_RETURN_STR(eCSR_ROAM_LOSTLINK_DETECTED); + CASE_RETURN_STR(eCSR_ROAM_MIC_ERROR_IND); + CASE_RETURN_STR(eCSR_ROAM_IBSS_IND); + CASE_RETURN_STR(eCSR_ROAM_CONNECT_STATUS_UPDATE); + CASE_RETURN_STR(eCSR_ROAM_GEN_INFO); + CASE_RETURN_STR(eCSR_ROAM_SET_KEY_COMPLETE); + CASE_RETURN_STR(eCSR_ROAM_IBSS_LEAVE); + CASE_RETURN_STR(eCSR_ROAM_INFRA_IND); + CASE_RETURN_STR(eCSR_ROAM_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STR(eCSR_ROAM_FT_RESPONSE); + CASE_RETURN_STR(eCSR_ROAM_FT_START); + CASE_RETURN_STR(eCSR_ROAM_SESSION_OPENED); + CASE_RETURN_STR(eCSR_ROAM_FT_REASSOC_FAILED); + CASE_RETURN_STR(eCSR_ROAM_PMK_NOTIFY); +#ifdef FEATURE_WLAN_LFR_METRICS + CASE_RETURN_STR(eCSR_ROAM_PREAUTH_INIT_NOTIFY); + CASE_RETURN_STR(eCSR_ROAM_PREAUTH_STATUS_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_PREAUTH_STATUS_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_HANDOVER_SUCCESS); +#endif +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STR(eCSR_ROAM_TDLS_STATUS_UPDATE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND); +#endif + CASE_RETURN_STR(eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS); + CASE_RETURN_STR(eCSR_ROAM_SEND_P2P_STOP_BSS); +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STR(eCSR_ROAM_UNPROT_MGMT_FRAME_IND); +#endif +#ifdef WLAN_FEATURE_RMC + CASE_RETURN_STR(eCSR_ROAM_IBSS_PEER_INFO_COMPLETE); +#endif +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STR(eCSR_ROAM_TSM_IE_IND); + CASE_RETURN_STR(eCSR_ROAM_CCKM_PREAUTH_NOTIFY); + 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_UPDATE_SCAN_RESULT); + CASE_RETURN_STR(eCSR_ROAM_START); + CASE_RETURN_STR(eCSR_ROAM_ABORT); + CASE_RETURN_STR(eCSR_ROAM_NAPI_OFF); + CASE_RETURN_STR(eCSR_ROAM_CHANNEL_COMPLETE_IND); + CASE_RETURN_STR(eCSR_ROAM_SAE_COMPUTE); + 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_IBSS_STARTED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_START_FAILED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_JOIN_FAILED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_CONNECT); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_INACTIVE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_NEW_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_COALESCED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_STOP); + 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_IBSS_PEER_INFO_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_PEER_INFO_FAILED); + 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_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"; + default: + return "unknown"; + } +} + +void csr_purge_vdev_pending_ser_cmd_list(struct sAniSirGlobal *mac_ctx, + uint32_t vdev_id) +{ + wlan_serialization_purge_cmd_list_by_vdev_id(mac_ctx->psoc, vdev_id, + false, true, false, + true, false); +} + +void csr_purge_vdev_all_ser_cmd_list(struct sAniSirGlobal *mac_ctx, + uint32_t vdev_id) +{ + wlan_serialization_purge_cmd_list_by_vdev_id(mac_ctx->psoc, vdev_id, + true, true, true, + true, true); +} + +void csr_purge_pdev_all_ser_cmd_list(struct sAniSirGlobal *mac_ctx) +{ + wlan_serialization_purge_cmd_list(mac_ctx->psoc, NULL, true, true, + true, true, true); +} + +void csr_nonscan_active_ll_insert_head(struct sAniSirGlobal *mac_ctx, + tListElem *entry, bool inter_locked) +{ +} + +void csr_nonscan_pending_ll_insert_head(struct sAniSirGlobal *mac_ctx, + tListElem *entry, bool inter_locked) +{ +} + +void csr_nonscan_pending_ll_insert_tail(struct sAniSirGlobal *mac_ctx, + tListElem *entry, bool inter_locked) +{ +} + +void csr_nonscan_pending_ll_unlock(struct sAniSirGlobal *mac_ctx) +{ +} + +void csr_nonscan_active_ll_unlock(struct sAniSirGlobal *mac_ctx) +{ +} + +void csr_nonscan_pending_ll_lock(struct sAniSirGlobal *mac_ctx) +{ +} + +void csr_nonscan_active_ll_lock(struct sAniSirGlobal *mac_ctx) +{ +} + +uint32_t csr_nonscan_active_ll_count(struct sAniSirGlobal *mac_ctx) +{ + return wlan_serialization_get_active_list_count(mac_ctx->psoc, false); +} + +uint32_t csr_nonscan_pending_ll_count(struct sAniSirGlobal *mac_ctx) +{ + return wlan_serialization_get_pending_list_count(mac_ctx->psoc, false); +} + +bool csr_nonscan_active_ll_is_list_empty(struct sAniSirGlobal *mac_ctx, + bool inter_locked) +{ + return !wlan_serialization_get_active_list_count(mac_ctx->psoc, false); +} +bool csr_nonscan_pending_ll_is_list_empty(struct sAniSirGlobal *mac_ctx, + bool inter_locked) +{ + return !wlan_serialization_get_pending_list_count(mac_ctx->psoc, false); +} + +tListElem *csr_nonscan_active_ll_peek_head(struct sAniSirGlobal *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) { + sme_err("No cmd found"); + return NULL; + } + sme_cmd = cmd->umac_cmd; + + return &sme_cmd->Link; +} + +tListElem *csr_nonscan_pending_ll_peek_head(struct sAniSirGlobal *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); + if (!cmd) + return NULL; + + sme_cmd = cmd->umac_cmd; + + return &sme_cmd->Link; +} + +bool csr_nonscan_active_ll_remove_entry(struct sAniSirGlobal *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_active_ll_remove_head(struct sAniSirGlobal *mac_ctx, + bool inter_locked) +{ + return csr_nonscan_active_ll_peek_head(mac_ctx, inter_locked); +} + +tListElem *csr_nonscan_pending_ll_remove_head(struct sAniSirGlobal *mac_ctx, + bool inter_locked) +{ + return csr_nonscan_pending_ll_peek_head(mac_ctx, inter_locked); +} + +tListElem *csr_nonscan_pending_ll_next(struct sAniSirGlobal *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->sessionId, 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); + if (!tcmd) { + sme_err("No cmd found"); + return NULL; + } + sme_cmd = tcmd->umac_cmd; + return &sme_cmd->Link; +} + +bool csr_get_bss_id_bss_desc(tSirBssDescription *pSirBssDesc, + struct qdf_mac_addr *pBssId) +{ + qdf_mem_copy(pBssId, &pSirBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + return true; +} + +bool csr_is_bss_id_equal(tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2) +{ + bool fEqual = false; + struct qdf_mac_addr bssId1; + struct qdf_mac_addr bssId2; + + do { + if (!pSirBssDesc1) + break; + if (!pSirBssDesc2) + break; + + if (!csr_get_bss_id_bss_desc(pSirBssDesc1, &bssId1)) + break; + if (!csr_get_bss_id_bss_desc(pSirBssDesc2, &bssId2)) + break; + + fEqual = qdf_is_macaddr_equal(&bssId1, &bssId2); + } while (0); + + return fEqual; +} + +static bool csr_is_conn_state(tpAniSirGlobal mac_ctx, uint32_t session_id, + eCsrConnectState state) +{ + QDF_BUG(session_id < CSR_ROAM_SESSION_MAX); + if (session_id >= CSR_ROAM_SESSION_MAX) + return false; + + return mac_ctx->roam.roamSession[session_id].connectState == state; +} + +bool csr_is_conn_state_connected_ibss(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + return csr_is_conn_state(mac_ctx, session_id, + eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED); +} + +bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + return csr_is_conn_state(mac_ctx, session_id, + eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED); +} + +bool csr_is_conn_state_connected_infra(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + return csr_is_conn_state(mac_ctx, session_id, + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED); +} + +bool csr_is_conn_state_connected(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_ibss(pMac, sessionId) || + csr_is_conn_state_connected_infra(pMac, sessionId) || + csr_is_conn_state_connected_wds(pMac, sessionId); +} + +bool csr_is_conn_state_infra(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_infra(pMac, sessionId); +} + +bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_ibss(pMac, sessionId) || + csr_is_conn_state_disconnected_ibss(pMac, sessionId); +} + +bool csr_is_conn_state_connected_wds(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal 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(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_wds(pMac, sessionId) || + csr_is_conn_state_disconnected_wds(pMac, sessionId); +} + +static bool csr_is_conn_state_ap(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession; + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) + return false; + if (CSR_IS_INFRA_AP(&pSession->connectedProfile)) + return true; + return false; +} + +bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) && + (csr_is_conn_state_infra(pMac, i) + || csr_is_conn_state_ibss(pMac, i) + || csr_is_conn_state_ap(pMac, i))) { + fRc = true; + break; + } + } + + return fRc; +} + +int8_t csr_get_infra_session_id(tpAniSirGlobal pMac) +{ + uint8_t i; + int8_t sessionid = -1; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_infra(pMac, i)) { + sessionid = i; + break; + } + } + + return sessionid; +} + +uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, uint8_t sessionId) +{ + uint8_t channel; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + channel = + pMac->roam.roamSession[sessionId].connectedProfile. + operationChannel; + } else { + channel = 0; + } + return channel; +} + +bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, uint8_t sessionId) +{ + struct csr_roam_session *pSession = NULL; + + if (CSR_IS_SESSION_VALID(pMac, sessionId) + && csr_is_conn_state_infra(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession->pCurRoamProfile) { + if ((pSession->pCurRoamProfile->csrPersona == + QDF_STA_MODE) + || (pSession->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE)) + return true; + } + } + return false; +} + +uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal mac_ctx) +{ + struct csr_roam_session *session = NULL; + uint8_t i = 0; + enum QDF_OPMODE persona; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + session = CSR_GET_SESSION(mac_ctx, i); + if (NULL == session->pCurRoamProfile) + continue; + persona = session->pCurRoamProfile->csrPersona; + if ((((persona == QDF_STA_MODE) || + (persona == QDF_P2P_CLIENT_MODE)) && + (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) || + (((persona == QDF_P2P_GO_MODE) || + (persona == QDF_SAP_MODE)) + && (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED))) + return session->connectedProfile.operationChannel; + + } + return 0; +} + +uint8_t csr_get_beaconing_concurrent_channel(tpAniSirGlobal 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 < CSR_ROAM_SESSION_MAX; i++) { + if (i == vdev_id_to_skip) + continue; + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + session = CSR_GET_SESSION(mac_ctx, i); + if (NULL == session->pCurRoamProfile) + continue; + persona = session->pCurRoamProfile->csrPersona; + if (((persona == QDF_P2P_GO_MODE) || + (persona == QDF_SAP_MODE)) && + (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) + return session->connectedProfile.operationChannel; + } + + 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)+2) +#define CSR_GET_HT40_MINUS_CCH(och) ((och)-2) + +#define CSR_GET_HT80_PLUS_LL_CCH(och) ((och)+6) +#define CSR_GET_HT80_PLUS_HL_CCH(och) ((och)+2) +#define CSR_GET_HT80_MINUS_LH_CCH(och) ((och)-2) +#define CSR_GET_HT80_MINUS_HH_CCH(och) ((och)-6) + +/** + * csr_get_ch_from_ht_profile() - to get channel from HT profile + * @pMac: pointer to Mac context + * @htp: pointer to HT profile + * @och: operating channel + * @cfreq: channel frequency + * @hbw: half bandwidth + * + * This function will fill half bandwidth and channel frequency based + * on the HT profile + * + * Return: none + */ +static void csr_get_ch_from_ht_profile(tpAniSirGlobal pMac, + tCsrRoamHTProfile *htp, + uint16_t och, uint16_t *cfreq, + uint16_t *hbw) +{ + uint16_t cch, ch_bond; + + if (och > 14) + ch_bond = pMac->roam.configParam.channelBondingMode5GHz; + else + ch_bond = pMac->roam.configParam.channelBondingMode24GHz; + + cch = och; + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + if (!ch_bond) + goto ret; + + sme_debug("HTC: %d scbw: %d rcbw: %d sco: %d VHTC: %d apc: %d apbw: %d", + htp->htCapability, htp->htSupportedChannelWidthSet, + htp->htRecommendedTxWidthSet, + htp->htSecondaryChannelOffset, + htp->vhtCapability, htp->apCenterChan, htp->apChanWidth + ); + + if (htp->vhtCapability) { + cch = htp->apCenterChan; + if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + *hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL); + else if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + *hbw = HALF_BW_OF(eCSR_BW_160MHz_VAL); + + if (!*hbw && htp->htCapability) { + if (htp->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) + *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + else + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + } + } else if (htp->htCapability) { + if (htp->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) { + *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (htp->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + cch = CSR_GET_HT40_PLUS_CCH(och); + else if (htp->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + cch = CSR_GET_HT40_MINUS_CCH(och); + } else { + cch = och; + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + } + } + +ret: + *cfreq = cds_chan_to_freq(cch); +} + +/** + * 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(tpAniSirGlobal mac_ctx, + uint16_t *sap_ch, eCsrPhyMode *sap_phymode, + uint16_t *sap_cch, uint16_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) { + /*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); + } + } +} + +/** + * 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: SAP/GO operating channel + * @sap_hbw: SAP/GO half bw + * @sap_cfreq: SAP/GO channel frequency + * @intf_ch: concurrent SAP/GO operating channel + * @intf_hbw: concurrent SAP/GO half bw + * @intf_cfreq: concurrent SAP/GO channel frequency + * + * 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(tpAniSirGlobal mac_ctx, + struct csr_roam_session *session, + uint16_t *sap_ch, uint16_t *sap_hbw, uint16_t *sap_cfreq, + uint16_t *intf_ch, uint16_t *intf_hbw, uint16_t *intf_cfreq) +{ + /* + * 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 == 0) { + *sap_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *sap_ch, sap_cfreq, sap_hbw); + } else if (*sap_ch != + session->connectedProfile.operationChannel) { + *intf_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *intf_ch, intf_cfreq, intf_hbw); + } + } else if (*sap_ch == 0 && + (session->pCurRoamProfile->csrPersona == + QDF_SAP_MODE)) { + *sap_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *sap_ch, sap_cfreq, sap_hbw); + } +} + + +/** + * csr_check_concurrent_channel_overlap() - To check concurrent overlap chnls + * @mac_ctx: Pointer to mac context + * @sap_ch: SAP channel + * @sap_phymode: SAP phy mode + * @cc_switch_mode: concurrent switch mode + * + * This routine will be called to check concurrent overlap channels + * + * Return: uint16_t + */ +uint16_t csr_check_concurrent_channel_overlap(tpAniSirGlobal mac_ctx, + uint16_t sap_ch, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode) +{ + struct csr_roam_session *session = NULL; + uint8_t i = 0, chb = PHY_SINGLE_CHANNEL_CENTERED; + uint16_t intf_ch = 0, sap_hbw = 0, intf_hbw = 0, intf_cfreq = 0; + uint16_t sap_cfreq = 0; + uint16_t sap_lfreq, sap_hfreq, intf_lfreq, intf_hfreq, sap_cch = 0; + QDF_STATUS status; + + sme_debug("sap_ch: %d sap_phymode: %d", sap_ch, sap_phymode); + + if (mac_ctx->roam.configParam.cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_DISABLE) + return 0; + + if (sap_ch != 0) { + sap_cch = sap_ch; + sap_hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + if (sap_ch > 14) + 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, + &sap_phymode, &sap_cch, &sap_hbw, &chb); + sap_cfreq = cds_chan_to_freq(sap_cch); + } + + sme_debug("sap_ch:%d sap_phymode:%d sap_cch:%d sap_hbw:%d chb:%d", + sap_ch, sap_phymode, sap_cch, sap_hbw, chb); + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + + session = CSR_GET_SESSION(mac_ctx, i); + if (NULL == session->pCurRoamProfile) + continue; + if (((session->pCurRoamProfile->csrPersona == QDF_STA_MODE) || + (session->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE)) && + (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) { + intf_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + intf_ch, &intf_cfreq, &intf_hbw); + sme_debug("%d: intf_ch:%d intf_cfreq:%d intf_hbw:%d", + i, intf_ch, intf_cfreq, intf_hbw); + } else if (((session->pCurRoamProfile->csrPersona == + QDF_P2P_GO_MODE) || + (session->pCurRoamProfile->csrPersona == + 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, &sap_hbw, &sap_cfreq, + &intf_ch, &intf_hbw, &intf_cfreq); + + sme_debug("%d: sap_ch:%d sap_hbw:%d sap_cfreq:%d intf_ch:%d intf_hbw:%d, intf_cfreq:%d", + i, sap_ch, sap_hbw, sap_cfreq, + intf_ch, intf_hbw, intf_cfreq); + } + if (intf_ch && ((intf_ch > 14 && sap_ch > 14) || + (intf_ch <= 14 && sap_ch <= 14))) + break; + } + + sme_debug("intf_ch:%d sap_ch:%d cc_switch_mode:%d, dbs:%d", + intf_ch, sap_ch, cc_switch_mode, + policy_mgr_is_dbs_enable(mac_ctx->psoc)); + + if (intf_ch && sap_ch != intf_ch && + !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_err("SAP: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d INTF: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d", + sap_ch, cds_chan_to_freq(sap_ch), + cds_freq_to_chan(sap_cfreq), sap_cfreq, sap_hbw * 2, + sap_lfreq, sap_hfreq, intf_ch, + cds_chan_to_freq(intf_ch), cds_freq_to_chan(intf_cfreq), + 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 = 0; + } else if (intf_ch && sap_ch != intf_ch && + ((cc_switch_mode == QDF_MCC_TO_SCC_SWITCH_FORCE) || + policy_mgr_is_force_scc(mac_ctx->psoc))) { + if (!((intf_ch <= 14 && sap_ch <= 14) || + (intf_ch > 14 && sap_ch > 14))) { + if (policy_mgr_is_dbs_enable(mac_ctx->psoc) || + cc_switch_mode == + QDF_MCC_TO_SCC_WITH_PREFERRED_BAND) + intf_ch = 0; + } else if (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) { + status = + policy_mgr_get_sap_mandatory_channel( + mac_ctx->psoc, + (uint32_t *)&intf_ch); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("no mandatory channel"); + } + } else if ((intf_ch == sap_ch) && (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL)) { + if (cds_chan_to_band(intf_ch) == CDS_BAND_2GHZ) { + status = + policy_mgr_get_sap_mandatory_channel( + mac_ctx->psoc, (uint32_t *)&intf_ch); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("no mandatory channel"); + } + } + + if (intf_ch == sap_ch) + intf_ch = 0; + + sme_err("##Concurrent Channels %s Interfering", + intf_ch == 0 ? "Not" : "Are"); + return intf_ch; +} +#endif + +bool csr_is_all_session_disconnected(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = true; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) { + fRc = false; + break; + } + } + + return fRc; +} + +/** + * csr_is_sta_session_connected() - to find if concurrent sta is active + * @mac_ctx: pointer to mac context + * + * This function will iterate through each session and check if sta + * session exist and active + * + * Return: true or false + */ +bool csr_is_sta_session_connected(tpAniSirGlobal mac_ctx) +{ + uint32_t i; + struct csr_roam_session *pSession = NULL; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i) && + !csr_is_conn_state_disconnected(mac_ctx, i)) { + pSession = CSR_GET_SESSION(mac_ctx, i); + + if ((NULL != pSession->pCurRoamProfile) && + (QDF_STA_MODE == + pSession->pCurRoamProfile->csrPersona)) + return true; + } + } + + return false; +} + +/** + * csr_is_p2p_session_connected() - to find if any p2p session is active + * @mac_ctx: pointer to mac context + * + * This function will iterate through each session and check if any p2p + * session exist and active + * + * Return: true or false + */ +bool csr_is_p2p_session_connected(tpAniSirGlobal pMac) +{ + uint32_t i; + struct csr_roam_session *pSession = NULL; + enum QDF_OPMODE persona; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(pMac, i)) + continue; + + if (csr_is_conn_state_disconnected(pMac, i)) + continue; + + pSession = CSR_GET_SESSION(pMac, i); + if (pSession->pCurRoamProfile == NULL) + continue; + + persona = pSession->pCurRoamProfile->csrPersona; + if (QDF_P2P_CLIENT_MODE == persona || + QDF_P2P_GO_MODE == persona) + return true; + } + + return false; +} + +bool csr_is_any_session_connected(tpAniSirGlobal pMac) +{ + uint32_t i, count; + bool fRc = false; + + count = 0; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) + count++; + } + + if (count > 0) + fRc = true; + return fRc; +} + +bool csr_is_infra_connected(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_connected_infra(pMac, i)) { + fRc = true; + break; + } + } + + return fRc; +} + +uint8_t csr_get_connected_infra(tpAniSirGlobal mac_ctx) +{ + uint32_t i; + uint8_t connected_session = CSR_SESSION_ID_INVALID; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i) + && csr_is_conn_state_connected_infra(mac_ctx, i)) { + connected_session = i; + break; + } + } + + return connected_session; +} + + +bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac) +{ + uint32_t i, noOfConnectedInfra = 0; + + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_connected_infra(pMac, i)) { + ++noOfConnectedInfra; + } + } + + /* More than one Infra Sta Connected */ + if (noOfConnectedInfra > 1) + fRc = true; + return fRc; +} + +bool csr_is_ibss_started(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_ibss(pMac, i)) { + fRc = true; + break; + } + } + + return fRc; +} + +bool csr_is_concurrent_session_running(tpAniSirGlobal pMac) +{ + uint32_t sessionId, noOfCocurrentSession = 0; + eCsrConnectState connectState; + + bool fRc = false; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + connectState = + pMac->roam.roamSession[sessionId].connectState; + if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED == + connectState) + || (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED == + connectState) + || (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED == + connectState)) { + ++noOfCocurrentSession; + } + } + } + + /* More than one session is Up and Running */ + if (noOfCocurrentSession > 1) + fRc = true; + return fRc; +} + +bool csr_is_infra_ap_started(tpAniSirGlobal pMac) +{ + uint32_t sessionId; + bool fRc = false; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + (csr_is_conn_state_connected_infra_ap(pMac, + sessionId))) { + fRc = true; + break; + } + } + + return fRc; + +} + +bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +/** + * csr_is_valid_mc_concurrent_session() - To check concurren session is valid + * @mac_ctx: pointer to mac context + * @session_id: session id + * @bss_descr: bss description + * + * This function validates the concurrent session + * + * Return: true or false + */ +bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tSirBssDescription *bss_descr) +{ + struct csr_roam_session *pSession = NULL; + + /* Check for MCC support */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return false; + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) + return false; + /* Validate BeaconInterval */ + pSession = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == pSession->pCurRoamProfile) + return false; + if (QDF_STATUS_SUCCESS == csr_validate_mcc_beacon_interval(mac_ctx, + bss_descr->channelId, + &bss_descr->beaconInterval, session_id, + pSession->pCurRoamProfile->csrPersona)) + return true; + return false; +} + +static tSirMacCapabilityInfo csr_get_bss_capabilities(tSirBssDescription * + pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps; + + /* tSirMacCapabilityInfo is 16-bit */ + qdf_get_u16((uint8_t *) &pSirBssDesc->capabilityInfo, + (uint16_t *) &dot11Caps); + + return dot11Caps; +} + +bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.ess; +} + +bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.ibss; +} + +static bool csr_is_qos_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.qos; +} + +bool csr_is_privacy(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.privacy; +} + +bool csr_is11d_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11dSupportEnabled; +} + +bool csr_is11h_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11hSupportEnabled; +} + +bool csr_is11e_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11eSupportEnabled; +} + +bool csr_is_mcc_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.fenableMCCMode; + +} + +bool csr_is_wmm_supported(tpAniSirGlobal pMac) +{ + if (eCsrRoamWmmNoQos == pMac->roam.configParam.WMMSupportMode) + return false; + else + return true; +} + +/* pIes is the IEs for pSirBssDesc2 */ +bool csr_is_ssid_equal(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2) +{ + bool fEqual = false; + tSirMacSSid Ssid1, Ssid2; + tDot11fBeaconIEs *pIes1 = NULL; + tDot11fBeaconIEs *pIesLocal = pIes2; + + do { + if ((NULL == pSirBssDesc1) || (NULL == pSirBssDesc2)) + break; + if (!pIesLocal + && + !QDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc2, + &pIesLocal))) { + sme_err("fail to parse IEs"); + break; + } + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc1, &pIes1))) { + break; + } + if ((!pIes1->SSID.present) || (!pIesLocal->SSID.present)) + break; + if (pIes1->SSID.num_ssid != pIesLocal->SSID.num_ssid) + break; + qdf_mem_copy(Ssid1.ssId, pIes1->SSID.ssid, + pIes1->SSID.num_ssid); + qdf_mem_copy(Ssid2.ssId, pIesLocal->SSID.ssid, + pIesLocal->SSID.num_ssid); + + fEqual = (!qdf_mem_cmp(Ssid1.ssId, Ssid2.ssId, + pIesLocal->SSID.num_ssid)); + + } while (0); + if (pIes1) + qdf_mem_free(pIes1); + if (pIesLocal && !pIes2) + qdf_mem_free(pIesLocal); + + return fEqual; +} + +/* pIes can be passed in as NULL if the caller doesn't have one prepared */ +static bool csr_is_bss_description_wme(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + /* Assume that WME is found... */ + bool fWme = true; + tDot11fBeaconIEs *pIesTemp = pIes; + + do { + if (pIesTemp == NULL) { + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesTemp))) { + fWme = false; + break; + } + } + /* if the Wme Info IE is found, then WME is supported... */ + if (CSR_IS_QOS_BSS(pIesTemp)) + break; + /* if none of these are found, then WME is NOT supported... */ + fWme = false; + } while (0); + if (!csr_is_wmm_supported(pMac) && fWme) + if (!pIesTemp->HTCaps.present) + fWme = false; + + if ((pIes == NULL) && (NULL != pIesTemp)) + /* we allocate memory here so free it before returning */ + qdf_mem_free(pIesTemp); + + return fWme; +} + +eCsrMediaAccessType csr_get_qos_from_bss_desc(tpAniSirGlobal mac_ctx, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + eCsrMediaAccessType qosType = eCSR_MEDIUM_ACCESS_DCF; + + if (NULL == pIes) { + QDF_ASSERT(pIes != NULL); + return qosType; + } + + do { + /* If we find WMM in the Bss Description, then we let this + * override and use WMM. + */ + if (csr_is_bss_description_wme(mac_ctx, pSirBssDesc, pIes)) + qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + else { + /* If the QoS bit is on, then the AP is + * advertising 11E QoS. + */ + if (csr_is_qos_bss_desc(pSirBssDesc)) + qosType = eCSR_MEDIUM_ACCESS_11e_eDCF; + else + qosType = eCSR_MEDIUM_ACCESS_DCF; + + /* Scale back based on the types turned on + * for the adapter. + */ + if (eCSR_MEDIUM_ACCESS_11e_eDCF == qosType + && !csr_is11e_supported(mac_ctx)) + qosType = eCSR_MEDIUM_ACCESS_DCF; + } + + } while (0); + + return qosType; +} + +/* Caller allocates memory for pIEStruct */ +QDF_STATUS csr_parse_bss_description_ies(tpAniSirGlobal mac_ctx, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIEStruct) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int ieLen = + (int)(pBssDesc->length + sizeof(pBssDesc->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + if (ieLen > 0 && pIEStruct) { + if (!DOT11F_FAILED(dot11f_unpack_beacon_i_es + (mac_ctx, (uint8_t *) pBssDesc->ieFields, + ieLen, pIEStruct, false))) + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +/* 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(tpAniSirGlobal mac_ctx, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIEStruct) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (pBssDesc && ppIEStruct) { + *ppIEStruct = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if ((*ppIEStruct) != NULL) { + status = csr_parse_bss_description_ies(mac_ctx, + pBssDesc, + *ppIEStruct); + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(*ppIEStruct); + *ppIEStruct = NULL; + } + } else { + sme_err("failed to allocate memory"); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + } + + return status; +} + +bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len) +{ + bool fNullSsid = false; + + uint32_t SsidLength; + uint8_t *pSsidStr; + + do { + if (0 == len) { + fNullSsid = true; + break; + } + /* Consider 0 or space for hidden SSID */ + if (0 == pBssSsid[0]) { + fNullSsid = true; + break; + } + + SsidLength = len; + pSsidStr = pBssSsid; + + while (SsidLength) { + if (*pSsidStr) + break; + + pSsidStr++; + SsidLength--; + } + + if (0 == SsidLength) { + fNullSsid = true; + break; + } + } while (0); + + return fNullSsid; +} + +uint32_t csr_get_frag_thresh(tpAniSirGlobal mac_ctx) +{ + return mac_ctx->roam.configParam.FragmentationThreshold; +} + +uint32_t csr_get_rts_thresh(tpAniSirGlobal mac_ctx) +{ + return mac_ctx->roam.configParam.RTSThreshold; +} + +static eCsrPhyMode +csr_translate_to_phy_mode_from_bss_desc(tpAniSirGlobal mac_ctx, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *ies) +{ + eCsrPhyMode phyMode; + uint8_t i; + + switch (pSirBssDesc->nwType) { + case eSIR_11A_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11a; + break; + + case eSIR_11B_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11b; + break; + + case eSIR_11G_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11g_ONLY; + + /* Check if the BSS is in b/g mixed mode or g_only mode */ + if (!ies || !ies->SuppRates.present) { + sme_debug("Unable to get rates, assume G only mode"); + break; + } + + for (i = 0; i < ies->SuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate11b_supported_rate( + ies->SuppRates.rates[i])) { + sme_debug("One B rate is supported"); + phyMode = eCSR_DOT11_MODE_11g; + break; + } + } + break; + case eSIR_11N_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11n; + break; + case eSIR_11AX_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11ax; + break; + case eSIR_11AC_NW_TYPE: + default: + phyMode = eCSR_DOT11_MODE_11ac; + break; + } + return phyMode; +} + +uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac, + enum csr_cfgdot11mode csrDot11Mode) +{ + uint32_t ret; + + switch (csrDot11Mode) { + case eCSR_CFG_DOT11_MODE_AUTO: + sme_debug("eCSR_CFG_DOT11_MODE_AUTO"); + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = WNI_CFG_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11A: + ret = WNI_CFG_DOT11_MODE_11A; + break; + case eCSR_CFG_DOT11_MODE_11B: + ret = WNI_CFG_DOT11_MODE_11B; + break; + case eCSR_CFG_DOT11_MODE_11G: + ret = WNI_CFG_DOT11_MODE_11G; + break; + case eCSR_CFG_DOT11_MODE_11N: + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11G_ONLY: + ret = WNI_CFG_DOT11_MODE_11G_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11N_ONLY: + ret = WNI_CFG_DOT11_MODE_11N_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC_ONLY; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AC: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AX_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = WNI_CFG_DOT11_MODE_11AX_ONLY; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AX: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = WNI_CFG_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + default: + sme_warn("doesn't expect %d as csrDo11Mode", csrDot11Mode); + if (BAND_2G == pMac->roam.configParam.eBand) + ret = WNI_CFG_DOT11_MODE_11G; + else + ret = WNI_CFG_DOT11_MODE_11A; + break; + } + + return ret; +} + +/** + * csr_get_phy_mode_from_bss() - Get Phy Mode + * @pMac: Global MAC context + * @pBSSDescription: BSS Descriptor + * @pPhyMode: Physical Mode + * @pIes: Pointer to the IE fields + * + * This function should only return the super set of supported modes + * 11n implies 11b/g/a/n. + * + * Return: success + **/ +QDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBSSDescription, + eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + eCsrPhyMode phyMode = + csr_translate_to_phy_mode_from_bss_desc(pMac, pBSSDescription, + pIes); + + if (pIes) { + if (pIes->HTCaps.present) { + phyMode = eCSR_DOT11_MODE_11n; + if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) || + IS_BSS_VHT_CAPABLE(pIes->vendor_vht_ie.VHTCaps)) + phyMode = eCSR_DOT11_MODE_11ac; + if (pIes->he_cap.present) + phyMode = eCSR_DOT11_MODE_11ax; + } + *pPhyMode = phyMode; + } + + return status; +} + +/** + * csr_get_phy_mode_in_use() - to get phymode + * @phyModeIn: physical mode + * @bssPhyMode: physical mode in bss + * @f5GhzBand: 5Ghz band + * @pCfgDot11ModeToUse: dot11 mode in use + * + * This function returns the correct eCSR_CFG_DOT11_MODE is the two phyModes + * matches. bssPhyMode is the mode derived from the BSS description + * f5GhzBand is derived from the channel id of BSS description + * + * Return: true or false + */ +static bool csr_get_phy_mode_in_use(tpAniSirGlobal mac_ctx, + eCsrPhyMode phyModeIn, + eCsrPhyMode bssPhyMode, + bool f5GhzBand, + enum csr_cfgdot11mode *pCfgDot11ModeToUse) +{ + bool fMatch = false; + enum csr_cfgdot11mode cfgDot11Mode; + + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + switch (phyModeIn) { + /* 11a or 11b or 11g */ + case eCSR_DOT11_MODE_abg: + fMatch = true; + if (f5GhzBand) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + else if (eCSR_DOT11_MODE_11b == bssPhyMode) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + + case eCSR_DOT11_MODE_11a: + if (f5GhzBand) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + } + break; + + case eCSR_DOT11_MODE_11g: + if (!f5GhzBand) { + fMatch = true; + if (eCSR_DOT11_MODE_11b == bssPhyMode) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + } + break; + + case eCSR_DOT11_MODE_11g_ONLY: + if ((bssPhyMode == eCSR_DOT11_MODE_11g) || + (bssPhyMode == eCSR_DOT11_MODE_11g_ONLY)) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + } + break; + + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + if (!f5GhzBand && (bssPhyMode != eCSR_DOT11_MODE_11g_ONLY)) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + } + break; + + case eCSR_DOT11_MODE_11n: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ax: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + } + break; + + case eCSR_DOT11_MODE_11n_ONLY: + if (eCSR_DOT11_MODE_11n == bssPhyMode) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + + } + + break; + case eCSR_DOT11_MODE_11ac: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ax: + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + } + break; + + case eCSR_DOT11_MODE_11ac_ONLY: + if (eCSR_DOT11_MODE_11ac == bssPhyMode) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + } + break; + case eCSR_DOT11_MODE_11ax: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ac: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + case eCSR_DOT11_MODE_11ax: + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AX; + break; + } + break; + + case eCSR_DOT11_MODE_11ax_ONLY: + if (eCSR_DOT11_MODE_11ax == bssPhyMode) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AX; + } + break; + + default: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ac: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + case eCSR_DOT11_MODE_11ax: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AX; + break; + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + break; + } + break; + } + + if (fMatch && pCfgDot11ModeToUse) { + if (cfgDot11Mode == eCSR_CFG_DOT11_MODE_11AX) { + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + *pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + *pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AC; + else + *pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + } else { + if (cfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC + && (!IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))) + *pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + else + *pCfgDot11ModeToUse = cfgDot11Mode; + } + } + return fMatch; +} + +/** + * csr_is_phy_mode_match() - to find if phy mode matches + * @pMac: pointer to mac context + * @phyMode: physical mode + * @pSirBssDesc: bss description + * @pProfile: pointer to roam profile + * @pReturnCfgDot11Mode: dot1 mode to return + * @pIes: pointer to IEs + * + * This function decides whether the one of the bit of phyMode is matching the + * mode in the BSS and allowed by the user setting + * + * Return: true or false based on mode that fits the criteria + */ +bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode, + tSirBssDescription *pSirBssDesc, + struct csr_roam_profile *pProfile, + enum csr_cfgdot11mode *pReturnCfgDot11Mode, + tDot11fBeaconIEs *pIes) +{ + bool fMatch = false; + eCsrPhyMode phyModeInBssDesc = eCSR_DOT11_MODE_AUTO, phyMode2; + enum csr_cfgdot11mode cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_AUTO; + uint32_t bitMask, loopCount; + + if (!QDF_IS_STATUS_SUCCESS(csr_get_phy_mode_from_bss(pMac, pSirBssDesc, + &phyModeInBssDesc, pIes))) + return fMatch; + + if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) { + if (eCSR_CFG_DOT11_MODE_ABG == + pMac->roam.configParam.uCfgDot11Mode) { + phyMode = eCSR_DOT11_MODE_abg; + } else if (eCSR_CFG_DOT11_MODE_AUTO == + pMac->roam.configParam.uCfgDot11Mode) { + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + phyMode = eCSR_DOT11_MODE_11ax; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + phyMode = eCSR_DOT11_MODE_11ac; + else + phyMode = eCSR_DOT11_MODE_11n; + } else { + /* user's pick */ + phyMode = pMac->roam.configParam.phyMode; + } + } + + if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) { + if (0 != phyMode) { + if (eCSR_DOT11_MODE_AUTO & phyMode) { + phyMode2 = + eCSR_DOT11_MODE_AUTO & phyMode; + } + } else { + phyMode2 = phyMode; + } + fMatch = csr_get_phy_mode_in_use(pMac, phyMode2, + phyModeInBssDesc, + WLAN_REG_IS_5GHZ_CH( + pSirBssDesc->channelId), + &cfgDot11ModeToUse); + } else { + bitMask = 1; + loopCount = 0; + while (loopCount < eCSR_NUM_PHY_MODE) { + phyMode2 = (phyMode & (bitMask << loopCount++)); + if (0 != phyMode2 && + csr_get_phy_mode_in_use(pMac, phyMode2, + phyModeInBssDesc, + WLAN_REG_IS_5GHZ_CH(pSirBssDesc->channelId), + &cfgDot11ModeToUse)) { + fMatch = true; + break; + } + } + } + if (fMatch && pReturnCfgDot11Mode) { + if (pProfile) { + /* + * IEEE 11n spec (8.4.3): HT STA shall + * eliminate TKIP as a choice for the pairwise + * cipher suite if CCMP is advertised by the AP + * or if the AP included an HT capabilities + * element in its Beacons and Probe Response. + */ + if ((!CSR_IS_11n_ALLOWED( + pProfile->negotiatedUCEncryptionType)) + && ((eCSR_CFG_DOT11_MODE_11N == + cfgDot11ModeToUse) || + (eCSR_CFG_DOT11_MODE_11AC == + cfgDot11ModeToUse) || + (eCSR_CFG_DOT11_MODE_11AX == + cfgDot11ModeToUse))) { + /* We cannot do 11n here */ + if (!WLAN_REG_IS_5GHZ_CH + (pSirBssDesc->channelId)) { + cfgDot11ModeToUse = + eCSR_CFG_DOT11_MODE_11G; + } else { + cfgDot11ModeToUse = + eCSR_CFG_DOT11_MODE_11A; + } + } + } + *pReturnCfgDot11Mode = cfgDot11ModeToUse; + } + + return fMatch; +} + +enum csr_cfgdot11mode csr_find_best_phy_mode(tpAniSirGlobal pMac, + uint32_t phyMode) +{ + enum csr_cfgdot11mode cfgDot11ModeToUse; + enum band_info eBand = pMac->roam.configParam.eBand; + + if ((0 == phyMode) || + (eCSR_DOT11_MODE_AUTO & phyMode) || + (eCSR_DOT11_MODE_11ax & phyMode)) { + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AX; + } else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AC; + } else { + /* Default to 11N mode if user has configured 11ac mode + * and FW doesn't supports 11ac mode . + */ + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + } + } else if (eCSR_DOT11_MODE_11ac & phyMode) { + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AC; + } else { + /* Default to 11N mode if user has configured 11ac mode + * and FW doesn't supports 11ac mode . + */ + } cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + } else { + if ((eCSR_DOT11_MODE_11n | eCSR_DOT11_MODE_11n_ONLY) & phyMode) + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + else if (eCSR_DOT11_MODE_abg & phyMode) { + if (BAND_2G != eBand) + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A; + else + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G; + } else if (eCSR_DOT11_MODE_11a & phyMode) + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A; + else if ((eCSR_DOT11_MODE_11g | eCSR_DOT11_MODE_11g_ONLY) & + phyMode) + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G; + else + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11B; + } + + return cfgDot11ModeToUse; +} + +uint32_t csr_get11h_power_constraint(tpAniSirGlobal mac_ctx, + tDot11fIEPowerConstraints *constraints) +{ + uint32_t localPowerConstraint = 0; + + /* check if .11h support is enabled, if not, + * the power constraint is 0. + */ + if (mac_ctx->roam.configParam.Is11hSupportEnabled && + constraints->present) { + localPowerConstraint = constraints->localPowerConstraints; + } + + return localPowerConstraint; +} + +bool csr_is_profile_wpa(struct csr_roam_profile *pProfile) +{ + bool fWpaProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: +#endif + fWpaProfile = true; + break; + + default: + fWpaProfile = false; + break; + } + + if (fWpaProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + fWpaProfile = true; + break; + + default: + fWpaProfile = false; + break; + } + } + return fWpaProfile; +} + +bool csr_is_profile_rsn(struct csr_roam_profile *pProfile) +{ + bool fRSNProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_RSN: + case eCSR_AUTH_TYPE_RSN_PSK: + case eCSR_AUTH_TYPE_FT_RSN: + case eCSR_AUTH_TYPE_FT_RSN_PSK: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_RSN: +#endif +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + /* fallthrough */ + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + case eCSR_AUTH_TYPE_DPP_RSN: + fRSNProfile = true; + break; + + case eCSR_AUTH_TYPE_OWE: + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA256: + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA384: + fRSNProfile = true; + break; + case eCSR_AUTH_TYPE_SAE: + fRSNProfile = true; + break; + + default: + fRSNProfile = false; + break; + } + + if (fRSNProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + /* !!REVIEW - For WPA2, use of RSN IE mandates */ + /* use of AES as encryption. Here, we qualify */ + /* even if encryption type is WEP or TKIP */ + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + case eCSR_ENCRYPT_TYPE_AES_GCMP: + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + fRSNProfile = true; + break; + + default: + fRSNProfile = false; + break; + } + } + return fRSNProfile; +} + +/** + * csr_update_mcc_p2p_beacon_interval() - update p2p beacon interval + * @mac_ctx: pointer to mac context + * + * This function is to update the mcc p2p beacon interval + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_update_mcc_p2p_beacon_interval(tpAniSirGlobal mac_ctx) +{ + uint32_t session_id = 0; + struct csr_roam_session *roam_session; + + /* If MCC is not supported just break and return SUCCESS */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return QDF_STATUS_E_FAILURE; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + /* + * If GO in MCC support different beacon interval, + * change the BI of the P2P-GO + */ + roam_session = &mac_ctx->roam.roamSession[session_id]; + if (roam_session->bssParams.bssPersona != QDF_P2P_GO_MODE) + continue; + /* + * Handle different BI scneario based on the + * configuration set.If Config is set to 0x02 then + * Disconnect all the P2P clients associated. If config + * is set to 0x04 then update the BI without + * disconnecting all the clients + */ + if ((mac_ctx->roam.configParam.fAllowMCCGODiffBI == 0x04) + && (roam_session->bssParams. + updatebeaconInterval)) { + return csr_send_chng_mcc_beacon_interval(mac_ctx, + session_id); + } else if (roam_session->bssParams.updatebeaconInterval) { + /* + * If the configuration of fAllowMCCGODiffBI is set to + * other than 0x04 + */ + return csr_roam_call_callback(mac_ctx, + session_id, + NULL, 0, + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS, + eCSR_ROAM_RESULT_NONE); + } + } + return QDF_STATUS_E_FAILURE; +} + +static uint16_t csr_calculate_mcc_beacon_interval(tpAniSirGlobal pMac, + uint16_t sta_bi, + uint16_t go_gbi) +{ + uint8_t num_beacons = 0; + uint8_t is_multiple = 0; + uint16_t go_cbi = 0; + uint16_t go_fbi = 0; + uint16_t sta_cbi = 0; + + /* If GO's given beacon Interval is less than 100 */ + if (go_gbi < 100) + go_cbi = 100; + /* if GO's given beacon Interval is greater than or equal to 100 */ + else + go_cbi = 100 + (go_gbi % 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; + sme_warn("sta_bi 2nd parameter is zero, initialize to %d", + sta_bi); + } + /* check, if either one is multiple of another */ + if (sta_bi > go_cbi) + is_multiple = !(sta_bi % go_cbi); + else + is_multiple = !(go_cbi % sta_bi); + + /* if it is multiple, then accept GO's beacon interval + * range [100,199] as it is + */ + if (is_multiple) + return go_cbi; + + /* 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_cbi = sta_bi / num_beacons; + go_fbi = sta_cbi; + } else + /* if STA beacon interval is less than 100, use GO's change + * bacon interval instead of updating to STA's beacon interval. + */ + go_fbi = go_cbi; + + return go_fbi; +} + +/** + * csr_validate_p2pcli_bcn_intrvl() - to validate p2pcli beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel id variable + * @bcn_interval: pointer to given beacon interval + * @session_id: given session id + * @status: fill the status in terms of QDF_STATUS to inform caller + * + * This API can provide the validation the beacon interval and re-calculate + * in case concurrency + * + * Return: bool + */ +static bool csr_validate_p2pcli_bcn_intrvl(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, uint16_t *bcn_interval, uint32_t session_id, + QDF_STATUS *status) +{ + struct csr_roam_session *roamsession; + + roamsession = &mac_ctx->roam.roamSession[session_id]; + if (roamsession->pCurRoamProfile && + (roamsession->pCurRoamProfile->csrPersona == + QDF_STA_MODE)) { + /* check for P2P client mode */ + sme_debug("Ignore Beacon Interval Validation..."); + } else if (roamsession->bssParams.bssPersona == QDF_P2P_GO_MODE) { + /* Check for P2P go scenario */ + if ((roamsession->bssParams.operationChn != chnl_id) + && (roamsession->bssParams.beaconInterval != + *bcn_interval)) { + sme_err("BcnIntrvl is diff can't connect to P2P_GO network"); + *status = QDF_STATUS_E_FAILURE; + return true; + } + } + return false; +} + +/** + * csr_validate_p2pgo_bcn_intrvl() - to validate p2pgo beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel id variable + * @bcn_interval: pointer to given beacon interval + * @session_id: given session id + * @status: fill the status in terms of QDF_STATUS to inform caller + * + * This API can provide the validation the beacon interval and re-calculate + * in case concurrency + * + * Return: bool + */ +static bool csr_validate_p2pgo_bcn_intrvl(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, uint16_t *bcn_interval, + uint32_t session_id, QDF_STATUS *status) +{ + struct csr_roam_session *roamsession; + struct csr_config *cfg_param; + tCsrRoamConnectedProfile *conn_profile; + uint16_t new_bcn_interval; + + roamsession = &mac_ctx->roam.roamSession[session_id]; + cfg_param = &mac_ctx->roam.configParam; + conn_profile = &roamsession->connectedProfile; + if (roamsession->pCurRoamProfile && + ((roamsession->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE) || + (roamsession->pCurRoamProfile->csrPersona == + QDF_STA_MODE))) { + /* check for P2P_client scenario */ + if ((conn_profile->operationChannel == 0) && + (conn_profile->beaconInterval == 0)) + return false; + + if (csr_is_conn_state_connected_infra(mac_ctx, session_id) && + (conn_profile->operationChannel != chnl_id) && + (conn_profile->beaconInterval != *bcn_interval)) { + /* + * Updated beaconInterval should be used only when + * we are starting a new BSS not incase of + * client or STA case + */ + + /* Calculate beacon Interval for P2P-GO incase of MCC */ + if (cfg_param->conc_custom_rule1 || + cfg_param->conc_custom_rule2) { + new_bcn_interval = CSR_CUSTOM_CONC_GO_BI; + } else { + new_bcn_interval = + csr_calculate_mcc_beacon_interval( + mac_ctx, + conn_profile->beaconInterval, + *bcn_interval); + } + if (*bcn_interval != new_bcn_interval) + *bcn_interval = new_bcn_interval; + *status = QDF_STATUS_SUCCESS; + return true; + } + } + return false; +} + +/** + * csr_validate_sta_bcn_intrvl() - to validate sta beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel id variable + * @bcn_interval: pointer to given beacon interval + * @session_id: given session id + * @status: fill the status in terms of QDF_STATUS to inform caller + * + * This API can provide the validation the beacon interval and re-calculate + * in case concurrency + * + * Return: bool + */ +static bool csr_validate_sta_bcn_intrvl(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, uint16_t *bcn_interval, + uint32_t session_id, QDF_STATUS *status) +{ + struct csr_roam_session *roamsession; + struct csr_config *cfg_param; + uint16_t new_bcn_interval; + + roamsession = &mac_ctx->roam.roamSession[session_id]; + cfg_param = &mac_ctx->roam.configParam; + + if (roamsession->pCurRoamProfile && + (roamsession->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE)) { + /* check for P2P client mode */ + sme_debug("Bcn Intrvl validation not require for STA/CLIENT"); + return false; + } + if ((roamsession->bssParams.bssPersona == QDF_SAP_MODE) && + (roamsession->bssParams.operationChn != chnl_id)) { + /* + * IF SAP has started and STA wants to connect + * on different channel MCC should + * MCC should not be enabled so making it + * false to enforce on same channel + */ + sme_err("*** MCC with SAP+STA sessions ****"); + *status = QDF_STATUS_SUCCESS; + return true; + } + /* + * Check for P2P go scenario + * if GO in MCC support different + * beacon interval, + * change the BI of the P2P-GO + */ + if ((roamsession->bssParams.bssPersona == QDF_P2P_GO_MODE) && + (roamsession->bssParams.operationChn != chnl_id) && + (roamsession->bssParams.beaconInterval != *bcn_interval)) { + /* if GO in MCC support diff beacon interval, return success */ + if (cfg_param->fAllowMCCGODiffBI == 0x01) { + *status = QDF_STATUS_SUCCESS; + return true; + } + /* + * Send only Broadcast disassoc and update bcn_interval + * If configuration is set to 0x04 then dont + * disconnect all the station + */ + if ((cfg_param->fAllowMCCGODiffBI == 0x02) + || (cfg_param->fAllowMCCGODiffBI == 0x04)) { + /* Check to pass the right beacon Interval */ + if (cfg_param->conc_custom_rule1 || + cfg_param->conc_custom_rule2) { + new_bcn_interval = CSR_CUSTOM_CONC_GO_BI; + } else { + new_bcn_interval = + csr_calculate_mcc_beacon_interval( + mac_ctx, *bcn_interval, + roamsession->bssParams.beaconInterval); + } + sme_debug("Peer AP BI : %d, new Beacon Interval: %d", + *bcn_interval, new_bcn_interval); + /* Update the becon Interval */ + if (new_bcn_interval != + roamsession->bssParams.beaconInterval) { + /* Update the bcn_interval now */ + sme_err("Beacon Interval got changed config used: %d", + cfg_param->fAllowMCCGODiffBI); + + roamsession->bssParams.beaconInterval = + new_bcn_interval; + roamsession->bssParams.updatebeaconInterval = + true; + *status = csr_update_mcc_p2p_beacon_interval( + mac_ctx); + return true; + } + *status = QDF_STATUS_SUCCESS; + return true; + } + if (cfg_param->fAllowMCCGODiffBI + == 0x03) { + /* Disconnect the P2P session */ + roamsession->bssParams.updatebeaconInterval = false; + *status = csr_roam_call_callback(mac_ctx, + session_id, NULL, 0, + eCSR_ROAM_SEND_P2P_STOP_BSS, + eCSR_ROAM_RESULT_NONE); + return true; + } + sme_err("BcnIntrvl is diff can't connect to preferred AP"); + *status = QDF_STATUS_E_FAILURE; + return true; + } + return false; +} + +/** + * csr_validate_mcc_beacon_interval() - to validate the mcc beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel number + * @bcn_interval: provided beacon interval + * @cur_session_id: current session id + * @cur_bss_persona: Current BSS persona + * + * This API will validate the mcc beacon interval + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, + uint16_t *bcn_interval, + uint32_t cur_session_id, + enum QDF_OPMODE cur_bss_persona) +{ + uint32_t session_id = 0; + QDF_STATUS status; + bool is_done; + + /* If MCC is not supported just break */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return QDF_STATUS_E_FAILURE; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (cur_session_id == session_id) + continue; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) + continue; + + switch (cur_bss_persona) { + case QDF_STA_MODE: + is_done = csr_validate_sta_bcn_intrvl(mac_ctx, chnl_id, + bcn_interval, session_id, &status); + if (true == is_done) + return status; + break; + + case QDF_P2P_CLIENT_MODE: + is_done = csr_validate_p2pcli_bcn_intrvl(mac_ctx, + chnl_id, bcn_interval, session_id, + &status); + if (true == is_done) + return status; + break; + + case QDF_SAP_MODE: + case QDF_IBSS_MODE: + break; + + case QDF_P2P_GO_MODE: + is_done = csr_validate_p2pgo_bcn_intrvl(mac_ctx, + chnl_id, bcn_interval, + session_id, &status); + if (true == is_done) + return status; + break; + + default: + sme_err("Persona not supported: %d", cur_bss_persona); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * csr_is_auth_type11r() - Check if Authentication type is 11R + * @mac: pointer to mac context + * @auth_type: The authentication type that is used to make the connection + * @mdie_present: Is MDIE IE present + * + * Return: true if is 11R auth type, false otherwise + */ +bool csr_is_auth_type11r(tpAniSirGlobal mac, eCsrAuthType auth_type, + uint8_t mdie_present) +{ + switch (auth_type) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + if (mdie_present && + mac->roam.configParam.enable_ftopen) + return true; + break; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + case eCSR_AUTH_TYPE_FT_RSN: + return true; + default: + break; + } + return false; +} + +/* Function to return true if the profile is 11r */ +bool csr_is_profile11r(tpAniSirGlobal mac, + struct csr_roam_profile *pProfile) +{ + return csr_is_auth_type11r(mac, pProfile->negotiatedAuthType, + pProfile->MDID.mdiePresent); +} + +bool csr_is_auth_type_ese(eCsrAuthType AuthType) +{ + switch (AuthType) { + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: + return true; + default: + break; + } + return false; +} + +#ifdef FEATURE_WLAN_ESE + +/* Function to return true if the profile is ESE */ +bool csr_is_profile_ese(struct csr_roam_profile *pProfile) +{ + return csr_is_auth_type_ese(pProfile->negotiatedAuthType); +} + +#endif + +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(struct csr_roam_profile *pProfile) +{ + bool fWapiProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + fWapiProfile = true; + break; + + default: + fWapiProfile = false; + break; + } + + if (fWapiProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_WPI: + fWapiProfile = true; + break; + + default: + fWapiProfile = false; + break; + } + } + return fWapiProfile; +} + +static bool csr_is_wapi_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1, + uint8_t *Oui2) +{ + return !qdf_mem_cmp(Oui1, Oui2, CSR_WAPI_OUI_SIZE); +} + +static bool csr_is_wapi_oui_match(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE], + uint8_t cAllCyphers, uint8_t Cypher[], + uint8_t Oui[]) +{ + bool fYes = false; + uint8_t idx; + + for (idx = 0; idx < cAllCyphers; idx++) { + if (csr_is_wapi_oui_equal(pMac, AllCyphers[idx], Cypher)) { + fYes = true; + break; + } + } + + if (fYes && Oui) + qdf_mem_copy(Oui, AllCyphers[idx], CSR_WAPI_OUI_SIZE); + + return fYes; +} +#endif /* FEATURE_WLAN_WAPI */ + +static bool csr_is_wpa_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1, + uint8_t *Oui2) +{ + return !qdf_mem_cmp(Oui1, Oui2, CSR_WPA_OUI_SIZE); +} + +static bool csr_is_oui_match(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WPA_OUI_SIZE], + uint8_t cAllCyphers, uint8_t Cypher[], uint8_t Oui[]) +{ + bool fYes = false; + uint8_t idx; + + for (idx = 0; idx < cAllCyphers; idx++) { + if (csr_is_wpa_oui_equal(pMac, AllCyphers[idx], Cypher)) { + fYes = true; + break; + } + } + + if (fYes && Oui) + qdf_mem_copy(Oui, AllCyphers[idx], CSR_WPA_OUI_SIZE); + + return fYes; +} + +static bool csr_match_rsnoui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_RSN_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllCyphers, cAllCyphers, csr_rsn_oui[ouiIndex], Oui); + +} + +#ifdef FEATURE_WLAN_WAPI +static bool csr_match_wapi_oui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllCyphers, cAllCyphers, csr_wapi_oui[ouiIndex], Oui); + +} +#endif /* FEATURE_WLAN_WAPI */ + +static bool csr_match_wpaoui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_RSN_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + if (ouiIndex < QDF_ARRAY_SIZE(csr_wpa_oui)) + return csr_is_oui_match + (pMac, AllCyphers, cAllCyphers, + csr_wpa_oui[ouiIndex], Oui); + else + return false; +} + +#ifdef FEATURE_WLAN_WAPI +static bool csr_is_auth_wapi_cert(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WAPI_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllSuites, cAllSuites, csr_wapi_oui[1], Oui); +} + +static bool csr_is_auth_wapi_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WAPI_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllSuites, cAllSuites, csr_wapi_oui[2], Oui); +} +#endif /* FEATURE_WLAN_WAPI */ + + +/* + * Function for 11R FT Authentication. We match the FT Authentication Cipher + * suite here. This matches for FT Auth with the 802.1X exchange. + */ +static bool csr_is_ft_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[03], Oui); +} + +/* + * Function for 11R FT Authentication. We match the FT Authentication Cipher + * suite here. This matches for FT Auth with the PSK. + */ +static bool csr_is_ft_auth_rsn_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[04], Oui); +} + + +#ifdef FEATURE_WLAN_ESE + +/* + * Function for ESE CCKM AKM Authentication. We match the CCKM AKM + * Authentication Key Management suite here. This matches for CCKM AKM Auth + * with the 802.1X exchange. + */ +static bool csr_is_ese_cckm_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[06], Oui); +} + +static bool csr_is_ese_cckm_auth_wpa(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[06], Oui); +} + +#endif + +static bool csr_is_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[01], Oui); +} + +static bool csr_is_auth_rsn_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[02], Oui); +} + +#ifdef WLAN_FEATURE_11W +static bool csr_is_auth_rsn_psk_sha256(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[07], Oui); +} +static bool csr_is_auth_rsn8021x_sha256(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[8], Oui); +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_is_auth_fils_sha256() - check whether oui is fils sha256 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is FILS SHA256, false otherwise + */ +static bool csr_is_auth_fils_sha256(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_FILS_SHA256], oui); +} + +/* + * csr_is_auth_fils_sha384() - check whether oui is fils sha384 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is FILS SHA384, false otherwise + */ +static bool csr_is_auth_fils_sha384(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_FILS_SHA384], oui); +} + +/* + * csr_is_auth_fils_ft_sha256() - check whether oui is fils ft sha256 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is FT FILS SHA256, false otherwise + */ +static bool csr_is_auth_fils_ft_sha256(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_FT_FILS_SHA256], oui); +} + +/* + * csr_is_auth_fils_ft_sha384() - check whether oui is fils ft sha384 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is FT FILS SHA384, false otherwise + */ +static bool csr_is_auth_fils_ft_sha384(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_FT_FILS_SHA384], oui); +} +#endif + +/* + * csr_is_auth_dpp_rsn() - check whether oui is dpp rsn + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is dpp rsn, false otherwise + */ +static bool csr_is_auth_dpp_rsn(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_DPP_RSN], oui); +} + +/* + * csr_is_auth_wpa_owe() - check whether oui is OWE + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is OWE, false otherwise + */ +static bool csr_is_auth_wpa_owe(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match + (mac, all_suites, suite_count, csr_rsn_oui[ENUM_OWE], oui); +} + +/* + * csr_is_auth_suiteb_eap_256() - check whether oui is SuiteB EAP256 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is SuiteB EAP256, false otherwise + */ +static bool csr_is_auth_suiteb_eap_256(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_SUITEB_EAP256], oui); +} + +/* + * csr_is_auth_suiteb_eap_384() - check whether oui is SuiteB EAP384 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is SuiteB EAP384, false otherwise + */ +static bool csr_is_auth_suiteb_eap_384(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match(mac, all_suites, suite_count, + csr_rsn_oui[ENUM_SUITEB_EAP384], oui); +} + +#ifdef WLAN_FEATURE_SAE +/* + * csr_is_auth_wpa_sae() - check whether oui is SAE + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is SAE, false otherwise + */ +static bool csr_is_auth_wpa_sae(tpAniSirGlobal mac, + uint8_t all_suites[][CSR_RSN_OUI_SIZE], + uint8_t suite_count, uint8_t oui[]) +{ + return csr_is_oui_match + (mac, all_suites, suite_count, csr_rsn_oui[ENUM_SAE], oui); +} +#endif + +static bool csr_is_auth_wpa(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[01], Oui); +} + +static bool csr_is_auth_wpa_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[02], Oui); +} + +/* + * csr_is_group_mgmt_gmac_128() - check whether oui is GMAC_128 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is GMAC_128, false otherwise + */ +static bool csr_is_group_mgmt_gmac_128(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match(pMac, AllSuites, cAllSuites, + csr_group_mgmt_oui[ENUM_GMAC_128], Oui); +} + +/* + * csr_is_group_mgmt_gmac_256() - check whether oui is GMAC_256 + * @mac: Global MAC context + * @all_suites: pointer to all supported akm suites + * @suite_count: all supported akm suites count + * @oui: Oui needs to be matched + * + * Return: True if OUI is GMAC_256, false otherwise + */ +static bool csr_is_group_mgmt_gmac_256(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match(pMac, AllSuites, cAllSuites, + csr_group_mgmt_oui[ENUM_GMAC_256], Oui); +} + +static uint8_t csr_get_oui_index_from_cipher(eCsrEncryptionType enType) +{ + uint8_t OUIIndex; + + switch (enType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + OUIIndex = CSR_OUI_WEP40_OR_1X_INDEX; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + OUIIndex = CSR_OUI_WEP104_INDEX; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + OUIIndex = CSR_OUI_TKIP_OR_PSK_INDEX; + break; + case eCSR_ENCRYPT_TYPE_AES: + OUIIndex = CSR_OUI_AES_INDEX; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP: + OUIIndex = CSR_OUI_AES_GCMP_INDEX; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + OUIIndex = CSR_OUI_AES_GCMP_256_INDEX; + break; + case eCSR_ENCRYPT_TYPE_NONE: + OUIIndex = CSR_OUI_USE_GROUP_CIPHER_INDEX; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + OUIIndex = CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: /* HOWTO handle this? */ + OUIIndex = CSR_OUI_RESERVED_INDEX; + break; + } /* switch */ + + return OUIIndex; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * csr_is_fils_auth() - update negotiated auth if matches to FILS auth type + * @mac_ctx: pointer to mac context + * @authsuites: auth suites + * @c_auth_suites: auth suites count + * @authentication: authentication + * @auth_type: authentication type list + * @index: current counter + * @neg_authtype: pointer to negotiated auth + * + * Return: None + */ +static void csr_is_fils_auth(tpAniSirGlobal mac_ctx, + uint8_t authsuites[][CSR_RSN_OUI_SIZE], uint8_t c_auth_suites, + uint8_t authentication[], tCsrAuthList *auth_type, + uint8_t index, eCsrAuthType *neg_authtype) +{ + /* + * TODO Always try with highest security + * move this down once sha384 is validated + */ + if (csr_is_auth_fils_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FILS_SHA256 == + auth_type->authType[index]) + *neg_authtype = eCSR_AUTH_TYPE_FILS_SHA256; + } + if ((*neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_fils_sha384(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FILS_SHA384 == + auth_type->authType[index]) + *neg_authtype = eCSR_AUTH_TYPE_FILS_SHA384; + } + if ((*neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_fils_ft_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_FILS_SHA256 == + auth_type->authType[index]) + *neg_authtype = eCSR_AUTH_TYPE_FT_FILS_SHA256; + } + if ((*neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_fils_ft_sha384(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_FILS_SHA384 == + auth_type->authType[index]) + *neg_authtype = eCSR_AUTH_TYPE_FT_FILS_SHA384; + } + sme_debug("negotiated auth type is %d", *neg_authtype); +} +#else +static void csr_is_fils_auth(tpAniSirGlobal mac_ctx, + uint8_t authsuites[][CSR_RSN_OUI_SIZE], uint8_t c_auth_suites, + uint8_t authentication[], tCsrAuthList *auth_type, + uint8_t index, eCsrAuthType *neg_authtype) +{ +} +#endif + +#ifdef WLAN_FEATURE_SAE +/** + * csr_check_sae_auth() - update negotiated auth if matches to SAE auth type + * @mac_ctx: pointer to mac context + * @authsuites: auth suites + * @c_auth_suites: auth suites count + * @authentication: authentication + * @auth_type: authentication type list + * @index: current counter + * @neg_authtype: pointer to negotiated auth + * + * Return: None + */ +static void csr_check_sae_auth(tpAniSirGlobal mac_ctx, + uint8_t authsuites[][CSR_RSN_OUI_SIZE], uint8_t c_auth_suites, + uint8_t authentication[], tCsrAuthList *auth_type, + uint8_t index, eCsrAuthType *neg_authtype) +{ + if ((*neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_wpa_sae(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_SAE == auth_type->authType[index]) + *neg_authtype = eCSR_AUTH_TYPE_SAE; + if (eCSR_AUTH_TYPE_OPEN_SYSTEM == auth_type->authType[index]) + *neg_authtype = eCSR_AUTH_TYPE_OPEN_SYSTEM; + } + sme_debug("negotiated auth type is %d", *neg_authtype); +} +#else +static void csr_check_sae_auth(tpAniSirGlobal mac_ctx, + uint8_t authsuites[][CSR_RSN_OUI_SIZE], uint8_t c_auth_suites, + uint8_t authentication[], tCsrAuthList *auth_type, + uint8_t index, eCsrAuthType *neg_authtype) +{ +} +#endif + +/** + * csr_get_rsn_information() - to get RSN information + * @mac_ctx: pointer to global MAC context + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @rsn_ie: pointer to RSN IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @capabilities: RSN capabilities + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * @gp_mgmt_cipher: group management cipher + * @mgmt_encryption_type: group management encryption type + * + * This routine will get all RSN information + * + * Return: bool + */ +static bool csr_get_rsn_information(tpAniSirGlobal mac_ctx, + tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIERSN *rsn_ie, uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + struct rsn_caps *capabilities, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher, + uint8_t *gp_mgmt_cipher, + tAniEdType *mgmt_encryption_type) +{ + bool acceptable_cipher = false; + bool group_mgmt_acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_group_mgmt_cipher = 0; + uint8_t c_auth_suites = 0, i; + uint8_t unicast[CSR_RSN_OUI_SIZE]; + uint8_t multicast[CSR_RSN_OUI_SIZE]; + uint8_t group_mgmt[CSR_RSN_OUI_SIZE]; + uint8_t authsuites[CSR_RSN_MAX_AUTH_SUITES][CSR_RSN_OUI_SIZE]; + uint8_t authentication[CSR_RSN_OUI_SIZE]; + uint8_t mccipher_arr[CSR_RSN_MAX_MULTICAST_CYPHERS][CSR_RSN_OUI_SIZE]; + uint8_t group_mgmt_arr[CSR_RSN_MAX_MULTICAST_CYPHERS][CSR_RSN_OUI_SIZE]; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + + if (!rsn_ie->present) + goto end; + c_mcast_cipher++; + qdf_mem_copy(mccipher_arr, rsn_ie->gp_cipher_suite, + CSR_RSN_OUI_SIZE); + c_ucast_cipher = + (uint8_t) (rsn_ie->pwise_cipher_suite_count); + + c_auth_suites = (uint8_t) (rsn_ie->akm_suite_cnt); + for (i = 0; i < c_auth_suites && i < CSR_RSN_MAX_AUTH_SUITES; i++) { + qdf_mem_copy((void *)&authsuites[i], + (void *)&rsn_ie->akm_suite[i], CSR_RSN_OUI_SIZE); + } + + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_rsnoui_index(mac_ctx, + rsn_ie->pwise_cipher_suites, c_ucast_cipher, + csr_get_oui_index_from_cipher(encr_type), + unicast); + + if (!acceptable_cipher) + goto end; + + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + acceptable_cipher = csr_match_rsnoui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]), + multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = mc_encryption->encryptionType[i]; + + /* Group Management Cipher only for 11w */ + if (mgmt_encryption_type) { + c_group_mgmt_cipher++; + qdf_mem_copy(group_mgmt_arr, rsn_ie->gp_mgmt_cipher_suite, + CSR_RSN_OUI_SIZE); + if (csr_is_group_mgmt_gmac_128(mac_ctx, group_mgmt_arr, + c_group_mgmt_cipher, group_mgmt)) { + group_mgmt_acceptable_cipher = true; + *mgmt_encryption_type = eSIR_ED_AES_GMAC_128; + } else if (csr_is_group_mgmt_gmac_256(mac_ctx, group_mgmt_arr, + c_group_mgmt_cipher, group_mgmt)) { + group_mgmt_acceptable_cipher = true; + *mgmt_encryption_type = eSIR_ED_AES_GMAC_256; + } else { + /* Default is CMAC */ + group_mgmt_acceptable_cipher = true; + *mgmt_encryption_type = eSIR_ED_AES_128_CMAC; + qdf_mem_copy(group_mgmt, csr_group_mgmt_oui[ENUM_CMAC], + CSR_RSN_OUI_SIZE); + } + } + + /* Initializing with false as it has true value already */ + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype. + */ + /* Set FILS as first preference */ + csr_is_fils_auth(mac_ctx, authsuites, c_auth_suites, + authentication, auth_type, i, &neg_authtype); + /* Changed the AKM suites according to order of preference */ + csr_check_sae_auth(mac_ctx, authsuites, c_auth_suites, + authentication, auth_type, i, &neg_authtype); + + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_dpp_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_DPP_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_DPP_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_ft_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_FT_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_ft_auth_rsn_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_RSN_PSK == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_FT_RSN_PSK; + } +#ifdef FEATURE_WLAN_ESE + /* ESE only supports 802.1X. No PSK. */ + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_ese_cckm_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_CCKM_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_CCKM_RSN; + } +#endif + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_PSK == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_PSK; + } +#ifdef WLAN_FEATURE_11W + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn_psk_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_rsn8021x_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } +#endif + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_wpa_owe(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_OWE == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_OWE; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_suiteb_eap_256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_SUITEB_EAP_SHA256 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_SUITEB_EAP_SHA256; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_suiteb_eap_384(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_SUITEB_EAP_SHA384 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; + } + + /* + * The 1st auth type in the APs RSN IE, to match stations + * connecting profiles auth type will cause us to exit this + * loop. This is added as some APs advertise multiple akms in + * the RSN IE + */ + if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) { + acceptable_cipher = true; + break; + } + } /* for */ +end: + if (acceptable_cipher) { + if (mcast_cipher) + qdf_mem_copy(mcast_cipher, multicast, + CSR_RSN_OUI_SIZE); + + if (ucast_cipher) + qdf_mem_copy(ucast_cipher, unicast, CSR_RSN_OUI_SIZE); + + if (gp_mgmt_cipher && group_mgmt_acceptable_cipher) + qdf_mem_copy(gp_mgmt_cipher, group_mgmt, + CSR_RSN_OUI_SIZE); + + if (auth_suite) + qdf_mem_copy(auth_suite, authentication, + CSR_RSN_OUI_SIZE); + + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + + if (capabilities) { + /* Bit 0 Preauthentication */ + capabilities->PreAuthSupported = + (rsn_ie->RSN_Cap[0] >> 0) & 0x1; + /* Bit 1 No Pairwise */ + capabilities->NoPairwise = + (rsn_ie->RSN_Cap[0] >> 1) & 0x1; + /* Bit 2, 3 PTKSA Replay Counter */ + capabilities->PTKSAReplayCounter = + (rsn_ie->RSN_Cap[0] >> 2) & 0x3; + /* Bit 4, 5 GTKSA Replay Counter */ + capabilities->GTKSAReplayCounter = + (rsn_ie->RSN_Cap[0] >> 4) & 0x3; +#ifdef WLAN_FEATURE_11W + /* Bit 6 MFPR */ + capabilities->MFPRequired = + (rsn_ie->RSN_Cap[0] >> 6) & 0x1; + /* Bit 7 MFPC */ + capabilities->MFPCapable = + (rsn_ie->RSN_Cap[0] >> 7) & 0x1; +#else + /* Bit 6 MFPR */ + capabilities->MFPRequired = 0; + /* Bit 7 MFPC */ + capabilities->MFPCapable = 0; +#endif + /* remaining reserved */ + capabilities->Reserved = rsn_ie->RSN_Cap[1] & 0xff; + } + } + return acceptable_cipher; +} + +#ifdef WLAN_FEATURE_11W +/** + * csr_is_pmf_capabilities_in_rsn_match() - check for PMF capability + * @mac: Global MAC Context + * @pFilterMFPEnabled: given by supplicant to us to specify what kind + * of connection supplicant is expecting to make + * if it is enabled then make PMF connection. + * if it is disabled then make normal connection. + * @pFilterMFPRequired: given by supplicant based on our configuration + * if it is 1 then we will require mandatory + * PMF connection and if it is 0 then we PMF + * connection is optional. + * @pFilterMFPCapable: given by supplicant based on our configuration + * if it 1 then we are PMF capable and if it 0 + * then we are not PMF capable. + * @pRSNIe: RSNIe from Beacon/probe response of + * neighbor AP against which we will compare + * our capabilities. + * + * This function is to match our current capabilities with the AP + * to which we are expecting make the connection. + * + * Return: if our PMF capabilities matches with AP then we + * will return true to indicate that we are good + * to make connection with it. Else we will return false + **/ +static bool +csr_is_pmf_capabilities_in_rsn_match(tpAniSirGlobal mac, + bool *pFilterMFPEnabled, + uint8_t *pFilterMFPRequired, + uint8_t *pFilterMFPCapable, + tDot11fIERSN *pRSNIe) +{ + uint8_t apProfileMFPCapable = 0; + uint8_t apProfileMFPRequired = 0; + + if (pRSNIe && pFilterMFPEnabled && pFilterMFPCapable + && pFilterMFPRequired) { + /* Extracting MFPCapable bit from RSN Ie */ + apProfileMFPCapable = csr_is_mfpc_capable(pRSNIe); + apProfileMFPRequired = (pRSNIe->RSN_Cap[0] >> 6) & 0x1; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "pFilterMFPEnabled: %d pFilterMFPRequired: %d pFilterMFPCapable: %d apProfileMFPCapable: %d apProfileMFPRequired: %d", + *pFilterMFPEnabled, *pFilterMFPRequired, + *pFilterMFPCapable, apProfileMFPCapable, + apProfileMFPRequired); + + if (*pFilterMFPEnabled && *pFilterMFPCapable + && *pFilterMFPRequired && (apProfileMFPCapable == 0)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "AP is not capable to make PMF connection"); + return false; + } else if (!(*pFilterMFPCapable) && + apProfileMFPCapable && apProfileMFPRequired) { + + /* + * In this case, AP with whom we trying to connect + * requires mandatory PMF connections and we are not + * capable so this AP is not good choice to connect + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "AP needs PMF connection and we are not capable of pmf connection"); + return false; + } + } + return true; +} +#endif + +static bool csr_is_rsn_match(tpAniSirGlobal mac_ctx, tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + bool *pMFPEnabled, uint8_t *pMFPRequired, + uint8_t *pMFPCapable, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthType, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fRSNMatch = false; + + /* See if the cyphers in the Bss description match with the + * settings in the profile. + */ + fRSNMatch = csr_get_rsn_information(mac_ctx, pAuthType, enType, + pEnMcType, &pIes->RSN, + NULL, NULL, NULL, NULL, + pNegotiatedAuthType, + pNegotiatedMCCipher, NULL, NULL); +#ifdef WLAN_FEATURE_11W + /* If all the filter matches then finally checks for PMF capabilities */ + if (fRSNMatch) + fRSNMatch = csr_is_pmf_capabilities_in_rsn_match(mac_ctx, + pMFPEnabled, + pMFPRequired, + pMFPCapable, + &pIes->RSN); +#endif + return fRSNMatch; +} + +/** + * csr_lookup_pmkid_using_ssid() - lookup pmkid using ssid and cache_id + * @mac: pointer to mac + * @session: sme session pointer + * @pmk_cache: pointer to pmk cache + * @index: index value needs to be seached + * + * Return: true if pmkid is found else false + */ +static bool csr_lookup_pmkid_using_ssid(tpAniSirGlobal mac, + struct csr_roam_session *session, + tPmkidCacheInfo *pmk_cache, + uint32_t *index) +{ + uint32_t i; + tPmkidCacheInfo *session_pmk; + + for (i = 0; i < session->NumPmkidCache; i++) { + session_pmk = &session->PmkidCacheInfo[i]; + sme_debug("match PMKID ssid %*.*s cache id %x %x ssid_len %d to ssid %s cache_id %x %x", + pmk_cache->ssid_len, pmk_cache->ssid_len, + pmk_cache->ssid, pmk_cache->cache_id[0], + pmk_cache->cache_id[1], pmk_cache->ssid_len, + session_pmk->ssid, + session_pmk->cache_id[0], session_pmk->cache_id[1]); + + if ((!qdf_mem_cmp(pmk_cache->ssid, session_pmk->ssid, + pmk_cache->ssid_len)) && + (!qdf_mem_cmp(session_pmk->cache_id, + pmk_cache->cache_id, CACHE_ID_LEN))) { + /* match found */ + *index = i; + sme_debug("PMKID found at index %d", i); + return true; + } + } + + return false; +} + +bool csr_lookup_pmkid_using_bssid(tpAniSirGlobal mac, + struct csr_roam_session *session, + tPmkidCacheInfo *pmk_cache, + uint32_t *index) +{ + uint32_t i; + tPmkidCacheInfo *session_pmk; + + for (i = 0; i < session->NumPmkidCache; i++) { + session_pmk = &session->PmkidCacheInfo[i]; + sme_debug("Matching BSSID: " MAC_ADDRESS_STR " to cached BSSID:" + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pmk_cache->BSSID.bytes), + MAC_ADDR_ARRAY(session_pmk->BSSID.bytes)); + if (qdf_is_macaddr_equal(&pmk_cache->BSSID, + &session_pmk->BSSID)) { + /* match found */ + *index = i; + sme_debug("PMKID found at index %d", i); + return true; + } + } + + return false; +} + +/** + * csr_lookup_pmkid() - lookup pmkid using bssid or ssid + cache_id + * @mac: pointer to mac + * @session: sme session pointer + * @pmk_cache: pointer to pmk cache + * @index: index value needs to be seached + * + * Return: true if pmkid is found else false + */ +static bool csr_lookup_pmkid(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCacheInfo *pmk_cache) +{ + bool fRC = false, fMatchFound = false; + uint32_t Index; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return false; + } + + if (pmk_cache->ssid_len) { + /* Try to find based on cache_id and ssid first */ + fMatchFound = csr_lookup_pmkid_using_ssid(pMac, pSession, + pmk_cache, &Index); + } + + /* If not able to find using cache id or ssid_len is not present */ + if (!fMatchFound) + fMatchFound = csr_lookup_pmkid_using_bssid(pMac, + pSession, pmk_cache, &Index); + + if (!fMatchFound) { + sme_debug("no pmkid match found NumPmkidCache = %d", + pSession->NumPmkidCache); + return false; + } + + qdf_mem_copy(pmk_cache->PMKID, + pSession->PmkidCacheInfo[Index].PMKID, + CSR_RSN_PMKID_SIZE); + + qdf_mem_copy(pmk_cache->pmk, + pSession->PmkidCacheInfo[Index].pmk, + pSession->PmkidCacheInfo[Index].pmk_len); + pmk_cache->pmk_len = pSession->PmkidCacheInfo[Index].pmk_len; + + fRC = true; + sme_debug("match = %d NumPmkidCache = %d", + fRC, pSession->NumPmkidCache); + + return fRC; +} + +#ifdef WLAN_FEATURE_FILS_SK +/* + * csr_update_pmksa_for_cache_id: update tPmkidCacheInfo to lookup using + * ssid and cache id + * @bss_desc: bss description + * @profile: csr roam profile + * @pmkid_cache: pmksa cache + * + * Return: true if cache identifier present else false + */ +static bool csr_update_pmksa_for_cache_id(tSirBssDescription *bss_desc, + struct csr_roam_profile *profile, + tPmkidCacheInfo *pmkid_cache) +{ + if (!bss_desc->fils_info_element.is_cache_id_present) + return false; + + pmkid_cache->ssid_len = + profile->SSIDs.SSIDList[0].SSID.length; + qdf_mem_copy(pmkid_cache->ssid, + profile->SSIDs.SSIDList[0].SSID.ssId, + profile->SSIDs.SSIDList[0].SSID.length); + qdf_mem_copy(pmkid_cache->cache_id, + bss_desc->fils_info_element.cache_id, + CACHE_ID_LEN); + qdf_mem_copy(pmkid_cache->BSSID.bytes, + bss_desc->bssId, QDF_MAC_ADDR_SIZE); + + return true; + +} + +/* + * csr_update_pmksa_to_profile: update pmk and pmkid to profile which will be + * used in case of fils session + * @profile: profile + * @pmkid_cache: pmksa cache + * + * Return: None + */ +static inline void csr_update_pmksa_to_profile(struct csr_roam_profile *profile, + tPmkidCacheInfo *pmkid_cache) +{ + if (!profile->fils_con_info) + return; + + profile->fils_con_info->pmk_len = pmkid_cache->pmk_len; + qdf_mem_copy(profile->fils_con_info->pmk, + pmkid_cache->pmk, pmkid_cache->pmk_len); + qdf_mem_copy(profile->fils_con_info->pmkid, + pmkid_cache->PMKID, CSR_RSN_PMKID_SIZE); + +} +#else +static inline bool csr_update_pmksa_for_cache_id(tSirBssDescription *bss_desc, + struct csr_roam_profile *profile, + tPmkidCacheInfo *pmkid_cache) +{ + return false; +} + +static inline void csr_update_pmksa_to_profile(struct csr_roam_profile *profile, + tPmkidCacheInfo *pmkid_cache) +{ +} +#endif + +/** + * csr_update_session_pmk() - Update the pmk len and pmk in the roam session + * @session: pointer to the CSR Roam session + * @pmkid_cache: pointer to the pmkid cache + * + * Return: None + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void csr_update_session_pmk(struct csr_roam_session *session, + tPmkidCacheInfo *pmkid_cache) +{ + session->pmk_len = pmkid_cache->pmk_len; + qdf_mem_zero(session->psk_pmk, sizeof(session->psk_pmk)); + qdf_mem_copy(session->psk_pmk, pmkid_cache->pmk, session->pmk_len); +} +#else +static inline void csr_update_session_pmk(struct csr_roam_session *session, + tPmkidCacheInfo *pmkid_cache) +{ +} +#endif + +uint8_t csr_construct_rsn_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe) +{ + uint32_t ret; + bool fRSNMatch; + uint8_t cbRSNIe = 0; + uint8_t UnicastCypher[CSR_RSN_OUI_SIZE]; + uint8_t MulticastCypher[CSR_RSN_OUI_SIZE]; + uint8_t gp_mgmt_cipher_suite[CSR_RSN_OUI_SIZE]; + uint8_t AuthSuite[CSR_RSN_OUI_SIZE]; + tCsrRSNAuthIe *pAuthSuite; + struct rsn_caps RSNCapabilities; + tCsrRSNPMKIe *pPMK; + tPmkidCacheInfo pmkid_cache; +#ifdef WLAN_FEATURE_11W + uint8_t *pGroupMgmtCipherSuite; +#endif + tDot11fBeaconIEs *pIesLocal = pIes; + eCsrAuthType negAuthType = eCSR_AUTH_TYPE_UNKNOWN; + tDot11fIERSN rsn_ie = {0}; + struct csr_roam_session *session = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId) || !session) + return 0; + qdf_mem_zero(&pmkid_cache, sizeof(pmkid_cache)); + qdf_mem_zero(&rsn_ie, sizeof(rsn_ie)); + + do { + if (!csr_is_profile_rsn(pProfile)) + break; + + if (!pIesLocal + && + (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + + /* + * Use intersection of the RSN cap sent by user space and + * the AP, so that only common capability are enabled. + */ + if (pProfile->pRSNReqIE && pProfile->nRSNReqIELength) { + ret = dot11f_unpack_ie_rsn(pMac, + pProfile->pRSNReqIE + 2, + pProfile->nRSNReqIELength -2, &rsn_ie, false); + if (!DOT11F_FAILED(ret)) { + pIesLocal->RSN.RSN_Cap[0] = + pIesLocal->RSN.RSN_Cap[0] & + rsn_ie.RSN_Cap[0]; + pIesLocal->RSN.RSN_Cap[1] = + pIesLocal->RSN.RSN_Cap[1] & + rsn_ie.RSN_Cap[1]; + } + } + /* See if the cyphers in the Bss description match with the + * settings in the profile. + */ + fRSNMatch = csr_get_rsn_information(pMac, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->RSN, UnicastCypher, + MulticastCypher, AuthSuite, + &RSNCapabilities, &negAuthType, NULL, + gp_mgmt_cipher_suite, + &pProfile->mgmt_encryption_type); + if (!fRSNMatch) + break; + + pRSNIe->IeHeader.ElementID = SIR_MAC_RSN_EID; + + pRSNIe->Version = CSR_RSN_VERSION_SUPPORTED; + + qdf_mem_copy(pRSNIe->MulticastOui, MulticastCypher, + sizeof(MulticastCypher)); + + pRSNIe->cUnicastCyphers = 1; + + qdf_mem_copy(&pRSNIe->UnicastOui[0], UnicastCypher, + sizeof(UnicastCypher)); + + pAuthSuite = + (tCsrRSNAuthIe *) (&pRSNIe-> + UnicastOui[pRSNIe->cUnicastCyphers]); + + pAuthSuite->cAuthenticationSuites = 1; + qdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + /* PreAuthSupported is an AP only capability */ + RSNCapabilities.PreAuthSupported = 0; + /* + * Use the Management Frame Protection values given by the + * supplicant, if AP and STA both are MFP capable. + */ +#ifdef WLAN_FEATURE_11W + if (RSNCapabilities.MFPCapable && pProfile->MFPCapable) { + RSNCapabilities.MFPCapable = pProfile->MFPCapable; + RSNCapabilities.MFPRequired = pProfile->MFPRequired; + } else { + RSNCapabilities.MFPCapable = 0; + RSNCapabilities.MFPRequired = 0; + } +#endif + *(uint16_t *) (&pAuthSuite->AuthOui[1]) = + *((uint16_t *) (&RSNCapabilities)); + + pPMK = (tCsrRSNPMKIe *) (((uint8_t *) (&pAuthSuite->AuthOui[1])) + + sizeof(uint16_t)); + + if (!csr_update_pmksa_for_cache_id(pSirBssDesc, + pProfile, &pmkid_cache)) + qdf_mem_copy(pmkid_cache.BSSID.bytes, + pSirBssDesc->bssId, QDF_MAC_ADDR_SIZE); + /* Don't include the PMK SA IDs for CCKM associations. */ + if ( +#ifdef FEATURE_WLAN_ESE + (eCSR_AUTH_TYPE_CCKM_RSN != negAuthType) && +#endif + csr_lookup_pmkid(pMac, sessionId, &pmkid_cache)) { + pPMK->cPMKIDs = 1; + + qdf_trace_hex_dump(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_INFO, + pmkid_cache.pmk, pmkid_cache.pmk_len); + qdf_mem_copy(pPMK->PMKIDList[0].PMKID, + pmkid_cache.PMKID, + CSR_RSN_PMKID_SIZE); + + /* + * 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. + */ + csr_update_session_pmk(session, &pmkid_cache); + + csr_update_pmksa_to_profile(pProfile, &pmkid_cache); + } else { + pPMK->cPMKIDs = 0; + } + session->rsn_caps = RSNCapabilities; + + qdf_mem_zero(&pmkid_cache, sizeof(pmkid_cache)); + +#ifdef WLAN_FEATURE_11W + /* Advertise BIP in group cipher key management only if PMF is + * enabled and AP is capable. + */ + if (pProfile->MFPEnabled && + (RSNCapabilities.MFPCapable && pProfile->MFPCapable)) { + pGroupMgmtCipherSuite = + (uint8_t *) pPMK + sizeof(uint16_t) + + (pPMK->cPMKIDs * CSR_RSN_PMKID_SIZE); + qdf_mem_copy(pGroupMgmtCipherSuite, + gp_mgmt_cipher_suite, CSR_RSN_OUI_SIZE); + } +#endif + host_log_rsn_info(UnicastCypher, MulticastCypher, + AuthSuite, gp_mgmt_cipher_suite); + + /* Add in the fixed fields plus 1 Unicast cypher, less the + * IE Header length Add in the size of the Auth suite (count + * plus a single OUI) Add in the RSN caps field. + * Add PMKID count and PMKID (if any) + * Add group management cipher suite + */ + pRSNIe->IeHeader.Length = + (uint8_t) (sizeof(*pRSNIe) - sizeof(pRSNIe->IeHeader) + + sizeof(*pAuthSuite) + + sizeof(struct rsn_caps)); + if (pPMK->cPMKIDs) + pRSNIe->IeHeader.Length += (uint8_t) (sizeof(uint16_t) + + (pPMK->cPMKIDs * + CSR_RSN_PMKID_SIZE)); +#ifdef WLAN_FEATURE_11W + if (pProfile->MFPEnabled && + (RSNCapabilities.MFPCapable && pProfile->MFPCapable)) { + if (0 == pPMK->cPMKIDs) + pRSNIe->IeHeader.Length += sizeof(uint16_t); + pRSNIe->IeHeader.Length += CSR_WPA_OUI_SIZE; + } +#endif + + /* return the size of the IE header (total) constructed... */ + cbRSNIe = pRSNIe->IeHeader.Length + sizeof(pRSNIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) + /* locally allocated */ + qdf_mem_free(pIesLocal); + + return cbRSNIe; +} + +#ifdef FEATURE_WLAN_WAPI +/** + * csr_get_wapi_information() - to get WAPI information + * @mac_ctx: pointer to global MAC context + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @wapi_ie: pointer to WAPI IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all WAPI information + * + * Return: bool + */ +static bool csr_get_wapi_information(tpAniSirGlobal mac_ctx, + tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIEWAPI *wapi_ie, + uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0, i; + uint8_t unicast[CSR_WAPI_OUI_SIZE]; + uint8_t multicast[CSR_WAPI_OUI_SIZE]; + uint8_t authsuites[CSR_WAPI_MAX_AUTH_SUITES][CSR_WAPI_OUI_SIZE]; + uint8_t authentication[CSR_WAPI_OUI_SIZE]; + uint8_t mccipher_arr[CSR_WAPI_MAX_MULTICAST_CYPHERS][CSR_WAPI_OUI_SIZE]; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + uint8_t wapioui_idx = 0; + + if (!wapi_ie->present) + goto end; + + c_mcast_cipher++; + qdf_mem_copy(mccipher_arr, wapi_ie->multicast_cipher_suite, + CSR_WAPI_OUI_SIZE); + c_ucast_cipher = (uint8_t) (wapi_ie->unicast_cipher_suite_count); + c_auth_suites = (uint8_t) (wapi_ie->akm_suite_count); + for (i = 0; i < c_auth_suites && i < CSR_WAPI_MAX_AUTH_SUITES; i++) + qdf_mem_copy((void *)&authsuites[i], + (void *)&wapi_ie->akm_suites[i], CSR_WAPI_OUI_SIZE); + + wapioui_idx = csr_get_oui_index_from_cipher(encr_type); + if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) { + sme_err("Wapi OUI index = %d out of limit", + wapioui_idx); + acceptable_cipher = false; + goto end; + } + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_wapi_oui_index(mac_ctx, + wapi_ie->unicast_cipher_suites, + c_ucast_cipher, wapioui_idx, unicast); + if (!acceptable_cipher) + goto end; + + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + wapioui_idx = csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]); + if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) { + sme_err("Wapi OUI index = %d out of limit", + wapioui_idx); + acceptable_cipher = false; + break; + } + acceptable_cipher = csr_match_wapi_oui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + wapioui_idx, multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = + mc_encryption->encryptionType[i]; + + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype + */ + if (csr_is_auth_wapi_cert + (mac_ctx, authsuites, c_auth_suites, authentication)) { + neg_authtype = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + } else if (csr_is_auth_wapi_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + neg_authtype = eCSR_AUTH_TYPE_WAPI_WAI_PSK; + } else { + acceptable_cipher = false; + neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + } + + /* Caller doesn't care about auth type, or BSS doesn't match */ + if ((0 == auth_type->numEntries) || (false == acceptable_cipher)) + goto end; + + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + if (auth_type->authType[i] == neg_authtype) { + acceptable_cipher = true; + break; + } + } + +end: + if (acceptable_cipher) { + if (mcast_cipher) + qdf_mem_copy(mcast_cipher, multicast, + CSR_WAPI_OUI_SIZE); + if (ucast_cipher) + qdf_mem_copy(ucast_cipher, unicast, CSR_WAPI_OUI_SIZE); + if (auth_suite) + qdf_mem_copy(auth_suite, authentication, + CSR_WAPI_OUI_SIZE); + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + } + return acceptable_cipher; +} + +static bool csr_is_wapi_match(tpAniSirGlobal mac_ctx, tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthType, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fWapiMatch = false; + + /* See if the cyphers in the Bss description match with the + * settings in the profile. + */ + fWapiMatch = + csr_get_wapi_information(mac_ctx, pAuthType, enType, pEnMcType, + &pIes->WAPI, NULL, NULL, NULL, + pNegotiatedAuthType, + pNegotiatedMCCipher); + + return fWapiMatch; +} + +static bool csr_lookup_bkid(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pBSSId, uint8_t *pBKId) +{ + bool fRC = false, fMatchFound = false; + uint32_t Index; + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return false; + } + + do { + for (Index = 0; Index < pSession->NumBkidCache; Index++) { + sme_debug("match BKID " MAC_ADDRESS_STR " to ", + MAC_ADDR_ARRAY(pBSSId)); + if (!qdf_mem_cmp + (pBSSId, pSession->BkidCacheInfo[Index].BSSID.bytes, + sizeof(struct qdf_mac_addr))) { + /* match found */ + fMatchFound = true; + break; + } + } + + if (!fMatchFound) + break; + + qdf_mem_copy(pBKId, pSession->BkidCacheInfo[Index].BKID, + CSR_WAPI_BKID_SIZE); + + fRC = true; + } while (0); + sme_debug( + "csr_lookup_bkid called return match = %d pMac->roam.NumBkidCache = %d", + fRC, pSession->NumBkidCache); + + return fRC; +} + +uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe) +{ + bool fWapiMatch = false; + uint8_t cbWapiIe = 0; + uint8_t UnicastCypher[CSR_WAPI_OUI_SIZE]; + uint8_t MulticastCypher[CSR_WAPI_OUI_SIZE]; + uint8_t AuthSuite[CSR_WAPI_OUI_SIZE]; + uint8_t BKId[CSR_WAPI_BKID_SIZE]; + uint8_t *pWapi = NULL; + bool fBKIDFound = false; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!csr_is_profile_wapi(pProfile)) + break; + + if (!pIesLocal + && + (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + /* See if the cyphers in the Bss description match with the + * settings in the profile. + */ + fWapiMatch = + csr_get_wapi_information(pMac, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->WAPI, UnicastCypher, + MulticastCypher, AuthSuite, NULL, + NULL); + if (!fWapiMatch) + break; + + qdf_mem_zero(pWapiIe, sizeof(tCsrWapiIe)); + + pWapiIe->IeHeader.ElementID = DOT11F_EID_WAPI; + + pWapiIe->Version = CSR_WAPI_VERSION_SUPPORTED; + + pWapiIe->cAuthenticationSuites = 1; + qdf_mem_copy(&pWapiIe->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + pWapi = (uint8_t *) (&pWapiIe->AuthOui[1]); + + *pWapi = (uint16_t) 1; /* cUnicastCyphers */ + pWapi += 2; + qdf_mem_copy(pWapi, UnicastCypher, sizeof(UnicastCypher)); + pWapi += sizeof(UnicastCypher); + + qdf_mem_copy(pWapi, MulticastCypher, sizeof(MulticastCypher)); + pWapi += sizeof(MulticastCypher); + + /* WAPI capabilities follows the Auth Suite (two octects) + * we shouldn't EVER be sending out "pre-auth supported". + * It is an AP only capability & since we already did a memset + * pWapiIe to 0, skip these fields + */ + pWapi += 2; + + fBKIDFound = + csr_lookup_bkid(pMac, sessionId, pSirBssDesc->bssId, + &(BKId[0])); + + if (fBKIDFound) { + /* Do we need to change the endianness here */ + *pWapi = (uint16_t) 1; /* cBKIDs */ + pWapi += 2; + qdf_mem_copy(pWapi, BKId, CSR_WAPI_BKID_SIZE); + } else { + *pWapi = 0; + pWapi += 1; + *pWapi = 0; + pWapi += 1; + } + + /* Add in the IE fields except the IE header */ + /* Add BKID count and BKID (if any) */ + pWapiIe->IeHeader.Length = + (uint8_t) (sizeof(*pWapiIe) - + sizeof(pWapiIe->IeHeader)); + + /*2 bytes for BKID Count field */ + pWapiIe->IeHeader.Length += sizeof(uint16_t); + + if (fBKIDFound) + pWapiIe->IeHeader.Length += CSR_WAPI_BKID_SIZE; + + /* return the size of the IE header (total) constructed... */ + cbWapiIe = pWapiIe->IeHeader.Length + sizeof(pWapiIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) + /* locally allocated */ + qdf_mem_free(pIesLocal); + + return cbWapiIe; +} +#endif /* FEATURE_WLAN_WAPI */ + +/** + * csr_get_wpa_cyphers() - to get WPA cipher info + * @mac_ctx: pointer to mac context + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @wpa_ie: pointer to WPA IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all WPA information + * + * Return: bool + */ +static bool csr_get_wpa_cyphers(tpAniSirGlobal mac_ctx, tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIEWPA *wpa_ie, uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0; + uint8_t unicast[CSR_WPA_OUI_SIZE]; + uint8_t multicast[CSR_WPA_OUI_SIZE]; + uint8_t authentication[CSR_WPA_OUI_SIZE]; + uint8_t mccipher_arr[1][CSR_WPA_OUI_SIZE]; + uint8_t i; + uint8_t index; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + + if (!wpa_ie->present) + goto end; + c_mcast_cipher = 1; + qdf_mem_copy(mccipher_arr, wpa_ie->multicast_cipher, CSR_WPA_OUI_SIZE); + c_ucast_cipher = (uint8_t) (wpa_ie->unicast_cipher_count); + c_auth_suites = (uint8_t) (wpa_ie->auth_suite_count); + + /* + * csr_match_wpaoui_index will provide the index of the + * array csr_wpa_oui to be read and determine if it is + * accepatable cipher or not. Below check ensures that + * the index will not be out of range of the array size. + */ + index = csr_get_oui_index_from_cipher(encr_type); + if (!(index < (sizeof(csr_wpa_oui)/CSR_WPA_OUI_SIZE))) { + sme_debug("Unacceptable index: %d", index); + goto end; + } + + sme_debug("kw_dbg: index: %d", index); + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_wpaoui_index(mac_ctx, + wpa_ie->unicast_ciphers, c_ucast_cipher, + index, unicast); + if (!acceptable_cipher) + goto end; + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + index = csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]); + sme_debug("kw_dbg: index: %d", index); + if (!(index < (sizeof(csr_wpa_oui)/CSR_WPA_OUI_SIZE))) { + sme_debug("Unacceptable MC index: %d", index); + acceptable_cipher = false; + continue; + } + acceptable_cipher = csr_match_wpaoui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + index, multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = mc_encryption->encryptionType[i]; + + /* Initializing with false as it has true value already */ + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype + */ + if (csr_is_auth_wpa(mac_ctx, wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_WPA == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_WPA; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_wpa_psk(mac_ctx, + wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_WPA_PSK == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_WPA_PSK; + } +#ifdef FEATURE_WLAN_ESE + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_ese_cckm_auth_wpa(mac_ctx, + wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_CCKM_WPA == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_CCKM_WPA; + } +#endif /* FEATURE_WLAN_ESE */ + + /* + * The 1st auth type in the APs WPA IE, to match stations + * connecting profiles auth type will cause us to exit this + * loop. This is added as some APs advertise multiple akms in + * the WPA IE + */ + if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) { + acceptable_cipher = true; + break; + } + } + +end: + if (acceptable_cipher) { + if (mcast_cipher) + qdf_mem_copy((uint8_t **) mcast_cipher, multicast, + CSR_WPA_OUI_SIZE); + + if (ucast_cipher) + qdf_mem_copy((uint8_t **) ucast_cipher, unicast, + CSR_WPA_OUI_SIZE); + + if (auth_suite) + qdf_mem_copy((uint8_t **) auth_suite, authentication, + CSR_WPA_OUI_SIZE); + + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + } + + return acceptable_cipher; +} + +static bool csr_is_wpa_encryption_match(tpAniSirGlobal pMac, + tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthtype, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fWpaMatch = false; + + /* See if the cyphers in the Bss description match with the + * settings in the profile. + */ + fWpaMatch = + csr_get_wpa_cyphers(pMac, pAuthType, enType, pEnMcType, + &pIes->WPA, + NULL, NULL, NULL, pNegotiatedAuthtype, + pNegotiatedMCCipher); + + return fWpaMatch; +} + +uint8_t csr_construct_wpa_ie(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe) +{ + bool fWpaMatch; + uint8_t cbWpaIe = 0; + uint8_t UnicastCypher[CSR_WPA_OUI_SIZE]; + uint8_t MulticastCypher[CSR_WPA_OUI_SIZE]; + uint8_t AuthSuite[CSR_WPA_OUI_SIZE]; + tCsrWpaAuthIe *pAuthSuite; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!csr_is_profile_wpa(pProfile)) + break; + + if (!pIesLocal + && + (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) + break; + /* See if the cyphers in the Bss description match with the + * settings in the profile. + */ + fWpaMatch = + csr_get_wpa_cyphers(pMac, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->WPA, UnicastCypher, + MulticastCypher, AuthSuite, NULL, NULL); + if (!fWpaMatch) + break; + + pWpaIe->IeHeader.ElementID = SIR_MAC_WPA_EID; + + qdf_mem_copy(pWpaIe->Oui, csr_wpa_oui[01], sizeof(pWpaIe->Oui)); + + pWpaIe->Version = CSR_WPA_VERSION_SUPPORTED; + + qdf_mem_copy(pWpaIe->MulticastOui, MulticastCypher, + sizeof(MulticastCypher)); + + pWpaIe->cUnicastCyphers = 1; + + qdf_mem_copy(&pWpaIe->UnicastOui[0], UnicastCypher, + sizeof(UnicastCypher)); + + pAuthSuite = + (tCsrWpaAuthIe *) (&pWpaIe-> + UnicastOui[pWpaIe->cUnicastCyphers]); + + pAuthSuite->cAuthenticationSuites = 1; + qdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + /* The WPA capabilities follows the Auth Suite (two octects)- + * this field is optional, and we always "send" zero, so just + * remove it. This is consistent with our assumptions in the + * frames compiler; c.f. bug 15234: + * http://gold.woodsidenet.com/bugzilla/show_bug.cgi?id=15234 + * Add in the fixed fields plus 1 Unicast cypher, less the IE + * Header length Add in the size of the Auth suite (count plus + * a single OUI) + */ + pWpaIe->IeHeader.Length = + sizeof(*pWpaIe) - sizeof(pWpaIe->IeHeader) + + sizeof(*pAuthSuite); + + /* return the size of the IE header (total) constructed... */ + cbWpaIe = pWpaIe->IeHeader.Length + sizeof(pWpaIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) + /* locally allocated */ + qdf_mem_free(pIesLocal); + + return cbWpaIe; +} + +/* If a WPAIE exists in the profile, just use it. Or else construct + * one from the BSS Caller allocated memory for pWpaIe and guarrantee + * it can contain a max length WPA IE + */ +uint8_t csr_retrieve_wpa_ie(tpAniSirGlobal pMac, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe) +{ + uint8_t cbWpaIe = 0; + + do { + if (!csr_is_profile_wpa(pProfile)) + break; + if (pProfile->nWPAReqIELength && pProfile->pWPAReqIE) { + if (pProfile->nWPAReqIELength <= + DOT11F_IE_RSN_MAX_LEN) { + cbWpaIe = (uint8_t) pProfile->nWPAReqIELength; + qdf_mem_copy(pWpaIe, pProfile->pWPAReqIE, + cbWpaIe); + } else + sme_warn("csr_retrieve_wpa_ie detect invalid WPA IE length (%d)", + pProfile->nWPAReqIELength); + } else + cbWpaIe = csr_construct_wpa_ie(pMac, pProfile, + pSirBssDesc, pIes, pWpaIe); + } while (0); + + return cbWpaIe; +} + +#ifdef WLAN_FEATURE_11W +/** + * csr_get_mc_mgmt_cipher(): Get mcast management cipher from profile rsn + * @mac: mac ctx + * @profile: connect profile + * @bss: ap scan entry + * @ap_ie: AP IE's + * + * Return: none + */ +static void csr_get_mc_mgmt_cipher(tpAniSirGlobal mac, + struct csr_roam_profile *profile, + tSirBssDescription *bss, + tDot11fBeaconIEs *ap_ie) +{ + int ret; + tDot11fIERSN rsn_ie = {0}; + uint8_t n_mgmt_cipher = 1; + struct rsn_caps rsn_caps; + tDot11fBeaconIEs *local_ap_ie = ap_ie; + uint8_t grp_mgmt_arr[CSR_RSN_MAX_MULTICAST_CYPHERS][CSR_RSN_OUI_SIZE]; + + if (!profile->MFPEnabled) + return; + + if (!local_ap_ie && + (!QDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies + (mac, bss, &local_ap_ie)))) + return; + + qdf_mem_copy(&rsn_caps, local_ap_ie->RSN.RSN_Cap, sizeof(rsn_caps)); + + if (!ap_ie && local_ap_ie) + /* locally allocated */ + qdf_mem_free(local_ap_ie); + + /* if AP is not PMF capable return */ + if (!rsn_caps.MFPCapable) + return; + + ret = dot11f_unpack_ie_rsn(mac, profile->pRSNReqIE + 2, + profile->nRSNReqIELength -2, + &rsn_ie, false); + if (DOT11F_FAILED(ret)) + return; + + qdf_mem_copy(&rsn_caps, rsn_ie.RSN_Cap, sizeof(rsn_caps)); + + /* if self cap is not PMF capable return */ + if (!rsn_caps.MFPCapable) + return; + + qdf_mem_copy(grp_mgmt_arr, rsn_ie.gp_mgmt_cipher_suite, + CSR_RSN_OUI_SIZE); + if (csr_is_group_mgmt_gmac_128(mac, grp_mgmt_arr, n_mgmt_cipher, NULL)) + profile->mgmt_encryption_type = eSIR_ED_AES_GMAC_128; + else if (csr_is_group_mgmt_gmac_256(mac, grp_mgmt_arr, + n_mgmt_cipher, NULL)) + profile->mgmt_encryption_type = eSIR_ED_AES_GMAC_256; + else + /* Default is CMAC */ + profile->mgmt_encryption_type = eSIR_ED_AES_128_CMAC; +} +#else +static inline +void csr_get_mc_mgmt_cipher(tpAniSirGlobal mac, + struct csr_roam_profile *profile, + tSirBssDescription *bss, + tDot11fBeaconIEs *ap_ie) +{ +} +#endif +/* If a RSNIE exists in the profile, just use it. Or else construct + * one from the BSS Caller allocated memory for pWpaIe and guarrantee + * it can contain a max length WPA IE + */ +uint8_t csr_retrieve_rsn_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe) +{ + uint8_t cbRsnIe = 0; + + do { + if (!csr_is_profile_rsn(pProfile)) + break; + /* copy RSNIE from user as it is if test mode is enabled */ + if (pProfile->force_rsne_override && + pProfile->nRSNReqIELength && pProfile->pRSNReqIE) { + sme_debug("force_rsne_override, copy RSN IE provided by user"); + if (pProfile->nRSNReqIELength <= + DOT11F_IE_RSN_MAX_LEN) { + cbRsnIe = (uint8_t) pProfile->nRSNReqIELength; + qdf_mem_copy(pRsnIe, pProfile->pRSNReqIE, + cbRsnIe); + csr_get_mc_mgmt_cipher(pMac, pProfile, + pSirBssDesc, pIes); + } else { + sme_warn("csr_retrieve_rsn_ie detect invalid RSN IE length (%d)", + pProfile->nRSNReqIELength); + } + break; + } + + cbRsnIe = csr_construct_rsn_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pRsnIe); + } while (0); + + return cbRsnIe; +} + +#ifdef FEATURE_WLAN_WAPI +/* If a WAPI IE exists in the profile, just use it. Or else construct + * one from the BSS Caller allocated memory for pWapiIe and guarrantee + * it can contain a max length WAPI IE + */ +uint8_t csr_retrieve_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + struct csr_roam_profile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe) +{ + uint8_t cbWapiIe = 0; + + do { + if (!csr_is_profile_wapi(pProfile)) + break; + if (pProfile->nWAPIReqIELength && pProfile->pWAPIReqIE) { + if (DOT11F_IE_WAPI_MAX_LEN >= + pProfile->nWAPIReqIELength) { + cbWapiIe = (uint8_t) pProfile->nWAPIReqIELength; + qdf_mem_copy(pWapiIe, pProfile->pWAPIReqIE, + cbWapiIe); + } else + sme_warn("csr_retrieve_wapi_ie detect invalid WAPI IE length (%d)", + pProfile->nWAPIReqIELength); + } else + cbWapiIe = + csr_construct_wapi_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pWapiIe); + } while (0); + + return cbWapiIe; +} +#endif /* FEATURE_WLAN_WAPI */ + +bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate) +{ + bool fSupported = false; + uint16_t nonBasicRate = + (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK)); + + switch (nonBasicRate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_11Mbps: + fSupported = true; + break; + + default: + break; + } + + return fSupported; +} + +bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate) +{ + bool fSupported = false; + uint16_t nonBasicRate = + (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK)); + + switch (nonBasicRate) { + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + fSupported = true; + break; + + default: + break; + } + + return fSupported; +} + +tAniEdType csr_translate_encrypt_type_to_ed_type(eCsrEncryptionType EncryptType) +{ + tAniEdType edType; + + switch (EncryptType) { + default: + case eCSR_ENCRYPT_TYPE_NONE: + edType = eSIR_ED_NONE; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + edType = eSIR_ED_WEP40; + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + edType = eSIR_ED_WEP104; + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + edType = eSIR_ED_TKIP; + break; + + case eCSR_ENCRYPT_TYPE_AES: + edType = eSIR_ED_CCMP; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + edType = eSIR_ED_WPI; + break; +#endif +#ifdef WLAN_FEATURE_11W + /* 11w BIP */ + case eCSR_ENCRYPT_TYPE_AES_CMAC: + edType = eSIR_ED_AES_128_CMAC; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP: + edType = eSIR_ED_GCMP; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + edType = eSIR_ED_GCMP_256; + break; + case eCSR_ENCRYPT_TYPE_AES_GMAC_128: + edType = eSIR_ED_AES_GMAC_128; + break; + case eCSR_ENCRYPT_TYPE_AES_GMAC_256: + edType = eSIR_ED_AES_GMAC_256; + break; +#endif + } + + return edType; +} + +/** + * csr_validate_wep() - to validate wep + * @uc_encry_type: unicast encryption type + * @auth_list: Auth list + * @mc_encryption_list: multicast encryption type + * @negotiated_authtype: negotiated auth type + * @negotiated_mc_encry: negotiated mc encry type + * @bss_descr: BSS description + * @ie_ptr: IE pointer + * + * This function just checks whether HDD is giving correct values for + * Multicast cipher and Auth + * + * Return: bool + */ +static bool csr_validate_wep(tpAniSirGlobal mac_ctx, + eCsrEncryptionType uc_encry_type, + tCsrAuthList *auth_list, + tCsrEncryptionList *mc_encryption_list, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mc_encry, + tSirBssDescription *bss_descr, + tDot11fBeaconIEs *ie_ptr) +{ + uint32_t idx; + bool match = false; + eCsrAuthType negotiated_auth = eCSR_AUTH_TYPE_OPEN_SYSTEM; + eCsrEncryptionType negotiated_mccipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + uint8_t oui_index; + + /* If privacy bit is not set, consider no match */ + if (!csr_is_privacy(bss_descr)) + goto end; + + for (idx = 0; idx < mc_encryption_list->numEntries; idx++) { + switch (mc_encryption_list->encryptionType[idx]) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + /* + * Multicast list may contain WEP40/WEP104. + * Check whether it matches UC. + */ + if (uc_encry_type == + mc_encryption_list->encryptionType[idx]) { + match = true; + negotiated_mccipher = + mc_encryption_list->encryptionType[idx]; + } + break; + default: + match = false; + break; + } + if (match) + break; + } + + if (!match) + goto end; + + for (idx = 0; idx < auth_list->numEntries; idx++) { + switch (auth_list->authType[idx]) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + case eCSR_AUTH_TYPE_SHARED_KEY: + case eCSR_AUTH_TYPE_AUTOSWITCH: + match = true; + negotiated_auth = auth_list->authType[idx]; + break; + default: + match = false; + } + if (match) + break; + } + + if (!match) + goto end; + + if (!ie_ptr) + goto end; + + /* + * In case of WPA / WPA2, check whether it supports WEP as well. + * Prepare the encryption type for WPA/WPA2 functions + */ + if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == uc_encry_type) + uc_encry_type = eCSR_ENCRYPT_TYPE_WEP40; + else if (eCSR_ENCRYPT_TYPE_WEP104 == uc_encry_type) + uc_encry_type = eCSR_ENCRYPT_TYPE_WEP104; + + /* else we can use the encryption type directly */ + if (ie_ptr->WPA.present) { + oui_index = csr_get_oui_index_from_cipher(uc_encry_type); + if (oui_index < QDF_ARRAY_SIZE(csr_wpa_oui)) + match = (!qdf_mem_cmp(ie_ptr->WPA.multicast_cipher, + csr_wpa_oui[oui_index], + CSR_WPA_OUI_SIZE)); + if (match) + goto end; + } + if (ie_ptr->RSN.present) { + match = (!qdf_mem_cmp(ie_ptr->RSN.gp_cipher_suite, + csr_rsn_oui[csr_get_oui_index_from_cipher( + uc_encry_type)], + CSR_RSN_OUI_SIZE)); + } + + +end: + if (match) { + if (negotiated_authtype) + *negotiated_authtype = negotiated_auth; + if (negotiated_mc_encry) + *negotiated_mc_encry = negotiated_mccipher; + } + return match; +} + +/** + * csr_validate_open_none() - Check if the security is matching + * @bss_desc: BSS Descriptor on which the check is done + * @mc_enc_type: Multicast encryption type + * @mc_cipher: Multicast Cipher + * @auth_type: Authentication type + * @neg_auth_type: Negotiated Auth type with the AP + * + * Return: Boolean value to tell if matched or not. + */ +static bool csr_validate_open_none(tSirBssDescription *bss_desc, + tCsrEncryptionList *mc_enc_type, eCsrEncryptionType *mc_cipher, + tCsrAuthList *auth_type, eCsrAuthType *neg_auth_type) +{ + bool match; + uint8_t idx; + + /* + * for NO encryption, if the Bss description has the + * Privacy bit turned on, then encryption is required + * so we have to reject this Bss. + */ + if (csr_is_privacy(bss_desc)) + match = false; + else + match = true; + if (match) { + match = false; + /* Check MC cipher and Auth type requested. */ + for (idx = 0; idx < mc_enc_type->numEntries; idx++) { + if (eCSR_ENCRYPT_TYPE_NONE == + mc_enc_type->encryptionType[idx]) { + match = true; + *mc_cipher = mc_enc_type->encryptionType[idx]; + break; + } + } + if (!match) + return match; + + match = false; + /* Check Auth list. It should contain AuthOpen. */ + for (idx = 0; idx < auth_type->numEntries; idx++) { + if ((eCSR_AUTH_TYPE_OPEN_SYSTEM == + auth_type->authType[idx]) || + (eCSR_AUTH_TYPE_AUTOSWITCH == + auth_type->authType[idx])) { + match = true; + *neg_auth_type = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + } + } + if (!match) + return match; + + } + return match; +} + +/** + * csr_validate_any_default() - Check if the security is matching + * @mac_ctx: Global MAC context + * @auth_type: Authentication type + * @mc_enc_type: Multicast encryption type + * @mfp_enabled: Management frame protection feature + * @mfp_required: Management frame protection mandatory + * @mfp_capable: Device capable of MFP + * @ies_ptr: Pointer to the IE fields + * @neg_auth_type: Negotiated Auth type with the AP + * @bss_desc: BSS Descriptor + * @neg_uc_cipher: Negotiated unicast cipher suite + * @neg_mc_cipher: Negotiated multicast cipher + * + * Return: Boolean value to tell if matched or not. + */ +static bool csr_validate_any_default(tpAniSirGlobal mac_ctx, + tCsrAuthList *auth_type, + tCsrEncryptionList *mc_enc_type, + bool *mfp_enabled, + uint8_t *mfp_required, + uint8_t *mfp_capable, + tDot11fBeaconIEs *ies_ptr, + eCsrAuthType *neg_auth_type, + tSirBssDescription *bss_desc, + eCsrEncryptionType *uc_cipher, + eCsrEncryptionType *mc_cipher) +{ + bool match_any = false; + bool match = true; + /* It is allowed to match anything. Try the more secured ones first. */ + if (ies_ptr) { + /* Check GCMP-256 first */ + *uc_cipher = eCSR_ENCRYPT_TYPE_AES_GCMP_256; + match_any = csr_is_rsn_match(mac_ctx, auth_type, + *uc_cipher, mc_enc_type, mfp_enabled, + mfp_required, mfp_capable, ies_ptr, + neg_auth_type, mc_cipher); + /* Check GCMP second */ + *uc_cipher = eCSR_ENCRYPT_TYPE_AES_GCMP; + match_any = csr_is_rsn_match(mac_ctx, auth_type, + *uc_cipher, mc_enc_type, mfp_enabled, + mfp_required, mfp_capable, ies_ptr, + neg_auth_type, mc_cipher); + /* Check AES third */ + *uc_cipher = eCSR_ENCRYPT_TYPE_AES; + match_any = csr_is_rsn_match(mac_ctx, auth_type, + *uc_cipher, mc_enc_type, mfp_enabled, + mfp_required, mfp_capable, ies_ptr, + neg_auth_type, mc_cipher); + if (!match_any) { + /* Check TKIP */ + *uc_cipher = eCSR_ENCRYPT_TYPE_TKIP; + match_any = csr_is_rsn_match(mac_ctx, auth_type, + *uc_cipher, + mc_enc_type, mfp_enabled, mfp_required, + mfp_capable, ies_ptr, neg_auth_type, + mc_cipher); + } +#ifdef FEATURE_WLAN_WAPI + if (!match_any) { + /* Check WAPI */ + *uc_cipher = eCSR_ENCRYPT_TYPE_WPI; + match_any = csr_is_wapi_match(mac_ctx, auth_type, + *uc_cipher, mc_enc_type, ies_ptr, + neg_auth_type, mc_cipher); + } +#endif + } + if (match_any) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + /* It must be open and no enc */ + if (csr_is_privacy(bss_desc)) { + match = false; + return match; + } + + *neg_auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + *mc_cipher = eCSR_ENCRYPT_TYPE_NONE; + *uc_cipher = eCSR_ENCRYPT_TYPE_NONE; + return match; + +} + +/** + * csr_is_security_match() - Check if the security is matching + * @mac_ctx: Global MAC context + * @auth_type: Authentication type + * @uc_enc_type: Unicast Encryption type + * @mc_enc_type: Multicast encryption type + * @mfp_enabled: Management frame protection feature + * @mfp_required: Management frame protection mandatory + * @mfp_capable: Device capable of MFP + * @bss_desc: BSS Descriptor + * @ies_ptr: Pointer to the IE fields + * @neg_auth_type: Negotiated Auth type with the AP + * @neg_uc_cipher: Negotiated unicast cipher suite + * @neg_mc_cipher: Negotiated multicast cipher + * + * Return: Boolean value to tell if matched or not. + */ +bool csr_is_security_match(tpAniSirGlobal mac_ctx, tCsrAuthList *auth_type, + tCsrEncryptionList *uc_enc_type, + tCsrEncryptionList *mc_enc_type, bool *mfp_enabled, + uint8_t *mfp_required, uint8_t *mfp_capable, + tSirBssDescription *bss_desc, tDot11fBeaconIEs *ies_ptr, + eCsrAuthType *neg_auth_type, + eCsrEncryptionType *neg_uc_cipher, + eCsrEncryptionType *neg_mc_cipher) +{ + bool match = false; + uint8_t i; + eCsrEncryptionType mc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + eCsrEncryptionType uc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + eCsrAuthType local_neg_auth_type = eCSR_AUTH_TYPE_UNKNOWN; + + for (i = 0; ((i < uc_enc_type->numEntries) && (!match)); i++) { + uc_cipher = uc_enc_type->encryptionType[i]; + /* + * If the Bss description shows the Privacy bit is on, then we + * must have some sort of encryption configured for the profile + * to work. Don't attempt to join networks with Privacy bit + * set when profiles say NONE for encryption type. + */ + switch (uc_cipher) { + case eCSR_ENCRYPT_TYPE_NONE: + match = csr_validate_open_none(bss_desc, mc_enc_type, + &mc_cipher, auth_type, + &local_neg_auth_type); + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + /* + * !! might want to check for WEP keys set in the + * Profile.... ? !! don't need to have the privacy bit + * in the Bss description. Many AP policies make + * legacy encryption 'optional' so we don't know if we + * can associate or not. The AP will reject if + * encryption is not allowed without the Privacy bit + * turned on. + */ + match = csr_validate_wep(mac_ctx, uc_cipher, auth_type, + mc_enc_type, &local_neg_auth_type, + &mc_cipher, bss_desc, ies_ptr); + + break; + /* these are all of the WPA encryption types... */ + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + match = csr_validate_wep(mac_ctx, uc_cipher, auth_type, + mc_enc_type, &local_neg_auth_type, + &mc_cipher, bss_desc, ies_ptr); + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + case eCSR_ENCRYPT_TYPE_AES_GCMP: + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + if (!ies_ptr) { + match = false; + break; + } + /* First check if there is a RSN match */ + match = csr_is_rsn_match(mac_ctx, auth_type, + uc_cipher, mc_enc_type, + mfp_enabled, mfp_required, + mfp_capable, ies_ptr, + &local_neg_auth_type, + &mc_cipher); + /* If not RSN, then check WPA match */ + if (!match) + match = csr_is_wpa_encryption_match( + mac_ctx, auth_type, + uc_cipher, mc_enc_type, + ies_ptr, + &local_neg_auth_type, + &mc_cipher); + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: /* WAPI */ + if (ies_ptr) + match = csr_is_wapi_match(mac_ctx, auth_type, + uc_cipher, mc_enc_type, ies_ptr, + &local_neg_auth_type, + &mc_cipher); + else + match = false; + break; +#endif /* FEATURE_WLAN_WAPI */ + case eCSR_ENCRYPT_TYPE_ANY: + default: + match = csr_validate_any_default(mac_ctx, auth_type, + mc_enc_type, mfp_enabled, mfp_required, + mfp_capable, ies_ptr, + &local_neg_auth_type, bss_desc, + &uc_cipher, &mc_cipher); + break; + } + + } + + if (match) { + if (neg_uc_cipher) + *neg_uc_cipher = uc_cipher; + if (neg_mc_cipher) + *neg_mc_cipher = mc_cipher; + if (neg_auth_type) + *neg_auth_type = local_neg_auth_type; + } + return match; +} + +bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len, + uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired) +{ + bool fMatch = false; + + do { + /* + * Check for the specification of the Broadcast SSID at the + * beginning of the list. If specified, then all SSIDs are + * matches (broadcast SSID means accept all SSIDs). + */ + if (ssid1Len == 0) { + fMatch = true; + break; + } + + /* There are a few special cases. If the Bss description has + * a Broadcast SSID, then our Profile must have a single SSID + * without Wildcards so we can program the SSID. + * + * SSID could be suppressed in beacons. In that case SSID IE + * has valid length but the SSID value is all NULL characters. + * That condition is trated same as NULL SSID + */ + if (csr_is_nullssid(bssSsid, bssSsidLen)) { + if (false == fSsidRequired) { + fMatch = true; + break; + } + } + + if (ssid1Len != bssSsidLen) + break; + if (!qdf_mem_cmp(bssSsid, ssid1, bssSsidLen)) { + fMatch = true; + break; + } + + } while (0); + + return fMatch; +} + +/* Null ssid means match */ +bool csr_is_ssid_in_list(tSirMacSSid *pSsid, tCsrSSIDs *pSsidList) +{ + bool fMatch = false; + uint32_t i; + + if (pSsidList && pSsid) { + for (i = 0; i < pSsidList->numOfSSIDs; i++) { + if (csr_is_nullssid + (pSsidList->SSIDList[i].SSID.ssId, + pSsidList->SSIDList[i].SSID.length) + || + ((pSsidList->SSIDList[i].SSID.length == + pSsid->length) + && (!qdf_mem_cmp(pSsid->ssId, + pSsidList->SSIDList[i].SSID. + ssId, pSsid->length)))) { + fMatch = true; + break; + } + } + } + + return fMatch; +} + +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; +} + +bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2) +{ + if ((eCSR_BSS_TYPE_ANY != bssType1 && eCSR_BSS_TYPE_ANY != bssType2) + && (bssType1 != bssType2)) + return false; + else + return true; +} + +bool csr_is_bss_type_ibss(eCsrRoamBssType bssType) +{ + return (bool) + (eCSR_BSS_TYPE_START_IBSS == bssType + || eCSR_BSS_TYPE_IBSS == bssType); +} + +/** + * csr_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 csr_is_aggregate_rate_supported(tpAniSirGlobal mac_ctx, + uint16_t rate) +{ + bool supported = false; + uint16_t idx, new_rate; + + /* In case basic rate flag is set */ + new_rate = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + if (eCSR_CFG_DOT11_MODE_11A == + mac_ctx->roam.configParam.uCfgDot11Mode) { + switch (new_rate) { + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + supported = true; + break; + default: + supported = false; + break; + } + + } else if (eCSR_CFG_DOT11_MODE_11B == + mac_ctx->roam.configParam.uCfgDot11Mode) { + switch (new_rate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_11Mbps: + supported = true; + break; + default: + supported = false; + break; + } + } else if (!mac_ctx->roam.configParam.ProprietaryRatesEnabled) { + + switch (new_rate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_11Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + supported = true; + break; + default: + supported = false; + break; + } + } else if (eCsrSuppRate_1Mbps == new_rate || + eCsrSuppRate_2Mbps == new_rate || + eCsrSuppRate_5_5Mbps == new_rate || + eCsrSuppRate_11Mbps == new_rate) + supported = true; + else { + idx = 0x1; + + switch (new_rate) { + case eCsrSuppRate_6Mbps: + supported = g_phy_rates_suppt[0][idx]; + break; + case eCsrSuppRate_9Mbps: + supported = g_phy_rates_suppt[1][idx]; + break; + case eCsrSuppRate_12Mbps: + supported = g_phy_rates_suppt[2][idx]; + break; + case eCsrSuppRate_18Mbps: + supported = g_phy_rates_suppt[3][idx]; + break; + case eCsrSuppRate_20Mbps: + supported = g_phy_rates_suppt[4][idx]; + break; + case eCsrSuppRate_24Mbps: + supported = g_phy_rates_suppt[5][idx]; + break; + case eCsrSuppRate_36Mbps: + supported = g_phy_rates_suppt[6][idx]; + break; + case eCsrSuppRate_40Mbps: + supported = g_phy_rates_suppt[7][idx]; + break; + case eCsrSuppRate_42Mbps: + supported = g_phy_rates_suppt[8][idx]; + break; + case eCsrSuppRate_48Mbps: + supported = g_phy_rates_suppt[9][idx]; + break; + case eCsrSuppRate_54Mbps: + supported = g_phy_rates_suppt[10][idx]; + break; + case eCsrSuppRate_72Mbps: + supported = g_phy_rates_suppt[11][idx]; + break; + case eCsrSuppRate_80Mbps: + supported = g_phy_rates_suppt[12][idx]; + break; + case eCsrSuppRate_84Mbps: + supported = g_phy_rates_suppt[13][idx]; + break; + case eCsrSuppRate_96Mbps: + supported = g_phy_rates_suppt[14][idx]; + break; + case eCsrSuppRate_108Mbps: + supported = g_phy_rates_suppt[15][idx]; + break; + case eCsrSuppRate_120Mbps: + supported = g_phy_rates_suppt[16][idx]; + break; + case eCsrSuppRate_126Mbps: + supported = g_phy_rates_suppt[17][idx]; + break; + case eCsrSuppRate_144Mbps: + supported = g_phy_rates_suppt[18][idx]; + break; + case eCsrSuppRate_160Mbps: + supported = g_phy_rates_suppt[19][idx]; + break; + case eCsrSuppRate_168Mbps: + supported = g_phy_rates_suppt[20][idx]; + break; + case eCsrSuppRate_192Mbps: + supported = g_phy_rates_suppt[21][idx]; + break; + case eCsrSuppRate_216Mbps: + supported = g_phy_rates_suppt[22][idx]; + break; + case eCsrSuppRate_240Mbps: + supported = g_phy_rates_suppt[23][idx]; + break; + default: + supported = false; + break; + } + } + return supported; +} + +void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap) +{ + uint16_t rateBitmap; + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + rateBitmap = *pRateBitmap; + switch (n) { + case SIR_MAC_RATE_1: + rateBitmap |= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + rateBitmap |= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + rateBitmap |= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + rateBitmap |= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + rateBitmap |= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + rateBitmap |= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + rateBitmap |= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + rateBitmap |= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + rateBitmap |= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + rateBitmap |= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + rateBitmap |= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + rateBitmap |= SIR_MAC_RATE_54_BITMAP; + break; + } + *pRateBitmap = rateBitmap; +} + +bool csr_check_rate_bitmap(uint8_t rate, uint16_t rateBitmap) +{ + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + switch (n) { + case SIR_MAC_RATE_1: + rateBitmap &= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + rateBitmap &= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + rateBitmap &= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + rateBitmap &= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + rateBitmap &= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + rateBitmap &= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + rateBitmap &= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + rateBitmap &= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + rateBitmap &= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + rateBitmap &= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + rateBitmap &= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + rateBitmap &= SIR_MAC_RATE_54_BITMAP; + break; + } + return !!rateBitmap; +} + +bool csr_rates_is_dot11_rate_supported(tpAniSirGlobal mac_ctx, uint8_t rate) +{ + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + return csr_is_aggregate_rate_supported(mac_ctx, n); +} + +static uint16_t csr_rates_mac_prop_to_dot11(uint16_t Rate) +{ + uint16_t ConvertedRate = Rate; + + switch (Rate) { + case SIR_MAC_RATE_1: + ConvertedRate = 2; + break; + case SIR_MAC_RATE_2: + ConvertedRate = 4; + break; + case SIR_MAC_RATE_5_5: + ConvertedRate = 11; + break; + case SIR_MAC_RATE_11: + ConvertedRate = 22; + break; + + case SIR_MAC_RATE_6: + ConvertedRate = 12; + break; + case SIR_MAC_RATE_9: + ConvertedRate = 18; + break; + case SIR_MAC_RATE_12: + ConvertedRate = 24; + break; + case SIR_MAC_RATE_18: + ConvertedRate = 36; + break; + case SIR_MAC_RATE_24: + ConvertedRate = 48; + break; + case SIR_MAC_RATE_36: + ConvertedRate = 72; + break; + case SIR_MAC_RATE_42: + ConvertedRate = 84; + break; + case SIR_MAC_RATE_48: + ConvertedRate = 96; + break; + case SIR_MAC_RATE_54: + ConvertedRate = 108; + break; + + case SIR_MAC_RATE_72: + ConvertedRate = 144; + break; + case SIR_MAC_RATE_84: + ConvertedRate = 168; + break; + case SIR_MAC_RATE_96: + ConvertedRate = 192; + break; + case SIR_MAC_RATE_108: + ConvertedRate = 216; + break; + case SIR_MAC_RATE_126: + ConvertedRate = 252; + break; + case SIR_MAC_RATE_144: + ConvertedRate = 288; + break; + case SIR_MAC_RATE_168: + ConvertedRate = 336; + break; + case SIR_MAC_RATE_192: + ConvertedRate = 384; + break; + case SIR_MAC_RATE_216: + ConvertedRate = 432; + break; + case SIR_MAC_RATE_240: + ConvertedRate = 480; + break; + + case 0xff: + ConvertedRate = 0; + break; + } + + return ConvertedRate; +} + +uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates, + tSirMacRateSet *pExtRates, + tSirMacPropRateSet *pPropRates) +{ + uint8_t i; + uint16_t nBest; + + nBest = pSuppRates->rate[0] & (~CSR_DOT11_BASIC_RATE_MASK); + + if (pSuppRates->numRates > SIR_MAC_RATESET_EID_MAX) + pSuppRates->numRates = SIR_MAC_RATESET_EID_MAX; + + for (i = 1U; i < pSuppRates->numRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + pSuppRates-> + rate[i] & (~CSR_DOT11_BASIC_RATE_MASK)); + } + + if (NULL != pExtRates) { + for (i = 0U; i < pExtRates->numRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + pExtRates-> + rate[i] & + (~CSR_DOT11_BASIC_RATE_MASK)); + } + } + + if (NULL != pPropRates) { + for (i = 0U; i < pPropRates->numPropRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + csr_rates_mac_prop_to_dot11 + (pPropRates->propRate[i])); + } + } + + return nBest; +} + +#ifdef WLAN_FEATURE_FILS_SK +static inline void csr_free_fils_profile_info(struct csr_roam_profile *profile) +{ + if (profile->fils_con_info) { + qdf_mem_free(profile->fils_con_info); + profile->fils_con_info = NULL; + } + + if (profile->hlp_ie) { + qdf_mem_free(profile->hlp_ie); + profile->hlp_ie = NULL; + profile->hlp_ie_len = 0; + } +} +#else +static inline void csr_free_fils_profile_info(struct csr_roam_profile *profile) +{ } +#endif + +void csr_release_profile(tpAniSirGlobal pMac, struct csr_roam_profile *pProfile) +{ + if (pProfile) { + if (pProfile->BSSIDs.bssid) { + qdf_mem_free(pProfile->BSSIDs.bssid); + pProfile->BSSIDs.bssid = NULL; + } + if (pProfile->SSIDs.SSIDList) { + qdf_mem_free(pProfile->SSIDs.SSIDList); + pProfile->SSIDs.SSIDList = NULL; + } + if (pProfile->pWPAReqIE) { + qdf_mem_free(pProfile->pWPAReqIE); + pProfile->pWPAReqIE = NULL; + } + if (pProfile->pRSNReqIE) { + qdf_mem_free(pProfile->pRSNReqIE); + pProfile->pRSNReqIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + if (pProfile->pWAPIReqIE) { + qdf_mem_free(pProfile->pWAPIReqIE); + pProfile->pWAPIReqIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ + + if (pProfile->pAddIEScan) { + qdf_mem_free(pProfile->pAddIEScan); + pProfile->pAddIEScan = NULL; + } + + if (pProfile->pAddIEAssoc) { + qdf_mem_free(pProfile->pAddIEAssoc); + pProfile->pAddIEAssoc = NULL; + } + if (pProfile->ChannelInfo.ChannelList) { + qdf_mem_free(pProfile->ChannelInfo.ChannelList); + pProfile->ChannelInfo.ChannelList = NULL; + } + csr_free_fils_profile_info(pProfile); + qdf_mem_zero(pProfile, sizeof(struct csr_roam_profile)); + } +} + +void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter + *pScanFilter) +{ + if (pScanFilter->BSSIDs.bssid) { + qdf_mem_free(pScanFilter->BSSIDs.bssid); + pScanFilter->BSSIDs.bssid = NULL; + } + if (pScanFilter->ChannelInfo.ChannelList) { + qdf_mem_free(pScanFilter->ChannelInfo.ChannelList); + pScanFilter->ChannelInfo.ChannelList = NULL; + } + if (pScanFilter->SSIDs.SSIDList) { + qdf_mem_free(pScanFilter->SSIDs.SSIDList); + pScanFilter->SSIDs.SSIDList = NULL; + } +} + +void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = &pMac->roam.roamSession[sessionId]; + + if (pSession->pCurRoamProfile) { + csr_release_profile(pMac, pSession->pCurRoamProfile); + qdf_mem_free(pSession->pCurRoamProfile); + pSession->pCurRoamProfile = NULL; + } +} + +void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = &pMac->roam.roamSession[sessionId]; + + if (pSession->pConnectBssDesc) { + qdf_mem_free(pSession->pConnectBssDesc); + pSession->pConnectBssDesc = NULL; + } +} + +tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp * + pSmeDisassocRsp) +{ + uint8_t *pBuffer = (uint8_t *) pSmeDisassocRsp; + uint32_t ret; + + pBuffer += (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(tSirMacAddr)); + /* tSirResultCodes is an enum, assuming is 32bit */ + /* If we cannot make this assumption, use copymemory */ + qdf_get_u32(pBuffer, &ret); + + return (tSirResultCodes) ret; +} + +tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp) +{ + uint8_t *pBuffer = (uint8_t *) pSmeRsp; + uint32_t ret; + + pBuffer += + (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint8_t) + + sizeof(uint16_t)); + /* tSirResultCodes is an enum, assuming is 32bit */ + /* If we cannot make this assumption, use copymemory */ + qdf_get_u32(pBuffer, &ret); + + return (tSirResultCodes) ret; +} + +tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId) +{ + tSirScanType scanType = eSIR_PASSIVE_SCAN; + enum channel_state channelEnabledType; + + channelEnabledType = wlan_reg_get_channel_state(pMac->pdev, chnId); + if (CHANNEL_STATE_ENABLE == channelEnabledType) + scanType = eSIR_ACTIVE_SCAN; + + return scanType; +} + +uint8_t csr_to_upper(uint8_t ch) +{ + uint8_t chOut; + + if (ch >= 'a' && ch <= 'z') + chOut = ch - 'a' + 'A'; + else + chOut = ch; + + return chOut; +} + +tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype) +{ + tSirBssType ret; + + switch (csrtype) { + case eCSR_BSS_TYPE_INFRASTRUCTURE: + ret = eSIR_INFRASTRUCTURE_MODE; + break; + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + ret = eSIR_IBSS_MODE; + break; + case eCSR_BSS_TYPE_INFRA_AP: + ret = eSIR_INFRA_AP_MODE; + break; + case eCSR_BSS_TYPE_NDI: + ret = eSIR_NDI_MODE; + break; + case eCSR_BSS_TYPE_ANY: + default: + ret = eSIR_AUTO_MODE; + break; + } + + return ret; +} + +/* This function use the parameters to decide the CFG value. */ +/* CSR never sets WNI_CFG_DOT11_MODE_ALL to the CFG */ +/* So PE should not see WNI_CFG_DOT11_MODE_ALL when it gets the CFG value */ +enum csr_cfgdot11mode +csr_get_cfg_dot11_mode_from_csr_phy_mode(struct csr_roam_profile *pProfile, + eCsrPhyMode phyMode, + bool fProprietary) +{ + 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 (pProfile && (CSR_IS_INFRA_AP(pProfile)) + && (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 (pProfile && CSR_IS_INFRA_AP(pProfile)) + 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; + + default: + /* No need to assign anything here */ + break; + } + + return cfgDot11Mode; +} + +QDF_STATUS csr_get_regulatory_domain_for_country(tpAniSirGlobal pMac, + uint8_t *pCountry, + v_REGDOMAIN_t *pDomainId, + enum country_src source) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + QDF_STATUS qdf_status; + uint8_t countryCode[CDS_COUNTRY_CODE_LEN + 1]; + v_REGDOMAIN_t domainId; + + if (pCountry) { + countryCode[0] = pCountry[0]; + countryCode[1] = pCountry[1]; + qdf_status = wlan_reg_get_domain_from_country_code(&domainId, + countryCode, + source); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + if (pDomainId) + *pDomainId = domainId; + status = QDF_STATUS_SUCCESS; + } else { + sme_warn("Couldn't find domain for country code %c%c", + pCountry[0], pCountry[1]); + status = QDF_STATUS_E_INVAL; + } + } + + return status; +} + +QDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + if (!pModifyProfileFields) + return QDF_STATUS_E_FAILURE; + + qdf_mem_copy(pModifyProfileFields, + &pMac->roam.roamSession[sessionId].connectedProfile. + modifyProfileFields, sizeof(tCsrRoamModifyProfileFields)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(pMac, sessionId); + + qdf_mem_copy(&pSession->connectedProfile.modifyProfileFields, + pModifyProfileFields, sizeof(tCsrRoamModifyProfileFields)); + + return QDF_STATUS_SUCCESS; +} + + +bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId) +{ + bool fRet = true; + struct csr_roam_session *pSession; + + pSession = CSR_GET_SESSION(pMac, sessionId); + + /* + * This condition is not working for infra state. When infra is in + * not-connected state the pSession->pCurRoamProfile is NULL, this + * function returns true, that is incorrect. + * Since SAP requires to set key without any BSS started, it needs + * this condition to be met. In other words, this function is useless. + * The current work-around is to process setcontext_rsp no matter + * what the state is. + */ + sme_debug("is not what it intends to. Must be revisit or removed"); + if ((NULL == pSession) + || (csr_is_conn_state_disconnected(pMac, sessionId) + && (pSession->pCurRoamProfile != NULL) + && (!(CSR_IS_INFRA_AP(pSession->pCurRoamProfile)))) + ) { + fRet = false; + } + + return fRet; +} + +/* 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; +} + +struct lim_channel_status * +csr_get_channel_status(tpAniSirGlobal mac, uint32_t channel_id) +{ + uint8_t i; + struct lim_scan_channel_status *channel_status; + struct lim_channel_status *entry; + + if (!mac->sap.acs_with_more_param) + return NULL; + + channel_status = &mac->lim.scan_channel_status; + for (i = 0; i < channel_status->total_channel; i++) { + entry = &channel_status->channel_status_list[i]; + if (entry->channel_id == channel_id) + return entry; + } + sme_err("Channel %d status info not exist", channel_id); + + return NULL; +} + +void csr_clear_channel_status(tpAniSirGlobal mac) +{ + struct lim_scan_channel_status *channel_status; + + if (!mac->sap.acs_with_more_param) + return; + + channel_status = &mac->lim.scan_channel_status; + channel_status->total_channel = 0; + + return; +} + +bool csr_is_channel_present_in_list(uint8_t *pChannelList, + int numChannels, uint8_t channel) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!pChannelList || (numChannels == 0)) + return false; + + /* Look for the channel in the list */ + for (i = 0; (i < numChannels) && + (i < WNI_CFG_VALID_CHANNEL_LIST_LEN); i++) { + if (pChannelList[i] == channel) + return true; + } + + return false; +} + +/** + * sme_bsstype_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) +{ + switch (bss_type) { + CASE_RETURN_STRING(eCSR_BSS_TYPE_INFRASTRUCTURE); + CASE_RETURN_STRING(eCSR_BSS_TYPE_INFRA_AP); + CASE_RETURN_STRING(eCSR_BSS_TYPE_IBSS); + CASE_RETURN_STRING(eCSR_BSS_TYPE_START_IBSS); + CASE_RETURN_STRING(eCSR_BSS_TYPE_ANY); + default: + return "unknown bss type"; + } +} + +QDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList, + int numChannels, uint8_t channel) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!pChannelList) + return QDF_STATUS_E_NULL_VALUE; + + /* Make room for the addition. (Start moving from the back.) */ + for (i = numChannels; i > 0; i--) + pChannelList[i] = pChannelList[i - 1]; + + /* Now add the NEW channel...at the front */ + pChannelList[0] = channel; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_wait_for_connection_update() - Wait for hw mode update + * @mac: Pointer to the MAC context + * @do_release_reacquire_lock: Indicates whether release and + * re-acquisition of SME global lock is required. + * + * Waits for CONNECTION_UPDATE_TIMEOUT time so that the + * hw mode update can get processed. + * + * Return: True if the wait was successful, false otherwise + */ +bool csr_wait_for_connection_update(tpAniSirGlobal mac, + bool do_release_reacquire_lock) +{ + QDF_STATUS status, ret; + + if (do_release_reacquire_lock == true) { + ret = sme_release_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + cds_err("lock release fail %d", ret); + return false; + } + } + + status = policy_mgr_wait_for_connection_update(mac->psoc); + + if (do_release_reacquire_lock == true) { + ret = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + cds_err("lock acquire fail %d", ret); + return false; + } + } + + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("wait for event failed"); + return false; + } + + return true; +} + +/** + * csr_get_session_persona() - get persona of a session + * @pmac: pointer to global MAC context + * @session_id: session id + * + * This function is to return the persona of a session + * + * Reture: enum QDF_OPMODE persona + */ +enum QDF_OPMODE csr_get_session_persona(tpAniSirGlobal pmac, + uint32_t session_id) +{ + struct csr_roam_session *session = NULL; + + session = CSR_GET_SESSION(pmac, session_id); + if (NULL == session || NULL == session->pCurRoamProfile) + return QDF_MAX_NO_OF_MODE; + + return session->pCurRoamProfile->csrPersona; +} + +/** + * 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(tpAniSirGlobal 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(tpAniSirGlobal mac_ctx, uint8_t channel) +{ + struct csr_roam_session *session; + enum QDF_OPMODE oper_mode; + uint8_t oper_channel = 0; + uint8_t session_id; + + if (channel == 0) + return false; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == session->pCurRoamProfile) + continue; + oper_mode = session->pCurRoamProfile->csrPersona; + if ((((oper_mode == QDF_STA_MODE) || + (oper_mode == QDF_P2P_CLIENT_MODE)) && + (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) || + (((oper_mode == QDF_P2P_GO_MODE) || + (oper_mode == QDF_SAP_MODE)) + && (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED))) + oper_channel = session->connectedProfile. + operationChannel; + + if (oper_channel && channel != oper_channel && + (!policy_mgr_is_hw_dbs_capable(mac_ctx->psoc) || + WLAN_REG_IS_SAME_BAND_CHANNELS(channel, + oper_channel))) + return true; + } + } + + return false; +} + diff --git a/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_api.c b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_api.c new file mode 100644 index 0000000000000000000000000000000000000000..125671ff2fd7522a0612e31aca61254cb7fc286b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_api.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 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. + */ + +#include +#include +#include "sme_api.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "nan_api.h" +#include "cfg_api.h" +#include "wma_types.h" + +/** + * sme_nan_register_callback() - + * This function gets called when HDD wants register nan rsp callback with + * sme layer. + * + * @hHal: Hal handle + * @callback: which needs to be registered. + * + * Return: void + */ +void sme_nan_register_callback(tHalHandle hHal, nan_callback callback) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + pMac = PMAC_STRUCT(hHal); + pMac->sme.nan_callback = callback; +} + +/** + * sme_nan_deregister_callback() - NAN De-register cb function + * @h_hal: Hal handle + * + * De-register nan rsp callback with sme layer. + * + * Return: void + */ +void sme_nan_deregister_callback(tHalHandle h_hal) +{ + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + pmac = PMAC_STRUCT(h_hal); + pmac->sme.nan_callback = NULL; +} + + +/** + * sme_nan_request() - + * This function gets called when HDD receives NAN vendor command + * from userspace + * + * @input: Nan Request structure ptr + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_nan_request(tpNanRequestReq input) +{ + struct scheduler_msg msg = {0}; + tpNanRequest data; + size_t data_len; + + data_len = sizeof(tNanRequest) + input->request_data_len; + data = qdf_mem_malloc(data_len); + + if (data == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Memory allocation failure")); + return QDF_STATUS_E_NOMEM; + } + 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_NAN_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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Not able to post WMA_NAN_REQUEST message to WMA"); + qdf_mem_free(data); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_nan_event() - + * This callback function will be called when SME received eWNI_SME_NAN_EVENT + * event from WMA + * + * @hHal: HAL handle for device + * @pMsg: Message body passed from WMA; includes NAN header + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_nan_event(tHalHandle hHal, void *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("msg ptr is NULL")); + status = QDF_STATUS_E_FAILURE; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("SME: Received sme_nan_event")); + if (pMac->sme.nan_callback) { + pMac->sme.nan_callback(pMac->hdd_handle, + (tSirNanEvent *) pMsg); + } + } + + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c new file mode 100644 index 0000000000000000000000000000000000000000..9cf33a39564ebef307034a21b50960323867d785 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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_start_ndi() - Start connection for NAN datapath + * @mac_ctx: Global MAC context + * @session: SME session ID + * @profile: Configuration profile + * + * Return: Success or failure code + */ +QDF_STATUS csr_roam_start_ndi(tpAniSirGlobal mac_ctx, uint32_t session, + struct csr_roam_profile *profile) +{ + QDF_STATUS status; + struct bss_config_param bss_cfg = {0}; + + /* Build BSS configuration from profile */ + status = csr_roam_prepare_bss_config_from_profile(mac_ctx, profile, + &bss_cfg, NULL); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac_ctx->roam.roamSession[session].bssParams.uCfgDot11Mode + = bss_cfg.uCfgDot11Mode; + /* Copy profile parameters to PE session */ + csr_roam_prepare_bss_params(mac_ctx, session, profile, NULL, + &bss_cfg, NULL); + /* + * Following routine will eventually call + * csrRoamIssueStartBss through csrRoamCcmCfgSetCallback + */ + status = csr_roam_set_bss_config_cfg(mac_ctx, session, profile, + NULL, &bss_cfg, NULL, false); + } + + sme_debug("profile config validity: %d", status); + + return status; +} + +/** + * csr_roam_save_ndi_connected_info() - Save connected profile parameters + * @mac_ctx: Global MAC context + * @session_id: Session ID + * @roam_profile: Profile given for starting BSS + * @bssdesc: BSS description from tSirSmeStartBssRsp response + * + * Saves NDI profile parameters into session's connected profile. + * + * Return: None + */ +void csr_roam_save_ndi_connected_info(tpAniSirGlobal mac_ctx, + uint32_t session_id, + struct csr_roam_profile *roam_profile, + tSirBssDescription *bssdesc) +{ + struct csr_roam_session *roam_session; + tCsrRoamConnectedProfile *connect_profile; + + roam_session = CSR_GET_SESSION(mac_ctx, session_id); + if (!roam_session) { + sme_err("session %d not found", session_id); + return; + } + + connect_profile = &roam_session->connectedProfile; + qdf_mem_zero(connect_profile, sizeof(*connect_profile)); + connect_profile->AuthType = roam_profile->negotiatedAuthType; + connect_profile->AuthInfo = roam_profile->AuthType; + connect_profile->EncryptionType = + roam_profile->negotiatedUCEncryptionType; + connect_profile->EncryptionInfo = roam_profile->EncryptionType; + connect_profile->mcEncryptionType = + roam_profile->negotiatedMCEncryptionType; + connect_profile->mcEncryptionInfo = + roam_profile->mcEncryptionType; + connect_profile->BSSType = roam_profile->BSSType; + connect_profile->modifyProfileFields.uapsd_mask = + roam_profile->uapsd_mask; + connect_profile->operationChannel = bssdesc->channelId; + connect_profile->beaconInterval = 0; + qdf_mem_copy(&connect_profile->Keys, &roam_profile->Keys, + sizeof(roam_profile->Keys)); + csr_get_bss_id_bss_desc(bssdesc, &connect_profile->bssid); + connect_profile->SSID.length = 0; + csr_free_connect_bss_desc(mac_ctx, session_id); + connect_profile->qap = false; + connect_profile->qosConnection = false; +} + +/** + * 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(tpAniSirGlobal mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct csr_roam_info *roam_info) +{ + + switch (result) { + case eCsrStartBssSuccess: + 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 eCsrStartBssFailure: + 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 eCsrStopBssSuccess: + 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 eCsrStopBssFailure: + 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/drivers/staging/qcacld-3.0/core/sme/src/qos/sme_qos.c b/drivers/staging/qcacld-3.0/core/sme/src/qos/sme_qos.c new file mode 100644 index 0000000000000000000000000000000000000000..4aa4299b1f4e3b46495c780f4af3bbf832029116 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/qos/sme_qos.c @@ -0,0 +1,7574 @@ +/* + * 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: 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" + +#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 CSR_ROAM_SESSION_MAX +#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 +/* 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 + */ +sme_QosEdcaAcType sme_qos_u_pto_ac_map[SME_QOS_WMM_UP_MAX] = { + SME_QOS_EDCA_AC_BE, /* User Priority 0 */ + SME_QOS_EDCA_AC_BK, /* User Priority 1 */ + SME_QOS_EDCA_AC_BK, /* User Priority 2 */ + SME_QOS_EDCA_AC_BE, /* User Priority 3 */ + SME_QOS_EDCA_AC_VI, /* User Priority 4 */ + SME_QOS_EDCA_AC_VI, /* User Priority 5 */ + SME_QOS_EDCA_AC_VO, /* User Priority 6 */ + SME_QOS_EDCA_AC_VO /* User Priority 7 */ +}; + +/* + * Table to map access category (AC) to appropriate user priority as specified + * in 802.11e/WMM + * Note: there is a quantization loss here because 4 ACs are mapped to 8 UPs + * Mapping is done for consistency + */ +enum sme_qos_wmmuptype sme_qos_a_cto_up_map[SME_QOS_EDCA_AC_MAX] = { + SME_QOS_WMM_UP_BE, /* AC BE */ + SME_QOS_WMM_UP_BK, /* AC BK */ + SME_QOS_WMM_UP_VI, /* AC VI */ + SME_QOS_WMM_UP_VO /* AC VO */ +}; + +/* + * 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; + sme_QosEdcaAcType 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; + sme_QosEdcaAcType ac; + struct sme_qos_wmmtspecinfo QoSInfo; +}; +/* + * DESCRIPTION + * SME QoS module's resend cmd related information structure. + */ +struct sme_qos_resendcmdinfo { + uint8_t tspecMask; + sme_QosEdcaAcType 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; + tpAniSirGlobal pMac; + 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[SME_QOS_EDCA_AC_MAX]; + /* 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; + sme_QosEdcaAcType 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; +}; +/* + * DESCRIPTION + * SME QoS module's internal control block. + */ +struct sme_qos_cb_s { + /* global Mac pointer */ + tpAniSirGlobal pMac; + /* All Session Info */ + struct sme_qos_sessioninfo sessionInfo[CSR_ROAM_SESSION_MAX]; + /* All FLOW info */ + tDblLinkList flow_list; + /* default TSPEC params */ + struct sme_qos_wmmtspecinfo def_QoSInfo[SME_QOS_EDCA_AC_MAX]; + /* counter for assigning Flow IDs */ + uint32_t nextFlowId; + /* counter for assigning Dialog Tokens */ + uint8_t nextDialogToken; +} sme_qos_cb; +typedef QDF_STATUS (*sme_QosProcessSearchEntry)(tpAniSirGlobal pMac, + tListElem *pEntry); + +static enum sme_qos_statustype sme_qos_internal_setup_req(tpAniSirGlobal pMac, + 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(tpAniSirGlobal pMac, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint32_t QosFlowID, + bool buffered_cmd); +static enum sme_qos_statustype sme_qos_internal_release_req(tpAniSirGlobal pMac, + uint8_t session_id, + uint32_t QosFlowID, + bool buffered_cmd); +static enum sme_qos_statustype sme_qos_setup(tpAniSirGlobal pMac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + sme_QosEdcaAcType ac); +static QDF_STATUS sme_qos_add_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + sme_QosEdcaAcType ac); +static QDF_STATUS sme_qos_del_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosEdcaAcType ac, uint8_t tspec_mask); +static QDF_STATUS sme_qos_process_add_ts_rsp(tpAniSirGlobal pMac, + void *pMsgBuf); +static QDF_STATUS sme_qos_process_del_ts_ind(tpAniSirGlobal pMac, + void *pMsgBuf); +static QDF_STATUS sme_qos_process_del_ts_rsp(tpAniSirGlobal pMac, + void *pMsgBuf); +static QDF_STATUS sme_qos_process_assoc_complete_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_reassoc_req_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_reassoc_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_reassoc_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_disconnect_ev(tpAniSirGlobal pMac, uint8_t + sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_join_req_ev(tpAniSirGlobal pMac, uint8_t + sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_handoff_assoc_req_ev(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info); +static QDF_STATUS sme_qos_process_handoff_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_preauth_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info); +static QDF_STATUS sme_qos_process_set_key_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info); +static QDF_STATUS sme_qos_process_aggr_qos_rsp(tpAniSirGlobal pMac, + void *pMsgBuf); +static QDF_STATUS sme_qos_ft_aggr_qos_req(tpAniSirGlobal pMac, uint8_t + sessionId); +static QDF_STATUS sme_qos_process_add_ts_success_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp); +static QDF_STATUS sme_qos_process_add_ts_failure_rsp(tpAniSirGlobal pMac, + 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, + sme_QosEdcaAcType ac, + uint8_t tspec_mask, + struct sme_qos_wmmtspecinfo *pTspec_Info); +static sme_QosEdcaAcType sme_qos_up_to_ac(enum sme_qos_wmmuptype up); +static bool sme_qos_is_acm(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + sme_QosEdcaAcType 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(tpAniSirGlobal pMac, + struct sme_qos_searchinfo search_key, + sme_QosProcessSearchEntry fnp); +static void sme_qos_state_transition(uint8_t sessionId, + sme_QosEdcaAcType 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(tpAniSirGlobal pMac, tListElem *pEntry); +static QDF_STATUS sme_qos_modification_notify_fnp(tpAniSirGlobal pMac, + tListElem *pEntry); +static QDF_STATUS sme_qos_modify_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +static QDF_STATUS sme_qos_del_ts_ind_fnp(tpAniSirGlobal pMac, tListElem + *pEntry); +static QDF_STATUS sme_qos_reassoc_success_ev_fnp(tpAniSirGlobal pMac, + tListElem *pEntry); +static QDF_STATUS sme_qos_add_ts_failure_fnp(tpAniSirGlobal pMac, tListElem + *pEntry); +static QDF_STATUS sme_qos_add_ts_success_fnp(tpAniSirGlobal pMac, tListElem + *pEntry); +static bool sme_qos_is_rsp_pending(uint8_t sessionId, sme_QosEdcaAcType ac); +static bool sme_qos_is_uapsd_active(void); + +static QDF_STATUS sme_qos_buffer_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId); +static QDF_STATUS sme_qos_delete_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId); +static void sme_qos_cleanup_ctrl_blk_for_handoff(tpAniSirGlobal pMac, + uint8_t sessionId); +static QDF_STATUS sme_qos_delete_buffered_requests(tpAniSirGlobal pMac, + uint8_t sessionId); +static bool sme_qos_validate_requested_params(tpAniSirGlobal pMac, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint8_t sessionId); + +static QDF_STATUS qos_issue_command(tpAniSirGlobal pMac, uint8_t sessionId, + eSmeCommandType cmdType, + struct sme_qos_wmmtspecinfo *pQoSInfo, + sme_QosEdcaAcType 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(tpAniSirGlobal pMac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pQoSInfo, + sme_QosEdcaAcType ac, + uint8_t tspecMask); +static void sme_qos_init_a_cs(tpAniSirGlobal pMac, uint8_t sessionId); +static QDF_STATUS sme_qos_request_reassoc(tpAniSirGlobal pMac, + 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); + +/* External APIs definitions */ + +/** + * sme_qos_open() - called to initialize SME QoS module. + * @pMac: global MAC context + * + * This function must be called before any API call to + * SME QoS module. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_open(tpAniSirGlobal pMac) +{ + struct sme_qos_sessioninfo *pSession; + uint8_t sessionId; + QDF_STATUS status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: initializing SME-QoS module", __func__, __LINE__); + /* init the control block */ + /* (note that this will make all sessions invalid) */ + qdf_mem_zero(&sme_qos_cb, sizeof(sme_qos_cb)); + sme_qos_cb.pMac = pMac; + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: cannot initialize Flow List", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pSession->sessionId = sessionId; + /* initialize the session's per-AC information */ + sme_qos_init_a_cs(pMac, sessionId); + /* initialize the session's buffered command list */ + status = csr_ll_open(&pSession->bufferedCommandList); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: cannot initialize cmd list for session %d", + __func__, __LINE__, sessionId); + return QDF_STATUS_E_FAILURE; + } + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: done initializing SME-QoS module", + __func__, __LINE__); + 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. + * + * pMac - Pointer to the global MAC parameter structure. + * Return QDF_STATUS + */ +QDF_STATUS sme_qos_close(tpAniSirGlobal pMac) +{ + struct sme_qos_sessioninfo *pSession; + sme_QosEdcaAcType ac; + uint8_t sessionId; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: closing down SME-QoS", __func__, __LINE__); + + /* 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 < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession == NULL) + continue; + + sme_qos_init_a_cs(pMac, 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(pMac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + + /* Clean up the assoc info if already allocated */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + /* close the session's buffered command list */ + csr_ll_close(&pSession->bufferedCommandList); + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) + sme_qos_state_transition(sessionId, ac, SME_QOS_CLOSED); + + pSession->sessionActive = false; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: closed down QoS", __func__, __LINE__); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_setup_req() - The SME QoS API exposed to HDD to request for QoS + * on a particular AC. + * @hHal: 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 callabck) 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(tHalHandle hHal, 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; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + enum sme_qos_statustype status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS Setup requested by client on session %d", + __func__, __LINE__, sessionId); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + /* Make sure the session is valid */ + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Supplied Session ID %d is invalid", + __func__, __LINE__, sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Make sure the session is active */ + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Supplied Session ID %d is inactive", + __func__, __LINE__, sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Assign a Flow ID */ + *pQosFlowID = sme_qos_assign_flow_id(); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS request on session %d assigned Flow ID %d", + __func__, __LINE__, sessionId, *pQosFlowID); + /* Call the internal function for QoS setup, */ + /* adding a layer of abstraction */ + status = + sme_qos_internal_setup_req(pMac, (uint8_t) + sessionId, + pQoSInfo, QoSCallback, + HDDcontext, UPType, + *pQosFlowID, false, + false); + } + } + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS setup return status on session %d is %d", + __func__, __LINE__, 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. + * @hHal: 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(tHalHandle hHal, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint32_t QosFlowID) +{ + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + enum sme_qos_statustype status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS Modify requested by client for Flow %d", + __func__, __LINE__, QosFlowID); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + 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(pMac, pQoSInfo, QosFlowID, false); + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS Modify return status on Flow %d is %d", + __func__, __LINE__, 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. + * + * @hHal: 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 sould 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(tHalHandle hHal, uint8_t session_id, + uint32_t QosFlowID) +{ + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + enum sme_qos_statustype status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS Release requested by client for Flow %d", + __func__, __LINE__, QosFlowID); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + 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(pMac, session_id, QosFlowID, + false); + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS Release return status on Flow %d is %d", + __func__, __LINE__, QosFlowID, status); + return status; +} + +void qos_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + qdf_mem_zero(&pCommand->u.qosCmd, sizeof(tGenericQosCmd)); + csr_release_command(pMac, 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(tpAniSirGlobal mac_ctx, + uint16_t msg_type, void *msg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tListElem *entry = NULL; + tSmeCmd *command; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL(" 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 (NULL == 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 (NULL == 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("unknown msg type = %d"), + msg_type); + break; + } + return status; +} + +/** + * sme_qos_validate_params() - validate SME QOS parameters. + * @pMac: Pointer to the global MAC parameter structure. + * @pBssDesc: Pointer to the BSS Descriptor information passed down by + * CSR to PE while issuing the Join request + * + * The SME QoS API exposed to CSR to validate AP + * capabilities regarding QoS support & any other QoS parameter validation. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_validate_params(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc) +{ + tDot11fBeaconIEs *pIes = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: validation for QAP & APSD", __func__, __LINE__); + do { + if (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pBssDesc, &pIes))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: csr_get_parsed_bss_description_ies() failed", + __func__, __LINE__); + break; + } + /* check if the AP is QAP & it supports APSD */ + if (!CSR_IS_QOS_BSS(pIes)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: AP doesn't support QoS", + __func__, __LINE__); + + break; + } + if (!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) && + !(pIes->WMMInfoAp.uapsd)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: AP doesn't support APSD", + __func__, __LINE__); + break; + } + status = QDF_STATUS_SUCCESS; + } while (0); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: validated with status = %d", + __func__, __LINE__, status); + if (pIes) + qdf_mem_free(pIes); + + return status; +} + +/* + * 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. + * + * pMac - 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(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On Session %d Event %d received from CSR", + __func__, __LINE__, sessionId, ind); + switch (ind) { + case SME_QOS_CSR_ASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = sme_qos_process_assoc_complete_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_reassoc_req_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = + sme_qos_process_reassoc_success_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_FAILURE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_reassoc_failure_ev(pMac, 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(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_JOIN_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_join_req_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_ASSOC_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_handoff_assoc_req_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_COMPLETE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_success_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_PREAUTH_SUCCESS_IND: + status = + sme_qos_process_preauth_success_ind(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_SET_KEY_SUCCESS_IND: + status = + sme_qos_process_set_key_success_ind(pMac, sessionId, + pEvent_info); + break; + default: + /* Err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On Session %d Unknown Event %d received from CSR", + __func__, __LINE__, sessionId, ind); + break; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On Session %d processed Event %d with status %d", + __func__, __LINE__, sessionId, ind, status); + 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) + * + * pMac - 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(tpAniSirGlobal pMac, tSirBssDescription + *pSirBssDesc, tDot11fBeaconIEs *pIes) +{ + sme_QosEdcaAcType ac; + uint8_t acm_mask = 0; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked", __func__, __LINE__); + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + if (sme_qos_is_acm(pMac, pSirBssDesc, ac, pIes)) + acm_mask = acm_mask | (1 << (SME_QOS_EDCA_AC_VO - ac)); + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: mask is %d", __func__, __LINE__, acm_mask); + return acm_mask; +} + +/* Internal function definitions */ + +/** + * sme_qos_internal_setup_req() - The SME QoS internal setup request handling + * function. + * + * @pMac: 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 callabck) 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(tpAniSirGlobal pMac, + 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; + sme_QosEdcaAcType 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d for flow %d", + __func__, __LINE__, sessionId, QosFlowID); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* if caller sent an empty TSPEC, fill up with the default one */ + if (!pQoSInfo) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "%s: %d: caller sent an empty QoS param list, using defaults", + __func__, __LINE__); + /* find the AC with UPType passed in */ + ac = sme_qos_up_to_ac(UPType); + if (SME_QOS_EDCA_AC_MAX == ac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, 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 (SME_QOS_EDCA_AC_MAX == ac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, pQoSInfo->ts_info.up); + + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + /* validate QoS params */ + if (!sme_qos_validate_requested_params(pMac, pQoSInfo, + sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid params", __func__, __LINE__); + 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 safegaurd 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: buffering the setup request for flow %d in state %d since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = pMac; + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the setup request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Buffered setup request for flow = %d", + __func__, __LINE__, 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(pMac, sessionId, &Tspec_Info, ac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d with AC %d in state SME_QOS_LINK_UP sme_qos_setup returned with status %d", + __func__, __LINE__, 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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new entry in the Flow List", + __func__, __LINE__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d with AC %d in state SME_QOS_LINK_UP tspec_mask_status is %d but should not be set yet", + __func__, __LINE__, 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(pMac), + 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Creating entry on session %d at %pK with flowID %d", + __func__, __LINE__, + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d returned by sme_qos_setup", + __func__, __LINE__, sessionId, status); + new_state = pACInfo->curr_state; + if (buffered_cmd && hoRenewal) + QoSCallback(MAC_HANDLE(pMac), 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Buffering setup request for flow %d in state = %d", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = pMac; + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d couldn't buffer the setup request for flow %d in state = %d", + __func__, __LINE__, + 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(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, + ac, NULL)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: tspec_mask_status = %d for AC = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status, ac); + if (!pACInfo->tspec_mask_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: tspec_mask_status can't be 0 for ac: %d in state: %d", + __func__, __LINE__, 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 + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: wrong tmask = %d", + __func__, __LINE__, + 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: tmask = %d, new_tmask = %d in state = %d", + __func__, __LINE__, + tmask, new_tmask, pACInfo->curr_state); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: tspec_mask_status = %d for AC = %d", + __func__, __LINE__, + 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: failed to aggregate params", + __func__, __LINE__); + 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 { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no flows running for ac = %d while in state = %d", + __func__, __LINE__, 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(pMac, sessionId, + &pACInfo->requested_QoSInfo[tmask - 1], + ac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", + __func__, __LINE__, 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 = + (struct sme_qos_flowinfoentry *) + qdf_mem_malloc(sizeof(*pentry)); + if (!pentry) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new entry in the Flow List", + __func__, __LINE__); + 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Creating flow %d", + __func__, __LINE__, 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(pMac), + 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 + (pMac, search_key, + sme_qos_setup_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other entries on this AC =%d", + __func__, __LINE__, + 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d creating entry at %pK with flowID %d", + __func__, __LINE__, + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d returned by sme_qos_setup", + __func__, __LINE__, sessionId, status); + new_state = pACInfo->curr_state; + } + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: setup requested in unexpected state = %d", + __func__, __LINE__, pACInfo->curr_state); + new_state = pACInfo->curr_state; + } + /* If current state is same as previous no need for transistion, + * 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. + * @pMac: 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(tpAniSirGlobal pMac, + 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; + sme_QosEdcaAcType 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked for flow %d", __func__, __LINE__, 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for flowID = %d", + __func__, __LINE__, 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(pMac, pQoSInfo, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid params", __func__, __LINE__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Modification of direction/tid/up is not allowed", + __func__, __LINE__); + + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: the addts parameters are same as last request, dropping the current request", + __func__, __LINE__); + + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + + /* 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 safegaurd 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: buffering the modify request for flow %d in state %d since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = pMac; + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the modify request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Buffered modify request for flow = %d", + __func__, __LINE__, 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 = (struct sme_qos_flowinfoentry *) qdf_mem_malloc( + sizeof(*pNewEntry)); + if (!pNewEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new entry in the Flow List", + __func__, __LINE__); + 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d creating modified entry at %pK with flowID %d", + __func__, __LINE__, + 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(pMac, sessionId, + &pACInfo-> + requested_QoSInfo[pNewEntry-> + tspec_mask - 1], + ac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", + __func__, __LINE__, 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(pMac, + 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 + (pMac, search_key, + sme_qos_modification_notify_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other entries on this AC =%d", + __func__, __LINE__, + 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(pMac), + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [pNewEntry-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + + } else { + /* unexpected status returned by + * sme_qos_setup() + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d returned by sme_qos_setup", + __func__, __LINE__, sessionId, status); + new_state = SME_QOS_QOS_ON; + } + } else { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_update_params() failed", + __func__, __LINE__); + 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Buffering modify request for flow %d in state = %d", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = pMac; + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the modify request in state = %d", + __func__, __LINE__, 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: modify requested in unexpected state = %d", + __func__, __LINE__, 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 + * @pMac: 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(tpAniSirGlobal pMac, + 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; + sme_QosEdcaAcType 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(pMac); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked for flow %d", __func__, __LINE__, 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for flowID = %d", + __func__, __LINE__, 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.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s:%d: Buffered release request for flow = %d", + __func__, __LINE__, QosFlowID); + } + } + 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(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id: %d is invalid", + __func__, __LINE__, 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 safegaurd 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: buffering the release request for flow %d in state %d since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the release request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Buffered release request for flow = %d", + __func__, __LINE__, 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: tspec_mask_status = %d for AC = %d with entry tspec_mask = %d", + __func__, __LINE__, + 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); + + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d buffering the AddTS request for AC %d in state %d as Addts is pending on other Tspec index of this AC", + __func__, __LINE__, + 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.pMac = pMac; + 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))) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to buffer the AddTS request for AC %d TSPEC %d in state %d", + __func__, __LINE__, + 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(pMac, sessionId, + &pACInfo-> + requested_QoSInfo + [flow_info->tspec_mask - + 1], ac); + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", + __func__, __LINE__, 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Deleting entry at %pK with flowID %d", + __func__, __LINE__, 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 + (pMac, search_key, + sme_qos_setup_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other entries on this AC =%d", + __func__, __LINE__, + ac); + } + } + status = + SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(pMac), + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + } else { + /* unexpected status returned by + * sme_qos_setup() + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d returned by sme_qos_setup", + __func__, __LINE__, 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d deleting entry at %pK with flowID %d", + __func__, __LINE__, 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(pMac), + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + } + } else { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_update_params() failed", + __func__, __LINE__); + new_state = SME_QOS_LINK_UP; + if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(pMac), + 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(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, + 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 << (SME_QOS_EDCA_AC_VO - ac)); + /* Also update modifyProfileFields. + * uapsd_mask in CSR for consistency + */ + csr_get_modify_profile_fields(pMac, + flow_info-> + sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask = + pSession->apsdMask; + csr_set_modify_profile_fields(pMac, + 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(pMac, + sessionId, + eSmeCommandDelTs, + NULL, ac, + flow_info-> + tspec_mask); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_del_ts_req() failed", + __func__, __LINE__); + 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 << (SME_QOS_EDCA_AC_VO - ac))) { + /* reassoc logic */ + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + pSession->apsdMask &= + ~(1 << (SME_QOS_EDCA_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(pMac, + sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: Reassoc failed", + __func__, __LINE__); + 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 { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: nothing to do for AC = %d", + __func__, __LINE__, ac); + } + + if (SME_QOS_RELEASE_BY_AP == pACInfo->relTrig) { + flow_info->QoSCallback(MAC_HANDLE(pMac), + flow_info->HDDcontext, + &pACInfo-> + curr_QoSInfo[flow_info-> + tspec_mask - + 1], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Deleting entry at %pK with flowID %d", + __func__, __LINE__, flow_info, + flow_info->QosFlowID); + } else if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(pMac), + 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 { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Exceeded the array bounds of pACInfo->num_flows", + __func__, __LINE__); + 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d deleting entry at %pK with flowID %d", + __func__, __LINE__, + 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.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the release request in state = %d", + __func__, __LINE__, 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: release request in unexpected state = %d", + __func__, __LINE__, 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. + * @pMac: 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(tpAniSirGlobal pMac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + sme_QosEdcaAcType 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(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id %d is invalid", + __func__, __LINE__, sessionId); + return status; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d is inactive", + __func__, __LINE__, sessionId); + return status; + } + if (!pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d has an Invalid BSS Descriptor", + __func__, __LINE__, sessionId); + return status; + } + hstatus = csr_get_parsed_bss_description_ies(pMac, + pSession->assocInfo.pBssDesc, + &pIes); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to parse BSS IEs", + __func__, __LINE__, sessionId); + return status; + } + + /* success so pIes was allocated */ + + if (!CSR_IS_QOS_BSS(pIes)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support QoS", + __func__, __LINE__, sessionId); + qdf_mem_free(pIes); + /* notify HDD through the synchronous status msg */ + return SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: UAPSD/PSB set %d: ", __func__, __LINE__, + pTspec_Info->ts_info.psb); + + pACInfo = &pSession->ac_info[ac]; + do { + /* is ACM enabled for this AC? */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, + 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 + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support APSD", + __func__, __LINE__, 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(pMac, sessionId, + eSmeCommandAddTs, + pTspec_Info, ac, 0); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_add_ts_req() failed", + __func__, __LINE__); + break; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d AddTS on AC %d is pending", + __func__, __LINE__, 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 << (SME_QOS_EDCA_AC_VO - ac))) { + /* APSD was formerly enabled on this AC but is + * no longer required so we must reassociate + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d reassoc needed to disable APSD on AC %d", + __func__, __LINE__, sessionId, ac); + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + hstatus = + sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to request reassociation", + __func__, __LINE__); + break; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d reassociation to enable APSD on AC %d is pending", + __func__, __LINE__, 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 + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Request is not looking for APSD & Admission Control isn't mandatory for the AC", + __func__, __LINE__); + /* 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 + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support APSD", + __func__, __LINE__, sessionId); + break; + } else if (pSession-> + apsdMask & (1 << (SME_QOS_EDCA_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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Request is looking for APSD and it is already set for the AC", + __func__, __LINE__); + break; + } else { + /* application is looking for APSD but it is not enabled on this + * AC so we need to reassociate + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask |= + 1 << (SME_QOS_EDCA_AC_VO - ac); + hstatus = sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to request reassociation", + __func__, __LINE__); + break; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_debug("Set Key complete"); + (void)sme_qos_process_buffered_cmd(sessionId); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +/** + * sme_qos_ese_save_tspec_response() - save TSPEC parameters. + * @pMac: 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(tpAniSirGlobal pMac, 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_u_pto_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 = eSIR_MAC_SUCCESS_STATUS; + pAddtsRsp->rsp.wmeTspecPresent = pTspec->present; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Copy Tspec to local data structure ac=%d, tspecIdx=%d", + __func__, ac, tspecIndex); + + if (pAddtsRsp->rsp.wmeTspecPresent) + /* Copy TSPEC params received in assoc response to addts + * response + */ + convert_wmmtspec(pMac, &pAddtsRsp->rsp.tspec, pTspec); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_ese_process_reassoc_tspec_rsp() - process ese reassoc tspec response + * @pMac: 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(tpAniSirGlobal pMac, + 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(pMac, sessionId); + if (NULL == pCsrSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("ESE Tspec IE len %d less than min %zu"), + tspecIeLen, sizeof(tDot11fIEWMMTSPEC)); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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 >= SME_QOS_EDCA_AC_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_WARN, + "Found Tspec entry flow = %d AC = %d", + tspec_flow_index, ac); + sme_qos_ese_save_tspec_response(pMac, sessionId, + pTspecIE, ac, + tspec_flow_index); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_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(pMac, sessionId); + + return status; +} + +/** + * sme_qos_copy_tspec_info() - copy tspec info. + * @pMac: 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(tpAniSirGlobal pMac, + struct sme_qos_wmmtspecinfo *pTspec_Info, + tSirMacTspecIE *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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); +} + +/** + * sme_qos_ese_retrieve_tspec_info() - retrieve tspec info. + * @pMac: 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(tpAniSirGlobal 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 = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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 + +static +QDF_STATUS sme_qos_create_tspec_ricie(tpAniSirGlobal pMac, + struct sme_qos_wmmtspecinfo *pTspec_Info, + uint8_t *pRICBuffer, uint32_t *pRICLength, + uint8_t *pRICIdentifier) +{ + tDot11fIERICDataDesc ricIE; + uint32_t nStatus; + + if (pRICBuffer == NULL || pRICIdentifier == NULL || pRICLength == + NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("RIC data is NULL, %pK, %pK, %pK"), + pRICBuffer, pRICIdentifier, pRICLength); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&ricIE, sizeof(tDot11fIERICDataDesc)); + + ricIE.present = 1; + ricIE.RICData.present = 1; + ricIE.RICData.resourceDescCount = 1; + ricIE.RICData.statusCode = 0; + ricIE.RICData.Identifier = sme_qos_assign_dialog_token(); +#ifndef USE_80211_WMMTSPEC_FOR_RIC + ricIE.TSPEC.present = 1; + ricIE.TSPEC.delay_bound = pTspec_Info->delay_bound; + ricIE.TSPEC.inactivity_int = pTspec_Info->inactivity_interval; + ricIE.TSPEC.burst_size = pTspec_Info->max_burst_size; + ricIE.TSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size; + ricIE.TSPEC.max_service_int = pTspec_Info->max_service_interval; + ricIE.TSPEC.mean_data_rate = pTspec_Info->mean_data_rate; + ricIE.TSPEC.medium_time = 0; + ricIE.TSPEC.min_data_rate = pTspec_Info->min_data_rate; + ricIE.TSPEC.min_phy_rate = pTspec_Info->min_phy_rate; + ricIE.TSPEC.min_service_int = pTspec_Info->min_service_interval; + ricIE.TSPEC.size = pTspec_Info->nominal_msdu_size; + ricIE.TSPEC.peak_data_rate = pTspec_Info->peak_data_rate; + ricIE.TSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance; + ricIE.TSPEC.suspension_int = pTspec_Info->suspension_interval; + ricIE.TSPEC.service_start_time = pTspec_Info->svc_start_time; + ricIE.TSPEC.direction = pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) + ricIE.TSPEC.psb = pTspec_Info->ts_info.psb; + else + ricIE.TSPEC.psb = 0; + + ricIE.TSPEC.tsid = pTspec_Info->ts_info.tid; + ricIE.TSPEC.user_priority = pTspec_Info->ts_info.up; + ricIE.TSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + *pRICIdentifier = ricIE.RICData.Identifier; + + nStatus = + dot11f_pack_ie_ric_data_desc(pMac, &ricIE, pRICBuffer, + sizeof(ricIE), pRICLength); + if (DOT11F_FAILED(nStatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Packing of RIC Data of length %d failed with status %d", + *pRICLength, nStatus); + } +#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 + */ + ricIE.WMMTSPEC.present = 1; + ricIE.WMMTSPEC.version = 1; + ricIE.WMMTSPEC.delay_bound = pTspec_Info->delay_bound; + ricIE.WMMTSPEC.inactivity_int = pTspec_Info->inactivity_interval; + ricIE.WMMTSPEC.burst_size = pTspec_Info->max_burst_size; + ricIE.WMMTSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size; + ricIE.WMMTSPEC.max_service_int = pTspec_Info->max_service_interval; + ricIE.WMMTSPEC.mean_data_rate = pTspec_Info->mean_data_rate; + ricIE.WMMTSPEC.medium_time = 0; + ricIE.WMMTSPEC.min_data_rate = pTspec_Info->min_data_rate; + ricIE.WMMTSPEC.min_phy_rate = pTspec_Info->min_phy_rate; + ricIE.WMMTSPEC.min_service_int = pTspec_Info->min_service_interval; + ricIE.WMMTSPEC.size = pTspec_Info->nominal_msdu_size; + ricIE.WMMTSPEC.peak_data_rate = pTspec_Info->peak_data_rate; + ricIE.WMMTSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance; + ricIE.WMMTSPEC.suspension_int = pTspec_Info->suspension_interval; + ricIE.WMMTSPEC.service_start_time = pTspec_Info->svc_start_time; + ricIE.WMMTSPEC.direction = pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) + ricIE.WMMTSPEC.psb = pTspec_Info->ts_info.psb; + else + ricIE.WMMTSPEC.psb = 0; + + ricIE.WMMTSPEC.tsid = pTspec_Info->ts_info.tid; + ricIE.WMMTSPEC.user_priority = pTspec_Info->ts_info.up; + ricIE.WMMTSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + nStatus = + dot11f_pack_ie_ric_data_desc(pMac, &ricIE, pRICBuffer, + sizeof(ricIE), pRICLength); + if (DOT11F_FAILED(nStatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Packing of RIC Data of length %d failed with status %d", + *pRICLength, nStatus); + } +#endif /* 80211_TSPEC */ + *pRICIdentifier = ricIE.RICData.Identifier; + return nStatus; +} +/** + * 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Invoked on session %d"), sessionId); + + session = &sme_qos_cb.sessionInfo[sessionId]; + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_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: + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("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(tpAniSirGlobal 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("invoked on session %d"), session_id); + + session = &sme_qos_cb.sessionInfo[session_id]; + + aggr_req = (tSirAggrQosReq *) qdf_mem_malloc(sizeof(tSirAggrQosReq)); + + if (!aggr_req) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("couldn't allocate memory for the msg buffer")); + 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.pBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + + for (i = 0; i < SME_QOS_EDCA_AC_MAX; i++) { + for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "ac=%d, tspec_mask_staus=%x, tspec_index=%d", + i, session->ac_info[i].tspec_mask_status, j); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("direction = %d"), + 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); + } + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("sent down a AGGR QoS req to PE")); + } + + return status; +} + +static +QDF_STATUS sme_qos_process_ftric_response(tpAniSirGlobal pMac, + 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(pMac, &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(pMac, &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(pMac, &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(pMac, &pAddtsRsp->rsp.delay, + &pRicDataDesc->TSDelay); + + /* Need to call for WMMTSPEC */ + if (pRicDataDesc->WMMTSPEC.present) + convert_wmmtspec(pMac, &pAddtsRsp->rsp.tspec, + &pRicDataDesc->WMMTSPEC); + + /* return sme_qos_process_add_ts_rsp(pMac, &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(tpAniSirGlobal 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Received AGGR_QOS resp from LIM")); + + /* Copy the updated response information for TSPEC of all the ACs */ + for (i = 0; i < SIR_QOS_NUM_AC_MAX; 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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(tpAniSirGlobal 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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]) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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 { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "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(tpAniSirGlobal 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("invoked on session %d"), sessionid); + + if (ac == SME_QOS_EDCA_AC_MAX) { + 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 == SME_QOS_EDCA_AC_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "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(tpAniSirGlobal 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 (NULL == csr_session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("The Session pointer is NULL")); + return QDF_STATUS_E_FAILURE; + } + csr_conn_info = &csr_session->connectedInfo; + ric_rsplen = csr_conn_info->nRICRspLength; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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)); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (!csr_session->roam_synch_in_progress) { +#endif + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("RIC Resp still follows . Rem len = %d"), + ric_rsplen); + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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 = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; + ac++) { + sme_qos_find_matching_tspec_lfr3(mac_ctx, + sessionid, ac, qos_session, ric_data, + ric_len); + } + } else + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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; +} + +/** + * sme_qos_add_ts_req() - send ADDTS request. + * @pMac: 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(tpAniSirGlobal pMac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + sme_QosEdcaAcType ac) +{ + tSirAddtsReq *pMsg = NULL; + struct sme_qos_sessioninfo *pSession; + QDF_STATUS status = QDF_STATUS_E_FAILURE; +#ifdef FEATURE_WLAN_ESE + struct csr_roam_session *pCsrSession = CSR_GET_SESSION(pMac, sessionId); +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d for AC %d", + __func__, __LINE__, sessionId, ac); + if (sessionId >= CSR_ROAM_SESSION_MAX) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: sessionId(%d) is invalid", + __func__, __LINE__, sessionId); + return QDF_STATUS_E_FAILURE; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pMsg = (tSirAddtsReq *) qdf_mem_malloc(sizeof(tSirAddtsReq)); + if (!pMsg) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the msg buffer", + __func__, __LINE__); + 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 (NULL == pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: BSS descriptor is NULL so we don't send request to PE", + __func__, __LINE__); + qdf_mem_free(pMsg); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&pMsg->bssid.bytes[0], + &pSession->assocInfo.pBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); +#ifdef FEATURE_WLAN_ESE + if (pCsrSession->connectedProfile.isESEAssoc) { + 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: sent down a ADDTS req to PE", + __func__, __LINE__); + /* 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 + * + * pMac - 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(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + tSirDeltsReq *pMsg; + struct sme_qos_wmmtspecinfo *pTspecInfo; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d for AC %d", + __func__, __LINE__, sessionId, ac); + pMsg = (tSirDeltsReq *) qdf_mem_malloc(sizeof(tSirDeltsReq)); + if (!pMsg) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the msg buffer", + __func__, __LINE__); + 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 (NULL == pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: BSS descriptor is NULL so we don't send request to PE", + __func__, __LINE__); + qdf_mem_free(pMsg); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&pMsg->bssid.bytes[0], + &pSession->assocInfo.pBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspecInfo->ts_info.up, pTspecInfo->ts_info.tid); + qdf_mem_zero(&pACInfo->curr_QoSInfo[tspec_mask - 1], + sizeof(struct sme_qos_wmmtspecinfo)); + + 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(pMac, &pMsg->req.tspec.tsinfo, + sessionId); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_process_add_ts_rsp() - Function to process the + * eWNI_SME_ADDTS_RSP came from PE + * + * pMac - Pointer to the global MAC parameter structure. + * pMsgBuf - Pointer to the msg buffer came from PE. + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_add_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirAddtsRsp paddts_rsp = (tpSirAddtsRsp) pMsgBuf; + 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; + sme_QosEdcaAcType 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]; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + + return QDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_HANDOFF == pACInfo->curr_state) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "ADDTS Rsp received for AC %d in HANDOFF State. Dropping", + ac); + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Invoked on session %d with return code %d", + __func__, __LINE__, 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(pMac, sessionId, + &paddts_rsp->rsp); + } else { + status = + sme_qos_process_add_ts_success_rsp(pMac, sessionId, + &paddts_rsp->rsp); + } + return status; +} + +/* + * sme_qos_process_del_ts_rsp() - Function to process the + * eWNI_SME_DELTS_RSP came from PE + * + * pMac - Pointer to the global MAC parameter structure. + * pMsgBuf - Pointer to the msg buffer came from PE. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_del_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirDeltsRsp pDeltsRsp = (tpSirDeltsRsp) pMsgBuf; + struct sme_qos_sessioninfo *pSession; + uint8_t sessionId = pDeltsRsp->sessionId; + + /* msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Invoked on session %d with return code %d", + __func__, __LINE__, 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 + * + * pMac - Pointer to the global MAC parameter structure. + * pMsgBuf - Pointer to the msg buffer came from PE. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_del_ts_ind(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirDeltsRsp pdeltsind = (tpSirDeltsRsp) pMsgBuf; + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + uint8_t sessionId = pdeltsind->sessionId; + sme_QosEdcaAcType ac; + struct sme_qos_searchinfo search_key; + tSirMacTSInfo *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 + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + tsinfo = &pdeltsind->rsp.tspec.tsinfo; + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, 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 perticular 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(pMac, search_key, + sme_qos_del_ts_ind_fnp))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for ac = %d", __func__, + __LINE__, search_key.key.ac_type); + return QDF_STATUS_E_FAILURE; + } + sme_set_tspec_uapsd_mask_per_session(pMac, 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(tpAniSirGlobal pMac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_BE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (((SME_QOS_INIT == pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_VO].curr_state)) + || (pSession->handoffRequested)) { + /* get the association info */ + if (!pEvent_info) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pEvent_info is NULL", + __func__, __LINE__); + return status; + } + if (!((sme_QosAssocInfo *) pEvent_info)->pBssDesc) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pBssDesc is NULL", + __func__, __LINE__); + return status; + } + if ((pSession->assocInfo.pBssDesc) && + (csr_is_bssid_match + ((struct qdf_mac_addr *) + &pSession->assocInfo.pBssDesc->bssId, + (struct qdf_mac_addr *) &(((sme_QosAssocInfo *) + pEvent_info)->pBssDesc->bssId)))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: assoc with the same BSS, no update needed", + __func__, __LINE__); + } else + status = sme_qos_save_assoc_info(pSession, pEvent_info); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: wrong state: BE %d, BK %d, VI %d, VO %d", + __func__, __LINE__, + pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state, + pSession->ac_info[SME_QOS_EDCA_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 = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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: + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, 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(tpAniSirGlobal pMac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + sme_QosEdcaAcType ac; + struct sme_qos_flowinfoentry *flow_info = NULL; + tListElem *entry = NULL; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (pSession->ftHandoffInProgress) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: no need for state transition, should already be in handoff state", + __func__, __LINE__); + + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("Changing FlowID %d reason to" + " SETUP 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(pMac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(pMac, sessionId); + return QDF_STATUS_SUCCESS; + } +/* TBH: Assuming both handoff algo & 11r willn't be enabled at the same time */ + if (pSession->ftHandoffInProgress) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: no need for state transition, should already be in handoff state", + __func__, __LINE__); + + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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 = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + 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 + * notificaiton + * + * Return: QDF_STATUS + */ +static +QDF_STATUS sme_qos_handle_handoff_state(tpAniSirGlobal mac_ctx, + struct sme_qos_sessioninfo *qos_session, + struct sme_qos_acinfo *ac_info, + sme_QosEdcaAcType ac, uint8_t sessionid) + +{ + struct sme_qos_searchinfo search_key; + struct sme_qos_searchinfo search_key1; + sme_QosEdcaAcType 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 << (SME_QOS_EDCA_AC_VO - ac); + else + qos_session->apsdMask &= ~(1 << (SME_QOS_EDCA_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 = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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(tpAniSirGlobal 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; + sme_QosEdcaAcType ac; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("invoked on session %d"), sessionid); + + if (CSR_ROAM_SESSION_MAX <= sessionid) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("event_info is NULL")); + return status; + } + + if (!((sme_QosAssocInfo *) event_info)->pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("pBssDesc is NULL")); + return status; + } + status = sme_qos_save_assoc_info(qos_session, event_info); + if (status) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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 { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, FL( + "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 = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + sme_QosEdcaAcType ac; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + break; + } + } + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + return QDF_STATUS_SUCCESS; +} + +/* + * 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(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + uint8_t ac; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: SME_QOS_CSR_HANDOFF_ASSOC_REQ received in SME_QOS_HANDOFF state with FT in progress", + __func__, __LINE__); + break; + } + + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + break; + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (csr_roam_is11r_assoc(pMac, sessionId)) + pSession->ftHandoffInProgress = true; +#endif + /* If FT handoff/ESE in progress, legacy handoff need not be enabled */ + if (!pSession->ftHandoffInProgress +#ifdef FEATURE_WLAN_ESE + && !csr_roam_is_ese_assoc(pMac, sessionId) +#endif + ) + pSession->handoffRequested = true; + + /* this session no longer needs UAPSD */ + pSession->apsdMask = 0; + /* do any sessions still require UAPSD? */ + sme_ps_uapsd_disable(MAC_HANDLE(pMac), 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(tpAniSirGlobal pMac, + 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* go back to original state before handoff */ + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + 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(tpAniSirGlobal pMac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: no need for state transition, should already be in handoff state", + __func__, __LINE__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("curr_state is not HANDOFF, session %d"), + sessionId); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_SUCCESS; + } + sme_qos_init_a_cs(pMac, sessionId); + /* this session doesn't require UAPSD */ + pSession->apsdMask = 0; + + sme_ps_uapsd_disable(MAC_HANDLE(pMac), sessionId); + + pSession->handoffRequested = false; + pSession->roamID = 0; + /* need to clean up buffered req */ + sme_qos_delete_buffered_requests(pMac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + /* clean up the assoc info */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = 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(tpAniSirGlobal pMac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + sme_QosEdcaAcType ac; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession->handoffRequested) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: no need for state transition, should already be in handoff state", + __func__, __LINE__); + 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)) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("curr_state is not HANDOFF, session %d"), + sessionId); + /* buffer the existing flows to be renewed after handoff is + * done + */ + sme_qos_buffer_existing_flows(pMac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(pMac, sessionId); + return QDF_STATUS_SUCCESS; + } + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + + /* clean up the assoc info if already set */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + return QDF_STATUS_SUCCESS; +} + +/** + * 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(tpAniSirGlobal 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("invoked on SME session %d"), sessionid); + + if (NULL == sme_session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_session is NULL")); + return QDF_STATUS_E_INVAL; + } + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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; + + /* Data is accessed from saved PreAuth Rsp */ + if (NULL == sme_session->ftSmeContext.psavedFTPreAuthRsp) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("psavedFTPreAuthRsp is NULL")); + return QDF_STATUS_E_INVAL; + } + + /* + * 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 + */ + ric_ie = sme_session->ftSmeContext.psavedFTPreAuthRsp->ric_ies; + ric_offset = + sme_session->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length; + + /* + * Now we have to process the currentTspeInfo inside this session and + * create the RIC IEs + */ + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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; + sme_session->ftSmeContext.psavedFTPreAuthRsp-> + ric_ies_length += ric_ielen; + tspec_mask_status >>= 1; + tspec_pending_status >>= 1; + tspec_idx++; + } while (tspec_mask_status); + } + return status; +} + +/* + * 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 + * + * pMac - 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(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + sme_QosEdcaAcType 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d for UP %d", __func__, __LINE__, + sessionId, up); + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d an AddTS is not pending on AC %d", + __func__, __LINE__, 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 + (pMac, search_key, sme_qos_add_ts_failure_fnp))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d no match found for ac = %d", + __func__, __LINE__, 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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 < SME_QOS_EDCA_AC_MAX) { + ac_info = &qos_session->ac_info[search_key.key.ac_type]; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Exceeded the array bounds")); + return QDF_STATUS_E_FAILURE; + } + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("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 + * + * pMac - 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(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + sme_QosEdcaAcType ac, ac_index; + struct sme_qos_searchinfo search_key; + struct sme_qos_searchinfo search_key1; + struct csr_roam_session *csr_session; + uint8_t tspec_pending; + tListElem *pEntry = NULL; + 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 */ + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d an AddTS is not pending on AC %d", + __func__, __LINE__, 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 << (SME_QOS_EDCA_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 << (SME_QOS_EDCA_AC_VO - ac)); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Exceeded the array bounds of pACInfo->requested_QosInfo", + __func__, __LINE__); + 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(pMac, + &pRsp->tspec.tsinfo, sessionId); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d AddTspec Medium Time %d", + __func__, __LINE__, 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 = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; + 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 + (pMac, search_key, sme_qos_add_ts_success_fnp))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d no match found for ac %d", + __func__, __LINE__, 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 */ + csr_session = CSR_GET_SESSION(pMac, sessionId); + if ((csr_session != NULL) && (NULL != csr_session->pCurRoamProfile) && + (csr_session->pCurRoamProfile->csrPersona == QDF_STA_MODE)) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CONNECT_IES_CHANGED); + + (void)sme_qos_process_buffered_cmd(sessionId); + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_aggregate_params() - Utility function to increament 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked", __func__, __LINE__); + if (!pInput_Tspec_Info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: input is NULL, nothing to aggregate", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + if (!pCurrent_Tspec_Info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Current is NULL, can't aggregate", + __func__, __LINE__); + 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, + sme_QosEdcaAcType 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: invoked on session %d for AC %d TSPEC %d", + __func__, __LINE__, sessionId, ac, tspec_mask); + if (!pTspec_Info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: output is NULL, can't aggregate", + __func__, __LINE__); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Flow List empty, nothing to update", + __func__, __LINE__); + 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Flow %d matches", + __func__, __LINE__, flow_info->QosFlowID); + + if ((SME_QOS_REASON_RELEASE == flow_info->reason) || + (SME_QOS_REASON_MODIFY == flow_info->reason)) { + /* msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Skipping Flow %d as it is marked for release/modify", + __func__, + __LINE__, flow_info->QosFlowID); + } else + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_aggregate_params + (&flow_info->QoSInfo, &Tspec_Info, + NULL))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_aggregate_params() failed", + __func__, __LINE__); + } + } + 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 sme_QosEdcaAcType sme_qos_up_to_ac(enum sme_qos_wmmuptype up) +{ + sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_MAX; + + if (up >= 0 && up < SME_QOS_WMM_UP_MAX) + ac = sme_qos_u_pto_ac_map[up]; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: up = %d ac = %d returned", + __func__, __LINE__, 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, + sme_QosEdcaAcType 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; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: On session %d new state=%d, old state=%d, for AC=%d", + __func__, __LINE__, + sessionId, pACInfo->curr_state, pACInfo->prev_state, ac); +} + +/** + * 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("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(tpAniSirGlobal 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; + sme_QosEdcaAcType ac_type; + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("match found on flowID, ending search")); + status = fnp(mac_ctx, list_elt); + if (QDF_STATUS_E_FAILURE == status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("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(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + sme_QosEdcaAcType ac, tDot11fBeaconIEs *pIes) +{ + bool ret_val = false; + tDot11fBeaconIEs *pIesLocal; + + if (!pSirBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pSirBssDesc is NULL", __func__, __LINE__); + return false; + } + + if (NULL != 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 + (pMac, pSirBssDesc, &pIesLocal))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: csr_get_parsed_bss_description_ies() failed", + __func__, __LINE__); + return false; + } + + /* if success then pIesLocal was allocated */ + } + + if (CSR_IS_QOS_BSS(pIesLocal)) { + switch (ac) { + case SME_QOS_EDCA_AC_BE: + if (pIesLocal->WMMParams.acbe_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_BK: + if (pIesLocal->WMMParams.acbk_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_VI: + if (pIesLocal->WMMParams.acvi_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_VO: + if (pIesLocal->WMMParams.acvo_acm) + ret_val = true; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: unknown AC = %d", + __func__, __LINE__, ac); + break; + } + } /* IS_QOS_BSS */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: ACM = %d for AC = %d", + __func__, __LINE__, ret_val, ac); + if (NULL == 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(tpAniSirGlobal 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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.pMac = 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))) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "couldn't buffer the setup request for flow %d in handoff state", + flow_info->QosFlowID); + else + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_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.pMac = mac_ctx; + cmd.sessionId = sessionid; + cmd.u.releaseCmdInfo.QosFlowID = flow_info->QosFlowID; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "couldn't buffer the release req for flow %d in handoff state", + flow_info->QosFlowID); + else + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_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.pMac = 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))) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "couldn't buffer the modify req for flow %d in handoff state", + flow_info->QosFlowID); + else + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "buffered a modify request for flow %d in handoff state", + flow_info->QosFlowID); + } + /* delete the entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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(tpAniSirGlobal pMac, + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Flow List empty, nothing to delete", + __func__, __LINE__); + 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(pMac), + flow_info->HDDcontext, + NULL, + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Deleting entry at %pK with flowID %d", + __func__, __LINE__, + 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Invoked", __func__, __LINE__); + pentry = (struct sme_qos_cmdinfoentry *) qdf_mem_malloc(sizeof( + struct sme_qos_cmdinfoentry)); + if (!pentry) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Memory allocation failure", + __func__, __LINE__); + 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Invoked on session %d"), session_id); + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Qos cmd %d"), qos_cmd->command); + switch (qos_cmd->command) { + case SME_QOS_SETUP_REQ: + hdd_status = sme_qos_internal_setup_req( + qos_cmd->pMac, 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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "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->pMac, + qos_cmd->sessionId, + qos_cmd->u.releaseCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == hdd_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "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->pMac, + &qos_cmd->u.modifyCmdInfo.QoSInfo, + qos_cmd->u.modifyCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == + hdd_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "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->pMac, + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "sme_qos_re_request_add_ts failed on session %d", + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("On session %d unknown cmd = %d"), + session_id, qos_cmd->command); + break; + } + /* buffered command has been processed, reclaim the memory */ + qdf_mem_free(pcmd); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("cmd buffer empty")); + } + 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(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_cmdinfoentry *pcmd = NULL; + tListElem *pEntry = NULL, *pNextEntry = NULL; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pEntry = csr_ll_peek_head(&pSession->bufferedCommandList, true); + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Buffered List empty, nothing to delete on session %d", + __func__, __LINE__, sessionId); + return QDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&pSession->bufferedCommandList, pEntry, + true); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: deleting entry from buffered List", __func__, + __LINE__); + /* 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) +{ + tSirBssDescription *pBssDesc = NULL; + uint32_t bssLen = 0; + + if (NULL == pAssoc_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pAssoc_info is NULL", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + /* clean up the assoc info if already set */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + bssLen = pAssoc_info->pBssDesc->length + + sizeof(pAssoc_info->pBssDesc->length); + /* save the bss Descriptor */ + pBssDesc = (tSirBssDescription *) qdf_mem_malloc(bssLen); + if (!pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the bss Descriptor", + __func__, __LINE__); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pBssDesc, pAssoc_info->pBssDesc, bssLen); + pSession->assocInfo.pBssDesc = pBssDesc; + /* save the apsd info from assoc */ + if (pAssoc_info->pProfile) + pSession->apsdMask |= pAssoc_info->pProfile->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 + * + * pMac - 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(tpAniSirGlobal pMac, 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; + sme_QosEdcaAcType ac; + + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + 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(pMac), + flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Entry with flowID = %d getting notified", + __func__, __LINE__, 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 + * + * pMac - 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(tpAniSirGlobal pMac, 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; + sme_QosEdcaAcType ac; + + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + 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(pMac), + flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Entry with flowID = %d getting notified", + __func__, __LINE__, flow_info->QosFlowID); + } + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_modify_fnp() - Utility function (pointer) to delete the origianl + * entry in FLOW list & add the modified one + * + * pMac - 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(tpAniSirGlobal pMac, tListElem *pEntry) +{ + struct sme_qos_flowinfoentry *flow_info = NULL; + + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Deleting original entry at %pK with flowID %d", + __func__, __LINE__, 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 perticular AC & delete them, also send HDD indication through the + * callback it registered per request + * + * pMac - 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(tpAniSirGlobal pMac, tListElem *pEntry) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *flow_info = NULL; + sme_QosEdcaAcType ac; + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + enum sme_qos_statustype status; + + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + 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(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + /* Call the internal function for QoS release, adding a layer of + * abstraction + */ + status = + sme_qos_internal_release_req(pMac, flow_info->sessionId, + flow_info->QosFlowID, false); + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: QoS Release return status on Flow %d is %d", + __func__, __LINE__, 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(tpAniSirGlobal 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; + sme_QosEdcaAcType ac; + QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; + + if (!entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + 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]--; + /* fall through */ + 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; + /* fall through */ + 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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 + * + * pMac - 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(tpAniSirGlobal pMac, 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; + sme_QosEdcaAcType ac; + + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + 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; + 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(pMac), + flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[pACInfo-> + tspec_pending + - 1], + hdd_status, + flow_info->QosFlowID); + } else { + flow_info->QoSCallback(MAC_HANDLE(pMac), + 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 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Deleting entry at %pK with flowID %d", + __func__, __LINE__, 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(tpAniSirGlobal 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; + sme_QosEdcaAcType ac; + QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; + tCsrRoamModifyProfileFields profile_fields; + uint8_t psb; + uint8_t tspec_index; + + if (!entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_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 << (SME_QOS_EDCA_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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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, sme_QosEdcaAcType ac) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + sme_QosEdcaAcType acIndex; + bool status = false; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (acIndex = SME_QOS_EDCA_AC_BE; acIndex < SME_QOS_EDCA_AC_MAX; + 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]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: handoffRequested %d updateHandOff %d", + __func__, __LINE__, 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 < CSR_ROAM_SESSION_MAX; ++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(tpAniSirGlobal pMac, + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Flow List empty, can't search", + __func__, __LINE__); + 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(pMac), + 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(tpAniSirGlobal pMac, + 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Flow List empty, can't search", + __func__, __LINE__); + 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(pMac), + 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(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + sme_QosEdcaAcType ac; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("invoked on session %d"), sessionId); + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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; + tpAniSirGlobal mac = MAC_CONTEXT(mac_handle); + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id %d is invalid", + __func__, __LINE__, sessionId); + return false; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d is inactive", + __func__, __LINE__, sessionId); + return false; + } + + if (!pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d has an Invalid BSS Descriptor", + __func__, __LINE__, sessionId); + return false; + } + + hstatus = csr_get_parsed_bss_description_ies(mac, + pSession->assocInfo.pBssDesc, + &pIes); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to parse BSS IEs", + __func__, __LINE__, 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) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d HT Caps aren't present but application set ack policy to HT ", + __func__, __LINE__, sessionId); + + qdf_mem_free(pIes); + return false; + } + + qdf_mem_free(pIes); + return true; +} + +static bool sme_qos_validate_requested_params(tpAniSirGlobal 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(tpAniSirGlobal pMac, uint8_t sessionId, + eSmeCommandType cmdType, + struct sme_qos_wmmtspecinfo *pQoSInfo, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + QDF_STATUS status = QDF_STATUS_E_RESOURCES; + tSmeCmd *pCommand = NULL; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: fail to get command buffer for command %d", + __func__, __LINE__, cmdType); + break; + } + pCommand->command = cmdType; + pCommand->sessionId = sessionId; + switch (cmdType) { + case eSmeCommandAddTs: + if (pQoSInfo) { + status = QDF_STATUS_SUCCESS; + pCommand->u.qosCmd.tspecInfo = *pQoSInfo; + pCommand->u.qosCmd.ac = ac; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: NULL pointer passed", + __func__, __LINE__); + 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: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid command type %d", + __func__, __LINE__, cmdType); + status = QDF_STATUS_E_INVAL; + break; + } + } while (0); + if (QDF_IS_STATUS_SUCCESS(status) && pCommand) + csr_queue_sme_command(pMac, pCommand, false); + else if (pCommand) + qos_release_command(pMac, pCommand); + + return status; +} + +bool qos_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fRemoveCmd = true; + + do { + switch (pCommand->command) { + case eSmeCommandAddTs: + status = + sme_qos_add_ts_req(pMac, (uint8_t) + pCommand->sessionId, + &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(pMac, (uint8_t) + pCommand->sessionId, + pCommand->u.qosCmd.ac, + pCommand->u.qosCmd.tspec_mask); + if (QDF_IS_STATUS_SUCCESS(status)) + fRemoveCmd = false; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid command type %d", + __func__, __LINE__, 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(tpAniSirGlobal mac_ctx, + uint8_t session_id, struct sme_qos_wmmtspecinfo *qos_info, + sme_QosEdcaAcType 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; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL(" 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 reqest 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 safegaurd 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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "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.pMac = 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "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); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("sme_qos_setup returned in SME_QOS_QOS_ON state")); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("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)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("UAPSD is setup already status = %d "), + status); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_qos_setup return status = %d "), + status); + } + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Re-Add request in state = %d buffer the request"), + ac_info->curr_state); + cmd.command = SME_QOS_RESEND_REQ; + cmd.pMac = 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))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL(" 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, */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("ReAdd 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(tpAniSirGlobal pMac, uint8_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + sme_QosEdcaAcType ac; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; 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(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModFields, bool fForce) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + QDF_STATUS status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Invoked on session %d with UAPSD mask 0x%X", + __func__, __LINE__, sessionId, pModFields->uapsd_mask); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + status = csr_reassoc(pMac, sessionId, pModFields, &pSession->roamID, + fForce); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Update the state to Handoff so subsequent requests are + * queued until this one is finished + */ + sme_QosEdcaAcType ac; + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: AC[%d] is in state [%d]", + __func__, __LINE__, 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 + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: Software Test made the flow counter wrap, QoS may no longer be functional", + __func__, __LINE__); + 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++; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("token %d"), token); + return token; +} +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ diff --git a/drivers/staging/qcacld-3.0/core/sme/src/rrm/sme_rrm.c b/drivers/staging/qcacld-3.0/core/sme/src/rrm/sme_rrm.c new file mode 100644 index 0000000000000000000000000000000000000000..9548e5512afd1664a62031850f3c5bf8192d944a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/rrm/sme_rrm.c @@ -0,0 +1,1618 @@ +/* + * 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. + */ + +/* + * DOC: sme_rrm.c + * + * Implementation for SME RRM APIs + */ + +#include "ani_global.h" +#include "sme_inside.h" +#include "sme_api.h" +#include "cfg_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 + +/* 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 + +uint64_t rrm_scan_timer; + +/** + * rrm_ll_purge_neighbor_cache() -Purges all the entries in the neighbor cache + * + * @pMac: 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(tpAniSirGlobal pMac, + 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 + * @pMac: 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(tpAniSirGlobal pMac, + QDF_STATUS qdf_status) +{ + NeighborReportRspCallback callback; + void *callbackContext; + + /* Reset the neighbor response pending status */ + pMac->rrm.rrmSmeContext.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(&pMac->rrm.rrmSmeContext. + neighborReqControlInfo. + neighborRspWaitTimer)) { + sme_debug("No entry in neighbor report cache"); + qdf_mc_timer_stop(&pMac->rrm.rrmSmeContext. + neighborReqControlInfo.neighborRspWaitTimer); + } + callback = + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallback; + callbackContext = + pMac->rrm.rrmSmeContext.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. + */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallback = NULL; + pMac->rrm.rrmSmeContext.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 + * @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(tpAniSirGlobal mac_ctx, + tCsrScanResultInfo **result_arr, uint8_t msrmnt_status, + uint8_t bss_count) +{ + tpSirBssDescription 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; + tpSirBssDescription bss_desc_to_free[SIR_BCN_REPORT_MAX_BSS_DESC] = {0}; + + if (NULL == 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 (NULL == beacon_rep) { + sme_err("Unable to allocate memory for beacon report"); + return QDF_STATUS_E_NOMEM; + } + beacon_rep->messageType = eWNI_SME_BEACON_REPORT_RESP_XMIT_IND; + beacon_rep->length = length; + 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 == NULL) + 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); + bss_desc_to_free[i] = + beacon_rep->pBssDescription[i]; + sme_debug("RRM Result Bssid = " MAC_ADDRESS_STR + " chan= %d, rssi = -%d", + MAC_ADDR_ARRAY( + beacon_rep->pBssDescription[i]->bssId), + beacon_rep->pBssDescription[i]->channelId, + 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 == NULL) + || (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(bss_desc_to_free[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 + * @session_id - session id + * @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( + tpAniSirGlobal mac_ctx, uint32_t session_id, + uint8_t channel, tCsrScanResultInfo **result_arr, + uint8_t msrmnt_status, uint8_t bss_count) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS fill_ie_status; + tpSirBssDescription 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; + struct csr_roam_info roam_info; + tSirEseBcnReportRsp bcn_rpt_rsp; + tpSirEseBcnReportRsp bcn_report = &bcn_rpt_rsp; + tpCsrEseBeaconReqParams cur_meas_req = NULL; + uint8_t i = 0, j = 0; + tBcnReportFields *bcn_rpt_fields; + + if (NULL == rrm_ctx) { + sme_err("rrm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == result_arr && !msrmnt_status) { + sme_err("Beacon report xmit Ind to HDD Failed"); + return QDF_STATUS_E_FAILURE; + } + + 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].channel == + channel) { + cur_meas_req = + &rrm_ctx->eseBcnReqInfo.bcnReq[i]; + break; + } + } + if (NULL != cur_meas_req) + bcn_report->measurementToken = + cur_meas_req->measurementToken; + sme_debug("Channel: %d MeasToken: %d", channel, + bcn_report->measurementToken); + + j = 0; + while (cur_result) { + bss_desc = &cur_result->BssDescriptor; + if (NULL == 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 = + bss_desc->channelId; + bcn_report->bcnRepBssInfo[j].bcnReportFields.Spare = 0; + if (NULL != 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"MAC_ADDRESS_STR" Channel: %d Rssi: %d", + MAC_ADDR_ARRAY(bss_desc->bssId), + bss_desc->channelId, (-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, + 0, 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); + 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 + * @num_chan: number of channels + * @chan_list: list of channels 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(tpAniSirGlobal mac_ctx, + uint8_t num_chan, + uint8_t *chan_list, + uint8_t measurementdone) +{ + mac_handle_t mac_handle = MAC_HANDLE(mac_ctx); + tCsrScanResultFilter filter; + tScanResultHandle result_handle; + tCsrScanResultInfo *scan_results, *next_result; + tCsrScanResultInfo **scanresults_arr = NULL; + struct scan_result_list *result_list; + QDF_STATUS status; + uint8_t num_scan_results, counter = 0; + tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + uint32_t session_id; + struct csr_roam_info *roam_info = NULL; + tSirScanType scan_type; + struct csr_roam_session *session; + + qdf_mem_zero(&filter, sizeof(filter)); + filter.BSSIDs.numOfBSSIDs = 1; + filter.BSSIDs.bssid = (struct qdf_mac_addr *)&rrm_ctx->bssId; + + if (rrm_ctx->ssId.length) { + filter.SSIDs.SSIDList = + (tCsrSSIDInfo *) qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (filter.SSIDs.SSIDList == NULL) { + sme_err("qdf_mem_malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + filter.SSIDs.SSIDList->SSID.length = + rrm_ctx->ssId.length; + qdf_mem_copy(filter.SSIDs.SSIDList->SSID.ssId, + rrm_ctx->ssId.ssId, rrm_ctx->ssId.length); + filter.SSIDs.numOfSSIDs = 1; + } else { + filter.SSIDs.numOfSSIDs = 0; + } + + filter.ChannelInfo.numOfChannels = num_chan; + filter.ChannelInfo.ChannelList = chan_list; + filter.fMeasurement = true; + + /* + * 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->sessionId; + } + status = sme_scan_get_result(mac_handle, (uint8_t)session_id, + &filter, &result_handle); + + if (filter.SSIDs.SSIDList) + qdf_mem_free(filter.SSIDs.SSIDList); + + sme_debug("RRM Measurement Done %d", measurementdone); + if (NULL == 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 respose 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, + session_id, chan_list[0], + NULL, measurementdone, 0); + else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + NULL, measurementdone, 0); + return status; + } + scan_results = sme_scan_result_get_first(mac_handle, result_handle); + if (NULL == 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, + session_id, + chan_list[0], + NULL, + measurementdone, + 0); + } else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + 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) { + sme_err("Failed to allocate scanresults_arr"); + status = QDF_STATUS_E_NOMEM; + goto rrm_send_scan_results_done; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (NULL == roam_info) { + sme_err("malloc failed"); + status = QDF_STATUS_E_NOMEM; + goto rrm_send_scan_results_done; + } + + session = CSR_GET_SESSION(mac_ctx, session_id); + if ((!session) || (!csr_is_conn_state_connected_infra( + mac_ctx, session_id)) || + (NULL == session->pConnectBssDesc)) { + sme_err("Invaild session"); + status = QDF_STATUS_E_FAILURE; + goto rrm_send_scan_results_done; + } + + 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]; + + while (scan_results) { + /* + * In passive scan, sta listens beacon. 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; + + if ((scan_type == eSIR_PASSIVE_SCAN) && + (!qdf_mem_cmp(scan_results->BssDescriptor.bssId, + session->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)))) { + is_conn_bss_found = true; + sme_debug("Connected BSS in scan results"); + } + next_result = sme_scan_result_get_next(mac_handle, + 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)) { + roam_info->pBssDesc = &scan_results->BssDescriptor; + csr_roam_call_callback(mac_ctx, session_id, roam_info, + 0, eCSR_ROAM_UPDATE_SCAN_RESULT, + eCSR_ROAM_RESULT_NONE); + scanresults_arr[counter++] = scan_results; + } + scan_results = next_result; + if (counter >= num_scan_results) + break; + } + /* + * 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, + session_id, chan_list[0], + scanresults_arr, measurementdone, + counter); + else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + scanresults_arr, measurementdone, + counter); + } + +rrm_send_scan_results_done: + if (scanresults_arr) + qdf_mem_free(scanresults_arr); + qdf_mem_free(roam_info); + sme_scan_result_purge(result_handle); + + return status; +} + + +/** + * sme_rrm_scan_request_callback() -Sends the beacon report xmit to PE + * @halHandle: Pointer to the Hal Handle. + * @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(tHalHandle halHandle, + uint8_t sessionId, + uint32_t scanId, + eCsrScanStatus status) +{ + uint16_t interval; + tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + uint32_t time_tick; + QDF_STATUS qdf_status; + uint32_t session_id; + bool valid_result = true; + + /* + * RRM scan response received after roaming to different AP. + * Post message to PE for rrm cleanup. + */ + qdf_status = csr_roam_get_session_id_from_bssid(pMac, + &pSmeRrmContext->sessionBssId, + &session_id); + if (qdf_status == QDF_STATUS_E_FAILURE) { + sme_debug("Cleanup RRM context due to STA roaming"); + valid_result = false; + } + + /* if any more channels are pending, start a timer of a random value + * within randomization interval. + */ + if (((pSmeRrmContext->currentIndex + 1) < + pSmeRrmContext->channelList.numOfChannels) && valid_result) { + sme_rrm_send_scan_result(pMac, 1, + &pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext + ->currentIndex], + false); + /* Advance the current index. */ + pSmeRrmContext->currentIndex++; + /* start the timer to issue next request. */ + /* From timer tick get a random number within 10ms and max + * randmization interval. + */ + time_tick = qdf_mc_timer_get_system_ticks(); + interval = + time_tick % (pSmeRrmContext->randnIntvl - 10 + 1) + 10; + + sme_debug("Set timer for interval %d ", interval); + qdf_status = qdf_mc_timer_start(&pSmeRrmContext->IterMeasTimer, + interval); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + qdf_mem_free(pSmeRrmContext->channelList.ChannelList); + pSmeRrmContext->channelList.ChannelList = NULL; + sme_reset_ese_bcn_req_in_progress(pSmeRrmContext); + } + + } 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(pMac, 1, + &pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext + ->currentIndex], + true); + qdf_mem_free(pSmeRrmContext->channelList.ChannelList); + pSmeRrmContext->channelList.ChannelList = NULL; + sme_reset_ese_bcn_req_in_progress(pSmeRrmContext); + } + + return QDF_STATUS_SUCCESS; +} + +static void sme_rrm_scan_event_callback(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + uint32_t scan_id; + uint8_t session_id; + eCsrScanStatus scan_status = eCSR_SCAN_FAILURE; + tHalHandle hal_handle; + bool success = false; + session_id = wlan_vdev_get_id(vdev); + scan_id = event->scan_id; + hal_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!hal_handle) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + FL("invalid h_hal")); + return; + } + + 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; + + sme_rrm_scan_request_callback(hal_handle, session_id, + scan_id, scan_status); +} + + +/** + * 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 + */ +static QDF_STATUS sme_rrm_issue_scan_req(tpAniSirGlobal mac_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpRrmSMEContext sme_rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + uint32_t session_id; + tSirScanType scan_type; + + 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= "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(sme_rrm_ctx->sessionBssId.bytes)); + status = QDF_STATUS_E_FAILURE; + goto free_ch_lst; + } + + if ((sme_rrm_ctx->currentIndex) >= + sme_rrm_ctx->channelList.numOfChannels) { + sme_rrm_send_beacon_report_xmit_ind(mac_ctx, 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; + uint64_t current_time; + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev; + uint32_t chan_num; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_debug("Failed to allocate memory"); + status = QDF_STATUS_E_NOMEM; + goto free_ch_lst; + } + + 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 free_ch_lst; + } + ucfg_scan_init_default_params(vdev, req); + req->scan_req.scan_id = ucfg_scan_get_scan_id(mac_ctx->psoc); + 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 > req->scan_req.dwell_time_passive) + req->scan_req.dwell_time_passive = + max_chan_time; + sme_debug("Passive Max Dwell Time(%d)", + req->scan_req.dwell_time_passive); + } else { + if (max_chan_time > req->scan_req.dwell_time_active) + req->scan_req.dwell_time_active = max_chan_time; + sme_debug("Active Max Dwell Time(%d)", + req->scan_req.dwell_time_active); + } + + 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 = 1; + chan_num = sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex]; + req->scan_req.chan_list.chan[0].freq = + wlan_chan_to_freq(chan_num); + sme_debug("Duration %d On channel %d freq %d", + req->scan_req.dwell_time_active, + chan_num, + req->scan_req.chan_list.chan[0].freq); + status = ucfg_scan_start(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + if (QDF_IS_STATUS_ERROR(status)) + goto free_ch_lst; + + 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; + if ((sme_rrm_ctx->currentIndex + 1) < + sme_rrm_ctx->channelList.numOfChannels) { + sme_rrm_send_scan_result(mac_ctx, 1, + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex], false); + /* Advance the current index. */ + sme_rrm_ctx->currentIndex++; + sme_rrm_issue_scan_req(mac_ctx); +#ifdef FEATURE_WLAN_ESE + sme_rrm_ctx->eseBcnReqInProgress = false; +#endif + return status; + } 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, 1, + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex], true); + goto free_ch_lst; + } + } else { + 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 + */ + sme_rrm_send_beacon_report_xmit_ind(mac_ctx, NULL, true, 0); + goto free_ch_lst; + } + +free_ch_lst: + qdf_mem_free(sme_rrm_ctx->channelList.ChannelList); + sme_rrm_ctx->channelList.ChannelList = NULL; + return status; +} + +/** + * sme_rrm_process_beacon_report_req_ind() -Process beacon report request + * @pMac:- Global Mac structure + * @pMsgBuf:- 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(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + tpSirBeaconReportReqInd pBeaconReq = (tpSirBeaconReportReqInd) pMsgBuf; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + uint32_t len = 0, i = 0; + + sme_debug("Received Beacon report request ind Channel = %d", + pBeaconReq->channelInfo.channelNum); + + if (pBeaconReq->channelList.numChannels > + SIR_ESE_MAX_MEAS_IE_REQS) { + sme_err("Beacon report request numChannels:%u exceeds max num channels", + pBeaconReq->channelList.numChannels); + return QDF_STATUS_E_INVAL; + } + + /* section 11.10.8.1 (IEEE Std 802.11k-2008) */ + /* channel 0 and 255 has special meaning. */ + if ((pBeaconReq->channelInfo.channelNum == 0) || + ((pBeaconReq->channelInfo.channelNum == 255) + && (pBeaconReq->channelList.numChannels == 0))) { + /* Add all the channel in the regulatory domain. */ + wlan_cfg_get_str_len(pMac, WNI_CFG_VALID_CHANNEL_LIST, &len); + if (pSmeRrmContext->channelList.ChannelList) { + qdf_mem_free(pSmeRrmContext->channelList.ChannelList); + pSmeRrmContext->channelList.ChannelList = NULL; + } + pSmeRrmContext->channelList.ChannelList = qdf_mem_malloc(len); + if (pSmeRrmContext->channelList.ChannelList == NULL) { + sme_err("qdf_mem_malloc failed"); + return QDF_STATUS_E_NOMEM; + } + csr_get_cfg_valid_channels(pMac, pSmeRrmContext->channelList. + ChannelList, &len); + pSmeRrmContext->channelList.numOfChannels = (uint8_t) len; + } else { + len = 0; + pSmeRrmContext->channelList.numOfChannels = 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 (pBeaconReq->channelInfo.channelNum != 255) + len = 1; + + len += pBeaconReq->channelList.numChannels; + + if (pSmeRrmContext->channelList.ChannelList) { + qdf_mem_free(pSmeRrmContext->channelList.ChannelList); + pSmeRrmContext->channelList.ChannelList = NULL; + } + pSmeRrmContext->channelList.ChannelList = qdf_mem_malloc(len); + if (pSmeRrmContext->channelList.ChannelList == NULL) { + sme_err("qdf_mem_malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + if (pBeaconReq->channelInfo.channelNum != 255) { + if (csr_roam_is_channel_valid + (pMac, pBeaconReq->channelInfo.channelNum)) + pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->channelList. + numOfChannels++] = + pBeaconReq->channelInfo.channelNum; + else + sme_err("Invalid channel: %d", + pBeaconReq->channelInfo.channelNum); + } + + for (i = 0; i < pBeaconReq->channelList.numChannels; i++) { + if (csr_roam_is_channel_valid(pMac, pBeaconReq-> + channelList.channelNumber[i])) { + pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->channelList. + numOfChannels] = pBeaconReq->channelList. + channelNumber[i]; + pSmeRrmContext->channelList.numOfChannels++; + } + } + } + + /* Copy session bssid */ + qdf_mem_copy(pSmeRrmContext->sessionBssId.bytes, pBeaconReq->bssId, + sizeof(tSirMacAddr)); + + /* copy measurement bssid */ + qdf_mem_copy(pSmeRrmContext->bssId, pBeaconReq->macaddrBssid, + sizeof(tSirMacAddr)); + + /* Copy ssid */ + qdf_mem_copy(&pSmeRrmContext->ssId, &pBeaconReq->ssId, + sizeof(tAniSSID)); + + pSmeRrmContext->token = pBeaconReq->uDialogToken; + pSmeRrmContext->regClass = pBeaconReq->channelInfo.regulatoryClass; + pSmeRrmContext->randnIntvl = + QDF_MAX(pBeaconReq->randomizationInterval, + pSmeRrmContext->rrmConfig.max_randn_interval); + pSmeRrmContext->currentIndex = 0; + pSmeRrmContext->msgSource = pBeaconReq->msgSource; + qdf_mem_copy((uint8_t *) &pSmeRrmContext->measMode, + (uint8_t *) &pBeaconReq->fMeasurementtype, + SIR_ESE_MAX_MEAS_IE_REQS); + qdf_mem_copy((uint8_t *) &pSmeRrmContext->duration, + (uint8_t *) &pBeaconReq->measurementDuration, + SIR_ESE_MAX_MEAS_IE_REQS); + + sme_debug("token: %d regClass: %d randnIntvl: %d msgSource: %d", + pSmeRrmContext->token, pSmeRrmContext->regClass, + pSmeRrmContext->randnIntvl, pSmeRrmContext->msgSource); + + return sme_rrm_issue_scan_req(pMac); +} + +/** + * 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(tpAniSirGlobal pMac, uint8_t + sessionId, tpRrmNeighborReq + pNeighborReq, + tpRrmNeighborRspCallbackInfo + callbackInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirNeighborReportReqInd pMsg; + struct csr_roam_session *pSession; + + sme_debug("Request to send Neighbor report request received "); + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sme_err("Invalid session %d", sessionId); + return QDF_STATUS_E_INVAL; + } + pSession = CSR_GET_SESSION(pMac, sessionId); + + /* If already a report is pending, return failure */ + if (true == + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + isNeighborRspPending) { + sme_err("Neighbor request already pending.. Not allowed"); + return QDF_STATUS_E_AGAIN; + } + + pMsg = qdf_mem_malloc(sizeof(tSirNeighborReportReqInd)); + if (NULL == pMsg) { + sme_err("Unable to allocate memory for Neighbor request"); + return QDF_STATUS_E_NOMEM; + } + + rrm_ll_purge_neighbor_cache(pMac, + &pMac->rrm.rrmSmeContext.neighborReportCache); + + pMsg->messageType = eWNI_SME_NEIGHBOR_REPORT_REQ_IND; + pMsg->length = sizeof(tSirNeighborReportReqInd); + qdf_mem_copy(&pMsg->bssId, &pSession->connectedProfile.bssid, + sizeof(tSirMacAddr)); + 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 + */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallback = callbackInfo->neighborRspCallback; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallbackContext = + callbackInfo->neighborRspCallbackContext; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending = + true; + + /* Start neighbor response wait timer now */ + qdf_mc_timer_start(&pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspWaitTimer, callbackInfo->timeout); + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_calculate_neighbor_ap_roam_score() - caclulates 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(tpAniSirGlobal mac_ctx, + tpRrmNeighborReportDesc nbr_report_desc) +{ + tpSirNeighborBssDescripton nbr_bss_desc; + uint32_t roam_score = 0; +#ifdef FEATURE_WLAN_ESE + uint8_t session_id; +#endif + if (NULL == nbr_report_desc) { + QDF_ASSERT(0); + return; + } + + if (NULL == 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; + /* It has come in the report so its the best score */ + if (csr_neighbor_roam_is11r_assoc(mac_ctx, session_id) == false) { + /* 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 + * @pNeighborReportDesc - Neighbor BSS Descriptor node to be stored in cache + * + * 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(tpAniSirGlobal pMac, + tpRrmNeighborReportDesc pNeighborReportDesc) +{ + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + tListElem *pEntry; + tRrmNeighborReportDesc *pTempNeighborReportDesc; + + if (NULL == pNeighborReportDesc) { + QDF_ASSERT(0); + return; + } + if (NULL == 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 != NULL) { + 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 + * @pMac - Global MAC structure + * @pMsgBuf - 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(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirNeighborReportInd pNeighborRpt = (tpSirNeighborReportInd) pMsgBuf; + tpRrmNeighborReportDesc pNeighborReportDesc; + uint8_t i = 0; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + /* Purge the cache on reception of unsolicited neighbor report */ + if (!pMac->rrm.rrmSmeContext.neighborReqControlInfo. + isNeighborRspPending) + rrm_ll_purge_neighbor_cache(pMac, + &pMac->rrm.rrmSmeContext. + neighborReportCache); + + for (i = 0; i < pNeighborRpt->numNeighborReports; i++) { + pNeighborReportDesc = + qdf_mem_malloc(sizeof(tRrmNeighborReportDesc)); + if (NULL == pNeighborReportDesc) { + sme_err("Failed to alloc memory for RRM report desc"); + status = QDF_STATUS_E_NOMEM; + goto end; + + } + + pNeighborReportDesc->pNeighborBssDescription = + qdf_mem_malloc(sizeof(tSirNeighborBssDescription)); + if (NULL == pNeighborReportDesc->pNeighborBssDescription) { + sme_err("Failed to alloc mem for RRM BSS Description"); + qdf_mem_free(pNeighborReportDesc); + status = QDF_STATUS_E_NOMEM; + goto end; + } + qdf_mem_copy(pNeighborReportDesc->pNeighborBssDescription, + &pNeighborRpt->sNeighborBssDescription[i], + sizeof(tSirNeighborBssDescription)); + + sme_debug("Received neighbor report with Neighbor BSSID: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + pNeighborRpt->sNeighborBssDescription[i].bssId)); + + rrm_calculate_neighbor_ap_roam_score(pMac, pNeighborReportDesc); + + if (pNeighborReportDesc->roamScore > 0) { + rrm_store_neighbor_rpt_by_roam_score(pMac, + pNeighborReportDesc); + } else { + sme_err("Roam score of BSSID " MAC_ADDRESS_STR + " is 0, Ignoring..", + MAC_ADDR_ARRAY(pNeighborRpt-> + sNeighborBssDescription[i]. + bssId)); + + qdf_mem_free( + pNeighborReportDesc->pNeighborBssDescription); + qdf_mem_free(pNeighborReportDesc); + } + } +end: + + if (!csr_ll_count(&pMac->rrm.rrmSmeContext.neighborReportCache)) + qdf_status = QDF_STATUS_E_FAILURE; + + rrm_indicate_neighbor_report_result(pMac, qdf_status); + + return status; +} + +/** + * sme_rrm_msg_processor()-Process RRM message + * @pMac - Pointer to the global MAC parameter structure. + * @msg_type - the type of msg passed by PE as defined in wni_api.h + * @pMsgBuf - 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(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL(" 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(pMac, pMsgBuf); + break; + + case eWNI_SME_BEACON_REPORT_REQ_IND: + sme_rrm_process_beacon_report_req_ind(pMac, pMsgBuf); + break; + + default: + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_rrm_msg_processor:unknown msg type = %d"), + msg_type); + + break; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_iter_meas_timer_handle() - Timer handler to handlet the timeout + * @ pMac - The handle returned by mac_open. + * + * Timer handler to handlet the timeout condition when a specific BT + * stop event does not come back, in which case to restore back the + * heartbeat timer. + * + * Return: NULL + */ +static void rrm_iter_meas_timer_handle(void *userData) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) userData; + + sme_warn("Randomization timer expired...send on next channel"); + /* Issue a scan req for next channel. */ + sme_rrm_issue_scan_req(pMac); +} +/** + * rrm_neighbor_rsp_timeout_handler() - Timer handler to handlet the timeout + * @pMac - 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) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) userData; + + sme_warn("Neighbor Response timed out"); + rrm_indicate_neighbor_report_result(pMac, QDF_STATUS_E_FAILURE); +} + +/** + * rrm_open() - Initialze all RRM module + * @ pMac: The handle returned by mac_open. + * + * Initialze all RRM module. + * + * Return: QDF_STATUS + */ +QDF_STATUS rrm_open(tpAniSirGlobal pMac) +{ + + QDF_STATUS qdf_status; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + + pSmeRrmContext->rrmConfig.max_randn_interval = 50; /* ms */ + + qdf_status = qdf_mc_timer_init(&pSmeRrmContext->IterMeasTimer, + QDF_TIMER_TYPE_SW, + rrm_iter_meas_timer_handle, + (void *)pMac); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to init timer"); + + return QDF_STATUS_E_FAILURE; + } + + qdf_status = + qdf_mc_timer_init(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer, QDF_TIMER_TYPE_SW, + rrm_neighbor_rsp_timeout_handler, + (void *)pMac); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to init timer"); + + return QDF_STATUS_E_FAILURE; + } + + pSmeRrmContext->neighborReqControlInfo.isNeighborRspPending = false; + + qdf_ret_status = csr_ll_open(&pSmeRrmContext->neighborReportCache); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to open neighbor cache result"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_close() - Release all RRM modules and their resources. + * @pMac - 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(tpAniSirGlobal pMac) +{ + + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&pSmeRrmContext->IterMeasTimer)) { + qdf_status = qdf_mc_timer_stop(&pSmeRrmContext->IterMeasTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Timer stop fail")); + } + } + + if (pSmeRrmContext->channelList.ChannelList) { + qdf_mem_free(pSmeRrmContext->channelList.ChannelList); + pSmeRrmContext->channelList.ChannelList = NULL; + } + + qdf_status = qdf_mc_timer_destroy(&pSmeRrmContext->IterMeasTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Fail to destroy timer")); + + } + + 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_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Timer stop fail")); + } + } + + qdf_status = + qdf_mc_timer_destroy(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Fail to destroy timer")); + + } + + rrm_ll_purge_neighbor_cache(pMac, &pSmeRrmContext->neighborReportCache); + + csr_ll_close(&pSmeRrmContext->neighborReportCache); + + return qdf_status; + +} + +/** + * rrm_change_default_config_param() - Changing default config param to new + * @pMac - The handle returned by mac_open. + * param pRrmConfig - pointer to new rrm configs. + * + * Return: QDF_STATUS + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS rrm_change_default_config_param(tpAniSirGlobal pMac, + struct rrm_config_param *rrm_config) +{ + qdf_mem_copy(&pMac->rrm.rrmSmeContext.rrmConfig, rrm_config, + sizeof(struct rrm_config_param)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS rrm_start(tpAniSirGlobal mac_ctx) +{ + tpRrmSMEContext smerrmctx = &mac_ctx->rrm.rrmSmeContext; + + /* Register with scan component */ + smerrmctx->req_id = ucfg_scan_register_requester(mac_ctx->psoc, + "RRM", + sme_rrm_scan_event_callback, + smerrmctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS rrm_stop(tpAniSirGlobal mac_ctx) +{ + tpRrmSMEContext smerrmctx = &mac_ctx->rrm.rrmSmeContext; + + ucfg_scan_unregister_requester(mac_ctx->psoc, smerrmctx->req_id); + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma.h new file mode 100644 index 0000000000000000000000000000000000000000..2ac5866c782d2ac3eab829ae05f08b6a6743e8b9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma.h @@ -0,0 +1,2556 @@ +/* + * 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 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 "cfg_api.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 + +/* 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 WMA_MAX_SUPPORTED_BSS SIR_MAX_SUPPORTED_BSS + +#define WMA_MAX_MGMT_MPDU_LEN 2000 + +#define MAX_PRINT_FAILURE_CNT 50 + +#define WMA_INVALID_VDEV_ID 0xFF + +/* Deprecated logging macros, to be removed. Please do not use in new code */ +#define WMA_LOGD(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, ## args) +#define WMA_LOGI(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_INFO, ## args) +#define WMA_LOGW(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_WARN, ## args) +#define WMA_LOGE(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, ## args) +#define WMA_LOGP(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_FATAL, ## args) + +#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_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_WMA, params) + +#define WMA_DEBUG_ALWAYS + +#ifdef WMA_DEBUG_ALWAYS +#define WMA_LOGA(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_FATAL, ## args) +#else +#define WMA_LOGA(args ...) +#endif + +#define WMA_WILDCARD_PDEV_ID 0x0 + +#define WMA_HW_DEF_SCAN_MAX_DURATION 30000 /* 30 secs */ + +#define WMA_SCAN_NPROBES_DEFAULT (2) + +#define WMA_BCAST_MAC_ADDR (0xFF) +#define WMA_MCAST_IPV4_MAC_ADDR (0x01) +#define WMA_MCAST_IPV6_MAC_ADDR (0x33) +#define WMA_ICMP_PROTOCOL (0x01) + +#define WMA_IS_EAPOL_GET_MIN_LEN 14 +#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_IS_ARP_GET_MIN_LEN 14 +#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 + +/** + * ds_mode: distribution system mode + * @IEEE80211_NO_DS: NO DS at either side + * @IEEE80211_TO_DS: DS at receiver side + * @IEEE80211_FROM_DS: DS at sender side + * @IEEE80211_DS_TO_DS: DS at both sender and revceiver side + */ +enum ds_mode { + IEEE80211_NO_DS, + IEEE80211_TO_DS, + IEEE80211_FROM_DS, + IEEE80211_DS_TO_DS +}; + +/* 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_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) + + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_MAX_EXTSCAN_MSG_SIZE 1536 +#define WMA_EXTSCAN_REST_TIME 100 +#define WMA_EXTSCAN_MAX_SCAN_TIME 50000 +#define WMA_EXTSCAN_BURST_DURATION 150 +#endif + +#define WMA_CHAN_START_RESP 0 +#define WMA_CHAN_END_RESP 1 + +#define WMA_BCN_BUF_MAX_SIZE 512 +#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_WOW_PTRN_MASK_VALID 0xFF +#define WMA_NUM_BITS_IN_BYTE 8 + +#define WMA_AP_WOW_DEFAULT_PTRN_MAX 4 + +#define WMA_BSS_STATUS_STARTED 0x1 +#define WMA_BSS_STATUS_STOPPED 0x2 + +#define WMA_TARGET_REQ_TYPE_VDEV_START 0x1 +#define WMA_TARGET_REQ_TYPE_VDEV_STOP 0x2 +#define WMA_TARGET_REQ_TYPE_VDEV_DEL 0x3 + +#define WMA_PEER_ASSOC_CNF_START 0x01 +#define WMA_PEER_ASSOC_TIMEOUT (6000) /* 6 seconds */ + +#define WMA_DELETE_STA_RSP_START 0x02 +#define WMA_DELETE_STA_TIMEOUT (6000) /* 6 seconds */ + +#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 + +#ifdef CONFIG_SLUB_DEBUG_ON +#define SLUB_DEBUG_FACTOR (2) +#else +#define SLUB_DEBUG_FACTOR (1) +#endif + +/* FW response timeout values in milli seconds */ +#define WMA_VDEV_START_REQUEST_TIMEOUT (6000) * (SLUB_DEBUG_FACTOR) +#define WMA_VDEV_STOP_REQUEST_TIMEOUT (6000) * (SLUB_DEBUG_FACTOR) +#define WMA_VDEV_HW_MODE_REQUEST_TIMEOUT (6000) * (SLUB_DEBUG_FACTOR) +#define WMA_VDEV_PLCY_MGR_CMD_TIMEOUT (6000) * (SLUB_DEBUG_FACTOR) +#define WMA_VDEV_DUAL_MAC_CFG_TIMEOUT (5000) * (SLUB_DEBUG_FACTOR) + +#define WMA_VDEV_SET_KEY_WAKELOCK_TIMEOUT WAKELOCK_DURATION_RECOMMENDED + +#define WMA_TGT_INVALID_SNR (0) + +#define WMA_TGT_IS_VALID_SNR(x) ((x) >= 0 && (x) < WMA_TGT_MAX_SNR) +#define WMA_TGT_IS_INVALID_SNR(x) (!WMA_TGT_IS_VALID_SNR(x)) + +#define WMA_TX_Q_RECHECK_TIMER_WAIT 2 /* 2 ms */ +#define WMA_TX_Q_RECHECK_TIMER_MAX_WAIT 20 /* 20 ms */ +#define WMA_MAX_NUM_ARGS 8 + +#define WMA_SMPS_MASK_LOWER_16BITS 0xFF +#define WMA_SMPS_MASK_UPPER_3BITS 0x7 +#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 + +/* Default InActivity Time is 200 ms */ +#define POWERSAVE_DEFAULT_INACTIVITY_TIME 200 + +/* Default WOW InActivity Time is 50 ms */ +#define WOW_POWERSAVE_DEFAULT_INACTIVITY_TIME 50 + +/* Default Listen Interval */ +#define POWERSAVE_DEFAULT_LISTEN_INTERVAL 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_SEC_TO_MSEC(sec) (sec * 1000) /* sec to msec */ +#define WMA_MSEC_TO_USEC(msec) (msec * 1000) /* msec to usec */ + +/* Default rssi threshold defined in CFG80211 */ +#define WMA_RSSI_THOLD_DEFAULT -300 + +#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 */ +#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 + +/* + * 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 */ +#define WMA_WSC_OUI { 0x00, 0x50, 0xF2 } /* Microsoft WSC OUI byte */ + +/* 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] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define P2PIE_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + + +#define WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE 1 + +#define WMA_DEFAULT_QPOWER_MAX_PSPOLL_BEFORE_WAKE 1 +#define WMA_DEFAULT_QPOWER_TX_WAKE_THRESHOLD 2 + +#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) + +/** + * 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) + +/* + * 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 + +typedef void (*txFailIndCallback)(uint8_t *peer_mac, uint8_t seqNo); + +typedef void (*tp_wma_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); + +/** + * 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, + WMA_RX_TASKLET_CTX, + WMA_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 + * @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; + 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; + uint8_t tim_bitmap[1]; +} __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 + * + * 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 +} 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; +}; + +/** + * struct wma_wow - store wow patterns + * @magic_ptrn_enable: magic pattern enable/disable + * @wow_enable: wow enable/disable + * @wow_enable_cmd_sent: is wow enable command sent to fw + * @deauth_enable: is deauth wakeup enable/disable + * @disassoc_enable: is disassoc wakeup enable/disable + * @bmiss_enable: is bmiss wakeup enable/disable + * @gtk_pdev_enable: is GTK based wakeup enable/disable + * @gtk_err_enable: is GTK error wakeup enable/disable + * @lphb_cache: lphb cache + * + * This structure stores wow patterns and + * wow related parameters in host. + */ +struct wma_wow { + bool magic_ptrn_enable; + bool wow_enable; + bool wow_enable_cmd_sent; + bool deauth_enable; + bool disassoc_enable; + bool bmiss_enable; + bool gtk_err_enable[WMA_MAX_SUPPORTED_BSS]; +}; + +#ifdef WLAN_FEATURE_11W +#define CMAC_IPN_LEN (6) +#define WMA_IGTK_KEY_INDEX_4 (4) +#define WMA_IGTK_KEY_INDEX_5 (5) + +/** + * struct wma_igtk_ipn_t - GTK IPN info + * @ipn: IPN info + */ +typedef struct { + uint8_t ipn[CMAC_IPN_LEN]; +} wma_igtk_ipn_t; + +/** + * struct wma_igtk_key_t - GTK key + * @key_length: key length + * @key: key + * @key_id: key id + * @key_cipher: key type + */ +typedef struct { + uint16_t key_length; + uint8_t key[CSR_AES_GMAC_256_KEY_LEN]; + + /* IPN is maintained per iGTK keyID + * 0th index for iGTK keyID = 4; + * 1st index for iGTK KeyID = 5 + */ + wma_igtk_ipn_t key_id[2]; + uint32_t key_cipher; +} wma_igtk_key_t; +#endif + +/** + * struct vdev_restart_params_t - vdev restart parameters + * @vdev_id: vdev id + * @ssid: ssid + * @flags: flags + * @requestor_id: requestor id + * @chan: channel + * @hidden_ssid_restart_in_progress: hidden ssid restart flag + * @ssidHidden: is ssid hidden or not + */ +typedef struct { + A_UINT32 vdev_id; + wmi_ssid ssid; + A_UINT32 flags; + A_UINT32 requestor_id; + A_UINT32 disable_hw_ack; + wmi_channel chan; + qdf_atomic_t hidden_ssid_restart_in_progress; + uint8_t ssidHidden; +} vdev_restart_params_t; + +struct roam_synch_frame_ind { + uint32_t bcn_probe_rsp_len; + uint8_t *bcn_probe_rsp; + uint8_t is_beacon; + uint32_t reassoc_req_len; + uint8_t *reassoc_req; + uint32_t reassoc_rsp_len; + uint8_t *reassoc_rsp; +}; + + +/** + * struct wma_txrx_node - txrx node + * @addr: mac address + * @bssid: bssid + * @handle: wma handle + * @beacon: beacon info + * @vdev_restart_params: vdev restart parameters + * @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 + * @ptrn_match_enable: is pattern match is enable or not + * @num_wow_default_patterns: number of default wow patterns configured for vdev + * @num_wow_user_patterns: number of user wow patterns configured for vdev + * @conn_state: connection state + * @beaconInterval: beacon interval + * @llbCoexist: 11b coexist + * @shortSlotTimeSupported: is short slot time supported or not + * @dtimPeriod: DTIM period + * @chanmode: channel mode + * @vht_capable: VHT capablity flag + * @ht_capable: HT capablity flag + * @mhz: channel frequency in KHz + * @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 + * @key: GTK key + * @uapsd_cached_val: uapsd cached value + * @stats_rsp: stats response + * @fw_stats_set: fw stats value + * @del_staself_req: delete sta self request + * @bss_status: bss status + * @rate_flags: rate flags + * @nss: nss value + * @is_channel_switch: is channel switch + * @pause_bitmap: pause bitmap + * @tx_power: tx power in dbm + * @max_tx_power: max tx power in dbm + * @nwType: network type (802.11a/b/g/n/ac) + * @staKeyParams: sta key parameters + * @ps_enabled: is powersave enable/disable + * @peer_count: peer count + * @peer_lock: peer lock + * @roam_synch_in_progress: flag is in progress or not + * @plink_status_req: link status request + * @psnr_req: snr request + * @delay_before_vdev_stop: delay + * @tx_streams: number of tx streams can be used by the vdev + * @rx_streams: number of rx streams can be used by the vdev + * @chain_mask: chain mask can be used by the vdev + * @mac_id: the mac on which vdev is on + * @wep_default_key_idx: wep default index for group key + * @arp_offload_req: cached arp offload request + * @ns_offload_req: cached ns offload request + * @wow_stats: stat counters for WoW related events + * @rcpi_req: rcpi request + * @in_bmps: Whether bmps for this interface has been enabled + * @vdev_start_wakelock: wakelock to protect vdev start op with firmware + * @vdev_stop_wakelock: wakelock to protect vdev stop op with firmware + * @vdev_set_key_wakelock: wakelock to protect vdev set key op with firmware + * @channel: channel + * @roam_offload_enabled: is roam offload enable/disable + * @roam_scan_stats_req: cached roam scan stats request + * + * It stores parameters per vdev in wma. + */ +struct wma_txrx_node { + uint8_t addr[IEEE80211_ADDR_LEN]; + uint8_t bssid[IEEE80211_ADDR_LEN]; + struct cdp_vdev *handle; + struct beacon_info *beacon; + vdev_restart_params_t vdev_restart_params; + vdev_cli_config_t config; + uint32_t type; + uint32_t sub_type; +#ifdef FEATURE_WLAN_ESE + bool plm_in_progress; +#endif + bool ptrn_match_enable; + uint8_t num_wow_default_patterns; + uint8_t num_wow_user_patterns; + bool conn_state; + tSirMacBeaconInterval beaconInterval; + uint8_t llbCoexist; + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + WMI_HOST_WLAN_PHY_MODE chanmode; + uint8_t vht_capable; + uint8_t ht_capable; + A_UINT32 mhz; + enum phy_ch_width chan_width; + bool vdev_active; + uint64_t tsfadjust; + void *addBssStaContext; + uint8_t aid; + uint8_t rmfEnabled; +#ifdef WLAN_FEATURE_11W + wma_igtk_key_t key; +#endif /* WLAN_FEATURE_11W */ + uint32_t uapsd_cached_val; + tAniGetPEStatsRsp *stats_rsp; + uint8_t fw_stats_set; + void *del_staself_req; + bool is_del_sta_defered; + qdf_atomic_t bss_status; + uint8_t rate_flags; + uint8_t nss; + bool is_channel_switch; + uint16_t pause_bitmap; + int8_t tx_power; + int8_t max_tx_power; + uint32_t nwType; + void *staKeyParams; + uint32_t peer_count; + qdf_spinlock_t peer_lock; + bool roam_synch_in_progress; + void *plink_status_req; + void *psnr_req; + uint8_t delay_before_vdev_stop; +#ifdef FEATURE_WLAN_EXTSCAN + bool extscan_in_progress; +#endif + uint32_t tx_streams; + uint32_t rx_streams; + uint32_t chain_mask; + uint32_t mac_id; + bool roaming_in_progress; + int32_t roam_synch_delay; + uint8_t nss_2g; + uint8_t nss_5g; + bool p2p_lo_in_progress; + uint8_t wep_default_key_idx; + tSirHostOffloadReq arp_offload_req; + tSirHostOffloadReq ns_offload_req; +#ifndef QCA_SUPPORT_CP_STATS + struct sir_vdev_wow_stats wow_stats; +#endif + struct sme_rcpi_req *rcpi_req; +#ifdef WLAN_FEATURE_11AX + bool he_capable; + uint32_t he_ops; +#endif + bool in_bmps; + struct beacon_filter_param beacon_filter; + bool beacon_filter_enabled; + qdf_wake_lock_t vdev_start_wakelock; + qdf_wake_lock_t vdev_stop_wakelock; + qdf_wake_lock_t vdev_set_key_wakelock; + struct roam_synch_frame_ind roam_synch_frame_ind; + bool is_waiting_for_key; + bool roam_offload_enabled; + uint8_t channel; + struct sir_roam_scan_stats *roam_scan_stats_req; +}; + +/** + * struct ibss_power_save_params - IBSS power save parameters + * @atimWindowLength: ATIM window length + * @isPowerSaveAllowed: is power save allowed + * @isPowerCollapseAllowed: is power collapsed allowed + * @isAwakeonTxRxEnabled: is awake on tx/rx enabled + * @inactivityCount: inactivity count + * @txSPEndInactivityTime: tx SP end inactivity time + * @ibssPsWarmupTime: IBSS power save warm up time + * @ibssPs1RxChainInAtimEnable: IBSS power save rx chain in ATIM enable + */ +typedef struct { + uint32_t atimWindowLength; + uint32_t isPowerSaveAllowed; + uint32_t isPowerCollapseAllowed; + uint32_t isAwakeonTxRxEnabled; + uint32_t inactivityCount; + uint32_t txSPEndInactivityTime; + uint32_t ibssPsWarmupTime; + uint32_t ibssPs1RxChainInAtimEnable; +} ibss_power_save_params; + +/** + * 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 + * + * Placeholder for WMA ini parameters. + */ +struct wma_ini_config { + uint8_t max_no_of_peers; +}; + +/** + * struct wmi_valid_channels - Channel details part of WMI_SCAN_CHAN_LIST_CMDID + * @num_channels: Number of channels + * @channel_list: Channel list + */ +struct wma_valid_channels { + uint8_t num_channels; + uint8_t channel_list[MAX_NUM_CHAN]; +}; + +/** + * 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 + * @wma_resume_event: wma resume event + * @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 + * @needShutdown: is shutdown needed or not + * @tgt_cfg_update_cb: configuration update callback + * @reg_cap: regulatory capablities + * @scan_id: scan id + * @interfaces: txrx nodes(per vdev) + * @pdevconfig: pdev related configrations + * @vdev_resp_queue: vdev response queue + * @vdev_respq_lock: vdev response queue lock + * @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 + * @wow: wow related patterns & parameters + * @no_of_suspend_ind: number of suspend indications + * @no_of_resume_ind: number of resume indications + * @ack_work_ctx: Context for deferred processing of TX ACK + * @powersave_mode: power save mode + * @ptrn_match_enable_all_vdev: is pattern match is enable/disable + * @pGetRssiReq: get RSSI request + * @get_one_peer_info: When a "get peer info" request is active, is + * the request for a single peer? + * @get_sta_peer_info: Is a "get peer info" request active? + * @peer_macaddr: When @get_one_peer_info is true, the peer's mac address + * @thermal_mgmt_info: Thermal mitigation related info + * @ssdp: ssdp flag + * @enable_mc_list: To Check if Multicast list filtering is enabled in FW + * @ibss_started: is IBSS started or not + * @ibsskey_info: IBSS key info + * @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 + * @wma_scan_comp_timer: scan completion timer + * @suitable_ap_hb_failure: better ap found + * @suitable_ap_hb_failure_rssi: RSSI when suitable_ap_hb_failure + * triggered for later usage to report RSSI at beacon miss scenario + * @wma_ibss_power_save_params: IBSS Power Save config Parameters + * @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 + * @is_nan_enabled: Flag to indicate if NaN feature is enabled or not + * @staMaxLIModDtim: station max listen interval + * @staModDtim: station mode DTIM + * @staDynamicDtim: station dynamic DTIM + * @enable_mhf_offload: is MHF offload enable/disable + * @last_mhf_entries_timestamp: timestamp when last entries where set + * @hw_bd_id: hardware board id + * @hw_bd_info: hardware board info + * @miracast_value: miracast value + * @log_completion_timer: log completion timer + * @num_dbs_hw_modes: Number of HW modes supported by the FW + * @hw_mode: DBS HW mode list + * @old_hw_mode_index: Previous configured HW mode index + * @new_hw_mode_index: Current configured HW mode index + * @peer_authorized_cb: peer authorized hdd callback + * @wow_unspecified_wake_count: Number of wake events which did not + * correspond to known wake events. Note that known wake events are + * tracked on a per-vdev basis via the struct sir_vdev_wow_stats + * wow_stats in struct wma_txrx_node + * @ocb_config_req: OCB request context + * @max_scan: maximum scan requests than can be queued + * @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 + * @wmi_cmd_rsp_wake_lock: wmi command response wake lock + * @wmi_cmd_rsp_runtime_lock: wmi command response bus lock + * @apf_enabled: Is APF enabled in firmware? + * @apf_packet_filter_enable: Is APF filter enabled om host? + * @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? + * @pe_ndp_event_handler: Handler function for NAN Data Path events + * @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 + * @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_support: per vdev nss, chains update + * @ito_repeat_count: Indicates ito repeated count + * @wma_fw_time_sync_timer: timer used for firmware time sync + * @critical_events_in_flight: number of suspend-preventing events + * in flight + * + * 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; + void *mac_context; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + qdf_event_t wma_resume_event; + 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[IEEE80211_ADDR_LEN]; + uint8_t hwaddr[IEEE80211_ADDR_LEN]; +#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_ota_ack_cb[SIR_MAC_MGMT_RESERVED15]; + wma_tx_ota_comp_callback umac_data_ota_ack_cb; + unsigned long last_umac_data_ota_timestamp; + qdf_nbuf_t last_umac_data_nbuf; + bool needShutdown; + 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 vdev_resp_queue; + qdf_spinlock_t vdev_respq_lock; + 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_wow wow; + uint8_t no_of_suspend_ind; + uint8_t no_of_resume_ind; + struct wma_tx_ack_work_ctx *ack_work_ctx; + uint8_t powersave_mode; + bool ptrn_match_enable_all_vdev; + void *pGetRssiReq; + bool get_one_peer_info; + bool get_sta_peer_info; + struct qdf_mac_addr peer_macaddr; + t_thermal_mgmt thermal_mgmt_info; + bool ssdp; + bool enable_mc_list; + uint8_t ibss_started; + tSetBssKeyParams ibsskey_info; + txFailIndCallback hddTxFailCb; +#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; + int wow_nack; + qdf_atomic_t is_wow_bus_suspended; + qdf_mc_timer_t wma_scan_comp_timer; + bool suitable_ap_hb_failure; + uint32_t suitable_ap_hb_failure_rssi; + ibss_power_save_params wma_ibss_power_save_params; +#ifdef FEATURE_WLAN_RA_FILTERING + bool IsRArateLimitEnabled; + uint16_t RArateLimitInterval; +#endif +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif +#ifdef WLAN_FEATURE_NAN + bool is_nan_enabled; +#endif + uint8_t staMaxLIModDtim; + uint8_t staModDtim; + uint8_t staDynamicDtim; + uint8_t enable_mhf_offload; + unsigned long last_mhf_entries_timestamp; + 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 num_dbs_hw_modes; + struct dbs_hw_mode_info hw_mode; + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + wma_peer_authorized_fp peer_authorized_cb; + uint32_t wow_unspecified_wake_count; + struct sir_ocb_config *ocb_config_req; + uint8_t max_scan; + uint16_t self_gen_frm_pwr; + bool tx_chain_mask_cck; + qdf_mc_timer_t service_ready_ext_timer; + + QDF_STATUS (*csr_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason); + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason); + qdf_wake_lock_t wmi_cmd_rsp_wake_lock; + qdf_runtime_lock_t wmi_cmd_rsp_runtime_lock; + bool apf_enabled; + bool apf_packet_filter_enable; + 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; + QDF_STATUS (*pe_ndp_event_handler)(tpAniSirGlobal mac_ctx, + struct scheduler_msg *msg); + bool fw_timeout_crash; + bool sub_20_support; + bool is_dfs_offloaded; + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb; + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb; + bool rcpi_enabled; + tSirLLStatsResults *link_stats_results; + uint64_t tx_fail_cnt; +#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 enable_peer_unmap_conf_support; + qdf_mc_timer_t wma_fw_time_sync_timer; + qdf_atomic_t critical_events_in_flight; + bool enable_tx_compl_tsf64; + bool enable_three_way_coex_config_legacy; +} t_wma_handle, *tp_wma_handle; + +extern void cds_wma_complete_cback(void); +extern 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 + */ +struct wma_tx_ack_work_ctx { + tp_wma_handle wma_handle; + uint16_t sub_type; + int32_t status; + qdf_work_t ack_cmp_work; +}; + +/** + * struct wma_target_req - target request parameters + * @event_timeout: event timeout + * @node: list + * @user_data: user data + * @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; + uint32_t msg_type; + uint8_t vdev_id; + uint8_t type; +}; + +/** + * struct wma_vdev_start_req - vdev start request parameters + * @beacon_intval: beacon interval + * @dtim_period: dtim period + * @max_txpow: max tx power + * @chan_offset: channel offset + * @is_dfs: is dfs supported or not + * @vdev_id: vdev id + * @chan: channel + * @oper_mode: operating mode + * @ssid: ssid + * @hidden_ssid: hidden ssid + * @pmf_enabled: is pmf enabled or not + * @vht_capable: VHT capabality + * @ht_capable: HT capabality + * @dot11_mode: 802.11 mode + * @is_half_rate: is the channel operating at 10MHz + * @is_quarter_rate: is the channel operating at 5MHz + * @preferred_tx_streams: policy manager indicates the preferred + * number of transmit streams + * @preferred_rx_streams: policy manager indicates the preferred + * number of receive streams + * @beacon_tx_rate: beacon tx rate + * @he_capable: HE capability + * @he_ops: HE operation + * @cac_duration_ms: cac duration in milliseconds + * @dfs_regdomain: dfs region + */ +struct wma_vdev_start_req { + uint32_t beacon_intval; + uint32_t dtim_period; + int32_t max_txpow; + enum phy_ch_width chan_width; + bool is_dfs; + uint8_t vdev_id; + uint8_t chan; + uint8_t oper_mode; + tSirMacSSid ssid; + uint8_t hidden_ssid; + uint8_t pmf_enabled; + uint8_t vht_capable; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t ht_capable; + uint8_t dot11_mode; + bool is_half_rate; + bool is_quarter_rate; + uint32_t preferred_tx_streams; + uint32_t preferred_rx_streams; + uint16_t beacon_tx_rate; +#ifdef WLAN_FEATURE_11AX + bool he_capable; + uint32_t he_ops; +#endif + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; +}; + +/** + * struct wma_set_key_params - set key parameters + * @vdev_id: vdev id + * @def_key_idx: used to see if we have to read the key from cfg + * @key_len: key length + * @peer_mac: peer mac address + * @singl_tid_rc: 1=Single TID based Replay Count, 0=Per TID based RC + * @key_type: key type + * @key_idx: key index + * @unicast: unicast flag + * @key_data: key data + */ +struct wma_set_key_params { + uint8_t vdev_id; + /* def_key_idx can be used to see if we have to read the key from cfg */ + uint32_t def_key_idx; + uint16_t key_len; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + uint8_t singl_tid_rc; + enum eAniEdType key_type; + uint32_t key_idx; + bool unicast; + uint8_t key_data[SIR_MAC_MAX_KEY_LENGTH]; + uint8_t key_rsc[SIR_MAC_MAX_KEY_RSC_LEN]; +}; + +/** + * struct t_thermal_cmd_params - thermal command parameters + * @minTemp: minimum temprature + * @maxTemp: maximum temprature + * @thermalEnable: thermal enable + */ +typedef struct { + uint16_t minTemp; + uint16_t maxTemp; + uint8_t thermalEnable; +} 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_IBSS_SET_ATIM_WINDOW_SIZE: set IBSS ATIM window size + * @WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED: set IBSS enable power save + * @WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED: set IBSS power collapse enable + * @WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX: awake IBSS on TX/RX + * @WMA_VDEV_IBSS_SET_INACTIVITY_TIME: set IBSS inactivity time + * @WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME: set IBSS TXSP + * @WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS: set IBSS power save warmup time + * @WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW: set IBSS power save ATIM + * @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_IBSS_SET_ATIM_WINDOW_SIZE, + WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED, + WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED, + WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX, + WMA_VDEV_IBSS_SET_INACTIVITY_TIME, + WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME, + WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS, + WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW, + 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 +}; + +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 +}; + +/** + * struct wma_roam_invoke_cmd - roam invoke command + * @vdev_id: vdev id + * @bssid: mac address + * @channel: channel + * @frame_len: frame length, includs mac header, fixed params and ies + * @frame_buf: buffer contaning probe response or beacon + * @is_same_bssid: flag to indicate if roaming is requested for same bssid + */ +struct wma_roam_invoke_cmd { + uint32_t vdev_id; + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint32_t channel; + uint32_t frame_len; + uint8_t *frame_buf; + uint8_t is_same_bssid; +}; + +/** + * struct wma_process_fw_event_params - fw event parameters + * @wmi_handle: wmi handle + * @evt_buf: event buffer + */ +typedef struct { + void *wmi_handle; + void *evt_buf; +} wma_process_fw_event_params; + +int wma_process_fw_event_handler(void *ctx, void *ev, uint8_t rx_ctx); + +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr); +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr); + +QDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id, + tp_wma_trigger_uapsd_params + trigger_uapsd_params); + +/* added to get average snr for both data and beacon */ +QDF_STATUS wma_send_snr_request(tp_wma_handle wma_handle, void *pGetRssiReq); + + +QDF_STATUS wma_update_vdev_tbl(tp_wma_handle wma_handle, uint8_t vdev_id, + void *tx_rx_vdev_handle, + uint8_t *mac, uint32_t vdev_type, bool add_del); + +void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle); +void wma_log_completion_timeout(void *data); + +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req); + +QDF_STATUS wma_send_pdev_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_vdev_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 *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type, + uint8_t type, void *params, + uint32_t timeout); + +QDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart); + +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); + +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); +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 +QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_param_update_req *req); +#else +static inline QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_param_update_req *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +QDF_STATUS wma_lro_config_cmd(void *handle, + struct cdp_lro_hash_config *wma_lro_cmd); + +void +wma_indicate_err(enum ol_rx_err_type err_type, + struct ol_error_info *err_info); + +/** + * wma_rx_mic_error_ind() - indicate mic error to the protocol stack + * @scn_handle: pdev handle from osif layer + * @vdev_id: vdev id + * @wh: pointer to ieee80211_frame structure + * + * This function indicates TKIP MIC errors encountered in the RX data path + * to the protocol stack + * + * Return: none + */ +void wma_rx_mic_error_ind(void *scn_handle, uint16_t vdev_id, void *wh); + +QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma_handle, + int32_t vdev_id); + +void 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 */ + +/** + * 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 mlme_nss_chains *user_cfg); + +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 *bssid, + uint8_t vdev_id, void *peer, + bool roam_synch_in_progress); + +QDF_STATUS wma_create_peer(tp_wma_handle wma, struct cdp_pdev *pdev, + struct cdp_vdev *vdev, u8 peer_addr[6], + u_int32_t peer_type, u_int8_t vdev_id, + bool roam_synch_in_progress); + +QDF_STATUS wma_peer_unmap_conf_cb(uint8_t vdev_id, + uint32_t peer_id_cnt, + uint16_t *peer_id_list); + +/** + * 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); +WLAN_PHY_MODE wma_chan_phy_mode(u8 chan, enum phy_ch_width chan_width, + u8 dot11_mode); + +#ifdef FEATURE_OEM_DATA_SUPPORT +QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle, + struct oem_data_req *oem_req); +#endif + +QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma_handle, + uint8_t val); +void wma_register_packetdump_callback( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_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); +void wma_peer_set_default_routing(void *scn_handle, uint8_t *peer_macaddr, + uint8_t vdev_id, bool hash_based, uint8_t ring_num); +int wma_peer_rx_reorder_queue_setup(void *scn_handle, + uint8_t vdev_id, uint8_t *peer_macaddr, qdf_dma_addr_t hw_qdesc, + int tid, uint16_t queue_no); +int wma_peer_rx_reorder_queue_remove(void *scn_handle, + uint8_t vdev_id, uint8_t *peer_macaddr, uint32_t peer_tid_bitmap); + +/** + * 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); + +/** + * 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_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_vdev_set_mlme_state() - Set vdev mlme state + * @wma: wma handle + * @vdev_id: the Id of the vdev to configure + * @state: vdev state + * + * Return: None + */ +static inline +void wma_vdev_set_mlme_state(tp_wma_handle wma, uint8_t vdev_id, + enum wlan_vdev_state state) +{ + struct wlan_objmgr_vdev *vdev; + + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (vdev) { + wlan_vdev_obj_lock(vdev); + wlan_vdev_mlme_set_state(vdev, state); + wlan_vdev_obj_unlock(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + } +} + +/** + * 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) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id: %d", __func__, vdev_id); + return; + } + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + WMA_LOGE("%s: Failed to get iface: NULL", + __func__); + return; + } + + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: NULL", + __func__); + 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) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return 0; + } + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + WMA_LOGE("%s: Failed to get iface: NULL", + __func__); + return 0; + } + + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: NULL", + __func__); + 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) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return 0; + } + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + WMA_LOGE("%s: Failed to get iface: NULL", + __func__); + return 0; + } + + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle:NULL", + __func__); + return 0; + } + + return iface->in_bmps || wma->in_imps; +} + +/** + * wma_vdev_get_cfg_int - Get cfg integer value + * @cfg_id: cfg item number + * @value: fill the out value + * + * Note caller must verify return status before using value + * + * Return: QDF_STATUS_SUCCESS when got item from cfg else QDF_STATUS_E_FAILURE + */ +static inline +QDF_STATUS wma_vdev_get_cfg_int(int cfg_id, int *value) +{ + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + *value = 0; + + if (!mac) + return QDF_STATUS_E_FAILURE; + + return wlan_cfg_get_int(mac, cfg_id, value); +} + +/** + * 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 || !iface->handle) + 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 || !iface->handle) + return QDF_STATUS_E_FAILURE; + + *value = iface->beaconInterval; + 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) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return; + } + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + WMA_LOGE("%s: Failed to get iface: NULL", + __func__); + return; + } + + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: NULL", + __func__); + 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) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return; + } + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + WMA_LOGE("%s: Failed to get iface: NULL", + __func__); + return; + } + + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: NULL", + __func__); + return; + } + + iface->pause_bitmap &= ~(1 << bit_pos); +} + +/** + * wma_process_roaming_config() - process roam request + * @wma_handle: wma handle + * @roam_req: roam request parameters + * + * Main routine to handle ROAM commands coming from CSR module. + * + * Return: QDF status + */ +QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req); + +#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_ipa_uc_stat_request() - set ipa config parameters + * @privcmd: private command + * + * Return: None + */ +void wma_ipa_uc_stat_request(wma_cli_set_cmd_t *privcmd); + +/** + * wma_set_rx_reorder_timeout_val() - set rx recorder timeout value + * @wma_handle: pointer to wma handle + * @reorder_timeout: rx reorder timeout value + * + * Return: VOS_STATUS_SUCCESS for success or error code. + */ +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); + +/** + * 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); + +/** + * wma_force_objmgr_vdev_peer_cleanup() - Cleanup ObjMgr Vdev peers during SSR + * @wma_handle: WMA handle + * @vdev_id: vdev ID + * + * Return: none + */ +void wma_force_objmgr_vdev_peer_cleanup(tp_wma_handle wma, uint8_t vdev_id); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_api.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_api.h new file mode 100644 index 0000000000000000000000000000000000000000..0e11072b577eddd0c4942e4f90d1f3c2c35f96f2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_api.h @@ -0,0 +1,414 @@ +/* + * 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 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 + +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_MODULATED_DTIM: moduled dtim + * @GEN_PARAM_CAPTURE_TSF: read tsf + * @GEN_PARAM_RESET_TSF_GPIO: reset tsf gpio + * @GEN_VDEV_ROAM_SYNCH_DELAY: roam sync delay + * @GEN_PARAM_LISTEN_INTERVAL: listen interval + */ +enum GEN_PARAM { + GEN_VDEV_PARAM_AMPDU = 0x1, + GEN_VDEV_PARAM_AMSDU, + GEN_PARAM_CRASH_INJECT, + GEN_PARAM_MODULATED_DTIM, + GEN_PARAM_CAPTURE_TSF, + GEN_PARAM_RESET_TSF_GPIO, + GEN_VDEV_ROAM_SYNCH_DELAY, + GEN_PARAM_LISTEN_INTERVAL, +}; + +/** + * 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; + uint32_t he_5g; + uint32_t tx_chain_mask_2G; + uint32_t rx_chain_mask_2G; + uint32_t tx_chain_mask_5G; + uint32_t rx_chain_mask_5G; +}; + + +#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); + +void wma_setneedshutdown(void); + +bool wma_needshutdown(void); + +QDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle); + +uint8_t wma_map_channel(uint8_t mapChannel); + +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_phy_mode_cb() - Callback to get current PHY Mode. + * @chan: channel number + * @chan_width: maximum channel width possible + * @phy_mode: PHY Mode + * + * Return: None + */ +void wma_get_phy_mode_cb(uint8_t chan, uint32_t chan_width, uint32_t *phy_mode); + +QDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value); + +/** + * wma_get_wcnss_software_version() - get wcnss software version + * @version: version pointer + * @version_buffer_size: buffer size + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_get_wcnss_software_version(uint8_t *version, + uint32_t version_buffer_size); + +void wma_set_peer_authorized_cb(void *wma_ctx, wma_peer_authorized_fp auth_cb); +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, tSirLinkSpeedInfo *pLinkSpeed); +#ifdef NOT_YET +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, void *scan_chan_info); +#endif + +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); + +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(tpAniSirGlobal pMac, struct scheduler_msg *pMsg); + +void wma_register_wow_wakeup_events(WMA_HANDLE handle, uint8_t vdev_id, + uint8_t vdev_type, uint8_t sub_type); +void wma_register_wow_default_patterns(WMA_HANDLE handle, uint8_t vdev_id); +int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id); +void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id, + uint32_t cfgd_hw_mode_index); +void wma_set_dbs_capability_ut(uint32_t dbs); +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 channel); +int wma_unified_radio_tx_mem_free(void *handle); +/** + * wma_form_unit_test_cmd_and_send() - to form a wma command and send it to FW + * @session_id: wma 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 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); + +/** + * wma_lro_init() - sends LRO configuration to FW + * @lro_config: pointer to the config parameters + * + * This function ends LRO configuration to FW. + * + * Return: 0 for success or reasons for failure + */ +int wma_lro_init(struct cdp_lro_hash_config *lro_config); + +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); + +bool wma_is_csa_offload_enabled(void); +bool wma_is_p2p_lo_capable(void); +bool wma_capability_enhanced_mcast_filter(void); +QDF_STATUS wma_p2p_lo_start(struct sir_p2p_lo_start *params); +QDF_STATUS wma_p2p_lo_stop(u_int32_t vdev_id); +#ifndef QCA_SUPPORT_CP_STATS +QDF_STATUS wma_get_wakelock_stats(struct sir_wake_lock_stats *wake_lock_stats); +#endif +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 sir_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); +QDF_STATUS wma_set_tx_rx_aggregation_size + (struct sir_set_tx_rx_aggregation_size *tx_rx_aggregation_size); + +/** + * wma_set_tx_rx_aggregation_size_per_ac() - set aggregation size per ac + * @tx_rx_aggregation_size: the parameter for aggregation size + * + * This function try to set the aggregation size per AC. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_set_tx_rx_aggregation_size_per_ac + (struct sir_set_tx_rx_aggregation_size *tx_rx_aggregation_size); +/** + * wma_set_sw_retry_threshold_per_ac() - set sw retry threshold per AC for tx + * @handle: wma handle + * @tx_sw_retry_threshold: value needs to set to firmware + * + * 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, + struct sir_set_tx_sw_retry_threshold *tx_sw_retry_threshold); +/** + * 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_cmd_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_qpower_config() - update qpower config in wma + * @vdev_id: the Id of the vdev to configure + * @qpower: new qpower value + * + * Return: QDF_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_qpower_config(uint8_t vdev_id, uint8_t qpower); + +#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); + +/** + * 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); + +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); + +/** + * 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); + +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 + * @max_rate: max rate + * @rate_flags: rate flags + * @nss: nss + * @mcs_rate_flag: mcs rate flags + * + * Return: mcs index + */ +uint8_t wma_get_mcs_idx(uint16_t max_rate, uint8_t rate_flags, + uint8_t *nss, uint8_t *mcs_rate_flag); +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_coex.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_coex.h new file mode 100644 index 0000000000000000000000000000000000000000..33ff1fd4d531d656b4db3797dcdf9bfad7df9096 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/wma/inc/wma_he.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_he.h new file mode 100644 index 0000000000000000000000000000000000000000..a33683493a39bf3e15fa5df71909d3eaaa920a2c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_he.h @@ -0,0 +1,327 @@ +/* + * 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. + */ + +#ifndef __WMA_HE_H +#define __WMA_HE_H + +#include "wma.h" +#include "sir_api.h" +#include "target_if.h" + +#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() - 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(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 + * @req: pointer to vdev start request + * @add_bss: pointer to ADD BSS params + * + * Return: None + */ +void wma_update_vdev_he_ops(struct wma_vdev_start_req *req, + tpAddBssParams add_bss); + +/** + * wma_copy_txrxnode_he_ops() - copy HE ops from vdev start req to txrx node + * @node: pointer to txrx node + * @req: pointer to vdev start request + * + * Return: None + */ +void wma_copy_txrxnode_he_ops(struct wma_txrx_node *node, + struct wma_vdev_start_req *req); + +/** + * wma_copy_vdev_start_he_ops() - copy HE ops from vdev start req to vdev start + * @params: pointer to vdev_start_params + * @req: pointer to vdev start request + * + * Return: None + */ +void wma_copy_vdev_start_he_ops(struct vdev_start_params *params, + struct wma_vdev_start_req *req); + +/** + * wma_vdev_set_he_bss_params() - set HE OPs in vdev start + * @wma: pointer to wma handle + * @vdev_id: VDEV id + * @req: pointer to vdev start request + * + * Return: None + */ +void wma_vdev_set_he_bss_params(tp_wma_handle wma, uint8_t vdev_id, + struct wma_vdev_start_req *req); + +/** + * 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, + tpAddBssParams add_bss); + +static inline bool wma_is_peer_he_capable(tpAddStaParams params) +{ + return params->he_capable; +} + +/** + * wma_update_vdev_he_capable() - update vdev start request he capability + * @req: pointer to vdev start request + * @params: pointer to chan switch params + * + * Return: None + */ +void wma_update_vdev_he_capable(struct wma_vdev_start_req *req, + tpSwitchChannelParams params); + +/** + * 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_VDEV_PARAM 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_VDEV_PARAM param_id); + +#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(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(struct wma_vdev_start_req *req, + tpAddBssParams add_bss) +{ +} +static inline void wma_copy_txrxnode_he_ops(struct wma_txrx_node *intr, + struct wma_vdev_start_req *req) +{ +} + +static inline void wma_copy_vdev_start_he_ops(struct vdev_start_params *params, + struct wma_vdev_start_req *req) +{ +} + +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 wma_vdev_start_req *req) +{ +} + +static inline void wma_vdev_set_he_config(tp_wma_handle wma, uint8_t vdev_id, + tpAddBssParams add_bss) +{ +} + +static inline bool wma_is_peer_he_capable(tpAddStaParams params) +{ + return false; +} + +static inline void wma_update_vdev_he_capable(struct wma_vdev_start_req *req, + tpSwitchChannelParams params) +{ +} + +static inline void wma_set_he_vdev_param(struct wma_txrx_node *intr, + WMI_VDEV_PARAM param_id, uint32_t value) +{ + WMA_LOGI(FL("Unable to update WMI_VDEV_PARAM: %0x"), param_id); +} + +static inline uint32_t wma_get_he_vdev_param(struct wma_txrx_node *intr, + WMI_VDEV_PARAM param_id) +{ + WMA_LOGI(FL("Unable to update WMI_VDEV_PARAM: %0x"), param_id); + return 0; +} + +#endif + +#endif /* __WMA_HE_H */ diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_if.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_if.h new file mode 100644 index 0000000000000000000000000000000000000000..80d8552f29a6066ec9990ab25794a4a8874397ac --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_if.h @@ -0,0 +1,1552 @@ +/* + * 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 _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 + +#define WMA_CONFIG_PARAM_UPDATE_REQ SIR_CFG_PARAM_UPDATE_IND + +#define HAL_NUM_BSSID 2 +/* 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 +#ifdef FEATURE_WLAN_TDLS +#define STA_ENTRY_TDLS_PEER 4 +#endif /* FEATURE_WLAN_TDLS */ +#define STA_ENTRY_NDI_PEER 5 + +#define STA_INVALID_IDX 0xFF + +/* invalid channel id. */ +#define INVALID_CHANNEL_ID 0 + +/* + * From NOVA Mac Arch document + * Encryp. mode The encryption mode + * 000: Encryption functionality is not enabled + * 001: Encryption is set to WEP + * 010: Encryption is set to WEP 104 + * 011: Encryption is set to TKIP + * 100: Encryption is set to AES + * 101 - 111: Reserved for future + */ +#define ENC_POLICY_NULL 0 +#define ENC_POLICY_WEP40 1 +#define ENC_POLICY_WEP104 2 +#define ENC_POLICY_TKIP 3 +#define ENC_POLICY_AES_CCM 4 + +/* Max number of bytes required for stations bitmap aligned at 4 bytes boundary + */ +#define HALMSG_NUMBYTES_STATION_BITMAP(x) (((x / 32) + ((x % 32) ? 1 : 0)) * 4) + + +#define HAL_MAX_SUPP_CHANNELS 128 +#define HAL_MAX_SUPP_OPER_CLASSES 32 + +/** + * 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 + */ +typedef struct sAniProbeRspStruct { + tSirMacMgmtHdr macHdr; + /* probeRsp body follows here */ +} qdf_packed tAniProbeRspStruct, *tpAniProbeRspStruct; + +/** + * 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 + * @shortPreambleSupported: is short preamble supported or not + * @listenInterval: Listen interval + * @wmmEnabled: Support for 11e/WMM + * @uAPSD: U-APSD Flags: 1b per AC + * @maxSPLen: Max SP Length + * @htCapable: 11n HT capable STA + * @greenFieldCapable: 11n Green Field preamble support + * @txChannelWidthSet: TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz + * @mimoPS: MIMO Power Save + * @rifsMode: RIFS mode: 0 - NA, 1 - Allowed + * @lsigTxopProtection: L-SIG TXOP Protection mechanism + * @us32MaxAmpduDuration: in units of 32 us + * @maxAmpduSize: 0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k + * @maxAmpduDensity: 3 : 0~7 : 2^(11nAMPDUdensity -4) + * @maxAmsduSize: 1 : 3839 bytes, 0 : 7935 bytes + * @fDsssCckMode40Mhz: DSSS CCK supported 40MHz + * @fShortGI40Mhz: short GI support for 40Mhz packets + * @fShortGI20Mhz: short GI support for 20Mhz packets + * @supportedRates: legacy supported rates + * @status: QDF status + * @staIdx: station index + * @bssIdx: BSSID of BSS to which the station is associated + * @updateSta: pdate the existing STA entry, if this flag is set + * @respReqd: A flag to indicate to HAL if the response message is required + * @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 + * @enableVhtGid: enable VHT GID + * @enableAmpduPs: AMPDU power save + * @enableHtSmps: enable HT SMPS + * @htSmpsconfig: HT SMPS config + * @htLdpcCapable: HT LDPC capable + * @vhtLdpcCapable: VHT LDPC capable + * @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 + * @atimIePresent: Peer Atim Info + * @peerAtimWindowLength: peer ATIM Window length + * @nss: Return the number of spatial streams supported + * @stbc_capable: stbc capable + * @max_amsdu_num: Maximum number of MSDUs in a tx aggregate frame + * + * 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; + uint8_t shortPreambleSupported; + tSirMacAddr staMac; + uint16_t listenInterval; + uint8_t wmmEnabled; + uint8_t uAPSD; + uint8_t maxSPLen; + uint8_t htCapable; + /* 11n Green Field preamble support + * 0 - Not supported, 1 - Supported + * Add it to RA related fields of sta entry in HAL + */ + uint8_t greenFieldCapable; + uint8_t ch_width; + + tSirMacHTMIMOPowerSaveState mimoPS; + uint8_t rifsMode; + /* L-SIG TXOP Protection mechanism + * 0 - No Support, 1 - Supported + * SG - there is global field. + */ + uint8_t lsigTxopProtection; + uint8_t us32MaxAmpduDuration; + uint8_t maxAmpduSize; + uint8_t maxAmpduDensity; + uint8_t maxAmsduSize; + + /* 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 fDsssCckMode40Mhz; + uint8_t fShortGI40Mhz; + uint8_t fShortGI20Mhz; + tSirSupportedRates 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; + /* Station index; valid only when 'status' field value is + * QDF_STATUS_SUCCESS + */ + uint8_t staIdx; + /* BSSID of BSS to which the station is associated. + * This should be filled back in by HAL, and sent back to LIM as part of + * the response message, so LIM can cache it in the station entry of + * hash table. When station is deleted, LIM will make use of this bssIdx + * to delete BSS from hal tables and from softmac. + */ + uint8_t bssIdx; + uint8_t updateSta; + uint8_t respReqd; + uint8_t rmfEnabled; + uint32_t encryptType; + uint8_t sessionId; + uint8_t p2pCapableSta; + uint8_t csaOffloadEnable; + uint8_t vhtCapable; + uint8_t vhtSupportedRxNss; + uint8_t vhtTxBFCapable; + uint8_t enable_su_tx_bformer; + uint8_t vhtTxMUBformeeCapable; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmpsconfig; + bool send_smps_action; + uint8_t htLdpcCapable; + uint8_t vhtLdpcCapable; + 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 atimIePresent; + uint32_t peerAtimWindowLength; + uint8_t nonRoamReassoc; + uint32_t nss; +#ifdef WLAN_FEATURE_11AX + bool he_capable; + tDot11fIEhe_cap he_config; + tDot11fIEhe_op he_op; +#endif + uint8_t stbc_capable; + uint8_t max_amsdu_num; +#ifdef WLAN_SUPPORT_TWT + uint8_t twt_requestor; + uint8_t twt_responder; +#endif +} tAddStaParams, *tpAddStaParams; + +/** + * struct tDeleteStaParams - parameters required for del sta request + * @staIdx: station index + * @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 staIdx; + 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 + * @staIdx: station id + * @encType: encryption type + * @wepType: WEP type + * @defWEPIdx: Default WEP key, valid only for static WEP, must between 0 and 3 + * @key: valid only for non-static WEP encyrptions + * @singleTidRc: 1=Single TID based Replay Count, 0=Per TID based RC + * @smesessionId: sme session id + * @peerMacAddr: peer mac address + * @status: status + * @sessionId: session id + * @sendRsp: send response + * + * 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 assoicated with; otherwise + * a new key descriptor is created based on the key field. + */ +typedef struct { + uint16_t staIdx; + tAniEdType encType; + tAniWepType wepType; + uint8_t defWEPIdx; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + uint8_t singleTidRc; + uint8_t smesessionId; + struct qdf_mac_addr peer_macaddr; + QDF_STATUS status; + uint8_t sessionId; + uint8_t sendRsp; +} tSetStaKeyParams, *tpSetStaKeyParams; + +/** + * struct sLimMlmSetKeysReq - set key request parameters + * @peerMacAddr: peer mac address + * @sessionId: PE session id + * @smesessionId: SME session id + * @aid: association id + * @edType: Encryption/Decryption type + * @numKeys: number of keys + * @key: key data + */ +typedef struct sLimMlmSetKeysReq { + struct qdf_mac_addr peer_macaddr; + uint8_t sessionId; /* Added For BT-AMP Support */ + uint8_t smesessionId; /* Added for drivers based on wmi interface */ + uint16_t aid; + tAniEdType edType; /* Encryption/Decryption type */ + uint8_t numKeys; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; +} tLimMlmSetKeysReq, *tpLimMlmSetKeysReq; + +/** + * struct tAddBssParams - parameters required for add bss params + * @bssId: MAC Address/BSSID + * @selfMacAddr: Self Mac Address + * @bssType: BSS type + * @operMode: AP - 0; STA - 1; + * @nwType: network type + * @shortSlotTimeSupported: is short slot time supported or not + * @llaCoexist: is 11a coexist or not + * @llbCoexist: 11b coexist supported or not + * @llgCoexist: 11g coexist supported or not + * @ht20Coexist: HT20 coexist supported or not + * @fLsigTXOPProtectionFullSupport: TXOP protection supported or not + * @fRIFSMode: RIFS is supported or not + * @beaconInterval: beacon interval + * @dtimPeriod: DTIM period + * @cfParamSet: CF Param Set + * @rateSet: MAC Rate Set + * @htCapable: Enable/Disable HT capabilities + * @obssProtEnabled: Enable/Disable OBSS protection + * @rmfEnabled: RMF enabled/disabled + * @htOperMode: HT Operating Mode + * @HT Operating Mode: Dual CTS Protection: 0 - Unused, 1 - Used + * @txChannelWidthSet: TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz + * @currentOperChannel: Current Operating Channel + * @currentExtChannel: Current Extension Channel, if applicable + * @staContext: sta context + * @status: status + * @bssIdx: BSS index allocated by HAL + * @updateBss: update the existing BSS entry, if this flag is set + * @ssId: Add BSSID info for rxp filter + * @respReqd: send the response message to LIM only when this flag is set + * @sessionId: PE session id + * @txMgmtPower: tx power used for mgmt frames + * @maxTxPower: max power to be used after applying the power constraint + * @extSetStaKeyParamValid: Ext Bss Config Msg if set + * @extSetStaKeyParam: SetStaKeyParams for ext bss msg + * @ucMaxProbeRespRetryLimit: probe Response Max retries + * @bHiddenSSIDEn: To Enable Hidden ssid. + * @bProxyProbeRespEn: To Enable Disable FW Proxy Probe Resp + * @halPersona: Persona for the BSS can be STA,AP,GO,CLIENT value + * @bSpectrumMgtEnabled: Spectrum Management Capability, 1:Enabled, 0:Disabled. + * @vhtCapable: VHT capablity + * @vhtTxChannelWidthSet: VHT tx channel width + * @reassocReq: Set only during roaming reassociation + * @chainMask: chain mask + * @smpsMode: SMPS mode + * @dot11_mode: 802.11 mode + * @he_capable: HE Capability + * @cac_duration_ms: cac duration in milliseconds + * @dfs_regdomain: dfs region + */ +typedef struct { + tSirMacAddr bssId; + tSirMacAddr selfMacAddr; + tSirBssType bssType; + uint8_t operMode; + tSirNwType nwType; + uint8_t shortSlotTimeSupported; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20Coexist; + uint8_t llnNonGFCoexist; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t fRIFSMode; + tSirMacBeaconInterval beaconInterval; + uint8_t dtimPeriod; + tSirMacCfParamSet cfParamSet; + tSirMacRateSet rateSet; + uint8_t htCapable; + uint8_t obssProtEnabled; + uint8_t rmfEnabled; + tSirMacHTOperatingMode htOperMode; + uint8_t dualCTSProtection; + uint8_t txChannelWidthSet; + uint8_t currentOperChannel; + tAddStaParams staContext; + QDF_STATUS status; + uint16_t bssIdx; + /* 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 resue the + * the old bssID and still return success. + */ + uint8_t updateBss; + tSirMacSSid ssId; + uint8_t respReqd; + uint8_t sessionId; + int8_t txMgmtPower; + int8_t maxTxPower; + + uint8_t extSetStaKeyParamValid; + tSetStaKeyParams extSetStaKeyParam; + + uint8_t ucMaxProbeRespRetryLimit; + uint8_t bHiddenSSIDEn; + uint8_t bProxyProbeRespEn; + uint8_t halPersona; + uint8_t bSpectrumMgtEnabled; + uint8_t vhtCapable; + enum phy_ch_width ch_width; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t reassocReq; /* Set only during roaming reassociation */ + uint16_t chainMask; + uint16_t smpsMode; + uint8_t dot11_mode; + uint8_t nonRoamReassoc; + uint8_t wps_state; + uint8_t nss; + uint8_t nss_2g; + uint8_t nss_5g; + uint16_t beacon_tx_rate; + 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 tx_non_aggregation_size_be; + uint32_t tx_non_aggregation_size_bk; + uint32_t tx_non_aggregation_size_vi; + uint32_t tx_non_aggregation_size_vo; + uint32_t rx_aggregation_size; +#ifdef WLAN_FEATURE_11AX + bool he_capable; + tDot11fIEhe_cap he_config; + tDot11fIEhe_op he_op; + uint32_t he_sta_obsspd; +#endif + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; +} tAddBssParams, *tpAddBssParams; + +/** + * struct tDeleteBssParams - params required for del bss request + * @bssIdx: BSSID + * @status: QDF status + * @respReqd: response message to LIM only when this flag is set + * @sessionId: PE session id + * @bssid: BSSID mac address + * @smesessionId: sme session id + */ +typedef struct { + uint8_t bssIdx; + QDF_STATUS status; + uint8_t respReqd; + uint8_t sessionId; + tSirMacAddr bssid; + uint8_t smesessionId; +} tDeleteBssParams, *tpDeleteBssParams; + +/** + * struct sSirScanEntry - scan entry + * @bssIdx: BSSID + * @activeBSScnt: active BSS count + */ +typedef struct sSirScanEntry { + uint8_t bssIdx[HAL_NUM_BSSID]; + uint8_t activeBSScnt; +} tSirScanEntry, *ptSirScanEntry; + +/** + * struct tInitScanParams - params required for init scan request + * @bssid: BSSID + * @notifyBss: notify BSS + * @useNoA: use NOA + * @notifyHost: notify UMAC if set + * @frameLength: frame length + * @frameType: frame type + * @scanDuration: Indicates the scan duration (in ms) + * @macMgmtHdr: For creation of CTS-to-Self and Data-NULL MAC packets + * @scanEntry: scan entry + * @checkLinkTraffic: when this flag is set, HAL should check for + * link traffic prior to scan + * @status: status + */ +typedef struct { + tSirMacAddr bssid; + uint8_t notifyBss; + uint8_t useNoA; + uint8_t notifyHost; + uint8_t frameLength; + uint8_t frameType; + uint16_t scanDuration; + tSirMacMgmtHdr macMgmtHdr; + tSirScanEntry scanEntry; + tSirLinkTrafficCheck checkLinkTraffic; + QDF_STATUS status; +} tInitScanParams, *tpInitScanParams; + +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 +} 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 + * @staId: station 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; + uint16_t staId; + tSirMacAddr bssId; + tSirMacAddr addr2; + uint16_t reasonCode; + int8_t rssi; +} tDeleteStaContext, *tpDeleteStaContext; + +/** + * struct tStartScanParams - params required for start scan request + * @scanChannel: Indicates the current scan channel + * @status: return status + * @startTSF: TSF value + * @txMgmtPower: TX mgmt power + */ +typedef struct { + uint8_t scanChannel; + QDF_STATUS status; + uint32_t startTSF[2]; + int8_t txMgmtPower; +} tStartScanParams, *tpStartScanParams; + +/** + * struct tEndScanParams - params required for end scan request + * @scanChannel: Indicates the current scan channel + * @status: return status + */ +typedef struct { + uint8_t scanChannel; + QDF_STATUS status; +} tEndScanParams, *tpEndScanParams; + +/** + * struct tFinishScanParams - params required for finish scan request + * @bssid: BSSID + * @currentOperChannel: Current operating channel + * @cbState: channel bond state + * @notifyBss: notify BSS flag + * @notifyHost: notify host flag + * @frameLength: frame length + * @frameType: frame type + * @macMgmtHdr: For creation of CTS-to-Self and Data-NULL MAC packets + * @scanEntry: scan entry + * @status: return status + * Request Type = SIR_HAL_FINISH_SCAN_REQ + */ +typedef struct { + tSirMacAddr bssid; + uint8_t currentOperChannel; + /* If 20/40 MHz is operational, this will indicate the 40 MHz extension + * channel in combination with the control channel + */ + ePhyChanBondState cbState; + /* For an STA, indicates if a Data NULL frame needs to be sent + * to the AP with FrameControl.PwrMgmt bit set to 0 + */ + uint8_t notifyBss; + uint8_t notifyHost; + uint8_t frameLength; + uint8_t frameType; + tSirMacMgmtHdr macMgmtHdr; + tSirScanEntry scanEntry; + QDF_STATUS status; +} tFinishScanParams, *tpFinishScanParams; + +#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 tBeaconGenParams - params required for beacon gen request + * @bssIdx: Identifies the BSSID for which it is time to generate a beacon + * @bssId: BSSID + * @numOfSta: Number of stations in power save, who have data pending + * @numOfStaWithoutData: Number of stations in power save, + * who don't have any data pending + * @fBroadcastTrafficPending: broadcast traffic pending flag + * @dtimCount: DTIM count + * @rsvd: reserved(padding) + */ +typedef struct sBeaconGenParams { + uint8_t bssIdx; + tSirMacAddr bssId; +#ifdef FIXME_VOLANS + uint8_t numOfSta; + uint8_t numOfStaWithoutData; + uint8_t fBroadcastTrafficPending; + uint8_t dtimCount; +#endif /* FIXME_VOLANS */ + uint8_t rsvd[3]; +} tBeaconGenParams, *tpBeaconGenParams; + +/** + * 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; +} tSendbeaconParams, *tpSendbeaconParams; + +/** + * struct tSendProbeRespParams - send probe response parameters + * @bssId: BSSID + * @probeRespTemplate: probe response template + * @probeRespTemplateLen: probe response template length + * @ucProxyProbeReqValidIEBmap: valid IE bitmap + */ +typedef struct sSendProbeRespParams { + tSirMacAddr bssId; + uint8_t probeRespTemplate[SIR_MAX_PROBE_RESP_SIZE]; + uint32_t probeRespTemplateLen; + uint32_t ucProxyProbeReqValidIEBmap[8]; +} tSendProbeRespParams, *tpSendProbeRespParams; + +/** + * struct tSetBssKeyParams - BSS key parameters + * @bssIdx: BSSID index + * @encType: encryption Type + * @numKeys: number of keys + * @key: key data + * @singleTidRc: 1=Single TID based Replay Count, 0=Per TID based RC + * @smesessionId: sme session id + * @status: return status of command + * @sessionId: PE session id + */ +typedef struct { + uint8_t bssIdx; + tAniEdType encType; + uint8_t numKeys; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + uint8_t singleTidRc; + uint8_t smesessionId; + QDF_STATUS status; + uint8_t sessionId; +} tSetBssKeyParams, *tpSetBssKeyParams; + +/** + * struct tUpdateBeaconParams - update beacon request parameters + * @bssIdx: 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 + * @smeSessionId: SME session id + */ +typedef struct { + uint8_t bssIdx; + 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 smeSessionId; + 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 staId; + 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 staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateRxNss, *tpUpdateRxNss; + +/** + * struct tUpdateMembership - update membership parmaters + * @membership: membership value + * @staId: station id + * @smesessionId: SME session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t membership; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateMembership, *tpUpdateMembership; + +/** + * struct tUpdateUserPos - update user position parmeters + * @userPos: user position + * @staId: station id + * @smesessionId: sme session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t userPos; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateUserPos, *tpUpdateUserPos; + +/** + * struct tUpdateCFParams -CF parameters + * @bssIdx: BSSID index + * @cfpCount: CFP count + * @cfpPeriod: the number of DTIM intervals between the start of CFPs + */ +typedef struct { + uint8_t bssIdx; + /* + * cfpCount indicates how many DTIMs (including the current frame) + * appear before the next CFP start. A CFPCount of 0 indicates that + * the current DTIM marks the start of the CFP. + */ + uint8_t cfpCount; + uint8_t cfpPeriod; +} tUpdateCFParams, *tpUpdateCFParams; + +/** + * struct tSwitchChannelParams - switch channel request parameter + * @channelNumber: channel number + * @localPowerConstraint: local power constraint + * @secondaryChannelOffset: scondary channel offset + * @peSessionId: PE session id + * @txMgmtPower: TX mgmt power + * @maxTxPower: max tx power + * @selfStaMacAddr: self mac address + * @bssId: bssid + * @status: QDF status + * @chainMask: chanin mask + * @smpsMode: SMPS mode + * @isDfsChannel: is DFS channel + * @vhtCapable: VHT capable + * @dot11_mode: 802.11 mode + * @cac_duration_ms: cac duration in milliseconds + * @dfs_regdomain: dfs region + * @reduced_beacon_interval: reduced beacon interval value + * @ssid_hidden: the sap ssid is hidden + * @ssid: sap ssid + */ +typedef struct { + uint8_t channelNumber; + uint8_t peSessionId; + int8_t txMgmtPower; + int8_t maxTxPower; + tSirMacAddr selfStaMacAddr; + /* the request has power constraints, this should be applied only to + * that session + * VO Wifi comment: BSSID is needed to identify which session issued + * this request. As the request has power constraints, this should be + * applied only to that session + * V IMP: Keep bssId field at the end of this msg. + * It is used to mantain backward compatbility by way of ignoring if + * using new host/old FW or old host/new FW since it is at the end of + * this struct + */ + tSirMacAddr bssId; + QDF_STATUS status; + uint16_t chainMask; + uint16_t smpsMode; + uint8_t isDfsChannel; + uint8_t vhtCapable; + enum phy_ch_width ch_width; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t dot11_mode; + + uint8_t restart_on_chan_switch; + uint8_t nss; +#ifdef WLAN_FEATURE_11AX + bool he_capable; +#endif + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; + uint16_t reduced_beacon_interval; + uint8_t ssid_hidden; + tSirMacSSid ssid; +} tSwitchChannelParams, *tpSwitchChannelParams; + +typedef void (*tpSetLinkStateCallback)(tpAniSirGlobal pMac, void *msgParam, + bool status); + +/** + * struct tLinkStateParams - link state parameters + * @bssid: BSSID + * @selfMacAddr: self mac address + * @state: link state + * @callback: callback function pointer + * @callbackArg: callback argument + * @session: session context + */ +typedef struct sLinkStateParams { + /* SIR_HAL_SET_LINK_STATE */ + tSirMacAddr bssid; + tSirMacAddr selfMacAddr; + tSirLinkState state; + tpSetLinkStateCallback callback; + void *callbackArg; + int ft; + void *session; + bool status; +} tLinkStateParams, *tpLinkStateParams; + +/** + * struct tAddTsParams - ADDTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: QDF status + * @sessionId: session id + * @tsm_interval: TSM interval period passed from lim to WMA + * @setRICparams: RIC parameters + * @sme_session_id: sme session id + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacTspecIE tspec; + QDF_STATUS status; + uint8_t sessionId; +#ifdef FEATURE_WLAN_ESE + uint16_t tsm_interval; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + uint8_t sme_session_id; +} tAddTsParams, *tpAddTsParams; + +/** + * struct tDelTsParams - DELTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC identifier uniquely identifying a TSPEC for a STA in a BSS + * @bssId: BSSID + * @sessionId: session id + * @userPrio: user priority + * @delTsInfo: DELTS info + * @setRICparams: RIC parameters + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacAddr bssId; + uint8_t sessionId; + uint8_t userPrio; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tSirDeltsReqInfo delTsInfo; + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +} tDelTsParams, *tpDelTsParams; + + +#define HAL_QOS_NUM_TSPEC_MAX 2 +#define HAL_QOS_NUM_AC_MAX 4 + +/** + * struct tAggrAddTsParams - ADDTS parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: QDF status + * @sessionId: session id + * @vdev_id: vdev id + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacTspecIE tspec[HAL_QOS_NUM_AC_MAX]; + QDF_STATUS status[HAL_QOS_NUM_AC_MAX]; + uint8_t sessionId; + uint8_t vdev_id; +} tAggrAddTsParams, *tpAggrAddTsParams; + + +typedef QDF_STATUS (*tHalMsgCallback)(tpAniSirGlobal pMac, uint32_t mesgId, + void *mesgParam); + +/** + * struct tEdcaParams - EDCA parameters + * @bssIdx: BSSID index + * @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 bssIdx; + tSirMacEdcaParamRecord acbe; + tSirMacEdcaParamRecord acbk; + tSirMacEdcaParamRecord acvi; + tSirMacEdcaParamRecord acvo; + bool mu_edca_params; +} tEdcaParams, *tpEdcaParams; + +/** + * struct tSetMIMOPS - MIMO power save related parameters + * @staIdx: station index + * @htMIMOPSState: MIMO Power Save State + * @status: response status + * @fsendRsp: send response flag + * @peerMac: peer mac address + * @sessionId: session id + */ +typedef struct sSet_MIMOPS { + uint16_t staIdx; + tSirMacHTMIMOPowerSaveState htMIMOPSState; + QDF_STATUS status; + uint8_t fsendRsp; + tSirMacAddr peerMac; + uint8_t sessionId; +} tSetMIMOPS, *tpSetMIMOPS; + +/** + * struct tUapsdParams - Uapsd related parameters + * @bkDeliveryEnabled: BK delivery enable flag + * @beDeliveryEnabled: BE delivery enable flag + * @viDeliveryEnabled: VI delivery enable flag + * @voDeliveryEnabled: VO delivery enable flag + * @bkTriggerEnabled: BK trigger enable flag + * @beTriggerEnabled: BE trigger enable flag + * @viTriggerEnabled: VI trigger enable flag + * @voTriggerEnabled: VO trigger enable flag + * @status: response status + * @bssIdx: BSSID index + * Request Type = SIR_HAL_ENTER_UAPSD_REQ + */ +typedef struct sUapsdParams { + 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; + QDF_STATUS status; + uint8_t bssIdx; +} tUapsdParams, *tpUapsdParams; + +/** + * struct tHalIndCB - hal message indication callback + * @pHalIndCB: hal message indication callabck + */ +typedef struct tHalIndCB { + tHalMsgCallback pHalIndCB; +} tHalIndCB, *tpHalIndCB; + +/** + * struct sControlTxParams - control tx parameters + * @stopTx: stop transmission + * @fCtrlGlobal: Master flag to stop or resume all transmission + * @ctrlSta: If this flag is set, staBitmap + * @ctrlBss: If this flag is set, bssBitmap and beaconBitmap is valid + * @bssBitmap: bitmap of BSS indices to be stopped for resumed + * @beaconBitmap: this bitmap contains bitmap of BSS indices to be + * stopped for resumed for beacon transmission + */ +typedef struct sControlTxParams { + bool stopTx; + uint8_t fCtrlGlobal; + uint8_t ctrlSta; + uint8_t ctrlBss; + /* When ctrlBss is set, this bitmap contains bitmap of BSS indices to be + * stopped for resumed for transmission. + * This is 32 bit bitmap, not array of bytes. + */ + uint32_t bssBitmap; + /* When ctrlBss is set, this bitmap contains bitmap of BSS indices to be + * stopped for resumed for beacon transmission. + */ + uint32_t beaconBitmap; +} tTxControlParams, *tpTxControlParams; + +/** + * 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 add_sta_self_params - Add Sta Self params + * @self_mac_addr: self MAC Address + * @curr_device_mode: operating device mode + * @type: Vdev Type + * @sub_type: Vdev Sub Type + * @session_id: SME Session ID + * @nss_2g: vdev nss in 2.4G + * @nss_5g: vdev nss in 5G + * @status: response status code + * @tx_aggregation_size: Tx aggregation size + * @rx_aggregation_size: Rx aggregation size + * @enable_bcast_probe_rsp: enable broadcast probe response + * @fils_max_chan_guard_time: FILS max channel guard time + * @pkt_err_disconn_th: packet drop threshold + * @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 + */ +struct add_sta_self_params { + tSirMacAddr self_mac_addr; + enum QDF_OPMODE curr_device_mode; + uint32_t type; + uint32_t sub_type; + uint8_t session_id; + uint8_t nss_2g; + uint8_t nss_5g; + uint32_t status; + 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; + bool enable_bcast_probe_rsp; + uint8_t fils_max_chan_guard_time; + uint16_t pkt_err_disconn_th; + uint8_t oce_feature_bitmap; + 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; +}; + +/** + * 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 + +#ifdef FEATURE_WLAN_TDLS + +#define HAL_TDLS_MAX_SUPP_CHANNELS 128 +#define HAL_TDLS_MAX_SUPP_OPER_CLASSES 32 + +/** + * struct tTdlsPeerCapParams - TDLS peer capablities parameters + * @isPeerResponder: is peer responder or not + * @peerUapsdQueue: peer uapsd queue + * @peerMaxSp: peer max SP value + * @peerBuffStaSupport: peer buffer sta supported or not + * @peerOffChanSupport: peer offchannel support + * @peerCurrOperClass: peer current operating class + * @selfCurrOperClass: self current operating class + * @peerChanLen: peer channel length + * @peerChan: peer channel list + * @peerOperClassLen: peer operating class length + * @peerOperClass: peer operating class + * @prefOffChanNum: peer offchannel number + * @prefOffChanBandwidth: peer offchannel bandwidth + * @opClassForPrefOffChan: operating class for offchannel + */ +typedef struct { + uint8_t isPeerResponder; + uint8_t peerUapsdQueue; + uint8_t peerMaxSp; + uint8_t peerBuffStaSupport; + uint8_t peerOffChanSupport; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t peerChanLen; + tSirUpdateChanParam peerChan[HAL_TDLS_MAX_SUPP_CHANNELS]; + uint8_t peerOperClassLen; + uint8_t peerOperClass[HAL_TDLS_MAX_SUPP_OPER_CLASSES]; + uint8_t prefOffChanNum; + uint8_t prefOffChanBandwidth; + uint8_t opClassForPrefOffChan; +} tTdlsPeerCapParams; + +/** + * struct tTdlsPeerStateParams - TDLS peer state parameters + * @vdevId: vdev id + * @peerMacAddr: peer mac address + * @peerCap: peer capabality + */ +typedef struct sTdlsPeerStateParams { + uint32_t vdevId; + tSirMacAddr peerMacAddr; + uint32_t peerState; + tTdlsPeerCapParams peerCap; + bool resp_reqd; +} tTdlsPeerStateParams; + +/** + * struct tdls_chan_switch_params - channel switch parameter structure + * @vdev_id: vdev ID + * @peer_mac_addr: Peer mac address + * @tdls_off_ch_bw_offset: Target off-channel bandwitdh offset + * @tdls_off_ch: Target Off Channel + * @oper_class: Operating class for target channel + * @is_responder: Responder or initiator + */ +typedef struct tdls_chan_switch_params_struct { + uint32_t vdev_id; + tSirMacAddr peer_mac_addr; + uint16_t tdls_off_ch_bw_offset; + uint8_t tdls_off_ch; + uint8_t tdls_sw_mode; + uint8_t oper_class; + uint8_t is_responder; +} tdls_chan_switch_params; + +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct tAbortScanParams - Abort scan parameters + * @SessionId: PE session id + * @scan_id: Scan ID used for original scan request + * @scan_requestor_id: Scan requesting entity + */ +typedef struct sAbortScanParams { + uint8_t SessionId; + uint32_t scan_id; + uint32_t scan_requestor_id; +} tAbortScanParams, *tpAbortScanParams; + +/** + * struct del_sta_self_params - Del Sta Self params + * @session_id: SME Session ID + * @status: response status code + * @sme_callback: callback to be called from WMA to SME + * @sme_ctx: pointer to context provided by SME + */ +struct del_sta_self_params { + tSirMacAddr self_mac_addr; + uint8_t session_id; + uint32_t status; + csr_session_close_cb sme_callback; + void *sme_ctx; +}; + +/** + * 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_sta_self_params *self_sta_param; + uint8_t generate_rsp; +}; + +/** + * struct tP2pPsParams - 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 + * @psSelection: power save selection + * @sessionId: session id + */ +typedef struct sP2pPsParams { + uint8_t opp_ps; + uint32_t ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; + uint8_t sessionId; +} tP2pPsParams, *tpP2pPsParams; + +/** + * struct tTdlsLinkEstablishParams - TDLS Link establish parameters + * @staIdx: station index + * @isResponder: responder flag + * @uapsdQueues: uapsd queue + * @maxSp: max SP period + * @isBufsta: is station flag + * @isOffChannelSupported: offchannel supported or not + * @peerCurrOperClass: peer current operating class + * @selfCurrOperClass: self current operating class + * @validChannelsLen: valid channel length + * @validChannels: valid channels + * @validOperClassesLen: valid operating class length + * @validOperClasses: valid operating class + * @status: return status of command + */ +typedef struct sTdlsLinkEstablishParams { + uint16_t staIdx; + uint8_t isResponder; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufsta; + uint8_t isOffChannelSupported; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t validChannelsLen; + uint8_t validChannels[HAL_MAX_SUPP_CHANNELS]; + uint8_t validOperClassesLen; + uint8_t validOperClasses[HAL_MAX_SUPP_OPER_CLASSES]; + uint32_t status; +} tTdlsLinkEstablishParams, *tpTdlsLinkEstablishParams; + +/** + * 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 tHalHiddenSsidVdevRestart - hidden ssid vdev restart params + * @ssidHidden: is hidden ssid or not + * @sessionId: session id + */ +typedef struct tHalHiddenSsidVdevRestart { + uint8_t ssidHidden; + uint8_t sessionId; + uint16_t pe_session_id; +} tHalHiddenSsidVdevRestart, *tpHalHiddenSsidVdevRestart; + + +extern void sys_process_mmh_msg(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg); + +/** + * struct tBeaconFilterMsg - Beacon Filtering data structure + * @capabilityInfo: capability info + * @capabilityMask: capabality mask + * @beaconInterval: beacon interval + * @ieNum: IE number + * @reserved: reserved + */ +typedef struct sBeaconFilterMsg { + uint16_t capabilityInfo; + uint16_t capabilityMask; + uint16_t beaconInterval; + uint16_t ieNum; + uint8_t bssIdx; + uint8_t reserved; +} qdf_packed tBeaconFilterMsg, *tpBeaconFilterMsg; + +/** + * struct tEidByteInfo - Eid byte info + * @offset: offset + * @value: value + * @bitMask: BIT mask + * @ref: reference + */ +typedef struct sEidByteInfo { + uint8_t offset; + uint8_t value; + uint8_t bitMask; + uint8_t ref; +} qdf_packed tEidByteInfo, *tpEidByteInfo; + +/** + * struct tBeaconFilterIe - beacon filter IE + * @elementId: element IE + * @checkIePresence: check IE presence + * @byte: Eid byte info + */ +typedef struct sBeaconFilterIe { + uint8_t elementId; + uint8_t checkIePresence; + tEidByteInfo byte; +} qdf_packed tBeaconFilterIe, *tpBeaconFilterIe; + +/** + * 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 */ + +#ifdef WLAN_FEATURE_NAN +/** + * struct tNanRequest - NAN request params + * @request_data_len: request data length + * @request_data: request data + */ +typedef struct sNanRequest { + uint16_t request_data_len; + uint8_t request_data[]; +} tNanRequest, *tpNanRequest; +#endif /* WLAN_FEATURE_NAN */ + +/* + * struct roam_blacklist_timeout - BTM blacklist entry + * @bssid - bssid that is to be blacklisted + * @timeout - time duration for which the bssid is blacklisted + * @received_time - timestamp at which the firmware event was received + */ +struct roam_blacklist_timeout { + struct qdf_mac_addr bssid; + uint32_t timeout; + qdf_time_t received_time; +}; + +/* + * struct roam_blacklist_event - Blacklist event entries destination structure + * @num_entries: total entries sent over the event + * @roam_blacklist: blacklist details + */ +struct roam_blacklist_event { + uint32_t num_entries; + struct roam_blacklist_timeout roam_blacklist[]; +}; + +#endif /* _HALMSGAPI_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_internal.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..a545cfeeaff3010e4c24e2ffd41f8f2f8aa1785d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_internal.h @@ -0,0 +1,1466 @@ +/* + * 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 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 firwmare 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 +#define WOW_CSA_EVENT_OFFSET 12 + +#define WMA_DEFAULT_SCAN_REQUESTER_ID 1 +#define WMI_SCAN_FINISH_EVENTS (WMI_SCAN_EVENT_START_FAILED | \ + WMI_SCAN_EVENT_COMPLETED | \ + WMI_SCAN_EVENT_DEQUEUED) +/* default value */ +#define DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD 20 +#define DEFAULT_STA_SA_QUERY_MAX_RETRIES_COUNT (5) +#define DEFAULT_STA_SA_QUERY_RETRY_INTERVAL (200) + +/* pdev vdev and peer stats*/ +#define FW_PDEV_STATS_SET 0x1 +#define FW_VDEV_STATS_SET 0x2 +#define FW_PEER_STATS_SET 0x4 +#define FW_RSSI_PER_CHAIN_STATS_SET 0x8 +#define FW_STATS_SET 0xf + +/*AR9888/AR6320 noise floor approx value + * similar to the mentioned the WMA + */ +#define WMA_TGT_NOISE_FLOOR_DBM (-96) +#define WMA_TGT_MAX_SNR (WMA_TGT_NOISE_FLOOR_DBM * (-1)) + +/* + * 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 AGC_DUMP 1 +#define CHAN_DUMP 2 +#define WD_DUMP 3 +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define PCIE_DUMP 4 +#endif + +/* conformance test limits */ +#define FCC 0x10 +#define MKK 0x40 +#define ETSI 0x30 + +#define WMI_DEFAULT_NOISE_FLOOR_DBM (-96) + +#define WMI_MCC_MIN_CHANNEL_QUOTA 20 +#define WMI_MCC_MAX_CHANNEL_QUOTA 80 +#define WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY 30 + +/* The maximum number of patterns that can be transmitted by the firmware + * and maximum patterns size. + */ +#define WMA_MAXNUM_PERIODIC_TX_PTRNS 6 + +#define WMI_MAX_HOST_CREDITS 2 +#define WMI_WOW_REQUIRED_CREDITS 1 + +#define WMI_MAX_MHF_ENTRIES 32 + + +#define MAX_HT_MCS_IDX 8 +#define MAX_VHT_MCS_IDX 10 +#define INVALID_MCS_IDX 255 + +#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 + +/* Time(in ms) to detect DOS attack */ +#define WMA_MGMT_FRAME_DETECT_DOS_TIMER 1000 + +#define MAX_NUM_HW_MODE 0xff +#define MAX_NUM_PHY 0xff + +/** + * 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 + */ +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]; +}; + +struct tSirWifiScanCmdReqParams; +/* + * wma_main.c functions declarations + */ + +int +wmi_unified_pdev_set_param(wmi_unified_t wmi_handle, WMI_PDEV_PARAM param_id, + uint32_t param_value); + +/** + * 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 +void wma_process_roam_invoke(WMA_HANDLE handle, + struct wma_roam_invoke_cmd *roaminvoke); + +void wma_process_roam_synch_fail(WMA_HANDLE handle, + struct roam_offload_synch_fail *synch_fail); + +int wma_roam_synch_event_handler(void *handle, uint8_t *event, + uint32_t len); + +/** + * wma_roam_synch_frame_event_handler() - roam synch frame event handler + * @handle: wma handle + * @event: event data + * @len: length of data + * + * This function is roam synch frame event handler. + * + * Return: Success or Failure status + */ +int wma_roam_synch_frame_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; +} +#endif + +/** + * wma_update_per_roam_config() -per roam config parameter updation to FW + * @handle: wma handle + * @req_buf: per roam config parameters + * + * Return: none + */ +void wma_update_per_roam_config(WMA_HANDLE handle, + struct wmi_per_roam_config_req *req_buf); + +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, + tSirUpdateChanList *chan_list); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wma_roam_scan_fill_self_caps(tp_wma_handle wma_handle, + roam_offload_param * + roam_offload_params, + tSirRoamOffloadScanReq *roam_req); +#endif + +QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, + wmi_start_scan_cmd_fixed_param * + scan_cmd_fp, + tSirRoamOffloadScanReq *roam_req, + uint32_t mode, uint32_t vdev_id); + +/** + * wma_roam_scan_mawc_params() - send roam scan mode request to fw + * @wma_handle: wma handle + * @roam_req: roam request param + * + * Fill the MAWC roaming parameters and send + * WMI_ROAM_CONFIGURE_MAWC_CMDID TLV to firmware. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_mawc_params(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req); + +QDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req); + +QDF_STATUS wma_roam_scan_offload_scan_period(tp_wma_handle wma_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id); + +QDF_STATUS wma_roam_scan_offload_rssi_change(tp_wma_handle wma_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans); + +QDF_STATUS wma_roam_scan_offload_chan_list(tp_wma_handle wma_handle, + uint8_t chan_count, + uint8_t *chan_list, + uint8_t list_type, uint32_t vdev_id); + +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr); + +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr); + +void wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_start_scan_cmd_fixed_param * + scan_params); + +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 wma_roam_scan_offload_command(tp_wma_handle wma_handle, + uint32_t command, uint32_t vdev_id); + +QDF_STATUS wma_roam_preauth_chan_set(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id); + +QDF_STATUS wma_roam_preauth_chan_cancel(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id); + +void wma_roam_preauth_scan_event_handler(tp_wma_handle wma_handle, + uint8_t vdev_id, + wmi_scan_event_fixed_param * + wmi_event); + +void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params); + +#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 + +int wma_handle_btm_blacklist_event(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +#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); + +QDF_STATUS wma_start_extscan(tp_wma_handle wma, + tSirWifiScanCmdReqParams *pstart); + +QDF_STATUS wma_stop_extscan(tp_wma_handle wma, + tSirExtScanStopReqParams *pstopcmd); + +/** + * 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); + +QDF_STATUS wma_extscan_get_cached_results(tp_wma_handle wma, + tSirExtScanGetCachedResultsReqParams * + pcached_results); + +QDF_STATUS wma_extscan_get_capabilities(tp_wma_handle wma, + tSirGetExtScanCapabilitiesReqParams * + pgetcapab); +QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_epno_params *req); + +QDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req); + +QDF_STATUS wma_reset_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req); +#endif + +QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, tSirScanMacOui *psetoui); + +int wma_scan_event_callback(WMA_HANDLE handle, uint8_t *data, uint32_t len); + +void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id); + +int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, + uint32_t len); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_process_roam_synch_complete(WMA_HANDLE handle, uint8_t vdev_id); +static inline bool wma_is_roam_synch_in_progress(tp_wma_handle wma, + uint8_t vdev_id) +{ + return wma->interfaces[vdev_id].roam_synch_in_progress; +} +#else +static inline bool wma_is_roam_synch_in_progress(tp_wma_handle wma, + uint8_t vdev_id) +{ + return false; +} +static inline uint32_t wma_roam_scan_get_cckm_mode( + struct sSirRoamOffloadScanReq *roam_req, uint32_t auth_mode) +{ + return WMI_AUTH_CCKM; +} +#endif + +/* + * wma_dev_if.c functions declarations + */ + +struct cdp_vdev *wma_find_vdev_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id); + +/** + * wma_find_vdev_by_id() - Returns vdev handle for given vdev id. + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: Returns vdev handle if given vdev id is valid. + * Otherwise returns NULL. + */ +static inline +struct cdp_vdev *wma_find_vdev_by_id(tp_wma_handle wma, uint8_t vdev_id) +{ + if (vdev_id >= wma->max_bssid) + return NULL; + + return wma->interfaces[vdev_id].handle; +} + +bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef QCA_IBSS_SUPPORT +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id); +#else +/** + * wma_is_vdev_in_ibss_mode(): dummy function + * @wma: wma handle + * @vdev_id: vdev id + * + * Return false since no vdev can be in ibss mode without ibss support + */ +static inline +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + return false; +} +#endif + +/** + * 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->interfaces[vdev_id].bssid; +} + +struct cdp_vdev *wma_find_vdev_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id); + +QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *pdel_sta_self_req_param, + uint8_t generateRsp); + +int wma_vdev_start_resp_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +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 *bssid, + uint8_t vdev_id, void *peer, + bool roam_synch_in_progress); + +QDF_STATUS wma_peer_unmap_conf_send(tp_wma_handle wma, + struct send_peer_unmap_conf_params *msg); + +QDF_STATUS wma_create_peer(tp_wma_handle wma, struct cdp_pdev *pdev, + struct cdp_vdev *vdev, + u8 peer_addr[IEEE80211_ADDR_LEN], + uint32_t peer_type, uint8_t vdev_id, + bool roam_synch_in_progress); + +int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, + u32 len); + +struct cdp_vdev *wma_vdev_attach(tp_wma_handle wma_handle, + struct add_sta_self_params *self_sta_req, + uint8_t generateRsp); + +QDF_STATUS wma_vdev_start(tp_wma_handle wma, struct wma_vdev_start_req *req, + bool isRestart); + +void wma_vdev_resp_timer(void *data); + +struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout); + +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); + +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); + +void wma_add_bss(tp_wma_handle wma, tpAddBssParams params); + +void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta); + +void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta); + +void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params); + +int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type); + +void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle, + tpDisableIntraBssFwd pdis_intra_fwd); + +void wma_delete_bss_ho_fail(tp_wma_handle wma, tpDeleteBssParams params); + +uint32_t wma_get_bcn_rate_code(uint16_t rate); + +/* + * wma_mgmt.c functions declarations + */ + +int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len); + +int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len); + +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); + +int wma_vdev_install_key_complete_event_handler(void *handle, + uint8_t *event, + uint32_t len); + +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); + +void wma_update_cfg_params(tp_wma_handle wma, struct scheduler_msg *cfgParam); + +void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info); + +void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma, + uint8_t vdev_id, + int8_t peer_num_delta); + +void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info); + +QDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle, + tEdcaParams *edca_params); + +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); + +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info); + +void wma_set_keepalive_req(tp_wma_handle wma, + tSirKeepAliveReq *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); + +void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle, + tHalHiddenSsidVdevRestart *pReq); + +/* + * wma_power.c functions declarations + */ + +void wma_enable_sta_ps_mode(tp_wma_handle wma, 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_ibss_pwrsave_params(tp_wma_handle wma, uint8_t vdev_id); + +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); + +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(tp_wma_handle wma, tpDisablePsParams ps_req); + +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, + tSirTxPowerLimit *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); + +int wma_p2p_noa_event_handler(void *handle, uint8_t *event, + uint32_t len); + +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 + */ + +void wma_set_bss_rate_flags(tp_wma_handle wma, uint8_t vdev_id, + tpAddBssParams add_bss); + +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); + +int wma_peer_state_change_event_handler(void *handle, + uint8_t *event_buff, + uint32_t len); + +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); + +void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params); + +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) + +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); + +int wma_ibss_peer_info_event_handler(void *handle, uint8_t *data, + uint32_t len); + +int wma_fast_tx_fail_event_handler(void *handle, uint8_t *data, + uint32_t len); + +/* + * wma_utils.c functions declarations + */ + +#ifdef WLAN_FEATURE_STATS_EXT +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); + +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); + +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); + +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 + * @wmi_event: WMI event + * + * This function is used to send RSO command status to upper layer + * + * Return: 0 for success + */ +int wma_rso_cmd_status_event_handler(wmi_roam_event_fixed_param *wmi_event); + +int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +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); + +QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle); + +int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, + uint32_t len); + +bool wma_is_sap_active(tp_wma_handle wma_handle); + +bool wma_is_p2p_go_active(tp_wma_handle wma_handle); + +bool wma_is_p2p_cli_active(tp_wma_handle wma_handle); + +bool wma_is_sta_active(tp_wma_handle wma_handle); + +WLAN_PHY_MODE 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); + +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); + +#ifdef QCA_SUPPORT_CP_STATS +static inline void wma_get_stats_req(WMA_HANDLE handle, + struct sAniGetPEStatsReq *get_stats_param) {} +#else +void wma_get_stats_req(WMA_HANDLE handle, + struct sAniGetPEStatsReq *get_stats_param); +#endif +/* + * 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); + +QDF_STATUS wma_get_peer_info(WMA_HANDLE handle, + struct sir_peer_info_req *peer_info_req); + +/** + * wma_get_peer_info_ext() - get peer info + * @handle: wma interface + * @peer_info_req: get peer info request information + * + * This function will send WMI_REQUEST_PEER_STATS_INFO_CMDID to FW + * + * Return: 0 on success, otherwise error value + */ +QDF_STATUS wma_get_peer_info_ext(WMA_HANDLE handle, + struct sir_peer_info_ext_req *peer_info_req); + +/** + * 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); + +/** + * wma_peer_info_event_handler() - Handler for WMI_PEER_STATS_INFO_EVENTID + * @handle: WMA global handle + * @cmd_param_info: Command event data + * @len: Length of cmd_param_info + * + * This function will handle WMI_PEER_STATS_INFO_EVENTID + * + * Return: 0 on success, error code otherwise + */ +int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len); + +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); + +void wma_wow_tx_complete(void *wma); + +int wma_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef WLAN_FEATURE_NAN +int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, uint32_t len); +#endif + +#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, tDelTsParams *msg); + +void wma_aggr_qos_req(tp_wma_handle wma, + tAggrAddTsParams *pAggrQosRspMsg); + +void wma_add_ts_req(tp_wma_handle wma, tAddTsParams *msg); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler, + void *pTsmStatsMsg); +QDF_STATUS wma_plm_start(tp_wma_handle wma, const tpSirPlmReq plm); +QDF_STATUS wma_plm_stop(tp_wma_handle wma, const tpSirPlmReq plm); +void wma_config_plm(tp_wma_handle wma, tpSirPlmReq plm); +#endif + +QDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, + tSirRcvFltMcAddrList * mcbc_param); +QDF_STATUS wma_process_cesium_enable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_get_peer_info_req + (tp_wma_handle wma, tSirIbssGetPeerInfoReqParams *pReq); + +QDF_STATUS wma_process_tx_fail_monitor_ind + (tp_wma_handle wma, tAniTXFailMonitorInd *pReq); + +QDF_STATUS wma_process_rmc_enable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_rmc_disable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_rmc_action_period_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn * + pAddPeriodicTxPtrnParams); + +QDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirDelPeriodicTxPtrn * + pDelPeriodicTxPtrnParams); + +#ifdef WLAN_FEATURE_STATS_EXT +QDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq); +#endif + +QDF_STATUS wma_process_ibss_route_table_update_ind(void *wma_handle, + tAniIbssRouteTable * pData); + +#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); + +QDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + tSirAutoShutdownCmdParams * + 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); +#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 WLAN_FEATURE_NAN +QDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req); +#endif + +#ifdef DHCP_SERVER_OFFLOAD +int wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + tSirDhcpSrvOffloadInfo * + pDhcpSrvOffloadInfo); +#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 + +QDF_STATUS wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams); +int wma_update_tdls_peer_state(WMA_HANDLE handle, + tTdlsPeerStateParams *peerStateParams); +/** + * wma_set_tdls_offchan_mode() - set tdls off channel mode + * @handle: wma handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: 0 on success; negative errno otherwise + */ +QDF_STATUS wma_set_tdls_offchan_mode(WMA_HANDLE wma_handle, + tdls_chan_switch_params *chan_switch_params); +#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); + +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len); + +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); +int wma_vdev_delete_handler(void *handle, uint8_t *cmd_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); +int wma_p2p_lo_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); + +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); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * wma_sta_kickout_event()- send sta kickout event + * @kickout_reason - reasoncode for kickout + * @macaddr[IEEE80211_ADDR_LEN]: 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_start_to_fw() - send the vdev start command to firmware + * @wma: a reference to the global WMA handle + * @params: the vdev start params to send to firmware + * + * Consumers should call wma_release_wakelock() upon receipt of the vdev start + * response from firmware to avoid power penalties. Alternatively, calling the + * matching vdev_up or vdev_down APIs will also release this lock. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_send_vdev_start_to_fw(t_wma_handle *wma, struct vdev_start_params *params); + +/** + * 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_up_to_fw() - send the vdev up command to firmware + * @wma: a reference to the global WMA handle + * @params: the vdev up params to send to firmware + * @bssid: the BssId to send to firmware + * + * This also releases the vdev start wakelock. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_vdev_up_to_fw(t_wma_handle *wma, + struct vdev_up_params *params, + uint8_t bssid[IEEE80211_ADDR_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); + +int wma_twt_en_complete_event_handler(void *handle, + uint8_t *event, uint32_t len); +/** + * 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_remove_peer_on_add_bss_failure() - remove the CDP peers in case of + * ADD BSS request failed + * @add_bss_params: Pointer to the Add BSS request params + * + * This API deletes the CDP peer created during ADD BSS in case of ADD BSS + * request sent to the FW fails. + * + * Return: None + */ +void wma_remove_peer_on_add_bss_failure(tpAddBssParams add_bss_params); + +/** + * 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_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); +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..1be3fd8f8657731c0074321a006fd0136b791197 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h @@ -0,0 +1,228 @@ +/* + * 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. + */ + +#ifndef WMA_TGT_CFG_H +#define WMA_TGT_CFG_H + +#include "wma_sar_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_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 + */ +struct wma_tgt_services { + uint32_t sta_power_save; + uint32_t 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; +#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 bcn_reception_stats; +}; + +/** + * 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 + */ +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; +}; + +/** + * 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 + */ +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; +}; + +/** + * struct wma_dfs_radar_ind - dfs radar indication + * @ieee_chan_number: ieee channel number + * @chan_freq: channel freq + * @dfs_radar_status: dfs radar status + */ +struct wma_dfs_radar_ind { + uint8_t ieee_chan_number; + uint32_t chan_freq; + uint32_t dfs_radar_status; +}; + +/** + * 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 + * @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 + * @bool is_ra_rate_limit_enabled: RA filter 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 + * @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 + * @dynamic_nss_chains_support: per vdev dynamic nss, chains update + */ +struct wma_tgt_cfg { + uint32_t target_fw_version; + uint32_t target_fw_vers_ext; + uint8_t band_cap; + struct wlan_mlme_chain_cfg chain_cfg; + 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; + bool apf_enabled; +#ifdef FEATURE_WLAN_RA_FILTERING + bool is_ra_rate_limit_enabled; +#endif +#ifdef WLAN_FEATURE_NAN_DATAPATH + 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]; +#endif + bool dfs_cac_offload; + bool tx_bfee_8ss_enabled; + 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; + bool dynamic_nss_chains_support; +}; +#endif /* WMA_TGT_CFG_H */ diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_twt.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_twt.h new file mode 100644 index 0000000000000000000000000000000000000000..8efec5baa5c0075e0c86b1beeacc747248df39db --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_twt.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. + */ + +#ifndef __WMA_TWT_H +#define __WMA_TWT_H + +#include "wma.h" + +#ifdef WLAN_SUPPORT_TWT +/** + * wma_send_twt_enable_cmd() - Send TWT Enable command to firmware + * @pdev_id: pdev id + * @congestion_timeout: Timeout value for the TWT congestion timer + * + * Return: None + */ +void wma_send_twt_enable_cmd(uint32_t pdev_id, uint32_t congestion_timeout); + +/** + * 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); +#else +static inline void wma_send_twt_enable_cmd(uint32_t pdev_id, + uint32_t congestion_timeout) +{ + WMA_LOGD(FL("TWT not supported as WLAN_SUPPORT_TWT is disabled")); +} + +static inline void wma_set_twt_peer_caps(tpAddStaParams params, + struct peer_assoc_params *cmd) +{ +} +#endif + +#endif /* __WMA_HE_H */ diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_types.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_types.h new file mode 100644 index 0000000000000000000000000000000000000000..9fb9536cd4b06850e31c2ccb3b40f21c48adf228 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_types.h @@ -0,0 +1,780 @@ +/* + * 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_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_MCC_SUPPORTED 1 +#define IS_FEATURE_SUPPORTED_BY_FW(feat_enum_value) \ + wma_get_fw_wlan_feat_caps(feat_enum_value) + +#define IS_ROAM_SCAN_OFFLOAD_FEATURE_ENABLE 1 + +#define IS_IBSS_HEARTBEAT_OFFLOAD_FEATURE_ENABLE 1 + +#ifdef FEATURE_WLAN_TDLS +#define IS_ADVANCE_TDLS_ENABLE 0 +#endif + +#define WMA_NVDownload_Start(x) ({ QDF_STATUS_SUCCESS; }) + +#define DPU_FEEDBACK_UNPROTECTED_ERROR 0x0F + +#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_MPDU_HEADER_OFFSET(pRxMeta) 0 + +#define WMA_GET_RX_UNKNOWN_UCAST(pRxMeta) 0 + +#define WMA_GET_RX_CH(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->channel) + +#define WMA_IS_RX_BCAST(pRxMeta) 0 + +#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_IS_RX_IN_SCAN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->scan) + +#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)->sessionId) +#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 */ +#define WMA_MSG_TYPES_BEGIN SIR_HAL_MSG_TYPES_BEGIN +#define WMA_ITC_MSG_TYPES_BEGIN SIR_HAL_ITC_MSG_TYPES_BEGIN +#define WMA_RADAR_DETECTED_IND SIR_HAL_RADAR_DETECTED_IND + +#define WMA_ADD_STA_REQ SIR_HAL_ADD_STA_REQ +#define WMA_ADD_STA_RSP SIR_HAL_ADD_STA_RSP +#define WMA_ADD_STA_SELF_RSP SIR_HAL_ADD_STA_SELF_RSP +#define WMA_DELETE_STA_REQ SIR_HAL_DELETE_STA_REQ +#define WMA_DELETE_STA_RSP SIR_HAL_DELETE_STA_RSP +#define WMA_ADD_BSS_REQ SIR_HAL_ADD_BSS_REQ +#define WMA_ADD_BSS_RSP SIR_HAL_ADD_BSS_RSP +#define WMA_DELETE_BSS_REQ SIR_HAL_DELETE_BSS_REQ +#define WMA_DELETE_BSS_HO_FAIL_REQ SIR_HAL_DELETE_BSS_HO_FAIL_REQ +#define WMA_DELETE_BSS_RSP SIR_HAL_DELETE_BSS_RSP +#define WMA_DELETE_BSS_HO_FAIL_RSP SIR_HAL_DELETE_BSS_HO_FAIL_RSP +#define WMA_SEND_BEACON_REQ SIR_HAL_SEND_BEACON_REQ +#define WMA_SEND_BCN_RSP SIR_HAL_SEND_BCN_RSP +#define WMA_SEND_PROBE_RSP_TMPL SIR_HAL_SEND_PROBE_RSP_TMPL +#define WMA_ROAM_BLACLIST_MSG SIR_HAL_ROAM_BLACKLIST_MSG +#define WMA_SEND_PEER_UNMAP_CONF SIR_HAL_SEND_PEER_UNMAP_CONF + +#define WMA_SET_BSSKEY_REQ SIR_HAL_SET_BSSKEY_REQ +#define WMA_SET_BSSKEY_RSP SIR_HAL_SET_BSSKEY_RSP +#define WMA_SET_STAKEY_REQ SIR_HAL_SET_STAKEY_REQ +#define WMA_SET_STAKEY_RSP SIR_HAL_SET_STAKEY_RSP +#define WMA_UPDATE_EDCA_PROFILE_IND SIR_HAL_UPDATE_EDCA_PROFILE_IND + +#define WMA_UPDATE_BEACON_IND SIR_HAL_UPDATE_BEACON_IND +#define WMA_UPDATE_CF_IND SIR_HAL_UPDATE_CF_IND +#define WMA_CHNL_SWITCH_REQ SIR_HAL_CHNL_SWITCH_REQ +#define WMA_ADD_TS_REQ SIR_HAL_ADD_TS_REQ +#define WMA_DEL_TS_REQ SIR_HAL_DEL_TS_REQ + +#define WMA_MISSED_BEACON_IND SIR_HAL_MISSED_BEACON_IND + +#define WMA_ENTER_PS_REQ SIR_HAL_ENTER_PS_REQ +#define WMA_EXIT_PS_REQ SIR_HAL_EXIT_PS_REQ + +#define WMA_HIDDEN_SSID_RESTART_RSP SIR_HAL_HIDDEN_SSID_RESTART_RSP +#define WMA_SWITCH_CHANNEL_RSP SIR_HAL_SWITCH_CHANNEL_RSP +#define WMA_P2P_NOA_ATTR_IND SIR_HAL_P2P_NOA_ATTR_IND +#define WMA_PWR_SAVE_CFG SIR_HAL_PWR_SAVE_CFG +#define WMA_REGISTER_PE_CALLBACK SIR_HAL_REGISTER_PE_CALLBACK + +#define WMA_IBSS_STA_ADD SIR_HAL_IBSS_STA_ADD +#define WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND +#define WMA_SET_LINK_STATE SIR_HAL_SET_LINK_STATE +#define WMA_SET_LINK_STATE_RSP SIR_HAL_SET_LINK_STATE_RSP +#define WMA_SET_STA_BCASTKEY_REQ SIR_HAL_SET_STA_BCASTKEY_REQ +#define WMA_SET_STA_BCASTKEY_RSP SIR_HAL_SET_STA_BCASTKEY_RSP +#define WMA_ADD_TS_RSP SIR_HAL_ADD_TS_RSP +#define WMA_DPU_MIC_ERROR SIR_HAL_DPU_MIC_ERROR +#define WMA_TIMER_CHIP_MONITOR_TIMEOUT SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT +#define WMA_TIMER_TRAFFIC_ACTIVITY_REQ SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ +#define WMA_TIMER_ADC_RSSI_STATS SIR_HAL_TIMER_ADC_RSSI_STATS +#define WMA_TIMER_TRAFFIC_STATS_IND SIR_HAL_TRAFFIC_STATS_IND + +#ifdef WLAN_FEATURE_11W +#define WMA_EXCLUDE_UNENCRYPTED_IND SIR_HAL_EXCLUDE_UNENCRYPTED_IND +#endif + +#ifdef FEATURE_WLAN_ESE +#define WMA_TSM_STATS_REQ SIR_HAL_TSM_STATS_REQ +#define WMA_TSM_STATS_RSP SIR_HAL_TSM_STATS_RSP +#endif + +#define WMA_HT40_OBSS_SCAN_IND SIR_HAL_HT40_OBSS_SCAN_IND + +#define WMA_SET_MIMOPS_REQ SIR_HAL_SET_MIMOPS_REQ +#define WMA_SET_MIMOPS_RSP SIR_HAL_SET_MIMOPS_RSP +#define WMA_SYS_READY_IND SIR_HAL_SYS_READY_IND +#define WMA_SET_TX_POWER_REQ SIR_HAL_SET_TX_POWER_REQ +#define WMA_SET_TX_POWER_RSP SIR_HAL_SET_TX_POWER_RSP +#define WMA_GET_TX_POWER_REQ SIR_HAL_GET_TX_POWER_REQ + +/* Messages to support transmit_halt and transmit_resume */ +#define WMA_TRANSMISSION_CONTROL_IND SIR_HAL_TRANSMISSION_CONTROL_IND + +#define WMA_ENABLE_UAPSD_REQ SIR_HAL_ENABLE_UAPSD_REQ +#define WMA_DISABLE_UAPSD_REQ SIR_HAL_DISABLE_UAPSD_REQ + +/* / PE <-> HAL statistics messages */ +#define WMA_GET_STATISTICS_REQ SIR_HAL_GET_STATISTICS_REQ +#define WMA_GET_STATISTICS_RSP SIR_HAL_GET_STATISTICS_RSP +#define WMA_SET_KEY_DONE SIR_HAL_SET_KEY_DONE + +/* / PE <-> HAL BTC messages */ +#define WMA_BTC_SET_CFG SIR_HAL_BTC_SET_CFG +#define WMA_HANDLE_FW_MBOX_RSP SIR_HAL_HANDLE_FW_MBOX_RSP + +#define WMA_SET_MAX_TX_POWER_REQ SIR_HAL_SET_MAX_TX_POWER_REQ +#define WMA_SET_MAX_TX_POWER_RSP SIR_HAL_SET_MAX_TX_POWER_RSP +#define WMA_SET_DTIM_PERIOD SIR_HAL_SET_DTIM_PERIOD + +#define WMA_SET_MAX_TX_POWER_PER_BAND_REQ \ + SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ + +/* / PE <-> HAL Host Offload message */ +#define WMA_SET_HOST_OFFLOAD SIR_HAL_SET_HOST_OFFLOAD + +/* / PE <-> HAL Keep Alive message */ +#define WMA_SET_KEEP_ALIVE SIR_HAL_SET_KEEP_ALIVE + +#ifdef WLAN_NS_OFFLOAD +#define WMA_SET_NS_OFFLOAD SIR_HAL_SET_NS_OFFLOAD +#endif /* WLAN_NS_OFFLOAD */ +#define WMA_ADD_STA_SELF_REQ SIR_HAL_ADD_STA_SELF_REQ +#define WMA_DEL_STA_SELF_REQ SIR_HAL_DEL_STA_SELF_REQ + +#ifdef FEATURE_WLAN_TDLS +#define WMA_SET_TDLS_LINK_ESTABLISH_REQ SIR_HAL_TDLS_LINK_ESTABLISH_REQ +#define WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP +#endif + +#define WMA_WLAN_SUSPEND_IND SIR_HAL_WLAN_SUSPEND_IND +#define WMA_WLAN_RESUME_REQ SIR_HAL_WLAN_RESUME_REQ +#define WMA_MSG_TYPES_END SIR_HAL_MSG_TYPES_END + +#define WMA_AGGR_QOS_REQ SIR_HAL_AGGR_QOS_REQ +#define WMA_AGGR_QOS_RSP SIR_HAL_AGGR_QOS_RSP + +#define WMA_CSA_OFFLOAD_EVENT SIR_CSA_OFFLOAD_EVENT + +#ifdef FEATURE_WLAN_ESE +#define WMA_SET_PLM_REQ SIR_HAL_SET_PLM_REQ +#endif + +#define WMA_ROAM_SCAN_OFFLOAD_REQ SIR_HAL_ROAM_SCAN_OFFLOAD_REQ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define WMA_ROAM_OFFLOAD_SYNCH_IND SIR_HAL_ROAM_OFFLOAD_SYNCH_IND +#define WMA_ROAM_OFFLOAD_SYNCH_FAIL SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL +#endif + +#ifdef WLAN_FEATURE_PACKET_FILTERING +#define WMA_8023_MULTICAST_LIST_REQ SIR_HAL_8023_MULTICAST_LIST_REQ +#define WMA_RECEIVE_FILTER_SET_FILTER_REQ SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ +#define WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ +#define WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP +#define WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +#define WMA_DHCP_START_IND SIR_HAL_DHCP_START_IND +#define WMA_DHCP_STOP_IND SIR_HAL_DHCP_STOP_IND + +#define WMA_TX_FAIL_MONITOR_IND SIR_HAL_TX_FAIL_MONITOR_IND + +#define WMA_HIDDEN_SSID_VDEV_RESTART SIR_HAL_HIDE_SSID_VDEV_RESTART + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define WMA_GTK_OFFLOAD_REQ SIR_HAL_GTK_OFFLOAD_REQ +#define WMA_GTK_OFFLOAD_GETINFO_REQ SIR_HAL_GTK_OFFLOAD_GETINFO_REQ +#define WMA_GTK_OFFLOAD_GETINFO_RSP SIR_HAL_GTK_OFFLOAD_GETINFO_RSP +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#define WMA_SET_TM_LEVEL_REQ SIR_HAL_SET_TM_LEVEL_REQ + +#define WMA_UPDATE_OP_MODE SIR_HAL_UPDATE_OP_MODE +#define WMA_UPDATE_RX_NSS SIR_HAL_UPDATE_RX_NSS +#define WMA_UPDATE_MEMBERSHIP SIR_HAL_UPDATE_MEMBERSHIP +#define WMA_UPDATE_USERPOS SIR_HAL_UPDATE_USERPOS + +#ifdef WLAN_FEATURE_NAN +#define WMA_NAN_REQUEST SIR_HAL_NAN_REQUEST +#endif + +#define WMA_START_SCAN_OFFLOAD_REQ SIR_HAL_START_SCAN_OFFLOAD_REQ +#define WMA_STOP_SCAN_OFFLOAD_REQ SIR_HAL_STOP_SCAN_OFFLOAD_REQ +#define WMA_UPDATE_CHAN_LIST_REQ SIR_HAL_UPDATE_CHAN_LIST_REQ +#define WMA_RX_SCAN_EVENT SIR_HAL_RX_SCAN_EVENT +#define WMA_RX_CHN_STATUS_EVENT SIR_HAL_RX_CHN_STATUS_EVENT +#define WMA_IBSS_PEER_INACTIVITY_IND SIR_HAL_IBSS_PEER_INACTIVITY_IND + +#define WMA_CLI_SET_CMD SIR_HAL_CLI_SET_CMD + +#ifndef REMOVE_PKT_LOG +#define WMA_PKTLOG_ENABLE_REQ SIR_HAL_PKTLOG_ENABLE_REQ +#endif + +#ifdef FEATURE_WLAN_LPHB +#define WMA_LPHB_CONF_REQ SIR_HAL_LPHB_CONF_IND +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID +#define WMA_CH_AVOID_UPDATE_REQ SIR_HAL_CH_AVOID_UPDATE_REQ +#endif /* FEATURE_WLAN_CH_AVOID */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define WMA_SET_AUTO_SHUTDOWN_TIMER_REQ SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ +#endif + +#define WMA_ADD_PERIODIC_TX_PTRN_IND SIR_HAL_ADD_PERIODIC_TX_PTRN_IND +#define WMA_DEL_PERIODIC_TX_PTRN_IND SIR_HAL_DEL_PERIODIC_TX_PTRN_IND + +#define WMA_TX_POWER_LIMIT SIR_HAL_SET_TX_POWER_LIMIT + +#define WMA_RATE_UPDATE_IND SIR_HAL_RATE_UPDATE_IND + +#define WMA_SEND_ADDBA_REQ SIR_HAL_SEND_ADDBA_REQ +#define WMA_INIT_THERMAL_INFO_CMD SIR_HAL_INIT_THERMAL_INFO_CMD +#define WMA_SET_THERMAL_LEVEL SIR_HAL_SET_THERMAL_LEVEL +#define WMA_RMC_ENABLE_IND SIR_HAL_RMC_ENABLE_IND +#define WMA_RMC_DISABLE_IND SIR_HAL_RMC_DISABLE_IND +#define WMA_RMC_ACTION_PERIOD_IND SIR_HAL_RMC_ACTION_PERIOD_IND + +/* IBSS peer info related message */ +#define WMA_GET_IBSS_PEER_INFO_REQ SIR_HAL_IBSS_PEER_INFO_REQ + +#define WMA_IBSS_CESIUM_ENABLE_IND SIR_HAL_IBSS_CESIUM_ENABLE_IND + +#define WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD SIR_HAL_BAD_PEER_TX_CTL_INI_CMD + +#ifdef FEATURE_WLAN_TDLS +#define WMA_UPDATE_TDLS_PEER_STATE SIR_HAL_UPDATE_TDLS_PEER_STATE +#define WMA_TDLS_SHOULD_DISCOVER_CMD SIR_HAL_TDLS_SHOULD_DISCOVER +#define WMA_TDLS_SHOULD_TEARDOWN_CMD SIR_HAL_TDLS_SHOULD_TEARDOWN +#define WMA_TDLS_PEER_DISCONNECTED_CMD SIR_HAL_TDLS_PEER_DISCONNECTED +#define WMA_TDLS_SET_OFFCHAN_MODE SIR_HAL_TDLS_SET_OFFCHAN_MODE +#define WMA_TDLS_CONNECTION_TRACKER_NOTIFICATION_CMD SIR_HAL_TDLS_CONNECTION_TRACKER_NOTIFICATION +#endif +#define WMA_SET_SAP_INTRABSS_DIS SIR_HAL_SET_SAP_INTRABSS_DIS + +/* Message to indicate beacon tx completion after beacon template update + * beacon offload case + */ +#define WMA_DFS_BEACON_TX_SUCCESS_IND SIR_HAL_BEACON_TX_SUCCESS_IND +#define WMA_DISASSOC_TX_COMP SIR_HAL_DISASSOC_TX_COMP +#define WMA_DEAUTH_TX_COMP SIR_HAL_DEAUTH_TX_COMP + +#define WMA_GET_PEER_INFO SIR_HAL_GET_PEER_INFO +#define WMA_GET_PEER_INFO_EXT SIR_HAL_GET_PEER_INFO_EXT + +#define WMA_GET_ISOLATION SIR_HAL_GET_ISOLATION + +#define WMA_MODEM_POWER_STATE_IND SIR_HAL_MODEM_POWER_STATE_IND + +#ifdef WLAN_FEATURE_STATS_EXT +#define WMA_STATS_EXT_REQUEST SIR_HAL_STATS_EXT_REQUEST +#endif + +#define WMA_GET_TEMPERATURE_REQ SIR_HAL_GET_TEMPERATURE_REQ +#define WMA_SET_WISA_PARAMS SIR_HAL_SET_WISA_PARAMS + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_EXTSCAN_GET_CAPABILITIES_REQ SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ +#define WMA_EXTSCAN_START_REQ SIR_HAL_EXTSCAN_START_REQ +#define WMA_EXTSCAN_STOP_REQ SIR_HAL_EXTSCAN_STOP_REQ +#define WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ +#define WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ +#define WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ +#define WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ +#define WMA_EXTSCAN_GET_CACHED_RESULTS_REQ SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ +#define WMA_SET_EPNO_LIST_REQ SIR_HAL_SET_EPNO_LIST_REQ +#define WMA_SET_PASSPOINT_LIST_REQ SIR_HAL_SET_PASSPOINT_LIST_REQ +#define WMA_RESET_PASSPOINT_LIST_REQ SIR_HAL_RESET_PASSPOINT_LIST_REQ + +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define WMA_LINK_LAYER_STATS_CLEAR_REQ SIR_HAL_LL_STATS_CLEAR_REQ +#define WMA_LINK_LAYER_STATS_SET_REQ SIR_HAL_LL_STATS_SET_REQ +#define WMA_LINK_LAYER_STATS_GET_REQ SIR_HAL_LL_STATS_GET_REQ +#define WMA_LINK_LAYER_STATS_RESULTS_RSP SIR_HAL_LL_STATS_RESULTS_RSP +#define WDA_LINK_LAYER_STATS_SET_THRESHOLD SIR_HAL_LL_STATS_EXT_SET_THRESHOLD +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#define WMA_LINK_STATUS_GET_REQ SIR_HAL_LINK_STATUS_GET_REQ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define WMA_WLAN_EXT_WOW SIR_HAL_CONFIG_EXT_WOW +#define WMA_WLAN_SET_APP_TYPE1_PARAMS SIR_HAL_CONFIG_APP_TYPE1_PARAMS +#define WMA_WLAN_SET_APP_TYPE2_PARAMS SIR_HAL_CONFIG_APP_TYPE2_PARAMS +#endif + +#define WMA_SET_SCAN_MAC_OUI_REQ SIR_HAL_SET_SCAN_MAC_OUI_REQ +#define WMA_TSF_GPIO_PIN SIR_HAL_TSF_GPIO_PIN_REQ + +#ifdef DHCP_SERVER_OFFLOAD +#define WMA_SET_DHCP_SERVER_OFFLOAD_CMD SIR_HAL_SET_DHCP_SERVER_OFFLOAD +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +#define WMA_LED_FLASHING_REQ SIR_HAL_LED_FLASHING_REQ +#endif + +/* Message posted by wmi when wmi event is received from FW */ +#define WMA_PROCESS_FW_EVENT SIR_HAL_PROCESS_FW_EVENT + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define WMA_UPDATE_Q2Q_IE_IND SIR_HAL_UPDATE_Q2Q_IE_IND +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#define WMA_SET_RSSI_MONITOR_REQ SIR_HAL_SET_RSSI_MONITOR_REQ + +#define WMA_OCB_SET_CONFIG_CMD SIR_HAL_OCB_SET_CONFIG_CMD +#define WMA_OCB_SET_UTC_TIME_CMD SIR_HAL_OCB_SET_UTC_TIME_CMD +#define WMA_OCB_START_TIMING_ADVERT_CMD SIR_HAL_OCB_START_TIMING_ADVERT_CMD +#define WMA_OCB_STOP_TIMING_ADVERT_CMD SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD +#define WMA_OCB_GET_TSF_TIMER_CMD SIR_HAL_OCB_GET_TSF_TIMER_CMD +#define WMA_DCC_GET_STATS_CMD SIR_HAL_DCC_GET_STATS_CMD +#define WMA_DCC_CLEAR_STATS_CMD SIR_HAL_DCC_CLEAR_STATS_CMD +#define WMA_DCC_UPDATE_NDL_CMD SIR_HAL_DCC_UPDATE_NDL_CMD +#define WMA_SET_IE_INFO SIR_HAL_SET_IE_INFO + +#define WMA_LRO_CONFIG_CMD SIR_HAL_LRO_CONFIG_CMD +#define WMA_GW_PARAM_UPDATE_REQ SIR_HAL_GATEWAY_PARAM_UPDATE_REQ +#define WMA_ADD_BCN_FILTER_CMDID SIR_HAL_ADD_BCN_FILTER_CMDID +#define WMA_REMOVE_BCN_FILTER_CMDID SIR_HAL_REMOVE_BCN_FILTER_CMDID +#define WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS + +#define WDA_APF_GET_CAPABILITIES_REQ SIR_HAL_APF_GET_CAPABILITIES_REQ +#define WDA_APF_SET_INSTRUCTIONS_REQ SIR_HAL_APF_SET_INSTRUCTIONS_REQ + +#define WMA_SET_PDEV_IE_REQ SIR_HAL_SET_PDEV_IE_REQ +#define WMA_UPDATE_WEP_DEFAULT_KEY SIR_HAL_UPDATE_WEP_DEFAULT_KEY +#define WMA_SEND_FREQ_RANGE_CONTROL_IND SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND +#define WMA_POWER_DEBUG_STATS_REQ SIR_HAL_POWER_DEBUG_STATS_REQ +#define WMA_BEACON_DEBUG_STATS_REQ SIR_HAL_BEACON_DEBUG_STATS_REQ +#define WMA_GET_RCPI_REQ SIR_HAL_GET_RCPI_REQ +#define WMA_ROAM_BLACKLIST_MSG SIR_HAL_ROAM_BLACKLIST_MSG + +#define WMA_SET_DBS_SCAN_SEL_CONF_PARAMS SIR_HAL_SET_DBS_SCAN_SEL_PARAMS + +#define WMA_SET_WOW_PULSE_CMD SIR_HAL_SET_WOW_PULSE_CMD + +#define WMA_SET_PER_ROAM_CONFIG_CMD SIR_HAL_SET_PER_ROAM_CONFIG_CMD + +#define WMA_SET_ARP_STATS_REQ SIR_HAL_SET_ARP_STATS_REQ +#define WMA_GET_ARP_STATS_REQ SIR_HAL_GET_ARP_STATS_REQ +#define WMA_SET_LIMIT_OFF_CHAN SIR_HAL_SET_LIMIT_OFF_CHAN +#define WMA_OBSS_DETECTION_REQ SIR_HAL_OBSS_DETECTION_REQ +#define WMA_OBSS_DETECTION_INFO SIR_HAL_OBSS_DETECTION_INFO +#define WMA_INVOKE_NEIGHBOR_REPORT SIR_HAL_INVOKE_NEIGHBOR_REPORT +#define WMA_OBSS_COLOR_COLLISION_REQ SIR_HAL_OBSS_COLOR_COLLISION_REQ +#define WMA_OBSS_COLOR_COLLISION_INFO SIR_HAL_OBSS_COLOR_COLLISION_INFO + +#define WMA_GET_ROAM_SCAN_STATS SIR_HAL_GET_ROAM_SCAN_STATS + +#ifdef WLAN_MWS_INFO_DEBUGFS +#define WMA_GET_MWS_COEX_INFO_REQ SIR_HAL_GET_MWS_COEX_INFO_REQ +#endif + +/* 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) \ + (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))) + +#define wma_tx_frameWithTxComplete(hHal, pFrmBuf, frmLen, frmType, txDir, tid, \ + pCompFunc, pData, pCBackFnTxComp, txFlag, sessionid, tdlsflag, \ + channel_freq, rid) \ + (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))) + + +#define WMA_SetEnableSSR(enable_ssr) ((void)enable_ssr) + +/** + * 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 + * @bssid: mac address + * @sessionid: sme session id / vdev id + * @bcnDtimPeriod: beacon DTIM Period + * @status: success/failure + */ +typedef struct sEnablePsParams { + tSirAddonPsReq psSetting; + tUapsd_Params uapsdParams; + tSirMacAddr bssid; + uint32_t sessionid; + uint8_t bcnDtimPeriod; + uint32_t status; +} tEnablePsParams, *tpEnablePsParams; + +/** + * struct sDisablePsParams - Disable PowerSave Params + * @psSetting: power save setting + * @bssid: mac address + * @sessionid: sme session id / vdev id + * @status: success/failure + */ +typedef struct sDisablePsParams { + tSirAddonPsReq psSetting; + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} 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 pMac 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 pMac 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); + +typedef void (*wma_txFailIndCallback)(uint8_t *, uint8_t); + +/* 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; + +#ifdef FEATURE_WLAN_TDLS +/** + * enum WMA_TdlsPeerState - TDLS PEER state + * @WMA_TDLS_PEER_STATE_PEERING: peer is making connection + * @WMA_TDLS_PEER_STATE_CONNECTED: peer is connected + * @WMA_TDLS_PEER_STATE_TEARDOWN: peer is teardown + * @WMA_TDLS_PEER_ADD_MAC_ADDR: add peer into connection table + * @WMA_TDLS_PEER_REMOVE_MAC_ADDR: remove peer from connection table + */ +enum WMA_TdlsPeerState { + WMA_TDLS_PEER_STATE_PEERING, + WMA_TDLS_PEER_STATE_CONNECTED, + WMA_TDLS_PEER_STATE_TEARDOWN, + WMA_TDLS_PEER_ADD_MAC_ADDR, + WMA_TDLS_PEER_REMOVE_MAC_ADDR, +}; + +/** + * enum wma_tdls_off_chan_mode - modes for WMI_TDLS_SET_OFFCHAN_MODE_CMDID + * @WMA_TDLS_ENABLE_OFFCHANNEL: enable off channel + * @WMA_TDLS_DISABLE_OFFCHANNEL: disable off channel + */ +enum wma_tdls_off_chan_mode { + WMA_TDLS_ENABLE_OFFCHANNEL, + WMA_TDLS_DISABLE_OFFCHANNEL +}; + +#endif /* FEATURE_WLAN_TDLS */ + +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(tpAniSirGlobal pMac, 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_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); + +QDF_STATUS +wma_ds_peek_rx_packet_info + (cds_pkt_t *vosDataBuff, void **ppRxHeader, bool bSwap); + + +void wma_tx_abort(uint8_t vdev_id); + +QDF_STATUS wma_tx_packet(void *pWMA, + void *pFrmBuf, + uint16_t frmLen, + eFrameType frmType, + eFrameTxDir txDir, + uint8_t tid, + wma_tx_dwnld_comp_callback pCompFunc, + void *pData, + wma_tx_ota_comp_callback pAckTxComp, + uint8_t txFlag, uint8_t sessionId, bool tdlsflag, + uint16_t channel_freq, enum rateid rid); + +/** + * 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_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason), + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason)); +#else +static inline QDF_STATUS wma_register_roaming_callbacks( + QDF_STATUS (*csr_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason), + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason)) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c b/drivers/staging/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c new file mode 100644 index 0000000000000000000000000000000000000000..dd3316a194232b274c163895d061ecbb91c61b43 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c @@ -0,0 +1,153 @@ +/* + * 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: 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 "cfg_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 + * @pMac: MAC parameters structure + * @pMsg: pointer with message + * + * Return: Success or Failure + */ + +QDF_STATUS wma_post_ctrl_msg(tpAniSirGlobal pMac, 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; +} + +/** + * wma_post_cfg_msg() - Posts MNT messages to gSirMntMsgQ + * @pMac: MAC parameters structure + * @pMsg: A pointer to the msg + * + * Return: Success or Failure + */ + +static QDF_STATUS wma_post_cfg_msg(tpAniSirGlobal pMac, + struct scheduler_msg *pMsg) +{ + QDF_STATUS rc = QDF_STATUS_SUCCESS; + + do { + /* + *For Windows based MAC, instead of posting message to different + * queues we will call the handler routines directly + */ + + cfg_process_mb_msg(pMac, (tSirMbMsg *) pMsg->bodyptr); + rc = QDF_STATUS_SUCCESS; + } while (0); + + return rc; +} + +/** + * u_mac_post_ctrl_msg() - post ctrl msg + * @pMb: A pointer to the maibox 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; + tpAniSirGlobal pMac = (tpAniSirGlobal) 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(pMac, &msg); + break; + + case SIR_LIM_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + status = lim_post_msg_api(pMac, &msg); + break; + + case SIR_CFG_MSG_TYPES_BEGIN: /* Posts a message to the CFG MsgQ */ + status = wma_post_cfg_msg(pMac, &msg); + break; + + case SIR_PMM_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + status = sme_post_pe_message(pMac, &msg); + break; + + default: + WMA_LOGD("Unknown message type = 0x%X\n", 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_TRACE_ERROR(QDF_MODULE_ID_SYS, "Invalid MAC handle"); + qdf_mem_free(msg); + return QDF_STATUS_E_FAILURE; + } + + return u_mac_post_ctrl_msg(mac_handle, msg); +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_coex.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_coex.c new file mode 100644 index 0000000000000000000000000000000000000000..cd23f7b42a4ec32eb65f14c6e03e927eb2f7e9c0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_coex.c @@ -0,0 +1,377 @@ + +/* + * 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. + */ + +#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; + tpAniSirGlobal 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; + tpAniSirGlobal 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; + tpAniSirGlobal 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; + tpAniSirGlobal 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; + tpAniSirGlobal 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_LOGE("Failed to send mws coex info"); +} + +void wma_register_mws_coex_events(tp_wma_handle wma_handle) +{ + if (!wma_handle) { + wma_err("wma_handle is NULL"); + 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/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c new file mode 100644 index 0000000000000000000000000000000000000000..7db95212e84010ef3a2433eb2ac7fb4e85210b0e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c @@ -0,0 +1,3214 @@ +/* + * 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_data.c + * This file contains tx/rx and data path 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 "cfg_api.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 "enet.h" +#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 +#include "wlan_lmac_if_api.h" +#include +#include + +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 gaurd 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 gaurd 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 gaurd 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 gaurd 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 gaurd 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 gaurd 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 gaurd 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, WMI_HOST_WLAN_PHY_MODE chanmode, + 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_LOGE("%s: Error, Invalid chwidth enum %d", __func__, + chwidth); + return (*streaming_rate != 0) ? QDF_STATUS_SUCCESS : QDF_STATUS_E_INVAL; +} + +/** + * wma_fill_vht_mcast_rate() - fill vht mcast rate + * @shortgi: short gaurd 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, + WMI_HOST_WLAN_PHY_MODE chanmode, + 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_LOGE("%s: chwidth enum %d not supported", + __func__, 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 gaurd 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, + WMI_HOST_WLAN_PHY_MODE chanmode, 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_LOGE("%s: Input: nss = %d, chanmode = %d, mbpsx10 = 0x%x, chwidth = %d, shortgi = %d", + __func__, nss, chanmode, mbpsx10_rate, chwidth, shortgi); + if ((mbpsx10_rate & 0x40000000) && nss > 0) { + /* bit 30 indicates user inputed 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, chanmode, &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, chanmode, &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_LOGE("%s: NSS = %d, ucast_chanmode = %d, freq = %d", + __func__, nss, chanmode, mhz); + WMA_LOGD(" %s: input_rate = %d, chwidth = %d rate = 0x%x, streaming_rate = %d", + __func__, 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_LOGE("%s: NSS = %d, ucast_chanmode = %d, input_rate = %d, rate = 0x%x", + __func__, nss, chanmode, mbpsx10_rate, *rate); + } + return ret; +} + +#ifdef QCA_SUPPORT_CP_STATS +/** + * 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]; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + WMA_LOGE("%s, vdev not found for id: %d", __func__, + vdev_id); + return; + } + + ucfg_mc_cp_stats_set_rate_flags(vdev, iface->rate_flags); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); +} +#else +static void wma_cp_stats_set_rate_flag(tp_wma_handle wma, uint8_t vdev_id) {} +#endif + +/** + * wma_set_bss_rate_flags() - set rate flags based on BSS capability + * @iface: txrx_node ctx + * @add_bss: add_bss params + * + * Return: none + */ +void wma_set_bss_rate_flags(tp_wma_handle wma, uint8_t vdev_id, + tpAddBssParams add_bss) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + iface->rate_flags = 0; + if (add_bss->vhtCapable) { + if (add_bss->ch_width == CH_WIDTH_80P80MHZ) + iface->rate_flags |= TX_RATE_VHT80; + if (add_bss->ch_width == CH_WIDTH_160MHZ) + iface->rate_flags |= TX_RATE_VHT80; + if (add_bss->ch_width == CH_WIDTH_80MHZ) + iface->rate_flags |= TX_RATE_VHT80; + else if (add_bss->ch_width) + iface->rate_flags |= TX_RATE_VHT40; + else + iface->rate_flags |= TX_RATE_VHT20; + } + /* avoid to conflict with htCapable flag */ + else if (add_bss->htCapable) { + if (add_bss->ch_width) + iface->rate_flags |= TX_RATE_HT40; + else + iface->rate_flags |= TX_RATE_HT20; + } + + if (add_bss->staContext.fShortGI20Mhz || + add_bss->staContext.fShortGI40Mhz) + iface->rate_flags |= TX_RATE_SGI; + + if (!add_bss->htCapable && !add_bss->vhtCapable) + iface->rate_flags = TX_RATE_LEGACY; + + wma_cp_stats_set_rate_flag(wma, vdev_id); +} + +/** + * 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_LOGD("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; + + if (cds_is_load_or_unload_in_progress()) { + WMA_LOGE("%s: Driver load/unload in progress", __func__); + return; + } + + work = (struct wma_tx_ack_work_ctx *)ack_work; + + wma_handle = work->wma_handle; + ack_cb = wma_handle->umac_data_ota_ack_cb; + + if (work->status) + WMA_LOGE("Data Tx Ack Cb Status %d", work->status); + else + WMA_LOGD("Data Tx Ack Cb Status %d", work->status); + + /* Call the Ack Cb registered by UMAC */ + if (ack_cb) + ack_cb((tpAniSirGlobal) (wma_handle->mac_context), NULL, + work->status, NULL); + else + WMA_LOGE("Data Tx Ack Cb is NULL"); + + wma_handle->umac_data_ota_ack_cb = NULL; + wma_handle->last_umac_data_nbuf = NULL; + qdf_mem_free(work); + 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) +{ + void *pdev; + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid WMA Handle", __func__); + return; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + 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) { + if (wma_handle->umac_data_ota_ack_cb) { + WMA_LOGE("%s: nbuf does not match but umac_data_ota_ack_cb is not null", + __func__); + } else { + WMA_LOGE("%s: nbuf does not match and umac_data_ota_ack_cb is also null", + __func__); + } + goto free_nbuf; + } + + if (wma_handle && wma_handle->umac_data_ota_ack_cb) { + struct wma_tx_ack_work_ctx *ack_work; + + ack_work = qdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx)); + wma_handle->ack_work_ctx = ack_work; + if (ack_work) { + ack_work->wma_handle = wma_handle; + ack_work->sub_type = 0; + ack_work->status = status; + + qdf_create_work(0, &ack_work->ack_cmp_work, + wma_data_tx_ack_work_handler, + ack_work); + qdf_sched_work(0, &ack_work->ack_cmp_work); + } + } + +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_LOGE("%s: Requested value %d over the range", + __func__, cmd_value); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_peer_state_change_event_handler() - peer state change event handler + * @handle: wma handle + * @event_buff: event buffer + * @len: length of buffer + * + * This event handler unpauses vdev if peer state change to AUTHORIZED STATE + * + * Return: 0 for success or error code + */ +int wma_peer_state_change_event_handler(void *handle, + uint8_t *event_buff, + uint32_t len) +{ + WMI_PEER_STATE_EVENTID_param_tlvs *param_buf; + wmi_peer_state_event_fixed_param *event; + struct cdp_vdev *vdev; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!event_buff) { + WMA_LOGE("%s: Received NULL event ptr from FW", __func__); + return -EINVAL; + } + param_buf = (WMI_PEER_STATE_EVENTID_param_tlvs *) event_buff; + if (!param_buf) { + WMA_LOGE("%s: Received NULL buf ptr from FW", __func__); + return -ENOMEM; + } + + event = param_buf->fixed_param; + vdev = wma_find_vdev_by_id(wma_handle, event->vdev_id); + if (NULL == vdev) { + WMA_LOGD("%s: Couldn't find vdev for vdev_id: %d", + __func__, event->vdev_id); + return -EINVAL; + } + + if ((cdp_get_opmode(cds_get_context(QDF_MODULE_ID_SOC), + vdev) == + wlan_op_mode_sta) && + event->state == WMI_PEER_STATE_AUTHORIZED) { + /* + * set event so that hdd + * can procced and unpause tx queue + */ +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + if (!wma_handle->peer_authorized_cb) { + WMA_LOGE("%s: peer authorized cb not registered", + __func__); + return -EINVAL; + } + wma_handle->peer_authorized_cb(event->vdev_id); +#endif + } + + return 0; +} + +/** + * 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 (NULL == wma) { + WMA_LOGE("%s : Failed to get wma", __func__); + 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) +{ + uint32_t cfg_val = 0; + struct sAniSirGlobal *pMac = NULL; + uint32_t channel1 = mcc_channel; + uint32_t chan1_freq = cds_chan_to_freq(channel1); + + if (!wma) { + WMA_LOGE("%s:NULL wma ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(pMac)) { + WMA_LOGE("%s: MCC is not active. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + /* Confirm MCC adaptive scheduler feature is disabled */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == QDF_STATUS_SUCCESS) { + if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) { + WMA_LOGD("%s: Can't set channel latency while MCC ADAPTIVE SCHED is enabled. Exit", + __func__); + return QDF_STATUS_SUCCESS; + } + } else { + WMA_LOGE("%s: Failed to get value for MCC_ADAPTIVE_SCHED, " + "Exit w/o setting latency", __func__); + 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) +{ + uint32_t cfg_val = 0; + struct sAniSirGlobal *pMac = 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_LOGE("%s:NULL wma ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(pMac)) { + WMA_LOGD("%s: MCC is not active. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* Confirm MCC adaptive scheduler feature is disabled */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == QDF_STATUS_SUCCESS) { + if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) { + WMA_LOGD("%s: Can't set channel quota while MCC_ADAPTIVE_SCHED is enabled. Exit", + __func__); + return QDF_STATUS_SUCCESS; + } + } else { + WMA_LOGE("%s: Failed to retrieve WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED. Exit", + __func__); + 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); +} + +/** + * wma_set_linkstate() - set wma linkstate + * @wma: wma handle + * @params: link state params + * + * Return: none + */ +void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params) +{ + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t vdev_id; + bool roam_synch_in_progress = false; + QDF_STATUS status; + struct wma_target_req *msg; + + params->status = true; + WMA_LOGD("%s: state %d selfmac %pM", __func__, + params->state, params->selfMacAddr); + if ((params->state != eSIR_LINK_PREASSOC_STATE) && + (params->state != eSIR_LINK_DOWN_STATE)) { + WMA_LOGD("%s: unsupported link state %d", + __func__, params->state); + params->status = false; + goto out; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Unable to get TXRX context", __func__); + params->status = false; + goto out; + } + + vdev = wma_find_vdev_by_addr(wma, params->selfMacAddr, &vdev_id); + if (!vdev) { + WMA_LOGP("%s: vdev not found for addr: %pM", + __func__, params->selfMacAddr); + params->status = false; + goto out; + } + + if (wma_is_vdev_in_ap_mode(wma, vdev_id)) { + WMA_LOGD("%s: Ignoring set link req in ap mode", __func__); + params->status = false; + goto out; + } + + if (params->state == eSIR_LINK_PREASSOC_STATE) { + if (wma_is_roam_synch_in_progress(wma, vdev_id)) + roam_synch_in_progress = true; + status = wma_create_peer(wma, pdev, vdev, params->bssid, + WMI_PEER_TYPE_DEFAULT, vdev_id, + roam_synch_in_progress); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Unable to create peer", __func__); + params->status = false; + } + if (roam_synch_in_progress) + return; + } else { + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP", + __func__, vdev_id); + cdp_fc_vdev_pause(soc, + wma->interfaces[vdev_id].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + msg = wma_fill_vdev_req(wma, vdev_id, + WMA_SET_LINK_STATE, + WMA_TARGET_REQ_TYPE_VDEV_STOP, params, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to fill vdev request for vdev_id %d"), + vdev_id); + params->status = false; + status = QDF_STATUS_E_NOMEM; + goto out; + } + wma_vdev_set_pause_bit(vdev_id, PAUSE_TYPE_HOST); + if (wma_send_vdev_stop_to_fw(wma, vdev_id)) { + WMA_LOGP("%s: %d Failed to send vdev stop", + __func__, __LINE__); + params->status = false; + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + } else { + WMA_LOGP("%s: %d vdev stop sent vdev %d", + __func__, __LINE__, vdev_id); + /* + * Remove peer, Vdev down and sending set link + * response will be handled in vdev stop response + * handler + */ + return; + } + } +out: + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); +} + +/** + * 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) +{ + int32_t ret = 0; + uint8_t vdev_id = 0; + void *pdev; + int32_t mbpsx10_rate = -1; + uint32_t paramId; + uint8_t rate = 0; + uint32_t short_gi; + struct wma_txrx_node *intr = wma->interfaces; + QDF_STATUS status; + + /* Get the vdev id */ + pdev = wma_find_vdev_by_addr(wma, pRateUpdateParams->bssid.bytes, + &vdev_id); + if (!pdev) { + WMA_LOGE("vdev handle is invalid for %pM", + pRateUpdateParams->bssid.bytes); + qdf_mem_free(pRateUpdateParams); + return QDF_STATUS_E_INVAL; + } + short_gi = intr[vdev_id].config.shortgi; + if (short_gi == 0) + short_gi = (intr[vdev_id].rate_flags & 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_LOGE("%s: dev_id = %d, dev_type = %d, dev_mode = %d,", + __func__, vdev_id, intr[vdev_id].type, + pRateUpdateParams->dev_mode); + WMA_LOGE("%s: mac = %pM, config.shortgi = %d, rate_flags = 0x%x", + __func__, pRateUpdateParams->bssid.bytes, + intr[vdev_id].config.shortgi, intr[vdev_id].rate_flags); + ret = wma_encode_mc_rate(short_gi, intr[vdev_id].config.chwidth, + intr[vdev_id].chanmode, intr[vdev_id].mhz, + mbpsx10_rate, pRateUpdateParams->nss, &rate); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Error, Invalid input rate value", __func__); + qdf_mem_free(pRateUpdateParams); + return ret; + } + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SGI, short_gi); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Fail to Set WMI_VDEV_PARAM_SGI(%d), status = %d", + __func__, short_gi, status); + qdf_mem_free(pRateUpdateParams); + return status; + } + status = wma_vdev_set_param(wma->wmi_handle, + vdev_id, paramId, rate); + qdf_mem_free(pRateUpdateParams); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Fail to Set rate, status = %d", __func__, status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * 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; + uint16_t desc_id; + + desc_id = QDF_NBUF_CB_MGMT_TXRX_DESC_ID(netbuf); + + mgmt_txrx_tx_completion_handler(pdev, desc_id, status, NULL); +} + +/** + * 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_LOGD("Tx Complete Status %d", status); + + if (!wma_handle->tx_frm_download_comp_cb) { + WMA_LOGE("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_LOGP("%s: Event Set failed - tx_frm_comp_event", __func__); +} + +/** + * 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 handle */ + struct cdp_pdev *txrx_pdev = cds_handle->pdev_txrx_ctx; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + /* Register for Tx Management Frames */ + cdp_mgmt_tx_cb_set(soc, txrx_pdev, 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, txrx_pdev, + 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 Vos Context */ + struct cds_context *cds_handle = + (struct cds_context *) (wma_handle->cds_context); + + /* Get the txRx Pdev handle */ + struct cdp_pdev *txrx_pdev = cds_handle->pdev_txrx_ctx; + + if (!soc) { + WMA_LOGE("%s:SOC context is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (txrx_pdev) { + /* Deregister with TxRx for Tx Mgmt completion call back */ + cdp_mgmt_tx_cb_set(soc, txrx_pdev, 0, NULL, NULL, txrx_pdev); + } + + /* 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) + +/** + * 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) +{ + 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_LOGE("Invalid roam event buffer"); + return -EINVAL; + } + + if (pmo_ucfg_get_wow_bus_suspend(wma->psoc)) { + WMA_LOGD(" Suspend is in progress: Pause/Unpause Tx is NoOp"); + return 0; + } + + if (!soc) { + WMA_LOGE("%s:SOC context is NULL", __func__); + 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].handle) { + WMA_LOGE("%s: invalid vdev ID %d", __func__, + vdev_id); + /* Test Next VDEV */ + vdev_map >>= 1; + continue; + } + + /* PAUSE action, add bitmap */ + if (ACTION_PAUSE == wmi_event->action) { + /* + * 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, + wma-> + interfaces[vdev_id].handle, + OL_TXQ_PAUSE_REASON_FW); + wma_vdev_set_pause_bit(vdev_id, + wmi_event->pause_type); + } + /* UNPAUSE action, clean bitmap */ + else if (ACTION_UNPAUSE == wmi_event->action) { + /* Handle unpause only if already paused */ + if (wma_vdev_get_pause_bitmap(vdev_id)) { + wma_vdev_clear_pause_bit(vdev_id, + wmi_event->pause_type); + + if (!wma->interfaces[vdev_id]. + pause_bitmap) { + /* PAUSE BIT MAP is cleared + * UNPAUSE VDEV + */ + cdp_fc_vdev_unpause(soc, + wma->interfaces[vdev_id] + .handle, + OL_TXQ_PAUSE_REASON_FW); + } + } + } else { + WMA_LOGE("Not Valid Action Type %d", + wmi_event->action); + } + + WMA_LOGD + ("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 firmare\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 seeting 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 */ + struct cdp_pdev *curr_pdev; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (NULL == wma || NULL == config) { + WMA_LOGE("%s Invalid input\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGE("%s enable %d period %d txq limit %d\n", __func__, + 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, + curr_pdev, + 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, + curr_pdev, + i, + threshold, + limit); + } + } + + return wma_set_peer_rate_report_condition(wma, config); +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + + +/** + * 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) +{ + t_thermal_cmd_params thermal_params; + struct cdp_pdev *curr_pdev; + + if (NULL == wma || NULL == pThermalParams) { + WMA_LOGE("TM Invalid input"); + return QDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("TM enable %d period %d", pThermalParams->thermalMgmtEnabled, + pThermalParams->throttlePeriod); + + WMA_LOGD("Throttle Duty Cycle Level in percentage:\n" + "0 %d\n" + "1 %d\n" + "2 %d\n" + "3 %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]); + + 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.thermalCurrLevel = WLAN_WMA_THERMAL_LEVEL_0; + + WMA_LOGD("TM level min max:\n" + "0 %d %d\n" + "1 %d %d\n" + "2 %d %d\n" + "3 %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); + + if (wma->thermal_mgmt_info.thermalMgmtEnabled) { + cdp_throttle_init_period(cds_get_context(QDF_MODULE_ID_SOC), + curr_pdev, + pThermalParams->throttlePeriod, + &pThermalParams->throttle_duty_cycle_tbl[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; + + WMA_LOGE("TM sending the following to firmware: min %d max %d enable %d", + thermal_params.minTemp, thermal_params.maxTemp, + thermal_params.thermalEnable); + + if (QDF_STATUS_SUCCESS != + wma_set_thermal_mgmt(wma, thermal_params)) { + WMA_LOGE("Could not send thermal mgmt command to the firmware!"); + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * 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_LOGI(FL("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_LOGE(FL( + "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) +{ + struct cdp_pdev *curr_pdev; + + if (NULL == wma) { + WMA_LOGE("TM Invalid input"); + return QDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGE("TM set level %d", thermal_level); + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + WMA_LOGE("Thermal mgmt is not enabled, ignoring set level command"); + return QDF_STATUS_E_FAILURE; + } + + if (thermal_level >= WLAN_WMA_MAX_THERMAL_LEVELS) { + WMA_LOGE("Invalid thermal level set %d", thermal_level); + return QDF_STATUS_E_FAILURE; + } + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + WMA_LOGD("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), + curr_pdev, + 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_LOGE("%s:'wma_set_thermal_mgmt':invalid input", __func__); + 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; + + 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_LOGW("Change thermal level from %d -> %d\n", + wma->thermal_mgmt_info.thermalCurrLevel, level); + + return level; +} + +/** + * wma_thermal_mgmt_evt_handler() - thermal mgmt event handler + * @wma_handle: Pointer to WMA handle + * @event: Thermal event information + * + * This function handles the thermal mgmt event from the firmware len + * + * 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; + WMI_THERMAL_MGMT_EVENTID_param_tlvs *param_buf; + struct cdp_pdev *curr_pdev; + + if (NULL == event || NULL == handle) { + WMA_LOGE("Invalid thermal mitigation event buffer"); + return -EINVAL; + } + + wma = (tp_wma_handle) handle; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma handle", __func__); + return -EINVAL; + } + + param_buf = (WMI_THERMAL_MGMT_EVENTID_param_tlvs *) event; + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return -EINVAL; + } + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + WMA_LOGE("Thermal mgmt is not enabled, ignoring event"); + return -EINVAL; + } + + tm_event = param_buf->fixed_param; + WMA_LOGD("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_LOGD("Thermal mgmt level %d", thermal_level); + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + WMA_LOGD("Current level %d is same as the set level, ignoring", + wma->thermal_mgmt_info.thermalCurrLevel); + return 0; + } + + wma->thermal_mgmt_info.thermalCurrLevel = thermal_level; + + /* Inform txrx */ + cdp_throttle_set_level(cds_get_context(QDF_MODULE_ID_SOC), + curr_pdev, + thermal_level); + + /* Send SME SET_THERMAL_LEVEL_IND message */ + wma_set_thermal_level_ind(thermal_level); + + /* 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; + + if (QDF_STATUS_SUCCESS != wma_set_thermal_mgmt(wma, thermal_params)) { + WMA_LOGE("Could not send thermal mgmt command to the firmware!"); + return -EINVAL; + } + + return 0; +} + +/** + * wma_ibss_peer_info_event_handler() - IBSS peer info event handler + * @handle: wma handle + * @data: event data + * @len: length of data + * + * This function handles IBSS peer info event from FW. + * + * Return: 0 for success or error code + */ +int wma_ibss_peer_info_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + struct scheduler_msg cds_msg = {0}; + wmi_peer_info *peer_info; + void *pdev; + tSirIbssPeerInfoParams *pSmeRsp; + uint32_t count, num_peers, status; + tSirIbssGetPeerInfoRspParams *pRsp; + WMI_PEER_INFO_EVENTID_param_tlvs *param_tlvs; + wmi_peer_info_event_fixed_param *fix_param; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: could not get pdev context", __func__); + return 0; + } + + param_tlvs = (WMI_PEER_INFO_EVENTID_param_tlvs *) data; + fix_param = param_tlvs->fixed_param; + peer_info = param_tlvs->peer_info; + num_peers = fix_param->num_peers; + status = 0; + + WMA_LOGE("%s: num_peers %d", __func__, num_peers); + + pRsp = qdf_mem_malloc(sizeof(tSirIbssGetPeerInfoRspParams)); + if (NULL == pRsp) { + WMA_LOGE("%s: could not allocate memory for ibss peer info rsp len %zu", + __func__, sizeof(tSirIbssGetPeerInfoRspParams)); + return 0; + } + + /*sanity check */ + if (!(num_peers) || (num_peers > 32) || + (num_peers > param_tlvs->num_peer_info) || + (!peer_info)) { + WMA_LOGE("%s: Invalid event data from target num_peers %d peer_info %pK", + __func__, num_peers, peer_info); + status = 1; + goto send_response; + } + + /* + *For displaying only connected IBSS peer info, iterate till + *last but one entry only as last entry is used for IBSS creator + */ + for (count = 0; count < num_peers-1; count++) { + pSmeRsp = &pRsp->ibssPeerInfoRspParams.peerInfoParams[count]; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_info->peer_mac_address, + peer_mac); + qdf_mem_copy(pSmeRsp->mac_addr, peer_mac, + sizeof(pSmeRsp->mac_addr)); + pSmeRsp->mcsIndex = 0; + pSmeRsp->rssi = peer_info->rssi + WMA_TGT_NOISE_FLOOR_DBM; + pSmeRsp->txRate = peer_info->data_rate; + pSmeRsp->txRateFlags = 0; + + WMA_LOGE("peer " MAC_ADDRESS_STR "rssi %d txRate %d", + MAC_ADDR_ARRAY(peer_mac), + pSmeRsp->rssi, pSmeRsp->txRate); + + peer_info++; + } + +send_response: + /* message header */ + pRsp->mesgType = eWNI_SME_IBSS_PEER_INFO_RSP; + pRsp->mesgLen = sizeof(tSirIbssGetPeerInfoRspParams); + pRsp->ibssPeerInfoRspParams.status = status; + pRsp->ibssPeerInfoRspParams.numPeers = num_peers; + + /* cds message wrapper */ + cds_msg.type = eWNI_SME_IBSS_PEER_INFO_RSP; + cds_msg.bodyptr = (void *)pRsp; + 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_LOGE("%s: could not post peer info rsp msg to SME", + __func__); + /* free the mem and return */ + qdf_mem_free((void *)pRsp); + } + + return 0; +} + +/** + * wma_fast_tx_fail_event_handler() -tx failure event handler + * @handle: wma handle + * @data: event data + * @len: data length + * + * Handle fast tx failure indication event from FW + * + * Return: 0 for success or error code. + */ +int wma_fast_tx_fail_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + uint8_t tx_fail_cnt; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *param_tlvs; + wmi_peer_tx_fail_cnt_thr_event_fixed_param *fix_param; + + param_tlvs = (WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *) data; + fix_param = param_tlvs->fixed_param; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fix_param->peer_mac_address, peer_mac); + WMA_LOGE("%s: received fast tx failure event for peer 0x:%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x seq No %d", + __func__, + peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], + peer_mac[4], peer_mac[5], fix_param->seq_no); + + tx_fail_cnt = fix_param->seq_no; + + /*call HDD callback */ + if (wma->hddTxFailCb != NULL) + wma->hddTxFailCb(peer_mac, tx_fail_cnt); + else + WMA_LOGE("%s: HDD callback is %pK", __func__, wma->hddTxFailCb); + + 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, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + ETHERNET_ADDR_LEN); + break; + } + + if (llc_hdr == NULL) { + 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 += IEEE80211_ADDR_LEN; + 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_LOGD(FL("rate_id: %d, mcs: %0x, nss: %0x, preamble: %0x"), + rid, tx_param->mcs_mask, tx_param->nss_mask, + tx_param->preamble_type); +} + +/** + * 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 + * @tx_frm_ota_comp_cb: OTA complition handler + * @tx_flag: tx flag + * @vdev_id: vdev id + * @tdlsFlag: tdls flag + * + * 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 tdlsFlag, + uint16_t channel_freq, enum rateid rid) +{ + 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; + struct cdp_vdev *txrx_vdev; + 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; +#ifdef WLAN_FEATURE_11W + uint8_t *pFrame = NULL; + void *pPacket = NULL; + uint16_t newFrmLen = 0; +#endif /* WLAN_FEATURE_11W */ + struct wma_txrx_node *iface; + tpAniSirGlobal pMac; + 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; + void *mac_addr; + bool is_5g = false; + uint8_t pdev_id; + + if (NULL == wma_handle) { + WMA_LOGE("wma_handle is NULL"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + iface = &wma_handle->interfaces[vdev_id]; + /* Get the vdev handle from vdev id */ + txrx_vdev = wma_handle->interfaces[vdev_id].handle; + + if (!txrx_vdev) { + WMA_LOGE("TxRx Vdev Handle is NULL"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + if (!soc) { + WMA_LOGE("%s:SOC context is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + cdp_hl_tdls_flag_reset(soc, txrx_vdev, false); + + if (frmType >= TXRX_FRM_MAX) { + WMA_LOGE("Invalid Frame Type Fail to send Frame"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("pMac Handle is NULL"); + 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_LOGE("No Support to send other frames except 802.11 Mgmt/Data"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } +#ifdef WLAN_FEATURE_11W + if ((iface && iface->rmfEnabled) && + (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 (!IEEE80211_IS_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 + */ + 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)) + return qdf_status; + + 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_LOGP("%s: Failed to allocate %d bytes for RMF status code (%x)", + __func__, 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 { + /* Allocate extra bytes for MMIE */ + newFrmLen = frmLen + IEEE80211_MMIE_LEN; + qdf_status = cds_packet_alloc((uint16_t) newFrmLen, + (void **)&pFrame, + (void **)&pPacket); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP("%s: Failed to allocate %d bytes for RMF status code (%x)", + __func__, 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 cds_attach_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)); + if (!cds_attach_mmie(iface->key.key, + iface->key.key_id[0].ipn, + WMA_IGTK_KEY_INDEX_4, + pFrame, + pFrame + newFrmLen, newFrmLen)) { + WMA_LOGP("%s: Failed to attach MMIE at the end of frame", + __func__); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + cds_packet_free((void *)tx_frame); + tx_frame = pPacket; + pData = pFrame; + frmLen = newFrmLen; + pFc = (tpSirMacFrameCtl) (qdf_nbuf_data(tx_frame)); + } + } +#endif /* WLAN_FEATURE_11W */ + 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; + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + 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(); + + if (pdev == NULL) { + WMA_LOGE("%s: pdev pointer is not available", __func__); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAULT; + } + + /* + * 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 5 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 + + 500) { + WMA_LOGE("%s: No Tx Ack for last data frame for more than 5 secs, allow Tx of current data frame", + __func__); + } else { + WMA_LOGE("%s: Already one Data pending for Ack, reject Tx of data frame", + __func__); + 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_LOGE("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, + txrx_vdev, tdlsFlag); + + ret = cdp_tx_non_std(soc, + txrx_vdev, + OL_TX_SPEC_NO_FREE, skb); + + cdp_hl_tdls_flag_reset(soc, + txrx_vdev, false); + + if (ret) { + WMA_LOGE("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, + txrx_vdev); + if (ctrl_pdev == NULL) { + WMA_LOGE("ol_pdev_handle is NULL\n"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + is_high_latency = cdp_cfg_is_high_latency(soc, ctrl_pdev); + + downld_comp_required = tx_frm_download_comp_cb && is_high_latency && + 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 Dowload 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_LOGP("%s: Event Reset failed tx comp event %x", + __func__, qdf_status); + 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)) && + (0 != wma_handle->interfaces[vdev_id].mhz)) + chanfreq = wma_handle->interfaces[vdev_id].mhz; + else + chanfreq = channel_freq; + WMA_LOGD("%s: Probe response frame on channel %d vdev:%d", + __func__, chanfreq, vdev_id); + if (wma_is_vdev_in_ap_mode(wma_handle, vdev_id) && !chanfreq) + WMA_LOGE("%s: AP oper chan is zero", __func__); + } else if (pFc->subType == SIR_MAC_MGMT_ACTION) { + chanfreq = channel_freq; + } else { + chanfreq = 0; + } + if (pMac->fEnableDebugLog & 0x1) { + if ((pFc->type == SIR_MAC_MGMT_FRAME) && + (pFc->subType != SIR_MAC_MGMT_PROBE_REQ) && + (pFc->subType != SIR_MAC_MGMT_PROBE_RSP)) { + WMA_LOGD("TX MGMT - Type %hu, SubType %hu seq_num[%d]", + pFc->type, pFc->subType, + ((mHdr->seqControl.seqNumHi << 4) | + mHdr->seqControl.seqNumLo)); + } + } + + if (wma_handle->interfaces[vdev_id].channel >= SIR_11A_CHANNEL_BEGIN) + is_5g = true; + + 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; + + /* + * 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_LOGD(FL("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_LOGE("%s: psoc ctx is NULL", __func__); + goto error; + } + + if (!wma_handle->pdev) { + WMA_LOGE("%s: pdev ctx is NULL", __func__); + goto error; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma_handle->pdev); + wh = (struct ieee80211_frame *)(qdf_nbuf_data(tx_frame)); + 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); + } + + status = wlan_mgmt_txrx_mgmt_frame_tx(peer, + (tpAniSirGlobal)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_LOGE("%s: mgmt tx failed", __func__); + 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 */ + u32 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_LOGE("%s: Failed to send Mgmt Frame", __func__); + else + WMA_LOGD("%s: Failed to send Mgmt Frame", __func__); + 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_LOGP("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; +} + +/** + * wma_ds_peek_rx_packet_info() - peek rx packet info + * @pkt: packet + * @pkt_meta: packet meta + * @bSwap: byte swap + * + * 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, + bool bSwap) +{ + /* Sanity Check */ + if (pkt == NULL) { + WMA_LOGE("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 (NULL == rx_aggr_hole_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + 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) { + WMA_LOGE("%s: Failed to post aggr event to SME", __func__); + 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 whihc 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); + tpSirSmeMicFailureInd mic_err_ind; + struct ether_header *eth_hdr; + struct scheduler_msg cds_msg = {0}; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return; + } + + if (err_type != OL_RX_ERR_TKIP_MIC) + return; + + if (qdf_nbuf_len(rx_frame) < sizeof(*eth_hdr)) + return; + eth_hdr = (struct ether_header *)qdf_nbuf_data(rx_frame); + mic_err_ind = qdf_mem_malloc(sizeof(*mic_err_ind)); + if (!mic_err_ind) { + WMA_LOGE("%s: Failed to allocate memory for MIC indication message", + __func__); + return; + } + + mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND; + mic_err_ind->length = sizeof(*mic_err_ind); + mic_err_ind->sessionId = vdev_id; + qdf_copy_macaddr(&mic_err_ind->bssId, + (struct qdf_mac_addr *) &wma->interfaces[vdev_id].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_LOGE("%s: could not post mic failure indication to SME", + __func__); + qdf_mem_free((void *)mic_err_ind); + } +} + +/** + * 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) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + tp_wma_handle wma; + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + struct wma_txrx_node *iface; + struct peer_flush_params param = {0}; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: %pK", + __func__, iface->handle); + return; + } + WMA_LOGD("%s: vdevid %d bssid %pM", __func__, vdev_id, iface->bssid); + wma_vdev_set_pause_bit(vdev_id, PAUSE_TYPE_HOST); + cdp_fc_vdev_pause(cds_get_context(QDF_MODULE_ID_SOC), + iface->handle, + OL_TXQ_PAUSE_REASON_TX_ABORT); + + /* 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, iface->bssid, + ¶m); +} + +/** + * wma_lro_config_cmd() - process the LRO config command + * @wma: Pointer to WMA handle + * @wma_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 + */ +QDF_STATUS wma_lro_config_cmd(void *handle, + struct cdp_lro_hash_config *wma_lro_cmd) +{ + struct wmi_lro_config_cmd_t wmi_lro_cmd = {0}; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma || NULL == wma_lro_cmd) { + WMA_LOGE("wma_lro_config_cmd': invalid input!"); + return QDF_STATUS_E_FAILURE; + } + + wmi_lro_cmd.lro_enable = wma_lro_cmd->lro_enable; + wmi_lro_cmd.tcp_flag = wma_lro_cmd->tcp_flag; + wmi_lro_cmd.tcp_flag_mask = wma_lro_cmd->tcp_flag_mask; + qdf_mem_copy(wmi_lro_cmd.toeplitz_hash_ipv4, + wma_lro_cmd->toeplitz_hash_ipv4, + LRO_IPV4_SEED_ARR_SZ * sizeof(uint32_t)); + qdf_mem_copy(wmi_lro_cmd.toeplitz_hash_ipv6, + wma_lro_cmd->toeplitz_hash_ipv6, + LRO_IPV6_SEED_ARR_SZ * sizeof(uint32_t)); + + return wmi_unified_lro_config_cmd(wma->wmi_handle, + &wmi_lro_cmd); +} + +/** + * wma_indicate_err() - indicate an error to the protocol stack + * @err_type: error type + * @err_info: information associated with the error + * + * This function indicates an error encountered in the data path + * to the protocol stack + * + * Return: none + */ +void +wma_indicate_err( + enum ol_rx_err_type err_type, + struct ol_error_info *err_info) +{ + switch (err_type) { + case OL_RX_ERR_TKIP_MIC: + { + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + tpSirSmeMicFailureInd mic_err_ind; + struct scheduler_msg cds_msg = {0}; + uint8_t vdev_id; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma context", + __func__); + return; + } + + mic_err_ind = qdf_mem_malloc(sizeof(*mic_err_ind)); + if (!mic_err_ind) { + WMA_LOGE("%s: MIC indication mem alloc failed", + __func__); + return; + } + + qdf_mem_zero((void *) mic_err_ind, sizeof(*mic_err_ind)); + mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND; + mic_err_ind->length = sizeof(*mic_err_ind); + vdev_id = err_info->u.mic_err.vdev_id; + qdf_copy_macaddr(&mic_err_ind->bssId, + (struct qdf_mac_addr *) &wma->interfaces[vdev_id].bssid); + WMA_LOGE("MIC error: BSSID:%02x:%02x:%02x:%02x:%02x:%02x\n", + mic_err_ind->bssId.bytes[0], + mic_err_ind->bssId.bytes[1], + mic_err_ind->bssId.bytes[2], + mic_err_ind->bssId.bytes[3], + mic_err_ind->bssId.bytes[4], + mic_err_ind->bssId.bytes[5]); + qdf_mem_copy(mic_err_ind->info.taMacAddr, + (struct qdf_mac_addr *) err_info->u.mic_err.ta, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.srcMacAddr, + (struct qdf_mac_addr *) err_info->u.mic_err.sa, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.dstMacAddr, + (struct qdf_mac_addr *) err_info->u.mic_err.da, + sizeof(tSirMacAddr)); + mic_err_ind->info.keyId = err_info->u.mic_err.key_id; + mic_err_ind->info.multicast = + IEEE80211_IS_MULTICAST(err_info->u.mic_err.da); + qdf_mem_copy(mic_err_ind->info.TSC, + (void *)&err_info-> + u.mic_err.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_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + &cds_msg)) { + WMA_LOGE("%s: mic failure ind post to SME failed", + __func__); + qdf_mem_free((void *)mic_err_ind); + } + break; + } + default: + { + WMA_LOGE("%s: unhandled ol error type %d", __func__, err_type); + break; + } + } +} + +void wma_rx_mic_error_ind(void *scn_handle, uint16_t vdev_id, void *wh) +{ + struct ieee80211_frame *w = (struct ieee80211_frame *)wh; + struct ol_error_info err_info; + + err_info.u.mic_err.vdev_id = vdev_id; + qdf_mem_copy(err_info.u.mic_err.da, w->i_addr1, OL_TXRX_MAC_ADDR_LEN); + qdf_mem_copy(err_info.u.mic_err.ta, w->i_addr2, OL_TXRX_MAC_ADDR_LEN); + + WMA_LOGD("MIC vdev_id %d\n", vdev_id); + WMA_LOGD("MIC DA: %02x:%02x:%02x:%02x:%02x:%02x\n", + err_info.u.mic_err.da[0], + err_info.u.mic_err.da[1], + err_info.u.mic_err.da[2], + err_info.u.mic_err.da[3], + err_info.u.mic_err.da[4], + err_info.u.mic_err.da[5]); + WMA_LOGD("MIC TA: %02x:%02x:%02x:%02x:%02x:%02x\n", + err_info.u.mic_err.ta[0], + err_info.u.mic_err.ta[1], + err_info.u.mic_err.ta[2], + err_info.u.mic_err.ta[3], + err_info.u.mic_err.ta[4], + err_info.u.mic_err.ta[5]); + + wma_indicate_err(OL_RX_ERR_TKIP_MIC, &err_info); +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c new file mode 100644 index 0000000000000000000000000000000000000000..33ea4e49bc307988bf3da57a271a885035352897 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c @@ -0,0 +1,6122 @@ +/* + * 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: 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 "cfg_api.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 "wma_internal.h" + +#include "wma_ocb.h" +#include "cdp_txrx_cfg.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#include +#include + +#include "wlan_policy_mgr_api.h" +#include "wma_nan_datapath.h" +#include "wlan_tgt_def_config.h" +#include +#include +#include "wlan_pmo_ucfg_api.h" +#include "wlan_reg_services_api.h" + +#include "wma_he.h" +#include "wlan_roam_debug.h" +#include "wlan_ocb_ucfg_api.h" +#include "init_deinit_lmac.h" +#include +#include "wlan_mlme_main.h" + +/** + * wma_find_vdev_by_addr() - find vdev_id from mac address + * @wma: wma handle + * @addr: mac address + * @vdev_id: return vdev_id + * + * Return: Returns vdev handle or NULL if mac address don't match + */ +struct cdp_vdev *wma_find_vdev_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id) +{ + uint8_t i; + + for (i = 0; i < wma->max_bssid; i++) { + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *) wma->interfaces[i].addr, + (struct qdf_mac_addr *) addr) == true) { + *vdev_id = i; + return wma->interfaces[i].handle; + } + } + return NULL; +} + + +/** + * 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_LOGE("%s: Invalid vdev_id %hu", __func__, 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; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_is_vdev_in_ibss_mode() - check that vdev is in ibss mode or not + * @wma: wma handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in IBSS mode or not. + * + * Return: True/False + */ +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %hu", __func__, vdev_id); + QDF_ASSERT(0); + return false; + } + + if (intf[vdev_id].type == WMI_VDEV_TYPE_IBSS) + return true; + + return false; +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_find_vdev_by_bssid() - Get the corresponding vdev_id from BSSID + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: fill vdev_id with appropriate vdev id and return vdev + * handle or NULL if not found. + */ +struct cdp_vdev *wma_find_vdev_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id) +{ + int i; + + for (i = 0; i < wma->max_bssid; i++) { + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *) wma->interfaces[i].bssid, + (struct qdf_mac_addr *) bssid) == true) { + *vdev_id = i; + return wma->interfaces[i].handle; + } + } + + return NULL; +} + +/** + * wma_get_txrx_vdev_type() - return operating mode of vdev + * @type: vdev_type + * + * Return: return operating mode as enum wlan_op_mode type + */ +static enum wlan_op_mode wma_get_txrx_vdev_type(uint32_t type) +{ + enum wlan_op_mode vdev_type = wlan_op_mode_unknown; + + switch (type) { + case WMI_VDEV_TYPE_AP: + vdev_type = wlan_op_mode_ap; + break; + case WMI_VDEV_TYPE_STA: + vdev_type = wlan_op_mode_sta; + break; +#ifdef QCA_IBSS_SUPPORT + case WMI_VDEV_TYPE_IBSS: + vdev_type = wlan_op_mode_ibss; + break; +#endif /* QCA_IBSS_SUPPORT */ + case WMI_VDEV_TYPE_OCB: + vdev_type = wlan_op_mode_ocb; + break; + case WMI_VDEV_TYPE_MONITOR: + vdev_type = wlan_op_mode_monitor; + break; + case WMI_VDEV_TYPE_NDI: + vdev_type = wlan_op_mode_ndi; + break; + default: + WMA_LOGE("Invalid vdev type %u", type); + vdev_type = wlan_op_mode_unknown; + } + + return vdev_type; +} + +/** + * wma_find_req() - find target request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @type: request type + * + * 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 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_LOGE(FL("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; + 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_LOGD(FL("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_LOGE(FL("target request not found for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + + WMA_LOGD(FL("target request found for vdev id: %d type %d"), + vdev_id, type); + + return req_msg; +} + +/** + * 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 + */ +static 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_LOGE(FL("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->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_LOGD(FL("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_LOGE(FL("target request not found for vdev_id %d type %d"), + vdev_id, msg_type); + return NULL; + } + + WMA_LOGD(FL("target request found for vdev id: %d type %d"), + vdev_id, msg_type); + + return req_msg; +} + + +/** + * wma_find_vdev_req() - find target request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @type: request type + * @remove_req_from_list: flag to indicate remove req or not. + * + * Return: return target request if found or NULL. + */ +static struct wma_target_req *wma_find_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type, + bool remove_req_from_list) +{ + 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->vdev_respq_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->vdev_resp_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGD(FL("unable to get target req from vdev resp queue vdev_id: %d type: %d"), + vdev_id, 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->type != type) + continue; + + found = true; + if (remove_req_from_list) { + status = qdf_list_remove_node(&wma->vdev_resp_queue, + node1); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGD(FL( + "Failed to target req for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + } + break; + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&wma->vdev_resp_queue, + node1, &node2)); + + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + if (!found) { + WMA_LOGD(FL("target request not found for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + WMA_LOGD(FL("target request found for vdev id: %d type %d msg %d"), + vdev_id, type, req_msg->msg_type); + return req_msg; +} + +/** + * wma_send_del_sta_self_resp() - send del sta self resp to Upper layer + * @param: params of del sta resp + * + * Return: none + */ +static inline void wma_send_del_sta_self_resp(struct del_sta_self_params *param) +{ + struct scheduler_msg sme_msg = {0}; + QDF_STATUS status; + + sme_msg.type = eWNI_SME_DEL_STA_SELF_RSP; + sme_msg.bodyptr = param; + + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_DEL_STA_SELF_RSP"); + qdf_mem_free(param); + } +} + +/** + * wma_vdev_detach_callback() - send vdev detach response to upper layer + * @ctx: txrx node ptr + * + * Return: none + */ +static void wma_vdev_detach_callback(void *ctx) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface = (struct wma_txrx_node *)ctx; + struct del_sta_self_params *param; + struct wma_target_req *req_msg; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma || !iface->del_staself_req) { + WMA_LOGE("%s: wma %pK iface %pK", __func__, wma, + iface->del_staself_req); + return; + } + param = (struct del_sta_self_params *) iface->del_staself_req; + iface->del_staself_req = NULL; + WMA_LOGD("%s: sending eWNI_SME_DEL_STA_SELF_RSP for vdev %d", + __func__, param->session_id); + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + req_msg = wma_find_vdev_req(wma, param->session_id, + WMA_TARGET_REQ_TYPE_VDEV_DEL, + true); + if (req_msg) { + WMA_LOGD("%s: Found vdev request for vdev id %d", + __func__, param->session_id); + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + } + } + + 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); + + param->status = QDF_STATUS_SUCCESS; + wma_send_del_sta_self_resp(param); +} + + +/** + * wma_self_peer_remove() - Self peer remove handler + * @wma: wma handle + * @del_sta_self_req_param: vdev id + * @generate_vdev_rsp: request type + * + * 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_sta_self_params *del_sta_self_req_param, + uint8_t generate_vdev_rsp) +{ + void *peer; + struct cdp_pdev *pdev; + QDF_STATUS qdf_status; + uint8_t peer_id; + uint8_t vdev_id = del_sta_self_req_param->session_id; + struct wma_target_req *msg = NULL; + struct del_sta_self_rsp_params *sta_self_wmi_rsp; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGD("P2P Device: removing self peer %pM", + del_sta_self_req_param->self_mac_addr); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + qdf_status = QDF_STATUS_E_FAULT; + goto error; + } + + peer = cdp_peer_find_by_addr(soc, pdev, + del_sta_self_req_param->self_mac_addr, + &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + del_sta_self_req_param->self_mac_addr); + qdf_status = QDF_STATUS_E_FAULT; + goto error; + } + + qdf_status = wma_remove_peer(wma_handle, + del_sta_self_req_param->self_mac_addr, + vdev_id, peer, false); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE(FL("wma_remove_peer is failed")); + goto error; + } + + 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 == NULL) { + WMA_LOGE(FL("Failed to allocate memory")); + qdf_status = QDF_STATUS_E_NOMEM; + goto error; + } + sta_self_wmi_rsp->self_sta_param = del_sta_self_req_param; + sta_self_wmi_rsp->generate_rsp = generate_vdev_rsp; + 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_LOGE(FL("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; + } + } + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +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]; + + cdp_vdev_detach(soc, + iface->handle, NULL, NULL); + iface->handle = NULL; +} + +/** + * wma_handle_monitor_mode_vdev_detach() - Stop and down monitor mode vdev + * @wma_handle: 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) +{ + if (wma_send_vdev_stop_to_fw(wma, vdev_id)) { + WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__); + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + } + + if (wma_send_vdev_down_to_fw(wma, vdev_id) != QDF_STATUS_SUCCESS) + WMA_LOGE("Failed to send vdev down cmd: vdev %d", vdev_id); +} + +static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *del_sta_self_req_param, + uint8_t generate_rsp) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = del_sta_self_req_param->session_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + struct wma_target_req *msg = NULL; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + WMA_LOGE("%s:SOC context is NULL", __func__); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + wma_handle_monitor_mode_vdev_detach(wma_handle, vdev_id); + + status = wmi_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Unable to remove an interface"); + goto out; + } + + WMA_LOGD("vdev_id:%hu vdev_hdl:%pK", vdev_id, iface->handle); + if (!generate_rsp) { + WMA_LOGE("Call txrx detach w/o callback for vdev %d", vdev_id); + goto out; + } + + iface->del_staself_req = del_sta_self_req_param; + msg = wma_fill_vdev_req(wma_handle, vdev_id, WMA_DEL_STA_SELF_REQ, + WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 6000); + if (!msg) { + WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d", + __func__, vdev_id); + status = QDF_STATUS_E_NOMEM; + iface->del_staself_req = NULL; + goto out; + } + + /* Acquire wake lock only when you expect a response from firmware */ + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sync_delete_cmds)) { + wma_acquire_wakelock(&wma_handle->wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION); + } + WMA_LOGD("Call txrx detach with callback for vdev %d", vdev_id); + wma_cdp_vdev_detach(soc, wma_handle, vdev_id); + + /* + * send the response immediately if WMI_SERVICE_SYNC_DELETE_CMDS + * service is not supported by firmware + */ + if (!wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sync_delete_cmds)) + wma_vdev_detach_callback(iface); + return status; +out: + WMA_LOGE("Call txrx detach callback for vdev %d, generate_rsp %u", + vdev_id, generate_rsp); + wma_cdp_vdev_detach(soc, wma_handle, vdev_id); + + wma_vdev_deinit(iface); + qdf_mem_zero(iface, sizeof(*iface)); + wma_vdev_init(iface); + + del_sta_self_req_param->status = status; + if (generate_rsp) + wma_send_del_sta_self_resp(del_sta_self_req_param); + return status; +} + +void wma_force_objmgr_vdev_peer_cleanup(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer = NULL; + struct wlan_objmgr_peer *peer_next = NULL; + qdf_list_t *peer_list; + + WMA_LOGE("%s: SSR: force cleanup peers in vdev(%d)", + __func__, vdev_id); + iface->vdev_active = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + + if (!vdev) { + WMA_LOGE("Failed to get Objmgr Vdev"); + return; + } + + qdf_spin_lock_bh(&iface->peer_lock); + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + WMA_LOGE("%s: peer_list is NULL", __func__); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + qdf_spin_unlock_bh(&iface->peer_lock); + return; + } + + /* + * We get refcount for each peer first, logically delete it and + * then release the refcount so that the peer is physically + * deleted. + */ + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_LEGACY_WMA_ID); + while (peer) { + WMA_LOGD("%s: Deleting Peer %pM", + __func__, peer->macaddr); + wlan_objmgr_peer_obj_delete(peer); + peer_next = wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, peer, WLAN_LEGACY_WMA_ID); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + peer = peer_next; + } + qdf_spin_unlock_bh(&iface->peer_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + + /* Force delete all the peers, set the wma interface peer_count to 0 */ + iface->peer_count = 0; +} + +static bool wma_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; + } +} + +/** + * wma_remove_objmgr_peer() - remove objmgr peer information from host driver + * @wma: wma handle + * @vdev_id: vdev id + * @peer_addr: peer mac address + * + * Return: none + */ +static void wma_remove_objmgr_peer(tp_wma_handle wma, uint8_t vdev_id, + uint8_t *peer_addr) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *obj_peer; + struct wlan_objmgr_vdev *obj_vdev; + struct wlan_objmgr_pdev *obj_pdev; + uint8_t pdev_id = 0; + + psoc = wma->psoc; + if (!psoc) { + WMA_LOGE("%s:PSOC is NULL", __func__); + return; + } + + obj_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (!obj_vdev) { + WMA_LOGE("Obj vdev not found. Unable to remove peer"); + 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); + WMA_LOGD("Peer %pM deleted", peer_addr); + } else { + WMA_LOGE("Peer %pM not found", peer_addr); + } + + wlan_objmgr_vdev_release_ref(obj_vdev, WLAN_LEGACY_WMA_ID); +} + +/** + * wma_vdev_detach() - send vdev delete command to fw + * @wma_handle: wma handle + * @pdel_sta_self_req_param: del sta params + * @generateRsp: generate Response flag + * + * Return: QDF status + */ +QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *pdel_sta_self_req_param, + uint8_t generateRsp) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t vdev_id = pdel_sta_self_req_param->session_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + struct wma_target_req *req_msg; + + if (!iface->handle) { + WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed", + vdev_id); + goto send_rsp; + } + + /* + * In SSR case or if FW is down we only need to clean up the host. + * There is no need to destroy vdev in firmware since it + * has already asserted. + * Cleanup the ObjMgr Peers for the current vdev and detach the + * CDP Vdev. + */ + if (!cds_is_target_ready()) { + wma_force_objmgr_vdev_peer_cleanup(wma_handle, vdev_id); + wma_cdp_vdev_detach(soc, wma_handle, vdev_id); + goto send_rsp; + } + + if (qdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) { + req_msg = wma_find_vdev_req(wma_handle, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP, false); + if (!req_msg) + goto send_fail_rsp; + if (req_msg->msg_type != WMA_DELETE_BSS_REQ) + goto send_fail_rsp; + WMA_LOGA("BSS is not yet stopped. Defering vdev(vdev id %x) deletion", + vdev_id); + iface->del_staself_req = pdel_sta_self_req_param; + iface->is_del_sta_defered = true; + return status; + } + iface->is_del_sta_defered = false; + + if (wma_vdev_uses_self_peer(iface->type, iface->sub_type)) { + status = wma_self_peer_remove(wma_handle, + pdel_sta_self_req_param, generateRsp); + if ((status != QDF_STATUS_SUCCESS) && generateRsp) { + WMA_LOGE("can't remove selfpeer, send rsp session: %d", + vdev_id); + status = wma_handle_vdev_detach(wma_handle, + pdel_sta_self_req_param, + generateRsp); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Trigger recovery for vdev %d", + vdev_id); + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); + } + return status; + } else if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("can't remove selfpeer, free msg session: %d", + vdev_id); + qdf_mem_free(pdel_sta_self_req_param); + pdel_sta_self_req_param = NULL; + return status; + } + if (!wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sync_delete_cmds)) + status = wma_handle_vdev_detach(wma_handle, + pdel_sta_self_req_param, generateRsp); + } else { + if (iface->type == WMI_VDEV_TYPE_STA) { + wma_remove_objmgr_peer(wma_handle, vdev_id, + pdel_sta_self_req_param->self_mac_addr); + } + status = wma_handle_vdev_detach(wma_handle, + pdel_sta_self_req_param, generateRsp); + } + + if (QDF_IS_STATUS_SUCCESS(status)) + iface->vdev_active = false; + return status; + +send_fail_rsp: + WMA_LOGE("rcvd del_self_sta without del_bss; vdev_id:%d", vdev_id); + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); + status = QDF_STATUS_E_FAILURE; + +send_rsp: + if (generateRsp) { + pdel_sta_self_req_param->status = status; + wma_send_del_sta_self_resp(pdel_sta_self_req_param); + } else { + qdf_mem_free(pdel_sta_self_req_param); + pdel_sta_self_req_param = NULL; + } + return status; +} + +/** + * wma_vdev_start_rsp() - send vdev start response to upper layer + * @wma: wma handle + * @add_bss: add bss params + * @resp_event: response params + * + * Return: none + */ +static void wma_vdev_start_rsp(tp_wma_handle wma, + tpAddBssParams add_bss, + wmi_vdev_start_response_event_fixed_param * + resp_event) +{ + struct beacon_info *bcn; + +#ifdef QCA_IBSS_SUPPORT + WMA_LOGD("%s: vdev start response received for %s mode", __func__, + add_bss->operMode == + BSS_OPERATIONAL_MODE_IBSS ? "IBSS" : "non-IBSS"); +#endif /* QCA_IBSS_SUPPORT */ + + if (resp_event->status) { + add_bss->status = QDF_STATUS_E_FAILURE; + goto send_fail_resp; + } + + if ((add_bss->operMode == BSS_OPERATIONAL_MODE_AP) +#ifdef QCA_IBSS_SUPPORT + || (add_bss->operMode == BSS_OPERATIONAL_MODE_IBSS) +#endif /* QCA_IBSS_SUPPORT */ + ) { + wma->interfaces[resp_event->vdev_id].beacon = + qdf_mem_malloc(sizeof(struct beacon_info)); + + bcn = wma->interfaces[resp_event->vdev_id].beacon; + if (!bcn) { + WMA_LOGE("%s: Failed alloc memory for beacon struct", + __func__); + add_bss->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) { + WMA_LOGE("%s: No memory allocated for beacon buffer", + __func__); + qdf_mem_free(bcn); + add_bss->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[resp_event->vdev_id].bss_status, + WMA_BSS_STATUS_STARTED); + WMA_LOGD("%s: AP mode (type %d subtype %d) BSS is started", + __func__, wma->interfaces[resp_event->vdev_id].type, + wma->interfaces[resp_event->vdev_id].sub_type); + + WMA_LOGD("%s: Allocated beacon struct %pK, template memory %pK", + __func__, bcn, bcn->buf); + } + add_bss->status = QDF_STATUS_SUCCESS; + add_bss->bssIdx = resp_event->vdev_id; + add_bss->chainMask = resp_event->chain_mask; + if ((2 != resp_event->cfgd_rx_streams) || + (2 != resp_event->cfgd_tx_streams)) { + add_bss->nss = 1; + } + add_bss->smpsMode = host_map_smps_mode(resp_event->smps_mode); +send_fail_resp: + /* Send vdev stop if vdev start was success */ + if (QDF_IS_STATUS_ERROR(add_bss->status)) { + if (!resp_event->status) + if (wma_send_vdev_stop_to_fw(wma, resp_event->vdev_id)) + WMA_LOGE(FL("Failed to send vdev stop")); + + wma_remove_peer_on_add_bss_failure(add_bss); + } + + WMA_LOGD("%s: Sending add bss rsp to umac(vdev %d status %d)", + __func__, resp_event->vdev_id, add_bss->status); + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +#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].mhz != prev_ch_freq) { + num_ch++; + prev_ch_freq = wma->interfaces[i].mhz; + } + } + } + + 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_vdev_start_resp_handler() - vdev start response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_start_resp_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_START_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_start_response_event_fixed_param *resp_event; + struct wma_target_req *req_msg; + struct wma_txrx_node *iface; + struct vdev_up_params param = {0}; + QDF_STATUS status; + int err; + wmi_host_channel_width chanwidth; + target_resource_config *wlan_res_cfg; + struct wlan_objmgr_psoc *psoc = wma->psoc; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); +#endif + + if (!psoc) { + WMA_LOGE("%s: psoc is NULL", __func__); + return -EINVAL; + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + policy_mgr_set_do_hw_mode_change_flag( + psoc, false); + return -EINVAL; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + WMA_LOGD("%s: Enter", __func__); + + wlan_res_cfg = lmac_get_tgt_res_cfg(psoc); + if (!wlan_res_cfg) { + WMA_LOGE("%s: Wlan resource config is NULL", __func__); + return -EINVAL; + } + + param_buf = (WMI_VDEV_START_RESP_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid start response event buffer"); + policy_mgr_set_do_hw_mode_change_flag( + wma->psoc, false); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + if (!resp_event) { + WMA_LOGE("Invalid start response event buffer"); + policy_mgr_set_do_hw_mode_change_flag( + wma->psoc, false); + return -EINVAL; + } + + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id received from firmware"); + return -EINVAL; + } + + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) + tgt_dfs_radar_enable(wma->pdev, 0, 0); + + if (resp_event->status == QDF_STATUS_SUCCESS) { + wma->interfaces[resp_event->vdev_id].tx_streams = + resp_event->cfgd_tx_streams; + wma->interfaces[resp_event->vdev_id].rx_streams = + resp_event->cfgd_rx_streams; + wma->interfaces[resp_event->vdev_id].chain_mask = + resp_event->chain_mask; + if (wlan_res_cfg->use_pdev_id) { + if (resp_event->pdev_id == WMI_PDEV_ID_SOC) { + WMA_LOGE("%s: soc level id received for mac id", + __func__); + return -EINVAL; + } + wma->interfaces[resp_event->vdev_id].mac_id = + WMA_PDEV_TO_MAC_MAP(resp_event->pdev_id); + } else { + wma->interfaces[resp_event->vdev_id].mac_id = + resp_event->mac_id; + } + + WMA_LOGD("%s: vdev:%d tx ss=%d rx ss=%d chain mask=%d mac=%d", + __func__, + resp_event->vdev_id, + wma->interfaces[resp_event->vdev_id].tx_streams, + wma->interfaces[resp_event->vdev_id].rx_streams, + wma->interfaces[resp_event->vdev_id].chain_mask, + wma->interfaces[resp_event->vdev_id].mac_id); + } + + iface = &wma->interfaces[resp_event->vdev_id]; + + req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START, + true); + + if (!req_msg) { + WMA_LOGE("%s: Failed to lookup request message for vdev %d", + __func__, resp_event->vdev_id); + policy_mgr_set_do_hw_mode_change_flag(wma->psoc, false); + return -EINVAL; + } + qdf_mc_timer_stop(&req_msg->event_timeout); + + if ((qdf_atomic_read( + &wma->interfaces[resp_event->vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress)) && + wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) && + (req_msg->msg_type == WMA_HIDDEN_SSID_VDEV_RESTART)) { + tpHalHiddenSsidVdevRestart hidden_ssid_restart = + (tpHalHiddenSsidVdevRestart)req_msg->user_data; + WMA_LOGE("%s: vdev restart event recevied for hidden ssid set using IOCTL", + __func__); + qdf_atomic_set(&wma->interfaces[resp_event->vdev_id]. + vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + + wma_send_msg(wma, WMA_HIDDEN_SSID_RESTART_RSP, + (void *)hidden_ssid_restart, 0); + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (resp_event->status == QDF_STATUS_SUCCESS + && mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, resp_event->vdev_id, true); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + if (req_msg->msg_type == WMA_CHNL_SWITCH_REQ) { + tpSwitchChannelParams params = + (tpSwitchChannelParams) req_msg->user_data; + + if (!params) { + WMA_LOGE("%s: channel switch params is NULL for vdev %d", + __func__, resp_event->vdev_id); + policy_mgr_set_do_hw_mode_change_flag(wma->psoc, false); + return -EINVAL; + } + + WMA_LOGD("%s: Send channel switch resp vdev %d status %d", + __func__, resp_event->vdev_id, resp_event->status); + params->chainMask = resp_event->chain_mask; + if ((2 != resp_event->cfgd_rx_streams) || + (2 != resp_event->cfgd_tx_streams)) { + params->nss = 1; + } + params->smpsMode = host_map_smps_mode(resp_event->smps_mode); + params->status = resp_event->status; + if (wma->interfaces[resp_event->vdev_id].is_channel_switch) { + wma->interfaces[resp_event->vdev_id].is_channel_switch = + false; + } + + if ((QDF_IS_STATUS_SUCCESS(resp_event->status) && + (resp_event->resp_type == WMI_VDEV_RESTART_RESP_EVENT) && + ((iface->type == WMI_VDEV_TYPE_STA) || + (iface->type == WMI_VDEV_TYPE_MONITOR))) || + ((resp_event->resp_type == WMI_VDEV_START_RESP_EVENT) && + (iface->type == WMI_VDEV_TYPE_MONITOR))) { + /* for CSA case firmware expects phymode before ch_wd */ + err = wma_set_peer_param(wma, iface->bssid, + WMI_PEER_PHYMODE, iface->chanmode, + resp_event->vdev_id); + WMA_LOGD("%s:vdev_id %d chanmode %d status %d", + __func__, resp_event->vdev_id, + iface->chanmode, err); + + chanwidth = + wmi_get_ch_width_from_phy_mode(wma->wmi_handle, + iface->chanmode); + err = wma_set_peer_param(wma, iface->bssid, + WMI_PEER_CHWIDTH, chanwidth, + resp_event->vdev_id); + WMA_LOGD("%s:vdev_id %d chanwidth %d status %d", + __func__, resp_event->vdev_id, + chanwidth, err); + + param.vdev_id = resp_event->vdev_id; + param.assoc_id = iface->aid; + status = wma_send_vdev_up_to_fw(wma, ¶m, + iface->bssid); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s:vdev_up failed vdev_id %d", + __func__, resp_event->vdev_id); + wma_vdev_set_mlme_state(wma, + resp_event->vdev_id, WLAN_VDEV_S_STOP); + policy_mgr_set_do_hw_mode_change_flag( + wma->psoc, false); + } else { + wma_vdev_set_mlme_state(wma, + resp_event->vdev_id, WLAN_VDEV_S_RUN); + if (iface->beacon_filter_enabled) + wma_add_beacon_filter(wma, + &iface->beacon_filter); + } + } + + wma_send_msg_high_priority(wma, WMA_SWITCH_CHANNEL_RSP, + (void *)params, 0); + } else if (req_msg->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams bssParams = (tpAddBssParams) req_msg->user_data; + + qdf_mem_copy(iface->bssid, bssParams->bssId, + IEEE80211_ADDR_LEN); + wma_vdev_start_rsp(wma, bssParams, resp_event); + } else if (req_msg->msg_type == WMA_OCB_SET_CONFIG_CMD) { + param.vdev_id = resp_event->vdev_id; + param.assoc_id = iface->aid; + if (wma_send_vdev_up_to_fw(wma, ¶m, iface->bssid) != + QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("failed to send vdev up")); + policy_mgr_set_do_hw_mode_change_flag( + wma->psoc, false); + return -EEXIST; + } + wma_vdev_set_mlme_state(wma, resp_event->vdev_id, + WLAN_VDEV_S_RUN); + ucfg_ocb_config_channel(wma->pdev); + } + + if ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) && + wma_is_vdev_up(resp_event->vdev_id)) + wma_set_sap_keepalive(wma, resp_event->vdev_id); + + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + + return 0; +} + +bool wma_is_vdev_valid(uint32_t vdev_id) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGD("%s: vdev_id: %d, null wma_handle", __func__, vdev_id); + return false; + } + + /* No of interface are allocated based on max_bssid value */ + if (vdev_id >= wma_handle->max_bssid) { + WMA_LOGD("%s: vdev_id: %d is invalid, max_bssid: %d", + __func__, vdev_id, wma_handle->max_bssid); + return false; + } + + WMA_LOGD("%s: vdev_id: %d, vdev_active: %d", __func__, vdev_id, + wma_handle->interfaces[vdev_id].vdev_active); + + 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_LOGE(FL("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.if_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_authorized_cb() - set peer authorized callback function + * @wma_ctx: wma handle + * @auth_cb: peer authorized callback + * + * Return: none + */ +void wma_set_peer_authorized_cb(void *wma_ctx, wma_peer_authorized_fp auth_cb) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx; + + wma_handle->peer_authorized_cb = auth_cb; +} + +/** + * 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}; + int err; + + param.vdev_id = vdev_id; + param.param_value = param_value; + param.param_id = param_id; + + err = wmi_set_peer_param_send(wma_handle->wmi_handle, peer_addr, + ¶m); + + return err; +} + +/** + * wma_peer_unmap_conf_send - send peer unmap conf cmnd to fw + * @wma_ctx: 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_LOGE("%s: null input params", __func__); + 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_LOGE("%s: peer_unmap_conf_send failed %d", + __func__, 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) { + WMA_LOGE("%s: peer_id_cnt: %d, null wma_handle", + __func__, peer_id_cnt); + return QDF_STATUS_E_INVAL; + } + + 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_LOGD("%s: post unmap_conf cmd to MC thread", __func__); + + if (!mac_ctx) { + WMA_LOGE("%s: mac_ctx is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + peer_unmap_conf_req = qdf_mem_malloc(sizeof( + struct send_peer_unmap_conf_params)); + + if (!peer_unmap_conf_req) { + WMA_LOGE("%s: peer_unmap_conf_req memory alloc failed", + __func__); + 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) { + WMA_LOGE("%s: peer_id_list memory alloc failed", + __func__); + 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_LOGE("%s: wma_post_ctrl_msg failed", __func__); + 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; +} + +/** + * wma_remove_peer() - remove peer information from host driver and fw + * @wma: wma handle + * @bssid: mac address + * @vdev_id: vdev id + * @peer: peer ptr + * @roam_synch_in_progress: roam in progress flag + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_remove_peer(tp_wma_handle wma, uint8_t *bssid, + uint8_t vdev_id, void *peer, + bool roam_synch_in_progress) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + uint8_t *peer_addr = bssid; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE] = {0}; + struct peer_flush_params param = {0}; + uint8_t *peer_mac_addr; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + void *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + void *vdev; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + uint32_t bitmap = 1 << CDP_PEER_DELETE_NO_SPECIAL; + bool peer_unmap_conf_support_enabled; + + if (!wma->interfaces[vdev_id].peer_count) { + WMA_LOGE("%s: Can't remove peer with peer_addr %pM vdevid %d peer_count %d", + __func__, bssid, vdev_id, + wma->interfaces[vdev_id].peer_count); + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); + return QDF_STATUS_E_INVAL; + } + + if (!soc) { + WMA_LOGE("%s:SOC context is NULL", __func__); + QDF_BUG(0); + return QDF_STATUS_E_INVAL; + } + + if (!peer) { + WMA_LOGE("%s: PEER is NULL for vdev_id: %d", __func__, vdev_id); + return QDF_STATUS_E_INVAL; + } + peer_unmap_conf_support_enabled = + cdp_cfg_get_peer_unmap_conf_support(soc); + + peer_mac_addr = cdp_peer_get_peer_mac_addr(soc, peer); + if (peer_mac_addr == NULL) { + WMA_LOGE("%s: peer mac addr is NULL, Can't remove peer with peer_addr %pM vdevid %d peer_count %d", + __func__, bssid, vdev_id, + wma->interfaces[vdev_id].peer_count); + QDF_BUG(0); + return QDF_STATUS_E_INVAL; + } + + if (roam_synch_in_progress) + 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; + wmi_unified_peer_flush_tids_send(wma->wmi_handle, bssid, + ¶m); + + if (wma_is_vdev_in_ibss_mode(wma, vdev_id)) { + WMA_LOGD("%s: bssid %pM peer->mac_addr %pM", __func__, + bssid, peer_mac_addr); + peer_addr = peer_mac_addr; + } + + /* peer->ref_cnt is not visible in WMA */ + wlan_roam_debug_log(vdev_id, DEBUG_PEER_DELETE_SEND, + DEBUG_INVALID_PEER_ID, peer_addr, peer, + 0, 0); + qdf_status = wmi_unified_peer_delete_send(wma->wmi_handle, peer_addr, + vdev_id); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("%s Peer delete could not be sent to firmware %d", + __func__, 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: + vdev = cdp_get_vdev_from_vdev_id(soc, pdev, vdev_id); + WMA_LOGD("%s: vdev %pK is detaching %pK with peer_addr %pM vdevid %d peer_count %d", + __func__, vdev, peer, peer_mac_addr, vdev_id, + wma->interfaces[vdev_id].peer_count); + /* Copy peer mac to find and delete objmgr peer */ + qdf_mem_copy(peer_mac, peer_mac_addr, QDF_MAC_ADDR_SIZE); + if (roam_synch_in_progress) { + if (!peer_unmap_conf_support_enabled) + cdp_peer_detach_force_delete(soc, peer); + else + cdp_peer_delete_sync(soc, peer, + wma_peer_unmap_conf_cb, + bitmap); + } else { + if (peer_unmap_conf_support_enabled) + cdp_peer_delete_sync(soc, peer, + wma_peer_unmap_conf_cb, + bitmap); + else + cdp_peer_delete(soc, peer, bitmap); + } + + wma_remove_objmgr_peer(wma, vdev_id, peer_mac); + + wma->interfaces[vdev_id].peer_count--; +#undef PEER_ALL_TID_BITMASK + + return qdf_status; +} + +/** + * wma_find_duplicate_peer_on_other_vdev() - Find if same peer exist + * on other vdevs + * @wma: wma handle + * @pdev: txrx pdev ptr + * @vdev_id: vdev id of vdev on which the peer + * needs to be added + * @peer_mac: peer mac addr which needs to be added + * + * Check if peer with same MAC is present on vdev other then + * the provided vdev_id + * + * Return: true if same peer is present on vdev other then vdev_id + * else return false + */ +static bool wma_find_duplicate_peer_on_other_vdev(tp_wma_handle wma, + struct cdp_pdev *pdev, uint8_t vdev_id, uint8_t *peer_mac) +{ + int i; + uint8_t peer_id; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + for (i = 0; i < wma->max_bssid; i++) { + /* Need to check vdevs other than the vdev_id */ + if (vdev_id == i || + !wma->interfaces[i].handle) + continue; + if (cdp_peer_find_by_addr_and_vdev(soc, pdev, + wma->interfaces[i].handle, peer_mac, &peer_id)) { + WMA_LOGE("%s :Duplicate peer %pM (peer id %d) already exist on vdev %d", + __func__, peer_mac, peer_id, i); + return true; + } + } + return false; +} + +/** + * wma_get_peer_type() - Determine the type of peer(eg. STA/AP) and return it + * @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; + + WMA_LOGD("vdev id %d vdev type %d vdev subtype %d peer addr %pM vdev addr %pM", + vdev_id, wma->interfaces[vdev_id].type, + wma->interfaces[vdev_id].sub_type, peer_addr, + wma->interfaces[vdev_id].addr); + + if (wma_peer_type == WMI_PEER_TYPE_TDLS) + return WLAN_PEER_TDLS; + + if (!qdf_mem_cmp(wma->interfaces[vdev_id].addr, peer_addr, + IEEE80211_ADDR_LEN)) { + 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) { + if (wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) + obj_peer_type = WLAN_PEER_P2P_CLI; + else + 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_LOGE("Couldnt find peertype for type %d and sub type %d", + wma->interfaces[vdev_id].type, + wma->interfaces[vdev_id].sub_type); + } + + return obj_peer_type; + +} + +/** + * 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 + * + * Return: objmgr peer pointer + */ + +static 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) +{ + uint32_t obj_peer_type = 0; + struct wlan_objmgr_peer *obj_peer = NULL; + struct wlan_objmgr_vdev *obj_vdev = NULL; + struct wlan_objmgr_psoc *psoc = wma->psoc; + + obj_peer_type = wma_get_obj_mgr_peer_type(wma, vdev_id, peer_addr, + wma_peer_type); + if (!obj_peer_type) { + WMA_LOGE("Invalid obj peer type. Unable to create peer %d", + obj_peer_type); + return NULL; + } + + /* Create obj_mgr peer */ + obj_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + + if (!obj_vdev) { + WMA_LOGE("Invalid obj vdev. Unable to create peer %d", + obj_peer_type); + return NULL; + } + + obj_peer = wlan_objmgr_peer_obj_create(obj_vdev, obj_peer_type, + peer_addr); + wlan_objmgr_vdev_release_ref(obj_vdev, WLAN_LEGACY_WMA_ID); + if (obj_peer) + WMA_LOGD("Peer %pM added successfully! Type: %d", peer_addr, + obj_peer_type); + + return obj_peer; + +} +/** + * wma_create_peer() - send peer create command to fw + * @wma: wma handle + * @pdev: txrx pdev ptr + * @vdev: txrx vdev ptr + * @peer_addr: peer mac addr + * @peer_type: peer type + * @vdev_id: vdev id + * @roam_synch_in_progress: roam in progress + * + * Return: QDF status + */ +QDF_STATUS wma_create_peer(tp_wma_handle wma, struct cdp_pdev *pdev, + struct cdp_vdev *vdev, + u8 peer_addr[IEEE80211_ADDR_LEN], + uint32_t peer_type, uint8_t vdev_id, + bool roam_synch_in_progress) +{ + void *peer = NULL; + struct peer_create_params param = {0}; + uint8_t *mac_addr_raw; + 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; + + if (!psoc) { + WMA_LOGE("%s: psoc is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + wlan_res_cfg = lmac_get_tgt_res_cfg(psoc); + if (!wlan_res_cfg) { + WMA_LOGE("%s: psoc target res cfg is null", __func__); + return QDF_STATUS_E_INVAL; + } + + if (++wma->interfaces[vdev_id].peer_count > + wlan_res_cfg->num_peers) { + WMA_LOGE("%s, the peer count exceeds the limit %d", __func__, + wma->interfaces[vdev_id].peer_count - 1); + goto err; + } + + if (!dp_soc) { + WMA_LOGE("%s:DP SOC context is NULL", __func__); + goto err; + } + + if (qdf_is_macaddr_group((struct qdf_mac_addr *)peer_addr) || + qdf_is_macaddr_zero((struct qdf_mac_addr *)peer_addr)) { + WMA_LOGE("Invalid peer address received reject it"); + goto err; + } + + /* + * Check if peer with same MAC exist on other Vdev, If so avoid + * adding this peer, as it will cause FW to crash. + */ + if (wma_find_duplicate_peer_on_other_vdev(wma, pdev, + vdev_id, peer_addr)) + goto err; + + obj_peer = wma_create_objmgr_peer(wma, vdev_id, peer_addr, peer_type); + if (!obj_peer) + goto err; + + /* 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 + */ + peer = cdp_peer_create(dp_soc, vdev, peer_addr); + if (!peer) { + WMA_LOGE("%s : Unable to attach peer %pM", __func__, peer_addr); + wlan_objmgr_peer_obj_delete(obj_peer); + goto err; + } + WMA_LOGD("%s: vdev %pK is attaching peer:%pK peer_addr %pM to vdev_id %d, peer_count - %d", + __func__, vdev, peer, peer_addr, vdev_id, + wma->interfaces[vdev_id].peer_count); + + if (roam_synch_in_progress) { + WMA_LOGD("%s: LFR3: Created peer %pK with peer_addr %pM vdev_id %d, peer_count - %d", + __func__, peer, peer_addr, vdev_id, + wma->interfaces[vdev_id].peer_count); + 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_LOGE("%s : Unable to create peer in Target", __func__); + if (cdp_cfg_get_peer_unmap_conf_support(dp_soc)) + cdp_peer_delete_sync( + dp_soc, peer, + wma_peer_unmap_conf_cb, + 1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER); + else + cdp_peer_delete( + dp_soc, peer, + 1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER); + wlan_objmgr_peer_obj_delete(obj_peer); + goto err; + } + + WMA_LOGD("%s: Created peer %pK with peer_addr %pM vdev_id %d, peer_count - %d", + __func__, peer, peer_addr, vdev_id, + wma->interfaces[vdev_id].peer_count); + + wlan_roam_debug_log(vdev_id, DEBUG_PEER_CREATE_SEND, + DEBUG_INVALID_PEER_ID, peer_addr, peer, 0, 0); + cdp_peer_setup(dp_soc, vdev, peer); + + WMA_LOGD("%s: Initialized peer with peer_addr %pM vdev_id %d", + __func__, peer_addr, vdev_id); + + mac_addr_raw = cdp_get_vdev_mac_addr(dp_soc, vdev); + if (mac_addr_raw == NULL) { + WMA_LOGE("%s: peer mac addr is NULL", __func__); + return QDF_STATUS_E_FAULT; + } + + /* for each remote ibss peer, clear its keys */ + if (wma_is_vdev_in_ibss_mode(wma, vdev_id) && + qdf_mem_cmp(peer_addr, mac_addr_raw, IEEE80211_ADDR_LEN)) { + tpSetStaKeyParams key_info; + + key_info = qdf_mem_malloc(sizeof(*key_info)); + if (!key_info) { + return QDF_STATUS_E_NOMEM; + } + WMA_LOGD("%s: remote ibss peer %pM key clearing\n", __func__, + peer_addr); + qdf_mem_zero(key_info, sizeof(*key_info)); + key_info->smesessionId = vdev_id; + qdf_mem_copy(key_info->peer_macaddr.bytes, peer_addr, + IEEE80211_ADDR_LEN); + key_info->sendRsp = false; + + wma_set_stakey(wma, key_info); + } + + return QDF_STATUS_SUCCESS; +err: + wma->interfaces[vdev_id].peer_count--; + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_cleanup_target_req_param() - free param memory of target request + * @tgt_req: target request params + * + * Return: none + */ +static void wma_cleanup_target_req_param(struct wma_target_req *tgt_req) +{ + WMA_LOGE("%s: Free target req user_data msg_type:%d", __func__, + tgt_req->msg_type); + if (tgt_req->msg_type == WMA_CHNL_SWITCH_REQ || + tgt_req->msg_type == WMA_DELETE_BSS_REQ || + tgt_req->msg_type == WMA_ADD_BSS_REQ) { + qdf_mem_free(tgt_req->user_data); + tgt_req->user_data = NULL; + } + + if (tgt_req->msg_type == WMA_SET_LINK_STATE && tgt_req->user_data) { + tpLinkStateParams params = + (tpLinkStateParams) tgt_req->user_data; + qdf_mem_free(params->callbackArg); + params->callbackArg = NULL; + qdf_mem_free(tgt_req->user_data); + tgt_req->user_data = NULL; + } +} + +/** + * wma_remove_bss_peer() - remove BSS peer + * @wma: pointer to WMA handle + * @pdev: pointer to PDEV + * @vdev_id: vdev id on which delete BSS request was received + * @params: pointer to Delete BSS params + * + * This function is called on receiving vdev stop response from FW or + * vdev stop response timeout. In case of IBSS/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, void *pdev, uint32_t vdev_id, + tpDeleteBssParams params) +{ + void *peer, *vdev; + uint8_t peer_id; + 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; + + vdev = cdp_get_vdev_from_vdev_id(soc, pdev, vdev_id); + if (!vdev) { + WMA_LOGE(FL("vdev is NULL for vdev_id = %d"), vdev_id); + return -EINVAL; + } + + if (wma_is_vdev_in_ibss_mode(wma, vdev_id) || + WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, vdev_id)) { + mac_addr = cdp_get_vdev_mac_addr(soc, vdev); + if (!mac_addr) { + WMA_LOGE(FL("mac_addr is NULL for vdev_id = %d"), + vdev_id); + return -EINVAL; + } + } else { + mac_addr = params->bssid; + } + + peer = cdp_peer_get_ref_by_addr(soc, pdev, mac_addr, + &peer_id, + PEER_DEBUG_ID_WMA_DEL_BSS); + if (!peer) { + WMA_LOGE(FL("peer NULL for vdev_id = %d"), vdev_id); + return -EINVAL; + } + + qdf_status = wma_remove_peer(wma, mac_addr, vdev_id, peer, false); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE(FL("wma_remove_peer failed vdev_id:%d"), vdev_id); + return -EINVAL; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + WMA_LOGD(FL("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_PEER_RSP, + params, + WMA_DELETE_STA_TIMEOUT); + if (!del_req) { + WMA_LOGE(FL("Failed to allocate request. vdev_id %d"), + vdev_id); + params->status = QDF_STATUS_E_NOMEM; + ret_value = -EINVAL; + } + } + if (peer) + cdp_peer_release_ref(soc, peer, + PEER_DEBUG_ID_WMA_DEL_BSS); + 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_LOGE("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_LOGD("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) +{ + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + 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 */ + +/** + * wma_send_del_bss_response() - send del bss resp to upper layer + * @wma: wma handle. + * @vdev_id: vdev ID of device for which MCC has to be checked + * + * This function sends del bss resp to upper layer + * + * Return: none + */ +static void +wma_send_del_bss_response(tp_wma_handle wma, struct wma_target_req *req, + uint8_t vdev_id) +{ + struct wma_txrx_node *iface; + struct beacon_info *bcn; + tpDeleteBssParams params; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!req) { + WMA_LOGE("%s req is NULL", __func__); + return; + } + + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, vdev_id); + if (req->user_data) + qdf_mem_free(req->user_data); + req->user_data = NULL; + return; + } + + params = (tpDeleteBssParams)req->user_data; + if (wma_send_vdev_down_to_fw(wma, vdev_id) != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", vdev_id); + } else { + wma_vdev_set_mlme_state(wma, vdev_id, WLAN_VDEV_S_STOP); + wma_check_and_find_mcc_ap(wma, vdev_id); + } + + cdp_fc_vdev_flush(soc, iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", + __func__, vdev_id); + cdp_fc_vdev_unpause(soc, iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma_vdev_clear_pause_bit(vdev_id, PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + + bcn = wma->interfaces[vdev_id].beacon; + if (bcn) { + WMA_LOGD("%s: Freeing beacon struct %pK, template memory %pK", + __func__, 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 (params->status == QDF_STATUS_FW_MSG_TIMEDOUT) { + qdf_mem_free(req->user_data); + req->user_data = NULL; + WMA_LOGE("%s: DEL BSS from ADD BSS timeout do not send resp to UMAC (vdev id %x)", + __func__, vdev_id); + } else { + params->status = QDF_STATUS_SUCCESS; + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_RSP, + (void *)params, 0); + } + + if (iface->del_staself_req && iface->is_del_sta_defered) { + iface->is_del_sta_defered = false; + WMA_LOGA("scheduling defered deletion (vdev id %x)", + vdev_id); + wma_vdev_detach(wma, iface->del_staself_req, 1); + } +} + +#ifdef WLAN_FEATURE_11W +static void wma_clear_iface_key(struct wma_txrx_node *iface) +{ + qdf_mem_zero(&iface->key, sizeof(iface->key)); +} +#else +static void wma_clear_iface_key(struct wma_txrx_node *iface) +{ +} +#endif + +/** + * wma_vdev_stop_resp_handler() - vdev stop response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, + u32 len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_STOPPED_EVENTID_param_tlvs *param_buf; + wmi_vdev_stopped_event_fixed_param *resp_event; + struct wma_target_req *req_msg, *del_req; + struct cdp_pdev *pdev; + void *peer = NULL; + uint8_t peer_id; + struct wma_txrx_node *iface; + int32_t status = 0; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS qdf_status; + + WMA_LOGD("%s: Enter", __func__); + + /* Ignore stop_response in Monitor mode */ + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + return QDF_STATUS_SUCCESS; + + param_buf = (WMI_VDEV_STOPPED_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid event buffer"); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d from FW", + __func__, resp_event->vdev_id); + return -EINVAL; + } + + 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_LOGD(FL("Reset rmfEnabled for vdev %d"), + resp_event->vdev_id); + } + + /* Clear key information */ + wma_clear_iface_key(iface); + wma_release_wakelock(&iface->vdev_stop_wakelock); + + req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP, true); + if (!req_msg) { + WMA_LOGE("%s: Failed to lookup vdev request for vdev id %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + status = -EINVAL; + wma_cleanup_target_req_param(req_msg); + qdf_mc_timer_stop(&req_msg->event_timeout); + goto free_req_msg; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + if (req_msg->msg_type == WMA_DELETE_BSS_REQ) { + tpDeleteBssParams params = + (tpDeleteBssParams) req_msg->user_data; + + if (iface->handle == NULL) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, resp_event->vdev_id); + wma_cleanup_target_req_param(req_msg); + status = -EINVAL; + goto free_req_msg; + } + + /* CCA is required only for sta interface */ + if (iface->type == WMI_VDEV_TYPE_STA) + wma_get_cca_stats(wma, resp_event->vdev_id); + + /* Clear arp and ns offload cache */ + qdf_mem_zero(&iface->ns_offload_req, + sizeof(iface->ns_offload_req)); + qdf_mem_zero(&iface->arp_offload_req, + sizeof(iface->arp_offload_req)); + + status = wma_remove_bss_peer(wma, pdev, resp_event->vdev_id, + params); + if (status) { + WMA_LOGE("%s Del bss failed call vdev down vdev:%d", + __func__, resp_event->vdev_id); + wma_send_del_bss_response(wma, req_msg, + resp_event->vdev_id); + goto free_req_msg; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) + goto free_req_msg; + + wma_send_del_bss_response(wma, req_msg, resp_event->vdev_id); + } else if (req_msg->msg_type == WMA_SET_LINK_STATE) { + tpLinkStateParams params = + (tpLinkStateParams) req_msg->user_data; + + peer = cdp_peer_get_ref_by_addr(soc, pdev, params->bssid, + &peer_id, + PEER_DEBUG_ID_WMA_VDEV_STOP_RESP); + if (peer) { + WMA_LOGP(FL("Deleting peer %pM vdev id %d"), + params->bssid, req_msg->vdev_id); + qdf_status = wma_remove_peer(wma, params->bssid, + req_msg->vdev_id, + peer, false); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE(FL("wma_remove_peer failed")); + status = -EINVAL; + params->status = QDF_STATUS_E_FAILURE; + goto set_link_rsp; + } + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + WMA_LOGI(FL("Wait for the peer delete. vdev_id %d"), + req_msg->vdev_id); + del_req = wma_fill_hold_req(wma, + req_msg->vdev_id, + WMA_DELETE_STA_REQ, + WMA_SET_LINK_PEER_RSP, + params, + WMA_DELETE_STA_TIMEOUT); + if (!del_req) { + WMA_LOGE(FL("Failed to allocate request. vdev_id %d"), + req_msg->vdev_id); + params->status = QDF_STATUS_E_NOMEM; + } else { + goto free_req_msg; + } + } + } + +set_link_rsp: + if (wma_send_vdev_down_to_fw(wma, req_msg->vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + req_msg->vdev_id); + } + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); + } + +free_req_msg: + if (peer) + cdp_peer_release_ref(soc, peer, + PEER_DEBUG_ID_WMA_VDEV_STOP_RESP); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + return status; +} + +/** + * wma_vdev_attach() - create vdev in fw + * @wma_handle: wma handle + * @self_sta_req: self sta request + * @generateRsp: generate response + * + * This function creates vdev in target and + * attach this vdev to txrx module. It also set + * vdev related params to fw. + * + * Return: txrx vdev handle + */ +struct cdp_vdev *wma_vdev_attach(tp_wma_handle wma_handle, + struct add_sta_self_params *self_sta_req, + uint8_t generateRsp) +{ + struct cdp_vdev *txrx_vdev_handle = NULL; + struct cdp_pdev *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + enum wlan_op_mode txrx_vdev_type; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t cfg_val, retry, param; + uint16_t val16; + QDF_STATUS ret; + tSirMacHTCapabilityInfo *phtCapInfo; + struct scheduler_msg sme_msg = { 0 }; + struct vdev_create_params params = { 0 }; + u_int8_t vdev_id; + struct sir_set_tx_rx_aggregation_size tx_rx_aggregation_size; + struct sir_set_tx_sw_retry_threshold tx_sw_retry_threshold; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_peer *obj_peer; + + qdf_mem_zero(&tx_rx_aggregation_size, sizeof(tx_rx_aggregation_size)); + WMA_LOGD("mac %pM, vdev_id %hu, type %d, sub_type %d, nss 2g %d, 5g %d", + self_sta_req->self_mac_addr, self_sta_req->session_id, + self_sta_req->type, self_sta_req->sub_type, + self_sta_req->nss_2g, self_sta_req->nss_5g); + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + goto end; + } + + vdev_id = self_sta_req->session_id; + if (wma_is_vdev_valid(vdev_id)) { + WMA_LOGE("%s: vdev %d already active", __func__, vdev_id); + goto end; + } + + params.if_id = self_sta_req->session_id; + params.type = self_sta_req->type; + params.subtype = self_sta_req->sub_type; + params.nss_2g = self_sta_req->nss_2g; + params.nss_5g = self_sta_req->nss_5g; + + /* Create a vdev in target */ + ret = wmi_unified_vdev_create_send(wma_handle->wmi_handle, + self_sta_req->self_mac_addr, + ¶ms); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("%s: Unable to add an interface for ath_dev", + __func__); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + txrx_vdev_type = wma_get_txrx_vdev_type(self_sta_req->type); + + if (wlan_op_mode_unknown == txrx_vdev_type) { + WMA_LOGE("Failed to get txrx vdev type"); + wmi_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + goto end; + } + + txrx_vdev_handle = cdp_vdev_attach(soc, txrx_pdev, + self_sta_req->self_mac_addr, + vdev_id, txrx_vdev_type); + + WMA_LOGD("vdev_id %hu, txrx_vdev_handle = %pK", vdev_id, + txrx_vdev_handle); + + if (NULL == txrx_vdev_handle) { + WMA_LOGE("%s: cdp_vdev_attach failed", __func__); + status = QDF_STATUS_E_FAILURE; + wmi_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + goto end; + } + + wma_handle->interfaces[vdev_id].vdev_active = true; + wma_handle->interfaces[vdev_id].handle = txrx_vdev_handle; + wma_vdev_update_pause_bitmap(vdev_id, 0); + + wma_handle->interfaces[vdev_id].ptrn_match_enable = + wma_handle->ptrn_match_enable_all_vdev ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_DEAUTH_ENABLE, &cfg_val) + != QDF_STATUS_SUCCESS) + wma_handle->wow.deauth_enable = true; + else + wma_handle->wow.deauth_enable = cfg_val ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_DISASSOC_ENABLE, &cfg_val) + != QDF_STATUS_SUCCESS) + wma_handle->wow.disassoc_enable = true; + else + wma_handle->wow.disassoc_enable = cfg_val ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_MAX_MISSED_BEACON, &cfg_val) + != QDF_STATUS_SUCCESS) + wma_handle->wow.bmiss_enable = true; + else + wma_handle->wow.bmiss_enable = cfg_val ? true : false; + + qdf_mem_copy(wma_handle->interfaces[vdev_id].addr, + self_sta_req->self_mac_addr, + sizeof(wma_handle->interfaces[vdev_id].addr)); + + tx_rx_aggregation_size.tx_aggregation_size = + self_sta_req->tx_aggregation_size; + tx_rx_aggregation_size.rx_aggregation_size = + self_sta_req->rx_aggregation_size; + tx_rx_aggregation_size.vdev_id = self_sta_req->session_id; + tx_rx_aggregation_size.aggr_type = WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU; + + ret = wma_set_tx_rx_aggregation_size(&tx_rx_aggregation_size); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set aggregation sizes(err=%d)", ret); + + tx_rx_aggregation_size.tx_aggregation_size_be = + self_sta_req->tx_aggregation_size_be; + tx_rx_aggregation_size.tx_aggregation_size_bk = + self_sta_req->tx_aggregation_size_bk; + tx_rx_aggregation_size.tx_aggregation_size_vi = + self_sta_req->tx_aggregation_size_vi; + tx_rx_aggregation_size.tx_aggregation_size_vo = + self_sta_req->tx_aggregation_size_vo; + + tx_sw_retry_threshold.tx_aggr_sw_retry_threshold_be = + self_sta_req->tx_aggr_sw_retry_threshold_be; + tx_sw_retry_threshold.tx_aggr_sw_retry_threshold_bk = + self_sta_req->tx_aggr_sw_retry_threshold_bk; + tx_sw_retry_threshold.tx_aggr_sw_retry_threshold_vi = + self_sta_req->tx_aggr_sw_retry_threshold_vi; + tx_sw_retry_threshold.tx_aggr_sw_retry_threshold_vo = + self_sta_req->tx_aggr_sw_retry_threshold_vo; + tx_sw_retry_threshold.tx_aggr_sw_retry_threshold = + self_sta_req->tx_aggr_sw_retry_threshold; + + tx_sw_retry_threshold.tx_non_aggr_sw_retry_threshold_be = + self_sta_req->tx_non_aggr_sw_retry_threshold_be; + tx_sw_retry_threshold.tx_non_aggr_sw_retry_threshold_bk = + self_sta_req->tx_non_aggr_sw_retry_threshold_bk; + tx_sw_retry_threshold.tx_non_aggr_sw_retry_threshold_vi = + self_sta_req->tx_non_aggr_sw_retry_threshold_vi; + tx_sw_retry_threshold.tx_non_aggr_sw_retry_threshold_vo = + self_sta_req->tx_non_aggr_sw_retry_threshold_vo; + tx_sw_retry_threshold.tx_non_aggr_sw_retry_threshold = + self_sta_req->tx_non_aggr_sw_retry_threshold; + + tx_sw_retry_threshold.vdev_id = self_sta_req->session_id; + + + switch (self_sta_req->type) { + case WMI_VDEV_TYPE_STA: + ret = wma_set_tx_rx_aggregation_size_per_ac( + &tx_rx_aggregation_size); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("set aggr sizes per ac(err=%d) failed", ret); + + if (wlan_cfg_get_int(mac, WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + &cfg_val) != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get value for WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD"); + cfg_val = DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD; + } + + wma_set_sta_keep_alive(wma_handle, + self_sta_req->session_id, + SIR_KEEP_ALIVE_NULL_PKT, + cfg_val, 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); + } + + retry = tx_sw_retry_threshold.tx_aggr_sw_retry_threshold; + param = WMI_PDEV_PARAM_AGG_SW_RETRY_TH; + if (retry) + wma_cli_set_command(vdev_id, param, retry, PDEV_CMD); + + retry = tx_sw_retry_threshold.tx_non_aggr_sw_retry_threshold; + param = WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH; + if (retry) + wma_cli_set_command(vdev_id, param, retry, PDEV_CMD); + + ret = wma_set_sw_retry_threshold_per_ac(wma_handle, + &tx_sw_retry_threshold); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set retry threshold(err=%d)", ret); + break; + } + + wma_handle->interfaces[vdev_id].type = self_sta_req->type; + wma_handle->interfaces[vdev_id].sub_type = self_sta_req->sub_type; + qdf_atomic_init(&wma_handle->interfaces[vdev_id].bss_status); + + if (wma_vdev_uses_self_peer(self_sta_req->type, + self_sta_req->sub_type)) { + ret = wma_create_peer(wma_handle, txrx_pdev, txrx_vdev_handle, + self_sta_req->self_mac_addr, + WMI_PEER_TYPE_DEFAULT, + self_sta_req->session_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("%s: Failed to create peer", __func__); + status = QDF_STATUS_E_FAILURE; + wmi_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + wma_handle->interfaces[vdev_id].vdev_active = false; + wma_cdp_vdev_detach(soc, wma_handle, vdev_id); + txrx_vdev_handle = NULL; + goto end; + } + } else if (self_sta_req->type == WMI_VDEV_TYPE_STA) { + obj_peer = wma_create_objmgr_peer(wma_handle, vdev_id, + self_sta_req->self_mac_addr, + WMI_PEER_TYPE_DEFAULT); + if (!obj_peer) { + WMA_LOGE("%s: Failed to create obj mgr peer for self sta", + __func__); + status = QDF_STATUS_E_FAILURE; + wmi_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + wma_handle->interfaces[vdev_id].vdev_active = false; + wma_cdp_vdev_detach(soc, wma_handle, vdev_id); + txrx_vdev_handle = NULL; + goto end; + } + } + + WMA_LOGD("Setting WMI_VDEV_PARAM_DISCONNECT_TH: %d", + self_sta_req->pkt_err_disconn_th); + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DISCONNECT_TH, + self_sta_req->pkt_err_disconn_th); + if (ret) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_DISCONNECT_TH"); + + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE, + mac->roam.configParam.mcc_rts_cts_prot_enable); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI VDEV MCC_RTSCTS_PROTECTION_ENABLE"); + + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE, + mac->roam.configParam.mcc_bcast_prob_resp_enable); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI VDEV MCC_BROADCAST_PROBE_ENABLE"); + + if (wlan_cfg_get_int(mac, WNI_CFG_RTS_THRESHOLD, + &cfg_val) == QDF_STATUS_SUCCESS) { + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_RTS_THRESHOLD, + cfg_val); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_RTS_THRESHOLD"); + } else { + WMA_LOGE("Failed to get value for WNI_CFG_RTS_THRESHOLD, leaving unchanged"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_FRAGMENTATION_THRESHOLD, + &cfg_val) == QDF_STATUS_SUCCESS) { + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + cfg_val); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD"); + } else { + WMA_LOGE("Failed to get value for WNI_CFG_FRAGMENTATION_THRESHOLD, leaving unchanged"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_HT_CAP_INFO, &cfg_val) == + QDF_STATUS_SUCCESS) { + val16 = (uint16_t) cfg_val; + phtCapInfo = (tSirMacHTCapabilityInfo *) &cfg_val; + + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_TX_STBC, + phtCapInfo->txSTBC); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_TX_STBC"); + } else { + WMA_LOGE("Failed to get value of HT_CAP, TX STBC unchanged"); + } + + wma_set_vdev_mgmt_rate(wma_handle, self_sta_req->session_id); + + /* Initialize roaming offload state */ + if ((self_sta_req->type == WMI_VDEV_TYPE_STA) && + (self_sta_req->sub_type == 0)) { + /* Pass down enable/disable bcast probe rsp to FW */ + ret = wma_vdev_set_param( + wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, + self_sta_req->enable_bcast_probe_rsp); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE"); + + /* Pass down the FILS max channel guard time to FW */ + ret = wma_vdev_set_param( + wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, + self_sta_req->fils_max_chan_guard_time); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME"); + + /* Pass down the Probe Request tx delay(in ms) to FW */ + ret = wma_vdev_set_param( + wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_PROBE_DELAY, + PROBE_REQ_TX_DELAY); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_PROBE_DELAY"); + + /* Pass down the probe request tx time gap(in ms) to FW */ + ret = wma_vdev_set_param( + wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_REPEAT_PROBE_TIME, + PROBE_REQ_TX_TIME_GAP); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_REPEAT_PROBE_TIME"); + } + + if ((self_sta_req->type == WMI_VDEV_TYPE_STA || + self_sta_req->type == WMI_VDEV_TYPE_AP) && + self_sta_req->sub_type == 0) { + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_ENABLE_DISABLE_OCE_FEATURES, + self_sta_req->oce_feature_bitmap); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ENABLE_DISABLE_OCE_FEATURES"); + } + + /* Initialize BMISS parameters */ + if ((self_sta_req->type == WMI_VDEV_TYPE_STA) && + (self_sta_req->sub_type == 0)) + wma_roam_scan_bmiss_cnt(wma_handle, + mac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt, + mac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt, + self_sta_req->session_id); + + if (wlan_cfg_get_int(mac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == QDF_STATUS_SUCCESS) { + WMA_LOGD("%s: setting ini value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED: %d", + __func__, cfg_val); + ret = wma_set_enable_disable_mcc_adaptive_scheduler(cfg_val); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to set WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED"); + } + } else { + WMA_LOGE("Failed to get value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, leaving unchanged"); + } + + if (self_sta_req->type == WMI_VDEV_TYPE_STA) { + ret = wma_config_active_apf_mode(wma_handle, + self_sta_req->session_id); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to configure active APF mode"); + } + +end: + self_sta_req->status = status; + +#ifdef QCA_IBSS_SUPPORT + if (generateRsp) +#endif + { + sme_msg.type = eWNI_SME_ADD_STA_SELF_RSP; + sme_msg.bodyptr = self_sta_req; + 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_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_ADD_STA_SELF_RSP"); + qdf_mem_free(self_sta_req); + } + } + return txrx_vdev_handle; +} + +uint32_t wma_get_bcn_rate_code(uint16_t rate) +{ + /* rate in multiples of 100 Kbps */ + switch (rate) { + case WMA_BEACON_TX_RATE_1_M: + return WMI_BCN_TX_RATE_CODE_1_M; + case WMA_BEACON_TX_RATE_2_M: + return WMI_BCN_TX_RATE_CODE_2_M; + case WMA_BEACON_TX_RATE_5_5_M: + return WMI_BCN_TX_RATE_CODE_5_5_M; + case WMA_BEACON_TX_RATE_11_M: + return WMI_BCN_TX_RATE_CODE_11M; + case WMA_BEACON_TX_RATE_6_M: + return WMI_BCN_TX_RATE_CODE_6_M; + case WMA_BEACON_TX_RATE_9_M: + return WMI_BCN_TX_RATE_CODE_9_M; + case WMA_BEACON_TX_RATE_12_M: + return WMI_BCN_TX_RATE_CODE_12_M; + case WMA_BEACON_TX_RATE_18_M: + return WMI_BCN_TX_RATE_CODE_18_M; + case WMA_BEACON_TX_RATE_24_M: + return WMI_BCN_TX_RATE_CODE_24_M; + case WMA_BEACON_TX_RATE_36_M: + return WMI_BCN_TX_RATE_CODE_36_M; + case WMA_BEACON_TX_RATE_48_M: + return WMI_BCN_TX_RATE_CODE_48_M; + case WMA_BEACON_TX_RATE_54_M: + return WMI_BCN_TX_RATE_CODE_54_M; + default: + return WMI_BCN_TX_RATE_CODE_1_M; + } +} + +/** + * wma_vdev_start() - send vdev start request to fw + * @wma: wma handle + * @req: vdev start params + * @isRestart: isRestart flag + * + * Return: QDF status + */ +QDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart) +{ + struct vdev_start_params params = { 0 }; + wmi_vdev_start_request_cmd_fixed_param *cmd; + struct wma_txrx_node *intr = wma->interfaces; + tpAniSirGlobal mac_ctx = NULL; + uint32_t temp_ssid_len = 0; + uint32_t temp_flags = 0; + uint32_t temp_chan_info = 0; + uint32_t temp_reg_info_1 = 0; + uint32_t temp_reg_info_2 = 0; + uint16_t bw_val; + struct wma_txrx_node *iface = &wma->interfaces[req->vdev_id]; + struct wma_target_req *req_msg; + uint32_t chan_mode; + enum phy_ch_width ch_width; + struct mlme_nss_chains *ini_cfg; + struct wlan_objmgr_vdev *vdev; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (mac_ctx == NULL) { + WMA_LOGE("%s: vdev start failed as mac_ctx is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (req->chan == 0) { + WMA_LOGE("%s: invalid channel: %d", __func__, req->chan); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + params.band_center_freq1 = cds_chan_to_freq(req->chan); + ch_width = req->chan_width; + bw_val = wlan_reg_get_bw_value(req->chan_width); + if (20 < bw_val) { + if (req->ch_center_freq_seg0) { + params.band_center_freq1 = + cds_chan_to_freq(req->ch_center_freq_seg0); + } else { + WMA_LOGE("%s: invalid cntr_freq for bw %d, drop to 20", + __func__, bw_val); + params.band_center_freq1 = cds_chan_to_freq(req->chan); + ch_width = CH_WIDTH_20MHZ; + bw_val = 20; + } + } + if (80 < bw_val) { + if (req->ch_center_freq_seg1) { + params.band_center_freq2 = + cds_chan_to_freq(req->ch_center_freq_seg1); + } else { + WMA_LOGE("%s: invalid cntr_freq for bw %d, drop to 80", + __func__, bw_val); + params.band_center_freq2 = 0; + ch_width = CH_WIDTH_80MHZ; + } + } else { + params.band_center_freq2 = 0; + } + chan_mode = wma_chan_phy_mode(req->chan, ch_width, + req->dot11_mode); + + if (chan_mode == MODE_UNKNOWN) { + WMA_LOGE("%s: invalid phy mode!", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!params.band_center_freq1) { + WMA_LOGE("%s: invalid center freq1", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (((ch_width == CH_WIDTH_160MHZ) || (ch_width == CH_WIDTH_80P80MHZ)) + && !params.band_center_freq2) { + WMA_LOGE("%s: invalid center freq2 for 160MHz", __func__); + return QDF_STATUS_E_FAILURE; + } + /* Fill channel info */ + params.chan_freq = cds_chan_to_freq(req->chan); + params.chan_mode = chan_mode; + + /* For Rome, only supports LFR2, not LFR3, for reassoc, need send vdev + * start cmd to F/W while vdev started first, then send reassoc frame + */ + if (!isRestart && + qdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED && + wmi_service_enabled(wma->wmi_handle, wmi_service_roam_ho_offload)) { + req_msg = wma_find_vdev_req(wma, req->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP, + false); + if (!req_msg || req_msg->msg_type != WMA_DELETE_BSS_REQ) { + WMA_LOGE("BSS is in started state before vdev start"); + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); + } + } + + WMA_LOGD("%s: Enter isRestart=%d vdev=%d", __func__, isRestart, + req->vdev_id); + params.vdev_id = req->vdev_id; + + intr[params.vdev_id].chanmode = params.chan_mode; + intr[params.vdev_id].ht_capable = req->ht_capable; + intr[params.vdev_id].vht_capable = req->vht_capable; + intr[params.vdev_id].config.gtx_info.gtxRTMask[0] = + CFG_TGT_DEFAULT_GTX_HT_MASK; + intr[params.vdev_id].config.gtx_info.gtxRTMask[1] = + CFG_TGT_DEFAULT_GTX_VHT_MASK; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TGT_GTX_USR_CFG, + &intr[params.vdev_id].config.gtx_info.gtxUsrcfg) + != QDF_STATUS_SUCCESS) { + intr[params.vdev_id].config.gtx_info.gtxUsrcfg = + WNI_CFG_TGT_GTX_USR_CFG_STADEF; + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_WARN, + "Failed to get WNI_CFG_TGT_GTX_USR_CFG"); + } + + intr[params.vdev_id].config.gtx_info.gtxPERThreshold = + CFG_TGT_DEFAULT_GTX_PER_THRESHOLD; + intr[params.vdev_id].config.gtx_info.gtxPERMargin = + CFG_TGT_DEFAULT_GTX_PER_MARGIN; + intr[params.vdev_id].config.gtx_info.gtxTPCstep = + CFG_TGT_DEFAULT_GTX_TPC_STEP; + intr[params.vdev_id].config.gtx_info.gtxTPCMin = + CFG_TGT_DEFAULT_GTX_TPC_MIN; + intr[params.vdev_id].config.gtx_info.gtxBWMask = + CFG_TGT_DEFAULT_GTX_BW_MASK; + intr[params.vdev_id].mhz = params.chan_freq; + intr[params.vdev_id].chan_width = ch_width; + intr[params.vdev_id].channel = req->chan; + wma_copy_txrxnode_he_ops(&intr[params.vdev_id], req); + + temp_chan_info &= 0xffffffc0; + temp_chan_info |= params.chan_mode; + + /* Set half or quarter rate WMI flags */ + params.is_half_rate = req->is_half_rate; + params.is_quarter_rate = req->is_quarter_rate; + + if (req->is_half_rate) + temp_chan_info |= (1 << WMI_CHAN_FLAG_HALF_RATE); + else if (req->is_quarter_rate) + temp_chan_info |= (1 << WMI_CHAN_FLAG_QUARTER_RATE); + + /* + * If the channel has DFS set, flip on radar reporting. + * + * It may be that this should only be done for IBSS/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. + */ + + params.is_dfs = req->is_dfs; + params.is_restart = isRestart; + params.cac_duration_ms = req->cac_duration_ms; + params.regdomain = req->dfs_regdomain; + if ((QDF_GLOBAL_MONITOR_MODE != cds_get_conparam()) && req->is_dfs) { + temp_chan_info |= (1 << WMI_CHAN_FLAG_DFS); + params.dis_hw_ack = true; + + /* + * If channel is DFS and operating in AP mode, + * set the WMI_CHAN_FLAG_DFS flag. + */ + if (wma_is_vdev_in_ap_mode(wma, params.vdev_id) == true) + params.flag_dfs = WMI_CHAN_FLAG_DFS; + } + + params.beacon_intval = req->beacon_intval; + params.dtim_period = req->dtim_period; + + if (req->beacon_tx_rate) { + WMA_LOGD("%s: beacon tx rate [%hu * 100 Kbps]", + __func__, req->beacon_tx_rate); + temp_flags |= WMI_UNIFIED_VDEV_START_BCN_TX_RATE_PRESENT; + /* + * beacon_tx_rate is in multiples of 100 Kbps. + * Convert the data rate to hw rate code. + */ + params.bcn_tx_rate_code = + wma_get_bcn_rate_code(req->beacon_tx_rate); + } + + /* FIXME: Find out min, max and regulatory power levels */ + params.max_txpow = req->max_txpow; + temp_reg_info_1 &= 0xff00ffff; + temp_reg_info_1 |= ((req->max_txpow&0xff) << 16); + + temp_reg_info_2 &= 0xffff00ff; + temp_reg_info_2 |= ((req->max_txpow&0xff)<<8); + + /* TODO: Handle regulatory class, max antenna */ + if (!isRestart) { + params.pmf_enabled = req->pmf_enabled; + if (req->pmf_enabled) + temp_flags |= WMI_UNIFIED_VDEV_START_PMF_ENABLED; + } + + /* Copy the SSID */ + if (req->ssid.length) { + params.ssid.length = req->ssid.length; + if (req->ssid.length < sizeof(cmd->ssid.ssid)) + temp_ssid_len = req->ssid.length; + else + temp_ssid_len = sizeof(cmd->ssid.ssid); + qdf_mem_copy(params.ssid.mac_ssid, req->ssid.ssId, + temp_ssid_len); + } + + params.hidden_ssid = req->hidden_ssid; + if (req->hidden_ssid) + temp_flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; + + params.num_noa_descriptors = 0; + params.preferred_rx_streams = req->preferred_rx_streams; + params.preferred_tx_streams = req->preferred_tx_streams; + + wma_copy_vdev_start_he_ops(¶ms, req); + + /* Store vdev params in SAP mode which can be used in vdev restart */ + if (intr[req->vdev_id].type == WMI_VDEV_TYPE_AP && + intr[req->vdev_id].sub_type == 0) { + intr[req->vdev_id].vdev_restart_params.vdev_id = req->vdev_id; + intr[req->vdev_id].vdev_restart_params.ssid.ssid_len = + temp_ssid_len; + qdf_mem_copy(intr[req->vdev_id].vdev_restart_params.ssid.ssid, + params.ssid.mac_ssid, temp_ssid_len); + intr[req->vdev_id].vdev_restart_params.flags = temp_flags; + intr[req->vdev_id].vdev_restart_params.requestor_id = 0; + intr[req->vdev_id].vdev_restart_params.disable_hw_ack = + params.dis_hw_ack; + intr[req->vdev_id].vdev_restart_params.chan.mhz = + params.chan_freq; + intr[req->vdev_id].vdev_restart_params.chan.band_center_freq1 = + params.band_center_freq1; + intr[req->vdev_id].vdev_restart_params.chan.band_center_freq2 = + params.band_center_freq2; + intr[req->vdev_id].vdev_restart_params.chan.info = + temp_chan_info; + intr[req->vdev_id].vdev_restart_params.chan.reg_info_1 = + temp_reg_info_1; + intr[req->vdev_id].vdev_restart_params.chan.reg_info_2 = + temp_reg_info_2; + } + + if (isRestart) { + /* + * Marking the VDEV UP STATUS to false + * since, VDEV RESTART will do a VDEV DOWN + * in the firmware. + */ + wma_vdev_set_mlme_state(wma, params.vdev_id, WLAN_VDEV_S_STOP); + } else { + WMA_LOGD("%s, vdev_id: %d, unpausing tx_ll_queue at VDEV_START", + __func__, params.vdev_id); + cdp_fc_vdev_unpause(cds_get_context(QDF_MODULE_ID_SOC), + wma->interfaces[params.vdev_id].handle, + 0xffffffff); + wma_vdev_update_pause_bitmap(params.vdev_id, 0); + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, params.vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + WMA_LOGE("%s, vdev_id: %d, failed to get vdev from psoc", + __func__, params.vdev_id); + return QDF_STATUS_E_FAILURE; + } + + ini_cfg = mlme_get_ini_vdev_config(vdev); + if (!ini_cfg) { + wma_err("nss chain ini config NULL"); + goto end; + } + + /* Send self capability of nss chain params before vdev start to fw */ + if (wma->dynamic_nss_chains_support) + wma_vdev_nss_chain_params_send(params.vdev_id, ini_cfg); + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + return wma_send_vdev_start_to_fw(wma, ¶ms); +} + +/** + * 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[IEEE80211_ADDR_LEN]; + int status = 0; + + WMA_LOGD(FL("Enter")); + param_buf = (WMI_PEER_ASSOC_CONF_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + WMA_LOGE("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr); + WMA_LOGD(FL("peer assoc conf for vdev:%d mac=%pM"), + event->vdev_id, macaddr); + + req_msg = wma_find_req(wma, event->vdev_id, + WMA_PEER_ASSOC_CNF_START); + + if (!req_msg) { + WMA_LOGE(FL("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_LOGE(FL("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 = QDF_STATUS_SUCCESS; + WMA_LOGD(FL("Send ADD_STA_RSP: statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + params->staType, params->smesessionId, + params->assocId, params->bssId, params->staIdx, + 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) { + tpAddBssParams params = (tpAddBssParams) req_msg->user_data; + + if (!params) { + WMA_LOGE(FL("add BSS 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 = QDF_STATUS_SUCCESS; + WMA_LOGD(FL("Send ADD BSS RSP: opermode: %d update_bss: %d nw_type: %d bssid: %pM staIdx %d status %d"), + params->operMode, + params->updateBss, params->nwType, params->bssId, + params->staContext.staIdx, params->status); + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, + (void *)params, 0); + } else { + WMA_LOGE(FL("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; +} + +/** + * wma_vdev_delete_handler() - vdev delete response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_delete_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_DELETE_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_delete_cmd_fixed_param *event; + struct wma_target_req *req_msg; + int status = 0; + + param_buf = (WMI_VDEV_DELETE_RESP_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + event = (wmi_vdev_delete_cmd_fixed_param *)param_buf->fixed_param; + if (!event) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + WMA_LOGD("%s Vdev delete resp vdev id %d", __func__, event->vdev_id); + req_msg = wma_find_vdev_req(wma, event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_DEL, true); + if (!req_msg) { + WMA_LOGD(FL("Vdev delete resp is not handled! vdev id %d"), + event->vdev_id); + return -EINVAL; + } + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + + /* Send response to upper layers */ + wma_vdev_detach_callback(req_msg->user_data); + qdf_mem_free(req_msg); + + return status; +} + +/** + * 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[IEEE80211_ADDR_LEN]; + int status = 0; + + param_buf = (WMI_PEER_DELETE_RESP_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + event = (wmi_peer_delete_cmd_fixed_param *)param_buf->fixed_param; + if (!event) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr); + WMA_LOGD(FL("Peer Delete Response, vdev %d Peer %pM"), + event->vdev_id, 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_LOGD("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_LOGD(FL("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_LOGD(FL("Calling vdev detach handler")); + wma_handle_vdev_detach(wma, data->self_sta_param, + data->generate_rsp); + qdf_mem_free(data); + } else if (req_msg->type == WMA_SET_LINK_PEER_RSP) { + tpLinkStateParams params = + (tpLinkStateParams) req_msg->user_data; + if (wma_send_vdev_down_to_fw(wma, req_msg->vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + req_msg->vdev_id); + } + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); + } else if (req_msg->type == WMA_DELETE_PEER_RSP) { + wma_send_del_bss_response(wma, req_msg, req_msg->vdev_id); + } + qdf_mem_free(req_msg); + return status; +} + +static void wma_trigger_recovery_assert_on_fw_timeout(uint16_t wma_msg) +{ + WMA_LOGE("%s timed out, triggering recovery", + mac_trace_get_wma_msg_string(wma_msg)); + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); +} + +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 wma_target_req *msg; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE(FL("Failed to get wma")); + return; + } + + WMA_LOGA(FL("request %d is timed out for vdev_id - %d"), + tgt_req->msg_type, tgt_req->vdev_id); + msg = wma_find_req(wma, tgt_req->vdev_id, tgt_req->type); + + if (!msg) { + WMA_LOGE(FL("Failed to lookup request message - %d"), + tgt_req->msg_type); + /* + * if find request failed, then firmware rsp should have + * consumed the buffer. Do not free. + */ + return; + } + + if (tgt_req->msg_type == WMA_ADD_STA_REQ) { + tpAddStaParams params = (tpAddStaParams) tgt_req->user_data; + + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA(FL("WMA_ADD_STA_REQ timed out")); + WMA_LOGD(FL("Sending add sta rsp to umac (mac:%pM, status:%d)"), + 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); + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, + (void *)params, 0); + } else if (tgt_req->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams params = (tpAddBssParams) tgt_req->user_data; + + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA(FL("WMA_ADD_BSS_REQ timed out")); + WMA_LOGD(FL("Sending add bss rsp to umac (mac:%pM, status:%d)"), + params->selfMacAddr, params->status); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_ADD_BSS_REQ); + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, + (void *)params, 0); + } 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_LOGE(FL("WMA_DEL_STA_REQ timed out")); + WMA_LOGE(FL("Sending del sta rsp to umac (mac:%pM, status:%d)"), + 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); + 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_LOGA(FL("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); + wma_handle_vdev_detach(wma, del_sta->self_sta_param, + del_sta->generate_rsp); + 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)) { + tpLinkStateParams params = + (tpLinkStateParams) tgt_req->user_data; + + params->status = false; + WMA_LOGA(FL("wma delete peer for set link timed out")); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_DELETE_STA_REQ); + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, params, 0); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_DELETE_PEER_RSP)) { + tpDeleteBssParams params = + (tpDeleteBssParams) tgt_req->user_data; + + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGE(FL("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); + + wma_send_del_bss_response(wma, tgt_req, tgt_req->vdev_id); + } 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_LOGE(FL("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); + if (!params) { + WMA_LOGE(FL("Failed to allocate memory for 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_LOGE(FL("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); + if (!resp) { + WMA_LOGE(FL("Failed to allocate memory for 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 { + WMA_LOGE(FL("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 + * @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) { + WMA_LOGE(FL("Failed to allocate memory for msg %d vdev %d"), + msg_type, vdev_id); + return NULL; + } + + WMA_LOGD(FL("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_LOGE(FL("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; +} + +/** + * 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_LOGD(FL("Remove req for vdev: %d type: %d"), vdev_id, type); + req_msg = wma_find_req(wma, vdev_id, type); + if (!req_msg) { + WMA_LOGE(FL("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_vdev_resp_timer() - wma response timeout function + * @data: target request params + * + * Return: none + */ +void wma_vdev_resp_timer(void *data) +{ + tp_wma_handle wma; + struct wma_target_req *tgt_req = (struct wma_target_req *)data; + struct cdp_pdev *pdev; + struct wma_target_req *msg; + uint8_t peer_id; + int status; + void *peer; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + wma_cleanup_target_req_param(tgt_req); + goto free_tgt_req; + } + + WMA_LOGA("%s: request %d is timed out for vdev_id - %d", __func__, + tgt_req->msg_type, tgt_req->vdev_id); + msg = wma_find_vdev_req(wma, tgt_req->vdev_id, tgt_req->type, true); + + if (!msg) { + WMA_LOGE("%s: Failed to lookup request message - %d", + __func__, tgt_req->msg_type); + return; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + wma_cleanup_target_req_param(tgt_req); + qdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + wma_cleanup_target_req_param(tgt_req); + goto free_tgt_req; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + if (tgt_req->msg_type == WMA_CHNL_SWITCH_REQ) { + tpSwitchChannelParams params = + (tpSwitchChannelParams) tgt_req->user_data; + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_SWITCH_CHANNEL_REQ timedout", __func__); + + /* + * Trigger host crash if the flag is set or if the timeout + * is not due to fw down + */ + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_CHNL_SWITCH_REQ); + wma_send_msg_high_priority(wma, WMA_SWITCH_CHANNEL_RSP, + (void *)params, 0); + if (wma->interfaces[tgt_req->vdev_id].is_channel_switch) { + wma->interfaces[tgt_req->vdev_id].is_channel_switch = + false; + } + } else if (tgt_req->msg_type == WMA_DELETE_BSS_REQ) { + tpDeleteBssParams params = + (tpDeleteBssParams) tgt_req->user_data; + struct beacon_info *bcn; + struct wma_txrx_node *iface; + + if (tgt_req->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d", __func__, + tgt_req->vdev_id); + wma_cleanup_target_req_param(tgt_req); + qdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + + iface = &wma->interfaces[tgt_req->vdev_id]; + if (iface->handle == NULL) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, tgt_req->vdev_id); + wma_cleanup_target_req_param(tgt_req); + qdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + /* + * Trigger host crash if the flag is set or if the timeout + * is not due to fw down + */ + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_DELETE_BSS_REQ); + + status = wma_remove_bss_peer(wma, pdev, tgt_req->vdev_id, + params); + if (status) { + WMA_LOGE("Del BSS failed call del bss response vdev_id:%d", + tgt_req->vdev_id); + wma_send_del_bss_response(wma, tgt_req, + tgt_req->vdev_id); + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) + goto free_tgt_req; + + if (wma_send_vdev_down_to_fw(wma, tgt_req->vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + tgt_req->vdev_id); + } else { + wma_vdev_set_mlme_state(wma, tgt_req->vdev_id, + WLAN_VDEV_S_STOP); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, tgt_req->vdev_id, false); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + } + cdp_fc_vdev_flush(soc, iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for WDA_DELETE_BSS_REQ timeout", + __func__, tgt_req->vdev_id); + cdp_fc_vdev_unpause(soc, iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma_vdev_clear_pause_bit(tgt_req->vdev_id, PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + + bcn = wma->interfaces[tgt_req->vdev_id].beacon; + + if (bcn) { + WMA_LOGD("%s: Freeing beacon struct %pK, template memory %pK", + __func__, 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[tgt_req->vdev_id].beacon = NULL; + } + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_DELETE_BSS_REQ timedout", __func__); + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_RSP, + (void *)params, 0); + if (iface->del_staself_req && iface->is_del_sta_defered) { + iface->is_del_sta_defered = false; + WMA_LOGA("scheduling defered deletion(vdev id %x)", + tgt_req->vdev_id); + wma_vdev_detach(wma, iface->del_staself_req, 1); + } + } else if (tgt_req->msg_type == WMA_DEL_STA_SELF_REQ) { + struct wma_txrx_node *iface = + (struct wma_txrx_node *)tgt_req->user_data; + struct del_sta_self_params *params = + (struct del_sta_self_params *) iface->del_staself_req; + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + } + params->status = QDF_STATUS_E_TIMEOUT; + + WMA_LOGA("%s: WMA_DEL_STA_SELF_REQ timedout", __func__); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) { + wma_trigger_recovery_assert_on_fw_timeout( + WMA_DEL_STA_SELF_REQ); + } else if (!cds_is_driver_unloading() && + (cds_is_fw_down() || cds_is_driver_recovering())) { + qdf_mem_free(iface->del_staself_req); + iface->del_staself_req = NULL; + } else { + wma_send_del_sta_self_resp(iface->del_staself_req); + iface->del_staself_req = NULL; + } + + wma_vdev_deinit(iface); + qdf_mem_zero(iface, sizeof(*iface)); + wma_vdev_init(iface); + } else if (tgt_req->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams params = (tpAddBssParams) tgt_req->user_data; + + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_ADD_BSS_REQ timedout", __func__); + WMA_LOGD("%s: bssid %pM vdev_id %d", __func__, params->bssId, + tgt_req->vdev_id); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_ADD_BSS_REQ); + if (wma_send_vdev_stop_to_fw(wma, tgt_req->vdev_id)) + WMA_LOGE("%s: Failed to send vdev stop to fw", + __func__); + + wma_remove_peer_on_add_bss_failure(params); + + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, + (void *)params, 0); + QDF_ASSERT(0); + goto free_tgt_req; + + } else if (tgt_req->msg_type == WMA_HIDDEN_SSID_VDEV_RESTART) { + if ((qdf_atomic_read( + &wma->interfaces[tgt_req->vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress)) && + wma_is_vdev_in_ap_mode(wma, tgt_req->vdev_id)) { + + WMA_LOGE("Hidden ssid vdev restart Timed Out; vdev_id: %d, type = %d", + tgt_req->vdev_id, tgt_req->type); + qdf_atomic_set(&wma->interfaces[tgt_req->vdev_id]. + vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + qdf_mem_free(tgt_req->user_data); + } + } else if (tgt_req->msg_type == WMA_SET_LINK_STATE) { + tpLinkStateParams params = + (tpLinkStateParams) tgt_req->user_data; + + peer = cdp_peer_find_by_addr(soc, pdev, params->bssid, &peer_id); + if (peer) { + WMA_LOGP(FL("Deleting peer %pM vdev id %d"), + params->bssid, tgt_req->vdev_id); + wma_remove_peer(wma, params->bssid, tgt_req->vdev_id, + peer, false); + } + if (wma_send_vdev_down_to_fw(wma, tgt_req->vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + tgt_req->vdev_id); + } + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_SET_LINK_STATE timedout vdev %d", __func__, + tgt_req->vdev_id); + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); + } +free_tgt_req: + qdf_mc_timer_destroy(&tgt_req->event_timeout); + qdf_mem_free(tgt_req); +} + +/** + * wma_fill_vdev_req() - fill vdev request + * @wma: wma handle + * @msg_type: message type + * @type: request type + * @params: request params + * @timeout: timeout value + * + * Return: wma_target_req ptr + */ +struct wma_target_req *wma_fill_vdev_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) { + WMA_LOGE("%s: Failed to allocate memory for msg %d vdev %d", + __func__, msg_type, vdev_id); + return NULL; + } + + WMA_LOGD("%s: vdev_id %d msg %d", __func__, vdev_id, msg_type); + qdf_spin_lock_bh(&wma->vdev_respq_lock); + req->vdev_id = vdev_id; + req->msg_type = msg_type; + req->type = type; + req->user_data = params; + status = qdf_list_insert_back(&wma->vdev_resp_queue, &req->node); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGE(FL("Failed add request in queue for vdev_id %d type %d"), + vdev_id, type); + qdf_mem_free(req); + return NULL; + } + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + qdf_mc_timer_init(&req->event_timeout, QDF_TIMER_TYPE_SW, + wma_vdev_resp_timer, req); + qdf_mc_timer_start(&req->event_timeout, timeout); + return req; +} + +/** + * wma_remove_vdev_req() - remove vdev request + * @wma: wma handle + * @vdev_id: vdev id + * @type: type + * + * Return: none + */ +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type) +{ + struct wma_target_req *req_msg; + + req_msg = wma_find_vdev_req(wma, vdev_id, type, true); + if (!req_msg) + return; + + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); +} + +/** + * 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: none + */ +static void +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) +{ + QDF_STATUS ret; + uint32_t slot_time; + struct wma_txrx_node *intr = wma->interfaces; + + /* Beacon Interval setting */ + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_BEACON_INTERVAL, + beaconInterval); + + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_BEACON_INTERVAL"); + 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_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD"); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DTIM_PERIOD, + dtimPeriod); + intr[vdev_id].dtimPeriod = dtimPeriod; + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD"); + + if (!maxTxPower) + WMA_LOGW("Setting Tx power limit to 0"); + WMA_LOGD("Set maxTx pwr [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + maxTxPower); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + maxTxPower); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_TX_PWRLIMIT"); + else + intr[vdev_id].max_tx_power = maxTxPower; + + /* Slot time */ + if (shortSlotTimeSupported) + slot_time = WMI_VDEV_SLOT_TIME_SHORT; + else + slot_time = WMI_VDEV_SLOT_TIME_LONG; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SLOT_TIME, + slot_time); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_SLOT_TIME"); + + /* Initialize protection mode in case of coexistence */ + wma_update_protection_mode(wma, vdev_id, llbCoexist); + +} + +#ifdef WLAN_FEATURE_11W +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_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, ret); + } else { + WMA_LOGD("%s: QOS MFP/PMF set", __func__); + } +} + +/** + * 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_LOGE("Peer of peer_mac %pM not found", + 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_LOGD("set is_pmf_enabled %d for %pM", is_pmf_enabled, peer_mac); + + return QDF_STATUS_SUCCESS; +} +#else +static inline void wma_set_mgmt_frame_protection(tp_wma_handle wma) +{ +} + +static QDF_STATUS +wma_set_peer_pmf_status(tp_wma_handle wma, uint8_t *peer_mac, + bool is_pmf_enabled) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_11W */ + +/** + * wma_add_bss_ap_mode() - process add bss request in ap mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_ap_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + struct wma_vdev_start_req req; + void *peer; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + QDF_STATUS status; + int8_t maxTxPower; + struct policy_mgr_hw_mode_params hw_mode = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wma_txrx_node *iface; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + + vdev = wma_find_vdev_by_addr(wma, add_bss->bssId, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: Failed to get vdev handle:"MAC_ADDRESS_STR, + __func__, MAC_ADDR_ARRAY(add_bss->bssId)); + + goto send_fail_resp; + } + if (SAP_WPS_DISABLED == add_bss->wps_state) + pmo_ucfg_disable_wakeup_event(wma->psoc, vdev_id, + WOW_PROBE_REQ_WPS_IE_EVENT); + wma_set_bss_rate_flags(wma, vdev_id, add_bss); + status = wma_create_peer(wma, pdev, vdev, add_bss->bssId, + WMI_PEER_TYPE_DEFAULT, vdev_id, false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + goto send_fail_resp; + } + + peer = cdp_peer_find_by_addr(soc, pdev, + add_bss->bssId, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->bssId); + goto send_fail_resp; + } + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + + iface = &wma->interfaces[vdev_id]; + + add_bss->staContext.staIdx = cdp_peer_get_local_peer_id(soc, peer); + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + req.dot11_mode = add_bss->dot11_mode; + + if (add_bss->ch_width == CH_WIDTH_10MHZ) + req.is_half_rate = 1; + else if (add_bss->ch_width == CH_WIDTH_5MHZ) + req.is_quarter_rate = 1; + + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; + wma_update_vdev_he_ops(&req, add_bss); + + req.max_txpow = add_bss->maxTxPower; + maxTxPower = add_bss->maxTxPower; + iface->rmfEnabled = add_bss->rmfEnabled; + if (add_bss->rmfEnabled) + wma_set_mgmt_frame_protection(wma); + + req.dot11_mode = add_bss->dot11_mode; + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.beacon_tx_rate = add_bss->beacon_tx_rate; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.oper_mode = BSS_OPERATIONAL_MODE_AP; + req.ssid.length = add_bss->ssId.length; + req.cac_duration_ms = add_bss->cac_duration_ms; + req.dfs_regdomain = add_bss->dfs_regdomain; + if (req.ssid.length > 0) + qdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = policy_mgr_get_current_hw_mode(wma->psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("policy_mgr_get_current_hw_mode failed"); + + if (add_bss->nss == 2) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } + + wma_vdev_set_bss_params(wma, vdev_id, + add_bss->beaconInterval, add_bss->dtimPeriod, + add_bss->shortSlotTimeSupported, + add_bss->llbCoexist, maxTxPower); + + wma_vdev_set_he_bss_params(wma, vdev_id, &req); + return; + +peer_cleanup: + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, false); +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_add_bss_ibss_mode() - process add bss request in IBSS mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_ibss_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + struct wma_vdev_start_req req; + void *peer = NULL; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + QDF_STATUS status; + tSetBssKeyParams key_info; + struct policy_mgr_hw_mode_params hw_mode = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + vdev = wma_find_vdev_by_addr(wma, add_bss->selfMacAddr, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: vdev not found for vdev id %d.", + __func__, vdev_id); + goto send_fail_resp; + } + WMA_LOGD("%s: add_bss->sessionId = %d", __func__, vdev_id); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + wma_set_bss_rate_flags(wma, vdev_id, add_bss); + + /* create ibss bss peer */ + status = wma_create_peer(wma, pdev, vdev, add_bss->selfMacAddr, + WMI_PEER_TYPE_DEFAULT, vdev_id, + false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + goto send_fail_resp; + } + WMA_LOGA("IBSS BSS peer created with mac %pM", + add_bss->selfMacAddr); + + peer = cdp_peer_find_by_addr(soc, pdev, + add_bss->selfMacAddr, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->selfMacAddr); + goto send_fail_resp; + } + + /* clear leftover ibss keys on bss peer */ + + WMA_LOGD("%s: ibss bss key clearing", __func__); + qdf_mem_zero(&key_info, sizeof(key_info)); + key_info.smesessionId = vdev_id; + key_info.numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + qdf_mem_copy(&wma->ibsskey_info, &key_info, sizeof(tSetBssKeyParams)); + + /* start ibss vdev */ + + add_bss->operMode = BSS_OPERATIONAL_MODE_IBSS; + + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + WMA_LOGD("%s: vdev start request for IBSS enqueued", __func__); + + add_bss->staContext.staIdx = cdp_peer_get_local_peer_id(soc, peer); + + /* + * If IBSS Power Save is supported by firmware + * set the IBSS power save params to firmware. + */ + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_ibss_pwrsave)) { + status = wma_set_ibss_pwrsave_params(wma, vdev_id); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to Set IBSS Power Save Params to firmware", + __func__); + goto peer_cleanup; + } + } + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; +#if defined WLAN_FEATURE_VOWIF + req.max_txpow = add_bss->maxTxPower; +#else + req.max_txpow = 0; +#endif /* WLAN_FEATURE_VOWIF */ + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.oper_mode = BSS_OPERATIONAL_MODE_IBSS; + req.ssid.length = add_bss->ssId.length; + if (req.ssid.length > 0) + qdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = policy_mgr_get_current_hw_mode(wma->psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("policy_mgr_get_current_hw_mode failed"); + + if (add_bss->nss == 2) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + WMA_LOGD("%s: chan %d chan_width %d", __func__, req.chan, + req.chan_width); + WMA_LOGD("%s: ssid = %s", __func__, req.ssid.ssId); + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } + WMA_LOGD("%s: vdev start request for IBSS sent to target", __func__); + + /* Initialize protection mode to no protection */ + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PROTECTION_MODE, + IEEE80211_PROT_NONE); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to initialize protection mode"); + + return; + +peer_cleanup: + if (peer) + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, false); +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_add_bss_sta_mode() - process add bss request in sta mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_sta_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + struct cdp_pdev *pdev; + struct wma_vdev_start_req req; + struct wma_target_req *msg; + uint8_t vdev_id = 0, peer_id; + void *peer = NULL; + QDF_STATUS status; + struct wma_txrx_node *iface; + int pps_val = 0; + bool roam_synch_in_progress = false; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + struct policy_mgr_hw_mode_params hw_mode = {0}; + bool peer_assoc_sent = false; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + goto send_fail_resp; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s Failed to get pdev", __func__); + goto send_fail_resp; + } + + vdev_id = add_bss->staContext.smesessionId; + iface = &wma->interfaces[vdev_id]; + + wma_set_bss_rate_flags(wma, vdev_id, add_bss); + if (add_bss->operMode) { + /* Save parameters later needed by WMA_ADD_STA_REQ */ + if (iface->addBssStaContext) + qdf_mem_free(iface->addBssStaContext); + iface->addBssStaContext = qdf_mem_malloc(sizeof(tAddStaParams)); + if (!iface->addBssStaContext) { + WMA_LOGE("%s Failed to allocat memory", __func__); + goto send_fail_resp; + } + qdf_mem_copy(iface->addBssStaContext, &add_bss->staContext, + sizeof(tAddStaParams)); + + if (iface->staKeyParams) { + qdf_mem_free(iface->staKeyParams); + iface->staKeyParams = NULL; + } + if (add_bss->extSetStaKeyParamValid) { + iface->staKeyParams = + qdf_mem_malloc(sizeof(tSetStaKeyParams)); + if (!iface->staKeyParams) { + WMA_LOGE("%s Failed to allocat memory", + __func__); + goto send_fail_resp; + } + qdf_mem_copy(iface->staKeyParams, + &add_bss->extSetStaKeyParam, + sizeof(tSetStaKeyParams)); + } + /* Save parameters later needed by WMA_ADD_STA_REQ */ + iface->rmfEnabled = add_bss->rmfEnabled; + iface->beaconInterval = add_bss->beaconInterval; + iface->llbCoexist = add_bss->llbCoexist; + iface->shortSlotTimeSupported = add_bss->shortSlotTimeSupported; + iface->nwType = add_bss->nwType; + if (add_bss->rmfEnabled) + wma_set_peer_pmf_status(wma, add_bss->bssId, true); + if (add_bss->nonRoamReassoc) { + peer = cdp_peer_find_by_addr(soc, + pdev, add_bss->bssId, + &peer_id); + if (peer) { + add_bss->staContext.staIdx = + cdp_peer_get_local_peer_id(soc, peer); + goto send_bss_resp; + } + } + if (add_bss->reassocReq) { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + struct cdp_vdev *vdev; +#endif + /* Called in preassoc state. BSSID peer is already + * added by set_linkstate + */ + peer = cdp_peer_find_by_addr(soc, + pdev, + add_bss->bssId, + &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->bssId); + goto send_fail_resp; + } + if (wma_is_roam_synch_in_progress(wma, vdev_id)) { + add_bss->staContext.staIdx = + cdp_peer_get_local_peer_id(soc, peer); + WMA_LOGD("LFR3:%s: bssid %pM staIdx %d", + __func__, add_bss->bssId, + add_bss->staContext.staIdx); + return; + } + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, + add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + + add_bss->staContext.staIdx = + cdp_peer_get_local_peer_id(soc, peer); + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + + if (add_bss->ch_width == CH_WIDTH_10MHZ) + req.is_half_rate = 1; + else if (add_bss->ch_width == CH_WIDTH_5MHZ) + req.is_quarter_rate = 1; + + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.max_txpow = add_bss->maxTxPower; + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.ssid.length = add_bss->ssId.length; + req.oper_mode = BSS_OPERATIONAL_MODE_STA; + if (req.ssid.length > 0) + qdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = policy_mgr_get_current_hw_mode(wma->psoc, + &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("policy_mgr_get_current_hw_mode failed"); + + if (add_bss->nss == 2) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s Invalid txrx vdev", __func__); + goto peer_cleanup; + } + cdp_fc_vdev_pause(soc, vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + /* ADD_BSS_RESP will be deferred to completion of + * VDEV_START + */ + return; + } + if (!add_bss->updateBss) + goto send_bss_resp; + /* Update peer state */ + if (add_bss->staContext.encryptType == eSIR_ED_NONE) { + WMA_LOGD("%s: Update peer(%pM) state into auth", + __func__, add_bss->bssId); + cdp_peer_state_update(soc, pdev, add_bss->bssId, + OL_TXRX_PEER_STATE_AUTH); + } else { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + struct cdp_vdev *vdev; +#endif + WMA_LOGD("%s: Update peer(%pM) state into conn", + __func__, add_bss->bssId); + cdp_peer_state_update(soc, pdev, add_bss->bssId, + OL_TXRX_PEER_STATE_CONN); +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + peer = cdp_peer_find_by_addr(soc, pdev, add_bss->bssId, + &peer_id); + if (!peer) { + WMA_LOGE("%s:%d Failed to find peer %pM", + __func__, __LINE__, add_bss->bssId); + goto send_fail_resp; + } + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s Invalid txrx vdev", __func__); + goto peer_cleanup; + } + cdp_fc_vdev_pause(soc, vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + } + + wmi_unified_send_txbf(wma, &add_bss->staContext); + + pps_val = ((pMac->enable5gEBT << 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_LOGE("Failed to send wmi packet power save cmd"); + else + WMA_LOGD("Sent PKT_PWR_SAVE_5G_EBT cmd to target, val = %x, status = %d", + pps_val, status); + status = wma_send_peer_assoc(wma, add_bss->nwType, + &add_bss->staContext); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to send peer assoc status:%d", status); + goto peer_cleanup; + } + peer_assoc_sent = true; + + /* 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); + + 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); + + /* + * Store the bssid in interface table, bssid will + * be used during group key setting sta mode. + */ + qdf_mem_copy(iface->bssid, add_bss->bssId, IEEE80211_ADDR_LEN); + + } +send_bss_resp: + + wma_vdev_set_he_config(wma, vdev_id, add_bss); + if (NULL == cdp_peer_find_by_addr(soc, pdev, add_bss->bssId, + &add_bss->staContext.staIdx)) + add_bss->status = QDF_STATUS_E_FAILURE; + else + add_bss->status = QDF_STATUS_SUCCESS; + add_bss->bssIdx = add_bss->staContext.smesessionId; + qdf_mem_copy(add_bss->staContext.staMac, add_bss->bssId, + sizeof(add_bss->staContext.staMac)); + + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_assoc_conf)) { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + goto send_final_rsp; + } + + /* In case of reassoc, peer assoc cmd will not be sent */ + if (!peer_assoc_sent) + goto send_final_rsp; + + msg = wma_fill_hold_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_PEER_ASSOC_CNF_START, add_bss, + WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGE(FL("Failed to allocate request for vdev_id %d"), + vdev_id); + wma_remove_req(wma, vdev_id, WMA_PEER_ASSOC_CNF_START); + goto peer_cleanup; + } + return; + +send_final_rsp: + WMA_LOGD("%s: opermode %d update_bss %d nw_type %d bssid %pM staIdx %d status %d", + __func__, add_bss->operMode, + add_bss->updateBss, add_bss->nwType, add_bss->bssId, + add_bss->staContext.staIdx, add_bss->status); + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); + return; + +peer_cleanup: + if (peer) + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, + roam_synch_in_progress); +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + if (!wma_is_roam_synch_in_progress(wma, vdev_id)) + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, + (void *)add_bss, 0); +} + +/** + * 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, tpAddBssParams params) +{ + WMA_LOGD("%s: add_bss_param.halPersona = %d", + __func__, params->halPersona); + + switch (params->halPersona) { + + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + wma_add_bss_ap_mode(wma, params); + break; + +#ifdef QCA_IBSS_SUPPORT + case QDF_IBSS_MODE: + wma_add_bss_ibss_mode(wma, params); + break; +#endif + + case QDF_NDI_MODE: + wma_add_bss_ndi_mode(wma, params); + break; + + default: + wma_add_bss_sta_mode(wma, params); + break; + } +} + +/** + * 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; + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + void *peer; + uint8_t peer_id; + QDF_STATUS status; + int32_t ret; + struct wma_txrx_node *iface = NULL; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t mcs_limit, i, j; + uint8_t *rate_pos; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + /* 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; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + iface = &wma->interfaces[add_sta->smesessionId]; + peer = cdp_peer_find_by_addr_and_vdev(soc, pdev, vdev, + add_sta->staMac, &peer_id); + if (peer) { + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + WMA_LOGE("%s: Peer already exists, Deleted peer with peer_addr %pM", + __func__, 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. + */ + peer = cdp_peer_find_by_addr(soc, pdev, + add_sta->staMac, &peer_id); + if (peer) { + WMA_LOGE("%s: My vdev:%pK, but Peer exists on other vdev with peer_addr %pM and peer_id %d", + __func__, vdev, add_sta->staMac, peer_id); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_DEFAULT, add_sta->smesessionId, + false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer for %pM", + __func__, add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = cdp_peer_find_by_addr_and_vdev(soc, pdev, + vdev, + add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE("%s: Failed to find peer handle using peer mac %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, 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 + + if (wlan_cfg_get_int(wma->mac_context, WNI_CFG_SAP_MAX_MCS_DATA, + &mcs_limit) != QDF_STATUS_SUCCESS) { + mcs_limit = WNI_CFG_SAP_MAX_MCS_DATA_STADEF; + } + + if (mcs_limit & CFG_CTRL_MASK) { + WMA_LOGD("%s: set mcs_limit %x", __func__, 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_LOGE(FL("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, peer, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + WMA_LOGE(FL("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; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + goto send_rsp; + } +#ifdef QCA_IBSS_SUPPORT + /* + * In IBSS mode send the peer + * Atim Window length if IBSS + * power save is enabled by the + * firmware. + */ + if (wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId) && + wmi_service_enabled(wma->wmi_handle, + wmi_service_ibss_pwrsave)) { + /* + * If ATIM Window is present in the peer + * beacon then send it to firmware else + * configure Zero ATIM Window length to + * firmware. + */ + if (add_sta->atimIePresent) { + wma_set_peer_param(wma, add_sta->staMac, + WMI_PEER_IBSS_ATIM_WINDOW_LENGTH, + add_sta->peerAtimWindowLength, + add_sta->smesessionId); + } else { + wma_set_peer_param(wma, add_sta->staMac, + WMI_PEER_IBSS_ATIM_WINDOW_LENGTH, + 0, add_sta->smesessionId); + } + } +#endif + 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_LOGE("Failed to set peer uapsd param for %pM", + add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + goto send_rsp; + } + } + + WMA_LOGD("%s: Moving peer %pM to state %d", + __func__, add_sta->staMac, state); + cdp_peer_state_update(soc, pdev, add_sta->staMac, state); + + add_sta->staIdx = cdp_peer_get_local_peer_id(soc, peer); + add_sta->nss = iface->nss; + 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_LOGD(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + return; + } + + WMA_LOGD(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, add_sta->bssId, add_sta->staIdx, + 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) +{ + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + void *peer; + uint8_t peer_id; + QDF_STATUS status; + int32_t ret; + tTdlsPeerStateParams *peerStateParams; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGD("%s: staType: %d, staIdx: %d, updateSta: %d, bssId: %pM, staMac: %pM", + __func__, add_sta->staType, add_sta->staIdx, + add_sta->updateSta, add_sta->bssId, add_sta->staMac); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + if (wma_is_roam_synch_in_progress(wma, add_sta->smesessionId)) { + WMA_LOGE("%s: roaming in progress, reject add sta!", __func__); + 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, vdev, add_sta->bssId); + + WMA_LOGD("%s: addSta, calling wma_create_peer for %pM, vdev_id %hu", + __func__, add_sta->staMac, add_sta->smesessionId); + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_TDLS, + add_sta->smesessionId, false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer for %pM", + __func__, add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = cdp_peer_find_by_addr(soc, pdev, + add_sta->staMac, + &peer_id); + if (!peer) { + WMA_LOGE("%s: addSta, failed to find peer handle for mac %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + cdp_peer_add_last_real_peer(soc, pdev, vdev, &peer_id); + goto send_rsp; + } + + add_sta->staIdx = cdp_peer_get_local_peer_id(soc, peer); + WMA_LOGD("%s: addSta, after calling cdp_local_peer_id, staIdx: %d, staMac: %pM", + __func__, add_sta->staIdx, add_sta->staMac); + + peerStateParams = qdf_mem_malloc(sizeof(tTdlsPeerStateParams)); + if (!peerStateParams) { + WMA_LOGE + ("%s: Failed to allocate memory for peerStateParams for %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_NOMEM; + goto send_rsp; + } + + peerStateParams->peerState = WMI_TDLS_PEER_STATE_PEERING; + peerStateParams->vdevId = add_sta->smesessionId; + qdf_mem_copy(&peerStateParams->peerMacAddr, + &add_sta->staMac, sizeof(tSirMacAddr)); + wma_update_tdls_peer_state(wma, peerStateParams); + } else { + /* its a change sta request * */ + peer = + cdp_peer_find_by_addr(soc, pdev, + add_sta->staMac, + &peer_id); + if (!peer) { + WMA_LOGE("%s: changeSta,failed to find peer handle for mac %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + + cdp_peer_add_last_real_peer(soc, pdev, vdev, &peer_id); + + goto send_rsp; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_assoc_conf)) { + WMA_LOGE(FL("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_LOGE(FL("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, peer, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + WMA_LOGD("%s: changeSta, calling wma_send_peer_assoc", + __func__); + + 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, peer, false); + cdp_peer_add_last_real_peer(soc, pdev, vdev, &peer_id); + 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_LOGD(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, add_sta->bssId, add_sta->staIdx, + 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_LOGD("%s: he_capable is not set for vdev_id:%d", + __func__, 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_LOGE("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 + +/** + * 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) +{ + struct cdp_pdev *pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + void *peer; + struct wma_txrx_node *iface; + int8_t maxTxPower; + int ret = 0; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + struct vdev_up_params param = {0}; + int smps_param; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) { + wma_add_tdls_sta(wma, params); + return; + } +#endif + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Unable to get pdev", __func__); + goto out; + } + + iface = &wma->interfaces[params->smesessionId]; + if (params->staType != STA_ENTRY_SELF) { + WMA_LOGE("%s: unsupported station type %d", + __func__, params->staType); + goto out; + } + peer = cdp_peer_find_by_addr(soc, + pdev, + params->bssId, ¶ms->staIdx); + if (peer == NULL) { + WMA_LOGE("%s: Peer is not present vdev id %d for %pM", __func__, + params->smesessionId, params->bssId); + status = QDF_STATUS_E_FAILURE; + goto out; + } + if (params->nonRoamReassoc) { + cdp_peer_state_update(soc, pdev, 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_LOGE("%s: vdev id %d is already UP for %pM", __func__, + params->smesessionId, params->bssId); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (peer != NULL && + (cdp_peer_state_get(soc, peer) == 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_LOGD("%s: Update peer(%pM) state into auth", + __func__, params->bssId); + cdp_peer_state_update(soc, pdev, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + } else { + WMA_LOGD("%s: Update peer(%pM) state into conn", + __func__, params->bssId); + cdp_peer_state_update(soc, pdev, params->bssId, + OL_TXRX_PEER_STATE_CONN); + } + + if (wma_is_roam_synch_in_progress(wma, 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, pdev, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + qdf_atomic_set(&iface->bss_status, + WMA_BSS_STATUS_STARTED); + iface->aid = params->assocId; + WMA_LOGD("LFR3:statype %d vdev %d aid %d bssid %pM", + params->staType, params->smesessionId, + params->assocId, params->bssId); + return; + } + wmi_unified_send_txbf(wma, params); + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_assoc_conf)) { + WMA_LOGD(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + 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_LOGD(FL("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->staMac, + params->smesessionId, peer, false); + peer_assoc_cnf = false; + goto out; + } + } else { + WMA_LOGD(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + 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, peer, false); + goto out; + } + + if (params->rmfEnabled) + wma_set_mgmt_frame_protection(wma); + + /* + * Set the PTK in 11r mode because we already have it. + */ + if (iface->staKeyParams) { + wma_set_stakey(wma, + (tpSetStaKeyParams) iface->staKeyParams); + } + } + maxTxPower = params->maxTxPower; + wma_vdev_set_bss_params(wma, params->smesessionId, + iface->beaconInterval, iface->dtimPeriod, + iface->shortSlotTimeSupported, + iface->llbCoexist, maxTxPower); + + 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_LOGE("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_LOGE("Unable to enable NAT keepalive for vdev_id:%d", + params->smesessionId); + } + } + + param.vdev_id = params->smesessionId; + param.assoc_id = params->assocId; + if (wma_send_vdev_up_to_fw(wma, ¶m, params->bssId) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to send vdev up cmd: vdev %d bssid %pM", + __func__, params->smesessionId, params->bssId); + policy_mgr_set_do_hw_mode_change_flag( + wma->psoc, false); + status = QDF_STATUS_E_FAILURE; + } else { + wma_set_vdev_mgmt_rate(wma, params->smesessionId); + wma_vdev_set_mlme_state(wma, params->smesessionId, + WLAN_VDEV_S_RUN); + } + + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED); + WMA_LOGD("%s: STA mode (type %d subtype %d) BSS is started", + __func__, iface->type, iface->sub_type); + /* 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 enbaled 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_LOGD("%s: Send SMPS force mode: %d", + __func__, 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)) { + WMA_LOGD("%s: listen interval offload enabled, setting params", + __func__); + status = wma_vdev_set_param(wma->wmi_handle, + params->smesessionId, + WMI_VDEV_PARAM_MAX_LI_OF_MODDTIM, + wma->staMaxLIModDtim); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("can't set MAX_LI for session: %d"), + params->smesessionId); + } + status = wma_vdev_set_param(wma->wmi_handle, + params->smesessionId, + WMI_VDEV_PARAM_DYNDTIM_CNT, + wma->staDynamicDtim); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("can't set DYNDTIM_CNT for session: %d"), + params->smesessionId); + } + status = wma_vdev_set_param(wma->wmi_handle, + params->smesessionId, + WMI_VDEV_PARAM_MODDTIM_CNT, + wma->staModDtim); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("can't set DTIM_CNT for session: %d"), + params->smesessionId); + } + + } else { + WMA_LOGD("%s: listen interval offload is not set", + __func__); + } + + iface->aid = params->assocId; + params->nss = iface->nss; +out: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) + return; + + params->status = status; + WMA_LOGD(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + params->staType, params->smesessionId, + params->assocId, params->bssId, params->staIdx, + params->status); + /* Don't send a response during roam sync operation */ + if (!wma_is_roam_synch_in_progress(wma, 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 cdp_pdev *pdev; + void *peer; + struct wma_target_req *msg; + uint8_t *peer_mac_addr; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS qdf_status; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + peer = cdp_peer_find_by_local_id(soc, + pdev, del_sta->staIdx); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer id %d", + __func__, del_sta->staIdx); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + peer_mac_addr = cdp_peer_get_peer_mac_addr(soc, peer); + + qdf_status = wma_remove_peer(wma, peer_mac_addr, del_sta->smesessionId, + peer, false); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE(FL("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_LOGE(FL("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_LOGD("%s: Sending del rsp to umac (status: %d)", + __func__, 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) +{ + tTdlsPeerStateParams *peerStateParams; + struct wma_target_req *msg; + int status; + + peerStateParams = qdf_mem_malloc(sizeof(tTdlsPeerStateParams)); + if (!peerStateParams) { + WMA_LOGE("%s: Failed to allocate memory for peerStateParams for: %pM", + __func__, del_sta->staMac); + del_sta->status = QDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + + if (wma_is_roam_synch_in_progress(wma, del_sta->smesessionId)) { + WMA_LOGE("%s: roaming in progress, reject del sta!", __func__); + del_sta->status = QDF_STATUS_E_PERM; + qdf_mem_free(peerStateParams); + goto send_del_rsp; + } + + peerStateParams->peerState = WMA_TDLS_PEER_STATE_TEARDOWN; + peerStateParams->vdevId = del_sta->smesessionId; + peerStateParams->resp_reqd = del_sta->respReqd; + qdf_mem_copy(&peerStateParams->peerMacAddr, + &del_sta->staMac, sizeof(tSirMacAddr)); + + WMA_LOGD("%s: sending tdls_peer_state for peer mac: %pM, peerState: %d", + __func__, peerStateParams->peerMacAddr, + peerStateParams->peerState); + + status = wma_update_tdls_peer_state(wma, peerStateParams); + + if (status < 0) { + WMA_LOGE("%s: wma_update_tdls_peer_state returned failure", + __func__); + 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_LOGE(FL("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_LOGD("%s: Sending del rsp to umac (status: %d)", + __func__, 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; + + iface = &wma->interfaces[params->smesessionId]; + iface->uapsd_cached_val = 0; + if (wma_is_roam_synch_in_progress(wma, params->smesessionId)) + return; +#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_LOGD("%s: vdev_id %d status %d", __func__, + params->smesessionId, status); + wma_send_msg_high_priority(wma, WMA_DELETE_STA_RSP, + (void *)params, 0); + } +} + +/** + * 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) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + void *htc_handle; + + htc_handle = lmac_get_htc_hdl(wma->psoc); + if (!htc_handle) { + WMA_LOGE(":%sHTC handle is NULL:%d", __func__, __LINE__); + return; + } + + WMA_LOGD("%s: add_sta->sessionId = %d.", __func__, + add_sta->smesessionId); + WMA_LOGD("%s: add_sta->bssId = %x:%x:%x:%x:%x:%x", __func__, + add_sta->bssId[0], add_sta->bssId[1], add_sta->bssId[2], + add_sta->bssId[3], add_sta->bssId[4], add_sta->bssId[5]); + + if (wma_is_vdev_in_ap_mode(wma, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_AP; + else if (wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_IBSS; + + if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_NDI; + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + wma_add_sta_req_sta_mode(wma, add_sta); + break; + + /* IBSS should share the same code as AP mode */ + case BSS_OPERATIONAL_MODE_IBSS: + case BSS_OPERATIONAL_MODE_AP: + htc_vote_link_up(htc_handle); + wma_add_sta_req_ap_mode(wma, add_sta); + break; + case BSS_OPERATIONAL_MODE_NDI: + wma_add_sta_ndi_mode(wma, add_sta); + break; + } + +#ifdef QCA_IBSS_SUPPORT + /* adjust heart beat thresold timer value for detecting ibss peer + * departure + */ + if (oper_mode == BSS_OPERATIONAL_MODE_IBSS) + wma_adjust_ibss_heart_beat_timer(wma, add_sta->smesessionId, 1); +#endif + +} + +/** + * 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) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + uint8_t smesession_id = del_sta->smesessionId; + bool rsp_requested = del_sta->respReqd; + void *htc_handle; + + htc_handle = lmac_get_htc_hdl(wma->psoc); + if (!htc_handle) { + WMA_LOGE(":%sHTC handle is NULL:%d", __func__, __LINE__); + return; + } + + if (wma_is_vdev_in_ap_mode(wma, smesession_id)) + oper_mode = BSS_OPERATIONAL_MODE_AP; + if (wma_is_vdev_in_ibss_mode(wma, smesession_id)) { + oper_mode = BSS_OPERATIONAL_MODE_IBSS; + WMA_LOGD("%s: to delete sta for IBSS mode", __func__); + } + if (del_sta->staType == STA_ENTRY_NDI_PEER) + oper_mode = BSS_OPERATIONAL_MODE_NDI; + + WMA_LOGD(FL("oper_mode %d"), oper_mode); + + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + wma_delete_sta_req_sta_mode(wma, del_sta); + if (wma_is_roam_synch_in_progress(wma, smesession_id)) { + WMA_LOGD(FL("LFR3: Del STA on vdev_id %d"), + del_sta->smesessionId); + qdf_mem_free(del_sta); + return; + } + if (!rsp_requested) { + WMA_LOGD(FL("vdev_id %d status %d"), + del_sta->smesessionId, del_sta->status); + qdf_mem_free(del_sta); + } + break; + + case BSS_OPERATIONAL_MODE_IBSS: /* IBSS shares AP code */ + case BSS_OPERATIONAL_MODE_AP: + htc_vote_link_down(htc_handle); + 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)) { + WMA_LOGD(FL("vdev_id %d status %d"), + del_sta->smesessionId, del_sta->status); + qdf_mem_free(del_sta); + } else if (!rsp_requested && + (del_sta->status != QDF_STATUS_SUCCESS)) { + WMA_LOGD(FL("Release del_sta mem vdev_id %d status %d"), + del_sta->smesessionId, del_sta->status); + qdf_mem_free(del_sta); + } + break; + case BSS_OPERATIONAL_MODE_NDI: + wma_delete_sta_req_ndi_mode(wma, del_sta); + break; + default: + WMA_LOGE(FL("Incorrect oper mode %d"), oper_mode); + qdf_mem_free(del_sta); + } + +#ifdef QCA_IBSS_SUPPORT + /* adjust heart beat thresold timer value for + * detecting ibss peer departure + */ + if (oper_mode == BSS_OPERATIONAL_MODE_IBSS) + wma_adjust_ibss_heart_beat_timer(wma, smesession_id, -1); +#endif +} + +/** + * wma_delete_bss_ho_fail() - process delete bss request for handoff failure + * @wma: wma handle + * @params: del bss parameters + * + * 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, tpDeleteBssParams params) +{ + struct cdp_pdev *pdev; + void *peer = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t peer_id; + struct cdp_vdev *txrx_vdev = NULL; + struct wma_txrx_node *iface; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s:Unable to get TXRX context", __func__); + goto fail_del_bss_ho_fail; + } + + peer = cdp_peer_find_by_addr(soc, + pdev, + params->bssid, &peer_id); + if (!peer) { + WMA_LOGE("%s: Failed to find peer %pM", __func__, + params->bssid); + status = QDF_STATUS_E_FAILURE; + goto fail_del_bss_ho_fail; + } + + iface = &wma->interfaces[params->smesessionId]; + if (!iface || !iface->handle) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, params->smesessionId); + goto fail_del_bss_ho_fail; + } + qdf_mem_zero(iface->bssid, IEEE80211_ADDR_LEN); + + txrx_vdev = wma_find_vdev_by_id(wma, params->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + status = QDF_STATUS_E_FAILURE; + goto fail_del_bss_ho_fail; + } + + /* Free the allocated stats response buffer for the the session */ + if (iface->stats_rsp) { + qdf_mem_free(iface->stats_rsp); + iface->stats_rsp = 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); + } + + qdf_mem_zero(&iface->ns_offload_req, + sizeof(iface->ns_offload_req)); + qdf_mem_zero(&iface->arp_offload_req, + sizeof(iface->arp_offload_req)); + + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)", + __func__, params->smesessionId); + cdp_fc_vdev_pause(soc, iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma_vdev_set_pause_bit(params->smesessionId, PAUSE_TYPE_HOST); + + cdp_fc_vdev_flush(soc, iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", + __func__, params->smesessionId); + cdp_fc_vdev_unpause(soc, iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma_vdev_clear_pause_bit(params->smesessionId, PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + wma_vdev_set_mlme_state(wma, params->smesessionId, WLAN_VDEV_S_STOP); + params->status = QDF_STATUS_SUCCESS; + if (!iface->peer_count) { + WMA_LOGE("%s: Can't remove peer with peer_addr %pM vdevid %d peer_count %d", + __func__, params->bssid, params->smesessionId, + iface->peer_count); + goto fail_del_bss_ho_fail; + } + + if (peer) { + WMA_LOGD("%s: vdev %pK is detaching peer:%pK peer_addr %pM to vdev_id %d, peer_count - %d", + __func__, txrx_vdev, peer, params->bssid, + params->smesessionId, iface->peer_count); + if (cdp_cfg_get_peer_unmap_conf_support(soc)) + cdp_peer_delete_sync( + soc, peer, + wma_peer_unmap_conf_cb, + 1 << CDP_PEER_DELETE_NO_SPECIAL); + else + cdp_peer_delete(soc, peer, + 1 << CDP_PEER_DELETE_NO_SPECIAL); + wma_remove_objmgr_peer(wma, params->smesessionId, + params->bssid); + } + iface->peer_count--; + + WMA_LOGI("%s: Removed peer %pK with peer_addr %pM vdevid %d peer_count %d", + __func__, peer, params->bssid, params->smesessionId, + iface->peer_count); +fail_del_bss_ho_fail: + params->status = status; + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_HO_FAIL_RSP, + (void *)params, 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) +{ + struct cdp_pdev *pdev; + uint8_t max_wait_iterations = 0; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!wma_is_vdev_valid(session_id)) { + WMA_LOGE("%s: Vdev is not valid: %d", + __func__, session_id); + return; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (pdev == NULL) { + WMA_LOGE("%s: pdev is not valid: %d", + __func__, session_id); + return; + } + max_wait_iterations = + wma->interfaces[session_id].delay_before_vdev_stop / + WMA_TX_Q_RECHECK_TIMER_WAIT; + + while (cdp_get_tx_pending(soc, pdev) && max_wait_iterations) { + WMA_LOGW(FL("Waiting for outstanding packet to drain.")); + qdf_wait_for_event_completion(&wma->tx_queue_empty_event, + WMA_TX_Q_RECHECK_TIMER_WAIT); + max_wait_iterations--; + } +} + +/** + * wma_delete_bss() - process delete bss request from upper layer + * @wma: wma handle + * @params: del bss parameters + * + * Return: none + */ +void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params) +{ + struct cdp_pdev *pdev; + void *peer = NULL; + struct wma_target_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t peer_id; + struct cdp_vdev *txrx_vdev = NULL; + bool roam_synch_in_progress = false; + struct wma_txrx_node *iface; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s:Unable to get TXRX context", __func__); + goto out; + } + if (wma_is_vdev_in_ibss_mode(wma, params->smesessionId)) + /* in rome ibss case, self mac is used to create the bss peer */ + peer = cdp_peer_find_by_addr(soc, + pdev, + wma->interfaces[params->smesessionId].addr, + &peer_id); + else if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, + params->smesessionId)) + /* In ndi case, self mac is used to create the self peer */ + peer = cdp_peer_find_by_addr(soc, pdev, + wma->interfaces[params->smesessionId].addr, + &peer_id); + else + peer = cdp_peer_find_by_addr(soc, pdev, + params->bssid, + &peer_id); + + if (!peer) { + WMA_LOGE("%s: Failed to find peer %pM", __func__, + params->bssid); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_mem_zero(wma->interfaces[params->smesessionId].bssid, + IEEE80211_ADDR_LEN); + + txrx_vdev = wma_find_vdev_by_id(wma, params->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + iface = &wma->interfaces[params->smesessionId]; + if (!iface || !iface->handle) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, params->smesessionId); + goto out; + } + /*Free the allocated stats response buffer for the the session */ + if (iface->stats_rsp) { + qdf_mem_free(iface->stats_rsp); + iface->stats_rsp = 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_op_mode_ibss == cdp_get_opmode(soc, txrx_vdev)) + wma->ibss_started = 0; + + if (wma_is_roam_synch_in_progress(wma, params->smesessionId)) { + roam_synch_in_progress = true; + WMA_LOGD("LFR3:%s: Setting vdev_up to FALSE for session %d", + __func__, params->smesessionId); + wma_vdev_set_mlme_state(wma, params->smesessionId, + WLAN_VDEV_S_STOP); + goto detach_peer; + } + msg = wma_fill_vdev_req(wma, params->smesessionId, WMA_DELETE_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_STOP, params, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d", + __func__, params->smesessionId); + status = QDF_STATUS_E_NOMEM; + goto detach_peer; + } + + WMA_LOGD(FL("Outstanding msdu packets: %d"), + cdp_get_tx_pending(soc, pdev)); + wma_wait_tx_complete(wma, params->smesessionId); + + if (cdp_get_tx_pending(soc, pdev)) { + WMA_LOGW(FL("Outstanding msdu packets before VDEV_STOP : %d"), + cdp_get_tx_pending(soc, pdev)); + } + + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)", + __func__, params->smesessionId); + wma_vdev_set_pause_bit(params->smesessionId, PAUSE_TYPE_HOST); + cdp_fc_vdev_pause(soc, + wma->interfaces[params->smesessionId].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + + if (wma_send_vdev_stop_to_fw(wma, params->smesessionId)) { + WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__); + wma_remove_vdev_req(wma, params->smesessionId, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + status = QDF_STATUS_E_FAILURE; + goto detach_peer; + } + WMA_LOGD("%s: bssid %pM vdev_id %d", + __func__, params->bssid, params->smesessionId); + return; +detach_peer: + wma_remove_peer(wma, params->bssid, params->smesessionId, peer, + roam_synch_in_progress); + if (wma_is_roam_synch_in_progress(wma, params->smesessionId)) + return; + +out: + params->status = status; + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_RSP, (void *)params, 0); +} + +/** + * wma_find_ibss_vdev() - 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 (NULL != intf) { + if (intf[vdev_id].type == type) + return vdev_id; + } + } + + return -EFAULT; +} + +/** + * 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) +{ + struct cdp_vdev *txrx_vdev; + + WMA_LOGD("%s:intra_fwd:vdev(%d) intrabss_dis=%s", + __func__, pdis_intra_fwd->sessionId, + (pdis_intra_fwd->disableintrabssfwd ? "true" : "false")); + + txrx_vdev = wma_handle->interfaces[pdis_intra_fwd->sessionId].handle; + cdp_cfg_vdev_rx_set_intrabss_fwd(cds_get_context(QDF_MODULE_ID_SOC), + txrx_vdev, + pdis_intra_fwd->disableintrabssfwd); +} + +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; +} + +/** + * 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 (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + goto end; + } + + /* Change the beacon interval back to its original value */ + WMA_LOGE("%s: Change beacon interval back to %d", + __func__, 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) { + WMA_LOGE("%s: Failed to allocate memory for beacon_interval_reset_req vdev %d", + __func__, vdev_id); + return -ENOMEM; + } + + WMA_LOGD("%s: vdev_id %d ", __func__, 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_LOGD("%s: set latency level %d, flags flag 0x%x", + __func__, 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_LOGW("Failed to set latency level"); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c new file mode 100644 index 0000000000000000000000000000000000000000..9c2cce96dcbb728c5969e78c215204f8a41342da --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c @@ -0,0 +1,6095 @@ +/* + * 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: 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 "cfg_api.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 "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_nan_datapath.h" +#include +#include "wlan_pmo_ucfg_api.h" +#include +#include "wlan_reg_services_api.h" +#include "wlan_roam_debug.h" +#include + +#ifndef ARRAY_LENGTH +#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) +#endif + +/** + * 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 + + +#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. + */ +#ifdef QCA_SUPPORT_CP_STATS +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 /* QCA_SUPPORT_CP_STATS*/ +static inline void qdf_wma_wow_wakeup_stats_event(tp_wma_handle wma) +{ + QDF_STATUS status; + struct sir_wake_lock_stats stats; + + WLAN_HOST_DIAG_EVENT_DEF(WowStats, + struct host_event_wlan_powersave_wow_stats); + + status = wma_get_wakelock_stats(&stats); + if (QDF_IS_STATUS_ERROR(status)) + return; + qdf_mem_zero(&WowStats, sizeof(WowStats)); + + WowStats.wow_bcast_wake_up_count = + stats.wow_bcast_wake_up_count; + WowStats.wow_ipv4_mcast_wake_up_count = + stats.wow_ipv4_mcast_wake_up_count; + WowStats.wow_ipv6_mcast_wake_up_count = + stats.wow_ipv6_mcast_wake_up_count; + WowStats.wow_ipv6_mcast_ra_stats = + stats.wow_ipv6_mcast_ra_stats; + WowStats.wow_ipv6_mcast_ns_stats = + stats.wow_ipv6_mcast_ns_stats; + WowStats.wow_ipv6_mcast_na_stats = + stats.wow_ipv6_mcast_na_stats; + WowStats.wow_pno_match_wake_up_count = + stats.wow_pno_match_wake_up_count; + WowStats.wow_pno_complete_wake_up_count = + stats.wow_pno_complete_wake_up_count; + WowStats.wow_gscan_wake_up_count = + stats.wow_gscan_wake_up_count; + WowStats.wow_low_rssi_wake_up_count = + stats.wow_low_rssi_wake_up_count; + WowStats.wow_rssi_breach_wake_up_count = + stats.wow_rssi_breach_wake_up_count; + WowStats.wow_icmpv4_count = + stats.wow_icmpv4_count; + WowStats.wow_icmpv6_count = + stats.wow_icmpv6_count; + WowStats.wow_oem_response_wake_up_count = + stats.wow_oem_response_wake_up_count; + + WLAN_HOST_DIAG_EVENT_REPORT(&WowStats, EVENT_WLAN_POWERSAVE_WOW_STATS); +} +#endif /* QCA_SUPPORT_CP_STATS */ +#else +static inline void qdf_wma_wow_wakeup_stats_event(tp_wma_handle wma) +{ + return; +} +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * wma_post_auto_shutdown_msg() - to post auto shutdown event to sme + * + * Return: 0 for success or error code + */ +static int wma_wake_reason_auto_shutdown(void) +{ + tSirAutoShutdownEvtParams *auto_sh_evt; + QDF_STATUS qdf_status; + struct scheduler_msg sme_msg = { 0 }; + + auto_sh_evt = (tSirAutoShutdownEvtParams *) + qdf_mem_malloc(sizeof(tSirAutoShutdownEvtParams)); + if (!auto_sh_evt) { + WMA_LOGE(FL("No Mem")); + return -ENOMEM; + } + + auto_sh_evt->shutdown_reason = + WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY; + sme_msg.type = eWNI_SME_AUTO_SHUTDOWN_IND; + sme_msg.bodyptr = auto_sh_evt; + 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_LOGE("Fail to post eWNI_SME_AUTO_SHUTDOWN_IND msg to SME"); + qdf_mem_free(auto_sh_evt); + return -EINVAL; + } + + return 0; +} +#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(uint8_t vdev_id) +{ + return 0; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/** + * wma_send_snr_request() - send request to fw to get RSSI stats + * @wma_handle: wma handle + * @pGetRssiReq: get RSSI request + * + * Return: QDF status + */ +QDF_STATUS wma_send_snr_request(tp_wma_handle wma_handle, + void *pGetRssiReq) +{ + tAniGetRssiReq *pRssiBkUp = NULL; + + /* command is in progress */ + if (NULL != wma_handle->pGetRssiReq) + return QDF_STATUS_SUCCESS; + + /* create a copy of csrRssiCallback to send rssi value + * after wmi event + */ + if (pGetRssiReq) { + pRssiBkUp = qdf_mem_malloc(sizeof(tAniGetRssiReq)); + if (!pRssiBkUp) { + WMA_LOGE("Failed to alloc memory for tAniGetRssiReq"); + wma_handle->pGetRssiReq = NULL; + return QDF_STATUS_E_NOMEM; + } + pRssiBkUp->sessionId = + ((tAniGetRssiReq *) pGetRssiReq)->sessionId; + pRssiBkUp->rssiCallback = + ((tAniGetRssiReq *) pGetRssiReq)->rssiCallback; + pRssiBkUp->pDevContext = + ((tAniGetRssiReq *) pGetRssiReq)->pDevContext; + wma_handle->pGetRssiReq = (void *)pRssiBkUp; + } + + if (wmi_unified_snr_request_cmd(wma_handle->wmi_handle)) { + WMA_LOGE("Failed to send host stats request to fw"); + qdf_mem_free(pRssiBkUp); + wma_handle->pGetRssiReq = NULL; + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * 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 (NULL == wma_handle) { + WMA_LOGE("%s : Failed to get wma_handle", __func__); + return QDF_STATUS_E_FAULT; + } + + intr = &wma_handle->interfaces[psnr_req->sessionId]; + /* command is in progress */ + if (NULL != intr->psnr_req) { + WMA_LOGE("%s : previous snr request is pending", __func__); + return QDF_STATUS_SUCCESS; + } + + psnr_req_bkp = qdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (!psnr_req_bkp) { + WMA_LOGE("Failed to allocate memory for tAniGetSnrReq"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(psnr_req_bkp, sizeof(tAniGetSnrReq)); + psnr_req_bkp->staId = psnr_req->staId; + 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_LOGE("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; +} + +/** + * 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_LOGE("%s:previous link status request is pending,deleting the new request", + __func__); + qdf_mem_free(pGetLinkStatus); + return; + } + + iface->plink_status_req = pGetLinkStatus; + cmd.session_id = pGetLinkStatus->sessionId; + if (wmi_unified_link_status_req_cmd(wma->wmi_handle, &cmd)) { + WMA_LOGE("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 +/** + * 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 == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + ptsf = qdf_mem_malloc(sizeof(*ptsf)); + if (NULL == ptsf) { + WMA_LOGE("%s: failed to allocate tsf data structure", __func__); + 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_LOGD("%s: receive WMI_VDEV_TSF_REPORT_EVENTID ", __func__); + WMA_LOGD("%s: vdev_id = %u,tsf_low =%u, tsf_high = %u", __func__, + ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high); + + WMA_LOGD("%s,g_tsf: %d %d; soc_timer: %d %d", + __func__, ptsf->global_tsf_low, ptsf->global_tsf_high, + ptsf->soc_timer_low, ptsf->soc_timer_high); + 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)) { + + WMA_LOGP("%s: Failed to post eWNI_SME_TSF_EVENT", __func__); + qdf_mem_free(ptsf); + return -EINVAL; + } + return 0; +} + +#ifdef QCA_WIFI_3_0 +#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 = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for cap tsf cmd", + __func__); + 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_LOGD("%s :vdev_id %u, tsf_cmd: %d", __func__, 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)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; + +error: + if (buf) + 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 = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + uint8_t *buf_ptr; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for reset tsf gpio", + __func__); + 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_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_RESET", __func__, + 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)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + return QDF_STATUS_SUCCESS; + +error: + if (buf) + 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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not set gpio", __func__); + return QDF_STATUS_E_INVAL; + } + + WMA_LOGD("%s: set tsf gpio pin: %d", __func__, pin); + + pdev_param.param_id = WMI_PDEV_PARAM_WNTS_CONFIG; + pdev_param.param_value = pin; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("%s: Failed to set tsf gpio pin (%d)", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#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 = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_wisa_cmd_fixed_param *cmd; + int ret, len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for WISA params", + __func__); + 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)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_WISA_CMDID); + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + return QDF_STATUS_SUCCESS; + +error: + 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; + int status = 0; + wmi_peer_set_param_cmd_fixed_param peer_set_param_fp = {0}; + + if (!wma_handle) { + WMA_LOGE("%s : wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!ta_dhcp_ind) { + WMA_LOGE("%s : DHCP indication is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_find_vdev_by_addr(wma_handle, + ta_dhcp_ind->adapterMacAddr.bytes, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for DHCP indication", + __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: WMA --> WMI_PEER_SET_PARAM triggered by DHCP, msgType=%s, device_mode=%d, macAddr=" MAC_ADDRESS_STR, + __func__, ta_dhcp_ind->msgType == WMA_DHCP_START_IND ? + "WMA_DHCP_START_IND" : "WMA_DHCP_STOP_IND", + ta_dhcp_ind->device_mode, + MAC_ADDR_ARRAY(ta_dhcp_ind->peerMacAddr.bytes)); + + /* fill in values */ + peer_set_param_fp.vdev_id = vdev_id; + peer_set_param_fp.param_id = WMI_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); + + status = wmi_unified_process_dhcp_ind(wma_handle->wmi_handle, + &peer_set_param_fp); + if (status != EOK) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_chan_phy__mode() - get WLAN_PHY_MODE for channel + * @chan: channel number + * @chan_width: maximum channel width possible + * @dot11_mode: maximum phy_mode possible + * + * Return: return WLAN_PHY_MODE + */ +WLAN_PHY_MODE wma_chan_phy_mode(u8 chan, enum phy_ch_width chan_width, + u8 dot11_mode) +{ + WLAN_PHY_MODE phymode = MODE_UNKNOWN; + uint16_t bw_val = wlan_reg_get_bw_value(chan_width); + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + WMA_LOGE("%s : wma_handle is NULL", __func__); + return MODE_UNKNOWN; + } + + if (chan_width >= CH_WIDTH_INVALID) { + WMA_LOGE("%s : Invalid channel width", __func__); + return MODE_UNKNOWN; + } + + if (WLAN_REG_IS_24GHZ_CH(chan)) { + if (((CH_WIDTH_5MHZ == chan_width) || + (CH_WIDTH_10MHZ == chan_width)) && + ((WNI_CFG_DOT11_MODE_11B == dot11_mode) || + (WNI_CFG_DOT11_MODE_11G == dot11_mode) || + (WNI_CFG_DOT11_MODE_11N == dot11_mode) || + (WNI_CFG_DOT11_MODE_ALL == dot11_mode) || + (WNI_CFG_DOT11_MODE_11AC == dot11_mode) || + (WNI_CFG_DOT11_MODE_11AX == dot11_mode))) + phymode = MODE_11G; + else { + switch (dot11_mode) { + case WNI_CFG_DOT11_MODE_11B: + if ((bw_val == 20) || (bw_val == 40)) + phymode = MODE_11B; + break; + case WNI_CFG_DOT11_MODE_11G: + if ((bw_val == 20) || (bw_val == 40)) + phymode = MODE_11G; + break; + case WNI_CFG_DOT11_MODE_11G_ONLY: + if ((bw_val == 20) || (bw_val == 40)) + phymode = MODE_11GONLY; + break; + case WNI_CFG_DOT11_MODE_11N: + case WNI_CFG_DOT11_MODE_11N_ONLY: + if (bw_val == 20) + phymode = MODE_11NG_HT20; + else if (bw_val == 40) + phymode = MODE_11NG_HT40; + break; + case WNI_CFG_DOT11_MODE_ALL: + case WNI_CFG_DOT11_MODE_11AC: + case WNI_CFG_DOT11_MODE_11AC_ONLY: + if (bw_val == 20) + phymode = MODE_11AC_VHT20_2G; + else if (bw_val == 40) + phymode = MODE_11AC_VHT40_2G; + break; +#if SUPPORT_11AX + case WNI_CFG_DOT11_MODE_11AX: + case WNI_CFG_DOT11_MODE_11AX_ONLY: + if (20 == bw_val) + phymode = MODE_11AX_HE20_2G; + else if (40 == bw_val) + phymode = MODE_11AX_HE40_2G; + break; +#endif + default: + break; + } + } + } else if (wlan_reg_is_dsrc_chan(wma->pdev, chan)) + phymode = MODE_11A; + else { + if (((CH_WIDTH_5MHZ == chan_width) || + (CH_WIDTH_10MHZ == chan_width)) && + ((WNI_CFG_DOT11_MODE_11A == dot11_mode) || + (WNI_CFG_DOT11_MODE_11N == dot11_mode) || + (WNI_CFG_DOT11_MODE_ALL == dot11_mode) || + (WNI_CFG_DOT11_MODE_11AC == dot11_mode) || + (WNI_CFG_DOT11_MODE_11AX == dot11_mode))) + phymode = MODE_11A; + else { + switch (dot11_mode) { + case WNI_CFG_DOT11_MODE_11A: + if (0 < bw_val) + phymode = MODE_11A; + break; + case WNI_CFG_DOT11_MODE_11N: + case WNI_CFG_DOT11_MODE_11N_ONLY: + if (bw_val == 20) + phymode = MODE_11NA_HT20; + else if (40 <= bw_val) + phymode = MODE_11NA_HT40; + break; + case WNI_CFG_DOT11_MODE_ALL: + case WNI_CFG_DOT11_MODE_11AC: + case WNI_CFG_DOT11_MODE_11AC_ONLY: + if (bw_val == 20) + phymode = MODE_11AC_VHT20; + else if (bw_val == 40) + phymode = MODE_11AC_VHT40; + else if (bw_val == 80) + phymode = MODE_11AC_VHT80; + else if (chan_width == CH_WIDTH_160MHZ) + phymode = MODE_11AC_VHT160; + else if (chan_width == CH_WIDTH_80P80MHZ) + phymode = MODE_11AC_VHT80_80; + break; +#if SUPPORT_11AX + case WNI_CFG_DOT11_MODE_11AX: + case WNI_CFG_DOT11_MODE_11AX_ONLY: + if (20 == bw_val) + phymode = MODE_11AX_HE20; + else if (40 == bw_val) + phymode = MODE_11AX_HE40; + else if (80 == bw_val) + phymode = MODE_11AX_HE80; + else if (CH_WIDTH_160MHZ == chan_width) + phymode = MODE_11AX_HE160; + else if (CH_WIDTH_80P80MHZ == chan_width) + phymode = MODE_11AX_HE80_80; + break; +#endif + default: + break; + } + } + } + + WMA_LOGD("%s: phymode %d channel %d ch_width %d dot11_mode %d", + __func__, phymode, chan, chan_width, dot11_mode); + + QDF_ASSERT(MODE_UNKNOWN != phymode); + 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, tSirLinkSpeedInfo *pLinkSpeed) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_mac_addr peer_macaddr; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue get link speed cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_estimate_linkspeed)) { + WMA_LOGE("%s: Linkspeed feature bit not enabled Sending value 0 as link speed.", + __func__); + 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_LOGD("%s: pLinkSpeed->peerMacAddr: %pM, peer_macaddr.mac_addr31to0: 0x%x, peer_macaddr.mac_addr47to32: 0x%x", + __func__, pLinkSpeed->peer_macaddr.bytes, + peer_macaddr.mac_addr31to0, + peer_macaddr.mac_addr47to32); + if (wmi_unified_get_link_speed_cmd(wma_handle->wmi_handle, + peer_macaddr)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_get_peer_info(WMA_HANDLE handle, + struct sir_peer_info_req *peer_info_req) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + wmi_request_stats_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue get rssi", + __func__); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(wmi_request_stats_cmd_fixed_param); + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *)wmi_buf_data(wmi_buf); + + cmd = (wmi_request_stats_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_request_stats_cmd_fixed_param)); + + cmd->stats_id = WMI_REQUEST_PEER_STAT; + cmd->vdev_id = peer_info_req->sessionid; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_info_req->peer_macaddr.bytes, + &cmd->peer_macaddr); + wma_handle->get_sta_peer_info = true; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_REQUEST_STATS_CMDID)) { + WMA_LOGE("Failed to send host stats request to fw"); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(&(wma_handle->peer_macaddr), + &(peer_info_req->peer_macaddr), + QDF_MAC_ADDR_SIZE); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_get_peer_info_ext(WMA_HANDLE handle, + struct sir_peer_info_ext_req *peer_info_req) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + wmi_request_peer_stats_info_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue get rssi", + __func__); + return QDF_STATUS_E_INVAL; + } + + WMA_LOGI("%s send WMI_REQUEST_PEER_STATS_INFO_CMDID", __func__); + + len = sizeof(wmi_request_peer_stats_info_cmd_fixed_param); + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *)wmi_buf_data(wmi_buf); + + cmd = (wmi_request_peer_stats_info_cmd_fixed_param *)buf_ptr; + 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->vdev_id = peer_info_req->sessionid; + cmd->request_type = WMI_REQUEST_ONE_PEER_STATS_INFO; + wma_handle->get_one_peer_info = true; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_info_req->peer_macaddr.bytes, + &cmd->peer_macaddr); + cmd->reset_after_request = peer_info_req->reset_after_request; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_REQUEST_PEER_STATS_INFO_CMDID)) { + WMA_LOGE("Failed to send peer stats request to fw"); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s vdev_id %d, mac %pM, req_type %x, reset %x", + __func__, + cmd->vdev_id, + peer_info_req->peer_macaddr.bytes, + cmd->request_type, + cmd->reset_after_request); + + qdf_mem_copy(&(wma_handle->peer_macaddr), + &(peer_info_req->peer_macaddr), + QDF_MAC_ADDR_SIZE); + + 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; + + WMA_LOGD("%s: get isolation", __func__); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue get isolation", + __func__); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(wmi_coex_get_antenna_isolation_cmd_fixed_param); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + 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(wma->wmi_handle, wmi_buf, len, + WMI_COEX_GET_ANTENNA_ISOLATION_CMDID)) { + WMA_LOGE("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; + + 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); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue set beacon filter", + __func__); + 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(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + 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_LOGD("beacon filter ie map = %u", ie_map[i]); + } + + ret = wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_ADD_BCN_FILTER_CMDID); + if (ret) { + WMA_LOGE("Failed to send wmi add beacon filter = %d", + 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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue remove beacon filter", + __func__); + return QDF_STATUS_E_INVAL; + } + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + 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(wma->wmi_handle, buf, len, + WMI_RMV_BCN_FILTER_CMDID); + if (ret) { + WMA_LOGE("Failed to send wmi remove beacon filter = %d", + 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_LOGE("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_LOGD(FL("send timer patter 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_LOGE(FL("Failed to send timer patter to fw")); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * 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) { + WMA_LOGE("%s: WMA is closed", + __func__); + return; + } + + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_wow_wakeup_by_timer_pattern)) { + WMA_LOGD("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_LOGD("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_LOGP("%s: Failed to send CSA offload enable command", + __func__); + return -EIO; + } + + return 0; +} + +#ifdef WLAN_FEATURE_NAN +/** + * wma_nan_rsp_event_handler() - Function is used to handle nan response + * @handle: wma handle + * @event_buf: event buffer + * @len: length of buffer + * + * Return: 0 for success or error code + */ +int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_NAN_EVENTID_param_tlvs *param_buf; + tSirNanEvent *nan_rsp_event; + wmi_nan_event_hdr *nan_rsp_event_hdr; + QDF_STATUS status; + struct scheduler_msg message = {0}; + uint8_t *buf_ptr; + uint32_t alloc_len; + + /* + * This is how received event_buf looks like + * + * <-------------------- event_buf -----------------------------------> + * + * <--wmi_nan_event_hdr--><---WMI_TLV_HDR_SIZE---><----- data --------> + * + * +-----------+---------+-----------------------+--------------------+ + * | tlv_header| data_len| WMITLV_TAG_ARRAY_BYTE | nan_rsp_event_data | + * +-----------+---------+-----------------------+--------------------+ + */ + + WMA_LOGD("%s: Posting NaN response event to SME", __func__); + param_buf = (WMI_NAN_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid nan response event buf", __func__); + return -EINVAL; + } + nan_rsp_event_hdr = param_buf->fixed_param; + buf_ptr = (uint8_t *) nan_rsp_event_hdr; + alloc_len = sizeof(tSirNanEvent); + alloc_len += nan_rsp_event_hdr->data_len; + if (nan_rsp_event_hdr->data_len > ((WMI_SVC_MSG_MAX_SIZE - + WMI_TLV_HDR_SIZE - sizeof(*nan_rsp_event_hdr)) / sizeof(uint8_t)) || + nan_rsp_event_hdr->data_len > param_buf->num_data) { + WMA_LOGE("excess data length:%d, num_data:%d", + nan_rsp_event_hdr->data_len, param_buf->num_data); + return -EINVAL; + } + nan_rsp_event = (tSirNanEvent *) qdf_mem_malloc(alloc_len); + if (NULL == nan_rsp_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return -ENOMEM; + } + + nan_rsp_event->event_data_len = nan_rsp_event_hdr->data_len; + qdf_mem_copy(nan_rsp_event->event_data, buf_ptr + + sizeof(wmi_nan_event_hdr) + WMI_TLV_HDR_SIZE, + nan_rsp_event->event_data_len); + message.type = eWNI_SME_NAN_EVENT; + message.bodyptr = (void *)nan_rsp_event; + message.bodyval = 0; + + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &message); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to post NaN response event to SME", + __func__); + qdf_mem_free(nan_rsp_event); + return -EFAULT; + } + WMA_LOGD("%s: NaN response event Posted to SME", __func__); + return 0; +} +#else +static int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + return 0; +} +#endif /* WLAN_FEATURE_NAN */ + +/** + * 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[IEEE80211_ADDR_LEN]; + uint8_t vdev_id = 0; + uint8_t cur_chan = 0; + struct ieee80211_channelswitch_ie *csa_ie; + struct csa_offload_params *csa_offload_event; + struct ieee80211_extendedchannelswitch_ie *xcsa_ie; + struct ieee80211_ie_wide_bw_switch *wb_ie; + struct wma_txrx_node *intr = wma->interfaces; + + param_buf = (WMI_CSA_HANDLING_EVENTID_param_tlvs *) event; + + WMA_LOGD("%s: Enter", __func__); + if (!param_buf) { + WMA_LOGE("Invalid csa event buffer"); + return -EINVAL; + } + csa_event = param_buf->fixed_param; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->i_addr2, &bssid[0]); + + if (wma_find_vdev_by_bssid(wma, bssid, &vdev_id) == NULL) { + WMA_LOGE("Invalid bssid received %s:%d", __func__, __LINE__); + return -EINVAL; + } + + csa_offload_event = qdf_mem_malloc(sizeof(*csa_offload_event)); + if (!csa_offload_event) { + WMA_LOGE("QDF MEM Alloc Failed for csa_offload_event"); + return -EINVAL; + } + + if (wma->interfaces[vdev_id].roaming_in_progress || + wma->interfaces[vdev_id].roam_synch_in_progress) { + WMA_LOGE("Roaming in progress for vdev %d, ignore csa_offload_event", + vdev_id); + qdf_mem_free(csa_offload_event); + return -EINVAL; + } + + qdf_mem_zero(csa_offload_event, sizeof(*csa_offload_event)); + qdf_mem_copy(csa_offload_event->bssId, &bssid, IEEE80211_ADDR_LEN); + + 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->switch_mode = csa_ie->switchmode; + } 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; + } else { + WMA_LOGE("CSA Event error: No CSA IE present"); + qdf_mem_free(csa_offload_event); + return -EINVAL; + } + + 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_width = wb_ie->new_ch_width; + 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->ies_present_flag = csa_event->ies_present_flag; + + WMA_LOGD("CSA: New Channel = %d BSSID:%pM", + csa_offload_event->channel, csa_offload_event->bssId); + + cur_chan = cds_freq_to_chan(intr[vdev_id].mhz); + /* + * basic sanity check: requested channel should not be 0 + * and equal to home channel + */ + if (0 == csa_offload_event->channel) { + WMA_LOGE("CSA Event with channel %d. Ignore !!", + csa_offload_event->channel); + qdf_mem_free(csa_offload_event); + return -EINVAL; + } + wma->interfaces[vdev_id].is_channel_switch = true; + 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; + tpAniSirGlobal pmac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE(FL("Invalid pmac")); + return -EINVAL; + } + + if (!pmac->sme.oem_data_rsp_callback) { + WMA_LOGE(FL("Callback not registered")); + return -EINVAL; + } + + param_buf = (WMI_OEM_RESPONSE_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE(FL("Received NULL buf ptr from FW")); + return -ENOMEM; + } + + data = param_buf->data; + datalen = param_buf->num_data; + + if (!data) { + WMA_LOGE(FL("Received NULL data from FW")); + return -EINVAL; + } + + if (datalen > OEM_DATA_RSP_SIZE) { + WMA_LOGE(FL("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) { + WMA_LOGE(FL("Failed to alloc oem_data_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) { + WMA_LOGE(FL("malloc failed for data")); + qdf_mem_free(oem_rsp); + return -ENOMEM; + } + } else { + WMA_LOGE(FL("Invalid rsp length: %d"), + oem_rsp->rsp_len); + qdf_mem_free(oem_rsp); + return -EINVAL; + } + + qdf_mem_copy(oem_rsp->data, data, datalen); + + WMA_LOGD("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; +} + +/** + * wma_start_oem_data_req() - start OEM data request to target + * @wma_handle: wma handle + * @oem_data_req: start request params + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle, + struct oem_data_req *oem_data_req) +{ + int ret = 0; + + WMA_LOGD(FL("Send OEM Data Request to target")); + + if (!oem_data_req || !oem_data_req->data) { + WMA_LOGE(FL("oem_data_req is null")); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL("WMA - closed, can not send Oem data request cmd")); + qdf_mem_free(oem_data_req->data); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_start_oem_data_cmd(wma_handle->wmi_handle, + oem_data_req->data_len, + oem_data_req->data); + + if (!QDF_IS_STATUS_SUCCESS(ret)) + WMA_LOGE(FL("wmi cmd send failed")); + + return ret; +} +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +#if !defined(REMOVE_PKT_LOG) +/** + * 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 */ + +/** + * wma_wow_wake_reason_str() - Converts wow wakeup reason code to text format + * @wake_reason - WOW wake reason + * + * Return: reason code in string format + */ +#ifdef WLAN_DEBUG +static const u8 *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_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"; + default: + return "unknown"; + } +} +#endif + +#ifdef QCA_SUPPORT_CP_STATS +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: + return true; + 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_LOGA("WLAN wake reason counters:"); + WMA_LOGA("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_LOGA("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_LOGA("pno_match:%d pno_complete:%d gscan:%d " + "low_rssi:%d rssi_breach:%d oem:%d scan_11d:%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->scan_11d); +} + +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); + 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); +} +#else +/** + * wma_wow_stats_display() - display wow wake up stats + * @stats: per vdev stats counters + * + * Return: none + */ +static void wma_wow_stats_display(struct sir_vdev_wow_stats *stats) +{ + WMA_LOGA("uc %d bc %d v4_mc %d v6_mc %d ra %d ns %d na %d pno_match %d pno_complete %d gscan %d low_rssi %d rssi_breach %d icmp %d icmpv6 %d oem %d", + stats->ucast, + stats->bcast, + stats->ipv4_mcast, + stats->ipv6_mcast, + stats->ipv6_mcast_ra, + stats->ipv6_mcast_ns, + stats->ipv6_mcast_na, + stats->pno_match, + stats->pno_complete, + stats->gscan, + stats->low_rssi, + stats->rssi_breach, + stats->icmpv4, + stats->icmpv6, + stats->oem_response); +} + +static void wma_print_wow_stats(t_wma_handle *wma, + WOW_EVENT_INFO_fixed_param *wake_info) +{ + struct sir_vdev_wow_stats *stats; + + switch (wake_info->wake_reason) { + 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: + break; + default: + return; + } + + stats = &wma->interfaces[wake_info->vdev_id].wow_stats; + wma_wow_stats_display(stats); +} + +/** + * wma_inc_wow_stats() - maintain wow pattern match wake up stats + * @wma: wma handle, containing the stats counters + * @wake_info: the wake event information + * + * Return: none + */ +static void wma_inc_wow_stats(t_wma_handle *wma, + WOW_EVENT_INFO_fixed_param *wake_info) +{ + struct sir_vdev_wow_stats *stats; + + if (wake_info->wake_reason == WOW_REASON_UNSPECIFIED) { + wma->wow_unspecified_wake_count++; + return; + } + + stats = &wma->interfaces[wake_info->vdev_id].wow_stats; + switch (wake_info->wake_reason) { + case WOW_REASON_RA_MATCH: + stats->ipv6_mcast++; + stats->ipv6_mcast_ra++; + stats->icmpv6++; + break; + case WOW_REASON_NLOD: + stats->pno_match++; + break; + case WOW_REASON_NLO_SCAN_COMPLETE: + stats->pno_complete++; + break; + case WOW_REASON_LOW_RSSI: + stats->low_rssi++; + break; + case WOW_REASON_EXTSCAN: + stats->gscan++; + break; + case WOW_REASON_RSSI_BREACH_EVENT: + stats->rssi_breach++; + break; + case WOW_REASON_OEM_RESPONSE_EVENT: + stats->oem_response++; + break; + case WOW_REASON_11D_SCAN: + stats->scan_11d++; + break; + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + stats->pwr_save_fail_detected++; + break; + } +} +#endif + +#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_LOGE("%s: Unknown tag: %d", __func__, tag); + break; + } + + WMA_LOGI("%s: For tag %d WMI event 0x%x", __func__, 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 = WOW_TDLS_CONN_TRACKER_EVENT; + 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; + default: + WMA_LOGD(FL("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: + 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_LOGE("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_LOGD("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_LOGD("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_LOGD("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_LOGD("IPV4 Packet"); + + proto_type = qdf_nbuf_data_get_ipv4_proto(data); + WMA_LOGD("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_LOGD("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_INVALID; + + if (len < WMA_DHCP_SUBTYPE_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + WMA_LOGD("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_LOGD("IPV6 Packet"); + + proto_type = qdf_nbuf_data_get_ipv6_proto(data); + WMA_LOGD("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_LOGD("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_LOGD("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_LOGD("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_LOGD("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_LOGD("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_LOGD("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_LOGD("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_LOGI("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_LOGD("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_LOGD("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_LOGI("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_LOGD("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_LOGD("TCP_seq_num: %u", qdf_cpu_to_be16(seq_num)); +} + +#ifdef QCA_SUPPORT_CP_STATS +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); +} +#else +static void wma_wow_inc_wake_lock_stats_by_dst_addr(t_wma_handle *wma, + uint8_t vdev_id, + uint8_t *dest_mac) +{ + struct wma_txrx_node *vdev; + struct sir_vdev_wow_stats *stats; + + vdev = &wma->interfaces[vdev_id]; + stats = &vdev->wow_stats; + + switch (*dest_mac) { + case WMA_BCAST_MAC_ADDR: + stats->bcast++; + break; + case WMA_MCAST_IPV4_MAC_ADDR: + stats->ipv4_mcast++; + break; + case WMA_MCAST_IPV6_MAC_ADDR: + stats->ipv6_mcast++; + break; + default: + stats->ucast++; + break; + } +} + +static void wma_wow_inc_wake_lock_stats_by_protocol(t_wma_handle *wma, + uint8_t vdev_id, enum qdf_proto_subtype proto_subtype) +{ + struct wma_txrx_node *vdev; + struct sir_vdev_wow_stats *stats; + + vdev = &wma->interfaces[vdev_id]; + stats = &vdev->wow_stats; + + switch (proto_subtype) { + case QDF_PROTO_ICMP_RES: + stats->icmpv4++; + break; + case QDF_PROTO_ICMPV6_REQ: + case QDF_PROTO_ICMPV6_RES: + case QDF_PROTO_ICMPV6_RS: + stats->icmpv6++; + break; + case QDF_PROTO_ICMPV6_RA: + stats->icmpv6++; + stats->ipv6_mcast_ra++; + break; + case QDF_PROTO_ICMPV6_NS: + stats->icmpv6++; + stats->ipv6_mcast_ns++; + break; + case QDF_PROTO_ICMPV6_NA: + stats->icmpv6++; + stats->ipv6_mcast_na++; + break; + default: + break; + } +} +#endif + +/** + * 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_LOGD("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_LOGI("Src_mac: " MAC_ADDRESS_STR ", Dst_mac: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(src_mac), MAC_ADDR_ARRAY(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_LOGI("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_LOGD("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_LOGE("RA: " MAC_ADDRESS_STR " TA: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr1), + MAC_ADDR_ARRAY(wh->i_addr2)); + + WMA_LOGE("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_DSTODS; + + switch (to_from_ds) { + case IEEE80211_NO_DS: + WMA_LOGE("BSSID: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3)); + break; + case IEEE80211_TO_DS: + WMA_LOGE("DA: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3)); + break; + case IEEE80211_FROM_DS: + WMA_LOGE("SA: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3)); + break; + case IEEE80211_DS_TO_DS: + if (buf_len >= sizeof(struct ieee80211_frame_addr4)) + WMA_LOGE("DA: " MAC_ADDRESS_STR " SA: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3), + MAC_ADDR_ARRAY(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_LOGE("SEQ_NUM: %u, FRAG_NUM: %u", + seq_num, frag_num); + } else { + WMA_LOGE("Insufficient buffer length for mgmt. packet"); + } +} + +/** + * wma_acquire_wakelock() - conditionally aquires a wakelock base on wake reason + * @wma: the wma handle with the wakelocks to aquire + * @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; + default: + return; + } + + WMA_LOGA("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_LOGE("AP Assoc Lost event data is null"); + return -EINVAL; + } + + roam_event = event_param->fixed_param; + WMA_LOGA(FL("Beacon miss indication on vdev %d"), roam_event->vdev_id); + + wma_beacon_miss_handler(wma, roam_event->vdev_id, roam_event->rssi); + + return 0; +} + +#ifdef WLAN_DEBUG +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"; + } +} +#endif + +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_LOGE("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_LOGE("Wake event packet is empty"); + return 0; + } + + if (packet_len > (event_param->num_wow_packet_buffer - 4)) { + WMA_LOGE("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; + + 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: + WMA_LOGD("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; + + default: + WMA_LOGE("Wake reason %s(%u) is not a packet event", + wma_wow_wake_reason_str(wake_info->wake_reason), + wake_info->wake_reason); + 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); + + 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; + uint8_t peer_id; + void *peer, *pdev; + tpDeleteStaContext del_sta_ctx; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + /* + * 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_LOGE("Invalid wow packet buffer from firmware %u", + event_param->num_wow_packet_buffer); + return 0; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + bssid = wma->interfaces[event_param->fixed_param->vdev_id].bssid; + peer = cdp_peer_find_by_addr(soc, pdev, bssid, &peer_id); + 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_LOGE("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_LOGD("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_LOGE(FL("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_LOGE(FL("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 = wma_roam_event_callback(wma, pb_event, + pb_event_len); + } else { + /* + * No wow_packet_buffer means a better AP beacon + * will follow in a later event. + */ + WMA_LOGD("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_event_handler(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_LOGE("WOW_REASON_TIMER_INTR_RECV received, indicating key exchange did not finish. Initiate disconnect"); + del_sta_ctx = (tpDeleteStaContext) qdf_mem_malloc( + sizeof(*del_sta_ctx)); + if (!del_sta_ctx) { + WMA_LOGE("%s: mem alloc failed ", __func__); + break; + } + del_sta_ctx->is_tdls = false; + del_sta_ctx->vdev_id = event_param->fixed_param->vdev_id; + del_sta_ctx->staId = peer_id; + qdf_mem_copy(del_sta_ctx->addr2, bssid, IEEE80211_ADDR_LEN); + qdf_mem_copy(del_sta_ctx->bssId, bssid, IEEE80211_ADDR_LEN); + 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; + + default: + WMA_LOGE("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_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_LOGA("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)); + } else if (!wmi_get_runtime_pm_inprogress(wma->wmi_handle)) { + WMA_LOGA("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); +} + +/** + * 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_LOGE("Wake event data is null"); + return -EINVAL; + } + + wake_info = event_param->fixed_param; + + if (wake_info->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, wake_info->vdev_id); + return -EINVAL; + } + + wma_wake_event_log_reason(wma, wake_info); + + pmo_ucfg_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_LOGE("Invalid D0-WOW disable ACK event buffer!"); + return -EINVAL; + } + + resp_data = param_buf->fixed_param; + + pmo_ucfg_psoc_wakeup_host_event_received(wma->psoc); + + WMA_LOGD("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_LOGA("Received PDEV resume event"); + + pmo_ucfg_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, tDelTsParams *msg) +{ + if (wmi_unified_del_ts_cmd(wma->wmi_handle, + msg->sessionId, + TID_TO_WME_AC(msg->userPrio))) { + WMA_LOGP("%s: Failed to send vdev DELTS command", __func__); + } + +#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); +} + +/** + * 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 requestes to firmware in loop for all the ACs with + * active flow. + * + * Return: none + */ +void wma_aggr_qos_req(tp_wma_handle wma, + tAggrAddTsParams *pAggrQosRspMsg) +{ + wmi_unified_aggr_qos_cmd(wma->wmi_handle, + (struct aggr_add_ts_param *)pAggrQosRspMsg); + /* send response to upper layers from here only. */ + wma_send_msg_high_priority(wma, WMA_AGGR_QOS_RSP, pAggrQosRspMsg, 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(tAddTsParams *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; + struct cdp_pdev *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return QDF_STATUS_E_FAILURE; + } + + interval_milliseconds = (req->tsm_interval * 1024) / 1000; + + cdp_tx_set_compute_interval(cds_get_context(QDF_MODULE_ID_SOC), + pdev, + interval_milliseconds); + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS wma_set_tsm_interval(tAddTsParams *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, tAddTsParams *msg) +{ + struct add_ts_param cmd = {0}; + + msg->status = QDF_STATUS_SUCCESS; + if (wma_set_tsm_interval(msg) == QDF_STATUS_SUCCESS) { + + cmd.sme_session_id = msg->sme_session_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->setRICparams == true) + 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, }; + struct cdp_pdev *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + qdf_mem_free(pTsmStatsMsg); + return QDF_STATUS_E_INVAL; + } + + /* get required values from data path APIs */ + cdp_tx_delay(soc, + pdev, + &queue_delay_microsec, + &tx_delay_microsec, tid); + cdp_tx_delay_hist(soc, + pdev, + bin_values, tid); + cdp_tx_packet_count(soc, + pdev, + &packet_count, + &packet_loss_count, tid); + + pTsmRspParams = qdf_mem_malloc(sizeof(*pTsmRspParams)); + if (NULL == pTsmRspParams) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "%s: QDF MEM Alloc Failure", __func__); + QDF_ASSERT(0); + qdf_mem_free(pTsmStatsMsg); + return QDF_STATUS_E_NOMEM; + } + pTsmRspParams->staId = pStats->staId; + 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_cesium_enable_ind() - enables cesium functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_cesium_enable_ind(tp_wma_handle wma) +{ + QDF_STATUS ret; + int32_t vdev_id; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not enable cesium", + __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Send enable cesium command to target */ + WMA_LOGE("Enable cesium in target for vdevId %d ", vdev_id); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_ENABLE_RMC, 1); + if (ret) { + WMA_LOGE("Enable cesium failed for vdevId %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_get_peer_info_req() - sends get peer info cmd to target + * @wma: wma handle + * @preq: get peer info request + * + * Return: QDF status + */ +QDF_STATUS wma_process_get_peer_info_req + (tp_wma_handle wma, tSirIbssGetPeerInfoReqParams *pReq) +{ + int32_t ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + struct cdp_pdev *pdev; + void *peer; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + uint8_t *peer_mac_raw; + wmi_peer_info_req_cmd_fixed_param *p_get_peer_info_cmd; + uint8_t bcast_mac[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff }; + + if (NULL == soc) { + WMA_LOGE("%s: SOC context is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not get peer info", + __func__); + return QDF_STATUS_E_FAILURE; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev context", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (0xFF == pReq->staIdx) { + /*get info for all peers */ + qdf_mem_copy(peer_mac, bcast_mac, IEEE80211_ADDR_LEN); + } else { + /*get info for a single peer */ + peer = cdp_peer_find_by_local_id(soc, + pdev, pReq->staIdx); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer id %d", + __func__, pReq->staIdx); + return QDF_STATUS_E_FAILURE; + } + peer_mac_raw = cdp_peer_get_peer_mac_addr(soc, peer); + if (peer_mac_raw == NULL) { + WMA_LOGE("peer_mac_raw is NULL"); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGE("%s: staIdx %d peer mac: 0x%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x", + __func__, pReq->staIdx, peer_mac_raw[0], + peer_mac_raw[1], peer_mac_raw[2], + peer_mac_raw[3], peer_mac_raw[4], + peer_mac_raw[5]); + qdf_mem_copy(peer_mac, peer_mac_raw, IEEE80211_ADDR_LEN); + } + + len = sizeof(wmi_peer_info_req_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_get_peer_info_cmd = (wmi_peer_info_req_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_get_peer_info_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_info_req_cmd_fixed_param)); + + p_get_peer_info_cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_mac, + &p_get_peer_info_cmd->peer_mac_address); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PEER_INFO_REQ_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("IBSS get peer info cmd sent len: %d, vdev %d command id: %d, status: %d", + len, vdev_id, WMI_PEER_INFO_REQ_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_tx_fail_monitor_ind() - sends tx fail monitor cmd to target + * @wma: wma handle + * @pReq: tx fail monitor command params + * + * Return: QDF status + */ +QDF_STATUS wma_process_tx_fail_monitor_ind(tp_wma_handle wma, + tAniTXFailMonitorInd *pReq) +{ + QDF_STATUS ret; + int32_t vdev_id; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not send fast tx fail monitor indication message to target", + __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Send enable cesium command to target */ + WMA_LOGE("send fast tx fail monitor ind cmd target for vdevId %d val %d", + vdev_id, pReq->tx_fail_count); + + if (pReq->tx_fail_count == 0) + wma->hddTxFailCb = NULL; + else + wma->hddTxFailCb = pReq->txFailIndCallback; + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, + pReq->tx_fail_count); + if (ret) { + WMA_LOGE("tx fail monitor failed for vdevId %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_enable_ind() - enables RMC functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_enable_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_mode_cmd_fixed_param *p_rmc_enable_cmd; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not enable RMC", + __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_mode_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_enable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_enable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_mode_cmd_fixed_param)); + + p_rmc_enable_cmd->vdev_id = vdev_id; + p_rmc_enable_cmd->enable_rmc = WMI_RMC_MODE_ENABLED; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_MODE_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("Enable RMC cmd sent len: %d, vdev %d command id: %d, status: %d", + len, vdev_id, WMI_RMC_SET_MODE_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_disable_ind() - disables rmc functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_disable_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_mode_cmd_fixed_param *p_rmc_disable_cmd; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not disable RMC", + __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_mode_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_disable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_disable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_mode_cmd_fixed_param)); + + p_rmc_disable_cmd->vdev_id = vdev_id; + p_rmc_disable_cmd->enable_rmc = WMI_RMC_MODE_DISABLED; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_MODE_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("Disable RMC cmd sent len: %d, vdev %d command id: %d, status: %d", + len, vdev_id, WMI_RMC_SET_MODE_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_action_period_ind() - sends RMC action period to target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_action_period_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + uint32_t periodicity_msec; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_action_period_cmd_fixed_param *p_rmc_cmd; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == mac) { + WMA_LOGE("%s: MAC mac does not exist", __func__); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not send RMC action period to target", + __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_action_period_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_cmd = (wmi_rmc_set_action_period_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_action_period_cmd_fixed_param)); + + if (wlan_cfg_get_int(mac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + &periodicity_msec) != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get value for RMC action period using default"); + periodicity_msec = WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF; + } + + p_rmc_cmd->vdev_id = vdev_id; + p_rmc_cmd->periodicity_msec = periodicity_msec; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_ACTION_PERIOD_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("RMC action period %d cmd sent len: %d, vdev %d command id: %d, status: %d", + periodicity_msec, len, vdev_id, WMI_RMC_SET_ACTION_PERIOD_CMDID, + ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_add_periodic_tx_ptrn_ind - add periodic tx ptrn + * @handle: wma handle + * @pAddPeriodicTxPtrnParams: tx ptrn params + * + * Retrun: QDF status + */ +QDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn * + pAddPeriodicTxPtrnParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct periodic_tx_pattern *params_ptr; + uint8_t vdev_id; + QDF_STATUS status; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw add pattern cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wma_find_vdev_by_addr(wma_handle, + pAddPeriodicTxPtrnParams->mac_address.bytes, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + pAddPeriodicTxPtrnParams->mac_address.bytes); + return QDF_STATUS_E_INVAL; + } + + params_ptr = qdf_mem_malloc(sizeof(*params_ptr)); + if (!params_ptr) { + WMA_LOGE("%s: unable to allocate memory for periodic_tx_pattern", + __func__); + return QDF_STATUS_E_NOMEM; + } + + params_ptr->ucPtrnId = pAddPeriodicTxPtrnParams->ucPtrnId; + params_ptr->ucPtrnSize = pAddPeriodicTxPtrnParams->ucPtrnSize; + params_ptr->usPtrnIntervalMs = + pAddPeriodicTxPtrnParams->usPtrnIntervalMs; + qdf_mem_copy(¶ms_ptr->mac_address, + &pAddPeriodicTxPtrnParams->mac_address, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params_ptr->ucPattern, + pAddPeriodicTxPtrnParams->ucPattern, + params_ptr->ucPtrnSize); + + status = wmi_unified_process_add_periodic_tx_ptrn_cmd( + wma_handle->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 + * + * Retrun: 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; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue Del Pattern cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wma_find_vdev_by_addr(wma_handle, + pDelPeriodicTxPtrnParams->mac_address.bytes, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + pDelPeriodicTxPtrnParams->mac_address.bytes); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_process_del_periodic_tx_ptrn_cmd( + wma_handle->wmi_handle, vdev_id, + pDelPeriodicTxPtrnParams->ucPtrnId); +} + +#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) +{ + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + struct stats_ext_params *params; + size_t params_len; + QDF_STATUS status; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + params_len = sizeof(*params) + preq->request_data_len; + params = qdf_mem_malloc(params_len); + + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + 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); + + 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_LOGD("Posting ready to suspend indication to umac"); + + len = sizeof(tSirReadyToExtWoWInd); + ready_to_extwow = (tSirReadyToExtWoWInd *) qdf_mem_malloc(len); + + if (NULL == ready_to_extwow) { + WMA_LOGE("%s: Memory allocation failure", __func__); + 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) { + WMA_LOGE("Failed to post ready to suspend"); + 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_LOGE("%s: wma handle is NULL", __func__); + 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_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__); + 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_LOGE("%s: wma handle is NULL", __func__); + 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_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, + __LINE__); + 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_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, + __LINE__); + return -EINVAL; + } + + WMA_LOGD("%s:%d: Auto Shutdown Evt: %d", __func__, __LINE__, + wmi_auto_sh_evt->shutdown_reason); + return wma_post_auto_shutdown_msg(); +} + +/** + * wma_set_auto_shutdown_timer_req() - sets auto shutdown timer in firmware + * @wma: wma handle + * @auto_sh_cmd: auto shutdown timer value + * + * Return: QDF status + */ +QDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + tSirAutoShutdownCmdParams * + auto_sh_cmd) +{ + if (auto_sh_cmd == NULL) { + WMA_LOGE("%s : Invalid Autoshutdown cfg cmd", __func__); + 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 WLAN_FEATURE_NAN +/** + * wma_nan_req() - to send nan request to target + * @wma: wma_handle + * @nan_req: request data which will be non-null + * + * Return: QDF status + */ +QDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ptr; + struct nan_req_params *params; + size_t params_len; + QDF_STATUS status; + + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + params_len = sizeof(*params) + nan_req->request_data_len; + params = qdf_mem_malloc(params_len); + + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_data_len = nan_req->request_data_len; + if (params->request_data_len > 0) + qdf_mem_copy(params->request_data, nan_req->request_data, + params->request_data_len); + + status = wmi_unified_nan_req_cmd(wma_handle->wmi_handle, params); + qdf_mem_free(params); + + return status; +} +#endif /* WLAN_FEATURE_NAN */ + +#ifdef DHCP_SERVER_OFFLOAD +/** + * wma_process_dhcpserver_offload() - enable DHCP server offload + * @wma_handle: wma handle + * @pDhcpSrvOffloadInfo: DHCP server offload info + * + * Return: 0 for success or error code + */ +QDF_STATUS wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + tSirDhcpSrvOffloadInfo * + pDhcpSrvOffloadInfo) +{ + struct dhcp_offload_info_params params = {0}; + QDF_STATUS status; + + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return -EIO; + } + + params.vdev_id = pDhcpSrvOffloadInfo->vdev_id; + params.dhcp_offload_enabled = + pDhcpSrvOffloadInfo->dhcpSrvOffloadEnabled; + params.dhcp_client_num = pDhcpSrvOffloadInfo->dhcpClientNum; + params.dhcp_srv_addr = pDhcpSrvOffloadInfo->dhcpSrvIP; + + status = wmi_unified_process_dhcpserver_offload_cmd( + wma_handle->wmi_handle, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("Set dhcp server offload to vdevId %d", + pDhcpSrvOffloadInfo->vdev_id); + 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; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue cmd")); + return QDF_STATUS_E_INVAL; + } + if (!flashing) { + WMA_LOGE(FL("invalid parameter: flashing")); + return QDF_STATUS_E_INVAL; + } + status = wmi_unified_set_led_flashing_cmd(wma_handle->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_LOGD(FL("handle:%pK event:%pK len:%u"), handle, event, len); + + wma_handle = handle; + if (!wma_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL 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_LOGE(FL("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; + + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + if (ch_avoid_update_req == NULL) { + WMA_LOGE("%s : ch_avoid_update_req is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: WMA --> WMI_CHAN_AVOID_UPDATE", __func__); + + status = wmi_unified_process_ch_avoid_update_cmd( + wma_handle->wmi_handle); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("%s: WMA --> WMI_CHAN_AVOID_UPDATE sent through WMI", + __func__); + return status; +} +#endif + +/** + * 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) +{ + 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_LOGD("reg_dmn: %d regdmn2g: %d regdmn5g :%d ctl2g: %d ctl5g: %d", + reg_dmn, regdmn2G, regdmn5G, ctl2G, ctl5G); + + if (NULL == wma) { + WMA_LOGE("%s: wma context is NULL", __func__); + 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_LOGE("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_set_tdls_offchan_mode() - set tdls off channel mode + * @handle: wma handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: 0 on success; Negative errno otherwise + */ +QDF_STATUS wma_set_tdls_offchan_mode(WMA_HANDLE handle, + tdls_chan_switch_params *chan_switch_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct tdls_channel_switch_params params = {0}; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL( + "WMA is closed, can not issue tdls off channel cmd" + )); + ret = -EINVAL; + goto end; + } + + if (wma_is_roam_synch_in_progress(wma_handle, + chan_switch_params->vdev_id)) { + WMA_LOGE("%s: roaming in progress, reject offchan mode cmd!", + __func__); + ret = -EPERM; + goto end; + } + + params.vdev_id = chan_switch_params->vdev_id; + params.tdls_off_ch_bw_offset = + chan_switch_params->tdls_off_ch_bw_offset; + params.tdls_off_ch = chan_switch_params->tdls_off_ch; + params.tdls_sw_mode = chan_switch_params->tdls_sw_mode; + params.oper_class = chan_switch_params->oper_class; + params.is_responder = chan_switch_params->is_responder; + qdf_mem_copy(params.peer_mac_addr, chan_switch_params->peer_mac_addr, + IEEE80211_ADDR_LEN); + + ret = wmi_unified_set_tdls_offchan_mode_cmd(wma_handle->wmi_handle, + ¶ms); + +end: + if (chan_switch_params) + qdf_mem_free(chan_switch_params); + return ret; +} + +/** + * wma_update_tdls_peer_state() - update TDLS peer state + * @handle: wma handle + * @peerStateParams: TDLS peer state params + * + * Return: 0 for success or error code + */ +int wma_update_tdls_peer_state(WMA_HANDLE handle, + tTdlsPeerStateParams *peerStateParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint32_t i; + struct cdp_pdev *pdev; + uint8_t peer_id; + void *peer; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t *peer_mac_addr; + int ret = 0; + uint32_t *ch_mhz = NULL; + bool restore_last_peer = false; + QDF_STATUS qdf_status; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + ret = -EINVAL; + goto end_tdls_peer_state; + } + + if (!soc) { + WMA_LOGE("%s: SOC context is NULL", __func__); + ret = -EINVAL; + goto end_tdls_peer_state; + } + + if (wma_is_roam_synch_in_progress(wma_handle, + peerStateParams->vdevId)) { + WMA_LOGE("%s: roaming in progress, reject peer update cmd!", + __func__); + ret = -EPERM; + goto end_tdls_peer_state; + } + + /* peer capability info is valid only when peer state is connected */ + if (WMA_TDLS_PEER_STATE_CONNECTED != peerStateParams->peerState) { + qdf_mem_zero(&peerStateParams->peerCap, + sizeof(tTdlsPeerCapParams)); + } + + if (peerStateParams->peerCap.peerChanLen) { + ch_mhz = qdf_mem_malloc(sizeof(uint32_t) * + peerStateParams->peerCap.peerChanLen); + if (ch_mhz == NULL) { + WMA_LOGE("%s: memory allocation failed", __func__); + ret = -ENOMEM; + goto end_tdls_peer_state; + } + } + + for (i = 0; i < peerStateParams->peerCap.peerChanLen; ++i) { + ch_mhz[i] = + cds_chan_to_freq(peerStateParams->peerCap.peerChan[i]. + chanId); + } + + /* Make sure that peer exists before sending peer state cmd*/ + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + ret = -EIO; + goto end_tdls_peer_state; + } + + peer = cdp_peer_find_by_addr(soc, + pdev, + peerStateParams->peerMacAddr, + &peer_id); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer mac %pM", + __func__, peerStateParams->peerMacAddr); + ret = -EIO; + goto end_tdls_peer_state; + } + + if (wmi_unified_update_tdls_peer_state_cmd(wma_handle->wmi_handle, + (struct tdls_peer_state_params *)peerStateParams, + ch_mhz)) { + WMA_LOGE("%s: failed to send tdls peer update state command", + __func__); + ret = -EIO; + goto end_tdls_peer_state; + } + + /* in case of teardown, remove peer from fw */ + if (WMA_TDLS_PEER_STATE_TEARDOWN == peerStateParams->peerState) { + peer_mac_addr = cdp_peer_get_peer_mac_addr(soc, peer); + if (peer_mac_addr == NULL) { + WMA_LOGE("peer_mac_addr is NULL"); + ret = -EIO; + goto end_tdls_peer_state; + } + + restore_last_peer = cdp_peer_is_vdev_restore_last_peer( + soc, peer); + + WMA_LOGD("%s: calling wma_remove_peer for peer " MAC_ADDRESS_STR + " vdevId: %d", __func__, + MAC_ADDR_ARRAY(peer_mac_addr), + peerStateParams->vdevId); + qdf_status = wma_remove_peer(wma_handle, peer_mac_addr, + peerStateParams->vdevId, peer, false); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE(FL("wma_remove_peer failed")); + ret = -EINVAL; + goto end_tdls_peer_state; + } + cdp_peer_update_last_real_peer(soc, + pdev, peer, &peer_id, + restore_last_peer); + } + +end_tdls_peer_state: + if (ch_mhz) + qdf_mem_free(ch_mhz); + if (peerStateParams) + qdf_mem_free(peerStateParams); + return ret; +} +#endif /* FEATURE_WLAN_TDLS */ + + +/* + * 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}; + int ret; + + if (!ie_info || !wma) { + WMA_LOGE(FL("input pointer is NULL")); + return QDF_STATUS_E_FAILURE; + } + + /* Validate the input */ + if (ie_info->length <= 0) { + WMA_LOGE(FL("Invalid IE length")); + return QDF_STATUS_E_INVAL; + } + + if (ie_info->vdev_id >= wma->max_bssid) { + WMA_LOGE(FL("Invalid vdev_id: %d"), ie_info->vdev_id); + return QDF_STATUS_E_INVAL; + } + + interface = &wma->interfaces[ie_info->vdev_id]; + if (!wma_is_vdev_valid(ie_info->vdev_id)) { + WMA_LOGE(FL("vdev_id: %d is not active"), ie_info->vdev_id); + return QDF_STATUS_E_INVAL; + } + + 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_LOGD(FL("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); + + ret = wmi_unified_process_set_ie_info_cmd(wma->wmi_handle, + &cmd); + return ret; +} + +#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; + tpAniSirGlobal pmac = (tpAniSirGlobal)cds_get_context( + QDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE("%s: Invalid pmac", __func__); + return -EINVAL; + } + if (!pmac->sme.apf_get_offload_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + 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) { + WMA_LOGP("%s: Memory allocation failed.", __func__); + 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_LOGD("%s: APF capabilities version: %d max apf filter size: %d", + __func__, apf_get_offload->apf_version, + apf_get_offload->max_bytes_for_apf_inst); + + WMA_LOGD("%s: sending apf capabilities event to hdd", __func__); + 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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue get APF capab")); + return QDF_STATUS_E_INVAL; + } + + if (!wmi_service_enabled(wma->wmi_handle, wmi_service_apf_offload)) { + WMA_LOGE(FL("APF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + 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(wma->wmi_handle, wmi_buf, len, + WMI_BPF_GET_CAPABILITY_CMDID)) { + WMA_LOGE(FL("Failed to send APF capability command")); + 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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue set APF capability", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_apf_offload)) { + WMA_LOGE(FL("APF offload feature Disabled")); + return QDF_STATUS_E_NOSUPPORT; + } + + if (!apf_set_offload) { + WMA_LOGE("%s: Invalid APF instruction request", __func__); + return QDF_STATUS_E_INVAL; + } + + if (apf_set_offload->session_id >= wma->max_bssid) { + WMA_LOGE(FL("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_LOGE("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(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + 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(wma->wmi_handle, wmi_buf, len, + WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID)) { + WMA_LOGE(FL("Failed to send config apf instructions command")); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGD(FL("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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue get APF capab")); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("APF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + status = wmi_unified_send_apf_enable_cmd(wma->wmi_handle, vdev_id, + apf_enable); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to send apf enable/disable cmd"); + return QDF_STATUS_E_FAILURE; + } + + if (apf_enable) + WMA_LOGD("Sent APF Enable on vdevid: %d", vdev_id); + else + WMA_LOGD("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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue write APF mem")); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("APF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_send_apf_write_work_memory_cmd(wma->wmi_handle, + write_params)) { + WMA_LOGE(FL("Failed to send APF write mem command")); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Sent APF wite 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; + tpAniSirGlobal pmac = cds_get_context(QDF_MODULE_ID_PE); + + WMA_LOGD(FL("handle:%pK event:%pK len:%u"), handle, evt_buf, len); + + wma_handle = handle; + if (!wma_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return -EINVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL wmi_handle")); + return -EINVAL; + } + + if (!pmac) { + WMA_LOGE(FL("Invalid pmac")); + return -EINVAL; + } + + if (!pmac->sme.apf_read_mem_cb) { + WMA_LOGE(FL("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_LOGE(FL("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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue read APF memory")); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("APF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_send_apf_read_work_memory_cmd(wma->wmi_handle, + read_params)) { + WMA_LOGE(FL("Failed to send APF read memory command")); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Sent APF read memory on vdevid: %d", read_params->vdev_id); + return status; +} +#endif /* FEATURE_WLAN_APF */ + +/** + * wma_set_tx_rx_aggregation_size() - sets tx rx aggregation sizes + * @tx_rx_aggregation_size: aggregation size parameters + * + * This function sets tx rx aggregation sizes + * + * Return: VOS_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_tx_rx_aggregation_size( + struct sir_set_tx_rx_aggregation_size *tx_rx_aggregation_size) +{ + tp_wma_handle wma_handle; + 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 (!tx_rx_aggregation_size) { + WMA_LOGE("%s: invalid pointer", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + 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 = tx_rx_aggregation_size->vdev_id; + cmd->tx_aggr_size = tx_rx_aggregation_size->tx_aggregation_size; + cmd->rx_aggr_size = tx_rx_aggregation_size->rx_aggregation_size; + /* bit 2 (aggr_type): TX Aggregation Type (0=A-MPDU, 1=A-MSDU) */ + if (tx_rx_aggregation_size->aggr_type == + WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU) + cmd->enable_bitmap |= 0x04; + + WMA_LOGD("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) { + WMA_LOGE("%s: Failed to send aggregation size command", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_set_tx_rx_aggregation_size_per_ac( + struct sir_set_tx_rx_aggregation_size *tx_rx_aggregation_size) +{ + tp_wma_handle wma_handle; + 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]; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!tx_rx_aggregation_size) { + WMA_LOGE("%s: invalid pointer", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return QDF_STATUS_E_INVAL; + } + + tx_aggr_size[0] = tx_rx_aggregation_size->tx_aggregation_size_be; + tx_aggr_size[1] = tx_rx_aggregation_size->tx_aggregation_size_bk; + tx_aggr_size[2] = tx_rx_aggregation_size->tx_aggregation_size_vi; + tx_aggr_size[3] = tx_rx_aggregation_size->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) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + 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 = tx_rx_aggregation_size->vdev_id; + cmd->rx_aggr_size = + tx_rx_aggregation_size->rx_aggregation_size; + + cmd->tx_aggr_size = tx_aggr_size[queue_num]; + /* 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 (tx_rx_aggregation_size->aggr_type == + WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU) + cmd->enable_bitmap |= 0x04; + + WMA_LOGD("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) { + WMA_LOGE("%s: Failed to send aggregation size command", + __func__); + 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_sw_retry_threshold_per_ac( + WMA_HANDLE handle, + struct sir_set_tx_sw_retry_threshold *tx_sw_retry_threshold) +{ + QDF_STATUS ret; + tp_wma_handle wma_handle; + uint8_t vdev_id; + int retry_type, queue_num; + uint32_t tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_MAX][WMI_AC_MAX]; + uint32_t sw_retry; + + wma_handle = (tp_wma_handle)handle; + + if (!tx_sw_retry_threshold) { + wma_err("%s: invalid pointer", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle) { + wma_err("%s: WMA context is invalid!", __func__); + return QDF_STATUS_E_INVAL; + } + + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_BE] = + tx_sw_retry_threshold->tx_aggr_sw_retry_threshold_be; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_BK] = + tx_sw_retry_threshold->tx_aggr_sw_retry_threshold_bk; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_VI] = + tx_sw_retry_threshold->tx_aggr_sw_retry_threshold_vi; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_VO] = + tx_sw_retry_threshold->tx_aggr_sw_retry_threshold_vo; + + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_BE] = + tx_sw_retry_threshold->tx_non_aggr_sw_retry_threshold_be; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_BK] = + tx_sw_retry_threshold->tx_non_aggr_sw_retry_threshold_bk; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_VI] = + tx_sw_retry_threshold->tx_non_aggr_sw_retry_threshold_vi; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_VO] = + tx_sw_retry_threshold->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; + + vdev_id = tx_sw_retry_threshold->vdev_id; + 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; +} + +/** + * wma_p2p_lo_start() - P2P listen offload start + * @params: p2p listen offload parameters + * + * This function sends WMI command to start P2P listen offload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_p2p_lo_start(struct sir_p2p_lo_start *params) +{ + wmi_buf_t buf; + wmi_p2p_lo_start_cmd_fixed_param *cmd; + int32_t len = sizeof(*cmd); + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint8_t *buf_ptr; + int ret; + int device_types_len_aligned, probe_resp_len_aligned; + + if (NULL == wma) { + WMA_LOGE("%s: wma context is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + device_types_len_aligned = qdf_roundup(params->dev_types_len, + sizeof(A_UINT32)); + probe_resp_len_aligned = qdf_roundup(params->probe_resp_len, + sizeof(A_UINT32)); + + len += 2 * WMI_TLV_HDR_SIZE + device_types_len_aligned + + probe_resp_len_aligned; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for p2p lo start", + __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_p2p_lo_start_cmd_fixed_param *)wmi_buf_data(buf); + buf_ptr = (uint8_t *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_lo_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_p2p_lo_start_cmd_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->ctl_flags = params->ctl_flags; + cmd->channel = params->freq; + cmd->period = params->period; + cmd->interval = params->interval; + cmd->count = params->count; + cmd->device_types_len = params->dev_types_len; + cmd->prob_resp_len = params->probe_resp_len; + + buf_ptr += sizeof(wmi_p2p_lo_start_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + device_types_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, params->device_types, params->dev_types_len); + + buf_ptr += device_types_len_aligned; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, probe_resp_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, params->probe_resp_tmplt, params->probe_resp_len); + + WMA_LOGI("%s: Sending WMI_P2P_LO_START command, channel=%d, period=%d, interval=%d, count=%d", + __func__, cmd->channel, cmd->period, + cmd->interval, cmd->count); + + ret = wmi_unified_cmd_send(wma->wmi_handle, + buf, len, + WMI_P2P_LISTEN_OFFLOAD_START_CMDID); + if (ret) { + WMA_LOGE("Failed to send p2p lo start: %d", ret); + wmi_buf_free(buf); + } + + WMA_LOGI("%s: Successfully sent WMI_P2P_LO_START", __func__); + wma->interfaces[params->vdev_id].p2p_lo_in_progress = true; + + return ret; +} + +/** + * wma_p2p_lo_stop() - P2P listen offload stop + * @vdev_id: vdev identifier + * + * This function sends WMI command to stop P2P listen offload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_p2p_lo_stop(u_int32_t vdev_id) +{ + wmi_buf_t buf; + wmi_p2p_lo_stop_cmd_fixed_param *cmd; + int32_t len; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + int ret; + + if (NULL == wma) { + WMA_LOGE("%s: wma context is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for p2p lo stop", + __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_p2p_lo_stop_cmd_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_lo_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_p2p_lo_stop_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + + WMA_LOGI("%s: Sending WMI_P2P_LO_STOP command", __func__); + + ret = wmi_unified_cmd_send(wma->wmi_handle, + buf, len, + WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID); + if (ret) { + WMA_LOGE("Failed to send p2p lo stop: %d", ret); + wmi_buf_free(buf); + } + + WMA_LOGI("%s: Successfully sent WMI_P2P_LO_STOP", __func__); + wma->interfaces[vdev_id].p2p_lo_in_progress = false; + + return ret; +} + +/** + * wma_p2p_lo_event_handler() - p2p lo event + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * This function receives P2P listen offload stop event from FW and + * pass the event information to upper layer. + * + * Return: 0 on success + */ +int wma_p2p_lo_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct sir_p2p_lo_event *event; + WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID_param_tlvs *param_tlvs; + wmi_p2p_lo_stopped_event_fixed_param *fix_param; + tpAniSirGlobal p_mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!wma) { + WMA_LOGE("%s: Invalid WMA Context", __func__); + return -EINVAL; + } + + if (!p_mac) { + WMA_LOGE("%s: Invalid p_mac", __func__); + return -EINVAL; + } + + if (!p_mac->sme.p2p_lo_event_callback) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID_param_tlvs *) + event_buf; + fix_param = param_tlvs->fixed_param; + if (fix_param->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, fix_param->vdev_id); + return -EINVAL; + } + event = qdf_mem_malloc(sizeof(*event)); + if (event == NULL) { + WMA_LOGE("Event allocation failed"); + return -ENOMEM; + } + event->vdev_id = fix_param->vdev_id; + event->reason_code = fix_param->reason; + + p_mac->sme.p2p_lo_event_callback(p_mac->sme.p2p_lo_event_context, + event); + + wma->interfaces[event->vdev_id].p2p_lo_in_progress = false; + + return 0; +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * wma_get_wakelock_stats() - Populates wake lock stats + * @stats: non-null wakelock structure to populate + * + * This function collects wake lock stats + * + * Return: QDF_STATUS_SUCCESS on success, error value otherwise + */ +QDF_STATUS wma_get_wakelock_stats(struct sir_wake_lock_stats *stats) +{ + t_wma_handle *wma; + struct sir_vdev_wow_stats *vstats; + int i; + + if (!stats) { + WMA_LOGE("%s: invalid stats pointer", __func__); + return QDF_STATUS_E_INVAL; + } + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: invalid WMA context", __func__); + return QDF_STATUS_E_INVAL; + } + + /* ensure counters are zeroed */ + qdf_mem_zero(stats, sizeof(*stats)); + + /* populate global level stats */ + stats->wow_unspecified_wake_up_count = wma->wow_unspecified_wake_count; + + /* populate vdev level stats */ + for (i = 0; i < wma->max_bssid; ++i) { + if (!wma->interfaces[i].handle) + continue; + + vstats = &wma->interfaces[i].wow_stats; + + stats->wow_ucast_wake_up_count += vstats->ucast; + stats->wow_bcast_wake_up_count += vstats->bcast; + stats->wow_ipv4_mcast_wake_up_count += vstats->ipv4_mcast; + stats->wow_ipv6_mcast_wake_up_count += vstats->ipv6_mcast; + stats->wow_ipv6_mcast_ra_stats += vstats->ipv6_mcast_ra; + stats->wow_ipv6_mcast_ns_stats += vstats->ipv6_mcast_ns; + stats->wow_ipv6_mcast_na_stats += vstats->ipv6_mcast_na; + stats->wow_icmpv4_count += vstats->icmpv4; + stats->wow_icmpv6_count += vstats->icmpv6; + stats->wow_rssi_breach_wake_up_count += vstats->rssi_breach; + stats->wow_low_rssi_wake_up_count += vstats->low_rssi; + stats->wow_gscan_wake_up_count += vstats->gscan; + stats->wow_pno_complete_wake_up_count += vstats->pno_complete; + stats->wow_pno_match_wake_up_count += vstats->pno_match; + stats->wow_oem_response_wake_up_count += vstats->oem_response; + } + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * 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 + */ +void wma_process_fw_test_cmd(WMA_HANDLE handle, + struct set_fwtest_params *wma_fwtest) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw test cmd", + __func__); + return; + } + + if (wmi_unified_fw_test_cmd(wma_handle->wmi_handle, + (struct set_fwtest_params *)wma_fwtest)) { + WMA_LOGE("%s: Failed to issue fw test cmd", + __func__); + return; + } +} + +/** + * 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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue set/clear CA")); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + 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(wma->wmi_handle, wmi_buf, len, + WMI_CHAN_AVOID_RPT_ALLOW_CMDID)) { + WMA_LOGE(FL("Failed to send enable/disable CA event command")); + 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_LOGI(FL("handle:%pK event:%pK len:%u"), handle, evt_buf, len); + + wma_handle = handle; + if (!wma_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL wmi_handle")); + return QDF_STATUS_E_INVAL; + } + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) { + WMA_LOGE(FL("failed to malloc sar_limit_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_LOGE(FL("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_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL 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_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL 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_LOGE(FL("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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue set sar limit msg", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (sar_limit_params == NULL) { + WMA_LOGE("%s: set sar limit ptr NULL", + __func__); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_send_sar_limit_cmd(wma->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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue coex config command", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!coex_cfg_params) { + WMA_LOGE("%s: coex cfg params ptr NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_send_coex_config_cmd(wma->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}; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + + if (!mac->sme.get_arp_stats_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + if (data == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + param_buf = (WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *)data; + if (!param_buf) { + WMA_LOGE("%s: Invalid get arp stats event", __func__); + return -EINVAL; + } + data_event = param_buf->fixed_param; + if (!data_event) { + WMA_LOGE("%s: Invalid get arp stats data event", __func__); + 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_LOGD("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_DEBUGFS +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; + + tpAniSirGlobal mac = (tpAniSirGlobal)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 || !mac->sme.power_stats_resp_callback) { + WMA_LOGD("%s: NULL mac ptr or HDD callback is null", __func__); + return -EINVAL; + } + + if (!param_buf) { + WMA_LOGD("%s: NULL power stats event fixed param", __func__); + 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_LOGE("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) { + WMA_LOGD("%s: could not allocate mem for power stats results", + __func__); + return -ENOMEM; + } + WMA_LOGD("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); + + mac->sme.power_stats_resp_callback(power_stats_results, + mac->sme.power_debug_stats_context); + qdf_mem_free(power_stats_results); + return 0; +} +#else +int wma_unified_power_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, uint32_t len) +{ + 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 sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + param_tlvs = + (WMI_VDEV_BCN_RECEPTION_STATS_EVENTID_param_tlvs *)cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + 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_LOGD("%s: NULL mac ptr or HDD callback is null", __func__); + return -EINVAL; + } + + if (!param_buf) { + WMA_LOGD("%s: NULL beacon stats event fixed param", __func__); + 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_LOGD("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 + +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; + tpAniSirGlobal mac = NULL; + struct lim_channel_status *channel_status; + + WMA_LOGD("%s: Enter", __func__); + + if (wma != NULL && wma->cds_context != NULL) + mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: monitor:%d", __func__, mac->snr_monitor_enabled); + if (mac->snr_monitor_enabled && mac->chan_info_cb) { + param_buf = + (WMI_CHAN_INFO_EVENTID_param_tlvs *)event_buf; + if (!param_buf) { + WMA_LOGA("%s: Invalid chan info event", __func__); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + WMA_LOGA("%s: Invalid fixed param", __func__); + return -EINVAL; + } + 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; + mac->chan_info_cb(&buf); + } + + if (mac->sap.acs_with_more_param && + mac->sme.currDeviceMode == QDF_SAP_MODE) { + param_buf = (WMI_CHAN_INFO_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("Invalid chan info event buffer"); + return -EINVAL; + } + event = param_buf->fixed_param; + channel_status = + qdf_mem_malloc(sizeof(*channel_status)); + if (!channel_status) { + WMA_LOGE(FL("Mem alloc fail")); + return -ENOMEM; + } + WMA_LOGD(FL("freq=%d nf=%d rxcnt=%u cyccnt=%u tx_r=%d tx_t=%d"), + event->freq, + event->noise_floor, + event->rx_clear_count, + event->cycle_count, + event->chan_tx_pwr_range, + event->chan_tx_pwr_tp); + + channel_status->channelfreq = event->freq; + channel_status->noise_floor = event->noise_floor; + 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_send_msg(handle, WMA_RX_CHN_STATUS_EVENT, + (void *)channel_status, 0); + } + + 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; + tpAniSirGlobal mac; + + mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + if (!mac || !mac->sme.stats_ext2_cb) { + WMA_LOGD("%s: NULL mac ptr or HDD callback is null", __func__); + return -EINVAL; + } + + param_buf = (WMI_REPORT_RX_AGGR_FAILURE_EVENTID_param_tlvs *)event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid stats ext event buf", __func__); + 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_LOGE("%s: Excess data from WMI num_failure_info %d", + __func__, 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 (NULL == rx_aggr_hole_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + 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_LOGE("Invalid no of hole count: %d", + rx_aggr_hole_event->hole_cnt); + qdf_mem_free(rx_aggr_hole_event); + return -EINVAL; + } + WMA_LOGD("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_LOGD("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_LOGE(FL("Invalid BT activity event buffer")); + return -EINVAL; + } + + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + WMA_LOGE(FL("Invalid BT activity event fixed param buffer")); + return -EINVAL; + } + + WMA_LOGI(FL("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)) { + WMA_LOGE(FL("Failed to post msg to SME")); + 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[IEEE80211_ADDR_LEN]; + + tpAniSirGlobal pmac = (tpAniSirGlobal)cds_get_context( + QDF_MODULE_ID_PE); + if (!pmac) { + WMA_LOGE(FL("Invalid pmac")); + return -EINVAL; + } + + if (!pmac->sme.get_chain_rssi_cb) { + WMA_LOGE(FL("Invalid get_chain_rssi_cb")); + return -EINVAL; + } + param_buf = (WMI_PDEV_DIV_RSSI_ANTID_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE(FL("Invalid rssi antid event buffer")); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + WMA_LOGE(FL("Invalid fixed param")); + return -EINVAL; + } + + if (event->num_chains_valid > CHAIN_MAX_NUM) { + WMA_LOGE(FL("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_LOGD(FL("macaddr: " MAC_ADDRESS_STR), MAC_ADDR_ARRAY(macaddr)); + + WMA_LOGD(FL("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_LOGD(FL("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]); + + chain_rssi_result.chain_rssi[i] += + WMA_TGT_NOISE_FLOOR_DBM; + } + + 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_LOGE("Invalid obss_detection_info event buffer"); + return -EINVAL; + } + + obss_detection = qdf_mem_malloc(sizeof(*obss_detection)); + if (!obss_detection) { + WMA_LOGE("%s: Failed to malloc", __func__); + return -ENOMEM; + } + + status = wmi_unified_extract_obss_detection_info(wma->wmi_handle, + event, obss_detection); + + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to extract obss info", __func__); + qdf_mem_free(obss_detection); + return -EINVAL; + } + + if (!wma_is_vdev_valid(obss_detection->vdev_id)) { + WMA_LOGE("%s: Invalid vdev id %d", __func__, + obss_detection->vdev_id); + qdf_mem_free(obss_detection); + return -EINVAL; + } + + wma_send_msg(wma, WMA_OBSS_DETECTION_INFO, obss_detection, 0); + + return 0; +} + +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_LOGE("Invalid obss_color_collision event buffer"); + return -EINVAL; + } + + obss_color_info = qdf_mem_malloc(sizeof(*obss_color_info)); + if (!obss_color_info) { + WMA_LOGE("%s: Failed to malloc", __func__); + return -ENOMEM; + } + + status = wmi_unified_extract_obss_color_collision_info(wma->wmi_handle, + event, + obss_color_info); + + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to extract obss color info", __func__); + qdf_mem_free(obss_color_info); + return -EINVAL; + } + + if (!wma_is_vdev_valid(obss_color_info->vdev_id)) { + WMA_LOGE("%s: Invalid vdev id %d", __func__, + 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; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_fips_api.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_fips_api.c new file mode 100644 index 0000000000000000000000000000000000000000..70f1e65eb806c10be3af2537b9585e1f64c54028 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_fips_api.c @@ -0,0 +1,112 @@ +/* + * 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: 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_LOGI(FL("handle:%pK event:%pK len:%u"), handle, event, len); + + wma_handle = handle; + if (!wma_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL wmi_handle")); + return QDF_STATUS_E_INVAL; + } + + status = wmi_extract_fips_event_data(wmi_handle, event, ¶m); + + WMA_LOGI(FL("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_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL 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_LOGE(FL("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/drivers/staging/qcacld-3.0/core/wma/src/wma_fips_api.h b/drivers/staging/qcacld-3.0/core/wma/src/wma_fips_api.h new file mode 100644 index 0000000000000000000000000000000000000000..5ca0efb94470f31888b344687afe22e974f3a769 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/wma/src/wma_fips_public_structs.h b/drivers/staging/qcacld-3.0/core/wma/src/wma_fips_public_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..13c5999b3b6029702feee146a57c2ce103e1207d --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/wma/src/wma_he.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_he.c new file mode 100644 index 0000000000000000000000000000000000000000..9e597907609c7368ea781061792088de6ab0ca26 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_he.c @@ -0,0 +1,1331 @@ +/* + * 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: 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_LOGD(FL("nss: %d ru: %d req_byte: %d\n"), 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_LOGD(FL("ppet16 (nss:%d ru:%d): %04x"), + i, j, ppet16); + WMA_LOGD(FL("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_LOGE(FL("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 + * + * 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) +{ + 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); + he_cap->twt_request = WMI_HECAP_MAC_TWTREQ_GET(mac_cap); + he_cap->twt_responder = WMI_HECAP_MAC_TWTRSP_GET(mac_cap); + he_cap->fragmentation = WMI_HECAP_MAC_HEFRAG_GET(mac_cap); + he_cap->max_num_frag_msdu = WMI_HECAP_MAC_MAXFRAGMSDU_GET(mac_cap); + he_cap->min_frag_size = WMI_HECAP_MAC_MINFRAGSZ_GET(mac_cap); + he_cap->trigger_frm_mac_pad = WMI_HECAP_MAC_TRIGPADDUR_GET(mac_cap); + he_cap->multi_tid_aggr = WMI_HECAP_MAC_ACKMTIDAMPDU_GET(mac_cap); + he_cap->he_link_adaptation = WMI_HECAP_MAC_HELKAD_GET(mac_cap); + he_cap->all_ack = WMI_HECAP_MAC_AACK_GET(mac_cap); + he_cap->ul_mu_rsp_sched = WMI_HECAP_MAC_ULMURSP_GET(mac_cap); + he_cap->a_bsr = WMI_HECAP_MAC_BSR_GET(mac_cap); + he_cap->broadcast_twt = WMI_HECAP_MAC_BCSTTWT_GET(mac_cap); + he_cap->ba_32bit_bitmap = WMI_HECAP_MAC_32BITBA_GET(mac_cap); + he_cap->mu_cascade = WMI_HECAP_MAC_MUCASCADE_GET(mac_cap); + he_cap->ack_enabled_multitid = WMI_HECAP_MAC_ACKMTIDAMPDU_GET(mac_cap); + he_cap->dl_mu_ba = WMI_HECAP_MAC_GROUPMSTABA_GET(mac_cap); + he_cap->omi_a_ctrl = WMI_HECAP_MAC_OMI_GET(mac_cap); + he_cap->ofdma_ra = WMI_HECAP_MAC_OFDMARA_GET(mac_cap); + he_cap->max_ampdu_len = WMI_HECAP_MAC_MAXAMPDULEN_EXP_GET(mac_cap); + he_cap->amsdu_frag = WMI_HECAP_MAC_AMSDUFRAG_GET(mac_cap); + he_cap->flex_twt_sched = WMI_HECAP_MAC_FLEXTWT_GET(mac_cap); + he_cap->rx_ctrl_frame = WMI_HECAP_MAC_MBSS_GET(mac_cap); + he_cap->bsrp_ampdu_aggr = WMI_HECAP_MAC_BSRPAMPDU_GET(mac_cap); + he_cap->qtp = WMI_HECAP_MAC_QTP_GET(mac_cap); + he_cap->a_bqr = WMI_HECAP_MAC_ABQR_GET(mac_cap); + he_cap->sr_responder = WMI_HECAP_MAC_SRRESP_GET(mac_cap); + he_cap->ndp_feedback_supp = WMI_HECAP_MAC_NDPFDBKRPT_GET(mac_cap); + he_cap->ops_supp = WMI_HECAP_MAC_OPS_GET(mac_cap); + he_cap->amsdu_in_ampdu = WMI_HECAP_MAC_AMSDUINAMPDU_GET(mac_cap); + /* HE PHY capabilities */ + he_cap->dual_band = WMI_HECAP_PHY_DB_GET(phy_cap); + 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_rx_max_nsts = + WMI_HECAP_PHY_MIDAMBLERXMAXNSTS_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->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->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_GET(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_SUBFMESTS_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->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_rx_1x_he_ltf = + WMI_HECAP_PHY_MIDAMBLERX2XAND1XHELTF_GET(phy_cap); + + /* + * supp_mcs is split into 16 bits with lower indicating le_80 and + * upper indicating 160 and 80_80. + */ + WMA_LOGD(FL("supported_mcs: 0x%08x\n"), 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) +{ + 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 = QDF_MIN(he_cap->max_num_frag_msdu, + new_cap->max_num_frag_msdu); + 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 = QDF_MIN(he_cap->multi_tid_aggr, + new_cap->multi_tid_aggr); + 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->ul_mu_rsp_sched = QDF_MIN(he_cap->ul_mu_rsp_sched, + new_cap->ul_mu_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->dl_mu_ba = QDF_MIN(he_cap->dl_mu_ba, + new_cap->dl_mu_ba); + 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 = QDF_MIN(he_cap->max_ampdu_len, + new_cap->max_ampdu_len); + 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->sr_responder = QDF_MIN(he_cap->sr_responder, + new_cap->sr_responder); + 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->reserved1 = QDF_MIN(he_cap->reserved1, + new_cap->reserved1); + + he_cap->dual_band = QDF_MIN(he_cap->dual_band, + new_cap->dual_band); + + 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->rx_pream_puncturing = + QDF_MIN(he_cap->rx_pream_puncturing, + new_cap->rx_pream_puncturing); + 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_rx_max_nsts = + QDF_MIN(he_cap->midamble_rx_max_nsts, + new_cap->midamble_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->tx_stbc_lt_80mhz = QDF_MIN(he_cap->tx_stbc_lt_80mhz, + new_cap->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_rx_1x_he_ltf = + QDF_MIN(he_cap->midamble_rx_1x_he_ltf, + new_cap->midamble_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); + mcs_1 = *((uint16_t *)he_cap->rx_he_mcs_map_160); + mcs_2 = *((uint16_t *)new_cap->rx_he_mcs_map_160); + *((uint16_t *)he_cap->rx_he_mcs_map_160) = + HE_INTERSECT_MCS(mcs_1, mcs_2); + mcs_1 = *((uint16_t *)he_cap->tx_he_mcs_map_160); + mcs_2 = *((uint16_t *)new_cap->tx_he_mcs_map_160); + *((uint16_t *)he_cap->tx_he_mcs_map_160) = + HE_INTERSECT_MCS(mcs_1, mcs_2); + mcs_1 = *((uint16_t *)he_cap->rx_he_mcs_map_80_80); + mcs_2 = *((uint16_t *)new_cap->rx_he_mcs_map_80_80); + *((uint16_t *)he_cap->rx_he_mcs_map_80_80) = + HE_INTERSECT_MCS(mcs_1, mcs_2); + mcs_1 = *((uint16_t *)he_cap->tx_he_mcs_map_80_80); + mcs_2 = *((uint16_t *)new_cap->tx_he_mcs_map_80_80); + *((uint16_t *)he_cap->tx_he_mcs_map_80_80) = + HE_INTERSECT_MCS(mcs_1, mcs_2); +} + +void wma_print_he_cap(tDot11fIEhe_cap *he_cap) +{ + uint8_t chan_width; + struct ppet_hdr *hdr; + + if (!he_cap->present) { + WMA_LOGI(FL("HE Capabilities not present")); + return; + } + + WMA_LOGD(FL("HE Capabilities:")); + + /* HE MAC capabilities */ + WMA_LOGD("\tHTC-HE conrol: 0x%01x", he_cap->htc_he); + WMA_LOGD("\tTWT Requestor support: 0x%01x", he_cap->twt_request); + WMA_LOGD("\tTWT Responder support: 0x%01x", he_cap->twt_responder); + WMA_LOGD("\tFragmentation support: 0x%02x", he_cap->fragmentation); + WMA_LOGD("\tMax no.of frag MSDUs: 0x%03x", he_cap->max_num_frag_msdu); + WMA_LOGD("\tMin. frag size: 0x%02x", he_cap->min_frag_size); + WMA_LOGD("\tTrigger MAC pad duration: 0x%02x", + he_cap->trigger_frm_mac_pad); + WMA_LOGD("\tMulti-TID aggr support: 0x%03x", he_cap->multi_tid_aggr); + WMA_LOGD("\tLink adaptation: 0x%02x", he_cap->he_link_adaptation); + WMA_LOGD("\tAll ACK support: 0x%01x", he_cap->all_ack); + WMA_LOGD("\tUL MU resp. scheduling: 0x%01x", he_cap->ul_mu_rsp_sched); + WMA_LOGD("\tA-Buff status report: 0x%01x", he_cap->a_bsr); + WMA_LOGD("\tBroadcast TWT support: 0x%01x", he_cap->broadcast_twt); + WMA_LOGD("\t32bit BA bitmap support: 0x%01x", he_cap->ba_32bit_bitmap); + WMA_LOGD("\tMU Cascading support: 0x%01x", he_cap->mu_cascade); + WMA_LOGD("\tACK enabled Multi-TID: 0x%01x", + he_cap->ack_enabled_multitid); + WMA_LOGD("\tMulti-STA BA in DL MU: 0x%01x", he_cap->dl_mu_ba); + WMA_LOGD("\tOMI A-Control support: 0x%01x", he_cap->omi_a_ctrl); + WMA_LOGD("\tOFDMA RA support: 0x%01x", he_cap->ofdma_ra); + WMA_LOGD("\tMax A-MPDU Length: 0x%02x", he_cap->max_ampdu_len); + WMA_LOGD("\tA-MSDU Fragmentation: 0x%01x", he_cap->amsdu_frag); + WMA_LOGD("\tFlex. TWT sched support: 0x%01x", he_cap->flex_twt_sched); + WMA_LOGD("\tRx Ctrl frame to MBSS: 0x%01x", he_cap->rx_ctrl_frame); + WMA_LOGD("\tBSRP A-MPDU Aggregation: 0x%01x", he_cap->bsrp_ampdu_aggr); + WMA_LOGD("\tQuite Time Period support: 0x%01x", he_cap->qtp); + WMA_LOGD("\tA-BQR support: 0x%01x", he_cap->a_bqr); + WMA_LOGD("\t SR Responder: 0x%01x", he_cap->sr_responder); + WMA_LOGD("\t ndp feedback supp: 0x%01x", he_cap->ndp_feedback_supp); + WMA_LOGD("\t ops supp: 0x%01x", he_cap->ops_supp); + WMA_LOGD("\t amsdu in ampdu: 0x%01x", he_cap->amsdu_in_ampdu); + + /* HE PHY capabilities */ + WMA_LOGD("\tDual band support: 0x%01x", he_cap->dual_band); + 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_LOGD("\tChannel width support: 0x%07x", chan_width); + WMA_LOGD("\tPreamble puncturing Rx: 0x%04x", + he_cap->rx_pream_puncturing); + WMA_LOGD("\tClass of device: 0x%01x", he_cap->device_class); + WMA_LOGD("\tLDPC coding support: 0x%01x", he_cap->ldpc_coding); + WMA_LOGD("\tLTF and GI for HE PPDUs: 0x%02x", + he_cap->he_1x_ltf_800_gi_ppdu); + WMA_LOGD("\tMidamble Rx MAX NSTS: 0x%02x", + he_cap->midamble_rx_max_nsts); + WMA_LOGD("\tLTF and GI for NDP: 0x%02x", he_cap->he_4x_ltf_3200_gi_ndp); + WMA_LOGD("\tSTBC Tx support <= 80M: 0x%01x", he_cap->tx_stbc_lt_80mhz); + WMA_LOGD("\tSTBC Rx support <= 80M: 0x%01x", he_cap->rx_stbc_lt_80mhz); + WMA_LOGD("\tDoppler support: 0x%02x", he_cap->doppler); + WMA_LOGD("\tUL MU: 0x%02x", he_cap->ul_mu); + WMA_LOGD("\tDCM encoding Tx: 0x%03x", he_cap->dcm_enc_tx); + WMA_LOGD("\tDCM encoding Tx: 0x%03x", he_cap->dcm_enc_rx); + WMA_LOGD("\tHE MU PPDU payload support: 0x%01x", he_cap->ul_he_mu); + WMA_LOGD("\tSU Beamformer: 0x%01x", he_cap->su_beamformer); + WMA_LOGD("\tSU Beamformee: 0x%01x", he_cap->su_beamformee); + WMA_LOGD("\tMU Beamformer: 0x%01x", he_cap->mu_beamformer); + WMA_LOGD("\tBeamformee STS for <= 80Mhz: 0x%03x", + he_cap->bfee_sts_lt_80); + WMA_LOGD("\tBeamformee STS for > 80Mhz: 0x%03x", + he_cap->bfee_sts_gt_80); + WMA_LOGD("\tNo. of sounding dim <= 80Mhz: 0x%03x", + he_cap->num_sounding_lt_80); + WMA_LOGD("\tNo. of sounding dim > 80Mhz: 0x%03x", + he_cap->num_sounding_gt_80); + WMA_LOGD("\tNg=16 for SU feedback support: 0x%01x", + he_cap->su_feedback_tone16); + WMA_LOGD("\tNg=16 for MU feedback support: 0x%01x", + he_cap->mu_feedback_tone16); + WMA_LOGD("\tCodebook size for SU: 0x%01x", he_cap->codebook_su); + WMA_LOGD("\tCodebook size for MU: 0x%01x ", he_cap->codebook_mu); + WMA_LOGD("\tBeamforming trigger w/ Trigger: 0x%01x", + he_cap->beamforming_feedback); + WMA_LOGD("\tHE ER SU PPDU payload: 0x%01x", he_cap->he_er_su_ppdu); + WMA_LOGD("\tDL MUMIMO on partial BW: 0x%01x", + he_cap->dl_mu_mimo_part_bw); + WMA_LOGD("\tPPET present: 0x%01x", he_cap->ppet_present); + WMA_LOGD("\tSRP based SR-support: 0x%01x", he_cap->srp); + WMA_LOGD("\tPower boost factor: 0x%01x", he_cap->power_boost); + WMA_LOGD("\t4x HE LTF support: 0x%01x", he_cap->he_ltf_800_gi_4x); + + WMA_LOGD("\tMax NC: 0x%01x", he_cap->max_nc); + WMA_LOGD("\tstbc Tx gt 80mhz: 0x%01x", he_cap->tx_stbc_gt_80mhz); + WMA_LOGD("\tstbc Rx gt 80mhz: 0x%01x", he_cap->rx_stbc_gt_80mhz); + WMA_LOGD("\ter_he_ltf_800_gi_4x: 0x%01x", he_cap->er_he_ltf_800_gi_4x); + WMA_LOGD("\the_ppdu_20_in_40Mhz_2G: 0x%01x", + he_cap->he_ppdu_20_in_40Mhz_2G); + WMA_LOGD("\the_ppdu_20_in_160_80p80Mhz: 0x%01x", + he_cap->he_ppdu_20_in_160_80p80Mhz); + WMA_LOGD("\the_ppdu_80_in_160_80p80Mhz: 0x%01x", + he_cap->he_ppdu_80_in_160_80p80Mhz); + WMA_LOGD("\ter_1x_he_ltf_gi: 0x%01x", + he_cap->er_1x_he_ltf_gi); + WMA_LOGD("\tmidamble_rx_1x_he_ltf: 0x%01x", + he_cap->midamble_rx_1x_he_ltf); + WMA_LOGD("\tRx MCS MAP for BW <= 80 MHz: 0x%x", + he_cap->rx_he_mcs_map_lt_80); + WMA_LOGD("\tTx MCS MAP for BW <= 80 MHz: 0x%x", + he_cap->tx_he_mcs_map_lt_80); + WMA_LOGD("\tRx MCS MAP for BW = 160 MHz: 0x%x", + *((uint16_t *)he_cap->rx_he_mcs_map_160)); + WMA_LOGD("\tTx MCS MAP for BW = 160 MHz: 0x%x", + *((uint16_t *)he_cap->tx_he_mcs_map_160)); + WMA_LOGD("\tRx MCS MAP for BW = 80 + 80 MHz: 0x%x", + *((uint16_t *)he_cap->rx_he_mcs_map_80_80)); + WMA_LOGD("\tTx MCS MAP for BW = 80 + 80 MHz: 0x%x", + *((uint16_t *)he_cap->tx_he_mcs_map_80_80)); + + hdr = (struct ppet_hdr *)&he_cap->ppet.ppe_threshold.ppe_th[0]; + /* HE PPET */ + WMA_LOGD("\tNSS: %d", hdr->nss + 1); + WMA_LOGD("\tRU Index mask: 0x%04x", hdr->ru_idx_mask); + WMA_LOGD("\tnum_ppet: %d", 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_LOGI(FL("PPET is NULL")); + return; + } + + numss = ppet->numss_m1 + 1; + ru_bit_mask = ppet->ru_bit_mask; + + WMA_LOGD(FL("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 (ru_count > 0) { + WMA_LOGD(FL("PPET has following RU INDEX,")); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX0_MASK) + WMA_LOGD("\tRU ALLOCATION INDEX 0"); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX1_MASK) + WMA_LOGD("\tRU ALLOCATION INDEX 1"); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX2_MASK) + WMA_LOGD("\tRU ALLOCATION INDEX 2"); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX3_MASK) + WMA_LOGD("\tRU ALLOCATION INDEX 3"); + } + + WMA_LOGD(FL("HE PPET: nss: %d, ru_count: %d"), numss, ru_count); + + for (i = 0; i < numss; i++) { + WMA_LOGD("PPET for NSS[%d]", i); + for (j = 1; j <= ru_count; j++) { + WMA_LOGD("\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_LOGD(FL("HE PHY Capabilities:")); + + WMA_LOGD("\tDual band support: 0x%01x", + WMI_HECAP_PHY_DB_GET(phy_cap)); + WMA_LOGD("\tChannel width support: 0x%07x", + WMI_HECAP_PHY_CBW_GET(phy_cap)); + WMA_LOGD("\tPreamble puncturing Rx: 0x%04x", + WMI_HECAP_PHY_PREAMBLEPUNCRX_GET(phy_cap)); + WMA_LOGD("\tClass of device: 0x%01x", WMI_HECAP_PHY_COD_GET(phy_cap)); + WMA_LOGD("\tLDPC coding support: 0x%01x", + WMI_HECAP_PHY_LDPC_GET(phy_cap)); + WMA_LOGD("\tLTF and GI for HE PPDUs: 0x%02x", + WMI_HECAP_PHY_LTFGIFORHE_GET(phy_cap)); + WMA_LOGD("\tLTF and GI for NDP: 0x%02x", + WMI_HECAP_PHY_LTFGIFORNDP_GET(phy_cap)); + WMA_LOGD("\tSTBC Tx & Rx support (BW <= 80Mhz): 0x%02x", + (WMI_HECAP_PHY_RXSTBC_GET(phy_cap) << 1) | + WMI_HECAP_PHY_TXSTBC_GET(phy_cap)); + WMA_LOGD("\tDoppler support: 0x%02x", + (WMI_HECAP_PHY_RXDOPPLER_GET(phy_cap) << 1) | + WMI_HECAP_PHY_TXDOPPLER_GET(phy_cap)); + WMA_LOGD("\tUL MU (Full BW): 0x%01x", + WMI_HECAP_PHY_UL_MU_MIMO_GET(phy_cap)); + WMA_LOGD("\tUL MU (Partial BW): 0x%01x", + WMI_HECAP_PHY_ULMUMIMOOFDMA_GET(phy_cap)); + WMA_LOGD("\tDCM encoding Tx: 0x%03x", WMI_HECAP_PHY_DCMTX_GET(phy_cap)); + WMA_LOGD("\tDCM encoding Tx: 0x%03x", WMI_HECAP_PHY_DCMRX_GET(phy_cap)); + WMA_LOGD("\tHE MU PPDU payload support: 0x%01x", + WMI_HECAP_PHY_ULHEMU_GET(phy_cap)); + WMA_LOGD("\tSU Beamformer: 0x%01x", WMI_HECAP_PHY_SUBFMR_GET(phy_cap)); + WMA_LOGD("\tSU Beamformee: 0x%01x", WMI_HECAP_PHY_SUBFME_GET(phy_cap)); + WMA_LOGD("\tMU Beamformer: 0x%01x", WMI_HECAP_PHY_MUBFMR_GET(phy_cap)); + WMA_LOGD("\tBeamformee STS for <= 80Mhz: 0x%03x", + WMI_HECAP_PHY_SUBFMESTS_GET(phy_cap)); + WMA_LOGD("\tNSTS total for <= 80Mhz: 0x%03x", + WMI_HECAP_PHY_NSTSLT80MHZ_GET(phy_cap)); + WMA_LOGD("\tBeamformee STS for > 80Mhz: 0x%03x", + WMI_HECAP_PHY_BFMESTSGT80MHZ_GET(phy_cap)); + WMA_LOGD("\tNSTS total for > 80Mhz: 0x%03x", + WMI_HECAP_PHY_NSTSGT80MHZ_GET(phy_cap)); + WMA_LOGD("\tNo. of sounding dim <= 80Mhz: 0x%03x", + WMI_HECAP_PHY_NUMSOUNDLT80MHZ_GET(phy_cap)); + WMA_LOGD("\tNo. of sounding dim > 80Mhz: 0x%03x", + WMI_HECAP_PHY_NUMSOUNDGT80MHZ_GET(phy_cap)); + WMA_LOGD("\tNg=16 for SU feedback support: 0x%01x", + WMI_HECAP_PHY_NG16SUFEEDBACKLT80_GET(phy_cap)); + WMA_LOGD("\tNg=16 for MU feedback support: 0x%01x", + WMI_HECAP_PHY_NG16MUFEEDBACKGT80_GET(phy_cap)); + WMA_LOGD("\tCodebook size for SU: 0x%01x", + WMI_HECAP_PHY_CODBK42SU_GET(phy_cap)); + WMA_LOGD("\tCodebook size for MU: 0x%01x ", + WMI_HECAP_PHY_CODBK75MU_GET(phy_cap)); + WMA_LOGD("\tBeamforming trigger w/ Trigger: 0x%01x", + WMI_HECAP_PHY_BFFEEDBACKTRIG_GET(phy_cap)); + WMA_LOGD("\tHE ER SU PPDU payload: 0x%01x", + WMI_HECAP_PHY_HEERSU_GET(phy_cap)); + WMA_LOGD("\tDL MUMIMO on partial BW: 0x%01x", + WMI_HECAP_PHY_DLMUMIMOPARTIALBW_GET(phy_cap)); + WMA_LOGD("\tPPET present: 0x%01x", WMI_HECAP_PHY_PADDING_GET(phy_cap)); + WMA_LOGD("\tSRP based SR-support: 0x%01x", + WMI_HECAP_PHY_SRPSPRESENT_GET(phy_cap)); + WMA_LOGD("\tPower boost factor: 0x%01x", + WMI_HECAP_PHY_PWRBOOSTAR_GET(phy_cap)); + WMA_LOGD("\t4x HE LTF support: 0x%01x", + WMI_HECAP_PHY_4XLTFAND800NSECSGI_GET(phy_cap)); + WMA_LOGD("\tMax Nc supported: 0x%03x", + WMI_HECAP_PHY_MAXNC_GET(phy_cap)); + WMA_LOGD("\tSTBC Tx & Rx support (BW > 80Mhz): 0x%02x", + (WMI_HECAP_PHY_STBCRXGT80_GET(phy_cap) << 1) | + WMI_HECAP_PHY_STBCTXGT80_GET(phy_cap)); + WMA_LOGD("\tER 4x HE LTF support: 0x%01x", + WMI_HECAP_PHY_ERSU4X800NSECGI_GET(phy_cap)); +} + +void wma_print_he_mac_cap(uint32_t mac_cap) +{ + WMA_LOGD(FL("HE MAC Capabilities:")); + + WMA_LOGD("\tHTC-HE conrol: 0x%01x", WMI_HECAP_MAC_HECTRL_GET(mac_cap)); + WMA_LOGD("\tTWT Requestor support: 0x%01x", + WMI_HECAP_MAC_TWTREQ_GET(mac_cap)); + WMA_LOGD("\tTWT Responder support: 0x%01x", + WMI_HECAP_MAC_TWTRSP_GET(mac_cap)); + WMA_LOGD("\tFragmentation support: 0x%02x", + WMI_HECAP_MAC_HEFRAG_GET(mac_cap)); + WMA_LOGD("\tMax no.of frag MSDUs: 0x%03x", + WMI_HECAP_MAC_MAXFRAGMSDU_GET(mac_cap)); + WMA_LOGD("\tMin. frag size: 0x%02x", + WMI_HECAP_MAC_MINFRAGSZ_GET(mac_cap)); + WMA_LOGD("\tTrigger MAC pad duration: 0x%02x", + WMI_HECAP_MAC_TRIGPADDUR_GET(mac_cap)); + WMA_LOGD("\tMulti-TID aggr support: 0x%03x", + WMI_HECAP_MAC_ACKMTIDAMPDU_GET(mac_cap)); + WMA_LOGD("\tLink adaptation: 0x%02x", + WMI_HECAP_MAC_HELKAD_GET(mac_cap)); + WMA_LOGD("\tAll ACK support: 0x%01x", + WMI_HECAP_MAC_AACK_GET(mac_cap)); + WMA_LOGD("\tUL MU resp. scheduling: 0x%01x", + WMI_HECAP_MAC_ULMURSP_GET(mac_cap)); + WMA_LOGD("\tA-Buff status report: 0x%01x", + WMI_HECAP_MAC_BSR_GET(mac_cap)); + WMA_LOGD("\tBroadcast TWT support: 0x%01x", + WMI_HECAP_MAC_BCSTTWT_GET(mac_cap)); + WMA_LOGD("\t32bit BA bitmap support: 0x%01x", + WMI_HECAP_MAC_32BITBA_GET(mac_cap)); + WMA_LOGD("\tMU Cascading support: 0x%01x", + WMI_HECAP_MAC_MUCASCADE_GET(mac_cap)); + WMA_LOGD("\tACK enabled Multi-TID: 0x%01x", + WMI_HECAP_MAC_ACKMTIDAMPDU_GET(mac_cap)); + WMA_LOGD("\tMulti-STA BA in DL MU: 0x%01x", + WMI_HECAP_MAC_GROUPMSTABA_GET(mac_cap)); + WMA_LOGD("\tOMI A-Control support: 0x%01x", + WMI_HECAP_MAC_OMI_GET(mac_cap)); + WMA_LOGD("\tOFDMA RA support: 0x%01x", + WMI_HECAP_MAC_OFDMARA_GET(mac_cap)); + WMA_LOGD("\tMax A-MPDU Length: 0x%02x", + WMI_HECAP_MAC_MAXAMPDULEN_EXP_GET(mac_cap)); + WMA_LOGD("\tA-MSDU Fragmentation: 0x%01x", + WMI_HECAP_MAC_AMSDUFRAG_GET(mac_cap)); + WMA_LOGD("\tFlex. TWT sched support: 0x%01x", + WMI_HECAP_MAC_FLEXTWT_GET(mac_cap)); + WMA_LOGD("\tRx Ctrl frame to MBSS: 0x%01x", + WMI_HECAP_MAC_MBSS_GET(mac_cap)); + WMA_LOGD("\tBSRP A-MPDU Aggregation: 0x%01x", + WMI_HECAP_MAC_BSRPAMPDU_GET(mac_cap)); + WMA_LOGD("\tQuite Time Period support: 0x%01x", + WMI_HECAP_MAC_QTP_GET(mac_cap)); + WMA_LOGD("\tA-BQR support: 0x%01x", WMI_HECAP_MAC_ABQR_GET(mac_cap)); + WMA_LOGD("\tSR Responder support: 0x%01x", + WMI_HECAP_MAC_SRRESP_GET(mac_cap)); + WMA_LOGD("\tOPS Support: 0x%01x", + WMI_HECAP_MAC_OPS_GET(mac_cap)); + WMA_LOGD("\tNDP Feedback Support: 0x%01x", + WMI_HECAP_MAC_NDPFDBKRPT_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}; + + 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 (!num_hw_modes) { + WMA_LOGE(FL("No extended HE cap for current SOC")); + he_cap->present = false; + return; + } + + if (!tgt_cfg->services.en_11ax) { + WMA_LOGI(FL("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]; + 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); + WMA_LOGD(FL("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); + + 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); + WMA_LOGD(FL("5g 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_5g, + (struct wmi_host_ppe_threshold *) + &mac_cap->he_ppet5G); + } + if (he_cap_mac.present) + wma_derive_ext_he_cap(&tmp_he_cap, + &he_cap_mac); + } + + qdf_mem_copy(he_cap, &tmp_he_cap, sizeof(*he_cap)); + wma_print_he_cap(he_cap); +} + +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_LOGI(FL("11ax is enabled")); + } else { + WMA_LOGI(FL("11ax is not enabled")); + } +} + +void wma_print_he_op(tDot11fIEhe_op *he_ops) +{ + WMA_LOGD(FL("bss_color: %0x, default_pe_duration: %0x, twt_required: %0x, rts_threshold: %0x, vht_oper_present: %0x"), + he_ops->bss_color, he_ops->default_pe, + he_ops->twt_required, he_ops->rts_threshold, + he_ops->vht_oper_present); + WMA_LOGD(FL("\tpartial_bss_color: %0x, MBSSID AP: %0x, Tx BSSID Indicator: %0x, BSS color disabled: %0x"), + he_ops->partial_bss_col, he_ops->mbssid_ap, + he_ops->tx_bssid_ind, 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_LOGD(FL("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_LOGD(FL("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 = 0, he_ops = 0; + uint8_t temp, i, chan_width; + + if (params->he_capable) + peer->peer_flags |= WMI_PEER_HE; + else + return; + + /* HE MAC capabilities */ + WMI_HECAP_MAC_HECTRL_SET(mac_cap, he_cap->htc_he); + WMI_HECAP_MAC_TWTREQ_SET(mac_cap, he_cap->twt_request); + WMI_HECAP_MAC_TWTRSP_SET(mac_cap, he_cap->twt_responder); + WMI_HECAP_MAC_HEFRAG_SET(mac_cap, he_cap->fragmentation); + WMI_HECAP_MAC_MAXFRAGMSDU_SET(mac_cap, he_cap->max_num_frag_msdu); + WMI_HECAP_MAC_MINFRAGSZ_SET(mac_cap, he_cap->min_frag_size); + WMI_HECAP_MAC_TRIGPADDUR_SET(mac_cap, he_cap->trigger_frm_mac_pad); + WMI_HECAP_MAC_ACKMTIDAMPDU_SET(mac_cap, he_cap->multi_tid_aggr); + WMI_HECAP_MAC_HELKAD_SET(mac_cap, he_cap->he_link_adaptation); + WMI_HECAP_MAC_AACK_SET(mac_cap, he_cap->all_ack); + WMI_HECAP_MAC_ULMURSP_SET(mac_cap, he_cap->ul_mu_rsp_sched); + WMI_HECAP_MAC_BSR_SET(mac_cap, he_cap->a_bsr); + WMI_HECAP_MAC_BCSTTWT_SET(mac_cap, he_cap->broadcast_twt); + WMI_HECAP_MAC_32BITBA_SET(mac_cap, he_cap->ba_32bit_bitmap); + WMI_HECAP_MAC_MUCASCADE_SET(mac_cap, he_cap->mu_cascade); + WMI_HECAP_MAC_ACKMTIDAMPDU_SET(mac_cap, he_cap->ack_enabled_multitid); + WMI_HECAP_MAC_GROUPMSTABA_SET(mac_cap, he_cap->dl_mu_ba); + WMI_HECAP_MAC_OMI_SET(mac_cap, he_cap->omi_a_ctrl); + WMI_HECAP_MAC_OFDMARA_SET(mac_cap, he_cap->ofdma_ra); + WMI_HECAP_MAC_MAXAMPDULEN_EXP_SET(mac_cap, he_cap->max_ampdu_len); + WMI_HECAP_MAC_AMSDUFRAG_SET(mac_cap, he_cap->amsdu_frag); + WMI_HECAP_MAC_FLEXTWT_SET(mac_cap, he_cap->flex_twt_sched); + WMI_HECAP_MAC_MBSS_SET(mac_cap, he_cap->rx_ctrl_frame); + WMI_HECAP_MAC_BSRPAMPDU_SET(mac_cap, he_cap->bsrp_ampdu_aggr); + WMI_HECAP_MAC_QTP_SET(mac_cap, he_cap->qtp); + WMI_HECAP_MAC_ABQR_SET(mac_cap, he_cap->a_bqr); + WMI_HECAP_MAC_SRRESP_SET(mac_cap, he_cap->sr_responder); + WMI_HECAP_MAC_OPS_SET(mac_cap, he_cap->ops_supp); + WMI_HECAP_MAC_NDPFDBKRPT_SET(mac_cap, he_cap->ndp_feedback_supp); + WMI_HECAP_MAC_AMSDUINAMPDU_SET(mac_cap, he_cap->amsdu_in_ampdu); + peer->peer_he_cap_macinfo = mac_cap; + + /* HE PHY capabilities */ + WMI_HECAP_PHY_DB_SET(phy_cap, he_cap->dual_band); + 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_MIDAMBLERXMAXNSTS_SET(phy_cap, + he_cap->midamble_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->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->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_MIDAMBLERX2XAND1XHELTF_SET(phy_cap, + he_cap->midamble_rx_1x_he_ltf); + + /* 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->ch_width > CH_WIDTH_80MHZ) { + 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; + } + + for (i = 0; i < peer->peer_he_mcs_count; i++) + WMA_LOGD(FL("[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->rts_threshold); + WMI_HEOPS_PARTBSSCOLOR_SET(he_ops, he_op->partial_bss_col); + WMI_HEOPS_TXBSSID_SET(he_ops, he_op->tx_bssid_ind); + 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_LOGD(FL("Peer HE Capabilities:")); + wma_print_he_phy_cap(phy_cap); + wma_print_he_mac_cap(mac_cap); + wma_print_he_ppet(&peer->peer_ppet); + + return; +} + +void wma_update_vdev_he_ops(struct wma_vdev_start_req *req, + tpAddBssParams add_bss) +{ + uint32_t he_ops = 0; + tDot11fIEhe_op *he_op = &add_bss->he_op; + + req->he_capable = add_bss->he_capable; + + 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->rts_threshold); + WMI_HEOPS_PARTBSSCOLOR_SET(he_ops, he_op->partial_bss_col); + WMI_HEOPS_TXBSSID_SET(he_ops, he_op->tx_bssid_ind); + WMI_HEOPS_BSSCOLORDISABLE_SET(he_ops, he_op->bss_col_disabled); + + req->he_ops = he_ops; +} + +void wma_copy_txrxnode_he_ops(struct wma_txrx_node *node, + struct wma_vdev_start_req *req) +{ + node->he_capable = req->he_capable; + node->he_ops = req->he_ops; +} + +void wma_copy_vdev_start_he_ops(struct vdev_start_params *params, + struct wma_vdev_start_req *req) +{ + params->he_ops = req->he_ops; +} + +void wma_vdev_set_he_bss_params(tp_wma_handle wma, uint8_t vdev_id, + struct wma_vdev_start_req *req) +{ + QDF_STATUS ret; + struct wma_txrx_node *intr = wma->interfaces; + + if (!req->he_capable) + return; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_HEOPS_0_31, req->he_ops); + + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE(FL("Failed to set HE OPs")); + else + intr[vdev_id].he_ops = req->he_ops; +} + +void wma_vdev_set_he_config(tp_wma_handle wma, uint8_t vdev_id, + tpAddBssParams 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_LOGE(FL("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_LOGD(FL("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); +} + +void wma_update_vdev_he_capable(struct wma_vdev_start_req *req, + tpSwitchChannelParams params) +{ + req->he_capable = params->he_capable; +} + +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) { + WMA_LOGE(FL("wrong wma_handle....")); + 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->rts_threshold); + WMI_HEOPS_PARTBSSCOLOR_SET(dword_he_op, he_op->partial_bss_col); + WMI_HEOPS_TXBSSID_SET(dword_he_op, he_op->tx_bssid_ind); + WMI_HEOPS_BSSCOLORDISABLE_SET(dword_he_op, he_op->bss_col_disabled); + + WMA_LOGD("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_HEOPS_0_31, dword_he_op); + + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE(FL("Failed to set HE OPs")); + + return ret; +} + +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) { + WMA_LOGE(FL("Invalid 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_VDEV_PARAM param_id, + uint32_t value) +{ + switch (param_id) { + case WMI_VDEV_PARAM_HE_DCM: + intr->config.dcm = value; + break; + case WMI_VDEV_PARAM_HE_RANGE_EXT: + intr->config.range_ext = value; + break; + default: + WMA_LOGE(FL("Unhandled HE vdev param: %0x"), param_id); + break; + } +} + +uint32_t wma_get_he_vdev_param(struct wma_txrx_node *intr, + WMI_VDEV_PARAM param_id) +{ + switch (param_id) { + case WMI_VDEV_PARAM_HE_DCM: + return intr->config.dcm; + case WMI_VDEV_PARAM_HE_RANGE_EXT: + return intr->config.range_ext; + default: + WMA_LOGE(FL("Unhandled HE vdev param: %0x"), param_id); + break; + } + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c new file mode 100644 index 0000000000000000000000000000000000000000..bf1c10ca550fa7ef280006663d1255605b148f90 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c @@ -0,0 +1,9319 @@ +/* + * 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_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" +#include "cfg_api.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 "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 "wlan_lmac_if_def.h" +#include "wlan_lmac_if_api.h" +#include "target_if.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" +#include +#include +#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 "init_cmd_api.h" +#include "wma_coex.h" + +#define WMA_LOG_COMPLETION_TIMER 3000 /* 3 seconds */ +#define WMI_TLV_HEADROOM 128 + +#define WMA_FW_TIME_SYNC_TIMER 60000 /* 1 min */ + +uint8_t *mac_trace_get_wma_msg_string(uint16_t wmaMsg); +static uint32_t g_fw_wlan_feat_caps; +/** + * wma_get_fw_wlan_feat_caps() - get fw feature capablity + * @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; +} + +QDF_STATUS +wma_vdev_nss_chain_params_send(uint8_t vdev_id, + struct mlme_nss_chains *user_cfg) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_vdev_nss_chain_params_send(wma_handle->wmi_handle, + vdev_id, + user_cfg); +} + +/** + * wma_set_fw_wlan_feat_caps() - set fw feature capablity + * @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) +{ + tp_wma_handle wma_handle; + + WMA_LOGA("%s: Timeout waiting for WMI_SERVICE_READY_EXT_EVENT", + __func__); + + wma_handle = (tp_wma_handle) data; + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + goto end; + } + +end: + /* 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) { + WMA_LOGE("%s: Invalid WMA context\n", __func__); + return NULL; + } + + return &wma->ini_config; +} + +#define MAX_SUPPORTED_PEERS_REV1_1 14 +#define MAX_SUPPORTED_PEERS_REV1_3 32 +#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 hif_target_info *tgt_info; + 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; + struct hif_opaque_softc *scn = cds_get_context(QDF_MODULE_ID_HIF); + + if (!scn) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return 0; + } + + tgt_info = hif_get_target_info_handle(scn); + + switch (tgt_info->target_version) { + case AR6320_REV1_1_VERSION: + if (max_no_of_peers > MAX_SUPPORTED_PEERS_REV1_1) + max_no_of_peers = MAX_SUPPORTED_PEERS_REV1_1; + break; + default: + if (max_no_of_peers > MAX_SUPPORTED_PEERS_REV1_3) + max_no_of_peers = MAX_SUPPORTED_PEERS_REV1_3; + break; + } + + 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 + * + * 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) +{ + return 4 * no_of_peers_supported; +} +#else +static uint32_t wma_get_number_of_tids_supported(uint8_t no_of_peers_supported) +{ + return 2 * (no_of_peers_supported + CFG_TGT_NUM_VDEV + 2); +} +#endif + +#ifdef PERE_IP_HDR_ALIGNMENT_WAR +static void wma_reset_rx_decap_mode(target_resource_config *tgt_cfg) +{ + /* + * To make the IP header begins at dword aligned address, + * we make the decapsulation mode as Native Wifi. + */ + tgt_cfg->rx_decap_mode = CFG_TGT_RX_DECAP_MODE_NWIFI; +} +#else +static void wma_reset_rx_decap_mode(target_resource_config *tgt_cfg) +{ +} + +#endif +/** + * wma_set_default_tgt_config() - set default tgt config + * @wma_handle: wma handle + * @tgt_cfg: Resource config given to target + * + * Return: none + */ +static void wma_set_default_tgt_config(tp_wma_handle wma_handle, + target_resource_config *tgt_cfg) +{ + uint8_t no_of_peers_supported; + + qdf_mem_zero(tgt_cfg, sizeof(target_resource_config)); + tgt_cfg->num_vdevs = CFG_TGT_NUM_VDEV; + tgt_cfg->num_peers = CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2; + tgt_cfg->num_offload_peers = CFG_TGT_NUM_OFFLOAD_PEERS; + tgt_cfg->num_offload_reorder_buffs = CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS; + tgt_cfg->num_peer_keys = CFG_TGT_NUM_PEER_KEYS; + tgt_cfg->num_tids = CFG_TGT_NUM_TIDS; + 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 = CFG_TGT_DEFAULT_SCAN_MAX_REQS; + 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 = + CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES; + 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 = 0; + 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; + + no_of_peers_supported = wma_get_number_of_peers_supported(wma_handle); + tgt_cfg->num_peers = no_of_peers_supported + CFG_TGT_NUM_VDEV + 2; + tgt_cfg->num_tids = wma_get_number_of_tids_supported( + no_of_peers_supported); + tgt_cfg->scan_max_pending_req = wma_handle->max_scan; + + tgt_cfg->mgmt_comp_evt_bundle_support = true; + tgt_cfg->tx_msdu_new_partition_id_support = true; + + /* reduce the peer/vdev if CFG_TGT_NUM_MSDU_DESC exceeds 1000 */ + wma_reset_rx_decap_mode(tgt_cfg); + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + tgt_cfg->rx_decap_mode = CFG_TGT_RX_DECAP_MODE_RAW; +} + +/** + * 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 (NULL == wma) { + WMA_LOGE("%s: Invalid wma handle", __func__); + 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: + case WMI_VDEV_PARAM_HE_RANGE_EXT: + ret = wma_get_he_vdev_param(&intr[vdev_id], param_id); + break; + default: + WMA_LOGE("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_LOGE("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; + default: + WMA_LOGE("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_LOGE("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_LOGE("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_LOGE("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) { + WMA_LOGE("%s: Failed alloc memory for iwcmd", __func__); + 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)) { + WMA_LOGE("%s: Failed to post WMA_CLI_SET_CMD msg", + __func__); + 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; + + WMA_LOGD(FL("enter")); + if (arg_count > WMA_MAX_NUM_ARGS) { + WMA_LOGE(FL("arg_count is crossed the boundary")); + return QDF_STATUS_E_FAILURE; + } + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL("Invalid WMA/WMI handle")); + return QDF_STATUS_E_FAILURE; + } + unit_test_args = qdf_mem_malloc(sizeof(*unit_test_args)); + if (NULL == unit_test_args) { + WMA_LOGE(FL("qdf_mem_malloc failed for 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(wma_handle->wmi_handle, + unit_test_args); + qdf_mem_free(unit_test_args); + WMA_LOGD(FL("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; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL("Invalid WMA/WMI handle")); + qdf_mem_free(send_addba); + return; + } + + status = wmi_unified_addba_send_cmd_send(wma_handle->wmi_handle, + send_addba->mac_addr, + &send_addba->param); + if (QDF_STATUS_SUCCESS != status) { + WMA_LOGE(FL("Failed to process WMA_SEND_ADDBA_REQ")); + } + WMA_LOGD(FL("sent ADDBA req to" MAC_ADDRESS_STR "tid %d buff_size %d"), + MAC_ADDR_ARRAY(send_addba->mac_addr), + send_addba->param.tidno, + send_addba->param.buffersize); + + qdf_mem_free(send_addba); +} + +/** + * wma_ipa_get_stat() - get IPA data path stats from FW + * + * Return: 0 on success, errno on failure + */ +#ifdef IPA_OFFLOAD +static int wma_ipa_get_stat(void) +{ + struct cdp_pdev *pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc stat"); + return -EINVAL; + } + cdp_ipa_get_stat(cds_get_context(QDF_MODULE_ID_SOC), pdev); + + return 0; +} +#else +static int wma_ipa_get_stat(void) +{ + return 0; +} +#endif + +/** + * wma_ipa_uc_get_share_stats() - get Tx/Rx byte stats from FW + * @privcmd: private command + * + * Return: 0 on success, errno on failure + */ +#if defined(IPA_OFFLOAD) && defined(FEATURE_METERING) +static int wma_ipa_uc_get_share_stats(wma_cli_set_cmd_t *privcmd) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_pdev *pdev; + uint8_t reset_stats = privcmd->param_value; + + WMA_LOGD("%s: reset_stats=%d", + "WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID", + reset_stats); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc get share stats"); + return -EINVAL; + } + cdp_ipa_uc_get_share_stats(soc, pdev, reset_stats); + + return 0; +} +#else +static int wma_ipa_uc_get_share_stats(wma_cli_set_cmd_t *privcmd) +{ + return 0; +} +#endif + +/** + * wma_ipa_uc_set_quota() - set quota limit to FW + * @privcmd: private command + * + * Return: 0 on success, errno on failure + */ +#if defined(IPA_OFFLOAD) && defined(FEATURE_METERING) +static int wma_ipa_uc_set_quota(wma_cli_set_cmd_t *privcmd) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_pdev *pdev; + uint64_t quota_bytes = privcmd->param_sec_value; + + quota_bytes <<= 32; + quota_bytes |= privcmd->param_value; + + WMA_LOGD("%s: quota_bytes=%llu", + "WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID", + quota_bytes); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc set quota"); + return -EINVAL; + } + cdp_ipa_uc_set_quota(soc, pdev, quota_bytes); + + return 0; +} +#else +static int wma_ipa_uc_set_quota(wma_cli_set_cmd_t *privcmd) +{ + return 0; +} +#endif + +/** + * 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_LOGD("%s: Parsed input: Channel #1:%d, latency:%dms", + __func__, 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_LOGD("%s: Parsed input: Channel #1:%d, Channel #2:%d, quota 1:%dms", + __func__, 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; + case WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE: + { + wma_handle->wma_ibss_power_save_params.atimWindowLength = + privcmd->param_value; + WMA_LOGD("%s: IBSS power save ATIM Window = %d", + __func__, wma_handle->wma_ibss_power_save_params. + atimWindowLength); + } + break; + case WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED: + { + wma_handle->wma_ibss_power_save_params.isPowerSaveAllowed = + privcmd->param_value; + WMA_LOGD("%s: IBSS is Power Save Allowed = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isPowerSaveAllowed); + } + break; + case WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED: + { + wma_handle->wma_ibss_power_save_params. isPowerCollapseAllowed = + privcmd->param_value; + WMA_LOGD("%s: IBSS is Power Collapse Allowed = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isPowerCollapseAllowed); + } + break; + case WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX: + { + wma_handle->wma_ibss_power_save_params.isAwakeonTxRxEnabled = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Awake on Tx/Rx Enabled = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isAwakeonTxRxEnabled); + } + break; + case WMA_VDEV_IBSS_SET_INACTIVITY_TIME: + { + wma_handle->wma_ibss_power_save_params.inactivityCount = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Data Inactivity Count = %d", + __func__, wma_handle->wma_ibss_power_save_params. + inactivityCount); + } + break; + case WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME: + { + wma_handle->wma_ibss_power_save_params.txSPEndInactivityTime = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Transmit EOSP inactivity time out = %d", + __func__, wma_handle->wma_ibss_power_save_params. + txSPEndInactivityTime); + } + break; + case WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS: + { + wma_handle->wma_ibss_power_save_params.ibssPsWarmupTime = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Warm Up Time in Seconds = %d", + __func__, wma_handle->wma_ibss_power_save_params. + ibssPsWarmupTime); + } + break; + case WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW: + { + wma_handle->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable + = privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save single RX Chain Enable In ATIM = %d", + __func__, wma_handle->wma_ibss_power_save_params. + ibssPs1RxChainInAtimEnable); + } + break; + + case WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: + { + wma_ipa_get_stat(); + } + break; + + case WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID: + { + wma_ipa_uc_get_share_stats(privcmd); + } + break; + + case WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID: + { + wma_ipa_uc_set_quota(privcmd); + + } + break; + + default: + WMA_LOGE("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_LOGE("%s: invalid VDEV", __func__); + return; + } + WMA_LOGD("%s: set dtim_period %d", __func__, + dtim_params->dtim_period); + iface->dtimPeriod = dtim_params->dtim_period; + +} + +/** + * 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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + struct qpower_params *qparams = &intr[vid].config.qpower_params; + struct pdev_params pdev_param; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct target_psoc_info *tgt_hdl; + struct sir_set_tx_rx_aggregation_size aggr; + + WMA_LOGD("wmihandle %pK", wma->wmi_handle); + qdf_mem_zero(&aggr, sizeof(aggr)); + + if (NULL == pMac) { + WMA_LOGE("%s: Failed to get pMac", __func__); + return; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma->psoc); + if (!tgt_hdl) { + WMA_LOGE("%s: target psoc info is NULL", __func__); + 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_LOGE("Failed to set wma priv congiuration"); + return; + } + + switch (privcmd->param_vp_dev) { + case VDEV_CMD: + if (!wma_is_vdev_valid(privcmd->param_vdev_id)) { + WMA_LOGE("%s Vdev id is not valid", __func__); + return; + } + + WMA_LOGD("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_LOGE("wma_vdev_set_param failed ret %d", + ret); + return; + } + break; + case PDEV_CMD: + WMA_LOGD("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_LOGD("Chainmask value is invalid"); + return; + } + } + pdev_param.param_id = privcmd->param_id; + pdev_param.param_value = privcmd->param_value; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("wma_vdev_set_param failed ret %d", + ret); + return; + } + break; + case GEN_CMD: + { + struct cdp_vdev *vdev = NULL; + struct wma_txrx_node *intr = wma->interfaces; + + vdev = wma_find_vdev_by_id(wma, privcmd->param_vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return; + } + + WMA_LOGD("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_LOGE("%s:SOC context is NULL", __func__); + return; + } + + if (privcmd->param_id == GEN_VDEV_PARAM_AMPDU) { + ret = cdp_aggr_cfg(soc, vdev, + privcmd->param_value, 0); + if (ret) + WMA_LOGE("cdp_aggr_cfg set ampdu failed ret %d", + ret); + else + intr[privcmd->param_vdev_id].config. + ampdu = privcmd->param_value; + + aggr.aggr_type = + WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU; + } else { + aggr.aggr_type = + WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU; + } + + aggr.vdev_id = vid; + aggr.tx_aggregation_size = privcmd->param_value; + aggr.rx_aggregation_size = privcmd->param_value; + + ret = wma_set_tx_rx_aggregation_size(&aggr); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("set_aggr_size failed ret %d", ret); + return; + } + break; + case GEN_PARAM_CRASH_INJECT: + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + WMA_LOGE("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: + WMA_LOGE("Invalid param id 0x%x", + privcmd->param_id); + break; + } + break; + } + case DBG_CMD: + WMA_LOGD("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_LOGE("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_LOGE("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_LOGE("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_LOGE("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_LOGE("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_LOGE("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_TYPE: + ret = dbglog_parser_type_init(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("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_LOGE("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_LOGE("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_LOGE("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_LOGE("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_LOGE("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_LOGE("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_LOGE("Set GreenAP Failed val %d", + privcmd->param_value); + } + break; + + default: + WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case PPS_CMD: + WMA_LOGD("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_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + + case QPOWER_CMD: + WMA_LOGD("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_LOGD("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_LOGE("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_LOGD("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_LOGE("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_LOGD("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_LOGE("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_LOGD("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_LOGE("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_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case GTX_CMD: + WMA_LOGD("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_LOGE("wma_vdev_set_param failed ret %d", + ret); + return; + } + break; + default: + break; + } + break; + + default: + WMA_LOGE("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: + case WMI_VDEV_PARAM_HE_RANGE_EXT: + wma_set_he_vdev_param(&intr[vid], privcmd->param_id, + privcmd->param_value); + break; + default: + WMA_LOGD("Invalid wma_cli_set vdev command/Not yet implemented 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 ((pMac->roam.configParam.bandCapability == + BAND_ALL) || + (pMac->roam.configParam.bandCapability == + BAND_2G)) { + if (cfg_set_int(pMac, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + privcmd->param_value) != + QDF_STATUS_SUCCESS) + WMA_LOGE("could not set WNI_CFG_CURRENT_TX_POWER_LEVEL"); + + } else { + WMA_LOGE("Current band is not 2G"); + } + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT5G: + wma->pdevconfig.txpow5g = privcmd->param_value; + if ((pMac->roam.configParam.bandCapability == + BAND_ALL) || + (pMac->roam.configParam.bandCapability == + BAND_5G)) { + if (cfg_set_int(pMac, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + privcmd->param_value) != + QDF_STATUS_SUCCESS) + WMA_LOGE("could not set WNI_CFG_CURRENT_TX_POWER_LEVEL"); + + } else { + WMA_LOGE("Current band is not 5G"); + } + break; + default: + WMA_LOGD("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_LOGE("Failed to send wmi packet power save cmd"); + else + WMA_LOGD("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; + + return qdf_atomic_read(&wma->critical_events_in_flight); +} + +static bool wma_event_is_critical(uint32_t event_id) +{ + switch (event_id) { + case WMI_ROAM_SYNCH_EVENTID: + return true; + default: + return false; + } +} + +/** + * wma_process_fw_event() - process any fw event + * @wma: wma handle + * @buf: fw event buffer + * + * This function process any fw event to serialize it through mc thread. + * + * Return: none + */ +static int wma_process_fw_event(tp_wma_handle wma, + wma_process_fw_event_params *buf) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)buf->wmi_handle; + uint32_t event_id = WMI_GET_FIELD(qdf_nbuf_data(buf->evt_buf), + WMI_CMD_HDR, COMMANDID); + + wmi_process_fw_event(wmi_handle, buf->evt_buf); + + if (wma_event_is_critical(event_id)) + qdf_atomic_dec(&wma->critical_events_in_flight); + + return 0; +} + +/** + * wmi_process_fw_event_tasklet_ctx() - process in tasklet context + * @ctx: handle to wmi + * @ev: wmi event buffer + * + * Event process by below function will be in tasket context, + * need to use this method only for time sensitive functions. + * + * Return: none + */ +static int wma_process_fw_event_tasklet_ctx(void *ctx, void *ev) +{ + wmi_process_fw_event(ctx, ev); + + return 0; +} + +/** + * 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_LOGE("%s: sir_pwr_dbg_params is null", __func__); + 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 void wma_discard_fw_event(struct scheduler_msg *msg) +{ + if (!msg->bodyptr) + return; + + switch (msg->type) { + case WMA_PROCESS_FW_EVENT: + qdf_nbuf_free(((wma_process_fw_event_params *)msg->bodyptr) + ->evt_buf); + break; + case WMA_SET_LINK_STATE: + qdf_mem_free(((tpLinkStateParams) msg->bodyptr)->callbackArg); + break; + } + + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + msg->bodyval = 0; + msg->type = 0; +} + +/** + * wma_process_fw_event_handler() - common event handler to serialize + * event processing through mc_thread + * @ctx: wmi context + * @ev: event buffer + * @rx_ctx: rx execution context + * + * Return: 0 on success, errno on failure + */ +static int wma_process_fw_event_mc_thread_ctx(void *ctx, void *ev) +{ + wma_process_fw_event_params *params_buf; + struct scheduler_msg cds_msg = { 0 }; + tp_wma_handle wma; + uint32_t event_id; + + params_buf = qdf_mem_malloc(sizeof(wma_process_fw_event_params)); + if (!params_buf) { + WMA_LOGE("%s: Failed alloc memory for params_buf", __func__); + qdf_nbuf_free(ev); + return -ENOMEM; + } + + params_buf->wmi_handle = (struct wmi_unified *)ctx; + params_buf->evt_buf = ev; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + event_id = WMI_GET_FIELD(qdf_nbuf_data(params_buf->evt_buf), + WMI_CMD_HDR, COMMANDID); + if (wma && wma_event_is_critical(event_id)) + qdf_atomic_inc(&wma->critical_events_in_flight); + + cds_msg.type = WMA_PROCESS_FW_EVENT; + cds_msg.bodyptr = params_buf; + cds_msg.bodyval = 0; + cds_msg.flush_callback = wma_discard_fw_event; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &cds_msg)) { + WMA_LOGE("%s: Failed to post WMA_PROCESS_FW_EVENT msg", + __func__); + qdf_nbuf_free(ev); + qdf_mem_free(params_buf); + return -EFAULT; + } + return 0; + +} + +/** + * wma_process_fw_event_handler() - common event handler to serialize + * event processing through mc_thread + * @ctx: wmi context + * @ev: event buffer + * @rx_ctx: rx execution context + * + * Return: 0 on success, errno on failure + */ +int wma_process_fw_event_handler(void *ctx, void *htc_packet, uint8_t rx_ctx) +{ + int err = 0; + ol_scn_t scn_handle; + struct wlan_objmgr_psoc *psoc; + struct target_psoc_info *tgt_hdl; + wmi_buf_t evt_buf; + bool is_wmi_ready = false; + + evt_buf = (wmi_buf_t) ((HTC_PACKET *)htc_packet)->pPktContext; + + scn_handle = ((wmi_unified_t)ctx)->scn_handle; + + psoc = target_if_get_psoc_from_scn_hdl(scn_handle); + if (!psoc) { + WMA_LOGE("psoc is null"); + return err; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); + if (!tgt_hdl) { + WMA_LOGE("target_psoc_info is null"); + return err; + } + + is_wmi_ready = target_psoc_get_wmi_ready(tgt_hdl); + if (!is_wmi_ready) { + WMA_LOGD("fw event recvd before ready event processed"); + WMA_LOGD("therefore use worker thread"); + wmi_process_fw_event_worker_thread_ctx(ctx, htc_packet); + return err; + } + + if (rx_ctx == WMA_RX_SERIALIZER_CTX) { + err = wma_process_fw_event_mc_thread_ctx(ctx, evt_buf); + } else if (rx_ctx == WMA_RX_TASKLET_CTX) { + wma_process_fw_event_tasklet_ctx(ctx, evt_buf); + } else { + WMA_LOGE("%s: invalid wmi event execution context", __func__); + qdf_nbuf_free(evt_buf); + } + + return err; +} + +#ifdef WLAN_FEATURE_NAN +/** + * wma_set_nan_enable() - set nan enable flag in WMA handle + * @wma_handle: Pointer to wma handle + * @cds_cfg: Pointer to CDS Configuration + * + * Return: none + */ +static void wma_set_nan_enable(tp_wma_handle wma_handle, + struct cds_config_info *cds_cfg) +{ + wma_handle->is_nan_enabled = cds_cfg->is_nan_enabled; +} +#else +static void wma_set_nan_enable(tp_wma_handle wma_handle, + struct cds_config_info *cds_cfg) +{ +} +#endif + +/** + * 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_LOGD("%s: handle %pK param %pK len %d", __func__, + handle, param, len); + + mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + 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_LOGE("%s: Invalid isolation event", __func__); + 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_LOGD("%s: chain1 %d chain2 %d chain3 %d chain4 %d", __func__, + 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_LOGE("%s: could not post peer info rsp msg to SME", + __func__); + /* 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 void 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); + + if (cfg == NULL) { + WMA_LOGE("%s: NULL WMA ini handle", __func__); + return; + } + + cfg->max_no_of_peers = max_peers; +} + +/** + * wma_cleanup_vdev_resp_queue() - cleanup vdev response queue + * @wma: wma handle + * + * Return: none + */ +static void wma_cleanup_vdev_resp_queue(tp_wma_handle wma) +{ + struct wma_target_req *req_msg = NULL; + qdf_list_node_t *node1 = NULL; + + qdf_spin_lock_bh(&wma->vdev_respq_lock); + if (!qdf_list_size(&wma->vdev_resp_queue)) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGD(FL("request queue maybe empty")); + return; + } + + WMA_LOGD(FL("Cleaning up vdev resp queue")); + + /* peek front, and then cleanup it in wma_vdev_resp_timer */ + while (qdf_list_peek_front(&wma->vdev_resp_queue, &node1) == + QDF_STATUS_SUCCESS) { + req_msg = qdf_container_of(node1, struct wma_target_req, node); + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + qdf_mc_timer_stop(&req_msg->event_timeout); + wma_vdev_resp_timer(req_msg); + qdf_spin_lock_bh(&wma->vdev_respq_lock); + } + qdf_spin_unlock_bh(&wma->vdev_respq_lock); +} + +/** + * 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_LOGD(FL("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) +{ + if (!msg || !msg->bodyptr) { + WMA_LOGE(FL("msg or body pointer is NULL")); + return QDF_STATUS_E_INVAL; + } + + wma_cleanup_vdev_resp_queue(msg->bodyptr); + wma_cleanup_hold_req(msg->bodyptr); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_shutdown_notifier_cb - Shutdown notifer 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; + + qdf_event_set(&wma_handle->wma_resume_event); + pmo_ucfg_psoc_wakeup_host_event_received(wma_handle->psoc); + wmi_stop(wma_handle->wmi_handle); + + msg.bodyptr = priv; + msg.callback = wma_cleanup_vdev_resp_and_hold_req; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE(FL("Failed to post SYS_MSG_ID_CLEAN_VDEV_RSP_QUEUE")); +} + +struct wma_version_info g_wmi_version_info; + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +/** + * wma_state_info_dump() - prints state information of wma layer + * @buf: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to dump state information of wma layer + * + * Return: None + */ +#ifdef QCA_SUPPORT_CP_STATS +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; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return; + } + + WMA_LOGD("%s: size of buffer: %d", __func__, *size); + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) + continue; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + vdev_id, WLAN_LEGACY_WMA_ID); + if (vdev == NULL) + 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" + "conn_state %d\n" + "dtimPeriod %d\n" + "chanmode %d\n" + "vht_capable %d\n" + "ht_capable %d\n" + "chan_width %d\n" + "vdev_active %d\n" + "vdev_up %d\n" + "aid %d\n" + "rate_flags %d\n" + "nss %d\n" + "tx_power %d\n" + "max_tx_power %d\n" + "nwType %d\n" + "tx_streams %d\n" + "rx_streams %d\n" + "chain_mask %d\n" + "nss_2g %d\n" + "nss_5g %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, + iface->conn_state, + iface->dtimPeriod, + iface->chanmode, + iface->vht_capable, + iface->ht_capable, + iface->chan_width, + iface->vdev_active, + wma_is_vdev_up(vdev_id), + iface->aid, + iface->rate_flags, + iface->nss, + iface->tx_power, + iface->max_tx_power, + iface->nwType, + iface->tx_streams, + iface->rx_streams, + iface->chain_mask, + iface->nss_2g, + iface->nss_5g); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + } + + *size -= len; + *buf_ptr += len; +} +#else /* QCA_SUPPORT_CP_STATS */ +static void wma_state_info_dump(char **buf_ptr, uint16_t *size) +{ + t_wma_handle *wma; + struct sir_vdev_wow_stats *stats; + uint16_t len = 0; + char *buf = *buf_ptr; + struct wma_txrx_node *iface; + uint8_t vdev_id; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return; + } + + WMA_LOGE("%s: size of buffer: %d", __func__, *size); + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) + continue; + + stats = &iface->wow_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" + "conn_state %d\n" + "dtimPeriod %d\n" + "chanmode %d\n" + "vht_capable %d\n" + "ht_capable %d\n" + "chan_width %d\n" + "vdev_active %d\n" + "vdev_up %d\n" + "aid %d\n" + "rate_flags %d\n" + "nss %d\n" + "tx_power %d\n" + "max_tx_power %d\n" + "nwType %d\n" + "tx_streams %d\n" + "rx_streams %d\n" + "chain_mask %d\n" + "nss_2g %d\n" + "nss_5g %d", + vdev_id, + stats->pno_match, + stats->pno_complete, + stats->gscan, + stats->low_rssi, + stats->rssi_breach, + stats->ucast, + stats->bcast, + stats->icmpv4, + stats->icmpv6, + stats->ipv4_mcast, + stats->ipv6_mcast, + stats->ipv6_mcast_ra, + stats->ipv6_mcast_ns, + stats->ipv6_mcast_na, + stats->oem_response, + iface->conn_state, + iface->dtimPeriod, + iface->chanmode, + iface->vht_capable, + iface->ht_capable, + iface->chan_width, + iface->vdev_active, + wma_is_vdev_up(vdev_id), + iface->aid, + iface->rate_flags, + iface->nss, + iface->tx_power, + iface->max_tx_power, + iface->nwType, + iface->tx_streams, + iface->rx_streams, + iface->chain_mask, + iface->nss_2g, + iface->nss_5g); + } + + *size -= len; + *buf_ptr += len; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +/** + * 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_LOGE("%s: pointer to lmac if tx ops is NULL", __func__); + 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_target_if_close() - Detach UMAC modules' interface with wmi layer + * @wma_handle: wma handle + * + * Return: None + */ +static void wma_target_if_close(tp_wma_handle wma_handle) +{ + struct wlan_objmgr_psoc *psoc = wma_handle->psoc; + + if (!psoc) + return; + + wlan_global_lmac_if_close(psoc); +} + +/** + * 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: None + */ +static struct wlan_objmgr_psoc *wma_get_psoc_from_scn_handle(void *scn_handle) +{ + tp_wma_handle wma_handle; + + if (!scn_handle) { + WMA_LOGE("invalid scn handle"); + return NULL; + } + wma_handle = (tp_wma_handle)scn_handle; + + return wma_handle->psoc; +} + +/** + * 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_LOGE("invalid scn handle"); + return NULL; + } + wma_handle = (tp_wma_handle)scn_handle; + + return wma_handle->pdev; +} + +/** + * 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); + default: + WMA_LOGE("Legacy callback invoked with invalid event_id:%d", + event_id); + QDF_BUG(0); + } + + return 0; +} + +/** + * wma_flush_complete_evt_handler() - FW log flush complete event handler + * @handle: WMI handle + * @event: Event recevied 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_LOGE("Invalid log flush complete event buffer"); + return QDF_STATUS_E_FAILURE; + } + + wmi_event = param_buf->fixed_param; + reason_code = wmi_event->reserved0; + WMA_LOGD("Received reason code %d from FW", reason_code); + + 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 (((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, + 0XFF, + data_stall_event->vdev_id_bitmap, + data_stall_event->recovery_type); + } + + /* + * 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_LOGD("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_LOGD("Received WMI flush event in response to flush CMD"); + status = qdf_mc_timer_stop(&wma->log_completion_timer); + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("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_LOGE("%s: Failed to set log trigger params", + __func__); + 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_LOGD("%s: Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + __func__, 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_LOGW("%s: Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + __func__, 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 + * @param evt_buf: pointer to event buffer + * @param datalen: data length of event buffer + * @param buf_offset: Pointer to hold value of current event buffer offset + * post extraction + * @param 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_LOGE("%s: not enough space? (datalen=%d, n=%d, hdr=%zu bytes", + __func__, 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_LOGE("%s: buf_len is garbage? (0x%x)", + __func__, ev->hdr.buf_len); + return QDF_STATUS_E_FAILURE; + } + if (n + ev->hdr.buf_len > datalen) { + WMA_LOGE("%s: buf_len exceeds available space n=%d, buf_len=%d, datalen=%d", + __func__, 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_LOGD("%s: len=%d, tsf=0x%08x, rssi = 0x%x/0x%x/0x%x/0x%x, comb rssi = 0x%x, phycode=%d", + __func__, + 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_LOGD("%s: chain 0: raw=0x%08x; pri20=%d sec20=%d sec40=%d sec80=%d", + __func__, + 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_LOGD("%s: chain 1: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d", + __func__, + 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_LOGD("%s: chain 2: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d", + __func__, + 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_LOGD("%s: chain 3: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d", + __func__, + 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_LOGD("%s: freq_info_1=0x%08x, freq_info_2=0x%08x", + __func__, ev->hdr.freq_info_1, ev->hdr.freq_info_2); + + /* + * The NF chain values are signed and are negative - hence + * the cast evilness. + */ + WMA_LOGD("%s: nfval[1]=0x%08x, nfval[2]=0x%08x, nf=%d/%d/%d/%d, freq1=%d, freq2=%d, cw=%d", + __func__, + 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 (NULL == wma) { + WMA_LOGE("%s:wma handle is NULL", __func__); + 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_LOGE("%s: extract comb phyerr failed", __func__); + 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_LOGE("%s: extract single phy err failed", __func__); + 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 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_LOGE("%s: psoc is null", __func__); + return QDF_STATUS_E_INVAL; + } + + dfs_rx_ops = wlan_lmac_if_get_dfs_rx_ops(handle->psoc); + if (!dfs_rx_ops) { + WMA_LOGE("%s: dfs_rx_ops is null", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!dfs_rx_ops->dfs_process_phyerr) { + WMA_LOGE("%s: dfs_process_phyerr handler is null", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!handle->pdev) { + WMA_LOGE("%s: pdev is null", __func__); + 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; + + if (!wma) { + WMA_LOGE("%s: wma handle is null", __func__); + 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_LOGE("%s: extract phyerr failed: %d", __func__, status); + 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_LOGD("%s: Unknown phy error event", __func__); + 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_LOGD("%s: Unexpected phy error, dfs offloaded", + __func__); + 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) +{ + qdf_wake_lock_create(&vdev->vdev_start_wakelock, "vdev_start"); + qdf_wake_lock_create(&vdev->vdev_stop_wakelock, "vdev_stop"); + qdf_wake_lock_create(&vdev->vdev_set_key_wakelock, "vdev_set_key"); + qdf_spinlock_create(&vdev->peer_lock); + 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); + /* validate the wma_handle */ + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + 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->handle) { + qdf_mem_free(vdev->handle); + vdev->handle = NULL; + } + + if (vdev->addBssStaContext) { + qdf_mem_free(vdev->addBssStaContext); + vdev->addBssStaContext = NULL; + } + + if (vdev->staKeyParams) { + qdf_mem_free(vdev->staKeyParams); + vdev->staKeyParams = NULL; + } + + if (vdev->del_staself_req) { + qdf_mem_free(vdev->del_staself_req); + vdev->del_staself_req = NULL; + } + + if (vdev->stats_rsp) { + qdf_mem_free(vdev->stats_rsp); + vdev->stats_rsp = 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; + } + + qdf_wake_lock_destroy(&vdev->vdev_start_wakelock); + qdf_wake_lock_destroy(&vdev->vdev_stop_wakelock); + qdf_wake_lock_destroy(&vdev->vdev_set_key_wakelock); + qdf_spinlock_destroy(&vdev->peer_lock); + 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 == NULL) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + "wma_handle is NULL\n"); + return; + } + wmi_stop(wma_handle->wmi_handle); +} + +#ifdef QCA_SUPPORT_CP_STATS +static void wma_register_stats_events(wmi_unified_t wmi_handle) {} +#else +static void wma_register_stats_events(wmi_unified_t wmi_handle) +{ + wmi_unified_register_event_handler(wmi_handle, + wmi_update_stats_event_id, + wma_stats_event_handler, + WMA_RX_SERIALIZER_CTX); +} +#endif + +#ifdef FEATURE_WLAN_APF +static void wma_register_apf_events(tp_wma_handle wma_handle) +{ + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + "wma_handle is NULL\n"); + 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 */ + +void wma_get_phy_mode_cb(uint8_t chan, uint32_t chan_width, uint32_t *phy_mode) +{ + uint32_t dot11_mode; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("MAC context is NULL"); + *phy_mode = MODE_UNKNOWN; + return; + } + + wlan_cfg_get_int(mac, WNI_CFG_DOT11_MODE, &dot11_mode); + *phy_mode = wma_chan_phy_mode(chan, chan_width, dot11_mode); +} + +/** + * wma_open() - Allocate wma context and initialize it. + * @cds_context: cds context + * @wma_tgt_cfg_cb: tgt config callback fun + * @radar_ind_cb: dfs radar indication callback + * @cds_cfg: mac parameters + * + * 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; + void *cds_context; + target_resource_config *wlan_res_cfg; + + WMA_LOGD("%s: Enter", __func__); + + cds_context = cds_get_global_context(); + if (!cds_context) { + WMA_LOGE("%s: Invalid CDS context", __func__); + 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_LOGE("%s: Invalid HTC handle", __func__); + 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_LOGE("%s: Memory allocation failed for wma_handle", + __func__); + return qdf_status; + } + + qdf_mem_zero(wma_handle, sizeof(t_wma_handle)); + + if (target_if_alloc_psoc_tgt_info(psoc)) { + WMA_LOGE("%s target psoc info allocation failed", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_free_wma_handle; + } + + if (cds_get_conparam() != 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_status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_LEGACY_WMA_ID); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("%s: PSOC get_ref fails", __func__); + goto err_get_psoc_ref; + } + wma_handle->psoc = psoc; + + /* Open target_if layer and register wma callback */ + wma_target_if_open(wma_handle); + target_if_open(wma_get_psoc_from_scn_handle); + + /* + * Allocate locally used params with its rx_ops member, + * and free it immediately after used. + */ + params = qdf_mem_malloc(sizeof(*params) + sizeof(struct wmi_rx_ops)); + if (!params) { + WMA_LOGE("%s: failed to allocate attach params", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + params->rx_ops = (struct wmi_rx_ops *)(params + 1); + params->osdev = NULL; + params->target_type = WMI_TLV_TARGET; + params->use_cookie = false; + params->psoc = psoc; + params->max_commands = WMI_MAX_CMDS; + /* Attach mc_thread context processing function */ + params->rx_ops->wma_process_fw_event_handler_cbk = + wma_process_fw_event_handler; + + /* 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_LOGE("%s: failed to attach WMI", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + target_if_register_legacy_service_ready_cb( + wma_legacy_service_ready_event_handler); + + WMA_LOGA("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); + /* 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->max_scan = cds_cfg->max_scan; + + wma_handle->enable_peer_unmap_conf_support = + cds_cfg->enable_peer_unmap_conf_support; + wma_handle->enable_tx_compl_tsf64 = + cds_cfg->enable_tx_compl_tsf64; + + wma_handle->enable_three_way_coex_config_legacy = + cds_cfg->enable_three_way_coex_config_legacy; + + /* Register Converged Event handlers */ + init_deinit_register_tgt_psoc_ev_handlers(psoc); + + /* Initialize max_no_of_peers for wma_get_number_of_peers_supported() */ + wma_init_max_no_of_peers(wma_handle, cds_cfg->max_station); + /* Cap maxStation based on the target version */ + cds_cfg->max_station = wma_get_number_of_peers_supported(wma_handle); + /* Reinitialize max_no_of_peers based on the capped maxStation value */ + wma_init_max_no_of_peers(wma_handle, cds_cfg->max_station); + + /* initialize default target config */ + wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_psoc_info); + if (!wlan_res_cfg) { + WMA_LOGE("%s: wlan_res_cfg is null", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + wma_set_default_tgt_config(wma_handle, wlan_res_cfg); + + wma_handle->tx_chain_mask_cck = cds_cfg->tx_chain_mask_cck; + wma_handle->self_gen_frm_pwr = cds_cfg->self_gen_frm_pwr; + wma_init_max_no_of_peers(wma_handle, cds_cfg->max_station); + cds_cfg->max_station = wma_get_number_of_peers_supported(wma_handle); + + cds_cfg->max_bssid = WMA_MAX_SUPPORTED_BSS; + + wlan_res_cfg->num_keep_alive_pattern = WMA_MAXNUM_PERIODIC_TX_PTRNS; + + /* The current firmware implementation requires the number of + * offload peers should be (number of vdevs + 1). + */ + wlan_res_cfg->num_offload_peers = + cds_cfg->ap_maxoffload_peers + 1; + + wlan_res_cfg->num_offload_reorder_buffs = + cds_cfg->ap_maxoffload_reorderbuffs + 1; + + wma_handle->max_station = cds_cfg->max_station; + wma_handle->max_bssid = cds_cfg->max_bssid; + wma_handle->ssdp = cds_cfg->ssdp; + wma_handle->enable_mc_list = cds_cfg->enable_mc_list; + wma_handle->apf_packet_filter_enable = + cds_cfg->apf_packet_filter_enable; + wma_handle->active_uc_apf_mode = cds_cfg->active_uc_apf_mode; + wma_handle->active_mc_bc_apf_mode = cds_cfg->active_mc_bc_apf_mode; + wma_handle->link_stats_results = NULL; +#ifdef FEATURE_WLAN_RA_FILTERING + wma_handle->IsRArateLimitEnabled = cds_cfg->is_ra_ratelimit_enabled; + wma_handle->RArateLimitInterval = cds_cfg->ra_ratelimit_interval; +#endif /* FEATURE_WLAN_RA_FILTERING */ +#ifdef WLAN_FEATURE_LPSS + wma_handle->is_lpass_enabled = cds_cfg->is_lpass_enabled; +#endif + wma_set_nan_enable(wma_handle, cds_cfg); + wma_handle->interfaces = qdf_mem_malloc(sizeof(struct wma_txrx_node) * + wma_handle->max_bssid); + if (!wma_handle->interfaces) { + WMA_LOGE("%s: failed to allocate interface table", __func__); + 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]); + wma_handle->interfaces[i].delay_before_vdev_stop = + cds_cfg->delay_before_vdev_stop; + } + /* 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_LOGE("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_LOGE("%s: target suspend event initialization failed", + __func__); + 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_LOGE("%s: failed to init tx_frm_download_comp_event", + __func__); + 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_LOGE("%s: failed to init tx_queue_empty_event", __func__); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->wma_resume_event); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: wma_resume_event initialization failed", + __func__); + goto err_event_init; + } + + qdf_status = cds_shutdown_notifier_register(wma_shutdown_notifier_cb, + wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Shutdown notifier register failed: %d", + __func__, qdf_status); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->runtime_suspend); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: runtime_suspend event initialization failed", + __func__); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->recovery_event); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: recovery event initialization failed", __func__); + goto err_event_init; + } + + qdf_list_create(&wma_handle->vdev_resp_queue, + MAX_ENTRY_VDEV_RESP_QUEUE); + qdf_spinlock_create(&wma_handle->vdev_respq_lock); + 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); + + /* Register vdev start response event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_vdev_start_resp_event_id, + wma_vdev_start_resp_handler, + WMA_RX_SERIALIZER_CTX); + + /* Register vdev stop response event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_vdev_stopped_event_id, + wma_vdev_stop_resp_handler, + WMA_RX_SERIALIZER_CTX); + + /* 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 stats event */ + wma_register_stats_events(wma_handle->wmi_handle); + + /* register for stats response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_get_arp_stats_req_id, + wma_get_arp_stats_handler, + WMA_RX_SERIALIZER_CTX); + + /* register for peer info response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_stats_info_event_id, + wma_peer_info_event_handler, + WMA_RX_SERIALIZER_CTX); + +#ifdef WLAN_POWER_DEBUGFS + /* 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 + + /* 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 peer change event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_state_event_id, + wma_peer_state_change_event_handler, + WMA_RX_WORK_CTX); + + /* 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 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_LOGE("%s: Firmware Dbglog initialization failed", __func__); + goto err_dbglog_init; + } + + /* + * Update Powersave mode + * 1 - Legacy Powersave + Deepsleep Disabled + * 2 - QPower + Deepsleep Disabled + * 3 - Legacy Powersave + Deepsleep Enabled + * 4 - QPower + Deepsleep Enabled + */ + wma_handle->powersave_mode = cds_cfg->powersave_offload_enabled; + wma_handle->staMaxLIModDtim = cds_cfg->sta_maxlimod_dtim; + wma_handle->staModDtim = cds_cfg->sta_mod_dtim; + wma_handle->staDynamicDtim = cds_cfg->sta_dynamic_dtim; + + /* + * Value of cds_cfg->wow_enable 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 patter and pattern byte match on + * all interfaces. + */ + wma_handle->wow.magic_ptrn_enable = + (cds_cfg->wow_enable & 0x01) ? true : false; + wma_handle->ptrn_match_enable_all_vdev = + (cds_cfg->wow_enable & 0x02) ? true : false; + + /* register for install key completion event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_vdev_install_key_complete_event_id, + wma_vdev_install_key_complete_event_handler, + WMA_RX_SERIALIZER_CTX); +#ifdef WLAN_FEATURE_NAN + /* register for nan response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_nan_event_id, + wma_nan_rsp_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* WLAN_FEATURE_NAN */ + +#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 */ + + WMA_LOGD("%s: Exit", __func__); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_roam_synch_event_id, + wma_roam_synch_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_roam_synch_frame_event_id, + wma_roam_synch_frame_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + 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); + + /* 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_vdev_delete_resp_event_id, + wma_vdev_delete_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 (cds_cfg->auto_power_save_fail_mode == + 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); + + + wma_register_debug_callback(); + wifi_pos_register_get_phy_mode_cb(wma_handle->psoc, + wma_get_phy_mode_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_cfg_int_callback(wma_handle->psoc, + wma_vdev_get_cfg_int); + 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; + qdf_status = policy_mgr_register_wma_cb(wma_handle->psoc, &wma_cbacks); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("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); + +#ifdef WLAN_SUPPORT_TWT + 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); +#endif + + wma_register_apf_events(wma_handle); + wma_register_mws_coex_events(wma_handle); + return QDF_STATUS_SUCCESS; + +err_dbglog_init: + qdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock); + qdf_runtime_lock_deinit(&wma_handle->wmi_cmd_rsp_runtime_lock); + qdf_spinlock_destroy(&wma_handle->vdev_respq_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; + OS_FREE(wmi_handle); + +err_wma_handle: + target_if_close(); + 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) { +#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); + } +err_free_wma_handle: + cds_free_context(QDF_MODULE_ID_WMA, wma_handle); + + WMA_LOGD("%s: Exit", __func__); + + 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; + struct scheduler_msg wma_msg = { 0 }; + void *htc_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* Validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: invalid wma handle", __func__); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + htc_handle = lmac_get_htc_hdl(wma_handle->psoc); + if (!htc_handle) { + WMA_LOGE("%s: invalid htc handle", __func__); + 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_LOGE("%s: wmi_unified_connect_htc_service", __func__); + if (!cds_is_fw_down()) + QDF_BUG(0); + + qdf_status = QDF_STATUS_E_FAULT; + goto end; + } + + WMA_LOGD("WMA --> wmi_unified_connect_htc_service - success"); + + /* Trigger the CFG DOWNLOAD */ + wma_msg.type = WNI_CFG_DNLD_REQ; + wma_msg.bodyptr = NULL; + wma_msg.bodyval = 0; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &wma_msg); + if (QDF_STATUS_SUCCESS != qdf_status) { + WMA_LOGE("%s: Failed to post WNI_CFG_DNLD_REQ msg", __func__); + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_FAILURE; + } +end: + WMA_LOGD("%s: Exit", __func__); + 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)) { + WMA_LOGE("Failed to post msg %d to PE", msg_type); + 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_LOGD("Base MAC Addr: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY((*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 recevied 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) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* 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) { + WMA_LOGE("%s: Memory allocation failed", __func__); + /* 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_LOGE("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_LOGE("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_LOGE("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_LOGD("%s: status:%d cfgd_hw_mode_index:%d num_vdev_mac_entries:%d", + __func__, 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 == WMI_PDEV_ID_SOC) { + WMA_LOGE("%s: soc level id received for mac id)", + __func__); + goto fail; + } + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: vdev_id: %d is invalid, max_bssid: %d", + __func__, vdev_id, wma->max_bssid); + goto fail; + } + + mac_id = WMA_PDEV_TO_MAC_MAP(vdev_mac_entry[i].pdev_id); + + WMA_LOGD("%s: vdev_id:%d mac_id:%d", + __func__, 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_LOGD("%s: Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + __func__, 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_LOGE("%s: Sending fail response to LIM", __func__); + 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 sir_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_LOGE("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; + WMA_LOGD("%s: old_hw_mode_index:%d new_hw_mode_index:%d entries=%d", + __func__, fixed_param->old_hw_mode_index, + fixed_param->new_hw_mode_index, + fixed_param->num_vdev_mac_entries); + + /* 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 == WMI_PDEV_ID_SOC) { + WMA_LOGE("%s: soc level id received for mac id)", + __func__); + return; + } + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: vdev_id: %d is invalid, max_bssid: %d", + __func__, vdev_id, wma->max_bssid); + return; + } + + mac_id = WMA_PDEV_TO_MAC_MAP(vdev_mac_entry[i].pdev_id); + + WMA_LOGE("%s: vdev_id:%d mac_id:%d", + __func__, vdev_id, mac_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); + } + 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); + + WMA_LOGD("%s: Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + __func__, wma->old_hw_mode_index, wma->new_hw_mode_index); +} + +/** + * wma_pdev_hw_mode_transition_evt_handler() - HW mode transition evt handler + * @handle: WMI handle + * @event: Event recevied 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 sir_hw_mode_trans_ind *hw_mode_trans_ind; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma) { + /* This is an async event. So, not sending any event to LIM */ + WMA_LOGE("Invalid WMA handle"); + 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_LOGE("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_LOGE("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) { + WMA_LOGE("%s: Memory allocation failed", __func__); + 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_LOGE("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); + /* Pass the message to PE */ + wma_send_msg(wma, SIR_HAL_PDEV_HW_MODE_TRANS_IND, + (void *) hw_mode_trans_ind, 0); + + 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) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* 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) { + WMA_LOGE("%s: Memory allocation failed", __func__); + /* 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_LOGE("%s: Invalid event", __func__); + goto fail; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGD("%s: status:%d", __func__, 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_LOGE("%s: Sending fail response to LIM", __func__); + 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; + +} + +/** + * wma_send_time_stamp_sync_cmd() - timer callback send timestamp to + * firmware to sync with host. + * @wma_handle: wma handle + * + * Return: void + */ +static void wma_send_time_stamp_sync_cmd(void *data) +{ + tp_wma_handle wma_handle; + QDF_STATUS qdf_status; + + wma_handle = (tp_wma_handle) data; + + wmi_send_time_stamp_sync_cmd_tlv(wma_handle->wmi_handle); + + /* Start/Restart the timer */ + qdf_status = qdf_mc_timer_start(&wma_handle->wma_fw_time_sync_timer, + WMA_FW_TIME_SYNC_TIMER); + if (QDF_IS_STATUS_ERROR(qdf_status)) + WMA_LOGE("Failed to start the firmware time sync timer"); +} + +#ifdef WLAN_CONV_SPECTRAL_ENABLE +static void wma_register_spectral_cmds(tp_wma_handle wma_handle) +{ + struct wmi_spectral_cmd_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_wmi_spectral_cmd_ops(wma_handle->pdev, &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; + int status; + struct wmi_unified *wmi_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc); + if (!wmi_handle) { + WMA_LOGE("%s: Invalid wmi handle", __func__); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + status = wmi_unified_register_event_handler(wmi_handle, + wmi_roam_event_id, + wma_roam_event_callback, + WMA_RX_SERIALIZER_CTX); + if (0 != status) { + WMA_LOGE("%s: Failed to register Roam callback", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wmi_handle, + wmi_wow_wakeup_host_event_id, + wma_wow_wakeup_host_event, + WMA_RX_TASKLET_CTX); + if (status) { + WMA_LOGE("%s: Failed to register wow wakeup host event handler", + __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + if (wma_d0_wow_is_supported()) { + 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 (status) { + WMA_LOGE("%s: Failed to register d0wow disable ack" + " event handler", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + } + + status = wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_resume_event_id, + wma_pdev_resume_event_handler, + WMA_RX_TASKLET_CTX); + if (status) { + WMA_LOGE("%s: Failed to register PDEV resume event handler", + __func__); + 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_LOGD("MCC TX Pause Event Handler register"); + 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_LOGD("Registering SAR2 response handler"); + 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 (status) { + WMA_LOGE("Failed to register sar response event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + WMA_LOGD("Registering auto shutdown handler"); + status = wmi_unified_register_event_handler(wmi_handle, + wmi_host_auto_shutdown_event_id, + wma_auto_shutdown_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register WMI Auto shutdown event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + status = wmi_unified_register_event_handler(wmi_handle, + wmi_thermal_mgmt_event_id, + wma_thermal_mgmt_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register thermal mitigation event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wma_ocb_register_callbacks(wma_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("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 */ + + if (wmi_service_enabled(wmi_handle, wmi_service_rmc)) { + + WMA_LOGD("FW supports cesium network, registering event handlers"); + + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_peer_info_event_id, + wma_ibss_peer_info_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register ibss peer info event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_peer_tx_fail_cnt_thr_event_id, + wma_fast_tx_fail_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register peer fast tx failure event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + } else { + WMA_LOGE("Target does not support cesium network"); + } + + qdf_status = wma_tx_attach(wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to register tx management", __func__); + goto end; + } + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { + /* Initialize firmware time stamp sync timer */ + qdf_status = + qdf_mc_timer_init(&wma_handle->wma_fw_time_sync_timer, + QDF_TIMER_TYPE_SW, + wma_send_time_stamp_sync_cmd, + wma_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) + WMA_LOGE(FL("Failed to initialize firmware time stamp sync timer")); + /* Start firmware time stamp sync timer */ + wma_send_time_stamp_sync_cmd(wma_handle); + } + + /* 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_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to initialize log completion timeout"); + goto end; + } + + status = wma_fips_register_event_handlers(wma_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to register FIPS event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wma_sar_register_event_handlers(wma_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to register SAR event handlers"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the get temperature event handler */ + status = wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_temperature_event_id, + wma_pdev_temperature_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register get_temperature event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wmi_handle, + wmi_vdev_tsf_report_event_id, + wma_vdev_tsf_handler, + WMA_RX_SERIALIZER_CTX); + if (0 != status) { + WMA_LOGE("%s: Failed to register tsf callback", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the wma_pdev_set_hw_mode_resp_evt_handler event handler */ + 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 (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("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 */ + 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 (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register hw mode transition event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the set dual mac configuration event handler */ + 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 (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register hw mode transition event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + 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_SUCCESS(status)) { + WMA_LOGE("Failed to register coex bt activity event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + wma_register_spectral_cmds(wma_handle); + +end: + WMA_LOGD("%s: Exit", __func__); + return qdf_status; +} + +QDF_STATUS wma_stop(void) +{ + tp_wma_handle wma_handle; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int i; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + WMA_LOGD("%s: Enter", __func__); + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid handle", __func__); + qdf_status = QDF_STATUS_E_INVAL; + 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); + 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_LOGE("Failed to destroy the log completion timer"); + /* clean up ll-queue for all vdev */ + for (i = 0; i < wma_handle->max_bssid; i++) { + if (wma_handle->interfaces[i].handle && + wma_is_vdev_up(i)) { + cdp_fc_vdev_flush( + cds_get_context(QDF_MODULE_ID_SOC), + wma_handle-> + interfaces[i].handle); + } + } + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { + /* Destroy firmware time stamp sync timer */ + qdf_status = qdf_mc_timer_destroy( + &wma_handle->wma_fw_time_sync_timer); + if (QDF_IS_STATUS_ERROR(qdf_status)) + WMA_LOGE(FL("Failed to destroy the fw time sync timer")); + } + + qdf_status = wma_tx_detach(wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to deregister tx management", __func__); + goto end; + } + +end: + WMA_LOGD("%s: Exit", __func__); + 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; + int i; + + WMA_LOGD("%s: Enter", __func__); + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + WMA_LOGE("%s: Invalid CDS context", __func__); + return QDF_STATUS_E_INVAL; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGE("%s: Invalid wmi handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* dettach the wmi serice */ + WMA_LOGD("calling wmi_unified_detach"); + wmi_unified_detach(wma_handle->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_LOGD("%s: Exit", __func__); + 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; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGE("%s: Invalid wmi handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* remove the wmi work */ + WMA_LOGD("calling wmi_unified_remove_work"); + wmi_unified_remove_work(wma_handle->wmi_handle); + + 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; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGE("%s: Invalid wmi handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* Free DBS list */ + if (wma_handle->hw_mode.hw_mode_list) { + qdf_mem_free(wma_handle->hw_mode.hw_mode_list); + wma_handle->hw_mode.hw_mode_list = NULL; + WMA_LOGD("%s: DBS list is freed", __func__); + } + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { +#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); + } + + /* unregister Firmware debug log */ + qdf_status = dbglog_deinit(wma_handle->wmi_handle); + if (qdf_status != QDF_STATUS_SUCCESS) + WMA_LOGE("%s: dbglog_deinit failed", __func__); + + qdf_status = qdf_mc_timer_destroy(&wma_handle->service_ready_ext_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + WMA_LOGE("%s: Failed to destroy service ready ext event timer", + __func__); + + qdf_event_destroy(&wma_handle->target_suspend); + qdf_event_destroy(&wma_handle->wma_resume_event); + 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_vdev_resp_queue(wma_handle); + wma_cleanup_hold_req(wma_handle); + qdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock); + qdf_runtime_lock_deinit(&wma_handle->wmi_cmd_rsp_runtime_lock); + qdf_spinlock_destroy(&wma_handle->vdev_respq_lock); + qdf_spinlock_destroy(&wma_handle->wma_hold_req_q_lock); + + if (NULL != wma_handle->pGetRssiReq) { + qdf_mem_free(wma_handle->pGetRssiReq); + wma_handle->pGetRssiReq = NULL; + } + + wma_unified_radio_tx_mem_free(wma_handle); + + 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_get_cfg_int_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; + target_if_close(); + wma_target_if_close(wma_handle); + + WMA_LOGD("%s: Exit", __func__); + 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); + + 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_LOGD("%s: TX_MSDU_ID_PARTITION=%d", __func__, + value); +} +#else +static void wma_set_tx_partition_base(uint32_t value) +{ +} +#endif + +/** + * 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); +#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); +#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); + + 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_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); +} + +/** + * 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); + + /* RF chains */ + cfg->num_rf_chains = target_if_get_num_rf_chains(tgt_hdl); + + WMA_LOGD("%s: 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", __func__, + 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); + +} + +/** + * 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_LOGD("%s: 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", __func__, + 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_LOGE("%s: NULL new supported band variable", __func__); + 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_LOGE("%s: wrong supported band", __func__); + 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 + * @tx_chain: given tx chainmask value + * @rx_chain: given rx chainmask value + * @value: new HT 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_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 == NULL) + 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->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->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); + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!num_hw_modes) { + WMA_LOGD("%s: No extended HT cap for current SOC", __func__); + 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_LOGD("%s: [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", __func__, + 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); +} + +/** + * 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 == NULL) + 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; + + 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); + + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!num_hw_modes) { + WMA_LOGD("%s: No extended VHT cap for current SOC", __func__); + 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 (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)); + } + + WMA_LOGD("%s: [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", __func__, + 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); +} + +/** + * wma_update_ra_rate_limit() - update wma config + * @wma_handle: wma handle + * @cfg: target config + * + * Return: none + */ +#ifdef FEATURE_WLAN_RA_FILTERING +static void wma_update_ra_rate_limit(tp_wma_handle wma_handle, + struct wma_tgt_cfg *cfg) +{ + cfg->is_ra_rate_limit_enabled = wma_handle->IsRArateLimitEnabled; +} +#else +static void wma_update_ra_rate_limit(tp_wma_handle wma_handle, + struct wma_tgt_cfg *cfg) +{ +} +#endif + +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 + * + * 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) +{ + switch (supported_band) { + case WMI_11G_CAPABILITY: + case WMI_11NG_CAPABILITY: + tgt_cfg->band_cap = BAND_2G; + break; + case WMI_11A_CAPABILITY: + case WMI_11NA_CAPABILITY: + case WMI_11AC_CAPABILITY: + tgt_cfg->band_cap = BAND_5G; + break; + case WMI_11AG_CAPABILITY: + case WMI_11NAG_CAPABILITY: + default: + tgt_cfg->band_cap = BAND_ALL; + } +} + +/** + * 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; +} + +#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); + +} +#else +static void wma_green_ap_register_handlers(tp_wma_handle wma_handle) +{ +} +#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 wma_tgt_cfg *tgt_cfg, + struct target_psoc_info *tgt_hdl, + uint8_t phy) +{ + uint8_t num_chain; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = + tgt_hdl->info.mac_phy_cap; + + num_chain = wma_convert_chainmask_to_chain(mac_phy_cap[phy]. + tx_chain_mask_2G); + + if (num_chain > tgt_cfg->chain_cfg.max_tx_chains_2g) + tgt_cfg->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 > tgt_cfg->chain_cfg.max_tx_chains_5g) + tgt_cfg->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 > tgt_cfg->chain_cfg.max_rx_chains_2g) + tgt_cfg->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 > tgt_cfg->chain_cfg.max_rx_chains_5g) + tgt_cfg->chain_cfg.max_rx_chains_5g = num_chain; +} + +/** + * 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; + uint8_t i; + 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; + int ret; + + WMA_LOGD("%s: Enter", __func__); + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + WMA_LOGE("%s: target psoc info is NULL", __func__); + return -EINVAL; + } + + wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_hdl); + if (!wlan_res_cfg) { + WMA_LOGE("%s: wlan_res_cfg is null", __func__); + 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_handle) { + WMA_LOGE("%s: wmi handle is NULL", __func__); + return -EINVAL; + } + + 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; + + 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); + + 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.apf_enabled = wma_handle->apf_enabled; + tgt_cfg.dfs_cac_offload = wma_handle->is_dfs_offloaded; + tgt_cfg.rcpi_enabled = wma_handle->rcpi_enabled; + wma_update_ra_rate_limit(wma_handle, &tgt_cfg); + wma_update_hdd_band_cap(target_if_get_phy_capability(tgt_hdl), + &tgt_cfg); + 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); + + /* 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_cfg, tgt_hdl, i); + + ret = wma_handle->tgt_cfg_update_cb(hdd_ctx, &tgt_cfg); + if (ret) + return -EINVAL; + + target_if_store_pdev_target_if_ctx(wma_get_pdev_from_scn_handle); + target_pdev_set_wmi_handle(wma_handle->pdev->tgt_if_handle, + wma_handle->wmi_handle); + wma_green_ap_register_handlers(wma_handle); + return ret; +} + +/** + * wma_dump_dbs_hw_mode() - Print the DBS HW modes + * @wma_handle: WMA handle + * + * Prints the DBS HW modes sent by the FW as part + * of WMI ready event + * + * Return: None + */ +static void wma_dump_dbs_hw_mode(tp_wma_handle wma_handle) +{ + uint32_t i, param; + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + for (i = 0; i < wma_handle->num_dbs_hw_modes; i++) { + param = wma_handle->hw_mode.hw_mode_list[i]; + WMA_LOGD("%s:[%d]-MAC0: tx_ss:%d rx_ss:%d bw_idx:%d", + __func__, i, + WMA_HW_MODE_MAC0_TX_STREAMS_GET(param), + WMA_HW_MODE_MAC0_RX_STREAMS_GET(param), + WMA_HW_MODE_MAC0_BANDWIDTH_GET(param)); + WMA_LOGD("%s:[%d]-MAC1: tx_ss:%d rx_ss:%d bw_idx:%d", + __func__, i, + WMA_HW_MODE_MAC1_TX_STREAMS_GET(param), + WMA_HW_MODE_MAC1_RX_STREAMS_GET(param), + WMA_HW_MODE_MAC1_BANDWIDTH_GET(param)); + WMA_LOGD("%s:[%d] DBS:%d SBS:%d", __func__, i, + WMA_HW_MODE_DBS_MODE_GET(param), + WMA_HW_MODE_SBS_MODE_GET(param)); + } + policy_mgr_dump_dbs_hw_mode(wma_handle->psoc); +} + +/** + * 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_LOGD("%s: Enter", __func__); + + if (!psoc) { + WMA_LOGE("%s: obj psoc is NULL", __func__); + return; + } + + policy_mgr_init_dbs_config(psoc, scan_config, fw_config); +} + +/** + * wma_update_ra_limit() - update ra limit based on apf filter + * enabled or not + * @handle: wma handle + * + * Return: none + */ +#ifdef FEATURE_WLAN_RA_FILTERING +static void wma_update_ra_limit(tp_wma_handle wma_handle) +{ + if (wma_handle->apf_enabled) + wma_handle->IsRArateLimitEnabled = false; +} +#else +static void wma_update_ra__limit(tp_wma_handle handle) +{ +} +#endif + +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) { + WMA_LOGE("%s: wma handler is null", __func__); + 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_LOGE("Failed to set PMO capabilities; status:%d", status); +} + +static void wma_set_component_caps(struct wlan_objmgr_psoc *psoc) +{ + wma_set_pmo_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_handle) { + WMA_LOGE("%s: wma_handle passed is NULL", __func__); + 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 sevice ready event. + * @handle: wma handle + * @cmd_param_info: command params info + * + * 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_LOGD("%s: Enter", __func__); + + if (!handle) { + WMA_LOGE("%s: wma_handle passed is NULL", __func__); + return -EINVAL; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + WMA_LOGE("%s: target psoc info is NULL", __func__); + 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_LOGE("%s: Invalid arguments", __func__); + return -EINVAL; + } + + ev = param_buf->fixed_param; + if (!ev) { + WMA_LOGE("%s: Invalid buffer", __func__); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc); + if (!wmi_handle) { + WMA_LOGE("%s: wmi handle is NULL", __func__); + return -EINVAL; + } + + WMA_LOGD("WMA <-- WMI_SERVICE_READY_EVENTID"); + + if (ev->num_dbs_hw_modes > param_buf->num_wlan_dbs_hw_mode_list) { + WMA_LOGE("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; + } + + wma_handle->num_dbs_hw_modes = ev->num_dbs_hw_modes; + ev_wlan_dbs_hw_mode_list = param_buf->wlan_dbs_hw_mode_list; + wma_handle->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*wma_handle->hw_mode.hw_mode_list) * + wma_handle->num_dbs_hw_modes); + if (!wma_handle->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for DBS", __func__); + /* Continuing with the rest of the processing */ + } + + if (wma_handle->hw_mode.hw_mode_list) + qdf_mem_copy(wma_handle->hw_mode.hw_mode_list, + ev_wlan_dbs_hw_mode_list, + (sizeof(*wma_handle->hw_mode.hw_mode_list) * + wma_handle->num_dbs_hw_modes)); + + policy_mgr_init_dbs_hw_mode(wma_handle->psoc, + ev->num_dbs_hw_modes, ev_wlan_dbs_hw_mode_list); + wma_dump_dbs_hw_mode(wma_handle); + + /* 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_LOGD("%s: Firmware default hw mode index : %d", + __func__, tgt_cap_info->default_dbs_hw_mode_index); + WMA_LOGI("%s: Firmware build version : %08x", + __func__, ev->fw_build_vers); + WMA_LOGD("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_LOGI("%s: Board id: %x, Board version: %x %x %x %x %x", + __func__, 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 = wmi_unified_register_event_handler(wmi_handle, + wmi_host_swba_event_id, + wma_beacon_swba_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to register swba beacon event cb"); + goto free_hw_mode_list; + } +#ifdef WLAN_FEATURE_LPSS + wma_handle->lpss_support = + wmi_service_enabled(wmi_handle, wmi_service_lpass); +#endif /* WLAN_FEATURE_LPSS */ + + /* + * 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); + + wma_handle->apf_enabled = (wma_handle->apf_packet_filter_enable && + wmi_service_enabled(wmi_handle, wmi_service_apf_offload)); + wma_update_ra_limit(wma_handle); + + if (wmi_service_enabled(wmi_handle, wmi_service_csa_offload)) { + WMA_LOGD("%s: FW support CSA offload capability", __func__); + 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_LOGE("Failed to register CSA offload event cb"); + goto free_hw_mode_list; + } + } + + if (wmi_service_enabled(wmi_handle, wmi_service_mgmt_tx_wmi)) { + WMA_LOGD("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_LOGE("Failed to register MGMT over WMI completion handler"); + goto free_hw_mode_list; + } + + 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_LOGE("Failed to register MGMT over WMI completion handler"); + goto free_hw_mode_list; + } + + } else { + WMA_LOGE("FW doesnot 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_LOGE("Failed to register GTK offload event cb"); + goto free_hw_mode_list; + } + + 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_LOGE("Failed to register WMI_TBTTOFFSET_UPDATE_EVENTID callback"); + goto free_hw_mode_list; + } + + 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_LOGE("Failed to register RCPI event handler"); + goto free_hw_mode_list; + } + 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_LOGE("Failed to register log supported event cb"); + goto free_hw_mode_list; + } + + cdp_mark_first_wakeup_packet(soc, + 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_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_LOGE("Failed to send WMI_INIT_CMDID command"); + goto free_hw_mode_list; + } + + 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_LOGE("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; + +free_hw_mode_list: + if (wma_handle->hw_mode.hw_mode_list) { + qdf_mem_free(wma_handle->hw_mode.hw_mode_list); + wma_handle->hw_mode.hw_mode_list = NULL; + WMA_LOGD("%s: DBS list is freed", __func__); + } + + return -EINVAL; + +} + +/** + * wma_get_phyid_for_given_band() - to get phyid for band + * + * @wma_handle: Pointer to wma handle +* @tgt_hdl: target psoc information + * @band: enum value of for 2G or 5G band + * @phyid: Pointer to phyid which needs to be filled + * + * This API looks in to the map to find out which particular phy supports + * provided band and return the idx (also called phyid) of that phy. Caller + * use this phyid to fetch various caps of that phy + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_get_phyid_for_given_band( + tp_wma_handle wma_handle, + struct target_psoc_info *tgt_hdl, + enum cds_band_type band, uint8_t *phyid) +{ + uint8_t idx, i, num_radios; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + + if (!wma_handle) { + WMA_LOGE("Invalid wma handle"); + return QDF_STATUS_E_FAILURE; + } + + idx = 0; + *phyid = idx; + num_radios = target_psoc_get_num_radios(tgt_hdl); + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + + for (i = 0; i < num_radios; i++) { + if ((band == CDS_BAND_2GHZ) && + (WLAN_2G_CAPABILITY == mac_phy_cap[idx + i].supported_bands)) { + *phyid = idx + i; + WMA_LOGD("Select 2G capable phyid[%d]", *phyid); + return QDF_STATUS_SUCCESS; + } else if ((band == CDS_BAND_5GHZ) && + (WLAN_5G_CAPABILITY == mac_phy_cap[idx + i].supported_bands)) { + *phyid = idx + i; + WMA_LOGD("Select 5G capable phyid[%d]", *phyid); + return QDF_STATUS_SUCCESS; + } + } + WMA_LOGD("Using default single hw mode phyid[%d]", *phyid); + return QDF_STATUS_SUCCESS; +} + +/** + * 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 phyid, our_hw_mode = hw_mode, num_hw_modes; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + + if (!wma_handle) { + WMA_LOGE("Invalid wma handle"); + return QDF_STATUS_E_FAILURE; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + WMA_LOGE("%s: target psoc info is NULL", __func__); + return -EINVAL; + } + + 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); + + if (!num_hw_modes) { + WMA_LOGD("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; + caps_per_phy->he_5g = 0; + + return QDF_STATUS_SUCCESS; + } + + if (!policy_mgr_is_dbs_enable(wma_handle->psoc)) + our_hw_mode = HW_MODE_DBS_NONE; + + if (!caps_per_phy) { + WMA_LOGE("Invalid caps pointer"); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != + wma_get_phyid_for_given_band(wma_handle, tgt_hdl, band, &phyid)) { + WMA_LOGE("Invalid phyid"); + return QDF_STATUS_E_FAILURE; + } + + caps_per_phy->ht_2g = mac_phy_cap[phyid].ht_cap_info_2G; + caps_per_phy->ht_5g = mac_phy_cap[phyid].ht_cap_info_5G; + caps_per_phy->vht_2g = mac_phy_cap[phyid].vht_cap_info_2G; + caps_per_phy->vht_5g = mac_phy_cap[phyid].vht_cap_info_5G; + caps_per_phy->he_2g = mac_phy_cap[phyid].he_cap_info_2G; + caps_per_phy->he_5g = mac_phy_cap[phyid].he_cap_info_5G; + + caps_per_phy->tx_chain_mask_2G = mac_phy_cap->tx_chain_mask_2G; + caps_per_phy->rx_chain_mask_2G = mac_phy_cap->rx_chain_mask_2G; + caps_per_phy->tx_chain_mask_5G = mac_phy_cap->tx_chain_mask_5G; + caps_per_phy->rx_chain_mask_5G = mac_phy_cap->rx_chain_mask_5G; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_is_rx_ldpc_supported_for_channel() - to find out if ldpc is supported + * + * @channel: Channel number 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 channel) +{ + 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) { + WMA_LOGE("Invalid wma handle"); + return false; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + WMA_LOGE("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(channel)) + 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(channel)) + 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, mac_5G; + 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_LOGD("\t: index [%d]", index); + WMA_LOGD("\t: cap for hw_mode_id[%d]", cap->hw_mode_id); + WMA_LOGD("\t: pdev_id[%d]", cap->pdev_id); + WMA_LOGD("\t: phy_id[%d]", cap->phy_id); + WMA_LOGD("\t: hw_mode_config_type[%d]", cap->hw_mode_config_type); + WMA_LOGD("\t: supports_11b[%d]", cap->supports_11b); + WMA_LOGD("\t: supports_11g[%d]", cap->supports_11g); + WMA_LOGD("\t: supports_11a[%d]", cap->supports_11a); + WMA_LOGD("\t: supports_11n[%d]", cap->supports_11n); + WMA_LOGD("\t: supports_11ac[%d]", cap->supports_11ac); + WMA_LOGD("\t: supports_11ax[%d]", cap->supports_11ax); + WMA_LOGD("\t: supported_bands[%d]", cap->supported_bands); + WMA_LOGD("\t: ampdu_density[%d]", cap->ampdu_density); + WMA_LOGD("\t: max_bw_supported_2G[%d]", cap->max_bw_supported_2G); + WMA_LOGD("\t: ht_cap_info_2G[%d]", cap->ht_cap_info_2G); + WMA_LOGD("\t: vht_cap_info_2G[%d]", cap->vht_cap_info_2G); + WMA_LOGD("\t: vht_supp_mcs_2G[%d]", cap->vht_supp_mcs_2G); + WMA_LOGD("\t: tx_chain_mask_2G[%d]", cap->tx_chain_mask_2G); + WMA_LOGD("\t: rx_chain_mask_2G[%d]", cap->rx_chain_mask_2G); + WMA_LOGD("\t: max_bw_supported_5G[%d]", cap->max_bw_supported_5G); + WMA_LOGD("\t: ht_cap_info_5G[%d]", cap->ht_cap_info_5G); + WMA_LOGD("\t: vht_cap_info_5G[%d]", cap->vht_cap_info_5G); + WMA_LOGD("\t: vht_supp_mcs_5G[%d]", cap->vht_supp_mcs_5G); + WMA_LOGD("\t: tx_chain_mask_5G[%d]", cap->tx_chain_mask_5G); + WMA_LOGD("\t: rx_chain_mask_5G[%d]", cap->rx_chain_mask_5G); + WMA_LOGD("\t: he_cap_info_2G[%08x]", cap->he_cap_info_2G); + WMA_LOGD("\t: he_supp_mcs_2G[%08x]", cap->he_supp_mcs_2G); + WMA_LOGD("\t: he_cap_info_5G[%08x]", cap->he_cap_info_5G); + WMA_LOGD("\t: he_supp_mcs_5G[%08x]", cap->he_supp_mcs_5G); + mac_2G = cap->he_cap_info_2G; + mac_5G = cap->he_cap_info_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(mac_2G); + wma_print_he_phy_cap(phy_2G); + wma_print_he_ppet(&ppet_2G); + wma_print_he_mac_cap(mac_5G); + 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_info: 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_LOGD("%s: num of hw modes [%d]", __func__, num_hw_modes); + WMA_LOGD("%s: num mac_phy_cnt [%d]", __func__, total_mac_phy_cnt); + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + WMA_LOGD("%s: <====== HW mode cap printing starts ======>", __func__); + /* print cap of each hw mode */ + for (i = 0; i < total_mac_phy_cnt; i++) { + WMA_LOGD("====>: hw mode id[%d], phy_id map[%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_LOGD("%s: <====== HW mode cap printing ends ======>\n", __func__); +} + +/** + * wma_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 wma_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; + default: + return HW_MODE_BW_NONE; + } + + return HW_MODE_BW_NONE; +} + +/** + * wma_get_hw_mode_params() - get TX-RX stream and bandwidth + * supported from the capabilities. + * @caps: PHY capability + * @info: param to store TX-RX stream and BW information + * + * This function will calculate TX-RX stream and bandwidth supported + * as per the PHY capability, and assign to mac_ss_bw_info. + * + * Return: none + */ +static void wma_get_hw_mode_params(struct wlan_psoc_host_mac_phy_caps *caps, + struct mac_ss_bw_info *info) +{ + if (!caps) { + WMA_LOGE("%s: Invalid capabilities", __func__); + return; + } + + info->mac_tx_stream = wma_get_num_of_setbits_from_bitmask( + QDF_MAX(caps->tx_chain_mask_2G, + caps->tx_chain_mask_5G)); + info->mac_rx_stream = wma_get_num_of_setbits_from_bitmask( + QDF_MAX(caps->rx_chain_mask_2G, + caps->rx_chain_mask_5G)); + info->mac_bw = wma_map_wmi_channel_width_to_hw_mode_bw( + QDF_MAX(caps->max_bw_supported_2G, + caps->max_bw_supported_5G)); +} + +/** + * wma_set_hw_mode_params() - sets TX-RX stream, bandwidth and + * DBS in hw_mode_list + * @wma_handle: pointer to wma global structure + * @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_index + * @dbs_mode: dbs_mode for the dbs_hw_mode + * @sbs_mode: sbs_mode for the sbs_hw_mode + * + * This function sets TX-RX stream, bandwidth and DBS mode in + * hw_mode_list. + * + * Return: none + */ +static void wma_set_hw_mode_params(t_wma_handle *wma_handle, + struct mac_ss_bw_info mac0_ss_bw_info, + struct mac_ss_bw_info mac1_ss_bw_info, + uint32_t pos, uint32_t dbs_mode, + uint32_t sbs_mode) +{ + WMA_HW_MODE_MAC0_TX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_tx_stream); + WMA_HW_MODE_MAC0_RX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_rx_stream); + WMA_HW_MODE_MAC0_BANDWIDTH_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_bw); + WMA_HW_MODE_MAC1_TX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_tx_stream); + WMA_HW_MODE_MAC1_RX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_rx_stream); + WMA_HW_MODE_MAC1_BANDWIDTH_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_bw); + WMA_HW_MODE_DBS_MODE_SET( + wma_handle->hw_mode.hw_mode_list[pos], + dbs_mode); + WMA_HW_MODE_AGILE_DFS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + HW_MODE_AGILE_DFS_NONE); + WMA_HW_MODE_SBS_MODE_SET( + wma_handle->hw_mode.hw_mode_list[pos], + sbs_mode); +} + +/** + * 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; + uint32_t dbs_mode, sbs_mode; + struct mac_ss_bw_info mac0_ss_bw_info = {0}; + struct mac_ss_bw_info mac1_ss_bw_info = {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_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + 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); + /* + * This list was updated as part of service ready event. Re-populate + * HW mode list from the device capabilities. + */ + if (wma_handle->hw_mode.hw_mode_list) { + qdf_mem_free(wma_handle->hw_mode.hw_mode_list); + wma_handle->hw_mode.hw_mode_list = NULL; + WMA_LOGD("%s: DBS list is freed", __func__); + } + + wma_handle->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*wma_handle->hw_mode.hw_mode_list) * + num_hw_modes); + if (!wma_handle->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for DBS", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Updated HW mode list: Num modes:%d", + __func__, num_hw_modes); + + for (i = 0; i < num_hw_modes; i++) { + /* Update for MAC0 */ + tmp = &mac_phy_cap[j++]; + wma_get_hw_mode_params(tmp, &mac0_ss_bw_info); + hw_config_type = tmp->hw_mode_config_type; + dbs_mode = HW_MODE_DBS_NONE; + sbs_mode = HW_MODE_SBS_NONE; + mac1_ss_bw_info.mac_tx_stream = 0; + mac1_ss_bw_info.mac_rx_stream = 0; + mac1_ss_bw_info.mac_bw = 0; + 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)) { + /* Update for MAC1 */ + tmp = &mac_phy_cap[j++]; + wma_get_hw_mode_params(tmp, &mac1_ss_bw_info); + if (hw_config_type == WMI_HW_MODE_DBS) + dbs_mode = HW_MODE_DBS; + if ((hw_config_type == WMI_HW_MODE_SBS_PASSIVE) || + (hw_config_type == WMI_HW_MODE_SBS)) + sbs_mode = HW_MODE_SBS; + if (QDF_STATUS_SUCCESS != + wma_update_supported_bands(tmp->supported_bands, + &new_supported_band)) + supported_band_update_failure = true; + } + + /* Updating HW mode list */ + wma_set_hw_mode_params(wma_handle, mac0_ss_bw_info, + mac1_ss_bw_info, i, dbs_mode, + sbs_mode); + } + + /* overwrite phy_capability which we got from service ready event */ + if (!supported_band_update_failure) { + WMA_LOGD("%s: updating supported band from old[%d] to new[%d]", + __func__, 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_LOGE("%s: failed to update policy manager", __func__); + wma_dump_dbs_hw_mode(wma_handle); + 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_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + void *hal_soc; + + if (!hif_ctx) { + WMA_LOGE("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_LOGD("%s: Enter", __func__); + + 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_rx_service_ready_ext_event() - evt handler for sevice 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; + uint32_t conc_scan_config_bits, fw_config_bits; + struct wmi_unified *wmi_handle; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + target_resource_config *wlan_res_cfg; + + WMA_LOGD("%s: Enter", __func__); + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc); + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + WMA_LOGE("%s: target psoc info is NULL", __func__); + 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_LOGE("%s: Invalid event", __func__); + return -EINVAL; + } + + ev = param_buf->fixed_param; + if (!ev) { + WMA_LOGE("%s: Invalid buffer", __func__); + return -EINVAL; + } + + WMA_LOGD("WMA <-- WMI_SERVICE_READY_EXT_EVENTID"); + + 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_LOGD("%s: Defaults: scan config:%x FW mode config:%x", + __func__, conc_scan_config_bits, fw_config_bits); + + ret = qdf_mc_timer_stop(&wma_handle->service_ready_ext_timer); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + WMA_LOGE("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_LOGE("Failed to update hw mode list"); + return -EINVAL; + } + + WMA_LOGD("WMA --> WMI_INIT_CMDID"); + + wma_init_scan_fw_mode_config(wma_handle->psoc, conc_scan_config_bits, + fw_config_bits); + + target_psoc_set_num_radios(tgt_hdl, 1); + + 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 (wma_handle->enable_peer_unmap_conf_support && + 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 (wma_handle->enable_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; + } + + 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_LOGD("%s: Enter", __func__); + + param_buf = (WMI_READY_EVENTID_param_tlvs *) cmd_param_info; + if (!(wma_handle && param_buf)) { + WMA_LOGE("%s: Invalid arguments", __func__); + QDF_ASSERT(0); + return -EINVAL; + } + + WMA_LOGD("WMA <-- WMI_READY_EVENTID"); + + 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_LOGD("Exit"); + + return 0; +} + +/** + * wma_setneedshutdown() - setting wma needshutdown flag + * + * Return: none + */ +void wma_setneedshutdown(void) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid arguments", __func__); + QDF_ASSERT(0); + return; + } + + wma_handle->needShutdown = true; + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_needshutdown() - Is wma needs shutdown? + * + * Return: returns true/false + */ +bool wma_needshutdown(void) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid arguments", __func__); + QDF_ASSERT(0); + return false; + } + + WMA_LOGD("%s: Exit", __func__); + return wma_handle->needShutdown; +} + +/** + * 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"); + 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 (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + 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_LOGD("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_LOGE("%s:INVALID PPS CONFIG", __func__); + } + + 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 (NULL == wma || NULL == mas_val) { + WMA_LOGE("%s: Invalid input to enable/disable MAS", __func__); + return QDF_STATUS_E_FAILURE; + } + + val = (*mas_val); + + if (QDF_STATUS_SUCCESS != + wma_set_enable_disable_mcc_adaptive_scheduler(val)) { + WMA_LOGE("%s: Unable to enable/disable MAS", __func__); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGE("%s: Value is %d", __func__, 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 (NULL == wma || NULL == miracast_val) { + WMA_LOGE("%s: Invalid input to store miracast value", __func__); + return QDF_STATUS_E_FAILURE; + } + + wma->miracast_value = *miracast_val; + WMA_LOGE("%s: Miracast value is %d", __func__, 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 (NULL == wma || NULL == avg_factor) { + WMA_LOGE("%s: Invalid input of stats avg factor", __func__); + 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_LOGE(" failed to set avg_factor for vdev_id %d", + avg_factor->vdev_id); + } + + WMA_LOGD("%s: Set stats_avg_factor %d for vdev_id %d", __func__, + 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 (NULL == wma || NULL == guard_time) { + WMA_LOGE("%s: Invalid input of guard time", __func__); + 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_LOGE(" failed to set guard time for vdev_id %d", + guard_time->vdev_id); + } + + WMA_LOGD("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_LOGE("%s: start_log pointer is NULL", __func__); + return; + } + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + if (!((start_log->ring_id == RING_ID_CONNECTIVITY) || + (start_log->ring_id == RING_ID_FIRMWARE_DEBUG))) { + WMA_LOGD("%s: Not connectivity or fw debug ring: %d", + __func__, 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: Struture 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 + * + */ +#ifdef 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_LOGE("%s: start_log pointer is NULL", __func__); + return; + } + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + /* No need to register for ring IDs other than packet stats */ + if (start_log->ring_id != RING_ID_PER_PACKET_STATS) { + WMA_LOGD("%s: Ring id is not for per packet stats: %d", + __func__, start_log->ring_id); + return; + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (scn == NULL) { + WMA_LOGE("%s: Invalid HIF handle", __func__); + return; + } + +#ifdef HELIUMPLUS + log_state = ATH_PKTLOG_ANI | ATH_PKTLOG_RCUPDATE | ATH_PKTLOG_RCFIND | + ATH_PKTLOG_RX | ATH_PKTLOG_TX | + ATH_PKTLOG_TEXT | ATH_PKTLOG_SW_EVENT; +#else + log_state = ATH_PKTLOG_LITE_T2H | ATH_PKTLOG_LITE_RX; +#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_LOGD("%s: Enabling per packet stats", __func__); + } else { + pktlog_enable(scn, 0, start_log->ini_triggered, + start_log->user_triggered, + start_log->is_iwpriv_command); + WMA_LOGD("%s: Disabling per packet stats", __func__); + } +} +#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; + int ret; + + ret = wmi_unified_flush_logs_to_fw_cmd(wma_handle->wmi_handle); + if (ret != EOK) + return; + + status = qdf_mc_timer_start(&wma_handle->log_completion_timer, + WMA_LOG_COMPLETION_TIMER); + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("Failed to start the log completion timer"); +} + +/** + * wma_update_wep_default_key - To update default key id + * @wma: pointer to wma handler + * @update_def_key: pointer to wep_update_default_key_idx + * + * This function makes a copy of default key index to txrx node + * + * Return: Success + */ +static QDF_STATUS wma_update_wep_default_key(tp_wma_handle wma, + struct wep_update_default_key_idx *update_def_key) +{ + struct wma_txrx_node *iface = + &wma->interfaces[update_def_key->session_id]; + iface->wep_default_key_idx = update_def_key->default_idx; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_tx_fail_cnt_th() - Set threshold for TX pkt fail + * @wma_handle: 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: VOS_STATUS_SUCCESS on success, error number otherwise + */ +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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue Tx pkt fail count threshold")); + 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_LOGD("Set TX pkt fail count threshold vdevId %d count %d", + vdev_id, tx_fail_disconn_th); + + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DISCONNECT_TH, + tx_fail_disconn_th); + + if (ret) { + WMA_LOGE(FL("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_handle: 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: VOS_STATUS_SUCCESS on success, error number otherwise + */ +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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("WMA is closed, can not issue short retry limit threshold"); + return QDF_STATUS_E_INVAL; + } + vdev_id = short_retry_limit_th->session_id; + short_retry_limit = short_retry_limit_th->short_retry_limit; + WMA_LOGD("Set short retry limit threshold vdevId %d count %d", + vdev_id, short_retry_limit); + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_NON_AGG_SW_RETRY_TH, + short_retry_limit); + + if (ret) { + WMA_LOGE("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_handle: 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: VOS_STATUS_SUCCESS on success, error number otherwise + */ +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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("WMA is closed, can not issue long retry limit threshold"); + return QDF_STATUS_E_INVAL; + } + vdev_id = long_retry_limit_th->session_id; + long_retry_limit = long_retry_limit_th->long_retry_limit; + WMA_LOGD("Set TX pkt fail count threshold vdevId %d count %d", + vdev_id, long_retry_limit); + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AGG_SW_RETRY_TH, + long_retry_limit); + + if (ret) { + WMA_LOGE("Failed to send long limit threshold command"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * 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; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("WMA is closed, can not issue sta_inactivity_timeout"); + 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; + + if (wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + min_inactive_time)) + WMA_LOGE("Failed to Set AP MIN IDLE INACTIVE TIME"); + + if (wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + max_inactive_time)) + WMA_LOGE("Failed to Set AP MAX IDLE INACTIVE TIME"); + + if (wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + max_unresponsive_time)) + WMA_LOGE("Failed to Set MAX UNRESPONSIVE TIME"); + + WMA_LOGD("%s:vdev_id:%d min_inactive_time: %u max_inactive_time: %u max_unresponsive_time: %u", + __func__, vdev_id, + min_inactive_time, max_inactive_time, + max_unresponsive_time); +} + +#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 + * @udp_response: 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) { + WMA_LOGE("wmi_buf_alloc failed"); + 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 = WMI_WOW_PULSE_REPEAT_CNT; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID)) { + WMA_LOGE("Failed to send send wow pulse"); + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Exit", __func__); + 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_DEBUGFS +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_handle) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + 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_LOGD("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) { + WMA_LOGE("%s: Failed to send power debug stats request", + __func__); + 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_LOGD("%s: Enter", __func__); + if (!wma_handle) { + WMA_LOGE("%s: input pointer is NULL", __func__); + 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_LOGD("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_LOGD("%s: Exit", __func__); + 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 + * @wma_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) +{ + int status; + struct set_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + if (!wma_is_vdev_valid(req_buf->vdev_id)) { + WMA_LOGE("vdev id not active or not valid"); + return; + } + + arp_stats = (struct set_arp_stats *)req_buf; + status = wmi_unified_set_arp_stats_req(wma_handle->wmi_handle, + arp_stats); + if (status != EOK) + WMA_LOGE("%s: failed to set arp stats to FW", + __func__); +} + +/** + * 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) +{ + int status; + struct get_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + if (!wma_is_vdev_valid(req_buf->vdev_id)) { + WMA_LOGE("vdev id not active or not valid"); + return; + } + + arp_stats = (struct get_arp_stats *)req_buf; + status = wmi_unified_get_arp_stats_req(wma_handle->wmi_handle, + arp_stats); + if (status != EOK) + WMA_LOGE("%s: failed to send get arp stats to FW", + __func__); +} + +/** + * 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) +{ + int status; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("WMA is closed, cannot send set del pmkid"); + return; + } + + status = wmi_unified_set_del_pmkid_cache(wma_handle->wmi_handle, + pmk_cache); + if (status != EOK) + WMA_LOGE("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; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("WMA is closed, cannot send invoke neighbor report"); + return; + } + + status = wmi_unified_invoke_neighbor_report_cmd(wma_handle->wmi_handle, + params); + + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("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_LOGE(FL("invalid pointer")); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle) { + WMA_LOGE(FL("WMA context is invald!")); + return QDF_STATUS_E_INVAL; + } + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + + if (!buf) { + WMA_LOGE(FL("Failed allocate wmi buffer")); + 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_LOGD("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) { + WMA_LOGE(FL("Failed to send aggregation timeout")); + 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_LOGE(FL("invalid pointer")); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle) { + WMA_LOGE(FL(" WMA context is invald!")); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + + if (!buf) { + WMA_LOGE(FL("Failed allocate wmi buffer")); + 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_LOGD("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) { + WMA_LOGE(FL("Failed to send aggregation size command")); + 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_handle) { + WMA_LOGE(FL("WMA is closed, can not issue cmd")); + return QDF_STATUS_E_INVAL; + } + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + 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)) { + WMA_LOGE(FL("failed to send get chain rssi command")); + 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) { + WMA_LOGE("%s : Memory allocation failed", __func__); + 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_LOGD("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_set_limit_off_chan() - set limit off chanel 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_LOGE(FL("Invalid vdev_id: %d"), param->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (!wma_is_vdev_up(param->vdev_id)) { + WMA_LOGD("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_LOGE("\n 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_LOGE(FL("Invalid vdev_id: %d"), cfg->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (!wma_is_vdev_up(cfg->vdev_id)) { + WMA_LOGE("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_LOGE("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_LOGE(FL("Invalid vdev_id: %d"), cfg->vdev_id); + return; + } + if (!wma_is_vdev_up(cfg->vdev_id)) { + WMA_LOGE("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_LOGE("Failed to send obss detection cfg"); + + return; +} + +/** + * 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; + struct cdp_vdev *txrx_vdev_handle = NULL; + + extern uint8_t *mac_trace_get_wma_msg_string(uint16_t wmaMsg); + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (NULL == msg) { + WMA_LOGE("msg is NULL"); + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + WMA_LOGD("msg->type = %x %s", msg->type, + mac_trace_get_wma_msg_string(msg->type)); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + QDF_ASSERT(0); + qdf_mem_free(msg->bodyptr); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + switch (msg->type) { + + /* Message posted by wmi for all control path related + * FW events to serialize through mc_thread. + */ + case WMA_PROCESS_FW_EVENT: + wma_process_fw_event(wma_handle, + (wma_process_fw_event_params *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + +#ifdef FEATURE_WLAN_ESE + case WMA_TSM_STATS_REQ: + WMA_LOGD("McThread: WMA_TSM_STATS_REQ"); + wma_process_tsm_stats_req(wma_handle, (void *)msg->bodyptr); + break; +#endif /* FEATURE_WLAN_ESE */ + case WNI_CFG_DNLD_REQ: + WMA_LOGD("McThread: WNI_CFG_DNLD_REQ"); + qdf_status = wma_wni_cfg_dnld(wma_handle); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + cds_wma_complete_cback(); + else + WMA_LOGD("config download failure"); + break; + case WMA_ADD_STA_SELF_REQ: + txrx_vdev_handle = + wma_vdev_attach(wma_handle, + (struct add_sta_self_params *) msg-> + bodyptr, 1); + if (!txrx_vdev_handle) { + WMA_LOGE("Failed to attach vdev"); + } else { + /* Register with TxRx Module for Data Ack Complete Cb */ + if (soc) { + cdp_data_tx_cb_set(soc, txrx_vdev_handle, + wma_data_tx_ack_comp_hdlr, + wma_handle); + } else { + WMA_LOGE("%s: SOC context is NULL", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + } + break; + case WMA_DEL_STA_SELF_REQ: + wma_vdev_detach(wma_handle, + (struct del_sta_self_params *) msg->bodyptr, 1); + break; + case WMA_UPDATE_CHAN_LIST_REQ: + wma_update_channel_list(wma_handle, + (tSirUpdateChanList *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_LINK_STATE: + wma_set_linkstate(wma_handle, (tpLinkStateParams) msg->bodyptr); + break; + case WMA_CHNL_SWITCH_REQ: + wma_set_channel(wma_handle, + (tpSwitchChannelParams) msg->bodyptr); + break; + case WMA_ADD_BSS_REQ: + wma_add_bss(wma_handle, (tpAddBssParams) 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_SET_BSSKEY_REQ: + wma_set_bsskey(wma_handle, (tpSetBssKeyParams) msg->bodyptr); + break; + case WMA_SET_STAKEY_REQ: + wma_set_stakey(wma_handle, (tpSetStaKeyParams) 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, + (tpDeleteBssParams) msg->bodyptr); + break; + case WMA_DELETE_BSS_REQ: + wma_delete_bss(wma_handle, (tpDeleteBssParams) msg->bodyptr); + 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_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) + 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_ENTER_PS_REQ: + wma_enable_sta_ps_mode(wma_handle, + (tpEnablePsParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXIT_PS_REQ: + wma_disable_sta_ps_mode(wma_handle, + (tpDisablePsParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + 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, + (tSirKeepAliveReq *) msg->bodyptr); + break; +#ifdef FEATURE_WLAN_ESE + case WMA_SET_PLM_REQ: + wma_config_plm(wma_handle, (tpSirPlmReq) msg->bodyptr); + break; +#endif + case WMA_GET_STATISTICS_REQ: + wma_get_stats_req(wma_handle, + (tAniGetPEStatsReq *) msg->bodyptr); + break; + + case WMA_CONFIG_PARAM_UPDATE_REQ: + wma_update_cfg_params(wma_handle, msg); + break; + + 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, (tAddTsParams *) msg->bodyptr); + break; + + case WMA_DEL_TS_REQ: + wma_del_ts_req(wma_handle, (tDelTsParams *) msg->bodyptr); + break; + + case WMA_AGGR_QOS_REQ: + wma_aggr_qos_req(wma_handle, (tAggrAddTsParams *) 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_SCAN_OFFLOAD_REQ: + /* + * Main entry point or roaming directives from CSR. + */ + wma_process_roaming_config(wma_handle, + (tSirRoamOffloadScanReq *) 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, + (tTdlsPeerStateParams *) msg->bodyptr); + break; + case WMA_TDLS_SET_OFFCHAN_MODE: + wma_set_tdls_offchan_mode(wma_handle, + (tdls_chan_switch_params *)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, + (tSirTxPowerLimit *) 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_IBSS_CESIUM_ENABLE_IND: + wma_process_cesium_enable_ind(wma_handle); + break; + case WMA_GET_IBSS_PEER_INFO_REQ: + wma_process_get_peer_info_req(wma_handle, + (tSirIbssGetPeerInfoReqParams *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TX_FAIL_MONITOR_IND: + wma_process_tx_fail_monitor_ind(wma_handle, + (tAniTXFailMonitorInd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_RMC_ENABLE_IND: + wma_process_rmc_enable_ind(wma_handle); + break; + case WMA_RMC_DISABLE_IND: + wma_process_rmc_disable_ind(wma_handle); + break; + case WMA_RMC_ACTION_PERIOD_IND: + wma_process_rmc_action_period_ind(wma_handle); + 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_PEER_INFO: + wma_get_peer_info(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_PEER_INFO_EXT: + wma_get_peer_info_ext(wma_handle, 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 */ + case WMA_HIDDEN_SSID_VDEV_RESTART: + wma_hidden_ssid_vdev_restart(wma_handle, + (tHalHiddenSsidVdevRestart *) msg->bodyptr); + break; +#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, + (tSirWifiScanCmdReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_STOP_REQ: + wma_stop_extscan(wma_handle, + (tSirExtScanStopReqParams *) 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, + (tSirExtScanGetCachedResultsReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_GET_CAPABILITIES_REQ: + wma_extscan_get_capabilities(wma_handle, + (tSirGetExtScanCapabilitiesReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_EPNO_LIST_REQ: + wma_set_epno_network_list(wma_handle, + (struct wifi_epno_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_PER_ROAM_CONFIG_CMD: + wma_update_per_roam_config(wma_handle, + (struct wmi_per_roam_config_req *)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, + (struct wifi_passpoint_req *)msg->bodyptr); + + wma_set_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_RESET_PASSPOINT_LIST_REQ: + wma_reset_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)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 */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WMA_ROAM_OFFLOAD_SYNCH_FAIL: + wma_process_roam_synch_fail(wma_handle, + (struct roam_offload_synch_fail *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_ROAM_INVOKE: + wma_process_roam_invoke(wma_handle, + (struct wma_roam_invoke_cmd *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef WLAN_FEATURE_NAN + case WMA_NAN_REQUEST: + wma_nan_req(wma_handle, (tNanRequest *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_NAN */ + 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, + (tSirDhcpSrvOffloadInfo *) 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, + (struct rssi_monitor_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_PDEV_SET_PCL_TO_FW: + wma_send_pdev_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 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_LRO_CONFIG_CMD: + wma_lro_config_cmd(wma_handle, + (struct cdp_lro_hash_config *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GW_PARAM_UPDATE_REQ: + wma_set_gateway_params(wma_handle, + (struct gateway_param_update_req *)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_UPDATE_WEP_DEFAULT_KEY: + wma_update_wep_default_key(wma_handle, + (struct wep_update_default_key_idx *)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, + (struct wmi_unified_pmk_cache *) 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_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 + default: + WMA_LOGD("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) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Timeout occurred for log completion command", __func__); + + wma_handle = (tp_wma_handle) data; + if (!wma_handle) + WMA_LOGE("%s: Invalid WMA handle", __func__); + + /* 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 + */ +static 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_NON_PCL_CHANNELS: + return WMI_PCL_WEIGHT_LOW; + default: + return WMI_PCL_WEIGHT_DISALLOW; + } +} + +/** + * wma_send_pdev_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_pdev_set_pcl_cmd(tp_wma_handle wma_handle, + struct set_pcl_req *msg) +{ + uint32_t i; + QDF_STATUS status; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + for (i = 0; i < wma_handle->saved_chan.num_channels; i++) { + msg->chan_weights.saved_chan_list[i] = + wma_handle->saved_chan.channel_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); + + 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]); + /* Dont allow roaming on 2G when 5G_ONLY configured */ + if (((wma_handle->bandcapability == BAND_5G) || + (msg->band == BAND_5G)) && + (WLAN_REG_IS_24GHZ_CH( + msg->chan_weights.saved_chan_list[i]))) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + } + if ((msg->band == BAND_2G) && + WLAN_REG_IS_5GHZ_CH(msg->chan_weights.saved_chan_list[i])) + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + WMA_LOGD("%s: chan:%d weight[%d]=%d", __func__, + msg->chan_weights.saved_chan_list[i], i, + msg->chan_weights.weighed_valid_list[i]); + } + + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("%s: Error in creating weighed pcl", __func__); + return status; + } + + 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_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + /* Handle is NULL. Will not be able to send failure + * response as well + */ + return QDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set HW mode param is NULL", __func__); + /* 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_LOGE("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) { + WMA_LOGE("%s: Memory allocation failed", __func__); + 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_LOGE("%s: Sending HW mode fail response to LIM", __func__); + 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_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set dual mode config is NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + /* + * aquire 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_CMD_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_LOGE("%s: Failed to send WMI_PDEV_SET_DUAL_MAC_CONFIG_CMDID: %d", + __func__, status); + wma_release_wakelock(&wma_handle->wmi_cmd_rsp_wake_lock); + goto fail; + } + policy_mgr_update_dbs_req_config(wma_handle->psoc, + msg->scan_config, msg->fw_mode_config); + + 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_LOGE("Failed to allocate request for SIR_HAL_PDEV_DUAL_MAC_CFG_REQ"); + wma_remove_req(wma_handle, 0, WMA_PDEV_MAC_CFG_RESP); + } + + 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_LOGE("%s: Sending failure response to LIM", __func__); + 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_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set antenna mode param is NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + 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 = WMI_PDEV_ID_SOC; + /* 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_LOGD("%s: Num of chains TX: %d RX: %d txrx_chains: 0x%x", + __func__, 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)) { + WMA_LOGE("%s: Failed to send WMI_PDEV_SET_ANTENNA_MODE_CMDID", + __func__); + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + goto resp; + } + status = QDF_STATUS_SUCCESS; + +resp: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + WMA_LOGE("%s: Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + param->status = (status) ? + SET_ANTENNA_MODE_STATUS_ECANCELED : + SET_ANTENNA_MODE_STATUS_OK; + WMA_LOGE("%s: Send antenna mode resp to LIM status: %d", + __func__, 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); +} + +#ifdef RECEIVE_OFFLOAD +int wma_lro_init(struct cdp_lro_hash_config *lro_config) +{ + struct scheduler_msg msg = {0}; + struct cdp_lro_hash_config *iwcmd; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + WMA_LOGE("memory allocation for WMA_LRO_CONFIG_CMD failed!"); + return -ENOMEM; + } + + *iwcmd = *lro_config; + + msg.type = WMA_LRO_CONFIG_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)) { + WMA_LOGE("Failed to post WMA_LRO_CONFIG_CMD msg!"); + qdf_mem_free(iwcmd); + return -EAGAIN; + } + + WMA_LOGD("sending the LRO configuration to the fw"); + return 0; +} +#endif + +void wma_peer_set_default_routing(void *scn_handle, uint8_t *peer_macaddr, + uint8_t vdev_id, bool hash_based, uint8_t ring_num) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct peer_set_params param; + + if (!wma) { + WMA_LOGE("%s:wma_handle is NULL", __func__); + return; + } + + /* TODO: Need bit definitions for ring number and hash based routing + * fields in common wmi header file + */ + param.param_id = WMI_HOST_PEER_SET_DEFAULT_ROUTING; + param.vdev_id = vdev_id; + param.param_value = ((hash_based) ? 1 : 0) | (ring_num << 1); + WMA_LOGD("%s: param_value 0x%x", __func__, param.param_value); + wmi_set_peer_param_send(wma->wmi_handle, peer_macaddr, ¶m); +} + +int wma_peer_rx_reorder_queue_setup(void *scn_handle, + uint8_t vdev_id, uint8_t *peer_macaddr, qdf_dma_addr_t hw_qdesc, + int tid, uint16_t queue_no) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct rx_reorder_queue_setup_params param; + + if (!wma) { + WMA_LOGE("%s:wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + param.tid = tid; + param.vdev_id = vdev_id; + param.peer_macaddr = peer_macaddr; + param.hw_qdesc_paddr_lo = hw_qdesc & 0xffffffff; + param.hw_qdesc_paddr_hi = (uint64_t)hw_qdesc >> 32; + param.queue_no = queue_no; + + return wmi_unified_peer_rx_reorder_queue_setup_send(wma->wmi_handle, + ¶m); +} + +int wma_peer_rx_reorder_queue_remove(void *scn_handle, + uint8_t vdev_id, uint8_t *peer_macaddr, uint32_t peer_tid_bitmap) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct rx_reorder_queue_remove_params param; + + if (!wma) { + WMA_LOGE("%s:wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + param.vdev_id = vdev_id; + param.peer_macaddr = peer_macaddr; + param.peer_tid_bitmap = peer_tid_bitmap; + + return wmi_unified_peer_rx_reorder_queue_remove_send(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) { + WMA_LOGE("%s: Failed to get wma", __func__); + 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_LOGE("Failed to set SMPS Param"); + + return status; +} + + +void wma_ipa_uc_stat_request(wma_cli_set_cmd_t *privcmd) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return; + } + + if (wma_set_priv_cfg(wma, privcmd)) + WMA_LOGE("Failed to set wma priv congiuration"); +} + +/** + * 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) { + WMA_LOGE("%s: Failed to get wma", __func__); + return status; + } + + status = wma_roam_scan_bmiss_cnt(wma_handle, first_cnt, final_cnt, + vdev_id); + + if (status) + WMA_LOGE("Failed to set Bmiss Param"); + + return status; +} + diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_mgmt.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..4f87a4d8bfede3276e9c9794368c870a8f0cad3d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_mgmt.c @@ -0,0 +1,4483 @@ +/* + * 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_mgmt.c + * + * This file contains STA/SAP/IBSS 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 "cfg_api.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" +#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 +#include "wma_twt.h" +#include +#include + +/** + * wma_send_bcn_buf_ll() - prepare and send beacon buffer to fw for LL + * @wma: wma handle + * @pdev: txrx pdev + * @vdev_id: vdev id + * @param_buf: SWBA parameters + * + * Return: none + */ +static void wma_send_bcn_buf_ll(tp_wma_handle wma, + struct cdp_pdev *pdev, + 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_LOGE("%s: Invalid beacon buffer", __func__); + return; + } + + if (!param_buf->tim_info || !param_buf->p2p_noa_info) { + WMA_LOGE("%s: Invalid tim info or p2p noa info", __func__); + return; + } + + if (WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info) > + WMI_P2P_MAX_NOA_DESCRIPTORS) { + WMA_LOGE("%s: Too many descriptors %d", __func__, + 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_LOGI("%s: index %u, oppPs %u, ctwindow %u, num_descriptors = %u", + __func__, 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_LOGI("%s: NoA descriptor[%d] type_count %u, duration %u, interval %u, start_time = %u", + __func__, 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_LOGE("%s: failed map beacon buf to DMA region", __func__); + 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); +} + +/** + * 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 + */ +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; + struct cdp_pdev *pdev; + 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_LOGE("Invalid swba event buffer"); + return -EINVAL; + } + swba_event = param_buf->fixed_param; + vdev_map = swba_event->vdev_map; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + return -EINVAL; + } + + WMA_LOGD("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, pdev, vdev_id, param_buf); + break; + } + return 0; +} + +#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, + IEEE80211_ADDR_LEN); + WLAN_HOST_DIAG_EVENT_REPORT(&sta_kickout, EVENT_WLAN_STA_KICKOUT); +} +#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, u8 *event, u32 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, peer_id, macaddr[IEEE80211_ADDR_LEN]; + void *peer; + struct cdp_pdev *pdev; + tpDeleteStaContext del_sta_ctx; + tpSirIbssPeerInactivityInd p_inactivity; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGD("%s: Enter", __func__); + param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) event; + kickout_event = param_buf->fixed_param; + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + return -EINVAL; + } + WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, macaddr); + peer = cdp_peer_find_by_addr(soc, pdev, macaddr, &peer_id); + if (!peer) { + WMA_LOGE("PEER [%pM] not found", macaddr); + return -EINVAL; + } + + if (cdp_peer_get_vdevid(soc, peer, &vdev_id) != QDF_STATUS_SUCCESS) { + WMA_LOGE("Not able to find BSSID for peer [%pM]", macaddr); + return -EINVAL; + } + + WMA_LOGA("%s: PEER:[%pM], ADDR:[%pN], INTERFACE:%d, peer_id:%d, reason:%d", + __func__, macaddr, wma->interfaces[vdev_id].addr, vdev_id, + peer_id, kickout_event->reason); + if (wma->interfaces[vdev_id].roaming_in_progress) { + WMA_LOGE("Ignore STA kick out since roaming is in progress"); + return -EINVAL; + } + + switch (kickout_event->reason) { + case WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT: + p_inactivity = (tpSirIbssPeerInactivityInd) + qdf_mem_malloc(sizeof( + tSirIbssPeerInactivityInd)); + if (!p_inactivity) { + WMA_LOGE("QDF MEM Alloc Failed for tSirIbssPeerInactivity"); + return -ENOMEM; + } + + p_inactivity->staIdx = peer_id; + qdf_mem_copy(p_inactivity->peer_addr.bytes, macaddr, + IEEE80211_ADDR_LEN); + wma_send_msg(wma, WMA_IBSS_PEER_INACTIVITY_IND, + (void *)p_inactivity, 0); + 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_LOGE("%s: mem alloc failed for struct del_sta_context for TDLS peer: %pM", + __func__, macaddr); + return -ENOMEM; + } + + del_sta_ctx->is_tdls = true; + del_sta_ctx->vdev_id = vdev_id; + del_sta_ctx->staId = peer_id; + qdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); + qdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].bssid, + IEEE80211_ADDR_LEN); + 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_XRETRY: + 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(wma->interfaces[vdev_id].bssid, + macaddr, IEEE80211_ADDR_LEN)) { + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_XRETRY, + 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_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_XRETRY event for STA", + __func__); + wma_beacon_miss_handler(wma, vdev_id, + kickout_event->rssi); + goto exit_handler; + } + break; + + 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(wma->interfaces[vdev_id].bssid, + macaddr, IEEE80211_ADDR_LEN)) { + 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_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED event for STA", + __func__); + wma_beacon_miss_handler(wma, vdev_id, + kickout_event->rssi); + goto exit_handler; + } + break; + + 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_LOGE("QDF MEM Alloc Failed for struct del_sta_context"); + return -ENOMEM; + } + + del_sta_ctx->is_tdls = false; + del_sta_ctx->vdev_id = vdev_id; + del_sta_ctx->staId = peer_id; + qdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); + qdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].addr, + IEEE80211_ADDR_LEN); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + del_sta_ctx->rssi = kickout_event->rssi + WMA_TGT_NOISE_FLOOR_DBM; + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_KEEP_ALIVE, + 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, kickout_event->rssi + + WMA_TGT_NOISE_FLOOR_DBM); +exit_handler: + WMA_LOGD("%s: Exit", __func__); + return 0; +} + +/** + * 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) +{ + 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_LOGE("Invalid bcn tx response event buffer"); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + + WMA_LOGD("%s", __func__); + + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, 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].handle) { + WMA_LOGE("%s: The session does not exist", __func__); + 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_LOGI("%s: Beacon Tx Indication does not support type %d and sub_type %d", + __func__, 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_LOGE("%s: Failed to alloc beacon_tx_complete_ind", + __func__); + return -ENOMEM; + } + + beacon_tx_complete_ind->messageType = WMA_DFS_BEACON_TX_SUCCESS_IND; + beacon_tx_complete_ind->length = sizeof(tSirFirstBeaconTxCompleteInd); + beacon_tx_complete_ind->bssIdx = resp_event->vdev_id; + + wma_send_msg(wma, WMA_DFS_BEACON_TX_SUCCESS_IND, + (void *)beacon_tx_complete_ind, 0); + return 0; +} + +/** + * 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 sAniSirGlobal *mac, + uint32_t sub_type, + uint32_t *max_inactive_time, + uint32_t *max_unresponsive_time) +{ + uint32_t keep_alive; + uint16_t lm_id, ka_id; + QDF_STATUS status; + + switch (sub_type) { + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO: + lm_id = WNI_CFG_GO_LINK_MONITOR_TIMEOUT; + ka_id = WNI_CFG_GO_KEEP_ALIVE_TIMEOUT; + break; + default: + /*For softAp the subtype value will be zero */ + lm_id = WNI_CFG_AP_LINK_MONITOR_TIMEOUT; + ka_id = WNI_CFG_AP_KEEP_ALIVE_TIMEOUT; + } + + status = wlan_cfg_get_int(mac, lm_id, max_inactive_time); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to read link monitor for subtype %d", + sub_type); + *max_inactive_time = WMA_LINK_MONITOR_DEFAULT_TIME_SECS; + } + + status = wlan_cfg_get_int(mac, ka_id, &keep_alive); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to read keep alive for subtype %d", sub_type); + keep_alive = WMA_KEEP_ALIVE_DEFAULT_TIME_SECS; + } + *max_unresponsive_time = *max_inactive_time + keep_alive; +} + +/** + * 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 + +/** + * 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; + int ret; + uint32_t per_band_mgmt_tx_rate = 0; + enum cds_band_type band = 0; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + return; + } + + if (wlan_cfg_get_int(mac, WNI_CFG_RATE_FOR_TX_MGMT, + &cfg_val) == QDF_STATUS_SUCCESS) { + band = CDS_BAND_ALL; + if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_STADEF) || + !wma_verify_rate_code(cfg_val, band)) { + WMA_LOGD("default WNI_CFG_RATE_FOR_TX_MGMT, ignore"); + } else { + ret = wma_vdev_set_param( + wma->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_MGMT_TX_RATE, + cfg_val); + if (ret) + WMA_LOGE( + "Failed to set WMI_VDEV_PARAM_MGMT_TX_RATE" + ); + } + } else { + WMA_LOGE("Failed to get value of WNI_CFG_RATE_FOR_TX_MGMT"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_RATE_FOR_TX_MGMT_2G, + &cfg_val) == QDF_STATUS_SUCCESS) { + band = CDS_BAND_2GHZ; + if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_2G_STADEF) || + !wma_verify_rate_code(cfg_val, band)) { + WMA_LOGD("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); + } + } else { + WMA_LOGE("Failed to get value of WNI_CFG_RATE_FOR_TX_MGMT_2G"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_RATE_FOR_TX_MGMT_5G, + &cfg_val) == QDF_STATUS_SUCCESS) { + band = CDS_BAND_5GHZ; + if ((cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_5G_STADEF) || + !wma_verify_rate_code(cfg_val, band)) { + WMA_LOGD("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); + } + } else { + WMA_LOGE("Failed to get value of WNI_CFG_RATE_FOR_TX_MGMT_5G"); + } + + ret = wma_vdev_set_param( + wma->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_PER_BAND_MGMT_TX_RATE, + per_band_mgmt_tx_rate); + if (ret) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_PER_BAND_MGMT_TX_RATE"); + +} + +/** + * 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 sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + QDF_STATUS status; + + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + 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 = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + min_inactive_time); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to Set AP MIN IDLE INACTIVE TIME"); + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + max_inactive_time); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to Set AP MAX IDLE INACTIVE TIME"); + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + max_unresponsive_time); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to Set MAX UNRESPONSIVE TIME"); + + WMA_LOGD("%s:vdev_id:%d min_inactive_time: %u max_inactive_time: %u max_unresponsive_time: %u", + __func__, vdev_id, + min_inactive_time, max_inactive_time, max_unresponsive_time); +} + +/** + * 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 sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t max_retries, retry_interval; + + WMA_LOGD(FL("Enter:")); + + if (!mac) { + WMA_LOGE(FL("mac context is NULL")); + return; + } + if (wlan_cfg_get_int + (mac, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &max_retries) != QDF_STATUS_SUCCESS) { + max_retries = DEFAULT_STA_SA_QUERY_MAX_RETRIES_COUNT; + WMA_LOGE(FL("Failed to get value for WNI_CFG_PMF_SA_QUERY_MAX_RETRIES")); + } + if (wlan_cfg_get_int + (mac, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retry_interval) != QDF_STATUS_SUCCESS) { + retry_interval = DEFAULT_STA_SA_QUERY_RETRY_INTERVAL; + WMA_LOGE(FL("Failed to get value for WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL")); + } + + wmi_unified_set_sta_sa_query_param_cmd(wma->wmi_handle, + vdev_id, + max_retries, + retry_interval); + + WMA_LOGD(FL("Exit :")); +} + +/** + * 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_params params; + + WMA_LOGD("%s: Enter", __func__); + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return; + } + + if (timeperiod > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) { + WMI_LOGE("Invalid period %d Max limit %d", timeperiod, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX); + return; + } + + params.vdev_id = vdev_id; + params.method = method; + params.timeperiod = timeperiod; + params.hostv4addr = hostv4addr; + params.destv4addr = destv4addr; + params.destmac = destmac; + + wmi_unified_set_sta_keep_alive_cmd(wma->wmi_handle, + ¶ms); + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_vdev_install_key_complete_event_handler() - install key complete handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * This event is sent by fw once WPA/WPA2 keys are installed in fw. + * + * Return: 0 for success or error code + */ +int wma_vdev_install_key_complete_event_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *param_buf = NULL; + wmi_vdev_install_key_complete_event_fixed_param *key_fp = NULL; + + if (!event) { + WMA_LOGE("%s: event param null", __func__); + return -EINVAL; + } + + param_buf = (WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + return -EINVAL; + } + + key_fp = param_buf->fixed_param; + if (!key_fp) { + WMA_LOGE("%s: received null event data from target", __func__); + return -EINVAL; + } + /* + * Do nothing for now. Completion of set key is already indicated to lim + */ + WMA_LOGD("%s: WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID", __func__); + return 0; +} +/* + * 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; +} + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * wma_unified_peer_state_update() - update peer state + * @pdev: pdev handle + * @sta_mac: pointer to sta mac addr + * @bss_addr: bss address + * @sta_type: sta entry type + * + * + * Return: None + */ +static void +wma_unified_peer_state_update( + struct cdp_pdev *pdev, + uint8_t *sta_mac, + uint8_t *bss_addr, + uint8_t sta_type) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (STA_ENTRY_TDLS_PEER == sta_type) + cdp_peer_state_update(soc, pdev, sta_mac, + OL_TXRX_PEER_STATE_AUTH); + else + cdp_peer_state_update(soc, pdev, bss_addr, + OL_TXRX_PEER_STATE_AUTH); +} +#else + +static inline void +wma_unified_peer_state_update( + struct cdp_pdev *pdev, + uint8_t *sta_mac, + uint8_t *bss_addr, + uint8_t sta_type) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + cdp_peer_state_update(soc, pdev, bss_addr, OL_TXRX_PEER_STATE_AUTH); +} +#endif + +#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 mcs_limit, i, j; + uint8_t *rate_pos = mcs_set; + + /* + * 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. + */ + if (wlan_cfg_get_int(wma->mac_context, WNI_CFG_MAX_HT_MCS_TX_DATA, + &mcs_limit) != QDF_STATUS_SUCCESS) { + mcs_limit = WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF; + } + + if (mcs_limit & CFG_CTRL_MASK) { + WMA_LOGD("%s: set mcs_limit %x", __func__, 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_11ac() - convert fw to host phymode for 11ax phymodes + * @wma: wma handle + * @phymode: phymode to convert + * + * Return: None + */ +static enum wlan_phymode wma_fw_to_host_phymode_11ac(WLAN_PHY_MODE phymode) +{ + switch (phymode) { + default: + return WLAN_PHYMODE_AUTO; +#if SUPPORT_11AX + case MODE_11AX_HE20: + return WLAN_PHYMODE_11AC_VHT20; + case MODE_11AX_HE40: + return WLAN_PHYMODE_11AC_VHT40; + case MODE_11AX_HE80: + return WLAN_PHYMODE_11AC_VHT80; + case MODE_11AX_HE80_80: + return WLAN_PHYMODE_11AC_VHT80_80; + case MODE_11AX_HE160: + return WLAN_PHYMODE_11AC_VHT160; + case MODE_11AX_HE20_2G: + return WLAN_PHYMODE_11AC_VHT20; + case MODE_11AX_HE40_2G: + return WLAN_PHYMODE_11AC_VHT40; + case MODE_11AX_HE80_2G: + return WLAN_PHYMODE_11AC_VHT80; +#endif + } + return WLAN_PHYMODE_AUTO; +} +#else +static enum wlan_phymode wma_fw_to_host_phymode_11ac(WLAN_PHY_MODE phymode) +{ + return WLAN_PHYMODE_AUTO; +} +#endif + +#ifdef CONFIG_160MHZ_SUPPORT +/** + * wma_fw_to_host_phymode_160() - convert fw to host phymode for 160 mhz + * phymodes + * @wma: wma handle + * @phymode: phymode to convert + * + * Return: None + */ +static enum wlan_phymode wma_fw_to_host_phymode_160(WLAN_PHY_MODE phymode) +{ + switch (phymode) { + default: + return WLAN_PHYMODE_AUTO; + case MODE_11AC_VHT80_80: + return WLAN_PHYMODE_11AC_VHT80_80; + case MODE_11AC_VHT160: + return WLAN_PHYMODE_11AC_VHT160; + } +} +#else +static enum wlan_phymode wma_fw_to_host_phymode_160(WLAN_PHY_MODE phymode) +{ + return WLAN_PHYMODE_AUTO; +} +#endif +/** + * wma_fw_to_host_phymode() - convert fw to host phymode + * @wma: wma handle + * @phymode: phymode to convert + * + * Return: None + */ +static enum wlan_phymode wma_fw_to_host_phymode(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; + return wma_fw_to_host_phymode_11ac(phymode); + case MODE_11A: + return WLAN_PHYMODE_11A; + case MODE_11G: + return WLAN_PHYMODE_11G; + case MODE_11B: + return WLAN_PHYMODE_11B; + case MODE_11GONLY: + return WLAN_PHYMODE_11G; + case MODE_11NA_HT20: + return WLAN_PHYMODE_11NA_HT20; + case MODE_11NG_HT20: + return WLAN_PHYMODE_11NG_HT20; + case MODE_11NA_HT40: + return WLAN_PHYMODE_11NA_HT40; + case MODE_11NG_HT40: + return WLAN_PHYMODE_11NG_HT40; + case MODE_11AC_VHT20: + return WLAN_PHYMODE_11AC_VHT20; + case MODE_11AC_VHT40: + return WLAN_PHYMODE_11AC_VHT40; + case MODE_11AC_VHT80: + return WLAN_PHYMODE_11AC_VHT80; + case MODE_11AC_VHT20_2G: + return WLAN_PHYMODE_11AC_VHT20; + case MODE_11AC_VHT40_2G: + return WLAN_PHYMODE_11AC_VHT40; + case MODE_11AC_VHT80_2G: + return WLAN_PHYMODE_11AC_VHT80; + } +} + +/** + * 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 + */ +static void wma_objmgr_set_peer_mlme_phymode(tp_wma_handle wma, + uint8_t *mac_addr, + WLAN_PHY_MODE 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) { + WMA_LOGE(FL("peer object null")); + return; + } + + wlan_peer_obj_lock(peer); + wlan_peer_set_phymode(peer, wma_fw_to_host_phymode(phymode)); + wlan_peer_obj_unlock(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +/** + * 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 cdp_pdev *pdev; + 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; + uint32_t phymode; + uint32_t peer_nss = 1; + uint32_t disable_abg_rate; + struct wma_txrx_node *intr = NULL; + bool is_he; + QDF_STATUS status; + + cmd = qdf_mem_malloc(sizeof(struct peer_assoc_params)); + if (!cmd) { + WMA_LOGE("Failed to allocate peer_assoc_params param"); + return QDF_STATUS_E_NOMEM; + } + + intr = &wma->interfaces[params->smesessionId]; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + qdf_mem_free(cmd); + return QDF_STATUS_E_INVAL; + } + + 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); + if ((params->ch_width > CH_WIDTH_40MHZ) && + ((nw_type == eSIR_11G_NW_TYPE) || + (nw_type == eSIR_11B_NW_TYPE))) { + WMA_LOGE("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); + + wma_objmgr_set_peer_mlme_phymode(wma, params->staMac, phymode); + + if (wlan_cfg_get_int(wma->mac_context, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + &disable_abg_rate) != QDF_STATUS_SUCCESS) + disable_abg_rate = WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF; + + if (!disable_abg_rate) { + /* 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 == MODE_11A && num_peer_11a_rates == 0) || + (phymode == MODE_11B && num_peer_11b_rates == 0)) { + WMA_LOGW("%s: Invalid phy rates. phymode 0x%x, 11b_rates %d, 11a_rates %d", + __func__, 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_LOGW("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/ibss 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)) + || (wma_is_vdev_in_ibss_mode(wma, params->smesessionId)) +#ifdef FEATURE_WLAN_TDLS + || (STA_ENTRY_TDLS_PEER == params->staType) +#endif /* FEATURE_WLAN_TDLS */ + ) + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->staMac, &cmd->peer_macaddr); + else + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->bssId, &cmd->peer_macaddr); + cmd->vdev_id = params->smesessionId; + cmd->peer_new_assoc = 1; + cmd->peer_associd = params->assocId; + + /* + * The target only needs a subset of the flags maintained in the host. + * Just populate those flags and send it down + */ + cmd->peer_flags = 0; + + if (params->wmmEnabled) + cmd->peer_flags |= WMI_PEER_QOS; + + if (params->uAPSD) { + cmd->peer_flags |= WMI_PEER_APSD; + WMA_LOGD("Set WMI_PEER_APSD: uapsd Mask %d", params->uAPSD); + } + + if (params->htCapable) { + cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_QOS); + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + + if (params->ch_width) { + cmd->peer_flags |= WMI_PEER_40MHZ; + 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; + } + } + + if (params->vhtCapable) { + cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_VHT | WMI_PEER_QOS); + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + } + + if (params->ch_width == CH_WIDTH_80MHZ) + cmd->peer_flags |= WMI_PEER_80MHZ; + else if (params->ch_width == CH_WIDTH_160MHZ) + cmd->peer_flags |= WMI_PEER_160MHZ; + else if (params->ch_width == CH_WIDTH_80P80MHZ) + cmd->peer_flags |= WMI_PEER_160MHZ; + + cmd->peer_vht_caps = params->vht_caps; + if (params->p2pCapableSta) + cmd->peer_flags |= WMI_PEER_IS_P2P_CAPABLE; + + if (params->rmfEnabled) + cmd->peer_flags |= WMI_PEER_PMF; + + if (params->stbc_capable) + cmd->peer_flags |= WMI_PEER_STBC; + + if (params->htLdpcCapable || params->vhtLdpcCapable) + cmd->peer_flags |= WMI_PEER_LDPC; + + switch (params->mimoPS) { + case eSIR_HT_MIMO_PS_STATIC: + cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS; + break; + case eSIR_HT_MIMO_PS_DYNAMIC: + cmd->peer_flags |= WMI_PEER_DYN_MIMOPS; + break; + case eSIR_HT_MIMO_PS_NO_LIMIT: + cmd->peer_flags |= WMI_PEER_SPATIAL_MUX; + break; + default: + break; + } + + wma_set_twt_peer_caps(params, cmd); +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) + cmd->peer_flags |= WMI_PEER_AUTH; +#endif /* FEATURE_WLAN_TDLS */ + + if (params->wpa_rsn +#ifdef FEATURE_WLAN_WAPI + || params->encryptType == eSIR_ED_WPI +#endif /* FEATURE_WLAN_WAPI */ + ) { + cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; + WMA_LOGD("Acquire set key wake lock for %d ms", + WMA_VDEV_SET_KEY_WAKELOCK_TIMEOUT); + wma_acquire_wakelock(&intr->vdev_set_key_wakelock, + WMA_VDEV_SET_KEY_WAKELOCK_TIMEOUT); + } + if (params->wpa_rsn >> 1) + cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; + + wma_unified_peer_state_update(pdev, params->staMac, + params->bssId, params->staType); + +#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_LOGE + ("Set WMI_VDEV_PARAM_DROP_UNENCRY Param status:%d\n", + 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_LOGD("Num tx_streams: %d, Disabled txSTBC", + intr->tx_streams); + } + WMA_LOGD("peer_nss %d peer_ht_rates.num_rates %d ", cmd->peer_nss, + peer_ht_rates.num_rates); + + 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; + + if (params->vhtSupportedRxNss) { + cmd->peer_nss = params->vhtSupportedRxNss; + } else { + cmd->peer_nss = ((cmd->rx_mcs_set & VHT2x2MCSMASK) + == VHT2x2MCSMASK) ? 1 : 2; + } + } + + WMA_LOGD(FL("rx_max_rate: %d, rx_mcs: %x, tx_max_rate: %d, tx_mcs: %x"), + cmd->rx_max_rate, cmd->rx_mcs_set, cmd->tx_max_rate, + cmd->tx_mcs_set); + + /* + * Limit nss to max number of rf chain supported by target + * Otherwise Fw will crash + */ + if (cmd->peer_nss > WMA_MAX_NSS) + cmd->peer_nss = WMA_MAX_NSS; + + wma_populate_peer_he_cap(cmd, params); + + intr->nss = cmd->peer_nss; + cmd->peer_phymode = phymode; + WMA_LOGD("%s: vdev_id %d associd %d peer_flags %x rate_caps %x peer_caps %x", + __func__, cmd->vdev_id, cmd->peer_associd, cmd->peer_flags, + cmd->peer_rate_caps, cmd->peer_caps); + WMA_LOGD("%s:listen_intval %d ht_caps %x max_mpdu %d nss %d phymode %d", + __func__, cmd->peer_listen_intval, cmd->peer_ht_caps, + cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode); + WMA_LOGD("%s: peer_mpdu_density %d encr_type %d cmd->peer_vht_caps %x", + __func__, cmd->peer_mpdu_density, params->encryptType, + cmd->peer_vht_caps); + + status = wmi_unified_peer_assoc_send(wma->wmi_handle, + cmd); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGP(FL("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_LOGE("Failed to send wmi protection mode cmd"); + else + WMA_LOGD("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_LOGE("Failed to update beacon interval"); + else + WMA_LOGI("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_LOGD("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_BSS_COLOR, dword_he_ops); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("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_LOGE("bcn_params NULL"); + return; + } + + if (bcn_params->smeSessionId >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id %d", bcn_params->smeSessionId); + return; + } + + if (bcn_params->paramChangeBitmap & PARAM_BCN_INTERVAL_CHANGED) { + wma_update_beacon_interval(wma, bcn_params->smeSessionId, + bcn_params->beaconInterval); + } + + if (bcn_params->paramChangeBitmap & PARAM_llBCOEXIST_CHANGED) + wma_update_protection_mode(wma, bcn_params->smeSessionId, + bcn_params->llbCoexist); + + if (bcn_params->paramChangeBitmap & PARAM_BSS_COLOR_CHANGED) + wma_update_bss_color(wma, bcn_params->smeSessionId, + bcn_params); +} + +/** + * wma_update_cfg_params() - update cfg parameters to target + * @wma: wma handle + * @cfgParam: cfg parameter + * + * Return: none + */ +void wma_update_cfg_params(tp_wma_handle wma, struct scheduler_msg *cfgParam) +{ + uint8_t vdev_id; + uint32_t param_id; + uint32_t cfg_val; + QDF_STATUS ret; + /* get mac to access CFG data base */ + struct sAniSirGlobal *pmac; + + switch (cfgParam->bodyval) { + case WNI_CFG_RTS_THRESHOLD: + param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; + break; + case WNI_CFG_FRAGMENTATION_THRESHOLD: + param_id = WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD; + break; + default: + WMA_LOGD("Unhandled cfg parameter %d", cfgParam->bodyval); + return; + } + + pmac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == pmac) { + WMA_LOGE("%s: Failed to get pmac", __func__); + return; + } + + if (wlan_cfg_get_int(pmac, (uint16_t) cfgParam->bodyval, + &cfg_val) != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get value for CFG PARAMS %d. returning without updating", + cfgParam->bodyval); + return; + } + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (wma->interfaces[vdev_id].handle != 0) { + ret = wma_vdev_set_param(wma->wmi_handle, + vdev_id, param_id, + cfg_val); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Update cfg params failed for vdevId %d", + vdev_id); + } + } +} + +/** + * wma_read_cfg_wepkey() - fill key_info for WEP key + * @wma_handle: wma handle + * @key_info: key_info ptr + * @def_key_idx: default key index + * @num_keys: number of keys + * + * This function reads WEP keys from cfg and fills + * up key_info. + * + * Return: none + */ +static void wma_read_cfg_wepkey(tp_wma_handle wma_handle, + tSirKeys *key_info, uint32_t *def_key_idx, + uint8_t *num_keys) +{ + QDF_STATUS status; + uint32_t val = SIR_MAC_KEY_LENGTH; + uint8_t i, j; + + WMA_LOGD("Reading WEP keys from cfg"); + /* NOTE:def_key_idx is initialized to 0 by the caller */ + status = wlan_cfg_get_int(wma_handle->mac_context, + WNI_CFG_WEP_DEFAULT_KEYID, def_key_idx); + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("Unable to read default id, defaulting to 0"); + + for (i = 0, j = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) { + status = wlan_cfg_get_str(wma_handle->mac_context, + (uint16_t) WNI_CFG_WEP_DEFAULT_KEY_1 + + i, key_info[j].key, &val); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("WEP key is not configured at :%d", i); + } else { + key_info[j].keyId = i; + key_info[j].keyLength = (uint16_t) val; + j++; + } + } + *num_keys = j; +} + +static void wma_set_peer_unicast_cipher(tp_wma_handle wma, + struct set_key_params *params) +{ + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + params->peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + WMA_LOGE("Peer of peer_mac %pM not found", params->peer_mac); + return; + } + + wlan_peer_set_unicast_cipher(peer, params->key_cipher); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +/** + * wma_setup_install_key_cmd() - set key parameters + * @wma_handle: wma handle + * @key_params: key parameters + * @mode: op mode + * + * This function fills structure from information + * passed in key_params. + * + * Return: QDF_STATUS_SUCCESS - success + QDF_STATUS_E_FAILURE - failure + QDF_STATUS_E_NOMEM - invalid request + */ +static QDF_STATUS wma_setup_install_key_cmd(tp_wma_handle wma_handle, + struct wma_set_key_params + *key_params, uint8_t mode) +{ + struct set_key_params params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wma_txrx_node *iface = NULL; + enum cdp_sec_type sec_type = cdp_sec_type_none; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_pdev *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct cdp_vdev *txrx_vdev; + uint32_t pn[4] = {0, 0, 0, 0}; + uint8_t peer_id; + struct cdp_peer *peer; + + if ((key_params->key_type == eSIR_ED_NONE && + key_params->key_len) || (key_params->key_type != eSIR_ED_NONE && + !key_params->key_len)) { + WMA_LOGE("%s:Invalid set key request", __func__); + return QDF_STATUS_E_NOMEM; + } + + if (NULL == wma_handle) { + WMA_LOGE(FL("Invalid wma_handle for vdev_id: %d"), + key_params->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (key_params->vdev_id >= wma_handle->max_bssid) { + WMA_LOGE(FL("Invalid vdev_id: %d"), key_params->vdev_id); + return QDF_STATUS_E_INVAL; + } + + txrx_vdev = wma_find_vdev_by_id(wma_handle, + key_params->vdev_id); + peer = cdp_peer_find_by_addr(soc, txrx_pdev, + key_params->peer_mac, &peer_id); + iface = &wma_handle->interfaces[key_params->vdev_id]; + + params.vdev_id = key_params->vdev_id; + params.key_idx = key_params->key_idx; + qdf_mem_copy(params.peer_mac, key_params->peer_mac, IEEE80211_ADDR_LEN); + +#ifdef FEATURE_WLAN_WAPI + qdf_mem_zero(params.tx_iv, 16); + qdf_mem_zero(params.rx_iv, 16); +#endif + params.key_txmic_len = 0; + params.key_rxmic_len = 0; + params.key_rsc_counter = qdf_mem_malloc(sizeof(uint64_t)); + if (!params.key_rsc_counter) { + WMA_LOGE(FL("can't allocate memory for key_rsc_counter")); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(params.key_rsc_counter, + &key_params->key_rsc[0], sizeof(uint64_t)); + params.key_flags = 0; + if (key_params->unicast) + params.key_flags |= PAIRWISE_USAGE; + else + params.key_flags |= GROUP_USAGE; + + switch (key_params->key_type) { + case eSIR_ED_NONE: + params.key_cipher = WMI_CIPHER_NONE; + sec_type = cdp_sec_type_none; + break; + case eSIR_ED_WEP40: + case eSIR_ED_WEP104: + params.key_cipher = WMI_CIPHER_WEP; + if (key_params->unicast && + params.key_idx == key_params->def_key_idx) { + WMA_LOGD("STA Mode: cmd->key_flags |= TX_USAGE"); + params.key_flags |= TX_USAGE; + } else if ((mode == wlan_op_mode_ap) && + (params.key_idx == key_params->def_key_idx)) { + WMA_LOGD("AP Mode: cmd->key_flags |= TX_USAGE"); + params.key_flags |= TX_USAGE; + } + sec_type = cdp_sec_type_wep104; + break; + case eSIR_ED_TKIP: + params.key_txmic_len = WMA_TXMIC_LEN; + params.key_rxmic_len = WMA_RXMIC_LEN; + params.key_cipher = WMI_CIPHER_TKIP; + sec_type = cdp_sec_type_tkip; + break; +#ifdef FEATURE_WLAN_WAPI +#define WPI_IV_LEN 16 + case eSIR_ED_WPI: + { + /*initialize receive and transmit IV with default values */ + /* **Note: tx_iv must be sent in reverse** */ + unsigned char tx_iv[16] = { 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c, + 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c, + 0x36, 0x5c, 0x36, 0x5c}; + unsigned char rx_iv[16] = { 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x37}; + if (mode == wlan_op_mode_ap) { + /* Authenticator initializes the value of PN as + * 0x5C365C365C365C365C365C365C365C36 for MCastkeyUpdate + */ + if (key_params->unicast) + tx_iv[0] = 0x37; + + rx_iv[WPI_IV_LEN - 1] = 0x36; + } else { + if (!key_params->unicast) + rx_iv[WPI_IV_LEN - 1] = 0x36; + } + + params.key_txmic_len = WMA_TXMIC_LEN; + params.key_rxmic_len = WMA_RXMIC_LEN; + + qdf_mem_copy(¶ms.rx_iv, &rx_iv, + WPI_IV_LEN); + qdf_mem_copy(¶ms.tx_iv, &tx_iv, + WPI_IV_LEN); + params.key_cipher = WMI_CIPHER_WAPI; + break; + } +#endif /* FEATURE_WLAN_WAPI */ + case eSIR_ED_CCMP: + params.key_cipher = WMI_CIPHER_AES_CCM; + sec_type = cdp_sec_type_aes_ccmp; + break; +#ifdef WLAN_FEATURE_11W + case eSIR_ED_AES_128_CMAC: + params.key_cipher = WMI_CIPHER_AES_CMAC; + break; + case eSIR_ED_AES_GMAC_128: + case eSIR_ED_AES_GMAC_256: + params.key_cipher = WMI_CIPHER_AES_GMAC; + break; +#endif /* WLAN_FEATURE_11W */ + /* Firmware uses length to detect GCMP 128/256*/ + case eSIR_ED_GCMP: + case eSIR_ED_GCMP_256: + params.key_cipher = WMI_CIPHER_AES_GCM; + break; + default: + /* TODO: MFP ? */ + WMA_LOGE("%s:Invalid encryption type:%d", __func__, + key_params->key_type); + status = QDF_STATUS_E_NOMEM; + goto end; + } + +#ifdef BIG_ENDIAN_HOST + { + /* for big endian host, copy engine byte_swap is enabled + * But the key data content is in network byte order + * Need to byte swap the key data content - so when copy engine + * does byte_swap - target gets key_data content in the correct + * order. + */ + int8_t i; + uint32_t *destp, *srcp; + + destp = (uint32_t *) params.key_data; + srcp = (uint32_t *) key_params->key_data; + for (i = 0; + i < roundup(key_params->key_len, sizeof(uint32_t)) / 4; + i++) { + *destp = le32_to_cpu(*srcp); + destp++; + srcp++; + } + } +#else + qdf_mem_copy((void *)params.key_data, + (const void *)key_params->key_data, key_params->key_len); +#endif /* BIG_ENDIAN_HOST */ + params.key_len = key_params->key_len; + +#ifdef WLAN_FEATURE_11W + iface = &wma_handle->interfaces[key_params->vdev_id]; + + if ((key_params->key_type == eSIR_ED_AES_128_CMAC) || + (key_params->key_type == eSIR_ED_AES_GMAC_128) || + (key_params->key_type == eSIR_ED_AES_GMAC_256)) { + if (iface) { + iface->key.key_length = key_params->key_len; + iface->key.key_cipher = params.key_cipher; + qdf_mem_copy(iface->key.key, + (const void *)key_params->key_data, + iface->key.key_length); + if ((params.key_idx == WMA_IGTK_KEY_INDEX_4) || + (params.key_idx == WMA_IGTK_KEY_INDEX_5)) + qdf_mem_zero(iface->key.key_id[params.key_idx - + WMA_IGTK_KEY_INDEX_4].ipn, + CMAC_IPN_LEN); + } + } +#endif /* WLAN_FEATURE_11W */ + + if (key_params->unicast) + wma_set_peer_unicast_cipher(wma_handle, ¶ms); + + WMA_LOGD("Key setup : vdev_id %d key_idx %d key_type %d key_len %d", + key_params->vdev_id, key_params->key_idx, + key_params->key_type, key_params->key_len); + WMA_LOGD("unicast %d peer_mac %pM def_key_idx %d", + key_params->unicast, key_params->peer_mac, + key_params->def_key_idx); + WMA_LOGD("keyrsc param %llu", *(params.key_rsc_counter)); + + /* Set PN check & security type in data path */ + cdp_set_pn_check(soc, txrx_vdev, peer, sec_type, pn); + + status = wmi_unified_setup_install_key_cmd(wma_handle->wmi_handle, + ¶ms); + if (!key_params->unicast) { + /* Its GTK release the wake lock */ + WMA_LOGD("Release set key wake lock"); + wma_release_wakelock(&iface->vdev_set_key_wakelock); + } + + /* install key was requested */ + if (iface) + iface->is_waiting_for_key = false; + +end: + qdf_mem_free(params.key_rsc_counter); + qdf_mem_zero(¶ms, sizeof(struct set_key_params)); + return status; +} + +/** + * wma_set_bsskey() - set encryption key to fw. + * @wma_handle: wma handle + * @key_info: key info + * + * Return: none + */ +void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info) +{ + struct wma_set_key_params key_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + uint32_t def_key_idx = 0; + uint32_t wlan_opmode; + struct cdp_vdev *txrx_vdev; + uint8_t *mac_addr; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGD("BSS key setup"); + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + wlan_opmode = cdp_get_opmode(soc, txrx_vdev); + + /* + * For IBSS, WMI expects the BSS key to be set per peer key + * So cache the BSS key in the wma_handle and re-use it when the + * STA key is been setup for a peer + */ + if (wlan_op_mode_ibss == wlan_opmode) { + key_info->status = QDF_STATUS_SUCCESS; + if (wma_handle->ibss_started > 0) + goto out; + WMA_LOGD("Caching IBSS Key"); + qdf_mem_copy(&wma_handle->ibsskey_info, key_info, + sizeof(tSetBssKeyParams)); + } + + qdf_mem_zero(&key_params, sizeof(key_params)); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = false; + if (wlan_opmode == wlan_op_mode_sta) { + qdf_mem_copy(key_params.peer_mac, + wma_handle->interfaces[key_info->smesessionId].bssid, + IEEE80211_ADDR_LEN); + } else { + mac_addr = cdp_get_vdev_mac_addr(soc, + txrx_vdev); + if (mac_addr == NULL) { + WMA_LOGE("%s: mac_addr is NULL for vdev with id %d", + __func__, key_info->smesessionId); + goto out; + } + /* vdev mac address will be passed for all other modes */ + qdf_mem_copy(key_params.peer_mac, mac_addr, + IEEE80211_ADDR_LEN); + WMA_LOGD("BSS Key setup with vdev_mac %pM\n", + mac_addr); + } + + if (key_info->numKeys == 0 && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104)) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &key_info->numKeys); + } else if ((key_info->encType == eSIR_ED_WEP40) || + (key_info->encType == eSIR_ED_WEP104)) { + struct wma_txrx_node *intf = + &wma_handle->interfaces[key_info->smesessionId]; + key_params.def_key_idx = intf->wep_default_key_idx; + } + + for (i = 0; i < key_info->numKeys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + if (key_info->encType == eSIR_ED_WPI) { + key_params.key_idx = key_info->key[i].keyId; + key_params.def_key_idx = key_info->key[i].keyId; + } else + key_params.key_idx = key_info->key[i].keyId; + + key_params.key_len = key_info->key[i].keyLength; + qdf_mem_copy(key_params.key_rsc, + key_info->key[i].keyRsc, + SIR_MAC_MAX_KEY_RSC_LEN); + if (key_info->encType == eSIR_ED_TKIP) { + qdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + qdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + qdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + qdf_mem_copy((void *)key_params.key_data, + (const void *)key_info->key[i].key, + key_info->key[i].keyLength); + + WMA_LOGD("%s: bss key[%d] length %d", __func__, i, + key_info->key[i].keyLength); + + status = wma_setup_install_key_cmd(wma_handle, &key_params, + wlan_opmode); + if (status == QDF_STATUS_E_NOMEM) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + key_info->status = QDF_STATUS_E_NOMEM; + goto out; + } else if (status == QDF_STATUS_E_FAILURE) { + WMA_LOGE("%s:Failed to send install key command", + __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + } + + wma_handle->ibss_started++; + /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */ + key_info->status = QDF_STATUS_SUCCESS; + + qdf_mem_zero(&key_params, sizeof(struct wma_set_key_params)); + +out: + wma_send_msg_high_priority(wma_handle, WMA_SET_BSSKEY_RSP, + (void *)key_info, 0); +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_calc_ibss_heart_beat_timer() - calculate IBSS heart beat timer + * @peer_num: number of peers + * + * Return: heart beat timer value + */ +static uint16_t wma_calc_ibss_heart_beat_timer(int16_t peer_num) +{ + /* heart beat timer value look-up table */ + /* entry index : (the number of currently connected peers) - 1 + * entry value : the heart time threshold value in seconds for + * detecting ibss peer departure + */ + static const uint16_t heart_beat_timer[MAX_PEERS] = { + 4, 4, 4, 4, 4, 4, 4, 4, + 8, 8, 8, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 16, 16, 16, 16 + }; + + if (peer_num < 1 || peer_num > MAX_PEERS) + return 0; + + return heart_beat_timer[peer_num - 1]; + +} + +/** + * wma_adjust_ibss_heart_beat_timer() - set ibss heart beat timer in fw. + * @wma: wma handle + * @vdev_id: vdev id + * @peer_num_delta: peer number delta value + * + * Return: none + */ +void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma, + uint8_t vdev_id, + int8_t peer_num_delta) +{ + struct cdp_vdev *vdev; + int16_t new_peer_num; + uint16_t new_timer_value_sec; + uint32_t new_timer_value_ms; + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (peer_num_delta != 1 && peer_num_delta != -1) { + WMA_LOGE("Invalid peer_num_delta value %d", peer_num_delta); + return; + } + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("vdev not found : vdev_id %d", vdev_id); + return; + } + + /* adjust peer numbers */ + new_peer_num = cdp_peer_update_ibss_add_peer_num_of_vdev(soc, + vdev, peer_num_delta); + if (OL_TXRX_INVALID_NUM_PEERS == new_peer_num) { + WMA_LOGE("new peer num %d out of valid boundary", new_peer_num); + return; + } + + /* reset timer value if all peers departed */ + if (new_peer_num == 0) { + cdp_set_ibss_vdev_heart_beat_timer(soc, vdev, 0); + return; + } + + /* calculate new timer value */ + new_timer_value_sec = wma_calc_ibss_heart_beat_timer(new_peer_num); + if (new_timer_value_sec == 0) { + WMA_LOGE("timer value %d is invalid for peer number %d", + new_timer_value_sec, new_peer_num); + return; + } + if (new_timer_value_sec == + cdp_set_ibss_vdev_heart_beat_timer(soc, + vdev, new_timer_value_sec)) { + WMA_LOGD("timer value %d stays same, no need to notify target", + new_timer_value_sec); + return; + } + + new_timer_value_ms = ((uint32_t) new_timer_value_sec) * 1000; + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, + new_timer_value_ms); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to set IBSS link monitoring timer value"); + return; + } + + WMA_LOGD("Set IBSS link monitor timer: peer_num = %d timer_value = %d", + new_peer_num, new_timer_value_ms); +} + +#endif /* QCA_IBSS_SUPPORT */ +/** + * wma_set_ibsskey_helper() - cached IBSS key in wma handle + * @wma_handle: wma handle + * @key_info: set bss key info + * @peerMacAddr: peer mac address + * + * Return: none + */ +static void wma_set_ibsskey_helper(tp_wma_handle wma_handle, + tpSetBssKeyParams key_info, + struct qdf_mac_addr peer_macaddr) +{ + struct wma_set_key_params key_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + uint32_t def_key_idx = 0; + struct cdp_vdev *txrx_vdev; + int opmode; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGD("BSS key setup for peer"); + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + return; + } + + qdf_mem_zero(&key_params, sizeof(key_params)); + opmode = cdp_get_opmode(soc, txrx_vdev); + qdf_mem_zero(&key_params, sizeof(key_params)); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = false; + ASSERT(wlan_op_mode_ibss == opmode); + + qdf_mem_copy(key_params.peer_mac, peer_macaddr.bytes, + IEEE80211_ADDR_LEN); + + if (key_info->numKeys == 0 && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104)) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &key_info->numKeys); + } else if ((key_info->encType == eSIR_ED_WEP40) || + (key_info->encType == eSIR_ED_WEP104)) { + struct wma_txrx_node *intf = + &wma_handle->interfaces[key_info->smesessionId]; + key_params.def_key_idx = intf->wep_default_key_idx; + } + + for (i = 0; i < key_info->numKeys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + key_params.key_idx = key_info->key[i].keyId; + key_params.key_len = key_info->key[i].keyLength; + if (key_info->encType == eSIR_ED_TKIP) { + qdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + qdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + qdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + qdf_mem_copy((void *)key_params.key_data, + (const void *)key_info->key[i].key, + key_info->key[i].keyLength); + + WMA_LOGD("%s: peer bcast key[%d] length %d", __func__, i, + key_info->key[i].keyLength); + + status = wma_setup_install_key_cmd(wma_handle, &key_params, + opmode); + if (status == QDF_STATUS_E_NOMEM) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + return; + } else if (status == QDF_STATUS_E_FAILURE) { + WMA_LOGE("%s:Failed to send install key command", + __func__); + } + } +} + +/** + * wma_set_stakey() - set encryption key + * @wma_handle: wma handle + * @key_info: station key info + * + * This function sets encryption key for WEP/WPA/WPA2 + * encryption mode in firmware and send response to upper layer. + * + * Return: none + */ +void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info) +{ + int32_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct cdp_pdev *txrx_pdev; + struct cdp_vdev *txrx_vdev; + void *peer; + uint8_t num_keys = 0, peer_id; + struct wma_set_key_params key_params; + uint32_t def_key_idx = 0; + int opmode; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGD("STA key setup"); + + /* Get the txRx Pdev handle */ + txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + WMA_LOGE("%s:Invalid txrx pdev handle", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + + peer = cdp_peer_find_by_addr(soc, txrx_pdev, + key_info->peer_macaddr.bytes, + &peer_id); + if (!peer) { + WMA_LOGE("%s:Invalid peer for key setting", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:TxRx Vdev Handle is NULL", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + opmode = cdp_get_opmode(soc, txrx_vdev); + + if (key_info->defWEPIdx == WMA_INVALID_KEY_IDX && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104) && + opmode != wlan_op_mode_ap) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &num_keys); + key_info->defWEPIdx = def_key_idx; + } else { + num_keys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + if (key_info->encType != eSIR_ED_NONE) { + for (i = 0; i < num_keys; i++) { + if (key_info->key[i].keyDirection == + eSIR_TX_DEFAULT) { + key_info->defWEPIdx = i; + break; + } + } + } + } + qdf_mem_zero(&key_params, sizeof(key_params)); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = true; + key_params.def_key_idx = key_info->defWEPIdx; + qdf_mem_copy((void *)key_params.peer_mac, + (const void *)key_info->peer_macaddr.bytes, + IEEE80211_ADDR_LEN); + for (i = 0; i < num_keys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + if (key_info->encType == eSIR_ED_TKIP) { + qdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + qdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + qdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + qdf_mem_copy(key_params.key_data, key_info->key[i].key, + key_info->key[i].keyLength); + if (key_info->encType == eSIR_ED_WPI) { + key_params.key_idx = key_info->key[i].keyId; + key_params.def_key_idx = key_info->key[i].keyId; + } else + key_params.key_idx = i; + + key_params.key_len = key_info->key[i].keyLength; + status = wma_setup_install_key_cmd(wma_handle, &key_params, + opmode); + if (status == QDF_STATUS_E_NOMEM) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + key_info->status = QDF_STATUS_E_NOMEM; + goto out; + } + + WMA_LOGD("%s: peer unicast key[%d] %d ", __func__, i, + key_info->key[i].keyLength); + + if (status == QDF_STATUS_E_FAILURE) { + WMA_LOGE("%s:Failed to send install key command", + __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + } + + /* In IBSS mode, set the BSS KEY for this peer + * BSS key is supposed to be cache into wma_handle + */ + if (wlan_op_mode_ibss == opmode) { + wma_set_ibsskey_helper(wma_handle, &wma_handle->ibsskey_info, + key_info->peer_macaddr); + } + + /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */ + key_info->status = QDF_STATUS_SUCCESS; +out: + qdf_mem_zero(&key_params, sizeof(struct wma_set_key_params)); + if (key_info->sendRsp) + wma_send_msg_high_priority(wma_handle, WMA_SET_STAKEY_RSP, + (void *)key_info, 0); + else + qdf_mem_free(key_info); +} + +/** + * 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[WME_NUM_AC]; + tSirMacEdcaParamRecord *edca_record; + int ac; + struct cdp_pdev *pdev; + 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); + + vdev_id = edca_params->bssIdx; + + for (ac = 0; ac < WME_NUM_AC; ac++) { + switch (ac) { + case WME_AC_BE: + edca_record = &edca_params->acbe; + break; + case WME_AC_BK: + edca_record = &edca_params->acbk; + break; + case WME_AC_VI: + edca_record = &edca_params->acvi; + break; + case WME_AC_VO: + edca_record = &edca_params->acvo; + break; + default: + goto fail; + } + + wma_update_edca_params_for_ac(edca_record, &wmm_param[ac], ac, + edca_params->mu_edca_params); + + 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; + } + + 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; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (pdev) + cdp_set_wmm_param(soc, (struct cdp_pdev *)pdev, + ol_tx_wmm_param); + else + QDF_ASSERT(0); + + return QDF_STATUS_SUCCESS; + +fail: + WMA_LOGE("%s: Failed to set WMM Paremeters", __func__); + 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; + + WMA_LOGD(FL("Send probe response template for vdev %d"), vdev_id); + + /* + * 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; + + return wmi_unified_probe_rsp_tmpl_send_cmd(wma->wmi_handle, vdev_id, + ¶ms); +} + +/** + * 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; + + WMA_LOGD("Send beacon template for vdev %d", vdev_id); + + 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 (p2p_ie_len) + 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; + 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; + + ret = wmi_unified_beacon_tmpl_send_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("%s: Failed to send bcn tmpl: %d", __func__, 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_LOGE("%s: Memory is not allocated to hold bcn template", + __func__); + return QDF_STATUS_E_INVAL; + } + + len = *(u32 *) &bcn_info->beacon[0]; + if (len > SIR_MAX_BEACON_SIZE - sizeof(uint32_t)) { + WMA_LOGE("%s: Received beacon len %u exceeding max limit %lu", + __func__, len, (unsigned long)( + SIR_MAX_BEACON_SIZE - sizeof(uint32_t))); + return QDF_STATUS_E_INVAL; + } + WMA_LOGD("%s: Storing received beacon template buf to local buffer", + __func__); + 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; + + 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; +} + +/** + * 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) +{ + 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) { + WMA_LOGE("Invalid wma handle"); + return -EINVAL; + } + + param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("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_LOGE("%s: Invalid adjusted_tsf", __func__); + return -EINVAL; + } + + for (; (if_id < wma->max_bssid && vdev_map); vdev_map >>= 1, if_id++) { + if (!(vdev_map & 0x1) || (!(intf[if_id].handle))) + continue; + + bcn = intf[if_id].beacon; + if (!bcn) { + WMA_LOGE("%s: Invalid beacon", __func__); + return -EINVAL; + } + if (!bcn->buf) { + WMA_LOGE("%s: Invalid beacon buffer", __func__); + 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; + qdf_spin_unlock_bh(&bcn->lock); + + /* 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_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + 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 funciton 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) +{ + struct cdp_vdev *vdev; + uint8_t vdev_id; + struct sAniProbeRspStruct *probe_rsp; + + if (!probe_rsp_info) { + WMA_LOGE(FL("probe_rsp_info is NULL")); + return; + } + + probe_rsp = (struct sAniProbeRspStruct *) + (probe_rsp_info->probeRespTemplate); + if (!probe_rsp) { + WMA_LOGE(FL("probe_rsp is NULL")); + return; + } + + vdev = wma_find_vdev_by_addr(wma, probe_rsp->macHdr.sa, &vdev_id); + if (!vdev) { + WMA_LOGE(FL("failed to get vdev handle")); + return; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_beacon_offload)) { + WMA_LOGD("Beacon Offload Enabled Sending Unified command"); + if (wmi_unified_probe_rsp_tmpl_send(wma, vdev_id, + probe_rsp_info) < 0) { + WMA_LOGE(FL("wmi_unified_probe_rsp_tmpl_send Failed ")); + return; + } + } +} + +/** + * wma_send_beacon() - send beacon template + * @wma: wma handle + * @bcn_info: beacon info + * + * This funciton store beacon template locally and + * update keep alive parameters + * + * Return: none + */ +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info) +{ + struct cdp_vdev *vdev; + uint8_t vdev_id; + QDF_STATUS status; + uint8_t *p2p_ie; + struct sAniBeaconStruct *beacon; + struct vdev_up_params param = {0}; + + WMA_LOGD("Beacon update reason %d", bcn_info->reason); + beacon = (struct sAniBeaconStruct *) (bcn_info->beacon); + vdev = wma_find_vdev_by_addr(wma, beacon->macHdr.sa, &vdev_id); + if (!vdev) { + WMA_LOGE("%s : failed to get vdev handle", __func__); + status = QDF_STATUS_E_INVAL; + goto send_rsp; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_beacon_offload)) { + WMA_LOGD("Beacon Offload Enabled Sending Unified command"); + status = wma_unified_bcn_tmpl_send(wma, vdev_id, bcn_info, 4); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ", + __func__); + goto send_rsp; + } + + if (bcn_info->p2pIeOffset) { + p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset; + WMA_LOGD("%s: p2pIe is present - vdev_id %hu, p2p_ie = %pK, p2p ie len = %hu", + __func__, vdev_id, p2p_ie, p2p_ie[1]); + if (wma_p2p_go_set_beacon_ie(wma, vdev_id, + p2p_ie) < 0) { + WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ", + __func__); + status = QDF_STATUS_E_INVAL; + goto send_rsp; + } + } + } + status = wma_store_bcn_tmpl(wma, vdev_id, bcn_info); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s : wma_store_bcn_tmpl Failed", __func__); + goto send_rsp; + } + if (!((qdf_atomic_read( + &wma->interfaces[vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress)) || + (wma->interfaces[vdev_id].is_channel_switch))) { + if (!wma_is_vdev_up(vdev_id)) { + param.vdev_id = vdev_id; + param.assoc_id = 0; + status = wma_send_vdev_up_to_fw(wma, ¶m, + bcn_info->bssId); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE(FL("failed to send vdev up")); + policy_mgr_set_do_hw_mode_change_flag( + wma->psoc, false); + goto send_rsp; + } + wma_vdev_set_mlme_state(wma, vdev_id, WLAN_VDEV_S_RUN); + wma_set_sap_keepalive(wma, vdev_id); + wma_set_vdev_mgmt_rate(wma, vdev_id); + } + } + +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, + tSirKeepAliveReq *keepalive) +{ + WMA_LOGD("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 + * @riis: 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) +{ + tSirSmeMissedBeaconInd *beacon_miss_ind; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + beacon_miss_ind = (tSirSmeMissedBeaconInd *) qdf_mem_malloc + (sizeof(tSirSmeMissedBeaconInd)); + + if (NULL == beacon_miss_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + 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(tSirSmeMissedBeaconInd); + beacon_miss_ind->bssIdx = vdev_id; + + wma_send_msg(wma, WMA_MISSED_BEACON_IND, (void *)beacon_miss_ind, 0); + wma_lost_link_info_handler(wma, vdev_id, rssi + + WMA_TGT_NOISE_FLOOR_DBM); +} + +/** + * wma_get_status_str() - get string of tx status from firmware + * @status: tx status + * + * Return: converted string of tx status + */ +#ifdef WLAN_DEBUG +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); + } +} +#endif + +/** + * wma_mgmt_pktdump_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 tx_status +wma_mgmt_pktdump_status_map(WMI_MGMT_TX_COMP_STATUS_TYPE status) +{ + enum tx_status pktdump_status; + + switch (status) { + case WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK: + pktdump_status = tx_status_ok; + break; + case WMI_MGMT_TX_COMP_TYPE_DISCARD: + pktdump_status = tx_status_discard; + break; + case WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK: + pktdump_status = tx_status_no_ack; + break; + default: + pktdump_status = tx_status_discard; + break; + } + return pktdump_status; +} + +/** + * 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; + uint8_t vdev_id = 0; + QDF_STATUS ret; + tp_wma_packetdump_cb packetdump_cb; + enum tx_status pktdump_status; + + if (wma_handle == NULL) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: status: %s wmi_desc_id: %d", __func__, + wma_get_status_str(status), desc_id); + + pdev = wma_handle->pdev; + if (pdev == NULL) { + WMA_LOGE("%s: psoc ptr is NULL", __func__); + return -EINVAL; + } + + buf = mgmt_txrx_get_nbuf(pdev, desc_id); + vdev_id = mgmt_txrx_get_vdev_id(pdev, desc_id); + + if (buf) + qdf_nbuf_unmap_single(wma_handle->qdf_dev, buf, + QDF_DMA_TO_DEVICE); + + packetdump_cb = wma_handle->wma_mgmt_tx_packetdump_cb; + if (packetdump_cb) { + pktdump_status = wma_mgmt_pktdump_status_map(status); + packetdump_cb(buf, pktdump_status, + vdev_id, TX_MGMT_PKT); + } + + ret = mgmt_txrx_tx_completion_handler(pdev, desc_id, status, NULL); + + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to process mgmt tx completion", __func__); + return -EINVAL; + } + + return 0; +} + +/** + * 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_LOGE("%s: Invalid mgmt Tx completion event", __func__); + return -EINVAL; + } + cmpl_params = param_buf->fixed_param; + + 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_LOGE("%s: Invalid mgmt Tx completion event", __func__); + 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_LOGE("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_LOGE("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++) + 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) +{ + struct wma_txrx_node *iface; + wmi_host_channel_width ch_width; + + iface = &wma_handle->interfaces[update_vht_opmode->smesessionId]; + ch_width = wmi_get_ch_width_from_phy_mode(wma_handle->wmi_handle, + iface->chanmode); + if (ch_width < update_vht_opmode->opMode) { + WMA_LOGE("%s: Invalid peer bw update %d, self bw %d", + __func__, update_vht_opmode->opMode, + ch_width); + return; + } + WMA_LOGD("%s: phymode = %d", __func__, iface->chanmode); + /* Always send phymode before BW to avoid any mismatch in FW */ + wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, + WMI_PEER_PHYMODE, iface->chanmode, + update_vht_opmode->smesessionId); + WMA_LOGD("%s: opMode = %d", __func__, update_vht_opmode->opMode); + wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, + WMI_PEER_CHWIDTH, update_vht_opmode->opMode, + 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_LOGE("%s: target psoc info is NULL", __func__); + 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_LOGD("%s: Rx Nss = %d", __func__, update_rx_nss->rxNss); + + wma_set_peer_param(wma_handle, update_rx_nss->peer_mac, + WMI_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_LOGD("%s: membership = %x ", __func__, membership->membership); + + wma_set_peer_param(wma_handle, membership->peer_mac, + WMI_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_LOGD("%s: userPos = %x ", __func__, userpos->userPos); + + wma_set_peer_param(wma_handle, userpos->peer_mac, + WMI_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_LOGE("Fail to Set CTS2SELF for p2p GO %d", + cts2self_for_p2p_go); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("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 capablity + * @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 (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + 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_LOGE("%s: ht_capab = %d, value = %d", __func__, 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_LOGE("%s:INVALID HT CONFIG", __func__); + } + + return ret; +} + +/** + * wma_hidden_ssid_vdev_restart() - vdev restart for hidden ssid + * @wma_handle: wma handle + * @pReq: hidden ssid vdev restart request + * + * Return: none + */ +void wma_hidden_ssid_vdev_restart(tp_wma_handle wma, + tHalHiddenSsidVdevRestart *pReq) +{ + struct wma_txrx_node *intr = wma->interfaces; + struct wma_target_req *msg; + struct hidden_ssid_vdev_restart_params params; + QDF_STATUS status; + uint8_t vdev_id; + + vdev_id = pReq->sessionId; + if ((vdev_id != intr[vdev_id].vdev_restart_params.vdev_id) + || !((intr[vdev_id].type == WMI_VDEV_TYPE_AP) + && (intr[vdev_id].sub_type == 0))) { + WMA_LOGE(FL("invalid vdev_id %d"), vdev_id); + return; + } + + intr[vdev_id].vdev_restart_params.ssidHidden = pReq->ssidHidden; + qdf_atomic_set(&intr[vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress, 1); + + WMA_LOGD(FL("hidden ssid set using IOCTL for vdev %d ssid_hidden %d"), + vdev_id, pReq->ssidHidden); + + msg = wma_fill_vdev_req(wma, vdev_id, + WMA_HIDDEN_SSID_VDEV_RESTART, + WMA_TARGET_REQ_TYPE_VDEV_START, + pReq, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE(FL("Failed to fill vdev request, vdev_id %d"), + vdev_id); + qdf_atomic_set(&intr[vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + qdf_mem_free(pReq); + return; + } + + params.session_id = vdev_id; + params.ssid_len = intr[vdev_id].vdev_restart_params.ssid.ssid_len; + qdf_mem_copy(params.ssid, + intr[vdev_id].vdev_restart_params.ssid.ssid, + params.ssid_len); + params.flags = intr[vdev_id].vdev_restart_params.flags; + if (intr[vdev_id].vdev_restart_params.ssidHidden) + params.flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; + else + params.flags &= (0xFFFFFFFE); + params.requestor_id = intr[vdev_id].vdev_restart_params.requestor_id; + params.disable_hw_ack = + intr[vdev_id].vdev_restart_params.disable_hw_ack; + + params.mhz = intr[vdev_id].vdev_restart_params.chan.mhz; + params.band_center_freq1 = + intr[vdev_id].vdev_restart_params.chan.band_center_freq1; + params.band_center_freq2 = + intr[vdev_id].vdev_restart_params.chan.band_center_freq2; + params.info = intr[vdev_id].vdev_restart_params.chan.info; + params.reg_info_1 = intr[vdev_id].vdev_restart_params.chan.reg_info_1; + params.reg_info_2 = intr[vdev_id].vdev_restart_params.chan.reg_info_2; + + wma_vdev_set_mlme_state(wma, vdev_id, WLAN_VDEV_S_STOP); + status = wmi_unified_hidden_ssid_vdev_restart_send(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE(FL("Failed to send vdev restart command")); + qdf_atomic_set(&intr[vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + qdf_mem_free(pReq); + } +} + + +#ifdef WLAN_FEATURE_11W + +/** + * 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); + + WMA_LOGE("PN of received packet is %llu", new_pn); + return new_pn; +} + +/** + * wma_is_ccmp_pn_replay_attack() - detect replay attacking using PN in CCMP + * @cds_ctx: cds context + * @wh: 802.11 frame header + * @ccmp_ptr: CCMP frame header + * + * Return: true/false + */ +static bool +wma_is_ccmp_pn_replay_attack(void *cds_ctx, struct ieee80211_frame *wh, + uint8_t *ccmp_ptr) +{ + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + void *peer; + uint8_t vdev_id, peer_id; + uint8_t *last_pn_valid = NULL; + uint64_t *last_pn = NULL, new_pn; + uint32_t *rmf_pn_replays = NULL; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + bool ret = false; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + return true; + } + + vdev = wma_find_vdev_by_bssid(cds_ctx, wh->i_addr3, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + return true; + } + + /* Retrieve the peer based on vdev and addr */ + peer = cdp_peer_get_ref_by_addr(soc, pdev, wh->i_addr2, &peer_id, + PEER_DEBUG_ID_WMA_CCMP_REPLAY_ATTACK); + + if (!peer) { + WMA_LOGE("%s: Failed to find peer, Not able to validate PN", + __func__); + return true; + } + + new_pn = wma_extract_ccmp_pn(ccmp_ptr); + + cdp_get_pn_info(soc, peer, &last_pn_valid, &last_pn, &rmf_pn_replays); + + if (!last_pn_valid || !last_pn || !rmf_pn_replays) { + WMA_LOGE("%s: PN validation seems not supported", __func__); + goto rel_peer_ref; + } + + if (*last_pn_valid) { + if (new_pn > *last_pn) { + *last_pn = new_pn; + WMA_LOGE("%s: PN validation successful", __func__); + } else { + WMA_LOGE("%s: PN Replay attack detected", __func__); + /* per 11W amendment, keeping track of replay attacks */ + *rmf_pn_replays += 1; + ret = true; + } + } else { + *last_pn_valid = 1; + *last_pn = new_pn; + } + +rel_peer_ref: + cdp_peer_release_ref(soc, peer, PEER_DEBUG_ID_WMA_CCMP_REPLAY_ATTACK); + 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; + uint16_t key_id; + uint8_t *efrm; + + efrm = qdf_nbuf_data(wbuf) + qdf_nbuf_len(wbuf); + + if (iface->key.key_cipher == WMI_CIPHER_AES_CMAC) { + mmie_size = cds_get_mmie_size(); + } else if (iface->key.key_cipher == WMI_CIPHER_AES_GMAC) { + mmie_size = cds_get_gmac_mmie_size(); + } else { + WMA_LOGE(FL("Invalid key cipher %d"), iface->key.key_cipher); + return -EINVAL; + } + + /* Check if frame is invalid length */ + if (efrm - (uint8_t *)wh < sizeof(*wh) + mmie_size) { + WMA_LOGE(FL("Invalid frame length")); + return -EINVAL; + } + + key_id = (uint16_t)*(efrm - mmie_size + 2); + if (!((key_id == WMA_IGTK_KEY_INDEX_4) + || (key_id == WMA_IGTK_KEY_INDEX_5))) { + WMA_LOGE(FL("Invalid KeyID(%d) dropping the frame"), key_id); + return -EINVAL; + } + + WMA_LOGD(FL("key_cipher %d key_id %d"), iface->key.key_cipher, key_id); + + switch (iface->key.key_cipher) { + case WMI_CIPHER_AES_CMAC: + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sta_pmf_offload)) { + /* + * if 11w offload is enabled then mmie validation is + * performed in firmware, host just need to trim the + * mmie. + */ + qdf_nbuf_trim_tail(wbuf, cds_get_mmie_size()); + } else { + if (cds_is_mmie_valid(iface->key.key, + iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn, + (uint8_t *) wh, efrm)) { + WMA_LOGD(FL("Protected BC/MC frame MMIE validation successful")); + /* Remove MMIE */ + qdf_nbuf_trim_tail(wbuf, cds_get_mmie_size()); + } else { + WMA_LOGD(FL("BC/MC MIC error or MMIE not present, dropping the frame")); + return -EINVAL; + } + } + break; + + case WMI_CIPHER_AES_GMAC: + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_gmac_offload_support)) { + /* + * if gmac offload is enabled then mmie validation is + * performed in firmware, host just need to trim the + * mmie. + */ + WMA_LOGD(FL("Trim GMAC MMIE")); + qdf_nbuf_trim_tail(wbuf, cds_get_gmac_mmie_size()); + } else { + if (cds_is_gmac_mmie_valid(iface->key.key, + iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn, + (uint8_t *) wh, efrm, iface->key.key_length)) { + WMA_LOGD(FL("Protected BC/MC frame GMAC MMIE validation successful")); + /* Remove MMIE */ + qdf_nbuf_trim_tail(wbuf, + cds_get_gmac_mmie_size()); + } else { + WMA_LOGD(FL("BC/MC GMAC MIC error or MMIE not present, dropping the frame")); + return -EINVAL; + } + } + break; + + default: + WMA_LOGE(FL("Unsupported key cipher %d"), + iface->key.key_cipher); + } + + + 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 (IEEE80211_IS_BROADCAST(wh->i_addr1) || + IEEE80211_IS_MULTICAST(wh->i_addr1)) { + WMA_LOGE("Encrypted BC/MC frame dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + 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_LOGE("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_LOGE("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_LOGE("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_LOGE("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 > WMA_MAX_MGMT_MPDU_LEN) { + WMA_LOGE("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_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"), + MAC_ADDR_ARRAY(wh->i_addr3), rx_pkt->pkt_meta.tsf_delta); + } else { + if (IEEE80211_IS_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_LOGE("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_LOGE("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_LOGE("Peer of peer_mac %pM not found", + peer_mac); + return false; + } + is_pmf_enabled = mlme_get_peer_pmf_status(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + WMA_LOGD("get is_pmf_enabled %d for %pM", is_pmf_enabled, 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->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)) { + 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; +} +#else +static inline 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) +{ + return 0; +} +#endif + +/** + * wma_is_pkt_drop_candidate() - check if the mgmt frame should be droppped + * @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 oterwise + */ +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 == IEEE80211_FC0_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); + tp_wma_packetdump_cb packetdump_cb; + 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) { + WMA_LOGE(FL("wma handle is NULL")); + 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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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.channel = mgmt_rx_params->channel; + 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_LOGE("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 > WMA_MAX_MGMT_MPDU_LEN) { + WMA_LOGE("Data Len %d greater than max, dropping frame from "MAC_ADDRESS_STR, + rx_pkt->pkt_meta.mpdu_data_len, + MAC_ADDR_ARRAY(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; + + /* 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 == IEEE80211_FC0_SUBTYPE_DISASSOC || + mgt_subtype == IEEE80211_FC0_SUBTYPE_DEAUTH || + mgt_subtype == IEEE80211_FC0_SUBTYPE_ACTION)) { + if (wma_find_vdev_by_bssid( + wma_handle, wh->i_addr3, &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.sessionId = + (vdev_id == WMA_INVALID_VDEV_ID ? 0 : vdev_id); + + if (mgt_type == IEEE80211_FC0_TYPE_MGT && + (mgt_subtype == IEEE80211_FC0_SUBTYPE_BEACON || + mgt_subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)) { + if (mgmt_rx_params->buf_len <= + (sizeof(struct ieee80211_frame) + + offsetof(struct wlan_bcn_frame, ie))) { + WMA_LOGD("Dropping frame from "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(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; + } + + packetdump_cb = wma_handle->wma_mgmt_rx_packetdump_cb; + if ((mgt_type == IEEE80211_FC0_TYPE_MGT && + mgt_subtype != IEEE80211_FC0_SUBTYPE_BEACON) && + packetdump_cb) + packetdump_cb(rx_pkt->pkt_buf, QDF_STATUS_SUCCESS, + rx_pkt->pkt_meta.sessionId, RX_MGMT_PKT); + + 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_handle) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return -EINVAL; + } + + mgmt_rx_params = qdf_mem_malloc(sizeof(*mgmt_rx_params)); + if (!mgmt_rx_params) { + WMA_LOGE("%s: memory allocation failed", __func__); + return -ENOMEM; + } + + if (wmi_extract_mgmt_rx_params(wma_handle->wmi_handle, + data, mgmt_rx_params, &bufp) != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Extraction of mgmt rx params failed", __func__); + qdf_mem_free(mgmt_rx_params); + return -EINVAL; + } + + if (mgmt_rx_params->buf_len > data_len) { + WMA_LOGE("%s: Invalid rx mgmt packet, data_len %u, mgmt_rx_params->buf_len %u", + __func__, data_len, mgmt_rx_params->buf_len); + qdf_mem_free(mgmt_rx_params); + return -EINVAL; + } + + 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 capabilites 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) { + WMA_LOGE("%s: Failed to allocate wbuf for mgmt rx len(%u)", + __func__, mgmt_rx_params->buf_len); + 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_LOGE("%s: psoc ctx is NULL", __func__); + 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) { + wma_err_rl("Failed to process mgmt rx frame"); + 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) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + 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_LOGE("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_synch_cb: CSR roam synch 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_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason), + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason)) +{ + + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return QDF_STATUS_E_FAILURE; + } + wma->csr_roam_synch_cb = csr_roam_synch_cb; + wma->pe_roam_synch_cb = pe_roam_synch_cb; + WMA_LOGD("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) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + 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_LOGE("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 + * @wma_mgmt_tx_packetdump_cb: tx mgmt packetdump cb + * @wma_mgmt_rx_packetdump_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( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("wma handle is NULL"); + return; + } + + wma_handle->wma_mgmt_tx_packetdump_cb = wma_mgmt_tx_packetdump_cb; + wma_handle->wma_mgmt_rx_packetdump_cb = wma_mgmt_rx_packetdump_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) { + WMA_LOGE("wma handle is NULL"); + 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; + QDF_STATUS status; + struct wmi_mgmt_params *mgmt_params = + (struct wmi_mgmt_params *)mgmt_tx_params; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_vdev *txrx_vdev; + + if (!mgmt_params) { + WMA_LOGE("%s: mgmt_params ptr passed is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + mgmt_params->desc_id = desc_id; + + if (!vdev) { + WMA_LOGE("%s: vdev ptr passed is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + txrx_vdev = wma_handle->interfaces[mgmt_params->vdev_id].handle; + + 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; + + status = cdp_mgmt_send_ext(soc, txrx_vdev, buf, + mgmt_params->tx_type, + mgmt_params->use_6mbps, + mgmt_params->chanfreq); + } + + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: mgmt tx failed", __func__); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +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_LOGE("%s: Psoc handle NULL", __func__); + return; + } + + dev = wlan_psoc_get_qdf_dev(psoc); + if (wlan_psoc_nif_fw_ext_cap_get(psoc, WLAN_SOC_CEXT_WMI_MGMT_REF)) + qdf_nbuf_unmap_single(dev, buf, QDF_DMA_TO_DEVICE); +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.c new file mode 100644 index 0000000000000000000000000000000000000000..e7143c112b82530a19c991534b7e31f1ef26ea54 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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 + +/** + * wma_add_bss_ndi_mode() - Process BSS creation request while adding NaN + * Data interface + * @wma: wma handle + * @add_bss: Parameters for ADD_BSS command + * + * Sends VDEV_START command to firmware + * Return: None + */ +void wma_add_bss_ndi_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + struct wma_vdev_start_req req; + void *peer = NULL; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGD("%s: enter", __func__); + vdev = wma_find_vdev_by_addr(wma, add_bss->bssId, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + goto send_fail_resp; + } + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + + wma_set_bss_rate_flags(wma, vdev_id, add_bss); + + status = wma_create_peer(wma, pdev, vdev, add_bss->selfMacAddr, + WMI_PEER_TYPE_DEFAULT, vdev_id, false); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to create peer", __func__); + goto send_fail_resp; + } + + peer = cdp_peer_find_by_addr(soc, pdev, add_bss->selfMacAddr, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->selfMacAddr); + goto send_fail_resp; + } + + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto send_fail_resp; + } + + add_bss->staContext.staIdx = cdp_peer_get_local_peer_id(soc, peer); + + /* + * beacon_intval, dtim_period, hidden_ssid, is_dfs, ssid + * will be ignored for NDI device. + */ + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; + req.max_txpow = add_bss->maxTxPower; + req.oper_mode = add_bss->operMode; + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto send_fail_resp; + } + WMA_LOGD("%s: vdev start request for NDI sent to target", __func__); + + /* Initialize protection mode to no protection */ + wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PROTECTION_MODE, IEEE80211_PROT_NONE); + + return; + +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + wma_send_msg_high_priority(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +/** + * 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: void + */ +void wma_add_sta_ndi_mode(tp_wma_handle wma, tpAddStaParams add_sta) +{ + enum ol_txrx_peer_state state = OL_TXRX_PEER_STATE_CONN; + struct cdp_pdev *pdev; + struct cdp_vdev *vdev; + void *peer; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + u_int8_t peer_id; + QDF_STATUS status; + struct wma_txrx_node *iface; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE(FL("Failed to find pdev")); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE(FL("Failed to find vdev")); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + iface = &wma->interfaces[cdp_get_vdev_id(soc, vdev)]; + WMA_LOGD(FL("vdev: %d, peer_mac_addr: "MAC_ADDRESS_STR), + add_sta->smesessionId, MAC_ADDR_ARRAY(add_sta->staMac)); + + peer = cdp_peer_find_by_addr_and_vdev(soc, + pdev, vdev, + add_sta->staMac, &peer_id); + if (peer) { + WMA_LOGE(FL("NDI peer already exists, peer_addr %pM"), + 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. + */ + peer = cdp_peer_find_by_addr(soc, + pdev, + add_sta->staMac, &peer_id); + if (peer) { + WMA_LOGE(FL("vdev:%d, peer exists on other vdev with peer_addr %pM and peer_id %d"), + cdp_get_vdev_id(soc, vdev), + add_sta->staMac, peer_id); + add_sta->status = QDF_STATUS_E_EXISTS; + goto send_rsp; + } + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_NAN_DATA, add_sta->smesessionId, + false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("Failed to create peer for %pM"), add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = cdp_peer_find_by_addr_and_vdev(soc, + pdev, vdev, + add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE(FL("Failed to find peer handle using peer mac %pM"), + add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + goto send_rsp; + } + + WMA_LOGD(FL("Moving peer %pM to state %d"), add_sta->staMac, state); + cdp_peer_state_update(soc, pdev, add_sta->staMac, state); + + add_sta->staIdx = cdp_peer_get_local_peer_id(soc, peer); + add_sta->nss = iface->nss; + add_sta->status = QDF_STATUS_SUCCESS; +send_rsp: + WMA_LOGD(FL("Sending add sta rsp to umac (mac:%pM, status:%d)"), + add_sta->staMac, add_sta->status); + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} + +/** + * 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 + * + * Return: None + */ +void wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ + struct cdp_pdev *pdev; + void *peer; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE(FL("Failed to get pdev")); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + peer = cdp_peer_find_by_local_id(cds_get_context(QDF_MODULE_ID_SOC), + pdev, del_sta->staIdx); + if (!peer) { + WMA_LOGE(FL("Failed to get peer handle using peer id %d"), + del_sta->staIdx); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + wma_remove_peer(wma, cdp_peer_get_peer_mac_addr(soc, peer), + del_sta->smesessionId, peer, false); + del_sta->status = QDF_STATUS_SUCCESS; + +send_del_rsp: + if (del_sta->respReqd) { + WMA_LOGD(FL("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_LOGD(FL("NDI Del Sta resp not needed")); + qdf_mem_free(del_sta); + } + +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.h b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..95394fb09490346ff06668f52cbef925ea3e8339 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 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. + */ + +/** + * 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_DATAPATH +#define WMA_IS_VDEV_IN_NDI_MODE(intf, vdev_id) \ + (WMI_VDEV_TYPE_NDI == intf[vdev_id].type) + +void 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; +} + +void wma_add_bss_ndi_mode(tp_wma_handle wma, tpAddBssParams add_bss); + +void 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 +#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 void wma_add_bss_ndi_mode(tp_wma_handle wma, + tpAddBssParams add_bss) +{ + return; +} + +static inline void wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ +} +static inline void wma_add_sta_ndi_mode(tp_wma_handle wma, + tpAddStaParams add_sta) {} + +static inline bool wma_is_ndi_active(tp_wma_handle wma_handle) { return false; } +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +#endif /* __WMA_NAN_DATAPATH_H */ diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.c new file mode 100644 index 0000000000000000000000000000000000000000..103ee427ac1c27f6e83ea4541613bdb719750d2b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.c @@ -0,0 +1,78 @@ +/* + * 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: 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" + +/** + * 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) +{ + struct wma_target_req *msg; + struct wma_vdev_start_req req; + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + qdf_mem_zero(&req, sizeof(req)); + msg = wma_fill_vdev_req(wma, config->vdev_id, + WMA_OCB_SET_CONFIG_CMD, + WMA_TARGET_REQ_TYPE_VDEV_START, + (void *)config, 1000); + if (!msg) { + WMA_LOGE(FL("Failed to fill vdev req %d"), config->vdev_id); + + return QDF_STATUS_E_NOMEM; + } + req.chan = cds_freq_to_chan(config->channels[0].chan_freq); + req.vdev_id = msg->vdev_id; + if (cds_chan_to_band(req.chan) == CDS_BAND_2GHZ) + req.dot11_mode = WNI_CFG_DOT11_MODE_11G; + else + req.dot11_mode = WNI_CFG_DOT11_MODE_11A; + + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, req.vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + WMA_LOGE(FL("vdev_start failed, status = %d"), status); + } + + 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/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.h b/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.h new file mode 100644 index 0000000000000000000000000000000000000000..a6339a3dd87035d19371187b55edf0aaecaa5ae3 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/core/wma/src/wma_power.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_power.c new file mode 100644 index 0000000000000000000000000000000000000000..a5f3b71ac1e19ae456096a9b4a4f2b4ca6856ff0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_power.c @@ -0,0 +1,1755 @@ +/* + * 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: 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 "cfg_api.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" + +/** + * wma_unified_modem_power_state() - set modem power state to fw + * @wmi_handle: wmi handle + * @param_value: parameter value + * + * Return: 0 for success or error code + */ +static int +wma_unified_modem_power_state(wmi_unified_t wmi_handle, uint32_t param_value) +{ + int ret; + 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) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + 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_LOGD("%s: Setting cmd->modem_power_state = %u", __func__, + param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_MODEM_POWER_STATE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send notify cmd ret = %d", ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * 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 (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGD("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 = 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; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_set_ibss_pwrsave_params() - set ibss power save parameter to fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code. + */ +QDF_STATUS +wma_set_ibss_pwrsave_params(tp_wma_handle wma, uint8_t vdev_id) +{ + QDF_STATUS ret; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH, + wma->wma_ibss_power_save_params.atimWindowLength); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH ret = %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, + wma->wma_ibss_power_save_params.isPowerSaveAllowed); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, + wma->wma_ibss_power_save_params.isPowerCollapseAllowed); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, + wma->wma_ibss_power_save_params.isAwakeonTxRxEnabled); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_INACTIVITY_CNT, + wma->wma_ibss_power_save_params.inactivityCount); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_INACTIVITY_CNT ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, + wma->wma_ibss_power_save_params.txSPEndInactivityTime); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, + wma->wma_ibss_power_save_params.ibssPsWarmupTime); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, + wma->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to set IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * 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_LOGD("Set WMI_AP_PS_PEER_PARAM_UAPSD 0x%x for %pM", + uapsd, 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_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_UAPSD for %pM", + peer_addr); + return ret; + } + + WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_MAX_SP 0x%x for %pM", + max_sp_len, 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_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_MAX_SP for %pM", + 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) +{ +#define WMA_WMM_EXPO_TO_VAL(val) ((1 << (val)) - 1) + if (mu_edca_param) { + wmm_param->cwmin = edca_param->cw.min; + wmm_param->cwmax = edca_param->cw.max; + } else { + 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; + + WMA_LOGD("WMM PARAMS 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; + struct cdp_vdev *vdev; + + if (tx_pwr_params->dev_mode == QDF_SAP_MODE || + tx_pwr_params->dev_mode == QDF_P2P_GO_MODE) { + vdev = wma_find_vdev_by_addr(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } else { + vdev = wma_find_vdev_by_bssid(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } + if (!vdev) { + WMA_LOGE("vdev handle is invalid for %pM", + tx_pwr_params->bssId.bytes); + qdf_mem_free(tx_pwr_params); + return; + } + + if (!wma_is_vdev_up(vdev_id)) { + WMA_LOGE("%s: vdev id %d is not up for %pM", __func__, vdev_id, + tx_pwr_params->bssId.bytes); + qdf_mem_free(tx_pwr_params); + return; + } + + if (tx_pwr_params->power == 0) { + /* set to default. Since the app does not care the tx power + * we keep the previous setting + */ + wma_handle->interfaces[vdev_id].tx_power = 0; + ret = 0; + goto end; + } + if (wma_handle->interfaces[vdev_id].max_tx_power != 0) { + /* make sure tx_power less than max_tx_power */ + if (tx_pwr_params->power > + wma_handle->interfaces[vdev_id].max_tx_power) { + tx_pwr_params->power = + wma_handle->interfaces[vdev_id].max_tx_power; + } + } + if (wma_handle->interfaces[vdev_id].tx_power != tx_pwr_params->power) { + + /* tx_power changed, Push the tx_power to FW */ + WMA_LOGI("%s: Set TX pwr limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + __func__, 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) + wma_handle->interfaces[vdev_id].tx_power = + 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_LOGE("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; + struct cdp_vdev *vdev; + int8_t prev_max_power; + + vdev = wma_find_vdev_by_addr(wma_handle, tx_pwr_params->bssId.bytes, + &vdev_id); + if (vdev == NULL) { + /* not in SAP array. Try the station/p2p array */ + vdev = wma_find_vdev_by_bssid(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } + if (!vdev) { + WMA_LOGE("vdev handle is invalid for %pM", + tx_pwr_params->bssId.bytes); + qdf_mem_free(tx_pwr_params); + return; + } + + if (!wma_is_vdev_up(vdev_id)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id); + qdf_mem_free(tx_pwr_params); + return; + } + + if (wma_handle->interfaces[vdev_id].max_tx_power == + tx_pwr_params->power) { + ret = QDF_STATUS_SUCCESS; + goto end; + } + prev_max_power = wma_handle->interfaces[vdev_id].max_tx_power; + wma_handle->interfaces[vdev_id].max_tx_power = tx_pwr_params->power; + if (wma_handle->interfaces[vdev_id].max_tx_power == 0) { + ret = QDF_STATUS_SUCCESS; + goto end; + } + WMA_LOGI("Set MAX TX pwr limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + wma_handle->interfaces[vdev_id].max_tx_power); + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + wma_handle->interfaces[vdev_id].max_tx_power); + if (ret == QDF_STATUS_SUCCESS) + wma_handle->interfaces[vdev_id].tx_power = + wma_handle->interfaces[vdev_id].max_tx_power; + else + wma_handle->interfaces[vdev_id].max_tx_power = prev_max_power; +end: + qdf_mem_free(tx_pwr_params); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("%s: Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT", + __func__); +} + +/** + * 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_LOGE("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 + * @qpower_config: qpower configuration + * + * 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, + enum powersave_qpower_mode qpower_config, + bool enable_ps) +{ + QDF_STATUS ret; + uint32_t cfg_data_val = 0; + /* get mac to access CFG data base */ + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t rx_wake_policy; + uint32_t tx_wake_threshold; + uint32_t pspoll_count; + uint32_t inactivity_time; + uint32_t psmode; + + WMA_LOGD("Set Force Sleep vdevId %d val %d", vdev_id, enable); + + if (NULL == mac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return QDF_STATUS_E_NOMEM; + } + + /* Set Tx/Rx Data InActivity Timeout */ + if (wlan_cfg_get_int(mac, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + &cfg_data_val) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT"); + cfg_data_val = POWERSAVE_DEFAULT_INACTIVITY_TIME; + } + inactivity_time = (uint32_t) cfg_data_val; + + 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 (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + } + if (cfg_data_val) + pspoll_count = (uint32_t) cfg_data_val; + else + pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE; + + psmode = WMI_STA_PS_MODE_ENABLED; + } else { + /* Ps Poll Wake Policy */ + if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + } + if (cfg_data_val) { + /* Ps Poll is enabled */ + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; + pspoll_count = (uint32_t) cfg_data_val; + 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; + } + + /* + * QPower is enabled by default in Firmware + * So Disable QPower explicitly + */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_ENABLE_QPOWER, + qpower_config); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("%s(%d) QPower Failed vdevId %d", + qpower_config ? "Enable" : "Disable", + qpower_config, vdev_id); + return ret; + } + WMA_LOGD("QPower %s(%d) vdevId %d", + qpower_config ? "Enabled" : "Disabled", + qpower_config, vdev_id); + + /* 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_LOGE("Setting wake policy Failed vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("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_LOGE("Setting TxWake Threshold vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("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_LOGE("Set Ps Poll Count Failed vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + return ret; + } + WMA_LOGD("Set Ps Poll Count vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + + /* Set the Tx/Rx InActivity */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_INACTIVITY_TIME, + inactivity_time); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Setting Tx/Rx InActivity Failed vdevId %d InAct %d", + vdev_id, inactivity_time); + return ret; + } + WMA_LOGD("Set Tx/Rx InActivity vdevId %d InAct %d", + vdev_id, inactivity_time); + + /* 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_LOGE("Enable Sta Mode Ps Failed vdevId %d", + vdev_id); + return ret; + } + } + + /* Set Listen Interval */ + if (wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL, + &cfg_data_val) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_LISTEN_INTERVAL"); + cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + cfg_data_val); + if (QDF_IS_STATUS_ERROR(ret)) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", vdev_id); + } + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, cfg_data_val); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_qpower_config() - get qpower configuration + * @wma: WMA handle + * + * Power Save Offload configuration: + * 0 -> Power save offload is disabled + * 1 -> Legacy Power save enabled + Deep sleep Disabled + * 2 -> QPower enabled + Deep sleep Disabled + * 3 -> Legacy Power save enabled + Deep sleep Enabled + * 4 -> QPower enabled + Deep sleep Enabled + * 5 -> Duty cycling QPower enabled + * + * Return: enum powersave_qpower_mode with below values + * QPOWER_DISABLED if QPOWER is disabled + * QPOWER_ENABLED if QPOWER is enabled + * QPOWER_DUTY_CYCLING if DUTY CYCLING QPOWER is enabled + */ +static enum powersave_qpower_mode wma_get_qpower_config(tp_wma_handle wma) +{ + switch (wma->powersave_mode) { + case PS_QPOWER_NODEEPSLEEP: + case PS_QPOWER_DEEPSLEEP: + WMA_LOGI("QPOWER is enabled in power save mode %d", + wma->powersave_mode); + return QPOWER_ENABLED; + case PS_DUTY_CYCLING_QPOWER: + WMA_LOGI("DUTY cycling QPOWER is enabled in power save mode %d", + wma->powersave_mode); + return QPOWER_DUTY_CYCLING; + + default: + WMA_LOGI("QPOWER is disabled in power save mode %d", + wma->powersave_mode); + return QPOWER_DISABLED; + } +} + +/** + * wma_enable_sta_ps_mode() - enable sta powersave params in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req) +{ + uint32_t vdev_id = ps_req->sessionid; + QDF_STATUS ret; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + if (!iface->handle) { + WMA_LOGE("vdev id %d is not active", vdev_id); + return; + } + if (eSIR_ADDON_NOTHING == ps_req->psSetting) { + if (qpower_config && iface->uapsd_cached_val) { + qpower_config = 0; + WMA_LOGD("Qpower is disabled"); + } + WMA_LOGD("Enable Sta Mode Ps vdevId %d", vdev_id); + 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_LOGE("Set Uapsd param 0 Failed vdevId %d", vdev_id); + return; + } + + ret = wma_set_force_sleep(wma, vdev_id, false, + qpower_config, true); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("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_LOGD("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_LOGE("Enable Uapsd Failed vdevId %d", + vdev_id); + return; + } + /* Cache the Uapsd Mask */ + iface->uapsd_cached_val = uapsd_val; + } else { + WMA_LOGD("Already Uapsd Enabled vdevId %d Mask %d", + vdev_id, uapsd_val); + } + + if (qpower_config && iface->uapsd_cached_val) { + qpower_config = 0; + WMA_LOGD("Qpower is disabled"); + } + WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma, vdev_id, true, + qpower_config, true); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Enable Forced Sleep Failed vdevId %d", + vdev_id); + return; + } + } + + if (wma->ito_repeat_count) { + WMA_LOGI("Set ITO count to %d for vdevId %d", + wma->ito_repeat_count, vdev_id); + + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX, + wma->ito_repeat_count); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("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(tp_wma_handle wma, tpDisablePsParams ps_req) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + WMA_LOGD("Disable Sta Mode Ps vdevId %d", vdev_id); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("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_LOGD("Disable Uapsd vdevId %d", vdev_id); + 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_LOGE("Disable Uapsd Failed vdevId %d", vdev_id); + /* + * Even this fails we can proceed as success + * since we disabled powersave + */ + } + } +} + +QDF_STATUS wma_set_qpower_config(uint8_t vdev_id, uint8_t qpower) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return QDF_STATUS_E_INVAL; + } + + WMA_LOGI("configuring qpower: %d", qpower); + wma->powersave_mode = qpower; + return wma_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_ENABLE_QPOWER, + wma_get_qpower_config(wma)); +} + +/** + * 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) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + uint32_t uapsd_val = 0; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + if (!iface->handle) { + WMA_LOGE("vdev id %d is not active", 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_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams); + + WMA_LOGD("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_LOGE("Enable Uapsd Failed vdevId %d", vdev_id); + return; + } + + if (qpower_config && uapsd_val) { + qpower_config = 0; + WMA_LOGD("Disable Qpower %d", vdev_id); + } + iface->uapsd_cached_val = uapsd_val; + WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma, vdev_id, true, + qpower_config, ps_req->uapsdParams.enable_ps); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("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; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + + WMA_LOGD("Disable Uapsd vdevId %d", vdev_id); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("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_LOGE("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, + qpower_config, true); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("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[IEEE80211_ADDR_LEN], + 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) * IEEE80211_ADDR_LEN); + ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wmi_handle, + &cmd); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set uapsd param ret = %d", ret); + + return ret; +} + +/** + * 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) +{ + QDF_STATUS ret; + struct sta_uapsd_params uapsd_trigger_param; + + WMA_LOGD("Trigger uapsd params vdev id %d", vdev_id); + + WMA_LOGD("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_LOGD("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; + + ret = wma_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, wma_handle->interfaces[vdev_id].bssid, + &uapsd_trigger_param, 1); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Fail to send uapsd param cmd for vdevid %d ret = %d", + ret, vdev_id); + return ret; + } + + return ret; +} + +/** + * 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) +{ + QDF_STATUS ret; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + struct sta_uapsd_params uapsd_trigger_param; + enum uapsd_up user_priority; + + WMA_LOGD("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_LOGE("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; + + ret = wma_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, wma_handle->interfaces[vdev_id].bssid, + &uapsd_trigger_param, 1); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("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_LOGE("Disable Uapsd per ac Failed vdevId %d ac %d", vdev_id, + ac); + return ret; + } + WMA_LOGD("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_LOGE("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_LOGE("Invalid pdev_temperature event buffer"); + return -EINVAL; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGI(FL("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_LOGE(FL("Fail to post get temperature ind msg")); + return 0; +} + +/** + * 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, + tSirTxPowerLimit *ptxlim) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + int32_t ret = 0; + uint32_t txpower_params2g = 0; + uint32_t txpower_params5g = 0; + struct pdev_params pdevparam; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue tx power limit", + __func__); + 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_LOGD("%s: txpower2g: %x txpower5g: %x", + __func__, txpower_params2g, txpower_params5g); + + pdevparam.param_id = WMI_PDEV_PARAM_TXPOWER_LIMIT2G; + pdevparam.param_value = txpower_params2g; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("%s: Failed to set txpower 2g (%d)", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + pdevparam.param_id = WMI_PDEV_PARAM_TXPOWER_LIMIT5G; + pdevparam.param_value = txpower_params5g; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("%s: Failed to set txpower 5g (%d)", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * 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_LOGD("%s: NoA is present in previous beacon, but not present in swba event, So Reset the NoA", + __func__); + /* 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_LOGD("%s: No need to update NoA", __func__); + return; + } + + if (bcn->noa_sub_ie_len && bcn->noa_ie) { + /* NoA present in previous beacon, update it */ + WMA_LOGD("%s: NoA present in previous beacon, update the NoA IE, bcn->len %u bcn->noa_sub_ie_len %u", + __func__, 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_LOGD("%s: NoA not present in previous beacon, add it bcn->len %u", + __func__, bcn->len); + buf = qdf_nbuf_data(bcn->buf); + bcn->noa_ie = buf + bcn->len; + } + + 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_LOGI("%s: Updated beacon length with NoA Ie is %u", + __func__, 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_LOGD("%s: NoA is not present", __func__); + new_noa_sub_ie_len = 0; + } else { + /* Create the binary blob containing NOA sub-IE */ + WMA_LOGD("%s: Create NOA sub ie", __func__); + wma_p2p_create_sub_ie_noa(&beacon->noa_sub_ie[0], + noa_ie, &new_noa_sub_ie_len); + } + } else { + WMA_LOGD("%s: No need to add NOA", __func__); + 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 = + (tSirP2PNoaAttr *) qdf_mem_malloc(sizeof(tSirP2PNoaAttr)); + WMA_LOGD("Received update NoA event"); + if (!noa_attr) { + WMA_LOGE("Failed to allocate memory for tSirP2PNoaAttr"); + 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_LOGD("Zero NoA descriptors"); + } else { + WMA_LOGD("%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_LOGI("Sending SIR_HAL_P2P_NOA_ATTR_IND to LIM"); + wma_send_msg(wma_handle, SIR_HAL_P2P_NOA_ATTR_IND, (void *)noa_attr, 0); +} + +/** + * wma_p2p_noa_event_handler() - p2p noa event handler + * @handle: wma handle + * @event: event data + * @len: length + * + * Return: 0 for success or error code. + */ +int wma_p2p_noa_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_P2P_NOA_EVENTID_param_tlvs *param_buf; + wmi_p2p_noa_event_fixed_param *p2p_noa_event; + uint8_t vdev_id, i; + wmi_p2p_noa_info *p2p_noa_info; + struct p2p_sub_element_noa noa_ie; + uint8_t *buf_ptr; + uint32_t descriptors; + + param_buf = (WMI_P2P_NOA_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid P2P NoA event buffer"); + return -EINVAL; + } + + p2p_noa_event = param_buf->fixed_param; + buf_ptr = (uint8_t *) p2p_noa_event; + buf_ptr += sizeof(wmi_p2p_noa_event_fixed_param); + p2p_noa_info = (wmi_p2p_noa_info *) (buf_ptr); + vdev_id = p2p_noa_event->vdev_id; + + 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); + descriptors = WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); + noa_ie.num_descriptors = (uint8_t) descriptors; + + if (noa_ie.num_descriptors > WMA_MAX_NOA_DESCRIPTORS) { + WMA_LOGD("Sizing down the no of desc %d to max", + noa_ie.num_descriptors); + noa_ie.num_descriptors = WMA_MAX_NOA_DESCRIPTORS; + } + WMA_LOGD("%s: index %u, oppPs %u, ctwindow %u, num_desc = %u", + __func__, 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_LOGI("%s: NoA descriptor[%d] type_count %u, duration %u, interval %u, start_time = %u", + __func__, 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); + } + + /* 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); + } + + return 0; +} + +/** + * 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_LOGD("%s: htMIMOPSState = %d, sessionId = %d peerMac <%02x:%02x:%02x:%02x:%02x:%02x>", + __func__, + mimops->htMIMOPSState, mimops->sessionId, mimops->peerMac[0], + mimops->peerMac[1], mimops->peerMac[2], mimops->peerMac[3], + mimops->peerMac[4], mimops->peerMac[5]); + + wma_set_peer_param(wma_handle, mimops->peerMac, + WMI_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_LOGE("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) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + + WMA_LOGD("%s: WMA notify Modem Power State %d", __func__, pReq->param); + + ret = wma_unified_modem_power_state(wma->wmi_handle, pReq->param); + if (ret) { + WMA_LOGE("%s: Fail to notify Modem Power State %d", + __func__, pReq->param); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Successfully notify Modem Power State %d", pReq->param); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_idle_ps_config() - enable/disble 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_LOGD("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_LOGE("Fail to Set Idle Ps Config %d", idle_ps); + return QDF_STATUS_E_FAILURE; + } + wma->in_imps = !!idle_ps; + + WMA_LOGD("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; + + ret = wmi_unified_set_smps_params(wma->wmi_handle, vdev_id, + value); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set Mimo PS ret = %d", ret); + + return ret; +} + +/** + * 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 = + (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_is_vdev_up(vdev_id)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, 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_LOGE("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 = + (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_is_vdev_up(vdev_id)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, 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_LOGE("Decrease tx power value failed"); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_sar_public_structs.h b/drivers/staging/qcacld-3.0/core/wma/src/wma_sar_public_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..f2b330ba3f8ecc104fc3ee31faa76b4130776c76 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_sar_public_structs.h @@ -0,0 +1,36 @@ +/* + * 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 __WMA_SAR_PUBLIC_STRUCTS_H +#define __WMA_SAR_PUBLIC_STRUCTS_H + +struct sar_limit_event; + +enum sar_version { + SAR_VERSION_1, + SAR_VERSION_2 +}; + +/** + * 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/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..144085724a863046306d425a482f0b0d6111e0ce --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c @@ -0,0 +1,5674 @@ +/* + * 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_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 "cfg_api.h" +#include +#include + +#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_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" +#include "wlan_tgt_def_config.h" +#include "wlan_reg_services_api.h" +#include "wlan_roam_debug.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 + +#define WMA_MCC_MIRACAST_REST_TIME 400 +#define WMA_SCAN_ID_MASK 0x0fff + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * enum extscan_report_events_type - extscan report events type + * @EXTSCAN_REPORT_EVENTS_BUFFER_FULL: report only when scan history is % full + * @EXTSCAN_REPORT_EVENTS_EACH_SCAN: report a scan completion event after scan + * @EXTSCAN_REPORT_EVENTS_FULL_RESULTS: forward scan results + * (beacons/probe responses + IEs) + * in real time to HAL, in addition to completion events. + * Note: To keep backward compatibility, + * fire completion events regardless of REPORT_EVENTS_EACH_SCAN. + * @EXTSCAN_REPORT_EVENTS_NO_BATCH: controls batching, + * 0 => batching, 1 => no batching + * @EXTSCAN_REPORT_EVENTS_CONTEXT_HUB: forward results to context hub + */ +enum extscan_report_events_type { + EXTSCAN_REPORT_EVENTS_BUFFER_FULL = 0x00, + EXTSCAN_REPORT_EVENTS_EACH_SCAN = 0x01, + EXTSCAN_REPORT_EVENTS_FULL_RESULTS = 0x02, + EXTSCAN_REPORT_EVENTS_NO_BATCH = 0x04, + EXTSCAN_REPORT_EVENTS_CONTEXT_HUB = 0x08, +}; + +#define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED + +/* + * Maximum number of entires that could be present in the + * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware + */ +#define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10 +#endif + +/** + * 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; + struct scan_chan_list_params scan_ch_param = {0}; + wmi_channel_param *tchan_info; + + scan_ch_param.chan_info = qdf_mem_malloc(sizeof(wmi_channel) * + chan_list->numChan); + if (NULL == scan_ch_param.chan_info) { + WMA_LOGE("%s: Failed to allocate channel info", __func__); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_zero(scan_ch_param.chan_info, sizeof(wmi_channel) * + chan_list->numChan); + WMA_LOGD("no of channels = %d", chan_list->numChan); + tchan_info = scan_ch_param.chan_info; + scan_ch_param.num_scan_chans = chan_list->numChan; + wma_handle->saved_chan.num_channels = chan_list->numChan; + WMA_LOGD("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) { + tchan_info->mhz = + cds_chan_to_freq(chan_list->chanParam[i].chanId); + tchan_info->band_center_freq1 = + tchan_info->mhz; + tchan_info->band_center_freq2 = 0; + wma_handle->saved_chan.channel_list[i] = + chan_list->chanParam[i].chanId; + + WMA_LOGD("chan[%d] = freq:%u chan:%d DFS:%d tx power:%d", + i, tchan_info->mhz, + chan_list->chanParam[i].chanId, + chan_list->chanParam[i].dfsSet, + chan_list->chanParam[i].pwr); + + if (chan_list->chanParam[i].dfsSet) { + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_PASSIVE); + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_DFS); + } + + if (tchan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) { + WMI_SET_CHANNEL_MODE(tchan_info, MODE_11G); + if (chan_list->vht_en && chan_list->vht_24_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_VHT); + } else { + WMI_SET_CHANNEL_MODE(tchan_info, MODE_11A); + if (chan_list->vht_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_VHT); + } + + if (chan_list->ht_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_HT); + + if (chan_list->chanParam[i].half_rate) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_HALF_RATE); + else if (chan_list->chanParam[i].quarter_rate) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_QUARTER_RATE); + + WMI_SET_CHANNEL_MAX_TX_POWER(tchan_info, + chan_list->chanParam[i].pwr); + + WMI_SET_CHANNEL_REG_POWER(tchan_info, + chan_list->chanParam[i].pwr); + tchan_info++; + } + + qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle, + &scan_ch_param); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + WMA_LOGE("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); + + qdf_mem_free(scan_ch_param.chan_info); + + return qdf_status; +} + +QDF_STATUS wma_roam_scan_mawc_params(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + struct wmi_mawc_roam_params *params; + QDF_STATUS status; + + if (!roam_req) { + WMA_LOGE("No MAWC parameters to send"); + return QDF_STATUS_E_INVAL; + } + params = qdf_mem_malloc(sizeof(*params)); + if (!params) { + WMA_LOGE("No memory allocated for MAWC roam params"); + return QDF_STATUS_E_NOMEM; + } + params->vdev_id = roam_req->sessionId; + params->enable = roam_req->mawc_roam_params.mawc_enabled && + roam_req->mawc_roam_params.mawc_roam_enabled; + params->traffic_load_threshold = + roam_req->mawc_roam_params.mawc_roam_traffic_threshold; + params->best_ap_rssi_threshold = + roam_req->mawc_roam_params.mawc_roam_ap_rssi_threshold - + WMA_NOISE_FLOOR_DBM_DEFAULT; + params->rssi_stationary_high_adjust = + roam_req->mawc_roam_params.mawc_roam_rssi_high_adjust; + params->rssi_stationary_low_adjust = + roam_req->mawc_roam_params.mawc_roam_rssi_low_adjust; + status = wmi_unified_roam_mawc_params_cmd( + wma_handle->wmi_handle, params); + qdf_mem_free(params); + + return status; +} +#ifdef WLAN_FEATURE_FILS_SK +/** + * wma_roam_scan_fill_fils_params() - API to fill FILS params in RSO command + * @wma_handle: WMA handle + * @params: Pointer to destination RSO params to be filled + * @roam_req: Pointer to RSO params from CSR + * + * Return: None + */ +static void wma_roam_scan_fill_fils_params(tp_wma_handle wma_handle, + struct roam_offload_scan_params + *params, tSirRoamOffloadScanReq + *roam_req) +{ + struct roam_fils_params *dst_fils_params, *src_fils_params; + + if (!params || !roam_req || !roam_req->is_fils_connection) { + WMA_LOGD("wma_roam_scan_fill_fils_params- NULL"); + return; + } + + src_fils_params = &roam_req->roam_fils_params; + dst_fils_params = ¶ms->roam_fils_params; + + params->add_fils_tlv = true; + + dst_fils_params->username_length = src_fils_params->username_length; + qdf_mem_copy(dst_fils_params->username, src_fils_params->username, + dst_fils_params->username_length); + + dst_fils_params->next_erp_seq_num = src_fils_params->next_erp_seq_num; + dst_fils_params->rrk_length = src_fils_params->rrk_length; + qdf_mem_copy(dst_fils_params->rrk, src_fils_params->rrk, + dst_fils_params->rrk_length); + + dst_fils_params->rik_length = src_fils_params->rik_length; + qdf_mem_copy(dst_fils_params->rik, src_fils_params->rik, + dst_fils_params->rik_length); + + dst_fils_params->realm_len = src_fils_params->realm_len; + qdf_mem_copy(dst_fils_params->realm, src_fils_params->realm, + dst_fils_params->realm_len); +} +#else +static inline void wma_roam_scan_fill_fils_params( + tp_wma_handle wma_handle, + struct roam_offload_scan_params *params, + tSirRoamOffloadScanReq *roam_req) + +{ } +#endif + +/** + * wma_roam_scan_offload_mode() - send roam scan mode request to fw + * @wma_handle: wma handle + * @scan_cmd_fp: start scan command ptr + * @roam_req: roam request param + * @mode: mode + * @vdev_id: vdev id + * + * send WMI_ROAM_SCAN_MODE TLV to firmware. It has a piggyback + * of WMI_ROAM_SCAN_MODE. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, + wmi_start_scan_cmd_fixed_param * + scan_cmd_fp, + tSirRoamOffloadScanReq *roam_req, + uint32_t mode, uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct roam_offload_scan_params *params = + qdf_mem_malloc(sizeof(*params)); + + if (!params) { + WMA_LOGE("%s: Failed to allocate scan params", __func__); + return QDF_STATUS_E_NOMEM; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + params->auth_mode = WMI_AUTH_NONE; + if (roam_req) + params->auth_mode = e_csr_auth_type_to_rsn_authmode + (roam_req->ConnectedNetwork.authentication, + roam_req->ConnectedNetwork.encryption); + WMA_LOGD("%s : auth mode = %d", __func__, params->auth_mode); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + + params->is_roam_req_valid = 0; + params->mode = mode; + params->vdev_id = vdev_id; + if (roam_req) { + params->is_roam_req_valid = 1; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + params->roam_offload_enabled = roam_req->RoamOffloadEnabled; + params->roam_offload_params.ho_delay_for_rx = + roam_req->ho_delay_for_rx; + params->roam_offload_params.roam_preauth_retry_count = + roam_req->roam_preauth_retry_count; + params->roam_offload_params.roam_preauth_no_ack_timeout = + roam_req->roam_preauth_no_ack_timeout; + params->prefer_5ghz = roam_req->Prefer5GHz; + params->roam_rssi_cat_gap = roam_req->RoamRssiCatGap; + params->select_5ghz_margin = roam_req->Select5GHzMargin; + params->reassoc_failure_timeout = + roam_req->ReassocFailureTimeout; + params->rokh_id_length = roam_req->R0KH_ID_Length; + qdf_mem_copy(params->rokh_id, roam_req->R0KH_ID, + WMI_ROAM_R0KH_ID_MAX_LEN); + qdf_mem_copy(params->krk, roam_req->KRK, WMI_KRK_KEY_LEN); + qdf_mem_copy(params->btk, roam_req->BTK, WMI_BTK_KEY_LEN); + qdf_mem_copy(params->psk_pmk, roam_req->PSK_PMK, + WMI_ROAM_SCAN_PSK_SIZE); + params->pmk_len = roam_req->pmk_len; + params->roam_key_mgmt_offload_enabled = + roam_req->RoamKeyMgmtOffloadEnabled; + wma_roam_scan_fill_self_caps(wma_handle, + ¶ms->roam_offload_params, roam_req); + params->fw_okc = roam_req->pmkid_modes.fw_okc; + params->fw_pmksa_cache = roam_req->pmkid_modes.fw_pmksa_cache; + params->rct_validity_timer = roam_req->rct_validity_timer; +#endif + params->min_delay_btw_roam_scans = + roam_req->min_delay_btw_roam_scans; + params->roam_trigger_reason_bitmask = + roam_req->roam_trigger_reason_bitmask; + params->is_ese_assoc = roam_req->IsESEAssoc; + params->is_11r_assoc = roam_req->is_11r_assoc; + params->mdid.mdie_present = roam_req->MDID.mdiePresent; + params->mdid.mobility_domain = roam_req->MDID.mobilityDomain; + params->assoc_ie_length = roam_req->assoc_ie.length; + qdf_mem_copy(params->assoc_ie, roam_req->assoc_ie.addIEdata, + roam_req->assoc_ie.length); + /*Configure roaming scan behavior (DBS/Non-DBS scan)*/ + if (roam_req->roaming_scan_policy) + scan_cmd_fp->scan_ctrl_flags_ext |= + WMI_SCAN_DBS_POLICY_FORCE_NONDBS; + else + scan_cmd_fp->scan_ctrl_flags_ext |= + WMI_SCAN_DBS_POLICY_DEFAULT; + + wma_roam_scan_fill_fils_params(wma_handle, params, roam_req); + } + + WMA_LOGD(FL("qos_caps: %d, qos_enabled: %d, ho_delay_for_rx: %d, roam_scan_mode: %d"), + params->roam_offload_params.qos_caps, + params->roam_offload_params.qos_enabled, + params->roam_offload_params.ho_delay_for_rx, params->mode); + + WMA_LOGD(FL("min_delay_btw_roam_scans:%d, roam_tri_reason_bitmask:%d"), + params->min_delay_btw_roam_scans, + params->roam_trigger_reason_bitmask); + + WMA_LOGD(FL("roam_preauth_retry_count: %d, roam_preauth_no_ack_timeout: %d"), + params->roam_offload_params.roam_preauth_retry_count, + params->roam_offload_params.roam_preauth_no_ack_timeout); + + status = wmi_unified_roam_scan_offload_mode_cmd(wma_handle->wmi_handle, + scan_cmd_fp, params); + qdf_mem_zero(params, sizeof(*params)); + qdf_mem_free(params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("%s: WMA --> WMI_ROAM_SCAN_MODE", __func__); + return status; +} + +/** + * wma_roam_scan_offload_rssi_threshold() - set scan offload rssi threashold + * @wma_handle: wma handle + * @roam_req: Roaming request buffer + * + * Send WMI_ROAM_SCAN_RSSI_THRESHOLD TLV to firmware + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + struct roam_offload_scan_rssi_params params = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int rssi_thresh, rssi_thresh_diff; + struct roam_ext_params *roam_params; + int32_t good_rssi_threshold; + uint32_t hirssi_scan_max_count; + uint32_t hirssi_scan_delta; + int32_t hirssi_upper_bound; + + /* Send rssi threshold */ + roam_params = &roam_req->roam_params; + rssi_thresh = roam_req->LookupThreshold - WMA_NOISE_FLOOR_DBM_DEFAULT; + rssi_thresh_diff = roam_req->OpportunisticScanThresholdDiff; + hirssi_scan_max_count = roam_req->hi_rssi_scan_max_count; + hirssi_scan_delta = roam_req->hi_rssi_scan_rssi_delta; + hirssi_upper_bound = roam_req->hi_rssi_scan_rssi_ub - + WMA_NOISE_FLOOR_DBM_DEFAULT; + + /* fill in threshold values */ + params.session_id = roam_req->sessionId; + params.rssi_thresh = rssi_thresh & 0x000000ff; + params.rssi_thresh_diff = rssi_thresh_diff & 0x000000ff; + params.hi_rssi_scan_max_count = hirssi_scan_max_count; + params.hi_rssi_scan_rssi_delta = hirssi_scan_delta; + params.hi_rssi_scan_rssi_ub = hirssi_upper_bound & 0x00000ff; + params.raise_rssi_thresh_5g = roam_params->raise_rssi_thresh_5g; + params.dense_rssi_thresh_offset = + roam_params->dense_rssi_thresh_offset; + params.dense_min_aps_cnt = roam_params->dense_min_aps_cnt; + params.traffic_threshold = + roam_params->traffic_threshold; + params.initial_dense_status = roam_params->initial_dense_status; + params.bg_scan_bad_rssi_thresh = roam_params->bg_scan_bad_rssi_thresh - + WMA_NOISE_FLOOR_DBM_DEFAULT; + params.bg_scan_client_bitmap = roam_params->bg_scan_client_bitmap; + params.roam_bad_rssi_thresh_offset_2g = + roam_params->roam_bad_rssi_thresh_offset_2g; + if (params.roam_bad_rssi_thresh_offset_2g) + params.flags |= WMI_ROAM_BG_SCAN_FLAGS_2G_TO_5G_ONLY; + + /* + * 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 (roam_params->raise_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT) + params.penalty_threshold_5g = 0; + else + params.boost_threshold_5g = + (roam_params->raise_rssi_thresh_5g - + WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + if (roam_params->drop_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT) + params.penalty_threshold_5g = 0; + else + params.penalty_threshold_5g = + (roam_params->drop_rssi_thresh_5g - + WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + params.raise_factor_5g = roam_params->raise_factor_5g; + params.drop_factor_5g = roam_params->drop_factor_5g; + params.max_raise_rssi_5g = roam_params->max_raise_rssi_5g; + params.max_drop_rssi_5g = roam_params->max_drop_rssi_5g; + + if (roam_params->good_rssi_roam) + good_rssi_threshold = WMA_NOISE_FLOOR_DBM_DEFAULT; + else + good_rssi_threshold = 0; + params.good_rssi_threshold = + (good_rssi_threshold - WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + + WMA_LOGD("WMA --> good_rssi_threshold=%d", + params.good_rssi_threshold); + + if (roam_req->early_stop_scan_enable) { + params.roam_earlystop_thres_min = + roam_req->early_stop_scan_min_threshold - + WMA_NOISE_FLOOR_DBM_DEFAULT; + params.roam_earlystop_thres_max = + roam_req->early_stop_scan_max_threshold - + WMA_NOISE_FLOOR_DBM_DEFAULT; + } else { + params.roam_earlystop_thres_min = 0; + params.roam_earlystop_thres_max = 0; + } + params.rssi_thresh_offset_5g = + roam_req->rssi_thresh_offset_5g; + + WMA_LOGD("early_stop_thresholds en=%d, min=%d, max=%d", + roam_req->early_stop_scan_enable, + params.roam_earlystop_thres_min, + params.roam_earlystop_thres_max); + WMA_LOGD("rssi_thresh_offset_5g = %d", params.rssi_thresh_offset_5g); + + status = wmi_unified_roam_scan_offload_rssi_thresh_cmd( + wma_handle->wmi_handle, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("roam_scan_offload_rssi_thresh_cmd failed %d", status); + return status; + } + + WMA_LOGD(FL("roam_scan_rssi_thresh=%d, roam_rssi_thresh_diff=%d"), + rssi_thresh, rssi_thresh_diff); + WMA_LOGD( + FL("hirssi_scan max_count=%d, delta=%d, hirssi_upper_bound=%d"), + hirssi_scan_max_count, hirssi_scan_delta, hirssi_upper_bound); + WMA_LOGD( + FL("dense_rssi_thresh_offset=%d, dense_min_aps_cnt=%d, traffic_threshold=%d initial_dense_status=%d"), + roam_params->dense_rssi_thresh_offset, + roam_params->dense_min_aps_cnt, + roam_params->traffic_threshold, + roam_params->initial_dense_status); + WMA_LOGD(FL("BG Scan Bad RSSI:%d, bitmap:0x%x Offset for 2G to 5G Roam:%d"), + roam_params->bg_scan_bad_rssi_thresh, + roam_params->bg_scan_client_bitmap, + roam_params->roam_bad_rssi_thresh_offset_2g); + return status; +} + +/** + * wma_roam_scan_offload_scan_period() - set roam offload scan period + * @wma_handle: wma handle + * @scan_period: scan period + * @scan_age: scan age + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_scan_period(tp_wma_handle wma_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id) +{ + return wmi_unified_roam_scan_offload_scan_period(wma_handle->wmi_handle, + scan_period, scan_age, vdev_id); +} + +/** + * wma_roam_scan_offload_rssi_change() - set roam offload RSSI change threshold + * @wma_handle: wma handle + * @rssi_change_thresh: RSSI Change threshold + * @bcn_rssi_weight: beacon RSSI weight + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD parameters to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_rssi_change(tp_wma_handle wma_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans) +{ + int status; + + status = wmi_unified_roam_scan_offload_rssi_change_cmd( + wma_handle->wmi_handle, + vdev_id, rssi_change_thresh, + bcn_rssi_weight, hirssi_delay_btw_scans); + if (status != EOK) + return QDF_STATUS_E_FAILURE; + + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_roam_scan_offload_chan_list() - set roam offload channel list + * @wma_handle: wma handle + * @chan_count: channel count + * @chan_list: channel list + * @list_type: list type + * @vdev_id: vdev id + * + * Set roam offload channel list. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_chan_list(tp_wma_handle wma_handle, + uint8_t chan_count, + uint8_t *chan_list, + uint8_t list_type, uint32_t vdev_id) +{ + QDF_STATUS status; + int i; + uint32_t *chan_list_mhz; + + if (chan_count == 0) { + WMA_LOGD("%s : invalid number of channels %d", __func__, + chan_count); + return QDF_STATUS_E_EMPTY; + } + chan_list_mhz = qdf_mem_malloc(chan_count * sizeof(*chan_list_mhz)); + if (chan_list_mhz == NULL) { + WMA_LOGE("%s : Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; ((i < chan_count) && + (i < SIR_ROAM_MAX_CHANNELS)); i++) { + chan_list_mhz[i] = cds_chan_to_freq(chan_list[i]); + WMA_LOGD("%d,", chan_list_mhz[i]); + } + + status = wmi_unified_roam_scan_offload_chan_list_cmd( + wma_handle->wmi_handle, + chan_count, chan_list_mhz, + list_type, vdev_id); + qdf_mem_free(chan_list_mhz); + + return status; +} + +/** + * e_csr_auth_type_to_rsn_authmode() - map csr auth type to rsn authmode + * @authtype: CSR authtype + * @encr: CSR Encryption + * + * Map CSR's authentication type into RSN auth mode used by firmware + * + * Return: WMI RSN auth mode + */ +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr) +{ + switch (authtype) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + return WMI_AUTH_OPEN; + case eCSR_AUTH_TYPE_WPA: + return WMI_AUTH_WPA; + case eCSR_AUTH_TYPE_WPA_PSK: + return WMI_AUTH_WPA_PSK; + case eCSR_AUTH_TYPE_RSN: + return WMI_AUTH_RSNA; + case eCSR_AUTH_TYPE_RSN_PSK: + return WMI_AUTH_RSNA_PSK; + case eCSR_AUTH_TYPE_FT_RSN: + return WMI_AUTH_FT_RSNA; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + return WMI_AUTH_FT_RSNA_PSK; +#ifdef FEATURE_WLAN_WAPI + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + return WMI_AUTH_WAPI; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + return WMI_AUTH_WAPI_PSK; +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: + return WMI_AUTH_CCKM_WPA; + case eCSR_AUTH_TYPE_CCKM_RSN: + return WMI_AUTH_CCKM_RSNA; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + return WMI_AUTH_RSNA_PSK_SHA256; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + return WMI_AUTH_RSNA_8021X_SHA256; +#endif /* WLAN_FEATURE_11W */ + case eCSR_AUTH_TYPE_NONE: + case eCSR_AUTH_TYPE_AUTOSWITCH: + /* In case of WEP and other keys, NONE means OPEN auth */ + if (encr == eCSR_ENCRYPT_TYPE_WEP40_STATICKEY || + encr == eCSR_ENCRYPT_TYPE_WEP104_STATICKEY || + encr == eCSR_ENCRYPT_TYPE_WEP40 || + encr == eCSR_ENCRYPT_TYPE_WEP104 || + encr == eCSR_ENCRYPT_TYPE_TKIP || + encr == eCSR_ENCRYPT_TYPE_AES || + encr == eCSR_ENCRYPT_TYPE_AES_GCMP || + encr == eCSR_ENCRYPT_TYPE_AES_GCMP_256) { + return WMI_AUTH_OPEN; + } + return WMI_AUTH_NONE; + case eCSR_AUTH_TYPE_FILS_SHA256: + return WMI_AUTH_RSNA_FILS_SHA256; + case eCSR_AUTH_TYPE_FILS_SHA384: + return WMI_AUTH_RSNA_FILS_SHA384; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA256: + return WMI_AUTH_RSNA_SUITE_B_8021X_SHA256; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA384: + return WMI_AUTH_RSNA_SUITE_B_8021X_SHA384; + default: + return WMI_AUTH_NONE; + } +} + +/** + * e_csr_encryption_type_to_rsn_cipherset() - map csr enc type to ESN cipher + * @encr: CSR Encryption + * + * Map CSR's encryption type into RSN cipher types used by firmware + * + * Return: WMI RSN cipher + */ +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr) +{ + + switch (encr) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + return WMI_CIPHER_WEP; + case eCSR_ENCRYPT_TYPE_TKIP: + return WMI_CIPHER_TKIP; + case eCSR_ENCRYPT_TYPE_AES: + return WMI_CIPHER_AES_CCM; + /* FWR will use key length to distinguish GCMP 128 or 256 */ + case eCSR_ENCRYPT_TYPE_AES_GCMP: + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + return WMI_CIPHER_AES_GCM; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + return WMI_CIPHER_WAPI; +#endif /* FEATURE_WLAN_WAPI */ + case eCSR_ENCRYPT_TYPE_ANY: + return WMI_CIPHER_ANY; + case eCSR_ENCRYPT_TYPE_NONE: + default: + return WMI_CIPHER_NONE; + } +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_roam_scan_get_cckm_mode() - Get the CCKM auth mode + * @roam_req: Roaming request buffer + * @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 wma_roam_scan_get_cckm_mode(tSirRoamOffloadScanReq *roam_req, + uint32_t auth_mode) +{ + if (roam_req->RoamOffloadEnabled) + return auth_mode; + else + return WMI_AUTH_CCKM; + +} +#endif +/** + * wma_roam_scan_fill_ap_profile() - fill ap_profile + * @roam_req: roam offload scan request + * @profile: ap profile + * + * Fill ap_profile structure from configured parameters + * + * Return: none + */ +static void wma_roam_scan_fill_ap_profile(tSirRoamOffloadScanReq *roam_req, + struct ap_profile *profile) +{ + uint32_t rsn_authmode; + + qdf_mem_zero(profile, sizeof(*profile)); + if (roam_req == NULL) { + profile->ssid.length = 0; + profile->ssid.mac_ssid[0] = 0; + profile->rsn_authmode = WMI_AUTH_NONE; + profile->rsn_ucastcipherset = WMI_CIPHER_NONE; + profile->rsn_mcastcipherset = WMI_CIPHER_NONE; + profile->rsn_mcastmgmtcipherset = WMI_CIPHER_NONE; + profile->rssi_threshold = WMA_ROAM_RSSI_DIFF_DEFAULT; + } else { + profile->ssid.length = + roam_req->ConnectedNetwork.ssId.length; + qdf_mem_copy(profile->ssid.mac_ssid, + roam_req->ConnectedNetwork.ssId.ssId, + profile->ssid.length); + profile->rsn_authmode = + e_csr_auth_type_to_rsn_authmode( + roam_req->ConnectedNetwork.authentication, + roam_req->ConnectedNetwork.encryption); + rsn_authmode = profile->rsn_authmode; + + if ((rsn_authmode == WMI_AUTH_CCKM_WPA) || + (rsn_authmode == WMI_AUTH_CCKM_RSNA)) + profile->rsn_authmode = + wma_roam_scan_get_cckm_mode( + roam_req, rsn_authmode); + profile->rsn_ucastcipherset = + e_csr_encryption_type_to_rsn_cipherset( + roam_req->ConnectedNetwork.encryption); + profile->rsn_mcastcipherset = + e_csr_encryption_type_to_rsn_cipherset( + roam_req->ConnectedNetwork.mcencryption); + profile->rsn_mcastmgmtcipherset = + profile->rsn_mcastcipherset; + profile->rssi_threshold = roam_req->RoamRssiDiff; + if (roam_req->rssi_abs_thresh) + profile->rssi_abs_thresh = + roam_req->rssi_abs_thresh - + WMA_NOISE_FLOOR_DBM_DEFAULT; +#ifdef WLAN_FEATURE_11W + if (roam_req->ConnectedNetwork.mfp_enabled) + profile->flags |= WMI_AP_PROFILE_FLAG_PMF; +#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) +{ + int ret; + 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) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + 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_LOGD("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); + } + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_HT_CAP_IE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + 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) +{ + int ret; + 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) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + 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_LOGD("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); + } + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_VHT_CAP_IE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } +} + +/** + * wma_roam_scan_scan_params() - fill roam scan params + * @wma_handle: wma handle + * @pMac: Mac ptr + * @scan_params: scan parameters + * @roam_req: NULL if this routine is called before connect + * It will be non-NULL if called after assoc. + * + * Fill scan_params structure from configured parameters + * + * Return: none + */ +void wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_start_scan_cmd_fixed_param * + scan_params) +{ + uint8_t channels_per_burst = 0; + uint32_t val = 0; + + if (NULL == pMac) { + WMA_LOGE("%s: pMac is NULL", __func__); + return; + } + + qdf_mem_zero(scan_params, sizeof(wmi_start_scan_cmd_fixed_param)); + scan_params->scan_ctrl_flags = WMI_SCAN_ADD_CCK_RATES | + WMI_SCAN_ADD_OFDM_RATES | + WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ; + if (roam_req != NULL) { + /* Parameters updated after association is complete */ + WMA_LOGD("%s: NeighborScanChannelMinTime: %d NeighborScanChannelMaxTime: %d", + __func__, + roam_req->NeighborScanChannelMinTime, + roam_req->NeighborScanChannelMaxTime); + WMA_LOGD("%s: NeighborScanTimerPeriod: %d " + "neighbor_scan_min_timer_period %d " + "HomeAwayTime: %d nProbes: %d", + __func__, + roam_req->NeighborScanTimerPeriod, + roam_req->neighbor_scan_min_timer_period, + roam_req->HomeAwayTime, roam_req->nProbes); + + /* + * roam_req->NeighborScanChannelMaxTime = SCAN_CHANNEL_TIME + * roam_req->HomeAwayTime = SCAN_HOME_AWAY_TIME + * roam_req->NeighborScanTimerPeriod = SCAN_HOME_TIME + * + * scan_params->dwell_time_active :time station stays on channel + * and sends probes; + * scan_params->dwell_time_passive:time station stays on channel + * and listens probes; + * scan_params->burst_duration :time station goes off channel + * to scan; + */ + + if (wlan_cfg_get_int + (pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + &val) != QDF_STATUS_SUCCESS) { + /* + * Could not get max channel value from CFG. Log error. + */ + WMA_LOGE("could not retrieve passive max channel value"); + + /* use a default value of 110ms */ + val = WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT; + } + + scan_params->dwell_time_passive = val; + /* + * 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 = + roam_req->NeighborScanChannelMaxTime; + if (roam_req->HomeAwayTime < + 2 * WMA_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_req->HomeAwayTime - + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME) + / (scan_params->dwell_time_active + + WMA_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_req->HomeAwayTime - + 2 * WMA_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; + } + } + if (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL + && roam_req->HomeAwayTime > 0 + && roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) { + /* 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. + */ + scan_params->burst_duration = + QDF_MAX(scan_params->burst_duration, + scan_params->dwell_time_passive); + } + scan_params->min_rest_time = + roam_req->neighbor_scan_min_timer_period; + scan_params->max_rest_time = roam_req->NeighborScanTimerPeriod; + scan_params->repeat_probe_time = (roam_req->nProbes > 0) ? + QDF_MAX(scan_params->dwell_time_active / + roam_req->nProbes, 1) : 0; + scan_params->probe_spacing_time = 0; + scan_params->probe_delay = 0; + /* 30 seconds for full scan cycle */ + scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + scan_params->idle_time = scan_params->min_rest_time; + scan_params->n_probes = roam_req->nProbes; + if (roam_req->allowDFSChannelRoam == + SIR_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 (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE && + roam_req->ChannelCacheType == CHANNEL_LIST_STATIC && + roam_req->ConnectedNetwork.ChannelCount > 0) { + scan_params->scan_ctrl_flags |= + WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS; + } + } + WMI_SCAN_SET_DWELL_MODE(scan_params->scan_ctrl_flags, + roam_req->roamscan_adaptive_dwell_mode); + + } else { + /* roam_req = NULL during initial or pre-assoc invocation */ + scan_params->dwell_time_active = + WMA_ROAM_DWELL_TIME_ACTIVE_DEFAULT; + scan_params->dwell_time_passive = + WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT; + scan_params->min_rest_time = WMA_ROAM_MIN_REST_TIME_DEFAULT; + scan_params->max_rest_time = WMA_ROAM_MAX_REST_TIME_DEFAULT; + scan_params->repeat_probe_time = 0; + scan_params->probe_spacing_time = 0; + scan_params->probe_delay = 0; + scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + scan_params->idle_time = scan_params->min_rest_time; + scan_params->burst_duration = 0; + scan_params->n_probes = 0; + } + + WMA_LOGD("%s: Rome roam scan parameters: dwell_time_active = %d, dwell_time_passive = %d", + __func__, scan_params->dwell_time_active, + scan_params->dwell_time_passive); + WMA_LOGD("%s: min_rest_time = %d, max_rest_time = %d, repeat_probe_time = %d n_probes = %d", + __func__, scan_params->min_rest_time, + scan_params->max_rest_time, + scan_params->repeat_probe_time, scan_params->n_probes); + WMA_LOGD("%s: max_scan_time = %d, idle_time = %d, burst_duration = %d, scan_ctrl_flags = 0x%x", + __func__, scan_params->max_scan_time, scan_params->idle_time, + scan_params->burst_duration, scan_params->scan_ctrl_flags); +} + +/** + * wma_roam_scan_offload_ap_profile() - set roam ap profile in fw + * @wma_handle: wma handle + * @mac_ctx: Mac ptr + * @roam_req: Request which contains the ap profile + * + * Send WMI_ROAM_AP_PROFILE to firmware + * + * Return: QDF status + */ +static QDF_STATUS wma_roam_scan_offload_ap_profile(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + struct ap_profile_params ap_profile; + + ap_profile.vdev_id = roam_req->sessionId; + wma_roam_scan_fill_ap_profile(roam_req, &ap_profile.profile); + ap_profile.param = roam_req->score_params; + return wmi_unified_send_roam_scan_offload_ap_cmd(wma_handle->wmi_handle, + &ap_profile); +} + +/** + * wma_roam_scan_filter() - Filter to be applied while roaming + * @wma_handle: Global WMA Handle + * @roam_req: Request which contains the filters + * + * There are filters such as whitelist, blacklist 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 wma_roam_scan_filter(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + int i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t num_bssid_black_list = 0, num_ssid_white_list = 0, + num_bssid_preferred_list = 0, num_rssi_rejection_ap = 0; + uint32_t op_bitmap = 0; + struct roam_ext_params *roam_params; + struct roam_scan_filter_params *params; + struct lca_disallow_config_params *lca_config_params; + + params = qdf_mem_malloc(sizeof(struct roam_scan_filter_params)); + if (params == NULL) { + WMA_LOGE("%s : Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + roam_params = &roam_req->roam_params; + lca_config_params = &roam_req->lca_config_params; + if (roam_req->Command != ROAM_SCAN_OFFLOAD_STOP) { + switch (roam_req->reason) { + case REASON_ROAM_SET_BLACKLIST_BSSID: + op_bitmap |= 0x1; + num_bssid_black_list = + roam_params->num_bssid_avoid_list; + break; + case REASON_ROAM_SET_SSID_ALLOWED: + op_bitmap |= 0x2; + num_ssid_white_list = + roam_params->num_ssid_allowed_list; + break; + case REASON_ROAM_SET_FAVORED_BSSID: + op_bitmap |= 0x4; + num_bssid_preferred_list = + roam_params->num_bssid_favored; + break; + case REASON_CTX_INIT: + if (roam_req->Command == ROAM_SCAN_OFFLOAD_START) { + params->lca_disallow_config_present = true; + op_bitmap |= + ROAM_FILTER_OP_BITMAP_LCA_DISALLOW | + ROAM_FILTER_OP_BITMAP_RSSI_REJECTION_OCE; + num_rssi_rejection_ap = + roam_params->num_rssi_rejection_ap; + } else { + WMA_LOGD("%s : Roam Filter need not be sent", __func__); + qdf_mem_free(params); + return QDF_STATUS_SUCCESS; + } + break; + default: + WMA_LOGD("%s : Roam Filter need not be sent", __func__); + qdf_mem_free(params); + return QDF_STATUS_SUCCESS; + } + } else { + /* In case of STOP command, reset all the variables + * except for blacklist BSSID which should be retained + * across connections. + */ + op_bitmap = 0x2 | 0x4; + num_ssid_white_list = roam_params->num_ssid_allowed_list; + num_bssid_preferred_list = roam_params->num_bssid_favored; + } + + /* fill in fixed values */ + params->session_id = roam_req->sessionId; + params->op_bitmap = op_bitmap; + params->num_bssid_black_list = num_bssid_black_list; + params->num_ssid_white_list = num_ssid_white_list; + params->num_bssid_preferred_list = num_bssid_preferred_list; + params->num_rssi_rejection_ap = num_rssi_rejection_ap; + qdf_mem_copy(params->bssid_avoid_list, roam_params->bssid_avoid_list, + MAX_BSSID_AVOID_LIST * sizeof(struct qdf_mac_addr)); + + for (i = 0; i < num_ssid_white_list; i++) { + qdf_mem_copy(params->ssid_allowed_list[i].mac_ssid, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + params->ssid_allowed_list[i].length = + roam_params->ssid_allowed_list[i].length; + WMA_LOGD("%s: SSID length=%d", __func__, + params->ssid_allowed_list[i].length); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)params->ssid_allowed_list[i].mac_ssid, + params->ssid_allowed_list[i].length); + } + qdf_mem_copy(params->bssid_favored, roam_params->bssid_favored, + MAX_BSSID_FAVORED * sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params->bssid_favored_factor, + roam_params->bssid_favored_factor, MAX_BSSID_FAVORED); + qdf_mem_copy(params->rssi_rejection_ap, + roam_params->rssi_rejection_ap, + MAX_RSSI_AVOID_BSSID_LIST * + sizeof(struct rssi_disallow_bssid)); + + if (params->lca_disallow_config_present) { + params->disallow_duration + = lca_config_params->disallow_duration; + params->rssi_channel_penalization + = lca_config_params->rssi_channel_penalization; + params->num_disallowed_aps + = lca_config_params->num_disallowed_aps; + } + status = wmi_unified_roam_scan_filter_cmd(wma_handle->wmi_handle, + params); + + qdf_mem_free(params); + return status; +} + +/** + * 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; + + WMA_LOGD("%s: first_bcnt: %d, final_bcnt: %d", __func__, first_bcnt, + final_bcnt); + + status = wma_vdev_set_param(wma_handle->wmi_handle, + vdev_id, WMI_VDEV_PARAM_BMISS_FIRST_BCNT, + first_bcnt); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d", + status); + return status; + } + + status = wma_vdev_set_param(wma_handle->wmi_handle, + vdev_id, WMI_VDEV_PARAM_BMISS_FINAL_BCNT, + final_bcnt); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d", + status); + return status; + } + + return status; +} + +/** + * wma_roam_scan_offload_command() - set roam offload command + * @wma_handle: wma handle + * @command: command + * @vdev_id: vdev id + * + * This function set roam offload command to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_command(tp_wma_handle wma_handle, + uint32_t command, uint32_t vdev_id) +{ + return wmi_unified_roam_scan_offload_cmd(wma_handle->wmi_handle, + command, vdev_id); +} + +/** + * wma_roam_scan_btm_offload() - Send BTM offload config + * @wma_handle: wma handle + * @roam_req: roam request parameters + * + * This function is used to send BTM offload config to fw + * + * Return: QDF status + */ +static QDF_STATUS wma_roam_scan_btm_offload(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + struct wmi_btm_config *params; + QDF_STATUS status; + + params = qdf_mem_malloc(sizeof(struct wmi_btm_config)); + if (!params) { + WMA_LOGE("Memory alloc failed for btm params"); + return QDF_STATUS_E_FAILURE; + } + + params->vdev_id = roam_req->sessionId; + params->btm_offload_config = roam_req->btm_offload_config; + params->btm_solicited_timeout = roam_req->btm_solicited_timeout; + params->btm_max_attempt_cnt = roam_req->btm_max_attempt_cnt; + params->btm_sticky_time = roam_req->btm_sticky_time; + params->disassoc_timer_threshold = roam_req->disassoc_timer_threshold; + + WMA_LOGD("%s: Sending BTM offload to FW for vdev %u btm_offload_config %u", + __func__, params->vdev_id, params->btm_offload_config); + + status = wmi_unified_send_btm_config(wma_handle->wmi_handle, params); + qdf_mem_free(params); + + + return status; +} + +/** + * wma_send_roam_bss_load_config() - API to send load bss trigger + * related parameters to fw + * + * @handle: WMA handle + * @roam_req: bss load config parameters from csr to be sent to fw + * + * Return: None + */ +static +void wma_send_roam_bss_load_config(WMA_HANDLE handle, + struct wmi_bss_load_config *params) +{ + QDF_STATUS status; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("WMA is closed, cannot send bss load config"); + return; + } + + WMA_LOGD("%s: Sending bss load trigger parameters to fw vdev %u bss_load_threshold %u bss_load_sample_time:%u", + __func__, params->vdev_id, params->bss_load_threshold, + params->bss_load_sample_time); + + status = wmi_unified_send_bss_load_config(wma_handle->wmi_handle, + params); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("failed to send bss load trigger config command"); +} + +/** + * wma_send_offload_11k_params() - API to send 11k offload params to FW + * @handle: WMA handle + * @params: Pointer to 11k offload params + * + * Return: None + */ +static +QDF_STATUS wma_send_offload_11k_params(WMA_HANDLE handle, + struct wmi_11k_offload_params *params) +{ + QDF_STATUS status; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send 11k offload cmd", + __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_11k_neighbour_report_support)) { + WMA_LOGE(FL("FW doesn't support 11k offload")); + return QDF_STATUS_E_NOSUPPORT; + } + + /* + * If 11k enable command and ssid length is 0, drop it + */ + if (params->offload_11k_bitmask && + !params->neighbor_report_params.ssid.length) { + WMA_LOGD("%s: SSID Len 0", __func__); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_offload_11k_cmd(wma_handle->wmi_handle, params); + + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("failed to send 11k offload command"); + + return status; +} + +/** + * wma_process_roaming_config() - process roam request + * @wma_handle: wma handle + * @roam_req: roam request parameters + * + * Main routine to handle ROAM commands coming from CSR module. + * + * Return: QDF status + */ +QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + wmi_start_scan_cmd_fixed_param scan_params; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t mode = 0; + struct wma_txrx_node *intr = NULL; + struct wmi_bss_load_config *bss_load_cfg; + + if (NULL == pMac) { + WMA_LOGE("%s: pMac is NULL", __func__); + qdf_mem_zero(roam_req, sizeof(*roam_req)); + qdf_mem_free(roam_req); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_handle->interfaces[roam_req->sessionId].roam_offload_enabled) { + /* roam scan offload is not enabled in firmware. + * Cannot initialize it in the middle of connection. + */ + qdf_mem_zero(roam_req, sizeof(*roam_req)); + qdf_mem_free(roam_req); + return QDF_STATUS_E_PERM; + } + WMA_LOGD("%s: RSO Command:%d, reason:%d session ID %d en %d", __func__, + roam_req->Command, roam_req->reason, roam_req->sessionId, + roam_req->RoamScanOffloadEnabled); + wma_handle->interfaces[roam_req->sessionId].roaming_in_progress = false; + switch (roam_req->Command) { + case ROAM_SCAN_OFFLOAD_START: + intr = &wma_handle->interfaces[roam_req->sessionId]; + intr->delay_before_vdev_stop = roam_req->delay_before_vdev_stop; + /* + * Scan/Roam threshold parameters are translated from fields of + * tSirRoamOffloadScanReq to WMITLV values sent to Rome firmware + * some of these parameters are configurable in qcom_cfg.ini + */ + + /* First param is positive rssi value to trigger rssi based scan + * Opportunistic scan is started at 30dB > trigger rssi. + */ + wma_handle->suitable_ap_hb_failure = false; + + qdf_status = wma_roam_scan_offload_rssi_thresh(wma_handle, + roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + qdf_status = wma_roam_scan_bmiss_cnt(wma_handle, + roam_req->RoamBmissFirstBcnt, + roam_req->RoamBmissFinalBcnt, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + /* Opportunistic scan runs on a timer, value set by + * EmptyRefreshScanPeriod. Age out the entries after 3 such + * cycles. + */ + if (roam_req->EmptyRefreshScanPeriod > 0) { + qdf_status = + wma_roam_scan_offload_scan_period(wma_handle, + roam_req->EmptyRefreshScanPeriod, + roam_req->EmptyRefreshScanPeriod * 3, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + mode = WMI_ROAM_SCAN_MODE_PERIODIC; + /* Don't use rssi triggered roam scans if external app + * is in control of channel list. + */ + if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC || + roam_req->roam_force_rssi_trigger) + mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + + } else { + mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + } + + /* 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. + */ + qdf_status = wma_roam_scan_offload_rssi_change(wma_handle, + roam_req->sessionId, + roam_req->RoamRescanRssiDiff, + roam_req->RoamBeaconRssiWeight, + roam_req->hi_rssi_scan_delay); + + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + qdf_status = wma_roam_scan_offload_ap_profile(wma_handle, + roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + qdf_status = wma_roam_scan_offload_chan_list(wma_handle, + roam_req->ConnectedNetwork.ChannelCount, + &roam_req->ConnectedNetwork.ChannelCache[0], + roam_req->ChannelCacheType, + roam_req->sessionId); + if ((qdf_status != QDF_STATUS_SUCCESS) && + (qdf_status != QDF_STATUS_E_EMPTY)) + break; + + + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + qdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, mode, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_mawc_support)) { + qdf_status = + wma_roam_scan_mawc_params(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Sending roaming MAWC params failed"); + break; + } + } else { + WMA_LOGD("MAWC roaming not supported by firmware"); + } + qdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Sending start for roam scan filter failed"); + break; + } + + /* Send BTM config as disabled during RSO Stop */ + qdf_status = wma_roam_scan_btm_offload(wma_handle, + roam_req); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("Sending BTM config to fw failed"); + break; + } + + /* + * Send 11k offload enable and bss load trigger parameters + * to FW as part of RSO Start + */ + qdf_status = wma_send_offload_11k_params(wma_handle, + &roam_req->offload_11k_params); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("11k offload enable not sent, status %d", + qdf_status); + break; + } + + if (roam_req->bss_load_trig_enabled) { + bss_load_cfg = &roam_req->bss_load_config; + wma_send_roam_bss_load_config(wma_handle, bss_load_cfg); + } + break; + + case ROAM_SCAN_OFFLOAD_STOP: + /* + * 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 (wma_is_roam_synch_in_progress(wma_handle, + roam_req->sessionId) && + roam_req->reason == + REASON_ROAM_STOP_ALL) { + WMA_LOGD("Dont send RSO stop during roam sync"); + break; + } + + /* + * Send 11k offload disable command to FW as part of RSO Stop + */ + qdf_status = + wma_send_offload_11k_params(wma_handle, + &roam_req->offload_11k_params); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("11k offload disable not sent, status %d", + qdf_status); + break; + } + + /* Send BTM config as disabled during RSO Stop */ + qdf_status = wma_roam_scan_btm_offload(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("Sending BTM config to fw failed")); + break; + } + + wma_handle->suitable_ap_hb_failure = false; + + wma_roam_scan_fill_scan_params(wma_handle, pMac, + NULL, &scan_params); + + if (roam_req->reason == REASON_ROAM_STOP_ALL || + roam_req->reason == REASON_DISCONNECTED || + roam_req->reason == REASON_ROAM_SYNCH_FAILED) { + mode = WMI_ROAM_SCAN_MODE_NONE; + } else { + if (csr_roamIsRoamOffloadEnabled(pMac)) + mode = WMI_ROAM_SCAN_MODE_NONE | + WMI_ROAM_SCAN_MODE_ROAMOFFLOAD; + else + mode = WMI_ROAM_SCAN_MODE_NONE; + } + + qdf_status = wma_roam_scan_offload_mode( + wma_handle, + &scan_params, NULL, mode, + roam_req->sessionId); + /* + * After sending the roam scan mode because of a disconnect, + * clear the scan bitmap client as well by sending + * the following command + */ + wma_roam_scan_offload_rssi_thresh(wma_handle, roam_req); + /* + * 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 (!roam_req->middle_of_roaming) { + qdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("clear for roam scan filter failed"); + break; + } + } + + if (roam_req->reason == + REASON_OS_REQUESTED_ROAMING_NOW) { + struct scheduler_msg cds_msg = {0}; + tSirRoamOffloadScanRsp *scan_offload_rsp; + + scan_offload_rsp = + qdf_mem_malloc(sizeof(*scan_offload_rsp)); + if (!scan_offload_rsp) { + WMA_LOGE("%s: Alloc failed for scan_offload_rsp", + __func__); + qdf_mem_free(roam_req); + return QDF_STATUS_E_NOMEM; + } + cds_msg.type = eWNI_SME_ROAM_SCAN_OFFLOAD_RSP; + scan_offload_rsp->sessionId = roam_req->sessionId; + scan_offload_rsp->reason = roam_req->reason; + cds_msg.bodyptr = scan_offload_rsp; + /* + * Since REASSOC request is processed in + * Roam_Scan_Offload_Rsp post a dummy rsp msg back to + * SME with proper reason code. + */ + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + &cds_msg)) { + qdf_mem_free(scan_offload_rsp); + QDF_TRACE(QDF_MODULE_ID_WMA, + QDF_TRACE_LEVEL_INFO, + "%s: Failed to post Scan Offload Rsp to UMAC", + __func__); + } + } + break; + + case ROAM_SCAN_OFFLOAD_ABORT_SCAN: + /* If roam scan is running, stop that cycle. + * It will continue automatically on next trigger. + */ + qdf_status = wma_roam_scan_offload_command(wma_handle, + WMI_ROAM_SCAN_STOP_CMD, + roam_req->sessionId); + break; + + case ROAM_SCAN_OFFLOAD_RESTART: + /* 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 ((roam_req->reason == REASON_PREAUTH_FAILED_FOR_ALL) + && wma_handle->suitable_ap_hb_failure) { + WMA_LOGE("%s: Sending heartbeat failure after preauth failures", + __func__); + wma_beacon_miss_handler(wma_handle, + roam_req->sessionId, + wma_handle->suitable_ap_hb_failure_rssi); + wma_handle->suitable_ap_hb_failure = false; + } + break; + + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + wma_handle->suitable_ap_hb_failure = false; + + if (roam_req->RoamScanOffloadEnabled) { + wma_roam_scan_fill_scan_params(wma_handle, pMac, + roam_req, &scan_params); + qdf_status = + wma_roam_scan_offload_mode( + wma_handle, &scan_params, roam_req, + WMI_ROAM_SCAN_MODE_NONE, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + } + + qdf_status = wma_roam_scan_bmiss_cnt(wma_handle, + roam_req->RoamBmissFirstBcnt, + roam_req->RoamBmissFinalBcnt, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + qdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Sending update for roam scan filter failed"); + break; + } + + + /* + * Runtime (after association) changes to rssi thresholds and + * other parameters. + */ + qdf_status = wma_roam_scan_offload_chan_list(wma_handle, + roam_req->ConnectedNetwork.ChannelCount, + &roam_req->ConnectedNetwork.ChannelCache[0], + roam_req->ChannelCacheType, + roam_req->sessionId); + /* + * Even though the channel list is empty, we can + * still go ahead and start Roaming. + */ + if ((qdf_status != QDF_STATUS_SUCCESS) && + (qdf_status != QDF_STATUS_E_EMPTY)) + break; + + + qdf_status = wma_roam_scan_offload_rssi_thresh(wma_handle, + roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + if (roam_req->EmptyRefreshScanPeriod > 0) { + qdf_status = wma_roam_scan_offload_scan_period( + wma_handle, + roam_req->EmptyRefreshScanPeriod, + roam_req->EmptyRefreshScanPeriod * 3, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + mode = WMI_ROAM_SCAN_MODE_PERIODIC; + /* Don't use rssi triggered roam scans if external app + * is in control of channel list. + */ + if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC || + roam_req->roam_force_rssi_trigger) + mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + + } else { + mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + } + + qdf_status = wma_roam_scan_offload_rssi_change(wma_handle, + roam_req->sessionId, + roam_req->RoamRescanRssiDiff, + roam_req->RoamBeaconRssiWeight, + roam_req->hi_rssi_scan_delay); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + qdf_status = wma_roam_scan_offload_ap_profile(wma_handle, + roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + if (!roam_req->RoamScanOffloadEnabled) + break; + + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + qdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, mode, + roam_req->sessionId); + + break; + + default: + break; + } + qdf_mem_zero(roam_req, sizeof(*roam_req)); + qdf_mem_free(roam_req); + return qdf_status; +} + +void wma_update_per_roam_config(WMA_HANDLE handle, + struct wmi_per_roam_config_req *req_buf) +{ + int status; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + + status = wmi_unified_set_per_roam_config(wma_handle->wmi_handle, + req_buf); + if (status != EOK) + WMA_LOGE("%s: failed to set per roam config to FW", + __func__); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + +/** + * wma_process_roam_invoke() - send roam invoke command to fw. + * @handle: wma handle + * @roaminvoke: roam invoke command + * + * Send roam invoke command to fw for fastreassoc. + * + * Return: none + */ +void wma_process_roam_invoke(WMA_HANDLE handle, + struct wma_roam_invoke_cmd *roaminvoke) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint32_t ch_hz; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not send roam invoke", + __func__); + goto free_frame_buf; + } + ch_hz = (A_UINT32)cds_chan_to_freq(roaminvoke->channel); + wmi_unified_roam_invoke_cmd(wma_handle->wmi_handle, + (struct wmi_roam_invoke_cmd *)roaminvoke, + ch_hz); +free_frame_buf: + if (roaminvoke->frame_len) { + qdf_mem_free(roaminvoke->frame_buf); + roaminvoke->frame_buf = NULL; + } +} + +/** + * wma_process_roam_synch_fail() -roam synch failure handle + * @handle: wma handle + * @synch_fail: roam synch fail parameters + * + * Return: none + */ +void wma_process_roam_synch_fail(WMA_HANDLE handle, + struct roam_offload_synch_fail *synch_fail) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not clean-up roam synch", + __func__); + return; + } + wlan_roam_debug_log(synch_fail->session_id, + DEBUG_ROAM_SYNCH_FAIL, + DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); + + /* Hand Off Failure could happen as an exception, when a roam synch + * indication is posted to Host, but a roam synch complete is not + * posted to the firmware.So, clear the roam synch in progress + * flag before disconnecting the session through this event. + */ + wma_handle->interfaces[synch_fail->session_id].roam_synch_in_progress = + false; +} + +/** + * wma_free_roam_synch_frame_ind() - Free the bcn_probe_rsp, reassoc_req, + * reassoc_rsp received as part of the ROAM_SYNC_FRAME event + * + * @iface - interaface corresponding to a vdev + * + * This API is used to free the buffer allocated during the ROAM_SYNC_FRAME + * event + * + */ +static void wma_free_roam_synch_frame_ind(struct wma_txrx_node *iface) +{ + if (iface->roam_synch_frame_ind.bcn_probe_rsp) { + qdf_mem_free(iface->roam_synch_frame_ind.bcn_probe_rsp); + iface->roam_synch_frame_ind.bcn_probe_rsp_len = 0; + iface->roam_synch_frame_ind.bcn_probe_rsp = NULL; + } + if (iface->roam_synch_frame_ind.reassoc_req) { + qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req); + iface->roam_synch_frame_ind.reassoc_req_len = 0; + iface->roam_synch_frame_ind.reassoc_req = NULL; + } + if (iface->roam_synch_frame_ind.reassoc_rsp) { + qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp); + iface->roam_synch_frame_ind.reassoc_rsp_len = 0; + iface->roam_synch_frame_ind.reassoc_rsp = NULL; + } +} + +/** + * wma_fill_data_synch_frame_event() - Fill the the roam sync data buffer using + * synch frame event data + * @wma: Global WMA Handle + * @roam_synch_ind_ptr: 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 wma_fill_data_synch_frame_event(tp_wma_handle wma, + roam_offload_synch_ind *roam_synch_ind_ptr, + struct wma_txrx_node *iface) +{ + uint8_t *bcn_probersp_ptr; + uint8_t *reassoc_rsp_ptr; + uint8_t *reassoc_req_ptr; + + /* Beacon/Probe Rsp data */ + roam_synch_ind_ptr->beaconProbeRespOffset = + sizeof(roam_offload_synch_ind); + bcn_probersp_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->beaconProbeRespOffset; + roam_synch_ind_ptr->beaconProbeRespLength = + iface->roam_synch_frame_ind.bcn_probe_rsp_len; + qdf_mem_copy(bcn_probersp_ptr, + iface->roam_synch_frame_ind.bcn_probe_rsp, + roam_synch_ind_ptr->beaconProbeRespLength); + qdf_mem_free(iface->roam_synch_frame_ind.bcn_probe_rsp); + iface->roam_synch_frame_ind.bcn_probe_rsp = NULL; + + /* ReAssoc Rsp data */ + roam_synch_ind_ptr->reassocRespOffset = + sizeof(roam_offload_synch_ind) + + roam_synch_ind_ptr->beaconProbeRespLength; + roam_synch_ind_ptr->reassocRespLength = + iface->roam_synch_frame_ind.reassoc_rsp_len; + reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->reassocRespOffset; + qdf_mem_copy(reassoc_rsp_ptr, + iface->roam_synch_frame_ind.reassoc_rsp, + roam_synch_ind_ptr->reassocRespLength); + qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp); + iface->roam_synch_frame_ind.reassoc_rsp = NULL; + + /* ReAssoc Req data */ + roam_synch_ind_ptr->reassoc_req_offset = + sizeof(roam_offload_synch_ind) + + roam_synch_ind_ptr->beaconProbeRespLength + + roam_synch_ind_ptr->reassocRespLength; + roam_synch_ind_ptr->reassoc_req_length = + iface->roam_synch_frame_ind.reassoc_req_len; + reassoc_req_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->reassoc_req_offset; + qdf_mem_copy(reassoc_req_ptr, + iface->roam_synch_frame_ind.reassoc_req, + roam_synch_ind_ptr->reassoc_req_length); + qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req); + iface->roam_synch_frame_ind.reassoc_req = NULL; +} + +/** + * wma_fill_data_synch_event() - Fill the the roam sync data buffer using synch + * event data + * @wma: Global WMA Handle + * @roam_synch_ind_ptr: 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 wma_fill_data_synch_event(tp_wma_handle wma, + roam_offload_synch_ind *roam_synch_ind_ptr, + 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_synch_ind_ptr->beaconProbeRespOffset = + sizeof(roam_offload_synch_ind); + bcn_probersp_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->beaconProbeRespOffset; + roam_synch_ind_ptr->beaconProbeRespLength = + synch_event->bcn_probe_rsp_len; + qdf_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame, + roam_synch_ind_ptr->beaconProbeRespLength); + /* ReAssoc Rsp data */ + roam_synch_ind_ptr->reassocRespOffset = + sizeof(roam_offload_synch_ind) + + roam_synch_ind_ptr->beaconProbeRespLength; + roam_synch_ind_ptr->reassocRespLength = synch_event->reassoc_rsp_len; + reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->reassocRespOffset; + qdf_mem_copy(reassoc_rsp_ptr, + param_buf->reassoc_rsp_frame, + roam_synch_ind_ptr->reassocRespLength); + + /* ReAssoc Req data */ + roam_synch_ind_ptr->reassoc_req_offset = + sizeof(roam_offload_synch_ind) + + roam_synch_ind_ptr->beaconProbeRespLength + + roam_synch_ind_ptr->reassocRespLength; + roam_synch_ind_ptr->reassoc_req_length = synch_event->reassoc_req_len; + reassoc_req_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->reassoc_req_offset; + qdf_mem_copy(reassoc_req_ptr, param_buf->reassoc_req_frame, + roam_synch_ind_ptr->reassoc_req_length); +} + +/** + * wma_fill_roam_synch_buffer() - Fill the the roam sync buffer + * @wma: Global WMA Handle + * @roam_synch_ind_ptr: 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: Success or Failure + */ +static int wma_fill_roam_synch_buffer(tp_wma_handle wma, + roam_offload_synch_ind *roam_synch_ind_ptr, + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf) +{ + wmi_roam_synch_event_fixed_param *synch_event; + wmi_channel *chan; + wmi_key_material *key; + struct wma_txrx_node *iface = NULL; + wmi_roam_fils_synch_tlv_param *fils_info; + int status = -EINVAL; + + synch_event = param_buf->fixed_param; + roam_synch_ind_ptr->roamedVdevId = synch_event->vdev_id; + roam_synch_ind_ptr->authStatus = synch_event->auth_status; + roam_synch_ind_ptr->roamReason = synch_event->roam_reason; + roam_synch_ind_ptr->rssi = synch_event->rssi; + iface = &wma->interfaces[synch_event->vdev_id]; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid, + roam_synch_ind_ptr->bssid.bytes); + WMA_LOGD("%s: roamedVdevId %d authStatus %d roamReason %d rssi %d isBeacon %d", + __func__, roam_synch_ind_ptr->roamedVdevId, + roam_synch_ind_ptr->authStatus, roam_synch_ind_ptr->roamReason, + roam_synch_ind_ptr->rssi, roam_synch_ind_ptr->isBeacon); + + if (!QDF_IS_STATUS_SUCCESS( + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, NULL, SIR_ROAMING_DEREGISTER_STA))) { + WMA_LOGE("LFR3: CSR Roam synch cb failed"); + wma_free_roam_synch_frame_ind(iface); + return 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 (!iface->roam_synch_frame_ind.bcn_probe_rsp) { + WMA_LOGE("LFR3: bcn_probe_rsp is NULL"); + QDF_ASSERT(iface->roam_synch_frame_ind. + bcn_probe_rsp != NULL); + wma_free_roam_synch_frame_ind(iface); + return status; + } + if (!iface->roam_synch_frame_ind.reassoc_rsp) { + WMA_LOGE("LFR3: reassoc_rsp is NULL"); + QDF_ASSERT(iface->roam_synch_frame_ind. + reassoc_rsp != NULL); + wma_free_roam_synch_frame_ind(iface); + return status; + } + if (!iface->roam_synch_frame_ind.reassoc_req) { + WMA_LOGE("LFR3: reassoc_req is NULL"); + QDF_ASSERT(iface->roam_synch_frame_ind. + reassoc_req != NULL); + wma_free_roam_synch_frame_ind(iface); + return status; + } + wma_fill_data_synch_frame_event(wma, roam_synch_ind_ptr, iface); + } else { + wma_fill_data_synch_event(wma, roam_synch_ind_ptr, param_buf); + } + + chan = (wmi_channel *) param_buf->chan; + roam_synch_ind_ptr->chan_freq = chan->mhz; + key = (wmi_key_material *) param_buf->key; + if (key != NULL) { + qdf_mem_copy(roam_synch_ind_ptr->kck, key->kck, + SIR_KCK_KEY_LEN); + roam_synch_ind_ptr->kek_len = SIR_KEK_KEY_LEN; + qdf_mem_copy(roam_synch_ind_ptr->kek, key->kek, + SIR_KEK_KEY_LEN); + qdf_mem_copy(roam_synch_ind_ptr->replay_ctr, + key->replay_counter, SIR_REPLAY_CTR_LEN); + } + if (param_buf->hw_mode_transition_fixed_param) + wma_process_pdev_hw_mode_trans_ind(wma, + param_buf->hw_mode_transition_fixed_param, + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping, + &roam_synch_ind_ptr->hw_mode_trans_ind); + else + WMA_LOGD(FL("hw_mode transition fixed param is NULL")); + + fils_info = (wmi_roam_fils_synch_tlv_param *) + (param_buf->roam_fils_synch_info); + if (fils_info) { + if ((fils_info->kek_len > SIR_KEK_KEY_LEN_FILS) || + (fils_info->pmk_len > SIR_PMK_LEN)) { + WMA_LOGE("%s: Invalid kek_len %d or pmk_len %d", + __func__, + fils_info->kek_len, + fils_info->pmk_len); + wma_free_roam_synch_frame_ind(iface); + return status; + } + + roam_synch_ind_ptr->kek_len = fils_info->kek_len; + qdf_mem_copy(roam_synch_ind_ptr->kek, fils_info->kek, + fils_info->kek_len); + + roam_synch_ind_ptr->pmk_len = fils_info->pmk_len; + qdf_mem_copy(roam_synch_ind_ptr->pmk, fils_info->pmk, + fils_info->pmk_len); + + qdf_mem_copy(roam_synch_ind_ptr->pmkid, fils_info->pmkid, + SIR_PMKID_LEN); + + roam_synch_ind_ptr->update_erp_next_seq_num = + fils_info->update_erp_next_seq_num; + roam_synch_ind_ptr->next_erp_seq_num = + fils_info->next_erp_seq_num; + + WMA_LOGD("Update ERP Seq Num %d, Next ERP Seq Num %d", + roam_synch_ind_ptr->update_erp_next_seq_num, + roam_synch_ind_ptr->next_erp_seq_num); + } + wma_free_roam_synch_frame_ind(iface); + return 0; +} + +static void wma_update_roamed_peer_unicast_cipher(tp_wma_handle wma, + uint32_t uc_cipher, + uint8_t *peer_mac) +{ + struct wlan_objmgr_peer *peer; + + if (!peer_mac) { + WMA_LOGE("peer_mac is NULL"); + return; + } + + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + WMA_LOGE("Peer of peer_mac %pM not found", peer_mac); + return; + } + + wlan_peer_set_unicast_cipher(peer, uc_cipher); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +static uint32_t wma_get_peer_uc_cipher(tp_wma_handle wma, uint8_t *peer_mac) +{ + uint32_t uc_cipher; + struct wlan_objmgr_peer *peer; + + if (!peer_mac) { + WMA_LOGE("peer_mac is NULL"); + return 0; + } + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + WMA_LOGE("Peer of peer_mac %pM not found", peer_mac); + return 0; + } + + uc_cipher = wlan_peer_get_unicast_cipher(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + + return uc_cipher; +} +/** + * 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: None + */ +static void wma_roam_update_vdev(tp_wma_handle wma, + roam_offload_synch_ind *roam_synch_ind_ptr) +{ + tDeleteBssParams *del_bss_params; + tDeleteStaParams *del_sta_params; + tLinkStateParams *set_link_params; + tAddStaParams *add_sta_params; + uint32_t uc_cipher; + uint8_t vdev_id; + + vdev_id = roam_synch_ind_ptr->roamedVdevId; + wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss; + del_bss_params = qdf_mem_malloc(sizeof(*del_bss_params)); + if (!del_bss_params) + return; + + del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params)); + if (!del_sta_params) { + qdf_mem_free(del_bss_params); + return; + } + + set_link_params = qdf_mem_malloc(sizeof(*set_link_params)); + if (!set_link_params) { + qdf_mem_free(del_bss_params); + qdf_mem_free(del_sta_params); + return; + } + add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params)); + if (!add_sta_params) { + qdf_mem_free(del_bss_params); + qdf_mem_free(del_sta_params); + qdf_mem_free(set_link_params); + return; + } + + qdf_mem_zero(del_bss_params, sizeof(*del_bss_params)); + qdf_mem_zero(del_sta_params, sizeof(*del_sta_params)); + qdf_mem_zero(set_link_params, sizeof(*set_link_params)); + qdf_mem_zero(add_sta_params, sizeof(*add_sta_params)); + + del_bss_params->smesessionId = vdev_id; + del_sta_params->smesessionId = vdev_id; + qdf_mem_copy(del_bss_params->bssid, wma->interfaces[vdev_id].bssid, + IEEE80211_ADDR_LEN); + set_link_params->state = eSIR_LINK_PREASSOC_STATE; + qdf_mem_copy(set_link_params->selfMacAddr, + roam_synch_ind_ptr->self_mac.bytes, IEEE80211_ADDR_LEN); + qdf_mem_copy(set_link_params->bssid, roam_synch_ind_ptr->bssid.bytes, + IEEE80211_ADDR_LEN); + add_sta_params->staType = STA_ENTRY_SELF; + add_sta_params->smesessionId = vdev_id; + qdf_mem_copy(&add_sta_params->bssId, &roam_synch_ind_ptr->bssid.bytes, + IEEE80211_ADDR_LEN); + add_sta_params->staIdx = STA_INVALID_IDX; + add_sta_params->assocId = roam_synch_ind_ptr->aid; + + /* + * Get uc cipher of old peer to update new peer as it doesnt + * change in roaming + */ + uc_cipher = wma_get_peer_uc_cipher(wma, del_bss_params->bssid); + + wma_delete_sta(wma, del_sta_params); + wma_delete_bss(wma, del_bss_params); + wma_set_linkstate(wma, set_link_params); + /* Update new peer's uc cipher */ + wma_update_roamed_peer_unicast_cipher(wma, uc_cipher, + roam_synch_ind_ptr->bssid.bytes); + wma_add_bss(wma, (tpAddBssParams)roam_synch_ind_ptr->add_bss_params); + wma_add_sta(wma, add_sta_params); + wma_vdev_set_mlme_state(wma, vdev_id, WLAN_VDEV_S_RUN); + qdf_mem_copy(wma->interfaces[vdev_id].bssid, + roam_synch_ind_ptr->bssid.bytes, IEEE80211_ADDR_LEN); + qdf_mem_free(del_bss_params); + qdf_mem_free(set_link_params); + qdf_mem_free(add_sta_params); +} + +/** + * wma_roam_synch_event_handler() - roam synch event handler + * @handle: wma handle + * @event: event data + * @len: length of data + * + * This function is roam synch event handler. It sends roam + * indication for upper layer. + * + * Return: Success or Failure status + */ +int wma_roam_synch_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_synch_event_fixed_param *synch_event = NULL; + tp_wma_handle wma = (tp_wma_handle) handle; + roam_offload_synch_ind *roam_synch_ind_ptr = NULL; + tpSirBssDescription bss_desc_ptr = NULL; + uint16_t ie_len = 0; + uint8_t channel; + int status = -EINVAL; + tSirRoamOffloadScanReq *roam_req; + qdf_time_t roam_synch_received = qdf_get_system_timestamp(); + uint32_t roam_synch_data_len; + A_UINT32 bcn_probe_rsp_len; + A_UINT32 reassoc_rsp_len; + A_UINT32 reassoc_req_len; + + WMA_LOGD("LFR3:%s", __func__); + if (!event) { + WMA_LOGE("%s: event param null", __func__); + goto cleanup_label; + } + + param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + goto cleanup_label; + } + + synch_event = param_buf->fixed_param; + if (!synch_event) { + WMA_LOGE("%s: received null event data from target", __func__); + goto cleanup_label; + } + + if (synch_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, synch_event->vdev_id); + return status; + } + + /* + * This flag is set during ROAM_START and once this event is being + * executed which is a run to completion, no other event can interrupt + * this in MC thread context. So, it is OK to reset the flag here as + * soon as we receive this event. + */ + wma->interfaces[synch_event->vdev_id].roaming_in_progress = false; + + 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) { + WMA_LOGD("Invalid 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); + goto cleanup_label; + } + + wlan_roam_debug_log(synch_event->vdev_id, DEBUG_ROAM_SYNCH_IND, + DEBUG_INVALID_PEER_ID, NULL, NULL, + synch_event->bssid.mac_addr31to0, + synch_event->bssid.mac_addr47to32); + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + synch_event->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_EVENT, QDF_ROAM_SYNCH)); + + if (wma_is_roam_synch_in_progress(wma, synch_event->vdev_id)) { + WMA_LOGE("%s: Ignoring RSI since one is already in progress", + __func__); + goto cleanup_label; + } + WMA_LOGD("LFR3: Received WMA_ROAM_OFFLOAD_SYNCH_IND"); + + /* + * All below length fields are unsigned and hence positive numbers. + * Maximum number during the addition would be (3 * MAX_LIMIT(UINT32) + + * few fixed fields). + */ + WMA_LOGD("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 = wma->interfaces[synch_event->vdev_id]. + roam_synch_frame_ind. + bcn_probe_rsp_len; + reassoc_req_len = wma->interfaces[synch_event->vdev_id]. + roam_synch_frame_ind.reassoc_req_len; + reassoc_rsp_len = wma->interfaces[synch_event->vdev_id]. + roam_synch_frame_ind.reassoc_rsp_len; + + roam_synch_data_len = bcn_probe_rsp_len + reassoc_rsp_len + + reassoc_req_len + sizeof(roam_offload_synch_ind); + + WMA_LOGD("Updated synch payload: LEN bcn:%d, req:%d, rsp:%d", + 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; + + if (synch_event->bcn_probe_rsp_len > WMI_SVC_MSG_MAX_SIZE) + goto cleanup_label; + if (synch_event->reassoc_rsp_len > + (WMI_SVC_MSG_MAX_SIZE - synch_event->bcn_probe_rsp_len)) + goto cleanup_label; + if (synch_event->reassoc_req_len > + WMI_SVC_MSG_MAX_SIZE - (synch_event->bcn_probe_rsp_len + + synch_event->reassoc_rsp_len)) + goto cleanup_label; + + roam_synch_data_len = bcn_probe_rsp_len + + reassoc_rsp_len + reassoc_req_len; + + /* + * Below is the check for the entire size of the message + * received from the firmware. + */ + if (roam_synch_data_len > WMI_SVC_MSG_MAX_SIZE - + (sizeof(*synch_event) + sizeof(wmi_channel) + + sizeof(wmi_key_material) + sizeof(uint32_t))) + goto cleanup_label; + + roam_synch_data_len += sizeof(roam_offload_synch_ind); + } + + WMA_LOGD("synch payload: LEN bcn:%d, req:%d, rsp:%d", + bcn_probe_rsp_len, + reassoc_req_len, + reassoc_rsp_len); + + cds_host_diag_log_work(&wma->roam_ho_wl, + WMA_ROAM_HO_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_WOW); + qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl, + WMA_ROAM_HO_WAKE_LOCK_DURATION); + + wma->interfaces[synch_event->vdev_id].roam_synch_in_progress = true; + + roam_synch_ind_ptr = + (roam_offload_synch_ind *)qdf_mem_malloc(roam_synch_data_len); + if (!roam_synch_ind_ptr) { + WMA_LOGE("%s: failed to allocate memory for roam_synch_event", + __func__); + QDF_ASSERT(roam_synch_ind_ptr != NULL); + status = -ENOMEM; + goto cleanup_label; + } + qdf_mem_zero(roam_synch_ind_ptr, roam_synch_data_len); + status = wma_fill_roam_synch_buffer(wma, + roam_synch_ind_ptr, param_buf); + if (status != 0) + goto cleanup_label; + /* 24 byte MAC header and 12 byte to ssid IE */ + if (roam_synch_ind_ptr->beaconProbeRespLength > + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { + ie_len = roam_synch_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + } else { + WMA_LOGE("LFR3: Invalid Beacon Length"); + goto cleanup_label; + } + bss_desc_ptr = qdf_mem_malloc(sizeof(tSirBssDescription) + ie_len); + if (NULL == bss_desc_ptr) { + WMA_LOGE("LFR3: mem alloc failed!"); + QDF_ASSERT(bss_desc_ptr != NULL); + status = -ENOMEM; + goto cleanup_label; + } + qdf_mem_zero(bss_desc_ptr, sizeof(tSirBssDescription) + ie_len); + if (QDF_IS_STATUS_ERROR(wma->pe_roam_synch_cb( + (tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr, + SIR_ROAM_SYNCH_PROPAGATION))) { + WMA_LOGE("LFR3: PE roam synch cb failed"); + status = -EBUSY; + goto cleanup_label; + } + + wma_roam_update_vdev(wma, roam_synch_ind_ptr); + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr, SIR_ROAM_SYNCH_PROPAGATION); + wma_process_roam_synch_complete(wma, synch_event->vdev_id); + + /* update freq and channel width */ + wma->interfaces[synch_event->vdev_id].mhz = + roam_synch_ind_ptr->chan_freq; + if (roam_synch_ind_ptr->join_rsp) + wma->interfaces[synch_event->vdev_id].chan_width = + roam_synch_ind_ptr->join_rsp->vht_channel_width; + /* + * update phy_mode in wma to avoid mismatch in phymode between host and + * firmware. The phymode stored in interface[vdev_id].chanmode 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. + */ + channel = cds_freq_to_chan(wma->interfaces[synch_event->vdev_id].mhz); + wma_get_phy_mode_cb(channel, + wma->interfaces[synch_event->vdev_id].chan_width, + &wma->interfaces[synch_event->vdev_id].chanmode); + + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr, SIR_ROAM_SYNCH_COMPLETE); + wma->interfaces[synch_event->vdev_id].roam_synch_delay = + qdf_get_system_timestamp() - roam_synch_received; + WMA_LOGD("LFR3: roam_synch_delay:%d", + wma->interfaces[synch_event->vdev_id].roam_synch_delay); + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr, SIR_ROAM_SYNCH_NAPI_OFF); + + status = 0; + +cleanup_label: + if (status != 0) { + if (roam_synch_ind_ptr) + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, NULL, SIR_ROAMING_ABORT); + roam_req = qdf_mem_malloc(sizeof(tSirRoamOffloadScanReq)); + if (roam_req && synch_event) { + roam_req->Command = ROAM_SCAN_OFFLOAD_STOP; + roam_req->reason = REASON_ROAM_SYNCH_FAILED; + roam_req->sessionId = synch_event->vdev_id; + wma_process_roaming_config(wma, roam_req); + } + } + if (roam_synch_ind_ptr && roam_synch_ind_ptr->join_rsp) + qdf_mem_free(roam_synch_ind_ptr->join_rsp); + if (roam_synch_ind_ptr) + qdf_mem_free(roam_synch_ind_ptr); + if (bss_desc_ptr) + qdf_mem_free(bss_desc_ptr); + if (wma && synch_event) + wma->interfaces[synch_event->vdev_id].roam_synch_in_progress = + false; + + return status; +} + +int wma_roam_synch_frame_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_synch_frame_event_fixed_param *synch_frame_event = NULL; + tp_wma_handle wma = (tp_wma_handle) handle; + A_UINT32 vdev_id; + struct wma_txrx_node *iface = NULL; + int status = -EINVAL; + + WMA_LOGD("LFR3:Synch Frame event"); + if (!event) { + WMA_LOGE("event param null"); + return status; + } + + param_buf = (WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("received null buf from target"); + return status; + } + + synch_frame_event = param_buf->fixed_param; + if (!synch_frame_event) { + WMA_LOGE("received null event data from target"); + return status; + } + + if (synch_frame_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("received invalid vdev_id %d", + synch_frame_event->vdev_id); + return status; + } + + if (synch_frame_event->bcn_probe_rsp_len > + param_buf->num_bcn_probe_rsp_frame || + synch_frame_event->reassoc_req_len > + param_buf->num_reassoc_req_frame || + synch_frame_event->reassoc_rsp_len > + param_buf->num_reassoc_rsp_frame) { + WMA_LOGE("fixed/actual len err: bcn:%d/%d req:%d/%d rsp:%d/%d", + synch_frame_event->bcn_probe_rsp_len, + param_buf->num_bcn_probe_rsp_frame, + synch_frame_event->reassoc_req_len, + param_buf->num_reassoc_req_frame, + synch_frame_event->reassoc_rsp_len, + param_buf->num_reassoc_rsp_frame); + return status; + } + + vdev_id = synch_frame_event->vdev_id; + iface = &wma->interfaces[vdev_id]; + + if (wma_is_roam_synch_in_progress(wma, vdev_id)) { + WMA_LOGE("Ignoring this event as it is unexpected"); + wma_free_roam_synch_frame_ind(iface); + return status; + } + WMA_LOGD("LFR3: Received ROAM_SYNCH_FRAME_EVENT"); + + WMA_LOGD("synch frame payload: LEN bcn:%d, req:%d, rsp:%d morefrag: %d", + synch_frame_event->bcn_probe_rsp_len, + synch_frame_event->reassoc_req_len, + synch_frame_event->reassoc_rsp_len, + synch_frame_event->more_frag); + + if (synch_frame_event->bcn_probe_rsp_len) { + iface->roam_synch_frame_ind.bcn_probe_rsp_len = + synch_frame_event->bcn_probe_rsp_len; + iface->roam_synch_frame_ind.is_beacon = + synch_frame_event->is_beacon; + + if (iface->roam_synch_frame_ind.bcn_probe_rsp) + qdf_mem_free(iface->roam_synch_frame_ind. + bcn_probe_rsp); + iface->roam_synch_frame_ind.bcn_probe_rsp = + qdf_mem_malloc(iface->roam_synch_frame_ind. + bcn_probe_rsp_len); + if (!iface->roam_synch_frame_ind.bcn_probe_rsp) { + WMA_LOGE("failed to allocate memory for bcn_probe_rsp"); + QDF_ASSERT(iface->roam_synch_frame_ind. + bcn_probe_rsp != NULL); + status = -ENOMEM; + wma_free_roam_synch_frame_ind(iface); + return status; + } + qdf_mem_copy(iface->roam_synch_frame_ind. + bcn_probe_rsp, + param_buf->bcn_probe_rsp_frame, + iface->roam_synch_frame_ind.bcn_probe_rsp_len); + } + + if (synch_frame_event->reassoc_req_len) { + iface->roam_synch_frame_ind.reassoc_req_len = + synch_frame_event->reassoc_req_len; + + if (iface->roam_synch_frame_ind.reassoc_req) + qdf_mem_free(iface->roam_synch_frame_ind.reassoc_req); + iface->roam_synch_frame_ind.reassoc_req = + qdf_mem_malloc(iface->roam_synch_frame_ind. + reassoc_req_len); + if (!iface->roam_synch_frame_ind.reassoc_req) { + WMA_LOGE("failed to allocate memory for reassoc_req"); + QDF_ASSERT(iface->roam_synch_frame_ind. + reassoc_req != NULL); + status = -ENOMEM; + wma_free_roam_synch_frame_ind(iface); + return status; + } + qdf_mem_copy(iface->roam_synch_frame_ind.reassoc_req, + param_buf->reassoc_req_frame, + iface->roam_synch_frame_ind.reassoc_req_len); + } + + if (synch_frame_event->reassoc_rsp_len) { + iface->roam_synch_frame_ind.reassoc_rsp_len = + synch_frame_event->reassoc_rsp_len; + + if (iface->roam_synch_frame_ind.reassoc_rsp) + qdf_mem_free(iface->roam_synch_frame_ind.reassoc_rsp); + + iface->roam_synch_frame_ind.reassoc_rsp = + qdf_mem_malloc(iface->roam_synch_frame_ind. + reassoc_rsp_len); + if (!iface->roam_synch_frame_ind.reassoc_rsp) { + WMA_LOGE("failed to allocate memory for reassoc_req"); + QDF_ASSERT(iface->roam_synch_frame_ind. + reassoc_rsp != NULL); + status = -ENOMEM; + wma_free_roam_synch_frame_ind(iface); + return status; + } + qdf_mem_copy(iface->roam_synch_frame_ind.reassoc_rsp, + param_buf->reassoc_rsp_frame, + iface->roam_synch_frame_ind.reassoc_rsp_len); + } + return 0; +} + +#define RSN_CAPS_SHIFT 16 +/** + * wma_roam_scan_fill_self_caps() - fill capabilities + * @wma_handle: wma handle + * @roam_offload_params: offload parameters + * @roam_req: roam request + * + * This function fills roam self capablities. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_fill_self_caps(tp_wma_handle wma_handle, + roam_offload_param * + roam_offload_params, + tSirRoamOffloadScanReq *roam_req) +{ + struct sAniSirGlobal *pMac = NULL; + tSirMacCapabilityInfo selfCaps; + uint32_t val = 0; + uint32_t nCfgValue; + uint16_t *pCfgValue16; + uint8_t nCfgValue8, *pCfgValue8; + tSirMacQosInfoStation macQosInfoSta; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + qdf_mem_zero(&macQosInfoSta, sizeof(tSirMacQosInfoStation)); + /* Roaming is done only for INFRA STA type. + * So, ess will be one and ibss will be Zero + */ + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_PRIVACY_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + selfCaps.ess = 1; + selfCaps.ibss = 0; + if (val) + selfCaps.privacy = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_SHORT_PREAMBLE"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.shortPreamble = 1; + + selfCaps.pbcc = 0; + selfCaps.channelAgility = 0; + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.shortSlotTime = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_11H_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_11H_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.spectrumMgt = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_QOS_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.qos = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_APSD_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_APSD_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.apsd = 1; + + selfCaps.rrm = pMac->rrm.rrmSmeContext.rrmConfig.rrm_enabled; + + if (wlan_cfg_get_int(pMac, WNI_CFG_BLOCK_ACK_ENABLED, &val) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_BLOCK_ACK_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + selfCaps.delayedBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + selfCaps.immediateBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + pCfgValue16 = (uint16_t *) &selfCaps; + + /* + * RSN caps arent been 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 this to firmware in the 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. + */ + roam_offload_params->capability = *((uint32_t *)(&roam_req->rsn_caps)); + roam_offload_params->capability <<= RSN_CAPS_SHIFT; + roam_offload_params->capability |= ((*pCfgValue16) & 0xFFFF); + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &nCfgValue) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_HT_CAP_INFO"); + return QDF_STATUS_E_FAILURE; + } + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + roam_offload_params->ht_caps_info = + uHTCapabilityInfo.nCfgValue16 & 0xFFFF; + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &nCfgValue) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_HT_AMPDU_PARAMS"); + return QDF_STATUS_E_FAILURE; + } + /* tSirMacHTParametersInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->ampdu_param = (nCfgValue8) & 0xFF; + + val = ROAM_OFFLOAD_NUM_MCS_SET; + if (wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + (uint8_t *) roam_offload_params->mcsset, + &val) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_SUPPORTED_MCS_SET"); + return QDF_STATUS_E_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_EXT_HT_CAP_INFO, &nCfgValue) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_EXT_HT_CAP_INFO"); + return QDF_STATUS_E_FAILURE; + } + /* uHTCapabilityInfo.extHtCapInfo */ + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + roam_offload_params->ht_ext_cap = + uHTCapabilityInfo.nCfgValue16 & 0xFFFF; + + if (wlan_cfg_get_int(pMac, WNI_CFG_TX_BF_CAP, &nCfgValue) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_TX_BF_CAP"); + return QDF_STATUS_E_FAILURE; + } + /* tSirMacTxBFCapabilityInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->ht_txbf = nCfgValue8 & 0xFF; + if (wlan_cfg_get_int(pMac, WNI_CFG_AS_CAP, &nCfgValue) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_AS_CAP"); + return QDF_STATUS_E_FAILURE; + } + /* tSirMacASCapabilityInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->asel_cap = nCfgValue8 & 0xFF; + + /* QOS Info */ + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &nCfgValue) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_MAX_SP_LENGTH"); + return QDF_STATUS_E_FAILURE; + } + nCfgValue8 = (uint8_t) nCfgValue; + macQosInfoSta.maxSpLen = nCfgValue8; + macQosInfoSta.moreDataAck = 0; + macQosInfoSta.qack = 0; + macQosInfoSta.acbe_uapsd = roam_req->AcUapsd.acbe_uapsd; + macQosInfoSta.acbk_uapsd = roam_req->AcUapsd.acbk_uapsd; + macQosInfoSta.acvi_uapsd = roam_req->AcUapsd.acvi_uapsd; + macQosInfoSta.acvo_uapsd = roam_req->AcUapsd.acvo_uapsd; + pCfgValue8 = (uint8_t *) &macQosInfoSta; + /* macQosInfoSta Only queue_request is set.Refer to + * populate_dot11f_wmm_caps for more details + */ + roam_offload_params->qos_caps = (*pCfgValue8) & 0xFF; + if (roam_offload_params->qos_caps) + roam_offload_params->qos_enabled = true; + roam_offload_params->wmm_caps = 0x4 & 0xFF; + return QDF_STATUS_SUCCESS; +} + +/** + * 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_LOGE("%s: wma handle is NULL", __func__); + return; + } + + wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * 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; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + if (!mac->sme.rssi_threshold_breached_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid rssi breached event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + + rssi.request_id = event->request_id; + rssi.session_id = event->vdev_id; + rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes); + + WMA_LOGD("%s: req_id: %u vdev_id: %d curr_rssi: %d", __func__, + rssi.request_id, rssi.session_id, rssi.curr_rssi); + WMA_LOGI("%s: curr_bssid: %pM", __func__, rssi.curr_bssid.bytes); + + mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi); + WMA_LOGD("%s: Invoke HDD rssi breached callback", __func__); + return 0; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_roam_ho_fail_handler() - LFR3.0 roam hand off failed handler + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_roam_ho_fail_handler(tp_wma_handle wma, uint32_t vdev_id) +{ + tSirSmeHOFailureInd *ho_failure_ind; + struct scheduler_msg sme_msg = { 0 }; + QDF_STATUS qdf_status; + + ho_failure_ind = qdf_mem_malloc(sizeof(tSirSmeHOFailureInd)); + + if (NULL == ho_failure_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + ho_failure_ind->sessionId = vdev_id; + sme_msg.type = eWNI_SME_HO_FAIL_IND; + sme_msg.bodyptr = ho_failure_ind; + 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_LOGE("Fail to post eWNI_SME_HO_FAIL_IND msg to SME"); + qdf_mem_free(ho_failure_ind); + return; + } +} + +/** + * wma_process_roam_synch_complete() - roam synch complete command to fw. + * @handle: wma handle + * @synchcnf: offload synch confirmation params + * + * This function sends roam synch complete event to fw. + * + * Return: none + */ +void wma_process_roam_synch_complete(WMA_HANDLE handle, uint8_t vdev_id) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue roam synch cnf", + __func__); + return; + } + + if (wmi_unified_roam_synch_complete_cmd(wma_handle->wmi_handle, + vdev_id)) { + return; + } + + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_EVENT, QDF_ROAM_COMPLETE)); + + WMA_LOGI("LFR3: Posting WMA_ROAM_OFFLOAD_SYNCH_CNF"); + wlan_roam_debug_log(vdev_id, DEBUG_ROAM_SYNCH_CNF, + DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); + +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * wma_set_channel() - set channel + * @wma: wma handle + * @params: switch channel parameters + * + * Return: none + */ +void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params) +{ + struct wma_vdev_start_req req; + struct wma_target_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id, peer_id; + void *peer; + struct cdp_pdev *pdev; + struct wma_txrx_node *intr = wma->interfaces; + struct policy_mgr_hw_mode_params hw_mode = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint16_t beacon_interval_ori; + + WMA_LOGD("%s: Enter", __func__); + if (!wma_find_vdev_by_addr(wma, params->selfStaMacAddr, &vdev_id)) { + WMA_LOGP("%s: Failed to find vdev id for %pM", + __func__, params->selfStaMacAddr); + status = QDF_STATUS_E_FAILURE; + goto send_resp; + } + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + status = QDF_STATUS_E_FAILURE; + goto send_resp; + } + + peer = cdp_peer_find_by_addr(soc, + pdev, + intr[vdev_id].bssid, &peer_id); + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = params->channelNumber; + req.chan_width = params->ch_width; + + if (params->ch_width == CH_WIDTH_10MHZ) + req.is_half_rate = 1; + else if (params->ch_width == CH_WIDTH_5MHZ) + req.is_quarter_rate = 1; + + req.vht_capable = params->vhtCapable; + req.ch_center_freq_seg0 = params->ch_center_freq_seg0; + req.ch_center_freq_seg1 = params->ch_center_freq_seg1; + req.dot11_mode = params->dot11_mode; + wma_update_vdev_he_capable(&req, params); + + WMA_LOGI(FL("vht_capable: %d, dot11_mode: %d"), + req.vht_capable, req.dot11_mode); + + status = policy_mgr_get_current_hw_mode(wma->psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("policy_mgr_get_current_hw_mode failed"); + + if (params->nss == 2) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + req.max_txpow = params->maxTxPower; + req.beacon_intval = 100; + req.dtim_period = 1; + req.is_dfs = params->isDfsChannel; + req.cac_duration_ms = params->cac_duration_ms; + req.dfs_regdomain = params->dfs_regdomain; + req.ssid = params->ssid; + + /* In case of AP mode, once radar is detected, we need to + * issuse VDEV RESTART, so we making is_channel_switch as + * true + */ + if ((wma_is_vdev_in_ap_mode(wma, req.vdev_id) == true) || + (params->restart_on_chan_switch == true)) { + wma->interfaces[req.vdev_id].is_channel_switch = true; + req.hidden_ssid = params->ssid_hidden; + } + + if (params->restart_on_chan_switch == true && + wma->interfaces[req.vdev_id].beacon_filter_enabled) + wma_remove_beacon_filter(wma, + &wma->interfaces[req.vdev_id].beacon_filter); + + if ((wma_is_vdev_in_ap_mode(wma, req.vdev_id) == true) && + (params->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_LOGD("%s: Changing beacon interval to %d", + __func__, params->reduced_beacon_interval); + + /* Add a timer to reset the beacon interval back*/ + beacon_interval_ori = req.beacon_intval; + req.beacon_intval = params->reduced_beacon_interval; + if (wma_fill_beacon_interval_reset_req(wma, + req.vdev_id, + beacon_interval_ori, + RESET_BEACON_INTERVAL_TIMEOUT)) { + + WMA_LOGD("%s: Failed to fill beacon interval reset req", + __func__); + } + } + + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam() && + wma_is_vdev_up(vdev_id)) { + WMA_LOGD("%s: setting channel switch to true for vdev_id:%d", + __func__, req.vdev_id); + wma->interfaces[req.vdev_id].is_channel_switch = true; + } + + msg = wma_fill_vdev_req(wma, req.vdev_id, WMA_CHNL_SWITCH_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, params, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s: Failed to fill channel switch request for vdev %d", + __func__, req.vdev_id); + status = QDF_STATUS_E_NOMEM; + goto send_resp; + } + status = wma_vdev_start(wma, &req, + wma->interfaces[req.vdev_id].is_channel_switch); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, req.vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + WMA_LOGP("%s: vdev start failed status = %d", __func__, + status); + goto send_resp; + } + + /* This is temporary, should be removed */ + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + ol_htt_mon_note_chan(pdev, req.chan); + + return; +send_resp: + WMA_LOGD("%s: channel %d ch_width %d txpower %d status %d", __func__, + params->channelNumber, params->ch_width, + params->maxTxPower, + status); + params->status = status; + WMA_LOGI("%s: sending WMA_SWITCH_CHANNEL_RSP, status = 0x%x", + __func__, status); + wma_send_msg_high_priority(wma, WMA_SWITCH_CHANNEL_RSP, + (void *)params, 0); +} + +#ifdef FEATURE_WLAN_ESE +/** + * wma_plm_start() - plm start request + * @wma: wma handle + * @plm: plm request parameters + * + * This function request FW to start PLM. + * + * Return: QDF status + */ +QDF_STATUS wma_plm_start(tp_wma_handle wma, const tpSirPlmReq plm) +{ + struct plm_req_params params = {0}; + uint32_t num_channels; + uint32_t *channel_list = NULL; + uint32_t i; + QDF_STATUS status; + + if (NULL == plm || NULL == wma) { + WMA_LOGE("%s: input pointer is NULL ", __func__); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGD("PLM Start"); + + num_channels = plm->plmNumCh; + + if (num_channels) { + channel_list = qdf_mem_malloc(sizeof(uint32_t) * num_channels); + if (!channel_list) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < num_channels; i++) { + channel_list[i] = plm->plmChList[i]; + + if (channel_list[i] < WMA_NLO_FREQ_THRESH) + channel_list[i] = + cds_chan_to_freq(channel_list[i]); + } + } + + params.diag_token = plm->diag_token; + params.meas_token = plm->meas_token; + params.num_bursts = plm->numBursts; + params.burst_int = plm->burstInt; + params.meas_duration = plm->measDuration; + params.burst_len = plm->burstLen; + params.desired_tx_pwr = plm->desiredTxPwr; + params.plm_num_ch = plm->plmNumCh; + params.session_id = plm->sessionId; + params.enable = plm->enable; + qdf_mem_copy(¶ms.mac_addr, &plm->mac_addr, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params.plm_ch_list, plm->plmChList, + WMI_CFG_VALID_CHANNEL_LIST_LEN); + + status = wmi_unified_plm_start_cmd(wma->wmi_handle, + ¶ms, channel_list); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(channel_list); + return status; + } + + qdf_mem_free(channel_list); + wma->interfaces[plm->sessionId].plm_in_progress = true; + + WMA_LOGD("Plm start request sent successfully for vdev %d", + plm->sessionId); + + return status; +} + +/** + * wma_plm_stop() - plm stop request + * @wma: wma handle + * @plm: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: QDF status + */ +QDF_STATUS wma_plm_stop(tp_wma_handle wma, const tpSirPlmReq plm) +{ + struct plm_req_params params = {0}; + QDF_STATUS status; + + if (NULL == plm || NULL == wma) { + WMA_LOGE("%s: input pointer is NULL ", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (false == wma->interfaces[plm->sessionId].plm_in_progress) { + WMA_LOGE("No active plm req found, skip plm stop req"); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("PLM Stop"); + + params.diag_token = plm->diag_token; + params.meas_token = plm->meas_token; + params.num_bursts = plm->numBursts; + params.burst_int = plm->burstInt; + params.meas_duration = plm->measDuration; + params.burst_len = plm->burstLen; + params.desired_tx_pwr = plm->desiredTxPwr; + params.plm_num_ch = plm->plmNumCh; + params.session_id = plm->sessionId; + params.enable = plm->enable; + qdf_mem_copy(¶ms.mac_addr, &plm->mac_addr, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params.plm_ch_list, plm->plmChList, + WMI_CFG_VALID_CHANNEL_LIST_LEN); + + status = wmi_unified_plm_stop_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[plm->sessionId].plm_in_progress = false; + + WMA_LOGD("Plm stop request sent successfully for vdev %d", + plm->sessionId); + + return status; +} + +/** + * wma_config_plm()- config PLM + * @wma: wma handle + * @plm: plm request parameters + * + * Return: none + */ +void wma_config_plm(tp_wma_handle wma, tpSirPlmReq plm) +{ + QDF_STATUS ret = 0; + + if (NULL == plm || NULL == wma) + return; + + if (plm->enable) + ret = wma_plm_start(wma, plm); + else + ret = wma_plm_stop(wma, plm); + + if (ret) + WMA_LOGE("%s: PLM %s failed %d", __func__, + plm->enable ? "start" : "stop", ret); + + /* SME expects WMA to free tpSirPlmReq memory after + * processing PLM request. + */ + qdf_mem_free(plm); + plm = NULL; +} +#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_LOGE(FL("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_handle) { + WMA_LOGE("%s: extscan wma_handle is NULL", __func__); + 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); + + /* Register BTM reject list event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_roam_blacklist_event_id, + wma_handle_btm_blacklist_event, + 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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid extscan event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind)); + if (!extscan_ind) { + WMA_LOGE("%s: extscan memory allocation failed", __func__); + 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_LOGE("%s: Unknown event(%d) from target", + __func__, event->status); + qdf_mem_free(extscan_ind); + return -EINVAL; + } + pMac->sme.pExtScanIndCb(pMac->hdd_handle, event_type, extscan_ind); + WMA_LOGD("%s: sending event to umac for requestid %u with status %d", + __func__, 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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid scan operation event", __func__); + return -EINVAL; + } + oprn_event = param_buf->fixed_param; + oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind)); + if (!oprn_ind) { + WMA_LOGE("%s: extscan memory allocation failed", __func__); + qdf_mem_free(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_LOGD("%s: received WMI_EXTSCAN_CYCLE_STARTED_EVENT", + __func__); + + if (oprn_event->num_buckets > param_buf->num_bucket_id) { + WMA_LOGE("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_LOGD(FL("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_LOGD("%s: received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT", + __func__); + 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_LOGD("%s: received WMI_EXTSCAN_BUCKET_STARTED_EVENT", + __func__); + oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT; + oprn_ind->status = 0; + goto exit_handler; + case WMI_EXTSCAN_THRESHOLD_NUM_SCANS: + WMA_LOGD("%s: received WMI_EXTSCAN_THRESHOLD_NUM_SCANS", + __func__); + oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS; + oprn_ind->status = 0; + break; + case WMI_EXTSCAN_THRESHOLD_PERCENT: + WMA_LOGD("%s: received WMI_EXTSCAN_THRESHOLD_PERCENT", + __func__); + oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT; + oprn_ind->status = 0; + break; + default: + WMA_LOGE("%s: Unknown event(%d) from target", + __func__, oprn_event->event); + qdf_mem_free(oprn_ind); + return -EINVAL; + } + pMac->sme.pExtScanIndCb(pMac->hdd_handle, + eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind); + WMA_LOGI("%s: sending scan progress event to hdd", __func__); +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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid table usage event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind)); + if (!tbl_usg_ind) { + WMA_LOGE("%s: table usage allocation failed", __func__); + return -ENOMEM; + } + tbl_usg_ind->requestId = event->request_id; + tbl_usg_ind->numResultsAvailable = event->entries_in_use; + pMac->sme.pExtScanIndCb(pMac->hdd_handle, + eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, + tbl_usg_ind); + WMA_LOGI("%s: sending scan_res available event to hdd", __func__); + 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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid capabilities event", __func__); + 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_LOGE("%s: Invalid capabilities list", __func__); + return -EINVAL; + } + dest_capab = qdf_mem_malloc(sizeof(*dest_capab)); + if (!dest_capab) { + WMA_LOGE("%s: Allocation failed for capabilities buffer", + __func__); + 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_white_listed_ssid = + event->num_roam_ssid_whitelist; + dest_capab->max_number_of_black_listed_bssid = + event->num_roam_bssid_blacklist; + dest_capab->status = 0; + + WMA_LOGD("%s: request_id: %u status: %d", + __func__, dest_capab->requestId, dest_capab->status); + + WMA_LOGD("%s: Capabilities: max_scan_buckets: %d, max_hotlist_bssids: %d, max_scan_cache_size: %d, max_ap_cache_per_scan: %d", + __func__, dest_capab->max_scan_buckets, + dest_capab->max_hotlist_bssids, dest_capab->max_scan_cache_size, + dest_capab->max_ap_cache_per_scan); + WMA_LOGD("%s: max_scan_reporting_threshold: %d, max_rssi_sample_size: %d, max_bssid_history_entries: %d, max_significant_wifi_change_aps: %d", + __func__, 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_LOGD("%s: Capabilities: max_hotlist_ssids: %d, max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d", + __func__, dest_capab->max_hotlist_ssids, + dest_capab->max_number_epno_networks, + dest_capab->max_number_epno_networks_by_ssid); + WMA_LOGD("%s: max_number_of_white_listed_ssid: %d, max_number_of_black_listed_bssid: %d", + __func__, dest_capab->max_number_of_white_listed_ssid, + dest_capab->max_number_of_black_listed_bssid); + + pMac->sme.pExtScanIndCb(pMac->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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid hotlist match event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->hotlist_match; + numap = event->total_entries; + + if (!src_hotlist || !numap) { + WMA_LOGE("%s: Hotlist AP's list invalid", __func__); + return -EINVAL; + } + if (numap > param_buf->num_hotlist_match) { + WMA_LOGE("Invalid no of total enteries %d", numap); + return -EINVAL; + } + if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) { + WMA_LOGE("%s: Total Entries %u greater than max", + __func__, 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_LOGE("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) { + WMA_LOGE("%s: Allocation failed for hotlist buffer", __func__); + return -ENOMEM; + } + dest_ap = &dest_hotlist->ap[0]; + dest_hotlist->numOfAps = event->total_entries; + 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_LOGD("%s: Hotlist match: requestId: %u," + "numOfAps: %d", __func__, + 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 > SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGE("%s Invalid SSID len %d, truncating", + __func__, src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; + } + 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; + pMac->sme.pExtScanIndCb(pMac->hdd_handle, + eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist); + WMA_LOGI("%s: sending hotlist match event to hdd", __func__); + 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; + 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]; + + if ((t_cached_result->num_scan_ids * + QDF_MIN(t_scan_id_grp->num_results, + param_buf->num_bssid_list)) > param_buf->num_bssid_list) { + WMA_LOGE("%s:num_scan_ids %d, num_results %d num_bssid_list %d", + __func__, + t_cached_result->num_scan_ids, + t_scan_id_grp->num_results, + param_buf->num_bssid_list); + return -EINVAL; + } + + WMA_LOGD("%s: num_scan_ids:%d", __func__, + t_cached_result->num_scan_ids); + for (i = 0; i < t_cached_result->num_scan_ids; i++) { + WMA_LOGD("%s: num_results:%d", __func__, + 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) { + WMA_LOGD("%s: qdf_mem_malloc failed", __func__); + return -ENOMEM; + } + + ap = &t_scan_id_grp->ap[0]; + for (j = 0; j < QDF_MIN(t_scan_id_grp->num_results, + param_buf->num_bssid_list); 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 > + SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGD("%s Invalid SSID len %d, truncating", + __func__, src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = + SIR_MAC_MAX_SSID_LENGTH; + } + 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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t total_len; + bool excess_data = false; + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid cached results event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + WMA_LOGI("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_LOGW("%s: Cached results empty, send 0 results", __func__); + 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_LOGE("%s:excess num_entries_in_page %d in WMI event. num_bssid_list %d", + __func__, + 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_LOGD("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_LOGD("total len RSSI samples: %d", total_len); + } + } + if (excess_data) { + WMA_LOGE("%s:excess data in WMI event", + __func__); + 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) { + WMA_LOGE("%s: qdf_mem_malloc failed", __func__); + 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_LOGD("%s: scan_ids_cnt %d", __func__, 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) { + WMA_LOGE("%s: Allocation failed for scanid grouping", __func__); + 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) + pMac->sme.pExtScanIndCb(pMac->hdd_handle, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + dest_cachelist); + else + WMA_LOGD("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; + + pMac->sme.pExtScanIndCb(pMac->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; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t buf_len; + bool excess_data = false; + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid change monitor event", __func__); + 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_LOGE("%s: Results invalid", __func__); + return -EINVAL; + } + if (numap > param_buf->num_bssid_signal_descriptor_list) { + WMA_LOGE("%s: Invalid num of entries in page: %d", __func__, numap); + return -EINVAL; + } + for (i = 0; i < numap; i++) { + if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) { + WMA_LOGE("%s: Invalid num of rssi samples %d numap %d rssi_num %d", + __func__, 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_LOGE("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) { + WMA_LOGE("%s: Allocation failed for change monitor", __func__); + 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_LOGE("%s: Invalid num in rssi list: %d", + __func__, 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; + + pMac->sme.pExtScanIndCb(pMac->hdd_handle, + eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, + dest_chglist); + WMA_LOGI("%s: sending change monitor results", __func__); + 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; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac", __func__); + return -EINVAL; + } + if (!mac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid passpoint match event", __func__); + 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_LOGE("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 > SIR_MAC_MAX_SSID_LENGTH) { + WMA_LOGD("%s: Invalid ssid len %d, truncating", + __func__, event->ssid.ssid_len); + event->ssid.ssid_len = SIR_MAC_MAX_SSID_LENGTH; + } + + dest_match = qdf_mem_malloc(sizeof(*dest_match) + buf_len); + + if (!dest_match) { + WMA_LOGE("%s: qdf_mem_malloc failed", __func__); + 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_LOGI("%s: passpoint match: id: %u anqp length %u", __func__, + 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.pExtScanIndCb(mac->hdd_handle, + eSIR_PASSPOINT_NETWORK_FOUND_IND, + dest_match); + WMA_LOGI("%s: sending passpoint match event to hdd", __func__); + qdf_mem_free(dest_match); + return 0; +} + +/** + * wma_start_extscan() - start extscan command to fw. + * @handle: wma handle + * @pstart: scan command request params + * + * This function sends start extscan request to fw. + * + * Return: QDF Status. + */ +QDF_STATUS wma_start_extscan(tp_wma_handle wma, + tSirWifiScanCmdReqParams *pstart) +{ + struct wifi_scan_cmd_req_params *params; + int i, j; + QDF_STATUS status; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed,can not issue extscan cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan feature bit not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params = qdf_mem_malloc(sizeof(struct wifi_scan_cmd_req_params)); + if (params == NULL) { + WMA_LOGE("%s : Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + params->base_period = pstart->basePeriod; + params->max_ap_per_scan = pstart->maxAPperScan; + params->report_threshold_percent = pstart->report_threshold_percent; + params->report_threshold_num_scans = pstart->report_threshold_num_scans; + params->request_id = pstart->requestId; + params->vdev_id = pstart->sessionId; + params->num_buckets = pstart->numBuckets; + params->min_dwell_time_active = pstart->min_dwell_time_active; + params->min_dwell_time_passive = pstart->min_dwell_time_passive; + params->max_dwell_time_active = pstart->max_dwell_time_active; + params->max_dwell_time_passive = pstart->max_dwell_time_passive; + params->configuration_flags = pstart->configuration_flags; + params->extscan_adaptive_dwell_mode = + pstart->extscan_adaptive_dwell_mode; + for (i = 0; i < WMI_WLAN_EXTSCAN_MAX_BUCKETS; i++) { + params->buckets[i].bucket = pstart->buckets[i].bucket; + params->buckets[i].band = + (enum wmi_wifi_band) pstart->buckets[i].band; + params->buckets[i].period = pstart->buckets[i].period; + params->buckets[i].report_events = + pstart->buckets[i].reportEvents; + params->buckets[i].max_period = pstart->buckets[i].max_period; + params->buckets[i].exponent = pstart->buckets[i].exponent; + params->buckets[i].step_count = pstart->buckets[i].step_count; + params->buckets[i].num_channels = + pstart->buckets[i].numChannels; + params->buckets[i].min_dwell_time_active = + pstart->buckets[i].min_dwell_time_active; + params->buckets[i].min_dwell_time_passive = + pstart->buckets[i].min_dwell_time_passive; + params->buckets[i].max_dwell_time_active = + pstart->buckets[i].max_dwell_time_active; + params->buckets[i].max_dwell_time_passive = + pstart->buckets[i].max_dwell_time_passive; + for (j = 0; j < WLAN_EXTSCAN_MAX_CHANNELS; j++) { + params->buckets[i].channels[j].channel = + pstart->buckets[i].channels[j].channel; + params->buckets[i].channels[j].dwell_time_ms = + pstart->buckets[i].channels[j].dwellTimeMs; + params->buckets[i].channels[j].passive = + pstart->buckets[i].channels[j].passive; + params->buckets[i].channels[j].channel_class = + pstart->buckets[i].channels[j].chnlClass; + } + } + + status = wmi_unified_start_extscan_cmd(wma->wmi_handle, + params); + qdf_mem_free(params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[pstart->sessionId].extscan_in_progress = true; + WMA_LOGD("Extscan start request sent successfully for vdev %d", + pstart->sessionId); + + return status; +} + +/** + * wma_stop_extscan() - stop extscan command to fw. + * @handle: wma handle + * @pstopcmd: 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, + tSirExtScanStopReqParams *pstopcmd) +{ + struct extscan_stop_req_params params = {0}; + QDF_STATUS status; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = pstopcmd->requestId; + params.vdev_id = pstopcmd->sessionId; + + status = wmi_unified_stop_extscan_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[pstopcmd->sessionId].extscan_in_progress = false; + WMA_LOGD("Extscan stop request sent successfully for vdev %d", + pstopcmd->sessionId); + + return status; +} + +/** wma_get_hotlist_entries_per_page() - hotlist entries per page + * @wmi_handle: wmi handle. + * @cmd: size of command structure. + * @per_entry_size: per entry size. + * + * This utility function calculates how many hotlist entries can + * fit in one page. + * + * Return: number of entries + */ +static inline int wma_get_hotlist_entries_per_page(wmi_unified_t wmi_handle, + size_t cmd_size, + size_t per_entry_size) +{ + uint32_t avail_space = 0; + int num_entries = 0; + uint16_t max_msg_len = wmi_get_max_msg_len(wmi_handle); + + /* Calculate number of hotlist entries that can + * be passed in wma message request. + */ + avail_space = max_msg_len - cmd_size; + num_entries = avail_space / per_entry_size; + return num_entries; +} + +QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, + struct extscan_bssid_hotlist_set_params *params) +{ + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue hotlist cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!params) { + WMA_LOGE("%s: Invalid params", __func__); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_extscan_start_hotlist_monitor_cmd(wma->wmi_handle, + params); +} + +QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, + struct extscan_bssid_hotlist_reset_params *params) +{ + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!params) { + WMA_LOGE("%s: Invalid params", __func__); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_extscan_stop_hotlist_monitor_cmd(wma->wmi_handle, + params); +} + +QDF_STATUS +wma_extscan_start_change_monitor(tp_wma_handle wma, + struct extscan_set_sig_changereq_params *params) +{ + QDF_STATUS status; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed,can not issue cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!params) { + WMA_LOGE("%s: NULL params", __func__); + return QDF_STATUS_E_NOMEM; + } + + status = wmi_unified_extscan_start_change_monitor_cmd(wma->wmi_handle, + params); + return status; +} + +QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, + struct extscan_capabilities_reset_params *params) +{ + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: ext scan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_extscan_stop_change_monitor_cmd(wma->wmi_handle, + params); +} + +/** + * wma_extscan_get_cached_results() - extscan get cached results + * @wma: wma handle + * @pcached_results: 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, + tSirExtScanGetCachedResultsReqParams * + pcached_results) +{ + struct extscan_cached_result_params params = {0}; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = pcached_results->requestId; + params.vdev_id = pcached_results->sessionId; + params.flush = pcached_results->flush; + + return wmi_unified_extscan_get_cached_results_cmd(wma->wmi_handle, + ¶ms); +} + +/** + * wma_extscan_get_capabilities() - extscan get capabilities + * @wma: wma handle + * @pgetcapab: get capabilities params + * + * This function send request to fw to get extscan capabilities. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_get_capabilities(tp_wma_handle wma, + tSirGetExtScanCapabilitiesReqParams * + pgetcapab) +{ + struct extscan_capabilities_params params = {0}; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = pgetcapab->requestId; + params.vdev_id = pgetcapab->sessionId; + + return wmi_unified_extscan_get_capabilities_cmd(wma->wmi_handle, + ¶ms); +} + +/** 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. + * + * Returns: 0 on success, error number otherwise + */ +QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_epno_params *req) +{ + struct wifi_enhanced_pno_params *params; + uint8_t i = 0; + QDF_STATUS status; + size_t params_len; + + WMA_LOGD("wma_set_epno_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_NOSUPPORT; + } + + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_epno_network_params)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->vdev_id = req->session_id; + params->num_networks = req->num_networks; + + /* Fill only when num_networks are non zero */ + if (req->num_networks) { + params->min_5ghz_rssi = req->min_5ghz_rssi; + params->min_24ghz_rssi = req->min_24ghz_rssi; + params->initial_score_max = req->initial_score_max; + params->same_network_bonus = req->same_network_bonus; + params->secure_bonus = req->secure_bonus; + params->band_5ghz_bonus = req->band_5ghz_bonus; + params->current_connection_bonus = + req->current_connection_bonus; + + for (i = 0; i < req->num_networks; i++) { + params->networks[i].flags = req->networks[i].flags; + params->networks[i].auth_bit_field = + req->networks[i].auth_bit_field; + params->networks[i].ssid.length = + req->networks[i].ssid.length; + qdf_mem_copy(params->networks[i].ssid.mac_ssid, + req->networks[i].ssid.ssId, + req->networks[i].ssid.length); + } + } + + status = wmi_unified_set_epno_network_list_cmd(wma->wmi_handle, params); + qdf_mem_free(params); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("set ePNO list request sent successfully for vdev %d", + req->session_id); + + return status; +} + +/** + * wma_set_passpoint_network_list() - set passpoint network list + * @handle: WMA handle + * @req: passpoint network request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down 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 *req) +{ + struct wifi_passpoint_req_param *params; + int i = 0; + QDF_STATUS status; + size_t params_len; + + WMA_LOGD("wma_set_passpoint_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_NOSUPPORT; + } + + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_passpoint_network_param)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->vdev_id = req->session_id; + params->num_networks = req->num_networks; + for (i = 0; i < req->num_networks; i++) { + params->networks[i].id = req->networks[i].id; + qdf_mem_copy(params->networks[i].realm, req->networks[i].realm, + WMI_PASSPOINT_REALM_LEN); + qdf_mem_copy(params->networks[i].roaming_consortium_ids, + req->networks[i].roaming_consortium_ids, + WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM * + sizeof(int64_t)); + qdf_mem_copy(params->networks[i].plmn, req->networks[i].plmn, + WMI_PASSPOINT_PLMN_LEN); + } + + status = wmi_unified_set_passpoint_network_list_cmd(wma->wmi_handle, + params); + qdf_mem_free(params); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("Set passpoint network list request is sent successfully for vdev %d", + req->session_id); + + return status; +} + +/** + * wma_reset_passpoint_network_list() - reset passpoint network list + * @handle: WMA handle + * @req: 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 *req) +{ + struct wifi_passpoint_req_param *params; + int i = 0; + QDF_STATUS status; + size_t params_len; + + WMA_LOGD("wma_reset_passpoint_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_extscan)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_NOSUPPORT; + } + + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_passpoint_network_param)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->vdev_id = req->session_id; + params->num_networks = req->num_networks; + for (i = 0; i < req->num_networks; i++) { + params->networks[i].id = req->networks[i].id; + qdf_mem_copy(params->networks[i].realm, req->networks[i].realm, + WMI_PASSPOINT_REALM_LEN); + qdf_mem_copy(params->networks[i].roaming_consortium_ids, + req->networks[i].roaming_consortium_ids, + WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM * + sizeof(int64_t)); + qdf_mem_copy(params->networks[i].plmn, req->networks[i].plmn, + WMI_PASSPOINT_PLMN_LEN); + } + + status = wmi_unified_reset_passpoint_network_list_cmd(wma->wmi_handle, + params); + qdf_mem_free(params); + + return status; +} + +#endif + +/** + * wma_scan_probe_setoui() - set scan probe OUI + * @wma: wma handle + * @psetoui: OUI parameters + * + * set scan probe OUI parameters in firmware + * + * Return: QDF status + */ +QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, tSirScanMacOui *psetoui) +{ + struct scan_mac_oui set_oui; + + qdf_mem_zero(&set_oui, sizeof(struct scan_mac_oui)); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(set_oui.oui, psetoui->oui, + WMI_WIFI_SCANNING_MAC_OUI_LENGTH); + + set_oui.vdev_id = psetoui->vdev_id; + set_oui.enb_probe_req_sno_randomization = + psetoui->enb_probe_req_sno_randomization; + set_oui.ie_whitelist = psetoui->ie_whitelist; + + return wmi_unified_scan_probe_setoui_cmd(wma->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 cds_msg = {0}; + tSirSmeCandidateFoundInd *candidate_ind; + + candidate_ind = qdf_mem_malloc(sizeof(tSirSmeCandidateFoundInd)); + if (!candidate_ind) { + WMA_LOGE("%s: Alloc failed for tSirSmeCandidateFoundInd", + __func__); + return; + } + WMA_LOGD("%s: roaming in progress for vdev %d", + __func__, vdev_id); + wma->interfaces[vdev_id].roaming_in_progress = true; + + candidate_ind->messageType = eWNI_SME_CANDIDATE_FOUND_IND; + candidate_ind->sessionId = vdev_id; + candidate_ind->length = sizeof(tSirSmeCandidateFoundInd); + + cds_msg.type = eWNI_SME_CANDIDATE_FOUND_IND; + cds_msg.bodyptr = candidate_ind; + cds_msg.callback = sme_mc_process_handler; + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_INFO, + FL("posting candidate ind to SME")); + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SCAN, + &cds_msg)) { + qdf_mem_free(candidate_ind); + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + FL("Failed to post candidate ind to SME")); + } +} + +/** + * wma_handle_btm_disassoc_imminent_msg() - Send del sta msg to lim on receiving + * BTM request from AP with disassoc imminent reason + * @wma_handle: wma handle + * @vdev_id: vdev id + * + * Return: None + */ +static void wma_handle_btm_disassoc_imminent_msg(tp_wma_handle wma_handle, + uint32_t vdev_id) +{ + tpDeleteStaContext del_sta_ctx; + + del_sta_ctx = + (tDeleteStaContext *)qdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) { + WMA_LOGE("Memory alloc failed for del sta context"); + return; + } + del_sta_ctx->vdev_id = vdev_id; + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT; + wma_send_msg(wma_handle, SIR_LIM_DELETE_STA_CONTEXT_IND, + (void *)del_sta_ctx, 0); +} + +/** + * wma_roam_event_callback() - roam event callback + * @handle: wma handle + * @event_buf: event buffer + * @len: buffer length + * + * Handler for all events from roam engine in firmware + * + * Return: 0 for success or error code + */ +int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_ROAM_EVENTID_param_tlvs *param_buf; + wmi_roam_event_fixed_param *wmi_event; + struct sSirSmeRoamOffloadSynchInd *roam_synch_data; + enum sir_roam_op_code op_code = {0}; + + param_buf = (WMI_ROAM_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("Invalid roam event buffer"); + return -EINVAL; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGD("%s: Reason %x, Notif %x for vdevid %x, rssi %d", + __func__, wmi_event->reason, wmi_event->notif, + wmi_event->vdev_id, wmi_event->rssi); + + if (wmi_event->vdev_id >= wma_handle->max_bssid) { + WMA_LOGE("Invalid vdev id from firmware"); + return -EINVAL; + } + wlan_roam_debug_log(wmi_event->vdev_id, DEBUG_ROAM_EVENT, + DEBUG_INVALID_PEER_ID, NULL, NULL, + wmi_event->reason, + (wmi_event->reason == WMI_ROAM_REASON_INVALID) ? + wmi_event->notif : wmi_event->rssi); + + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + wmi_event->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_EVENT, QDF_ROAM_EVENTID)); + + switch (wmi_event->reason) { + case WMI_ROAM_REASON_BTM: + /* + * 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_LOGD("Kickout due to btm request"); + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BTM, + wmi_event->vdev_id, NULL); + wma_handle_btm_disassoc_imminent_msg(wma_handle, + wmi_event->vdev_id); + break; + case WMI_ROAM_REASON_BMISS: + WMA_LOGD("Beacon Miss for vdevid %x", wmi_event->vdev_id); + wma_beacon_miss_handler(wma_handle, wmi_event->vdev_id, + wmi_event->rssi); + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS, + wmi_event->vdev_id, NULL); + break; + case WMI_ROAM_REASON_BETTER_AP: + WMA_LOGD("%s:Better AP found for vdevid %x, rssi %d", __func__, + wmi_event->vdev_id, wmi_event->rssi); + wma_handle->suitable_ap_hb_failure = false; + wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); + break; + case WMI_ROAM_REASON_SUITABLE_AP: + wma_handle->suitable_ap_hb_failure = true; + wma_handle->suitable_ap_hb_failure_rssi = wmi_event->rssi; + WMA_LOGD("%s:Bmiss scan AP found for vdevid %x, rssi %d", + __func__, wmi_event->vdev_id, wmi_event->rssi); + wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WMI_ROAM_REASON_HO_FAILED: + WMA_LOGE("LFR3:Hand-Off Failed for vdevid %x", + wmi_event->vdev_id); + wma_roam_ho_fail_handler(wma_handle, wmi_event->vdev_id); + wma_handle->interfaces[wmi_event->vdev_id]. + roaming_in_progress = false; + break; +#endif + case WMI_ROAM_REASON_INVALID: + roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); + if (NULL == roam_synch_data) { + WMA_LOGE("Memory unavailable for roam synch data"); + return -ENOMEM; + } + if (wmi_event->notif == WMI_ROAM_NOTIF_ROAM_START) { + op_code = SIR_ROAMING_START; + wma_handle->interfaces[wmi_event->vdev_id]. + roaming_in_progress = true; + } + if (wmi_event->notif == WMI_ROAM_NOTIF_ROAM_ABORT) { + op_code = SIR_ROAMING_ABORT; + wma_handle->interfaces[wmi_event->vdev_id]. + roaming_in_progress = false; + } + roam_synch_data->roamedVdevId = wmi_event->vdev_id; + wma_handle->pe_roam_synch_cb( + (tpAniSirGlobal)wma_handle->mac_context, + roam_synch_data, NULL, op_code); + wma_handle->csr_roam_synch_cb( + (tpAniSirGlobal)wma_handle->mac_context, + roam_synch_data, NULL, op_code); + qdf_mem_free(roam_synch_data); + break; + case WMI_ROAM_REASON_RSO_STATUS: + wma_rso_cmd_status_event_handler(wmi_event); + break; + case WMI_ROAM_REASON_INVOKE_ROAM_FAIL: + roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); + if (!roam_synch_data) { + WMA_LOGE("Memory unavailable for roam synch data"); + return -ENOMEM; + } + roam_synch_data->roamedVdevId = wmi_event->vdev_id; + wma_handle->csr_roam_synch_cb( + (tpAniSirGlobal)wma_handle->mac_context, + roam_synch_data, NULL, SIR_ROAMING_INVOKE_FAIL); + qdf_mem_free(roam_synch_data); + break; + default: + WMA_LOGD("%s:Unhandled Roam Event %x for vdevid %x", __func__, + wmi_event->reason, wmi_event->vdev_id); + break; + } + return 0; +} + + +/** + * wma_set_rssi_monitoring() - set rssi monitoring + * @handle: WMA 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 + */ +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req) +{ + struct rssi_monitor_param params = {0}; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + params.request_id = req->request_id; + params.session_id = req->session_id; + params.min_rssi = req->min_rssi; + params.max_rssi = req->max_rssi; + params.control = req->control; + + return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, + ¶ms); +} + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * wma_set_gateway_params() - set gateway parameters + * @wma: WMA 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 + */ +QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_param_update_req *req) +{ + struct gateway_update_req_param params = {0}; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + params.request_id = req->request_id; + params.session_id = req->session_id; + params.max_retries = req->max_retries; + params.timeout = req->timeout; + params.ipv4_addr_type = req->ipv4_addr_type; + params.ipv6_addr_type = req->ipv6_addr_type; + qdf_mem_copy(¶ms.gw_mac_addr, &req->gw_mac_addr, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params.ipv4_addr, req->ipv4_addr, + QDF_IPV4_ADDR_SIZE); + qdf_mem_copy(params.ipv6_addr, req->ipv6_addr, + QDF_IPV6_ADDR_SIZE); + + return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, + ¶ms); +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * wma_ht40_stop_obss_scan() - ht40 obss stop scan + * @wma: WMA handel + * @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) +{ + + wmi_buf_t buf; + wmi_obss_scan_disable_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + WMA_LOGD("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; + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_OBSS_SCAN_DISABLE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send gw config parameter to fw, ret: %d", + ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_ht40_obss_scanind() - ht40 obss start scan indication + * @wma: WMA handel + * @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) +{ + wmi_buf_t buf; + wmi_obss_scan_enable_cmd_fixed_param *cmd; + int ret; + int len = 0; + uint8_t *buf_ptr, i; + uint8_t *channel_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)); + + WMA_LOGE("cmdlen %d vdev_id %d channel count %d iefield_len %d", + len, req->bss_id, req->channel_count, req->iefield_len); + + WMA_LOGE("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) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + 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] = req->channels[i]; + WMA_LOGD("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; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_OBSS_SCAN_ENABLE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send gw config parameter to fw, ret: %d", + ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +int wma_handle_btm_blacklist_event(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + 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_blacklist_event *dst_list; + struct roam_blacklist_timeout *roam_blacklist; + uint32_t num_entries, i; + + param_buf = (WMI_ROAM_BLACKLIST_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid event buffer"); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + if (!resp_event) { + WMA_LOGE("%s: received null event data from target", __func__); + return -EINVAL; + } + + if (resp_event->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: received invalid vdev_id %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + + num_entries = param_buf->num_blacklist_with_timeout; + if (num_entries == 0) { + /* no aps to blacklist just return*/ + WMA_LOGE("%s: No APs in blacklist received", __func__); + return 0; + } + + if (num_entries > MAX_RSSI_AVOID_BSSID_LIST) { + WMA_LOGE("%s: num blacklist entries:%d exceeds maximum value", + __func__, num_entries); + return -EINVAL; + } + + src_list = param_buf->blacklist_with_timeout; + if (len < (sizeof(*resp_event) + (num_entries * sizeof(*src_list)))) { + WMA_LOGE("%s: Invalid length:%d", __func__, len); + return -EINVAL; + } + + dst_list = qdf_mem_malloc(sizeof(struct roam_blacklist_event) + + (sizeof(struct roam_blacklist_timeout) * + num_entries)); + if (!dst_list) + return -ENOMEM; + + roam_blacklist = &dst_list->roam_blacklist[0]; + for (i = 0; i < num_entries; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_list->bssid, + roam_blacklist->bssid.bytes); + roam_blacklist->timeout = src_list->timeout; + roam_blacklist->received_time = + qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + roam_blacklist++; + src_list++; + } + + dst_list->num_entries = num_entries; + wma_send_msg(wma, WMA_ROAM_BLACKLIST_MSG, (void *)dst_list, 0); + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_twt.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_twt.c new file mode 100644 index 0000000000000000000000000000000000000000..9ccf323afb0c489841be2404fc76929ccd5ea59a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_twt.c @@ -0,0 +1,90 @@ +/* + * 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: 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" + +void wma_send_twt_enable_cmd(uint32_t pdev_id, uint32_t congestion_timeout) +{ + 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) { + WMA_LOGE("Invalid WMA context, enable TWT failed"); + return; + } + twt_enable_params.pdev_id = pdev_id; + twt_enable_params.sta_cong_timer_ms = congestion_timeout; + ret = wmi_unified_twt_enable_cmd(wma->wmi_handle, &twt_enable_params); + + if (ret) + WMA_LOGE("Failed to enable TWT"); +} + +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 = (tp_wma_handle) handle; + wmi_unified_t wmi_handle; + tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (!wma_handle) { + WMA_LOGE("Invalid wma handle for TWT complete"); + return status; + } + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE("Invalid wmi handle for TWT complete"); + return status; + } + if (!mac) { + WMA_LOGE("Invalid MAC context"); + 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_LOGD("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_set_twt_peer_caps(tpAddStaParams params, struct peer_assoc_params *cmd) +{ + if (params->twt_requestor) + cmd->peer_flags |= WMI_PEER_TWT_REQ; + if (params->twt_responder) + cmd->peer_flags |= WMI_PEER_TWT_RESP; +} + diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..69580af31edfdcf7d8fd2eaf7c9aecd7f2277b3a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c @@ -0,0 +1,5079 @@ +/* + * 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_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 "cfg_api.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 "wlan_mlme_main.h" +#include "host_diag_core_log.h" + +/* MCS Based rate table */ +/* HT MCS parameters with Nss = 1 */ +static 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 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 struct index_vht_data_rate_type vht_mcs_nss1[] = { + /* MCS L20 S20 L40 S40 L80 S80 */ + {0, {65, 72 }, {135, 150}, {293, 325} }, + {1, {130, 144}, {270, 300}, {585, 650} }, + {2, {195, 217}, {405, 450}, {878, 975} }, + {3, {260, 289}, {540, 600}, {1170, 1300} }, + {4, {390, 433}, {810, 900}, {1755, 1950} }, + {5, {520, 578}, {1080, 1200}, {2340, 2600} }, + {6, {585, 650}, {1215, 1350}, {2633, 2925} }, + {7, {650, 722}, {1350, 1500}, {2925, 3250} }, + {8, {780, 867}, {1620, 1800}, {3510, 3900} }, + {9, {865, 960}, {1800, 2000}, {3900, 4333} } +}; + +/*MCS parameters with Nss = 2*/ +static struct index_vht_data_rate_type vht_mcs_nss2[] = { + /* MCS L20 S20 L40 S40 L80 S80 */ + {0, {130, 144}, {270, 300}, { 585, 650} }, + {1, {260, 289}, {540, 600}, {1170, 1300} }, + {2, {390, 433}, {810, 900}, {1755, 1950} }, + {3, {520, 578}, {1080, 1200}, {2340, 2600} }, + {4, {780, 867}, {1620, 1800}, {3510, 3900} }, + {5, {1040, 1156}, {2160, 2400}, {4680, 5200} }, + {6, {1170, 1300}, {2430, 2700}, {5265, 5850} }, + {7, {1300, 1444}, {2700, 3000}, {5850, 6500} }, + {8, {1560, 1733}, {3240, 3600}, {7020, 7800} }, + {9, {1730, 1920}, {3600, 4000}, {7800, 8667} } +}; + +#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 */ + +/** + * wma_mcs_rate_match() - find the match mcs rate + * @match_rate: the rate to look up + * @is_sgi: return if the SGI rate is found + * @nss: the nss in use + * @nss1_rate: the nss1 rate + * @nss1_srate: the nss1 SGI rate + * @nss2_rate: the nss2 rate + * @nss2_srate: the nss2 SGI rate + * + * This is a helper function to find the match of the tx_rate + * in terms of the nss1/nss2 rate with non-SGI/SGI. + * + * Return: the found rate or 0 otherwise + */ +static inline uint16_t wma_mcs_rate_match(uint16_t match_rate, bool *is_sgi, + uint8_t *nss, uint16_t nss1_rate, + uint16_t nss1_srate, + uint16_t nss2_rate, + uint16_t nss2_srate) +{ + WMA_LOGD("%s match_rate: %d, %d %d %d %d", + __func__, match_rate, nss1_rate, nss1_srate, nss2_rate, + nss2_srate); + + if (match_rate == nss1_rate) { + *nss = 1; + return nss1_rate; + } else if (match_rate == nss1_srate) { + *is_sgi = true; + *nss = 1; + return nss1_srate; + } else if (*nss == 2 && match_rate == nss2_rate) + return nss2_rate; + else if (*nss == 2 && match_rate == nss2_srate) { + *is_sgi = true; + return nss2_srate; + } else + return 0; +} + +uint8_t wma_get_mcs_idx(uint16_t maxRate, uint8_t rate_flags, + uint8_t *nss, uint8_t *mcsRateFlag) +{ + uint8_t index = 0; + uint16_t match_rate = 0; + bool is_sgi = false; + + WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d", + __func__, maxRate, rate_flags, *nss); + + *mcsRateFlag = rate_flags; + *mcsRateFlag &= ~TX_RATE_SGI; + for (index = 0; index < MAX_VHT_MCS_IDX; index++) { + if (rate_flags & TX_RATE_VHT80) { + /* check for vht80 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + vht_mcs_nss1[index].ht80_rate[0], + vht_mcs_nss1[index].ht80_rate[1], + vht_mcs_nss2[index].ht80_rate[0], + vht_mcs_nss2[index].ht80_rate[1]); + if (match_rate) + goto rate_found; + } + if ((rate_flags & TX_RATE_VHT40) | + (rate_flags & TX_RATE_VHT80)) { + /* check for vht40 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + vht_mcs_nss1[index].ht40_rate[0], + vht_mcs_nss1[index].ht40_rate[1], + vht_mcs_nss2[index].ht40_rate[0], + vht_mcs_nss2[index].ht40_rate[1]); + if (match_rate) { + *mcsRateFlag &= ~TX_RATE_VHT80; + goto rate_found; + } + } + if ((rate_flags & TX_RATE_VHT20) | + (rate_flags & TX_RATE_VHT40) | + (rate_flags & TX_RATE_VHT80)) { + /* check for vht20 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + vht_mcs_nss1[index].ht20_rate[0], + vht_mcs_nss1[index].ht20_rate[1], + vht_mcs_nss2[index].ht20_rate[0], + vht_mcs_nss2[index].ht20_rate[1]); + if (match_rate) { + *mcsRateFlag &= ~(TX_RATE_VHT80 | + TX_RATE_VHT40); + goto rate_found; + } + } + } + for (index = 0; index < MAX_HT_MCS_IDX; index++) { + if (rate_flags & TX_RATE_HT40) { + /* check for ht40 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + mcs_nss1[index].ht40_rate[0], + mcs_nss1[index].ht40_rate[1], + mcs_nss2[index].ht40_rate[0], + mcs_nss2[index].ht40_rate[1]); + if (match_rate) { + *mcsRateFlag = TX_RATE_HT40; + if (*nss == 2) + index += MAX_HT_MCS_IDX; + goto rate_found; + } + } + if ((rate_flags & TX_RATE_HT20) || + (rate_flags & TX_RATE_HT40)) { + /* check for ht20 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + mcs_nss1[index].ht20_rate[0], + mcs_nss1[index].ht20_rate[1], + mcs_nss2[index].ht20_rate[0], + mcs_nss2[index].ht20_rate[1]); + if (match_rate) { + *mcsRateFlag = 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 && is_sgi == true) + *mcsRateFlag |= TX_RATE_SGI; + + WMA_LOGD("%s - match_rate: %d index: %d rate_flag: 0x%x is_sgi: %d", + __func__, match_rate, index, *mcsRateFlag, is_sgi); + + return match_rate ? index : INVALID_MCS_IDX; +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * wma_peek_vdev_req() - peek what request message is queued for response. + * the function does not delete the node after found + * @wma: WMA handle + * @vdev_id: vdev ID + * @type: request message type + * + * Return: the request message found + */ +static struct wma_target_req *wma_peek_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *node1 = NULL, *node2 = NULL; + + qdf_spin_lock_bh(&wma->vdev_respq_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->vdev_resp_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + 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; + break; + } while (QDF_STATUS_SUCCESS == qdf_list_peek_next(&wma->vdev_resp_queue, + node1, &node2)); + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + if (!found) { + WMA_LOGE(FL("target request not found for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + WMA_LOGD(FL("target request found for vdev id: %d type %d msg %d"), + vdev_id, type, req_msg->msg_type); + return req_msg; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +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}; + + /* 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)) { + lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info)); + if (NULL == lost_link_info) { + WMA_LOGE("%s: failed to allocate memory", __func__); + 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; + WMA_LOGD("%s: post msg to SME, bss_idx %d, rssi %d", __func__, + lost_link_info->vdev_id, lost_link_info->rssi); + + 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_LOGE("%s: fail to post msg to SME", __func__); + 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 commmand 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_LOGE(FL("smps mode cannot be mapped :%d "), + smps_mode); + } + return param; +} + +#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) +{ + 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_LOGD("%s: Posting stats ext event to SME", __func__); + + param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid stats ext event buf", __func__); + 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_LOGE("Excess data_len:%d, num_data:%d", + stats_ext_info->data_len, param_buf->num_data); + return -EINVAL; + } + stats_ext_event = (tSirStatsExtEvent *) qdf_mem_malloc(alloc_len); + if (NULL == stats_ext_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + 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) { + WMA_LOGE("%s: Failed to post stats ext event to SME", __func__); + qdf_mem_free(stats_ext_event); + return -EFAULT; + } + + WMA_LOGD("%s: stats ext event Posted to SME", __func__); + return 0; +} +#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; + uint8_t *buf_ptr; + char temp_str[150]; + + param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid profile data event buf", __func__); + return -EINVAL; + } + profile_ctx = param_buf->profile_ctx; + buf_ptr = (uint8_t *)profile_ctx; + buf_ptr = buf_ptr + sizeof(wmi_wlan_profile_ctx_t) + WMI_TLV_HDR_SIZE; + profile_data = (wmi_wlan_profile_t *) buf_ptr; + entries = profile_ctx->bin_count; + + if (entries > param_buf->num_profile_data) { + WMA_LOGE("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]"); + + 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_LOGE(FL("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_LOGE("%s: 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", + __func__, 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 = (tSirLLStatsResults *)qdf_mem_malloc(buf_len); + if (buf == NULL) { + WMA_LOGE("%s: Cannot allocate link layer stats.", __func__); + buf_len = 0; + return NULL; + } + + *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 + * + * 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, 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_LOGE(FL("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_LOGE(FL("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_LOGE(FL("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_LOGE(FL("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_LOGE(FL("Invalid arg, peer_tx %pK, wmi_tx %pK stats %pK"), + wmi_peer_tx, wmi_tx, peer_stats); + 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_LOGE(FL("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 + * + * 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_LOGE(FL("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_LOGE(FL("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_LOGE(FL("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_LOGE(FL("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; + tpAniSirGlobal mac; + struct scheduler_msg sme_msg = { 0 }; + QDF_STATUS qdf_status; + + mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGD("%s: NULL mac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_ext_cb) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: Posting MAC counters event to HDD", __func__); + + param_buf = (WMI_REPORT_STATS_EVENTID_param_tlvs *)event; + if (!param_buf) { + WMA_LOGD("%s: param_buf is null", __func__); + return -EINVAL; + } + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + WMA_LOGD("%s: fixed_param is null", __func__); + 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_LOGE("%s: excess num_peer_signal_stats:%d, num_peer_ac_tx_stats:%d, num_peer_ac_rx_stats:%d", + __func__, 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_LOGE("%s: Fail to allocate stats buffer", __func__); + 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_LOGE("%s: result is null", __func__); + 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_LOGD("%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_LOGE(FL("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_LOGE(FL("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)) { + WMA_LOGP(FL("Failed to post peer stat change msg!")); + qdf_mem_free(link_stats_results); + return -EINVAL; + } + + return 0; +} + +/** + * 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) +{ + 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; + 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; + + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGD("%s: NULL mac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + 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_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__); + 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_LOGE("excess wmi buffer: rates:%d, peers:%d", + peer_stats->num_rates, fixed_param->num_peers); + return -EINVAL; + } + + peer_stats_size = sizeof(tSirWifiPeerStat); + peer_info_size = sizeof(tSirWifiPeerInfo); + rate_stats_size = sizeof(tSirWifiRateStat); + 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 (NULL == link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + 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 = 0; + 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); + + 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; + + /* Copy rate stats associated with this peer */ + for (count = 0; count < peer_stats->num_rates; count++) { + 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++; + } + + /* 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.pLinkLayerStatsIndCallback(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_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; + tSirWifiRadioStat *rs_results; + uint32_t i = 0; + + if (!wma_handle->link_stats_results) + return 0; + + rs_results = (tSirWifiRadioStat *) + &wma_handle->link_stats_results->results[0]; + for (i = 0; i < wma_handle->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++; + } + + qdf_mem_free(wma_handle->link_stats_results); + wma_handle->link_stats_results = NULL; + + 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; + 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; + tSirWifiRadioStat *rs_results; + uint32_t max_total_num_tx_power_levels = MAX_TPC_LEVELS * NUM_OF_BANDS * + MAX_SPATIAL_STREAM_ANY_V3; + + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid tx power level stats event", __func__); + return -EINVAL; + } + + fixed_param = param_tlvs->fixed_param; + if (!fixed_param) { + WMA_LOGA("%s:Invalid param_tlvs for Radio tx_power level Stats", + __func__); + return -EINVAL; + } + + link_stats_results = wma_handle->link_stats_results; + if (!link_stats_results) { + WMA_LOGA("%s: link_stats_results is NULL", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: tot_num_tx_pwr_lvls: %u num_tx_pwr_lvls: %u pwr_lvl_offset: %u radio_id: %u", + __func__, fixed_param->total_num_tx_power_levels, + fixed_param->num_tx_power_levels, + fixed_param->power_level_offset, + fixed_param->radio_id); + + 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_LOGE("%s: excess tx_power buffers:%d, num_tx_time_per_power_level:%d", + __func__, 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_LOGE("%s: Invalid radio_id %d num_radio %d", + __func__, 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_LOGD("Invalid total_num_tx_power_levels %d", + fixed_param->total_num_tx_power_levels); + return -EINVAL; + } + + rs_results = (tSirWifiRadioStat *) &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_LOGE("%s: excess tx_power buffers:%d, total_num_tx_power_levels:%d", + __func__, 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_LOGE("%s: Invalid offset %d total_num %d num %d", + __func__, 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) { + WMA_LOGA("%s: Mem alloc fail for tx power level stats", + __func__); + /* 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_LOGD("%s: moreResultToFollow: %u nr: %u nr_received: %u", + __func__, link_stats_results->moreResultToFollow, + link_stats_results->num_radio, + 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.pLinkLayerStatsIndCallback(mac->hdd_handle, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results, + mac->sme.ll_stats_context); + wma_unified_radio_tx_mem_free(handle); + + 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; + 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; + size_t radio_stats_size, chan_stats_size; + size_t link_stats_results_size; + tSirWifiRadioStat *rs_results; + tSirWifiChannelStats *chn_results; + + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGD("%s: NULL mac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + 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; + radio_stats = param_tlvs->radio_stats; + channel_stats = param_tlvs->channel_stats; + + if (!fixed_param || !radio_stats || + (radio_stats->num_channels && !channel_stats)) { + WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__); + return -EINVAL; + } + if (radio_stats->num_channels > + (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS) || + radio_stats->num_channels > param_tlvs->num_channel_stats) { + WMA_LOGE("%s: Too many channels %d", + __func__, radio_stats->num_channels); + return -EINVAL; + } + + radio_stats_size = sizeof(tSirWifiRadioStat); + chan_stats_size = sizeof(tSirWifiChannelStats); + if (fixed_param->num_radio > + (UINT_MAX - sizeof(*link_stats_results))/radio_stats_size) { + WMA_LOGE("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_LOGE("%s, invalid radio id:%d, num radio:%d", + __func__, radio_stats->radio_id, + fixed_param->num_radio); + return -EINVAL; + } + + if (!wma_handle->link_stats_results) { + wma_handle->link_stats_results = qdf_mem_malloc( + link_stats_results_size); + if (NULL == wma_handle->link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + 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_LOGE("Invalid following WMI_RADIO_LINK_STATS_EVENTID. Discarding this set"); + wma_unified_radio_tx_mem_free(handle); + return -EINVAL; + } + + WMA_LOGD("Radio stats Fixed Param:"); + WMA_LOGD("req_id: %u num_radio: %u more_radio_events: %u", + fixed_param->request_id, fixed_param->num_radio, + fixed_param->more_radio_events); + + WMA_LOGD("Radio Info: radio_id: %u on_time: %u tx_time: %u rx_time: %u on_time_scan: %u", + radio_stats->radio_id, radio_stats->on_time, + radio_stats->tx_time, radio_stats->rx_time, + radio_stats->on_time_scan); + WMA_LOGD("on_time_nbd: %u on_time_gscan: %u on_time_roam_scan: %u", + radio_stats->on_time_nbd, + radio_stats->on_time_gscan, radio_stats->on_time_roam_scan); + WMA_LOGD("on_time_pno_scan: %u on_time_hs20: %u num_channels: %u", + radio_stats->on_time_pno_scan, radio_stats->on_time_hs20, + radio_stats->num_channels); + WMA_LOGD("on_time_host_scan: %u, on_time_lpi_scan: %u", + radio_stats->on_time_host_scan, radio_stats->on_time_lpi_scan); + + link_stats_results->paramId = WMI_LINK_STATS_RADIO; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = 0; + 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; + + results = (uint8_t *) link_stats_results->results; + t_radio_stats = (uint8_t *) radio_stats; + t_channel_stats = (uint8_t *) channel_stats; + + rs_results = (tSirWifiRadioStat *) &results[0] + radio_stats->radio_id; + rs_results->radio = radio_stats->radio_id; + rs_results->onTime = radio_stats->on_time; + rs_results->txTime = radio_stats->tx_time; + rs_results->rxTime = radio_stats->rx_time; + rs_results->onTimeScan = radio_stats->on_time_scan; + rs_results->onTimeNbd = radio_stats->on_time_nbd; + rs_results->onTimeGscan = radio_stats->on_time_gscan; + rs_results->onTimeRoamScan = radio_stats->on_time_roam_scan; + rs_results->onTimePnoScan = radio_stats->on_time_pno_scan; + rs_results->onTimeHs20 = radio_stats->on_time_hs20; + 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; + } + if (rs_results->channels) { + qdf_mem_free(rs_results->channels); + rs_results->channels = NULL; + } + rs_results->numChannels = radio_stats->num_channels; + 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->numChannels) { + rs_results->channels = (tSirWifiChannelStats *) qdf_mem_malloc( + radio_stats->num_channels * + chan_stats_size); + if (rs_results->channels == NULL) { + WMA_LOGD("%s: could not allocate mem for channel stats (size=%zu)", + __func__, radio_stats->num_channels * chan_stats_size); + wma_unified_radio_tx_mem_free(handle); + return -ENOMEM; + } + + chn_results = (tSirWifiChannelStats *) &rs_results->channels[0]; + next_chan_offset = WMI_TLV_HDR_SIZE; + WMA_LOGD("Channel Stats Info"); + for (count = 0; count < radio_stats->num_channels; count++) { + WMA_LOGD("channel_width %u center_freq %u center_freq0 %u", + channel_stats->channel_width, + channel_stats->center_freq, + channel_stats->center_freq0); + WMA_LOGD("center_freq1 %u radio_awake_time %u cca_busy_time %u", + channel_stats->center_freq1, + channel_stats->radio_awake_time, + channel_stats->cca_busy_time); + 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 (link_stats_results->moreResultToFollow) { + /* More results coming, don't post yet */ + return 0; + } + 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.pLinkLayerStatsIndCallback(mac->hdd_handle, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results, + mac->sme.ll_stats_context); + wma_unified_radio_tx_mem_free(handle); + + return 0; +} + +#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; + tSirWifiPeerStat *peer_stat; + tSirWifiPeerInfo *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; + + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGD("%s: NULL mac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_ext_cb) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: Posting Peer Stats PS event to HDD", __func__); + + param_buf = (WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *)event; + fixed_param = param_buf->fixed_param; + + result_len = sizeof(tSirLLStatsResults) + + sizeof(tSirWifiPeerStat) + + sizeof(tSirWifiPeerInfo); + link_stats_results = qdf_mem_malloc(result_len); + if (link_stats_results == NULL) { + WMA_LOGE("%s: Cannot allocate link layer stats.", __func__); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_param->peer_macaddr, &mac_address[0]); + WMA_LOGD("Peer power state change event from FW"); + WMA_LOGD("Fixed Param:"); + WMA_LOGD("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 = (tSirWifiPeerStat *)link_stats_results->results; + peer_stat->numPeers = 1; + peer_info = (tSirWifiPeerInfo *)peer_stat->peerInfo; + qdf_mem_copy(&peer_info->peerMacAddress, + &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_LOGE("%s: Fail to post ps change ind msg", __func__); + 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 (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + 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_SERIALIZER_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_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_radio_link_stats_link, + wma_unified_link_radio_stats_event_handler, + WMA_RX_SERIALIZER_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_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_sta_ps_statechg_event_id, + wma_peer_ps_evt_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_report_stats_event_id, + wma_ll_stats_evt_handler, + WMA_RX_SERIALIZER_CTX); + +} + + +/** + * 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) +{ + struct ll_stats_clear_params cmd = {0}; + int ret; + + if (!clearReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma->interfaces[clearReq->staId].handle) { + WMA_LOGE("%s: vdev_id %d handle is NULL", + __func__, clearReq->staId); + return QDF_STATUS_E_FAILURE; + } + + cmd.stop_req = clearReq->stopReq; + cmd.sta_id = clearReq->staId; + cmd.stats_clear_mask = clearReq->statsClearReqMask; + + ret = wmi_unified_process_ll_stats_clear_cmd(wma->wmi_handle, &cmd, + wma->interfaces[clearReq->staId].addr); + if (ret) { + WMA_LOGE("%s: Failed to send clear link stats req", __func__); + 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_LOGE("%s: input pointer is NULL", __func__); + 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_LOGE("%s: Failed to send set link stats request", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * 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) +{ + struct ll_stats_get_params cmd = {0}; + int ret; + + if (!getReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma->interfaces[getReq->staId].vdev_active) { + WMA_LOGE("%s: vdev not created yet", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd.req_id = getReq->reqId; + cmd.param_id_mask = getReq->paramIdMask; + cmd.sta_id = getReq->staId; + + ret = wmi_unified_process_ll_stats_get_cmd(wma->wmi_handle, &cmd, + wma->interfaces[getReq->staId].addr); + if (ret) { + WMA_LOGE("%s: Failed to send get link stats request", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_unified_link_iface_stats_event_handler() - link iface stats event handler + * @wma: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) +{ + 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; + tSirLLStatsResults *link_stats_results; + tSirWifiIfaceStat *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; + + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGD("%s: NULL mac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + 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_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__); + return -EINVAL; + } + if (link_stats->num_ac > WIFI_AC_MAX || link_stats->num_ac > + param_tlvs->num_ac) { + WMA_LOGE("%s: Excess data received from firmware num_ac %d, param_tlvs->num_ac %d", + __func__, 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_LOGE("%s: Excess num offload stats recvd from fw: %d, um_iface_offload_stats: %d", + __func__, fixed_param->num_offload_stats, + param_tlvs->num_iface_offload_stats); + return -EINVAL; + } + + link_stats_size = sizeof(tSirWifiIfaceStat); + iface_info_size = sizeof(tSirWifiInterfaceInfo); + + 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(tSirWifiIfaceStat, 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) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + 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 tSirWifiIfaceStat in upper layer + * tSirWifiIfaceStat + * - tSirWifiInterfaceInfo (all fields except roaming is + * filled by host in the upper layer) + * - various members of tSirWifiIfaceStat (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 = (tSirWifiIfaceStat *)link_stats_results->results; + + iface_link_stats = &iface_stat->link_stats; + *iface_link_stats = *link_stats; + + /* Copy roaming state */ + iface_stat->info.roaming = link_stats->roam_state; + + 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++; + } + + /* 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.pLinkLayerStatsIndCallback(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 + * @threshold: threhold 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) +{ + 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_LOGE(FL("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) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + 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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGD(FL("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_LOGA("WMA --> WMI_PDEV_SET_STATS_THRESHOLD_CMDID(0x%x), length=%d", + WMI_PDEV_SET_STATS_THRESHOLD_CMDID, len); + if (EOK != wmi_unified_cmd_send(wma->wmi_handle, + buf, len, + WMI_PDEV_SET_STATS_THRESHOLD_CMDID)) { + WMA_LOGE("Failed to send WMI_PDEV_SET_STATS_THRESHOLD_CMDID"); + wmi_buf_free(buf); + } +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifndef QCA_SUPPORT_CP_STATS +/** + * wma_update_pdev_stats() - update pdev stats + * @wma: wma handle + * @pdev_stats: pdev stats + * + * Return: none + */ +static void wma_update_pdev_stats(tp_wma_handle wma, + wmi_pdev_stats *pdev_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + uint32_t temp_mask; + uint8_t *stats_buf; + tCsrGlobalClassAStatsInfo *classa_stats = NULL; + struct wma_txrx_node *node; + uint8_t i; + + for (i = 0; i < wma->max_bssid; i++) { + node = &wma->interfaces[i]; + stats_rsp_params = node->stats_rsp; + if (stats_rsp_params) { + node->fw_stats_set |= FW_PDEV_STATS_SET; + WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", i); + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassAStats)) { + classa_stats = + (tCsrGlobalClassAStatsInfo *) stats_buf; + classa_stats->max_pwr = pdev_stats->chan_tx_pwr; + } + } + } +} + +/** + * wma_vdev_stats_lost_link_helper() - helper function to extract + * lost link information from vdev statistics event while deleting BSS. + * @wma: WMA handle + * @vdev_stats: statistics information from firmware + * + * This is for informing HDD to collect lost link information while + * disconnection. Following conditions to check + * 1. vdev is up + * 2. bssid is zero. When handling DELETE_BSS request message, it sets bssid to + * zero, hence add the check here to indicate the event comes during deleting + * BSS + * 3. DELETE_BSS is the request message queued. Put this condition check on the + * last one as it consumes more resource searching entries in the list + * + * Return: none + */ +static void wma_vdev_stats_lost_link_helper(tp_wma_handle wma, + wmi_vdev_stats *vdev_stats) +{ + struct wma_txrx_node *node; + int32_t rssi; + struct wma_target_req *req_msg; + static const uint8_t zero_mac[QDF_MAC_ADDR_SIZE] = {0}; + int32_t bcn_snr, dat_snr; + + if (vdev_stats->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %hu", + __func__, vdev_stats->vdev_id); + return; + } + + node = &wma->interfaces[vdev_stats->vdev_id]; + if (wma_is_vdev_up(vdev_stats->vdev_id) && + !qdf_mem_cmp(node->bssid, zero_mac, QDF_MAC_ADDR_SIZE)) { + req_msg = wma_peek_vdev_req(wma, vdev_stats->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + if ((NULL == req_msg) || + (WMA_DELETE_BSS_REQ != req_msg->msg_type)) { + WMA_LOGD(FL("cannot find DELETE_BSS request message")); + return; + } + bcn_snr = vdev_stats->vdev_snr.bcn_snr; + dat_snr = vdev_stats->vdev_snr.dat_snr; + WMA_LOGD(FL("get vdev id %d, beancon snr %d, data snr %d"), + vdev_stats->vdev_id, bcn_snr, dat_snr); + + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) + rssi = bcn_snr; + else if (WMA_TGT_IS_VALID_SNR(dat_snr)) + rssi = dat_snr; + else + rssi = WMA_TGT_INVALID_SNR; + + /* Get the absolute rssi value from the current rssi value */ + rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; + wma_lost_link_info_handler(wma, vdev_stats->vdev_id, rssi); + } +} + +/** + * wma_update_vdev_stats() - update vdev stats + * @wma: wma handle + * @vdev_stats: vdev stats + * + * Return: none + */ +static void wma_update_vdev_stats(tp_wma_handle wma, + wmi_vdev_stats *vdev_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + tCsrSummaryStatsInfo *summary_stats = NULL; + uint8_t *stats_buf; + struct wma_txrx_node *node; + uint8_t i; + int32_t rssi = 0; + QDF_STATUS qdf_status; + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) wma->pGetRssiReq; + struct scheduler_msg sme_msg = { 0 }; + int32_t bcn_snr, dat_snr; + + if (vdev_stats->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %hu", + __func__, vdev_stats->vdev_id); + return; + } + + bcn_snr = vdev_stats->vdev_snr.bcn_snr; + dat_snr = vdev_stats->vdev_snr.dat_snr; + WMA_LOGD("vdev id %d beancon snr %d data snr %d", + vdev_stats->vdev_id, bcn_snr, dat_snr); + + node = &wma->interfaces[vdev_stats->vdev_id]; + stats_rsp_params = node->stats_rsp; + if (stats_rsp_params) { + stats_buf = (uint8_t *) (stats_rsp_params + 1); + node->fw_stats_set |= FW_VDEV_STATS_SET; + WMA_LOGD("<---FW VDEV STATS received for vdevId:%d", + vdev_stats->vdev_id); + if (stats_rsp_params->statsMask & (1 << eCsrSummaryStats)) { + summary_stats = (tCsrSummaryStatsInfo *) stats_buf; + for (i = 0; i < 4; i++) { + summary_stats->tx_frm_cnt[i] = + vdev_stats->tx_frm_cnt[i]; + summary_stats->fail_cnt[i] = + vdev_stats->fail_cnt[i]; + summary_stats->multiple_retry_cnt[i] = + vdev_stats->multiple_retry_cnt[i]; + } + + summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt; + summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt; + summary_stats->rx_discard_cnt = + vdev_stats->rx_discard_cnt; + summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt; + summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt; + summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt; + /* Update SNR and RSSI in SummaryStats */ + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) { + summary_stats->snr = bcn_snr; + summary_stats->rssi = + bcn_snr + WMA_TGT_NOISE_FLOOR_DBM; + } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) { + summary_stats->snr = dat_snr; + summary_stats->rssi = + dat_snr + WMA_TGT_NOISE_FLOOR_DBM; + } else { + summary_stats->snr = WMA_TGT_INVALID_SNR; + summary_stats->rssi = 0; + } + } + } + + if (pGetRssiReq && pGetRssiReq->sessionId == vdev_stats->vdev_id) { + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) { + rssi = bcn_snr; + rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; + } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) { + rssi = dat_snr; + rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; + } else { + /* + * Firmware sends invalid snr till it sees + * Beacon/Data after connection since after + * vdev up fw resets the snr to invalid. + * In this duartion Host will return the last know + * rssi during connection. + */ + WMA_LOGE("Invalid SNR from firmware"); + } + + WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi, + pGetRssiReq->sessionId); + + /* update the average rssi value to UMAC layer */ + if (NULL != pGetRssiReq->rssiCallback) { + ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))(rssi, + pGetRssiReq->staId, + pGetRssiReq->pDevContext); + } + + qdf_mem_free(pGetRssiReq); + wma->pGetRssiReq = NULL; + } + + if (node->psnr_req) { + tAniGetSnrReq *p_snr_req = node->psnr_req; + + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) + p_snr_req->snr = bcn_snr; + else if (WMA_TGT_IS_VALID_SNR(dat_snr)) + p_snr_req->snr = dat_snr; + else + p_snr_req->snr = WMA_TGT_INVALID_SNR; + + sme_msg.type = eWNI_SME_SNR_IND; + sme_msg.bodyptr = p_snr_req; + 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_LOGE("%s: Fail to post snr ind msg", __func__); + qdf_mem_free(p_snr_req); + } + + node->psnr_req = NULL; + } + wma_vdev_stats_lost_link_helper(wma, vdev_stats); +} + +/** + * wma_post_stats() - update stats to PE + * @wma: wma handle + * @node: txrx node + * + * Return: none + */ +static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node) +{ + /* send response to UMAC */ + wma_send_msg(wma, WMA_GET_STATISTICS_RSP, node->stats_rsp, 0); + node->stats_rsp = NULL; + node->fw_stats_set = 0; +} + +/** + * wma_update_peer_stats() - update peer stats + * @wma: wma handle + * @peer_stats: peer stats + * + * Return: none + */ +static void wma_update_peer_stats(tp_wma_handle wma, + wmi_peer_stats *peer_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + tCsrGlobalClassAStatsInfo *classa_stats = NULL; + struct wma_txrx_node *node; + uint8_t *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags; + uint32_t temp_mask; + uint8_t nss; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]); + if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id)) + return; + + node = &wma->interfaces[vdev_id]; + stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; + if (stats_rsp_params) { + node->fw_stats_set |= FW_PEER_STATS_SET; + WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id); + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassAStats)) { + classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf; + WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate); + WMA_LOGD("peer rx rate:%d", peer_stats->peer_rx_rate); + /* The linkspeed returned by fw is in kbps so convert + * it in to units of 500kbps which is expected by UMAC + */ + if (peer_stats->peer_tx_rate) { + classa_stats->tx_rate = + peer_stats->peer_tx_rate / 500; + } + + if (peer_stats->peer_rx_rate) { + classa_stats->rx_rate = + peer_stats->peer_rx_rate / 500; + } + classa_stats->tx_rx_rate_flags = node->rate_flags; + if (!(node->rate_flags & TX_RATE_LEGACY)) { + nss = node->nss; + classa_stats->tx_mcs_index = + wma_get_mcs_idx( + (peer_stats->peer_tx_rate / + 100), node->rate_flags, + &nss, &mcsRateFlags); + classa_stats->tx_nss = nss; + classa_stats->tx_mcs_rate_flags = mcsRateFlags; + } + if (!(node->rate_flags & TX_RATE_LEGACY)) { + nss = node->nss; + classa_stats->rx_mcs_index = + wma_get_mcs_idx( + (peer_stats->peer_rx_rate / + 100), node->rate_flags, + &nss, &mcsRateFlags); + classa_stats->rx_nss = nss; + classa_stats->rx_mcs_rate_flags = mcsRateFlags; + } + + /* FW returns tx power in intervals of 0.5 dBm + * Convert it back to intervals of 1 dBm + */ + classa_stats->max_pwr = + roundup(classa_stats->max_pwr, 2) >> 1; + } + } +} +#endif /* WMA_GET_STATISTICS_RSP */ + +/** + * 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_LOGE("%s: Fail to post link status ind msg", __func__); + qdf_mem_free(pGetLinkStatus); + } +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * wma_update_per_chain_rssi_stats() - to store per chain rssi stats + * @wma: wma handle + * @rssi_stats: rssi stats + * @rssi_per_chain_stats: buffer where rssi stats to be stored + * + * This function stores per chain rssi stats received from fw for all vdevs for + * which the stats were requested into a csr stats structure. + * + * Return: void + */ +static void wma_update_per_chain_rssi_stats(tp_wma_handle wma, + wmi_rssi_stats *rssi_stats, + struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats) +{ + int i; + int32_t bcn_snr, dat_snr; + + for (i = 0; i < NUM_CHAINS_MAX; i++) { + bcn_snr = rssi_stats->rssi_avg_beacon[i]; + dat_snr = rssi_stats->rssi_avg_data[i]; + WMA_LOGD("chain %d beacon snr %d data snr %d", + i, bcn_snr, dat_snr); + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) + rssi_per_chain_stats->rssi[i] = bcn_snr; + else if (WMA_TGT_IS_VALID_SNR(dat_snr)) + rssi_per_chain_stats->rssi[i] = dat_snr; + else + /* + * Firmware sends invalid snr till it sees + * Beacon/Data after connection since after + * vdev up fw resets the snr to invalid. + * In this duartion Host will return an invalid rssi + * value. + */ + rssi_per_chain_stats->rssi[i] = WMA_TGT_INVALID_SNR; + + /* + * Get the absolute rssi value from the current rssi value the + * sinr value is hardcoded into 0 in the qcacld-new/CORE stack + */ + rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr), + rssi_per_chain_stats->peer_mac_addr); + } +} + +/** + * wma_update_rssi_stats() - to update rssi stats for all vdevs + * for which the stats were requested. + * @wma: wma handle + * @rssi_stats: rssi stats + * + * This function updates the rssi stats for all vdevs for which + * the stats were requested. + * + * Return: void + */ +static void wma_update_rssi_stats(tp_wma_handle wma, + wmi_rssi_stats *rssi_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL; + struct wma_txrx_node *node; + uint8_t *stats_buf; + uint32_t temp_mask; + uint8_t vdev_id; + + if (rssi_stats->vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %hu", + __func__, rssi_stats->vdev_id); + return; + } + + vdev_id = rssi_stats->vdev_id; + node = &wma->interfaces[vdev_id]; + stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; + if (stats_rsp_params) { + node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET; + WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d", + vdev_id); + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassAStats)) + stats_buf += sizeof(tCsrGlobalClassAStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassDStats)) + stats_buf += sizeof(tCsrGlobalClassDStatsInfo); + + if (temp_mask & (1 << csr_per_chain_rssi_stats)) { + rssi_per_chain_stats = + (struct csr_per_chain_rssi_stats_info *)stats_buf; + wma_update_per_chain_rssi_stats(wma, rssi_stats, + rssi_per_chain_stats); + } + } +} +#endif /* QCA_SUPPORT_CP_STATS */ + +/** + * 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) +{ + 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; + + param_buf = + (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + 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; + + WMA_LOGD("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_LOGE("%s: excess vdev_stats buffers:%d, num_ht_info:%d", + __func__, event->num_vdev_stats, + param_buf->num_ht_info); + return -EINVAL; + } + for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) { + WMA_LOGD("%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d", + __func__, 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 (intr[ht_info->vdevid].rate_flags & + (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(wmi_roam_event_fixed_param *wmi_event) +{ + 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) { + WMA_LOGE("%s: malloc fails for rso cmd status", __func__); + return -ENOMEM; + } + + rso_status->vdev_id = wmi_event->vdev_id; + if (WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS == wmi_event->notif) + rso_status->status = true; + else if (WMI_ROAM_NOTIF_SCAN_MODE_FAIL == wmi_event->notif) + rso_status->status = false; + sme_msg.type = eWNI_SME_RSO_CMD_STATUS_IND; + sme_msg.bodyptr = rso_status; + sme_msg.bodyval = 0; + WMA_LOGD("%s: Post RSO cmd status to SME", __func__); + + 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_LOGE("%s: fail to post RSO cmd status to SME", __func__); + qdf_mem_free(rso_status); + } + return 0; +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * wma_handle_sta_peer_info() - handle peer information in + * peer stats + * @num_peer_stats: peer number + * @peer_stats: peer stats received from firmware + * @peer_macaddr: the specified mac address + * @sapaddr: sap mac address + * + * This function will send eWNI_SME_GET_PEER_INFO_IND + * to sme with stations' information + * + */ +static void wma_handle_sta_peer_info(uint32_t num_peer_stats, + wmi_peer_stats *peer_stats, + struct qdf_mac_addr peer_macaddr, + uint8_t *sapaddr) +{ + QDF_STATUS qdf_status; + wmi_mac_addr temp_addr; + struct sir_peer_info_resp *peer_info; + struct scheduler_msg sme_msg = {0}; + uint32_t i; + uint32_t j = 0; + + if (!qdf_is_macaddr_broadcast(&peer_macaddr)) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_macaddr.bytes, &temp_addr); + for (i = 0; i < num_peer_stats; i++) { + if ((((temp_addr.mac_addr47to32) & 0x0000ffff) == + ((peer_stats->peer_macaddr.mac_addr47to32) & + 0x0000ffff)) + && (temp_addr.mac_addr31to0 == + peer_stats->peer_macaddr.mac_addr31to0)) { + + break; + } + peer_stats = peer_stats + 1; + } + peer_info = qdf_mem_malloc(sizeof(*peer_info) + + sizeof(peer_info->info[0])); + if (NULL == peer_info) { + WMA_LOGE("%s: Memory allocation failed.", __func__); + return; + } + if (i < num_peer_stats) { + peer_info->count = 1; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr), + peer_info->info[0].peer_macaddr.bytes); + peer_info->info[0].rssi = peer_stats->peer_rssi; + peer_info->info[0].tx_rate = peer_stats->peer_tx_rate; + peer_info->info[0].rx_rate = peer_stats->peer_rx_rate; + WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d", + __func__, + peer_info->info[0].peer_macaddr.bytes, + peer_stats->peer_rssi, + peer_stats->peer_tx_rate, + peer_stats->peer_rx_rate); + } else { + WMA_LOGE("%s: no match mac address", __func__); + peer_info->count = 0; + } + } else { + peer_info = qdf_mem_malloc(sizeof(*peer_info) + + num_peer_stats * sizeof(peer_info->info[0])); + if (NULL == peer_info) { + WMA_LOGE("%s: Memory allocation failed.", __func__); + return; + } + peer_info->count = num_peer_stats; + + for (i = 0; i < num_peer_stats; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&(peer_stats->peer_macaddr), + peer_info->info[j].peer_macaddr.bytes); + peer_info->info[j].rssi = peer_stats->peer_rssi; + peer_info->info[j].tx_rate = peer_stats->peer_tx_rate; + peer_info->info[j].rx_rate = peer_stats->peer_rx_rate; + WMA_LOGD("%s peer %pM rssi %d tx_rate %d rx_rate %d", + __func__, + peer_info->info[j].peer_macaddr.bytes, + peer_stats->peer_rssi, + peer_stats->peer_tx_rate, + peer_stats->peer_rx_rate); + if (!qdf_mem_cmp(peer_info->info[j].peer_macaddr.bytes, + sapaddr, QDF_MAC_ADDR_SIZE)) { + peer_info->count = peer_info->count - 1; + } else { + j++; + } + peer_stats = peer_stats + 1; + } + WMA_LOGD("WDA send peer num %d", peer_info->count); + } + + sme_msg.type = eWNI_SME_GET_PEER_INFO_IND; + sme_msg.bodyptr = peer_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_LOGE("%s: Fail to post get rssi msg", __func__); + qdf_mem_free(peer_info); + } + + return; +} + +/** + * wma_stats_event_handler() - stats event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *event; + wmi_pdev_stats *pdev_stats; + wmi_vdev_stats *vdev_stats; + wmi_peer_stats *peer_stats; + wmi_rssi_stats *rssi_stats; + wmi_per_chain_rssi_stats *rssi_event; + struct wma_txrx_node *node; + uint8_t *temp; + uint32_t i; + uint32_t buf_len = 0; + bool excess_data = false; + wmi_congestion_stats *congestion_stats; + tpAniSirGlobal mac; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + temp = (uint8_t *) param_buf->data; + + do { + if (event->num_pdev_stats > ((WMI_SVC_MSG_MAX_SIZE - + sizeof(*event)) / sizeof(*pdev_stats))) { + excess_data = true; + break; + } else { + buf_len += event->num_pdev_stats * sizeof(*pdev_stats); + } + + if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE - + sizeof(*event)) / sizeof(*vdev_stats))) { + excess_data = true; + break; + } else { + buf_len += event->num_vdev_stats * sizeof(*vdev_stats); + } + + if (event->num_peer_stats > ((WMI_SVC_MSG_MAX_SIZE - + sizeof(*event)) / sizeof(*peer_stats))) { + excess_data = true; + break; + } else { + buf_len += event->num_peer_stats * sizeof(*peer_stats); + } + + if (buf_len > param_buf->num_data) { + WMA_LOGE("%s: num_data: %d Invalid num_pdev_stats:%d or num_vdev_stats:%d or num_peer_stats:%d", + __func__, param_buf->num_data, + event->num_pdev_stats, + event->num_vdev_stats, event->num_peer_stats); + return -EINVAL; + } + + rssi_event = + (wmi_per_chain_rssi_stats *) param_buf->chain_stats; + if (rssi_event) { + if (rssi_event->num_per_chain_rssi_stats > + ((WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) / + sizeof(*rssi_event))) { + excess_data = true; + break; + } else { + buf_len += sizeof(*rssi_event) * + rssi_event->num_per_chain_rssi_stats; + } + } + } while (0); + + if (excess_data || + (buf_len > WMI_SVC_MSG_MAX_SIZE - sizeof(*event))) { + WMA_LOGE("excess wmi buffer: stats pdev %d vdev %d peer %d", + event->num_pdev_stats, event->num_vdev_stats, + event->num_peer_stats); + return -EINVAL; + } + + if (event->num_pdev_stats > 0) { + for (i = 0; i < event->num_pdev_stats; i++) { + pdev_stats = (wmi_pdev_stats *) temp; + wma_update_pdev_stats(wma, pdev_stats); + temp += sizeof(wmi_pdev_stats); + } + } + + if (event->num_vdev_stats > 0) { + for (i = 0; i < event->num_vdev_stats; i++) { + vdev_stats = (wmi_vdev_stats *) temp; + wma_update_vdev_stats(wma, vdev_stats); + temp += sizeof(wmi_vdev_stats); + } + } + + if (event->num_peer_stats > 0) { + if (wma->get_sta_peer_info == true) { + wma_handle_sta_peer_info(event->num_peer_stats, + (wmi_peer_stats *)temp, + wma->peer_macaddr, + wma->myaddr); + } else { + for (i = 0; i < event->num_peer_stats; i++) { + peer_stats = (wmi_peer_stats *) temp; + wma_update_peer_stats(wma, peer_stats); + temp += sizeof(wmi_peer_stats); + } + } + } + + rssi_event = (wmi_per_chain_rssi_stats *) param_buf->chain_stats; + if (rssi_event) { + if (rssi_event->num_per_chain_rssi_stats > + param_buf->num_rssi_stats) { + WMA_LOGE("%s: Invalid num_per_chain_rssi_stats:%d", + __func__, rssi_event->num_per_chain_rssi_stats); + return -EINVAL; + } + if (((rssi_event->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) && + ((rssi_event->tlv_header & 0x0000FFFF) == + WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats))) { + if (rssi_event->num_per_chain_rssi_stats > 0) { + temp = (uint8_t *) rssi_event; + temp += sizeof(*rssi_event); + + /* skip past struct array tlv header */ + temp += WMI_TLV_HDR_SIZE; + + for (i = 0; + i < rssi_event->num_per_chain_rssi_stats; + i++) { + rssi_stats = (wmi_rssi_stats *)temp; + wma_update_rssi_stats(wma, rssi_stats); + temp += sizeof(wmi_rssi_stats); + } + } + } + } + + congestion_stats = (wmi_congestion_stats *) param_buf->congestion_stats; + if (congestion_stats) { + if (((congestion_stats->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_congestion_stats) && + ((congestion_stats->tlv_header & 0x0000FFFF) == + WMITLV_GET_STRUCT_TLVLEN(wmi_congestion_stats))) { + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGE("%s: Invalid mac", __func__); + return -EINVAL; + } + if (!mac->sme.congestion_cb) { + WMA_LOGE("%s: Callback not registered", + __func__); + return -EINVAL; + } + WMA_LOGI("%s: congestion %d", __func__, + congestion_stats->congestion); + mac->sme.congestion_cb(mac->hdd_handle, + congestion_stats->congestion, + congestion_stats->vdev_id); + } + } + + for (i = 0; i < wma->max_bssid; i++) { + node = &wma->interfaces[i]; + if (node->fw_stats_set & FW_PEER_STATS_SET) + wma_post_stats(wma, node); + } + + return 0; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +/** + * wma_fill_peer_info() - fill SIR peer info from WMI peer info struct + * @wma: wma interface + * @stats_info: WMI peer info pointer + * @peer_info: SIR peer info pointer + * + * This function will fill SIR peer info from WMI peer info struct + * + * Return: None + */ +static void wma_fill_peer_info(tp_wma_handle wma, + wmi_peer_stats_info *stats_info, + struct sir_peer_info_ext *peer_info) +{ + peer_info->tx_packets = stats_info->tx_packets.low_32; + peer_info->tx_bytes = stats_info->tx_bytes.high_32; + peer_info->tx_bytes <<= 32; + peer_info->tx_bytes += stats_info->tx_bytes.low_32; + peer_info->rx_packets = stats_info->rx_packets.low_32; + peer_info->rx_bytes = stats_info->rx_bytes.high_32; + peer_info->rx_bytes <<= 32; + peer_info->rx_bytes += stats_info->rx_bytes.low_32; + peer_info->tx_retries = stats_info->tx_retries; + peer_info->tx_failed = stats_info->tx_failed; + peer_info->rssi = stats_info->peer_rssi; + peer_info->tx_rate = stats_info->last_tx_bitrate_kbps; + peer_info->tx_rate_code = stats_info->last_tx_rate_code; + peer_info->rx_rate = stats_info->last_rx_bitrate_kbps; + peer_info->rx_rate_code = stats_info->last_rx_rate_code; +} + +/** + * wma_peer_info_ext_rsp() - process peer ext info ext + * @handle: wma interface + * @buf: wmi event buf pointer + * + * This function will send eWNI_SME_GET_PEER_INFO_EXT_IND to SME + * + * Return: 0 on success, error code otherwise + */ +static QDF_STATUS wma_peer_info_ext_rsp(tp_wma_handle wma, u_int8_t *buf) +{ + wmi_peer_stats_info_event_fixed_param *event; + wmi_peer_stats_info *stats_info; + struct sir_peer_info_ext_resp *resp; + struct sir_peer_info_ext *peer_info; + struct scheduler_msg sme_msg = {0}; + int i, j = 0; + QDF_STATUS qdf_status; + + event = (wmi_peer_stats_info_event_fixed_param *)buf; + stats_info = (wmi_peer_stats_info *)(buf + + sizeof(wmi_peer_stats_info_event_fixed_param)); + + if (wma->get_one_peer_info) { + resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) + + sizeof(resp->info[0])); + if (!resp) { + WMA_LOGE(FL("resp allocation failed.")); + return QDF_STATUS_E_NOMEM; + } + resp->count = 0; + peer_info = &resp->info[0]; + for (i = 0; i < event->num_peers; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr, + peer_info->peer_macaddr.bytes); + + if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes, + wma->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE)) { + wma_fill_peer_info(wma, stats_info, peer_info); + resp->count++; + break; + } + + stats_info = stats_info + 1; + } + } else { + resp = qdf_mem_malloc(sizeof(struct sir_peer_info_ext_resp) + + event->num_peers * sizeof(resp->info[0])); + if (!resp) { + WMA_LOGE(FL("resp allocation failed.")); + return QDF_STATUS_E_NOMEM; + } + resp->count = event->num_peers; + for (i = 0; i < event->num_peers; i++) { + peer_info = &resp->info[j]; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats_info->peer_macaddr, + peer_info->peer_macaddr.bytes); + + if (!qdf_mem_cmp(peer_info->peer_macaddr.bytes, + wma->myaddr, QDF_MAC_ADDR_SIZE)) { + resp->count = resp->count - 1; + } else { + wma_fill_peer_info(wma, stats_info, peer_info); + j++; + } + stats_info = stats_info + 1; + } + } + + sme_msg.type = eWNI_SME_GET_PEER_INFO_EXT_IND; + sme_msg.bodyptr = resp; + 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_LOGE("%s: Fail to post get peer info msg", __func__); + qdf_mem_free(resp); + } + + return qdf_status; +} + +/** + * dump_peer_stats_info() - dump wmi peer info struct + * @event: wmi peer info fixed param pointer + * @peer_stats: wmi peer stats info pointer + * + * This function will dump wmi peer info struct + * + * Return: None + */ +static void dump_peer_stats_info(wmi_peer_stats_info_event_fixed_param *event, + wmi_peer_stats_info *peer_stats) +{ + int i; + wmi_peer_stats_info *stats = peer_stats; + u_int8_t mac[6]; + + WMA_LOGI("%s vdev_id %d, num_peers %d more_data %d", + __func__, event->vdev_id, + event->num_peers, event->more_data); + + for (i = 0; i < event->num_peers; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac); + WMA_LOGI("%s mac %pM", __func__, mac); + WMA_LOGI("%s tx_bytes %d %d tx_packets %d %d", + __func__, + stats->tx_bytes.low_32, + stats->tx_bytes.high_32, + stats->tx_packets.low_32, + stats->tx_packets.high_32); + WMA_LOGI("%s rx_bytes %d %d rx_packets %d %d", + __func__, + stats->rx_bytes.low_32, + stats->rx_bytes.high_32, + stats->rx_packets.low_32, + stats->rx_packets.high_32); + WMA_LOGI("%s tx_retries %d tx_failed %d", + __func__, stats->tx_retries, stats->tx_failed); + WMA_LOGI("%s tx_rate_code %x rx_rate_code %x", + __func__, + stats->last_tx_rate_code, + stats->last_rx_rate_code); + WMA_LOGI("%s tx_rate %x rx_rate %x", + __func__, + stats->last_tx_bitrate_kbps, + stats->last_rx_bitrate_kbps); + WMA_LOGI("%s peer_rssi %d", __func__, stats->peer_rssi); + stats++; + } +} + +int wma_peer_info_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf; + wmi_peer_stats_info_event_fixed_param *event; + u_int32_t buf_size; + u_int8_t *buf; + + param_buf = + (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + WMA_LOGI("%s Recv WMI_PEER_STATS_INFO_EVENTID", __func__); + event = param_buf->fixed_param; + if (event->num_peers > + ((WMI_SVC_MSG_MAX_SIZE - + sizeof(wmi_peer_stats_info_event_fixed_param))/ + sizeof(wmi_peer_stats_info)) || event->num_peers > + param_buf->num_peer_stats_info) { + WMA_LOGE("Excess num of peers from fw: %d, num_peer_stats_info:%d", + event->num_peers, param_buf->num_peer_stats_info); + return -EINVAL; + } + buf_size = sizeof(wmi_peer_stats_info_event_fixed_param) + + sizeof(wmi_peer_stats_info) * event->num_peers; + buf = qdf_mem_malloc(buf_size); + if (!buf) { + WMA_LOGE("%s: Failed alloc memory for buf", __func__); + return -ENOMEM; + } + + qdf_mem_copy(buf, param_buf->fixed_param, + sizeof(wmi_peer_stats_info_event_fixed_param)); + qdf_mem_copy((buf + sizeof(wmi_peer_stats_info_event_fixed_param)), + param_buf->peer_stats_info, + sizeof(wmi_peer_stats_info) * event->num_peers); + WMA_LOGI("%s dump peer stats info", __func__); + dump_peer_stats_info(event, param_buf->peer_stats_info); + + wma_peer_info_ext_rsp(wma, buf); + qdf_mem_free(buf); + + 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) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx; + tSirLinkSpeedInfo *ls_ind; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return QDF_STATUS_E_INVAL; + } + + ls_ind = (tSirLinkSpeedInfo *)qdf_mem_malloc(sizeof(tSirLinkSpeedInfo)); + if (!ls_ind) { + WMA_LOGE("%s: Memory allocation failed.", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + } else { + ls_ind->estLinkSpeed = link_speed; + if (mac_ctx->sme.pLinkSpeedIndCb) + mac_ctx->sme.pLinkSpeedIndCb(ls_ind, + mac_ctx->sme.pLinkSpeedCbContext); + else + WMA_LOGD("%s: pLinkSpeedIndCb is null", __func__); + qdf_mem_free(ls_ind); + + } + return qdf_status; +} + +/** + * 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_LOGE("%s: Invalid linkspeed event", __func__); + 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; +} + +/** + * wma_wni_cfg_dnld() - cfg download request + * @handle: wma handle + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + void *mac = cds_get_context(QDF_MODULE_ID_PE); + + WMA_LOGD("%s: Enter", __func__); + + if (NULL == mac) { + WMA_LOGE("%s: Invalid context", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + process_cfg_download_req(mac); + + WMA_LOGD("%s: Exit", __func__); + return qdf_status; +} + +#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_LOGE("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_LOGE("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_LOGE("%s Invalid data len %d, limiting to max", + __func__, datalen); + datalen = BIG_ENDIAN_MAX_DEBUG_BUF - 1; + } + char dbgbuf[BIG_ENDIAN_MAX_DEBUG_BUF] = { 0 }; + + memcpy(dbgbuf, data, datalen); + SWAPME(dbgbuf, datalen); + WMA_LOGD("FIRMWARE:%s", dbgbuf); + return 0; + } +#else + WMA_LOGD("FIRMWARE:%s", data); + return 0; +#endif /* BIG_ENDIAN_HOST */ +} + +/** + * wma_is_sap_active() - check sap is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_sap_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_is_vdev_up(i)) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP && + wma_handle->interfaces[i].sub_type == 0) + return true; + } + return false; +} + +/** + * wma_is_p2p_go_active() - check p2p go is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_p2p_go_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_is_vdev_up(i)) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP && + wma_handle->interfaces[i].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) + return true; + } + return false; +} + +/** + * wma_is_p2p_cli_active() - check p2p cli is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_p2p_cli_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_is_vdev_up(i)) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA && + wma_handle->interfaces[i].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) + return true; + } + return false; +} + +/** + * wma_is_sta_active() - check sta is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_sta_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_is_vdev_up(i)) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA && + wma_handle->interfaces[i].sub_type == 0) + return true; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS) + return true; + } + return false; +} + +/** + * 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 + * + * Return: WLAN_PHY_MODE + */ +WLAN_PHY_MODE 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) +{ + WLAN_PHY_MODE phymode = MODE_UNKNOWN; + + switch (nw_type) { + case eSIR_11B_NW_TYPE: +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == sta_type) { + if (is_vht) { + if (CH_WIDTH_80MHZ == ch_width) + phymode = MODE_11AC_VHT80; + else + phymode = (CH_WIDTH_40MHZ == ch_width) ? + MODE_11AC_VHT40 : + MODE_11AC_VHT20; + } else if (is_ht) { + phymode = (CH_WIDTH_40MHZ == ch_width) ? + MODE_11NG_HT40 : MODE_11NG_HT20; + } else + phymode = MODE_11B; + } else +#endif /* FEATURE_WLAN_TDLS */ + { + phymode = MODE_11B; + if (is_ht || is_vht || is_he) + WMA_LOGE("HT/VHT is enabled with 11B NW type"); + } + break; + case eSIR_11G_NW_TYPE: + if (!(is_ht || is_vht || is_he)) { + phymode = MODE_11G; + break; + } + if (CH_WIDTH_40MHZ < ch_width) + WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz"); + if (ch_width) { +#if SUPPORT_11AX + phymode = (is_he) ? MODE_11AX_HE40_2G : (is_vht) ? + MODE_11AC_VHT40_2G : MODE_11NG_HT40; +#else + phymode = (is_vht) ? MODE_11AC_VHT40_2G : + MODE_11NG_HT40; +#endif + } else { +#if SUPPORT_11AX + phymode = (is_he) ? MODE_11AX_HE20_2G : (is_vht) ? + MODE_11AC_VHT20_2G : MODE_11NG_HT20; +#else + phymode = (is_vht) ? MODE_11AC_VHT20_2G : + MODE_11NG_HT20; +#endif + } + break; + case eSIR_11A_NW_TYPE: + if (!(is_ht || is_vht || is_he)) { + phymode = MODE_11A; + break; + } +#if SUPPORT_11AX + if (is_he) { + if (ch_width == CH_WIDTH_160MHZ) + phymode = MODE_11AX_HE160; + else if (ch_width == CH_WIDTH_80P80MHZ) + phymode = MODE_11AX_HE80_80; + else if (ch_width == CH_WIDTH_80MHZ) + phymode = MODE_11AX_HE80; + else + phymode = (ch_width) ? + MODE_11AX_HE40 : MODE_11AX_HE20; + } +#endif + else if (is_vht) { + if (ch_width == CH_WIDTH_160MHZ) + phymode = MODE_11AC_VHT160; + else if (ch_width == CH_WIDTH_80P80MHZ) + phymode = MODE_11AC_VHT80_80; + else if (ch_width == CH_WIDTH_80MHZ) + phymode = MODE_11AC_VHT80; + else + phymode = (ch_width) ? + MODE_11AC_VHT40 : MODE_11AC_VHT20; + } else + phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20; + break; + default: + WMA_LOGE("%s: Invalid nw type %d", __func__, nw_type); + break; + } + WMA_LOGD(FL("nw_type %d is_ht %d ch_width %d is_vht %d is_he %d phymode %d"), + nw_type, is_ht, ch_width, is_vht, is_he, 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; + struct cdp_vdev *vdev; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + WMA_LOGE("%s:SOC context is NULL", __func__); + return -EINVAL; + } + + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return -EINVAL; + } + qdf_mem_zero(&req, sizeof(req)); + req.stats_type_reset_mask = value; + cdp_fw_stats_get(soc, vdev, &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 + +#ifdef HELIUMPLUS +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_LOGE("%s: Not supported", __func__); + 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_LOGE("%s: Not supported", __func__); + 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; + struct cdp_vdev *vdev; + uint32_t l_up_mask; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + WMA_LOGE("%s:SOC context is NULL", __func__); + return -EINVAL; + } + + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + 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, &req, false, true); + + return 0; +} + +#ifndef QCA_SUPPORT_CP_STATS +/** + * wma_get_stats_rsp_buf() - fill get stats response buffer + * @get_stats_param: get stats parameters + * + * Return: stats response buffer + */ +static tAniGetPEStatsRsp *wma_get_stats_rsp_buf + (tAniGetPEStatsReq *get_stats_param) +{ + tAniGetPEStatsRsp *stats_rsp_params; + uint32_t len, temp_mask; + + len = sizeof(tAniGetPEStatsRsp); + temp_mask = get_stats_param->statsMask; + + if (temp_mask & (1 << eCsrSummaryStats)) + len += sizeof(tCsrSummaryStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassAStats)) + len += sizeof(tCsrGlobalClassAStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassDStats)) + len += sizeof(tCsrGlobalClassDStatsInfo); + + if (temp_mask & (1 << csr_per_chain_rssi_stats)) + len += sizeof(struct csr_per_chain_rssi_stats_info); + + stats_rsp_params = qdf_mem_malloc(len); + if (!stats_rsp_params) { + WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp"); + QDF_ASSERT(0); + return NULL; + } + + stats_rsp_params->staId = get_stats_param->staId; + stats_rsp_params->statsMask = get_stats_param->statsMask; + stats_rsp_params->msgType = WMA_GET_STATISTICS_RSP; + stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp); + stats_rsp_params->rc = QDF_STATUS_SUCCESS; + return stats_rsp_params; +} + +/** + * wma_get_stats_req() - get stats request + * @handle: wma handle + * @get_stats_param: stats params + * + * Return: none + */ +void wma_get_stats_req(WMA_HANDLE handle, + tAniGetPEStatsReq *get_stats_param) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wma_txrx_node *node; + struct stats_request_params cmd = {0}; + tAniGetPEStatsRsp *pGetPEStatsRspParams; + + + WMA_LOGD("%s: Enter", __func__); + node = &wma_handle->interfaces[get_stats_param->sessionId]; + if (node->stats_rsp) { + pGetPEStatsRspParams = node->stats_rsp; + if (pGetPEStatsRspParams->staId == get_stats_param->staId && + pGetPEStatsRspParams->statsMask == + get_stats_param->statsMask) { + WMA_LOGD("Stats for staId %d with stats mask %d is pending.. ignore new request", + get_stats_param->staId, + get_stats_param->statsMask); + pGetPEStatsRspParams = + wma_get_stats_rsp_buf(get_stats_param); + if (!pGetPEStatsRspParams) { + WMA_LOGE("failed to allocate memory for stats response"); + goto end; + } + goto req_pending; + } else { + qdf_mem_free(node->stats_rsp); + node->stats_rsp = NULL; + node->fw_stats_set = 0; + } + } + + pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param); + if (!pGetPEStatsRspParams) + goto end; + + node->fw_stats_set = 0; + if (node->stats_rsp) { + WMA_LOGD(FL("stats_rsp is not null, prev_value: %pK"), + node->stats_rsp); + qdf_mem_free(node->stats_rsp); + node->stats_rsp = NULL; + } + node->stats_rsp = pGetPEStatsRspParams; + wma_handle->get_sta_peer_info = false; + WMA_LOGD("stats_rsp allocated: %pK, sta_id: %d, mask: %d, vdev_id: %d", + node->stats_rsp, node->stats_rsp->staId, + node->stats_rsp->statsMask, get_stats_param->sessionId); + + cmd.vdev_id = get_stats_param->sessionId; + cmd.stats_id = get_stats_param->statsMask; + if (wmi_unified_stats_request_send(wma_handle->wmi_handle, + node->bssid, + &cmd)) { + WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID", + __func__); + goto failed; + } + + goto end; +failed: + node->stats_rsp = NULL; +req_pending: + pGetPEStatsRspParams->rc = QDF_STATUS_E_FAILURE; + /* send response to UMAC */ + wma_send_msg(wma_handle, WMA_GET_STATISTICS_RSP, pGetPEStatsRspParams, + 0); +end: + qdf_mem_free(get_stats_param); + WMA_LOGD("%s: Exit", __func__); +} +#endif /* QCA_SUPPORT_CP_STATS */ + +/** + * 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_LOGE("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) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) { + WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id); + return NULL; + } + + beacon = wma->interfaces[vdev_id].beacon; + + if (!beacon) { + WMA_LOGE("%s: beacon invalid", __func__); + 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); + WMA_LOGE("%s: alloc failed for beacon buf", __func__); + 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; +} + +/** + * 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) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + return wma->interfaces[vdev_id].addr; +} + +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 (NULL == wma_conn_table_entry) { + WMA_LOGE("%s: can't find vdev_id %d in WMA table", __func__, 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->mhz; + conn_table_entry->sub_type = wma_conn_table_entry->sub_type; + conn_table_entry->type = wma_conn_table_entry->type; + + 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) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + return &wma->interfaces[vdev_id]; +} + +QDF_STATUS wma_get_wcnss_software_version(uint8_t *version, + uint32_t version_buffer_size) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct target_psoc_info *tgt_hdl; + + if (NULL == wma_handle) { + WMA_LOGE("%s: Failed to get wma", __func__); + return QDF_STATUS_E_FAULT; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + WMA_LOGE("%s: Failed to get wma", __func__); + return QDF_STATUS_E_FAULT; + } + + snprintf(version, version_buffer_size, "%x", + target_if_get_fw_version(tgt_hdl)); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev + * @vdev_id: VDEV whose MAC ID is required + * + * Get MAC id corresponding to a vdev id from the WMA structure + * + * Return: Negative value on failure and MAC id on success + */ +int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + + if (wma->interfaces) + return wma->interfaces[vdev_id].mac_id; + + return -EINVAL; +} + +/** + * 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; + uint32_t param; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + if (!wma->interfaces) { + WMA_LOGE("%s: Interface is NULL", __func__); + return; + } + + if (cfgd_hw_mode_index > wma->num_dbs_hw_modes) { + WMA_LOGE("%s: Invalid index", __func__); + return; + } + + param = wma->hw_mode.hw_mode_list[cfgd_hw_mode_index]; + wma->interfaces[vdev_id].mac_id = mac_id; + if (mac_id == 0) { + wma->interfaces[vdev_id].tx_streams = + WMA_HW_MODE_MAC0_TX_STREAMS_GET(param); + wma->interfaces[vdev_id].rx_streams = + WMA_HW_MODE_MAC0_RX_STREAMS_GET(param); + } else { + wma->interfaces[vdev_id].tx_streams = + WMA_HW_MODE_MAC1_TX_STREAMS_GET(param); + wma->interfaces[vdev_id].rx_streams = + WMA_HW_MODE_MAC1_RX_STREAMS_GET(param); + } +} + +/** + * 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 (NULL == 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); +} +#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 + +/** + * 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; +} + +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) +{ + struct wlan_objmgr_vdev *vdev; + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + enum wlan_vdev_state state = WLAN_VDEV_S_INIT; + + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (vdev) { + wlan_vdev_obj_lock(vdev); + state = wlan_vdev_mlme_get_state(vdev); + wlan_vdev_obj_unlock(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + } + return (state == WLAN_VDEV_S_RUN) ? true : false; +} + +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_start_to_fw(t_wma_handle *wma, struct vdev_start_params *params) +{ + QDF_STATUS status; + struct wma_txrx_node *vdev = &wma->interfaces[params->vdev_id]; + + wma_acquire_wakelock(&vdev->vdev_start_wakelock, + WMA_VDEV_START_REQUEST_TIMEOUT); + status = wmi_unified_vdev_start_send(wma->wmi_handle, params); + if (QDF_IS_STATUS_ERROR(status)) + wma_release_wakelock(&vdev->vdev_start_wakelock); + + return status; +} + +QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id) +{ + QDF_STATUS status; + struct wma_txrx_node *vdev = &wma->interfaces[vdev_id]; + struct mlme_nss_chains *ini_cfg; + struct mlme_nss_chains *dynamic_cfg; + struct wlan_objmgr_vdev *vdev_obj; + + /* + * 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. + */ + + vdev_obj = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev_obj) { + WMA_LOGE("%s, vdev_id: %d, failed to get vdev from psoc", + __func__, vdev_id); + return QDF_STATUS_E_FAILURE; + } + + ini_cfg = mlme_get_ini_vdev_config(vdev_obj); + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev_obj); + + if (!dynamic_cfg || !ini_cfg) { + wma_err("nss chain dynamic/ini config NULL"); + goto get_config_failed; + } + *dynamic_cfg = *ini_cfg; + +get_config_failed: + wlan_objmgr_vdev_release_ref(vdev_obj, WLAN_LEGACY_WMA_ID); + + wma_acquire_wakelock(&vdev->vdev_stop_wakelock, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + + status = wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + wma_release_wakelock(&vdev->vdev_stop_wakelock); + + 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_LOGD("%s: Enter", __func__); + iface = &wma_handle->interfaces[rcpi_request->session_id]; + /* command is in progress */ + if (iface->rcpi_req != NULL) { + WMA_LOGE("%s : previous rcpi request is pending", __func__); + return QDF_STATUS_SUCCESS; + } + + node_rcpi_req = qdf_mem_malloc(sizeof(*node_rcpi_req)); + if (!node_rcpi_req) { + WMA_LOGE("Failed to allocate memory for rcpi_request"); + 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_LOGE("%s: Failed to send WMI_REQUEST_RCPI_CMDID", + __func__); + iface->rcpi_req = NULL; + qdf_mem_free(node_rcpi_req); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Exit", __func__); + + 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; + + iface = &wma_handle->interfaces[res.vdev_id]; + if (!iface->rcpi_req) { + WMI_LOGE("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_LOGE("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; +} + +/** + * wma_set_roam_offload_flag() - Set roam offload flag to fw + * @wma: wma handle + * @vdev_id: vdev id + * @is_set: set or clear + * + * Return: none + */ +static void wma_set_roam_offload_flag(tp_wma_handle wma, uint8_t vdev_id, + bool is_set) +{ + QDF_STATUS status; + uint32_t flag = 0; + + if (is_set) + flag = WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG | + WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG; + + WMA_LOGD("%s: vdev_id:%d, is_set:%d, flag:%d, roam_offload_enabled:%d", + __func__, vdev_id, is_set, flag, + wma->interfaces[vdev_id].roam_offload_enabled); + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_ROAM_FW_OFFLOAD, flag); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ROAM_FW_OFFLOAD"); + else + wma->interfaces[vdev_id].roam_offload_enabled = is_set; +} + +/** + * wma_update_roam_offload_flag() - update roam offload flag to fw + * @wma: wma handle + * @vdev_id: vdev id + * @is_connected: connected or disconnected + * + * Return: none + */ +static void wma_update_roam_offload_flag(tp_wma_handle wma, uint8_t vdev_id, + bool is_connected) +{ + struct wma_txrx_node *iface; + uint8_t id; + uint8_t roam_offload_vdev_id = WMA_INVALID_VDEV_ID; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t count; + + WMA_LOGD("%s: vdev_id:%d, is_connected:%d", __func__, + vdev_id, is_connected); + + iface = &wma->interfaces[vdev_id]; + + if ((iface->type != WMI_VDEV_TYPE_STA) || + (iface->sub_type != 0)) { + WMA_LOGE("%s: this isn't a STA: %d", + __func__, vdev_id); + return; + } + + if (iface->roaming_in_progress || iface->roam_synch_in_progress) { + WMA_LOGE("%s: roaming in progress: %d", + __func__, vdev_id); + return; + } + + for (id = 0; id < wma->max_bssid; id++) { + if (wma->interfaces[id].roam_offload_enabled) + roam_offload_vdev_id = id; + } + + /* + * If sta connected, and no connected sta interface exist, then set + * set roam offload flag to this sta interface + */ + if (is_connected && (roam_offload_vdev_id == WMA_INVALID_VDEV_ID)) + wma_set_roam_offload_flag(wma, vdev_id, true); + + if (!is_connected && roam_offload_vdev_id == vdev_id) { + /* If sta disconnected and roam offload enaled on this + * interface, then clear roam offload flag + */ + wma_set_roam_offload_flag(wma, vdev_id, false); + + count = policy_mgr_mode_specific_connection_count( + wma->psoc, PM_STA_MODE, list); + WMA_LOGD("%s: valid sta count:%d", __func__, count); + /* + * If there is multi sta connection before this disconnection, + * then set roam offload flag to other connected sta inferface. + */ + if (count > 1) { + for (id = 0; id < count; id++) { + if (list[id] != vdev_id) + wma_set_roam_offload_flag(wma, list[id], + true); + } + } + } +} + +QDF_STATUS wma_send_vdev_up_to_fw(t_wma_handle *wma, + struct vdev_up_params *params, + uint8_t bssid[IEEE80211_ADDR_LEN]) +{ + QDF_STATUS status; + struct wma_txrx_node *vdev = &wma->interfaces[params->vdev_id]; + + if (wma_is_vdev_up(params->vdev_id)) { + WMA_LOGD("vdev %d is already up for bssid %pM. Do not send", + params->vdev_id, bssid); + return QDF_STATUS_SUCCESS; + } + + wma_update_roam_offload_flag(wma, params->vdev_id, true); + status = wmi_unified_vdev_up_send(wma->wmi_handle, bssid, params); + wma_release_wakelock(&vdev->vdev_start_wakelock); + + return status; +} + +QDF_STATUS wma_send_vdev_down_to_fw(t_wma_handle *wma, uint8_t vdev_id) +{ + QDF_STATUS status; + struct wma_txrx_node *vdev = &wma->interfaces[vdev_id]; + + wma_update_roam_offload_flag(wma, vdev_id, false); + wma->interfaces[vdev_id].roaming_in_progress = false; + status = wmi_unified_vdev_down_send(wma->wmi_handle, vdev_id); + wma_release_wakelock(&vdev->vdev_start_wakelock); + + return status; +} + +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_LOGE("Cannot map wmi_peer_type %d to HAL peer type", type); + return WIFI_PEER_INVALID; + } +} + +/** + * 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_LOGE("Fail to Set Voltage Corner config (0x%x)", + vc_bitmap); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Successfully Set Voltage Corner config (0x%x)", + vc_bitmap); + + return QDF_STATUS_SUCCESS; +} + +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; + tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context( + QDF_MODULE_ID_PE); + if (wma == NULL) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return -EINVAL; + } + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + if (!mac->sme.chip_power_save_fail_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = + (WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid pwr_save_fail_params breached event", + __func__); + 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_LOGD("%s: Invoke HDD pwr_save_fail callback", __func__); + 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_handle) { + WMA_LOGE(FL("NULL wma_handle")); + return -EINVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (!wmi_handle) { + WMA_LOGE(FL("NULL 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_LOGE(FL("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_LOGE(FL("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_LOGE(FL("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_LOGE(FL("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_LOGD("%s: Enter", __func__); + iface = &wma_handle->interfaces[req->vdev_id]; + /* command is in progress */ + if (iface->roam_scan_stats_req) { + WMA_LOGE(FL("previous roam scan stats req is pending")); + return QDF_STATUS_SUCCESS; + } + + node_req = qdf_mem_malloc(sizeof(*node_req)); + if (!node_req) { + WMA_LOGE("Failed to allocate memory for roam scan stats 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_LOGE("%s: Failed to send WMI_REQUEST_ROAM_SCAN_STATS_CMDID", + __func__); + iface->roam_scan_stats_req = NULL; + qdf_mem_free(node_req); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Exit", __func__); + + return QDF_STATUS_SUCCESS; +} + +void wma_remove_peer_on_add_bss_failure(tpAddBssParams add_bss_params) +{ + tp_wma_handle wma; + struct cdp_pdev *pdev; + void *peer = NULL; + uint8_t peer_id; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + WMA_LOGE("%s: ADD BSS failure %d", __func__, add_bss_params->status); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return; + } + + peer = cdp_peer_find_by_addr(soc, pdev, add_bss_params->bssId, + &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", + __func__, add_bss_params->bssId); + return; + } + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s wma handle is NULL", __func__); + return; + } + wma_remove_peer(wma, add_bss_params->bssId, add_bss_params->bssIdx, + peer, false); +} + +#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_handle) { + WMA_LOGE("NULL wma handle"); + return -EINVAL; + } + + param_buf = + (WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID_param_tlvs *)event_buff; + if (!param_buf) { + WMA_LOGE("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_LOGE("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_LOGE("Cold Boot Cal Diag log not sent"); + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_utils_ut.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils_ut.c new file mode 100644 index 0000000000000000000000000000000000000000..0fbd6041d209dcafce9941a285c8309f537bd417 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils_ut.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015-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. + */ + +/** + * DOC: wma_utils_ut.c + * This file contains utilities related to unit test framework + */ + +/* Header files */ + +#include "wma.h" + +/** + * wma_set_dbs_capability_ut() - Set DBS capability for UT framework + * @dbs: Value of DBS capability to be set + * + * Sets the DBS capability for unit test framework. If the HW mode is + * already sent by the FW, only the DBS capability needs to be set. If the + * FW did not send any HW mode list, a single entry is created and DBS mode + * is set in it. The DBS capability is also set in the service bit map. + * + * Return: None + */ +void wma_set_dbs_capability_ut(uint32_t dbs) +{ + tp_wma_handle wma; + uint32_t i; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + /* DBS list was not configured by the FW, so + * for UT, we can configure a single entry + */ + if (wma->hw_mode.hw_mode_list == NULL) { + wma->num_dbs_hw_modes = 1; + wma->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*wma->hw_mode.hw_mode_list) * + wma->num_dbs_hw_modes); + if (!wma->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for UT-DBS", + __func__); + return; + } + wma->hw_mode.hw_mode_list[0] = 0x0000; + } + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + WMA_HW_MODE_DBS_MODE_SET(wma->hw_mode.hw_mode_list[i], + dbs); + } + + WMI_SERVICE_ENABLE(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT); +} diff --git a/drivers/staging/qcacld-3.0/uapi/linux/a_debug.h b/drivers/staging/qcacld-3.0/uapi/linux/a_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..db21bc2d66df5a53cf4a33c2135c0e014fa04ab6 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/uapi/linux/a_types.h b/drivers/staging/qcacld-3.0/uapi/linux/a_types.h new file mode 100644 index 0000000000000000000000000000000000000000..190d40df6afd201eff6333def8a9e3593b0df199 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/uapi/linux/athstartpack.h b/drivers/staging/qcacld-3.0/uapi/linux/athstartpack.h new file mode 100644 index 0000000000000000000000000000000000000000..0b92352228ec2ac218873f3eb2fb779ca7e69a74 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/uapi/linux/dbglog_common.h b/drivers/staging/qcacld-3.0/uapi/linux/dbglog_common.h new file mode 100644 index 0000000000000000000000000000000000000000..75c2d5e729c9b5727dd3ab771b5d49a95077bd83 --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/dbglog_common.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011, 2014-2015 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 _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 satisify 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[0]; +}; + +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[0]; +} __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/drivers/staging/qcacld-3.0/uapi/linux/debug_linux.h b/drivers/staging/qcacld-3.0/uapi/linux/debug_linux.h new file mode 100644 index 0000000000000000000000000000000000000000..d91dd110f8f448cfd1709dec6c017da0e5cad403 --- /dev/null +++ b/drivers/staging/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/drivers/staging/qcacld-3.0/uapi/linux/osapi_linux.h b/drivers/staging/qcacld-3.0/uapi/linux/osapi_linux.h new file mode 100644 index 0000000000000000000000000000000000000000..eb6c19a659d7e0f28e612633007340dad273856b --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/osapi_linux.h @@ -0,0 +1,277 @@ +/* + * 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. + */ + +/* ------------------------------------------------------------------------------ */ +/* 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(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, ## args) +#define A_PRINTF(args ...) \ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, ## args) +#define A_PRINTF_LOG(args ...) \ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, ## args) +#define A_SNPRINTF(buf, len, args ...) snprintf(buf, len, args) + +/* + * 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/drivers/staging/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h b/drivers/staging/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h new file mode 100644 index 0000000000000000000000000000000000000000..5bc1969e5277d261546b49f717a382b1d25bb252 --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h @@ -0,0 +1,397 @@ +/* + * 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 _PKTLOG_FMT_H_ +#define _PKTLOG_FMT_H_ + +#ifndef 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 HELIUMPLUS + 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 + * packet origin [1:0] + * 00 - Local + * 01 - Remote + * 10 - Unknown/Not applicable + * 11 - Reserved + * reserved [15:2] + */ +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 +/* From WIN definations */ +#define PKTLOG_TYPE_LITE_T2H 23 +#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[0]; /* 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[0]; +}; + +#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 + * + * 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, +}; + +/** + * 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_ */